Skip to main content
Audience: developers integrating BeeOS agents into an LLM tool host — Claude Desktop, Cursor, OpenAI’s MCP support, n8n, MCP Inspector, or any Model Context Protocol client.
The MCP Gateway turns every MCP-enabled BeeOS agent into a spec-compliant MCP tool server. From the host’s point of view it looks like any other MCP endpoint: discover tools, call them, optionally stream responses. From your side as the agent owner it’s “flip mcp_enabled=true on the agent and you’re done.” For the decision of whether MCP is the right surface (vs. OpenAPI or A2A), see Choosing a Protocol. This guide covers MCP-specific integration once you’ve made that choice.

1. Where it lives

ItemValue
Hosthttps://mcp.beeos.ai
MCP endpoint shapePOST /{agentId}/mcp
TransportStreamable HTTP (JSON-RPC 2.0 over HTTP, SSE for streaming)
OAuth metadataGET /.well-known/oauth-authorization-server
Protected resource metadataGET /.well-known/oauth-protected-resource
Health probeGET /healthz
Local development: the gateway listens on http://localhost:8094 with the same path shape; see backend/services/mcp-gateway/README.md for the goreman wiring. The agent ID in the URL pins each MCP session to one BeeOS agent. A single MCP host can mount multiple BeeOS agents by registering multiple endpoints with different {agentId} segments.

2. Authentication — three credentials, one endpoint

/{agentId}/mcp accepts three credential types. Pick the one that matches your client’s identity model.
CredentialHeaderBest forScope
OAuth 2.1 Bearer (HS256 JWT from /oauth/token)Authorization: Bearer <jwt>Spec-compliant MCP clients (Claude Desktop, MCP Inspector)Per-session, agent set granted at consent time
User API Key (oag_…)Authorization: Bearer oag_…Scripts, CI, n8n acting as a BeeOS userAll MCP-enabled agents the user owns
Agent API Key (bak_…)X-Agent-API-Key: bak_… or Authorization: Bearer bak_…Third-party integrations bound to a single agentOne agent (the URL’s {agentId} MUST match)
The fixed priority order is OAuth → User → Agent. Sending two different credentials (e.g. Authorization: Bearer oag_… plus X-Agent-API-Key: bak_… with a different value) returns 401. Sending the same bak_ in both Authorization and X-Agent-API-Key for a stubborn proxy is fine. For credential rotation and revocation, see Authentication & API Keys.

2.1 OAuth 2.1 flow (spec-compliant MCP clients)

Claude Desktop / Cursor / MCP Inspector use Dynamic Client Registration (DCR) + Authorization Code + PKCE per the MCP Authorization spec:
  1. Client POSTs /oauth/register{client_id, …}.
  2. Client opens browser at /oauth/authorize?client_id=…&code_challenge=…&redirect_uri=…&state=….
  3. MCP Gateway redirects to BeeOS web login (MCP_WEB_LOGIN_URL/mcp-login?return_to=…).
  4. User signs into BeeOS, picks which agents to grant.
  5. Web app redirects back to MCP Gateway, gateway redirects to redirect_uri with ?code=…&state=….
  6. Client POSTs /oauth/token with code_verifier → access token.
  7. Client uses token on /{agentId}/mcp from then on.
You don’t usually code this manually — Claude Desktop, MCP Inspector, and similar tools handle DCR + PKCE automatically. What you DO need to make sure of:
  • Your BeeOS user account has at least one MCP-enabled agent (mcp_enabled=true). Check with GET /api/v1/agents on the OpenAPI surface — the mcp_enabled field surfaces in the catalog response.
  • Your client’s redirect_uri is reachable from a browser (the authorization-code redirect can’t go to a non-routable host).
  • For local dev: MCP_PUBLIC_URL=http://localhost:8094 is in the gateway’s env, and the web app at localhost:3000 exposes a /mcp-login route.

2.2 API-key-only flow (n8n, scripts, CI)

For non-interactive callers, skip the OAuth flow entirely and use an oag_ (User API Key) or bak_ (Agent API Key) as a bearer credential:
# n8n / CI: list this user's MCP-enabled agents
curl -X POST https://mcp.beeos.ai/<agentId>/mcp \
  -H "Authorization: Bearer oag_XXXXXXXXXXXXXXXX" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

# Third-party app bound to ONE agent
curl -X POST https://mcp.beeos.ai/<agentId>/mcp \
  -H "X-Agent-API-Key: bak_XXXXXXXXXXXXXXXX" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
bak_ is the right choice for third-party apps because:
  • The key is bound to ONE agent — losing the key compromises only that integration, not your whole user account.
  • It can be revoked independently of your oag_ keys.
  • The agent owner (you) explicitly issued it, so consent is audit-traceable.

3. What each MCP method does

The gateway implements four JSON-RPC methods. All requests are POST to /{agentId}/mcp; responses are JSON-RPC 2.0 envelopes.

3.1 initialize

Standard MCP handshake. The gateway returns its protocol version and capabilities. Clients that auto-reconnect should re-issue this on every session start.
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2024-11-05",
    "capabilities": { "tools": {} },
    "clientInfo": { "name": "claude-desktop", "version": "0.7.0" }
  }
}

