Skip to main content
MCP (Model Context Protocol) is the open standard Anthropic introduced for AI tool servers. Linear, GitHub, Stripe, Atlassian, Sentry, and dozens of other vendors publish official MCP servers. qlaud lets you connect any of them with one POST — we open a connection, list every tool the server exposes, and add them to your account, prefixed with the server name you pick. This is the third tool kind alongside webhooks and built-ins. All three flow through the same /v1/threads/:id/messages dispatch path; the model never sees a difference.
All /v1/mcp-servers endpoints are master-key only. Same posture as /v1/tools — registering an arbitrary MCP server URL is control plane, and a leaked per-user key shouldn’t be able to point a discovery probe at attacker.com or shove tools into another tenant’s roster.

How it works

   POST /v1/mcp-servers              MCP server (Linear, Stripe, …)
        │                                      ▲
        │ name: "linear"                      │ tools/list
        │ server_url: "https://mcp.linear..."  │
        │ auth_headers: { Authorization: ... } │
        ▼                                      │
   ┌───────────────────────────────────────────┴──┐
   │  qlaud edge                                  │
   │  1. Connect (Streamable HTTP)                │
   │  2. tools/list → discover what's available   │
   │  3. Encrypt auth_headers (AES-GCM, write-only)│
   │  4. Insert mcp_servers row                    │
   │  5. Insert one `tools` row per discovered    │
   │     tool, prefixed: "linear/create_issue"     │
   └───────────────────────────────────────────────┘
When the model later invokes linear/create_issue, qlaud opens a fresh MCP session, calls tools/call with the unprefixed name, and returns the result — same shape the model expects from any tool.

POST /v1/mcp-servers — Connect

curl https://api.qlaud.ai/v1/mcp-servers \
  -H "x-api-key: $QLAUD_MASTER_KEY" \
  -H "content-type: application/json" \
  -d '{
    "name": "linear",
    "server_url": "https://mcp.linear.app/sse",
    "auth_headers": {
      "Authorization": "Bearer lin_oauth_…"
    }
  }'
We connect to the server BEFORE persisting. If the URL is bad, the auth is wrong, or the server doesn’t speak MCP, you get a clean 400 at registration time — not a mid-chat dispatch failure.

Body

FieldTypeRequiredDescription
namestringyesLowercase alphanumeric (with - or _), 1-31 chars. Becomes the prefix on every tool from this server. Per-account unique among non-revoked servers. Cannot start with qlaud-builtin/.
server_urlstringyesThe MCP server’s Streamable HTTP endpoint. https:// only.
auth_modestringnotenant (default — auth_headers set here are used for every dispatch by every end-user) or per_user (each end-user supplies their own headers via qlaud_manage_connections.connect at runtime).
auth_headersobjectnoFlat string→string map of headers sent on every call (e.g. Authorization, X-API-Key). Encrypted at rest. Must be omitted when auth_mode='per_user' — per-user mode means headers come from each end-user inline in chat, not from registration.

Response (201)

{
  "id": "mcp_a1b2c3d4...",
  "object": "mcp_server",
  "name": "linear",
  "server_url": "https://mcp.linear.app/sse",
  "tools_discovered": 12,
  "tools_registered": 12,
  "tools_skipped": [],
  "tools": [
    { "id": "tool_xxx", "name": "linear/create_issue" },
    { "id": "tool_yyy", "name": "linear/list_issues" },
    { "id": "tool_zzz", "name": "linear/update_issue" }
  ],
  "created_at": 1777262997717
}
tools_skipped lists any tools whose prefixed name conflicted with an existing tool (registered as a webhook or built-in earlier). Rename those first or pick a different MCP server prefix.

GET /v1/mcp-servers — List

curl https://api.qlaud.ai/v1/mcp-servers -H "x-api-key: $QLAUD_MASTER_KEY"
Returns every non-revoked MCP server you’ve connected. auth_headers is never returned — only a has_auth_headers: boolean indicator.

DELETE /v1/mcp-servers/:id — Disconnect

curl -X DELETE https://api.qlaud.ai/v1/mcp-servers/$ID \
  -H "x-api-key: $QLAUD_MASTER_KEY"
Soft delete — the row stays for audit, hard-delete cron sweeps later. Cascades to tools: every tools row backed by this server is revoked at the same time. Existing thread audits referencing those tools resolve cleanly; new thread messages can no longer use them.

POST /v1/mcp-servers/:id/refresh — Re-discover

curl -X POST https://api.qlaud.ai/v1/mcp-servers/$ID/refresh \
  -H "x-api-key: $QLAUD_MASTER_KEY"
Vendors add and remove tools. This re-calls tools/list and reconciles: new tools get inserted, removed tools get revoked, matching tools stay intact. Returns the diff:
{
  "id": "mcp_a1b2c3d4...",
  "refreshed": true,
  "tools_discovered": 13,
  "added": ["linear/create_comment"],
  "removed": []
}

Tool naming convention

Every discovered tool is registered as <server_name>/<original_name>. This means:
  • The model sees linear/create_issue and knows it’s a Linear tool.
  • Two MCP servers can expose tools with the same bare name without colliding (e.g. linear/create_issue vs github/create_issue).
  • The <server_name> half is a path in your namespace — tool names starting with qlaud-builtin/ are reserved for the built-in catalog.
When dispatch happens, qlaud sends only the bare name (create_issue) to the MCP server since that’s what the server registered.

Auth header encryption

auth_headers is encrypted with AES-GCM using the gateway’s TOOL_CONFIG_ENC_KEY secret before being persisted to D1. The headers are only decrypted at dispatch time inside the worker. There is no read path that returns the plaintext — to rotate a token, revoke the server and re-register with the new one.

Errors

StatusMeaning
400Body malformed (bad name format, non-https URL, malformed auth_headers), OR the MCP server returned an error during the discovery probe (bad auth, unreachable, no tools, protocol error). The error message names the failing stage (connect, list_tools).
401Bad / revoked qlk key.
403Caller used a per-user (standard-scope) key. All /v1/mcp-servers endpoints require a master (admin-scope) key.
409An MCP server with the same name already exists. Pick a different name or revoke the existing one.
502Refresh failed because the server is unreachable. Server stays connected; tools cache stays as-is.
503Gateway is missing the TOOL_CONFIG_ENC_KEY operator secret — MCP servers requiring auth_headers can’t be registered until it’s set. Servers with no auth still work.

Where MCP fits vs. the other tool kinds

KindWhen to useCode you write
Built-inThe popular cases qlaud already curates (web search, Slack post, Linear issue, …) — paste an API key, doneNone
WebhookCustom business logic only your backend knows (read your DB, query your warehouse, post-process your data)One HTTP handler per tool
MCPAny vendor that publishes an MCP server — you get the FULL surface (often 30+ tools per vendor) without us writing wrappersNone
The general rule: try built-in first (curated UX, sensible defaults). If you want broader vendor coverage than the curated builtins offer, connect their MCP server. Use webhooks for the truly custom stuff that no public tool can express.