Are you an LLM? You can read better optimized documentation at /developers/docs/mcp/authorization.md for this page in Markdown format
Authorization
The Flat MCP server follows the MCP authorization specification: OAuth 2.1, authorization code grant with PKCE, discovered from metadata. A client that implements the spec needs no Flat-specific configuration.
Discovery
An unauthenticated request to https://mcp.flat.io/mcp answers 401 with a WWW-Authenticate challenge pointing to the protected resource metadata (RFC 9728):
GET https://mcp.flat.io/.well-known/oauth-protected-resourcejson
{
"resource": "https://mcp.flat.io/mcp",
"authorization_servers": ["https://api.flat.io"],
"bearer_methods_supported": ["header"],
"scopes_supported": ["mcp"],
"resource_name": "Flat",
"resource_documentation": "https://flat.io/developers/docs/mcp"
}The authorization server metadata (RFC 8414) is at https://api.flat.io/.well-known/oauth-authorization-server (also served as /.well-known/openid-configuration):
| Field | Value |
|---|---|
issuer | https://api.flat.io |
authorization_endpoint | https://flat.io/auth/oauth/mcp |
token_endpoint | https://api.flat.io/oauth/access_token |
revocation_endpoint | https://api.flat.io/oauth/invalidate_token |
registration_endpoint | https://api.flat.io/oauth/mcp/register |
grant_types_supported | authorization_code, refresh_token |
code_challenge_methods_supported | S256 |
client_id_metadata_document_supported | true |
scopes_supported | mcp |
Client registration
Client ID Metadata Documents (preferred)
Use an https:// URL as your client_id. Flat fetches it at authorization time and reads your client metadata from it (CIMD).
- The URL must be
https, have a path (not just a host) and no fragment. - The document's
client_idmust equal the URL exactly. client_nameand a non-emptyredirect_urisare required.- Redirect URIs must be
https, orhttponlocalhost/127.0.0.1, without a fragment. - Flat follows at most 3 redirects, reads at most 64 KB and waits at most 5 seconds. It caches the document according to
Cache-Control: max-age, between 5 minutes and 24 hours.
There is nothing to register with Flat beforehand.
Dynamic Client Registration
For clients that do not support CIMD, Flat accepts RFC 7591 registration:
http
POST https://api.flat.io/oauth/mcp/register
Content-Type: application/json
{
"client_name": "My MCP client",
"redirect_uris": ["http://127.0.0.1:33418/callback"]
}The response (201) contains a client_id, with token_endpoint_auth_method: "none" and scope: "mcp". No client secret is issued: every MCP client is a public client. Registration is limited to 10 clients per IP address per hour (429, Retry-After: 3600).
Clients registered this way cannot prove who they are, so the consent screen marks them as unverified (see below). Prefer CIMD.
Authorization request
https://flat.io/auth/oauth/mcp
?response_type=code
&client_id=https://example.com/oauth/client.json
&redirect_uri=https://example.com/oauth/callback
&code_challenge=...
&code_challenge_method=S256
&scope=mcp
&resource=https://mcp.flat.io/mcp
&state=...response_typemust becode.- PKCE is required, with
S256only. The verifier is 43 to 128 characters. redirect_urimust match a registered URI exactly. Forhttploopback URIs (localhost,127.0.0.1), any port matches (RFC 8252); scheme, host, path and query must still match. A mismatch is shown on Flat's page and never redirected.scopedefaults tomcp; a request withoutmcpfails withinvalid_scope.resource(RFC 8707) defaults tohttps://mcp.flat.io/mcp. Unknown values fail withinvalid_target.
The redirect back carries code, state and iss (RFC 9207). The code is valid for 10 minutes and can be redeemed once.
The mcp scope is only granted through this flow. It cannot be added to a regular Flat developer app or a personal access token.
Tokens
| Token | Lifetime |
|---|---|
| Access token | 24 hours |
| Refresh token | 30 days, renewed on every refresh |
Every refresh returns a new refresh token with a new 30-day lifetime and invalidates the previous one. A client that does not refresh for 30 days must send the customer through consent again.
Send the access token as a bearer token on every MCP request:
http
Authorization: Bearer <access_token>The MCP server only accepts tokens issued for its resource (https://mcp.flat.io/mcp).
Consent screen
The customer approves every client on Flat's consent screen, which lists the single permission requested: Read and change the content of your Flat account. How the client is presented depends on what Flat could verify:
| Client | Shown as |
|---|---|
| Recognized (ChatGPT, Claude, Visual Studio Code) | Product name and logo, "recognized by Flat" |
| CIMD client | The domain of its client_id as a proven origin, with the name it declares |
| DCR client | "This app hasn't proven who it is", and the button reads Allow anyway |
When the redirect URI is a loopback address, the screen also says the access code goes to a program running on the customer's computer.
Errors
| Situation | Result |
|---|---|
| Missing, expired or revoked token | 401, invalid_token |
| Token issued for another resource | 401, invalid_token |
| Account without Flat Power | 403, MCP_UPGRADE_REQUIRED |
| Flat for Education account | 403, MCP_EDUCATION_NOT_AVAILABLE |
| Disabled account | 403, MCP_ACCOUNT_DISABLED |
| Client disabled by Flat | MCP_CLIENT_DISABLED |
Eligibility is checked at consent and on every request. The error messages are localized to the customer's language and meant to be shown to them as is.
Revocation
- By the customer: removing the client from Link external accounts and apps in their Flat account settings deletes all its tokens for that customer.
- By the client:
POST https://api.flat.io/oauth/invalidate_token(RFC 7009) revokes the token you send.