3.2 tools/list

Enumerates the single BeeOS agent reachable through this endpoint as one tool. The tool’s name, description, and input schema come from the agent’s Agent Card (pkg/agentcard resolves it).
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/list"
}
Response (truncated):
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "tools": [
      {
        "name": "agent_abc123",
        "description": "Analyze CSV files and produce a chart.",
        "inputSchema": {
          "type": "object",
          "properties": {
            "message": { "type": "string" },
            "context_id": { "type": "string" }
          },
          "required": ["message"]
        }
      }
    ]
  }
}
The shape is deliberately uniform across BeeOS agents — every agent looks like a message → reply tool to MCP. If your agent needs structured input, validate inside the agent process (the message field is the JSON or natural-language envelope the agent expects); MCP itself doesn’t model per-agent schemas deeply.

3.3 tools/call

Invokes the agent. Synchronous by default; pass an SSE-capable Accept header to stream notifications/progress events as the agent emits agent_reply_delta.
{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "agent_abc123",
    "arguments": {
      "message": "What's the top-selling SKU last week?",
      "context_id": "ctx-uuid-optional"
    }
  }
}
Synchronous response:
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [
      { "type": "text", "text": "Top SKU last week: BLUE-42 (1,329 units)" }
    ]
  }
}
Streaming response: same JSON-RPC ID, but the gateway writes notifications/progress events on the SSE stream as the agent emits agent_reply_delta, then closes with the final result.

3.4 tools/call cancel

The MCP spec doesn’t standardise cancel today. If you need cancel semantics for a long-running call, use the OpenAPI tasks surface in parallel — submit the same work as a BeeOS task and cancel via POST /tasks/{id}/cancel. The MCP tools/call will see the agent’s terminal state through the underlying Message Service channel.

4. Behavioural contract — what MCP guarantees, what it doesn’t

Guaranteed:
  • tools/list is read-only and idempotent. Safe to call repeatedly across reconnects.
  • tools/call always delivers exactly one result (or one error) per JSON-RPC ID. Cancellation triggered server-side (deadline, agent crash) surfaces as a JSON-RPC error with a stable code from Error Reference.
  • The same agent reachable via OpenAPI / A2A is reachable here; responses are bit-identical (same agent_reply from the same Message Service channel).
  • Idempotency: pass params.arguments.idempotency_key and the gateway honours it on the underlying L0 invoke. See Calling Agents § Idempotency.
  • Attachments: pass params.arguments.attachments[] with file_id values from POST /api/v1/files/presign-upload. The agent sees a normal multi-part chat_message.
Not guaranteed:
  • Durable async — MCP tools/call is request-response. Long-running work that needs to survive client disconnects belongs on OpenAPI tasks. Reaching for “fire-and-forget MCP tool” is a sign the protocol’s wrong for the use case.
  • Multi-turn within one call — every tools/call is a fresh turn. To chain related turns, the MCP host typically keeps the conversation context client-side and includes the relevant history in the next message. If you need server-side conversation continuity, use the OpenAPI conversations surface and reference the conversation ID from arguments.context_id on MCP calls.
  • Webhook push — MCP has no notion of server-pushed events outside the in-flight call. For “tell me when this task finishes” semantics, use OpenAPI webhooks (P2-A — see the webhooks guide).
  • Rate-limit visibility — the gateway enforces rate limits per credential × agent, but rate-limit metadata is returned in the standard MCP error shape (code, message). Inspect the code (rate_limited) to back off; the wire doesn’t carry Retry-After today.

5. Common failure modes

SymptomLikely causeFix
401 unauthorized even after DCR + PKCEThe agent isn’t MCP-enabled.Flip mcp_enabled=true on the agent (PATCH /api/v1/agents/{id}).
401 with WWW-Authenticate: Bearer realm="MCP", resource_metadata="…/.well-known/oauth-protected-resource"Credential missing or expired. The header points at the OAuth metadata so spec-aware clients auto-retry.Re-run the OAuth flow (most clients do this automatically).
400 invalid_param on tools/callarguments.message empty, or attachments[i].file_id references a missing / mismatched-owner file.Verify the file ID in GET /api/v1/files/{id} from your oag_ first.
503 agent_service_unavailableAgent pod is offline or has no Message Service subscription.Check the agent’s instance state via GET /api/v1/instances; restart if delivery_mode=push and the pod is in STOPPED.
409 conflict on duplicate idempotency_keyA previous call with the same key is still in flight.Either wait for the prior reply or rotate the key.

6. End-to-end example — Claude Desktop

~/Library/Application Support/Claude/claude_desktop_config.json:
{
  "mcpServers": {
    "beeos-csv-analyst": {
      "transport": "streamable-http",
      "url": "https://mcp.beeos.ai/agent_abc123/mcp"
    }
  }
}
On first use, Claude walks DCR → /oauth/authorize → the BeeOS consent screen → token → tools/listtools/call. You’ll see “BeeOS CSV Analyst” appear as a tool in Claude’s prompt menu. After the first session the token is cached locally; refreshes follow standard OAuth refresh-token semantics.

7. See also