| title | MCP connections |
|---|---|
| description | Connect OAuth and API-key clients to FrontLit's stateless MCP server. |
FrontLit exposes one remote MCP endpoint:
https://api.frontlit.app/mcp
The endpoint supports the stateless MCP 2026-07-28 protocol and older
Streamable HTTP clients through the official SDK 2 stateless compatibility
mode. FrontLit does not expose the retired standalone SSE transport: GET /mcp is intentionally not a connection endpoint, and no client receives an
Mcp-Session-Id.
OAuth-capable clients should be given only the HTTPS /mcp URL. They discover
the protected resource at:
/.well-known/oauth-protected-resource/mcp
That document points to FrontLit's authorization server. Current clients can onboard through a Client ID Metadata Document (CIMD); Dynamic Client Registration remains available for clients such as MCP Inspector. Both use authorization code with PKCE, resource binding, user consent, and explicit tool scopes.
An OAuth connection belongs to your account, not to one team. There is no team picker: one connection works in every team you're a member of, including teams you join later, and each call is limited to your role and permissions in that team. Leaving a team stops the connection's access to it on the next call.
Team-scoped tools take a teamId argument. Call list_teams to see your teams
with your permissions in each, then pass the chosen teamId. It is optional
only when you belong to a single team; otherwise the tool returns
team_required with the list of teams, and the assistant should ask you which
one to use. Results of tools that change something end with a line naming the
team they acted in.
Tickets, contacts, documentation improvements, and GitHub proposals contain text written by people outside your team. FrontLit marks those tools as untrusted so assistants treat their text as data, not instructions. Review what an assistant plans to change, especially when it has been reading outside-written content.
FrontLit configures an identity-only registration baseline (openid profile email). Better Auth represents the combined identity and allowed MCP scopes
as a client's capability set, so a DCR response can list every MCP scope.
That is not an access grant: authorization requests with missing or blank
scope are rejected, and only explicitly requested and approved scopes are
issued in a token. A consent screen may therefore show many scopes because
the client requested them.
Scope families include teams, API keys, pages, themes, media, blogs, help
documents, changelogs, contacts, segments, broadcasts, ESP configuration,
chatbot, helpdesk, domains, and settings. Read and write scopes are separate,
and sending a broadcast requires the distinct broadcasts:send scope.
A team API key is a full-team credential until scoped keys are introduced as a separate product feature. Configure the client to send:
x-frontlit-apikey: fl_live_...
For example, clients that accept a JSON header configuration can use:
{
"url": "https://<api-host>/mcp",
"headers": {
"x-frontlit-apikey": "fl_live_..."
}
}The submitted secret is verified at the HTTP boundary and is never copied
into MCP tool context or logs. API keys cannot call account-only tools such as
list_teams, create_team, or delete_team. A key only works in its own
team; a teamId naming any other team returns team_mismatch.
Desktop and hosted clients commonly require public HTTPS. Start the API, then
use a controlled tunnel or Funnel that proxies the public hostname to the
local API port. Set ENABLE_TRUST_PROXY=true only when the deployment really
has the configured one trusted proxy hop.
Check each layer before opening a GUI client:
curl -i http://localhost:4000/health
curl -i http://localhost:4000/.well-known/oauth-protected-resource/mcp
curl -i http://localhost:4000/.well-known/oauth-authorization-server/api/auth
curl -i -X POST http://localhost:4000/mcp \
-H 'content-type: application/json' \
-H 'accept: application/json, text/event-stream'The final request should return 401 with a WWW-Authenticate challenge that
contains the protected-resource metadata URL. Repeat the health and discovery
checks against the public hostname before starting OAuth.
- If the browser completes OAuth but the client fails, inspect the first
subsequent
POST /mcpstatus and body. - Some clients try
GET /mcpas standalone SSE after a failed POST. The resulting404 Cannot GET /mcpis expected and is usually secondary to the earlier POST failure; do not add SSE to hide it. no_teammeans authentication succeeded but the user has no team yet. Create one withcreate_team, or join a team; no reconnect is needed.team_requiredmeans you belong to several teams and the call had noteamId. Pass one fromlist_teams.not_a_team_membermeans theteamIdnames a team you don't belong to (or were removed from).invalid_client_metadatainvolving Device Authorization or JWT Bearer means the client's published CIMD grants changed or the exact compatibility rule no longer matched. FrontLit does not globally relax grant validation.ERR_ERL_UNEXPECTED_X_FORWARDED_FORmeans the proxy is forwarding client IPs while Express is not configured to trust that deployment hop.- Reconnect after changing scopes, discovery metadata, tool schemas, or the tool catalog because clients may cache them.