Auth
Two credentials open the MCP server. An MCP client signs in with OAuth 2.1 and PKCE, with nothing pasted into a config file. A server-to-server integration uses an API key an operator creates under Settings, which can be pinned to one site. Either way, every call is bound to one organization.
What the client does
- It POSTs to
https://app.seoaio.ai/api/mcpwithout a token and gets 401 with aWWW-Authenticateheader pointing athttps://app.seoaio.ai/.well-known/oauth-protected-resource. - From that document it finds the authorization server, reads
https://app.seoaio.ai/.well-known/oauth-authorization-server, and registers itself athttps://app.seoaio.ai/api/oauth/register. No client secret exists; public clients with PKCE only. - It opens
https://app.seoaio.ai/oauth/authorizein a browser. You sign in with the account that owns the workspace and approve. - It exchanges the code at
https://app.seoaio.ai/api/oauth/tokenand calls the server with a Bearer token from then on. - Refresh tokens rotate. A refresh token presented twice revokes its whole family, on purpose, so a stolen one cannot be reused quietly.
Scopes requested: visibility:read. A token is minted for the resource https://app.seoaio.ai/api/mcp and no other host.
API keys, and what a scope is
An operator creates a key under Settings and presents it as a Bearer token. A key can be pinned to a single site: that credential reads that site, cannot enumerate the rest of the roster, and is refused anything else with a message naming only its own site. That is what lets an agency hand a client MCP access without handing over the client list.
Revoke
Connected apps and API keys are listed at https://app.seoaio.ai/dashboard/settings/api. Revoking takes effect on the next call, which answers 401 until you connect again.
Every error the token endpoint sends
| error | error_description |
|---|---|
| invalid_request | Malformed request body. |
| invalid_request | code, client_id and redirect_uri are required. |
| invalid_request | A valid PKCE code_verifier is required. |
| invalid_grant | Authorization code is invalid or expired. |
| invalid_grant | Client mismatch. |
| invalid_grant | redirect_uri mismatch. |
| invalid_grant | PKCE verification failed. |
| invalid_request | refresh_token and client_id are required. |
| invalid_grant | Refresh token is invalid or expired. |
| unsupported_grant_type | Supported grants: authorization_code, refresh_token. |
What each one means and what to do next is on the troubleshooting page.
