Docs

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

  1. It POSTs to https://app.seoaio.ai/api/mcp without a token and gets 401 with a WWW-Authenticate header pointing at https://app.seoaio.ai/.well-known/oauth-protected-resource.
  2. From that document it finds the authorization server, reads https://app.seoaio.ai/.well-known/oauth-authorization-server, and registers itself at https://app.seoaio.ai/api/oauth/register. No client secret exists; public clients with PKCE only.
  3. It opens https://app.seoaio.ai/oauth/authorize in a browser. You sign in with the account that owns the workspace and approve.
  4. It exchanges the code at https://app.seoaio.ai/api/oauth/token and calls the server with a Bearer token from then on.
  5. 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

errorerror_description
invalid_requestMalformed request body.
invalid_requestcode, client_id and redirect_uri are required.
invalid_requestA valid PKCE code_verifier is required.
invalid_grantAuthorization code is invalid or expired.
invalid_grantClient mismatch.
invalid_grantredirect_uri mismatch.
invalid_grantPKCE verification failed.
invalid_requestrefresh_token and client_id are required.
invalid_grantRefresh token is invalid or expired.
unsupported_grant_typeSupported grants: authorization_code, refresh_token.

What each one means and what to do next is on the troubleshooting page.