API & MCP

MCP API server troubleshooting

Diagnose authentication, JSON-RPC, rate limits, tool scope, and runtime issues for the AffinityBots MCP endpoint at /api/mcp/server.

April 7, 2026
12 min read

This guide goes deeper than the MCP Server overview. It reflects how the public MCP endpoint (POST /api/mcp/server) validates requests, which errors you may see from clients such as Claude Desktop or Cursor, and how that differs from in-app MCP integrations under Tools.

How the endpoint behaves

  1. Authentication — Every POST must send an API key in the Authorization header. The server accepts Bearer ab_live_... or a raw header value starting with ab_live_. Keys are validated with the validate_api_key database function (hash lookup, revocation, expiry, then usage counters).
  2. Rate limiting — After a successful validation, a per-key limit runs before the body is parsed. Exceeding it returns HTTP 429 with a JSON-RPC-shaped error.
  3. JSON-RPC — The body must be JSON-RPC 2.0 with a method string. Supported methods: initialize, tools/list, tools/call, and ping. Anything else returns method not found.
  4. Tool executiontools/call runs server-side handlers that read your agents and workflows from Postgres and, for chat and threads, call the LangGraph API with LANGGRAPH_API_URL and LANGSMITH_API_KEY.

GET /api/mcp/server returns static server metadata and does not require a Bearer token. You can use it to confirm the deployment and documentation URL.

Quick checks

CheckWhat to verify
URLPOST target is /api/mcp/server on your environment (e.g. production https://affinitybots.com/api/mcp/server).
TransportClient is configured for streamable HTTP, not stdio-only MCP.
HeaderAuthorization: Bearer ab_live_... with no extra spaces or quoted values.
Key formatSecret portion is hex; full key starts with ab_live_.
ScopeKey scope is Agents & Workflows (or all) if you need both tool groups.
RestartAfter editing MCP config, fully restart the client (not always a hot reload).

HTTP status codes and JSON-RPC errors

Responses are JSON. Transport-level failures use HTTP status; protocol errors include a JSON-RPC error object with a numeric code.

HTTPTypical meaning
401Missing key, malformed Authorization, invalid hash, revoked key, or expired key. Message text comes from validation (e.g. Invalid API key, API key has been revoked, API key has expired).
429Per-key rate limit exceeded for the current minute window. Retry with backoff.
400Body is not valid JSON-RPC (jsonrpc, method, etc.).
500Unhandled server error during processing.

Custom and standard JSON-RPC codes used in responses include:

CodeMeaning
-32700Parse error
-32601Method not found
-32602Invalid params (e.g. missing tool name)
-32603Internal error
-32001Unauthorized
-32004Rate limited

Authentication edge cases

  • "Invalid API key" when the key looks right — Only values starting with ab_live_ are extracted. If the header is Bearer <something_else> or the secret was truncated when copying, validation fails. Regenerate a key if unsure.
  • Bearer required in practice — Some clients send only Bearer; raw ab_live_ without the Bearer prefix is accepted by the server only when the entire header value is the key (see extractApiKey). Prefer the documented Bearer form for compatibility.
  • Internal validation error — Rare; indicates a database or RPC failure during validate_api_key, not a bad key. Retry later; if it persists, capture the time and environment for support.

Tools missing or "not allowed for scope"

  • tools/list is filtered by key scopeagents returns only agent tools; workflows only workflow tools; full access returns the combined list. If a tool never appears, create a key with Agents & Workflows (or the narrow scope you need).
  • Tool '…' is not allowed for scope '…' — The tool exists but the key used for the call does not include that category. This returns as a successful JSON-RPC result with isError: true and a JSON payload describing the error, not as HTTP 403.
  • Unknown tool — Usually a typo in params.name or a client calling a tool name that is not defined on this server.

Agent tools: empty lists, "Agent not found", chat failures

  • Listed agents respect workspace — If the API key has a workspace_id, agent lists are filtered to rows whose workspace_id, metadata.workspace_id, or config.configurable.workspace_id matches. If you see no agents, try a key scoped to the correct workspace or create agents in that workspace.
  • Access model — Agents are visible if you own them (metadata.owner_id) or they are linked via user_assistants. An ID copied from another account or workspace will yield Agent not found for chat and get.
  • Failed to chat with agent / thread errors — Chat and thread APIs use the LangGraph SDK. Failures often mean the graph runtime is unreachable, misconfigured in the deployment (LANGGRAPH_API_URL, LANGSMITH_API_KEY), or the assistant ID is not a valid graph assistant in that environment. Operators should verify env vars and LangGraph health; end users should retry and confirm the agent runs in the product UI.

Workflow tools: activation, triggers, run status

  • Workflow is not activatedaffinitybots_execute_workflow requires activated_at to be set. Activate the workflow in the app first.
  • No trigger available for this workflow — The handler picks a manual trigger by default, or the trigger_id you pass. Ensure at least one trigger exists.
  • Workflow not found / Run not found — IDs must belong to the same user as the API key; run lookups also enforce ownership via the related workflow.

Important: affinitybots_execute_workflow creates a workflow_runs row and returns a run_id. It does not call the same HTTP execution pipeline as the interactive workflow runner. If status never advances beyond running or no output appears, run the workflow from the app or use the standard workflow execution API you rely on in production. Treat MCP execution behavior as environment-dependent until you confirm runs complete end-to-end.

Rate limiting details

Limits are enforced per API key ID using an in-memory counter per deployment process, reset on a sliding minute boundary after the first request in a window. On a single Node instance this matches “N requests per minute per key.” If you self-host multiple instances without a shared limiter, effective throughput can be higher than the documented plan cap until a shared store is introduced—hitting 429 still means that instance saw too many requests for that key in its window.

CORS

OPTIONS /api/mcp/server returns permissive CORS headers for Content-Type and Authorization. Browser-based MCP clients are uncommon; if you build one and see preflight failures, confirm the custom domain and method are allowed.

In-app MCP vs this endpoint

Problems connecting external MCP servers inside AffinityBots (OAuth, discovery, diagnostics under /api/mcp/diagnostics, Smithery, etc.) use different routes and lib/mcp/* code paths. This page focuses on your clients talking to /api/mcp/server. For integration OAuth and discovery issues, use the in-app Tools experience and Adding integrations.

Still stuck?

If you have checked the items above and something still fails consistently—including suspected bugs with workflow runs from MCP, LangGraph connectivity, or key validation—contact the AffinityBots team (for example via in-app chat or your account representative) with the approximate time of the request, the HTTP status or JSON-RPC error (redact your full API key), and which client you use. That context allows the team to trace logs and reproduce the path quickly.