Skip to main content

MCP OAuth Troubleshooting

Technical reference for OAuth-related CrossTrade MCP errors. For a trader-friendly walkthrough, see Troubleshoot 401, 403, and 408 Errors.

Error matrix

HTTPerrorCauseResolution
401invalid_tokenAccess token expired, revoked, or never issuedReauthorize from AI Clients
401WWW-Authenticate: Bearer realm="..." (no body)First-call discovery probeExpected; client follows the header to OAuth discovery
403subscription_required / message "MCP requires an Elite subscription"Account is below EliteUpgrade
403insufficient_scopeTool requires mcp:trade; token has mcp:readReauthorize at mcp:trade
408addon_disconnected / generic timeoutNT8 closed or add-on disconnectedOpen NT8; verify the add-on panel
400invalid_grantPKCE verifier mismatch, code reuse, or stale codeRestart the auth flow
400invalid_requestMalformed registration or token request bodyInspect the client's request shape
400invalid_client_metadataRegistration body violates RFC 7591 constraintsReduce metadata to required fields
429too_many_registrationsRate-limit on /v1/oauth/mcp/register (10/hour/IP)Reuse the existing client_id or wait
500server_errorTransient backend failureRetry; if persistent, contact support

401: invalid_token

401 is the default response when a tool is called without a valid bearer token. Two distinct conditions:

  1. No token presented. Server returns 401 with WWW-Authenticate: Bearer resource_metadata=.... This is the first step of the OAuth discovery flow.
  2. Token presented but invalid. Server returns 401 with error: invalid_token. The token expired, was revoked, or was never issued for this client.

Resolution:

  • Reauthorize the client from the AI Clients page.
  • If the client cached an old token, remove and re-add the MCP server in the client.
  • If PKCE timestamps look off, confirm system clock.

403: subscription_required (Elite gate)

The MCP transport itself is Elite-gated. OAuth completes on all tiers (so the discovery flow does not fail), but tools/call returns:

{
"error": "subscription_required",
"message": "MCP requires an Elite subscription"
}

Resolution: upgrade at Subscriptions. REST and WebSocket remain available on Pro.

403: insufficient_scope

The token has mcp:read but the requested tool requires mcp:trade.

{
"error": "insufficient_scope",
"required": "mcp:trade"
}

Resolution: either rewrite the prompt to keep the agent in read-only mode, or revoke and reauthorize at mcp:trade. See Use mcp:read vs mcp:trade.

408: addon_disconnected

Tools that need NT8 state route through the CrossTrade Add-On. If the add-on is not connected, the server returns 408 Request Timeout or addon_disconnected.

Resolution:

  1. Open NT8.
  2. Open the CrossTrade Add-On panel.
  3. Confirm the version is v1.13.0 or higher.
  4. Confirm status shows connected.
  5. Restart the add-on if necessary.

400: invalid_grant on token exchange

The authorization code is single-use, has a short expiry, and is bound to the PKCE verifier the client sent at the authorization step. Common causes:

  • Client tried to reuse a code that was already exchanged.
  • The code expired before exchange (default expiry is short).
  • PKCE verifier sent at the token endpoint does not match the challenge sent at the authorization endpoint.

Resolution: restart the entire auth flow.

400: invalid_client_metadata (DCR)

POST /v1/oauth/mcp/register rejects metadata that violates RFC 7591 constraints. Common rejections:

  • scope includes anything other than mcp:read or mcp:trade.
  • redirect_uris missing or malformed.

Resolution: send only the supported metadata fields.

429: too_many_registrations

POST /v1/oauth/mcp/register is rate-limited per IP. Default: 10 registrations per hour. Most clients register once and persist the client_id. Re-registering on every connection attempt is a bug in the client.

Resolution:

  • Persist the client_id after first registration.
  • If you genuinely need to re-register, wait an hour or use a different IP for the test.

Discovery sequence reference

For the full discovery sequence, see MCP Authentication.

Quick summary:

  1. Client → POST /v1/api/mcp (no token) → 401 with WWW-Authenticate.
  2. Client → GET /.well-known/oauth-protected-resource (RFC 9728).
  3. Client → GET /.well-known/oauth-authorization-server (RFC 8414).
  4. Client → POST /v1/oauth/mcp/register (RFC 7591).
  5. Browser → authorization endpoint, user consents.
  6. Client → POST /v1/oauth/mcp/token (exchange code).
  7. Client → POST /v1/api/mcp with Authorization: Bearer <token>.

What to send to support

Include:

  • HTTP status code
  • error field if present
  • Approximate timestamp in UTC
  • Client name and version
  • Whether you completed OAuth in the last 24 hours
  • The result of GetMcpCapabilities if it works

Do not send:

  • Bearer tokens
  • Account numbers or balances
  • Webhook secrets
  • Full request/response bodies that may contain the above