MCP Server
WarmHub implements the Model Context Protocol (MCP) over HTTP, exposing all read and write operations as typed tools that AI agents can discover and call.
Protocol
Section titled “Protocol”- MCP version: 2024-11-05
- Transport: JSON-RPC 2.0 over HTTP POST
- Supported methods:
initialize,tools/list,tools/call,ping
Endpoints
Section titled “Endpoints”| Method | Path | Description |
|---|---|---|
POST | /mcp | Global MCP endpoint |
GET | /mcp | Returns 405 Method Not Allowed with RFC 9728 discovery challenge |
POST | /mcp/:org/:repo | Repo-scoped MCP endpoint |
GET | /mcp/:org/:repo | Returns 405 Method Not Allowed with RFC 9728 discovery challenge |
GET | /.well-known/oauth-protected-resource | OAuth 2.0 Protected Resource Metadata (RFC 9728) |
GET | /.well-known/oauth-authorization-server | OAuth 2.0 Authorization Server Metadata (RFC 8414) |
Global vs Repo-Scoped
Section titled “Global vs Repo-Scoped”Global Mode (POST /mcp)
Section titled “Global Mode (POST /mcp)”The global endpoint exposes the full MCP tool catalog. Repo-level tools require orgName and repoName arguments. It also includes org-level tools:
warmhub_org_listwarmhub_org_getwarmhub_org_set_descriptionwarmhub_org_set_display_namewarmhub_org_archivewarmhub_org_unarchivewarmhub_repo_listwarmhub_repo_create
Best for agents that work across multiple repos.
Repo-Scoped Mode (POST /mcp/:org/:repo)
Section titled “Repo-Scoped Mode (POST /mcp/:org/:repo)”Org and repo are baked into the URL. Tool schemas omit orgName/repoName parameters. The repo-scoped endpoint includes tools that need both an organization and a repository to operate, plus advisory and meta tools that require neither — tools that operate only at the organization level are excluded. The following tools are among those excluded:
warmhub_org_listwarmhub_org_getwarmhub_org_set_descriptionwarmhub_org_set_display_namewarmhub_org_archivewarmhub_org_unarchive
Org-scoped subscription tools (category: subscription) are also excluded because they operate at the organization level rather than on a specific repo. Repo administration tools (warmhub_repo_list, warmhub_repo_create) are also excluded. Repo-level tools such as warmhub_repo_set_description, warmhub_repo_set_display_name, warmhub_repo_archive, and warmhub_repo_unarchive remain available and operate on the repo baked into the URL.
Advisory and meta tools that do not require an organization or repository — including warmhub_use, warmhub_channel, warmhub_doctor, and warmhub_capabilities — are also available in repo-scoped mode.
Best for agents that focus on a single repo — simpler tool schemas, fewer required arguments.
Authentication
Section titled “Authentication”POST /mcp and POST /mcp/:org/:repo require a Bearer token. Unauthenticated POSTs return HTTP 401 with an RFC 9728 challenge:
HTTP/1.1 401 UnauthorizedWWW-Authenticate: Bearer resource_metadata="https://api.warmhub.ai/.well-known/oauth-protected-resource"Content-Type: application/json
{ "error": { "code": "UNAUTHENTICATED", "message": "Authentication required" } }GET requests to /mcp and /mcp/:org/:repo return HTTP 405 Method Not Allowed and include the same RFC 9728 WWW-Authenticate challenge header:
HTTP/1.1 405 Method Not AllowedAllow: POSTWWW-Authenticate: Bearer resource_metadata="https://api.warmhub.ai/.well-known/oauth-protected-resource"This means a GET probe against either MCP route can bootstrap OAuth discovery in the same way as an unauthenticated POST — standards-compliant clients can follow the challenge from either response to discover the protected-resource metadata endpoint and acquire a token.
Standards-compliant MCP/OAuth clients use the challenge to discover the protected-resource metadata endpoint and bootstrap auth. Without a valid Bearer token, callers cannot list or call MCP tools — there is no anonymous tool catalog.
Configuration
Section titled “Configuration”MCP Client Setup
Section titled “MCP Client Setup”Add a WarmHub entry to the mcpServers section of your MCP client’s configuration. The examples below use the standard format supported by Claude Desktop, Cursor, and other MCP-compatible clients. The transport field is required by some clients (e.g., Claude Desktop); others infer it from the URL scheme.
The MCP POST endpoints require a Bearer token — the URL alone is not enough. Standards-compliant MCP/OAuth clients follow the RFC 9728 challenge returned on the first unauthenticated request to discover the OAuth flow and acquire a token automatically. Clients without that capability must inject the token themselves; mint a personal access token (see HTTP Authentication) and configure your client to send Authorization: Bearer <token> on every MCP POST. Many clients accept a headers map in the mcpServers entry for this purpose, e.g.:
{ "mcpServers": { "warmhub": { "transport": "http", "url": "https://api.warmhub.ai/mcp/myorg/myrepo", "headers": { "Authorization": "Bearer ${WH_TOKEN}" } } }}The MCP endpoint authenticates the bearer token in the Authorization header; the example above sources that value from WH_TOKEN. See Environment Variables for the variables WarmHub reads and their precedence.
Consult your MCP client’s documentation for the exact field name. See Authentication above for the challenge format and discovery contract.
Repo-scoped (recommended):
{ "mcpServers": { "warmhub": { "transport": "http", "url": "https://api.warmhub.ai/mcp/myorg/myrepo" } }}Global (multi-repo):
{ "mcpServers": { "warmhub": { "transport": "http", "url": "https://api.warmhub.ai/mcp" } }}The examples above use the production API URL. For self-hosted deployments, replace api.warmhub.ai with your deployment URL.
Tool Responses
Section titled “Tool Responses”Tool responses include both human-readable and structured content:
{ "content": [{ "type": "text", "text": "..." }], "structuredContent": { ... }, "isError": false}content— tool result as text for the model-readable channel. Typically JSON.structuredContent— typed object for programmatic access. Includes anauthfield on every response (see below).isError—trueif the tool call failed
Every tool definition in tools/list includes an outputSchema covering both the successful structuredContent object (including auth) and the structured tool-error payload (including error and auth), and an annotations block with explicit safety hints:
readOnlyHint—trueonly for tools that do not change state.openWorldHint—truewhen a write can affect public WarmHub data, another user, or a third-party webhook; alwaysfalsefor read-only tools.destructiveHint—truewhen a write can delete, overwrite, retract, revoke access, or cause a comparable irreversible effect.category— one oforg,repo,shape,thing-read,collection,commit,subscription,action,meta.- Clients can use
categoryto group or filter tools in discovery UIs. warmhub_capabilitiesuses the same enum, but groups tools under each category rather than repeating the value per tool. Each summary includesname,description,readOnly,openWorld,destructive, andannotationJustification; the category is implicit in the enclosing group. TheannotationJustificationfield is a short rationale for why the safety hints were assigned to that tool.
Authentication Awareness
Section titled “Authentication Awareness”POST /mcp requires a Bearer token (see Authentication above), so every dispatched tool call has a resolved caller. Tool responses still include structuredContent.auth with the caller’s authentication status — at the public HTTP transport this is always { "authenticated": true } once a tool dispatches:
{ "structuredContent": { "items": [...], "auth": { "authenticated": true } } }Read-only tool descriptions append a runtime auth-hint that reads: “Returns public data only when unauthenticated. If expected data is missing, suggest the user authenticate to access private orgs and repos.” Agents using the same tools through transports that allow unauthenticated dispatch can branch on the hint to prompt the user to sign in.
Error Handling
Section titled “Error Handling”MCP tool failures arrive in three distinct ways. Inspect the tool response, not just the client-level try/catch.
Tool-result errors. The tool dispatched, but its execution failed. The response carries isError: true and a structured error in content / structuredContent. This covers VALIDATION_ERROR, NOT_FOUND, FORBIDDEN, RATE_LIMITED (per-user / per-org tier limits hit during the call), QUERY_TOO_EXPENSIVE (typed where predicate exceeded the query budget), and warmhub_commit_submit ambiguous append failures. Each code is described in the Tool-error code reference below.
warmhub_commit_submit per-operation failures. Per-op failures are not tool errors. The response is a normal success payload with partial: true, statusCounts.error > 0, and one or more rows with status: "error" plus an error object. Treat partial results as a routine outcome to inspect.
Transport-level errors. Some failures happen before the tool dispatches and surface as HTTP errors instead of tool results:
- POST with no
Authorizationheader, within the anonymous rate-limit budget → HTTP 401 with theWWW-Authenticatechallenge. A fresh anonymous request always reaches the challenge; use it to authenticate. - POST with no
Authorizationheader, once the anonymous rate-limit budget is exhausted → HTTP 429 (see the anonymous rate-limit bullet below) rather than the401challenge. If you are seeing 429 on headerless requests, authenticate rather than only backing off. - POST with a malformed or unverified bearer → treated as anonymous: the request draws down the anonymous rate-limit budget and, once that is exhausted, returns HTTP 429 (below) rather than the
401challenge. A429after presenting a token means the token wasn’t accepted — re-authenticate with a valid one rather than only backing off. - Request body exceeds the MCP size limit → HTTP 413 with a JSON-RPC error body. The error uses code
-32013. This check runs before tool dispatch, so no tool result is produced. Reduce the request payload and retry. - Repo-scoped endpoint cannot resolve the scope (authenticated, but the repo isn’t visible or doesn’t exist) → HTTP 404.
- Anonymous request over the rate limit → HTTP 429 carrying a JSON-RPC error whose
error.data.warmhubholds{ code, message, status, hint, retryAfter, details }. Thedetailsobject has the shape{ reason: "rate_limit_reset", retryAfterSeconds, resetAt }. ReadretryAfter(seconds) to back off; readdetails.resetAtfor the precise reset timestamp. Note that this transport-level 429 shape differs from the tool-resultRATE_LIMITEDerror — see the Tool-error code reference below for the tool-result fields.
Authenticated MCP traffic bypasses the anonymous rate limit and never sees that 429. Once authenticated, rate limits surface instead as the RATE_LIMITED tool-result error described below (per-user / per-org tier limits hit during a call).
Tool-error code reference
Section titled “Tool-error code reference”- Validation failures — include the validation message and, for
warmhub_commit_submit, enriched hint data (seewarmhub_commit_submitValidation Hint below). NOT_FOUND— includes the error details. Tool calls always carry a resolved caller (POST requires a Bearer token), and missing targets surface asNOT_FOUNDregardless of which token was presented.FORBIDDEN— surfaced aserrorCode: "FORBIDDEN"in the structured error when the presented token is valid but lacks the scope required for the requested resource. Distinct fromNOT_FOUND; use it to decide whether retrying with a more privileged token is sensible.RATE_LIMITED— surfaced aserrorCode: "RATE_LIMITED"instructuredContent.error.datawhen a per-user or per-org write limit is hit. The samedataobject also carries adetailsfield with the shape{ reason: "rate_limit_reset", retryAfterSeconds, resetAt }. See Rate Limiting for tier limits and retry guidance. Treat as retryable with a bounded backoff, prefer theerrorCodeover string-matching the message, and readdetails.resetAtfor the precise reset time. Note that this tool-result shape (errorCode/backendCodeplusdetailsunderstructuredContent.error.data) differs from the transport-level anonymous 429 shape (error.data.warmhubwithcode,hint,retryAfter, anddetails) — parse them separately.QUERY_TOO_EXPENSIVE— surfaced aserrorCode: "QUERY_TOO_EXPENSIVE"instructuredContent.error.datawhen a typedwherepredicate is rejected as too broad or complex to execute within the query budget. This is distinct fromRATE_LIMITED: it signals that the query itself needs to be narrowed, not that a throughput limit was hit. Recovery depends on which tool raised the error:- Paged
wherequeries (warmhub_thing_head,warmhub_thing_query,warmhub_thing_about): tighten thewherepredicate to reduce the result set, or retry with a shallower page size. - Count-mode requests (
warmhub_thing_headorwarmhub_thing_querycalled withcount: true): count mode has no page-size argument, so reducing page size is not applicable. Narrow the query with a more selective equality predicate instead. Backing off without changing the query will not resolve this error in either case.
- Paged
- Ambiguous append failures (
warmhub_commit_submitonly) — when a transport-ambiguous failure (network reset, 5xx, timeout) interrupts the stream append, the tool returnsisError: truewithstructuredContent.error.datacarryingpartial: true,completedOperationCount,failedOperationOffset, and acontinuationobject containing thestreamId. The failed append may have landed server-side. Treat repository state as the source of truth — inspect it withwarmhub_thing_get/warmhub_thing_querybefore deciding whether to resume. When resuming, pass thecontinuation’sstreamIdin the new call and re-submit only the operations that haven’t been acknowledged; makeaddoperations idempotent withskipExisting: truefor safer retries. See SDK Streaming Write Failures for the parallel SDK contract.
Tool-result errors (the isError: true responses above) also include structuredContent.auth with the caller’s authentication status, so agents can decide whether to suggest authenticating and retrying. Transport-level failures do not carry this field.
warmhub_commit_submit Validation Hint
Section titled “warmhub_commit_submit Validation Hint”When warmhub_commit_submit rejects a malformed operations entry, the tool result’s structuredContent.error.data lists the eight valid operation variant signatures so agents can self-correct on the next turn — the message is the original validation message.
{ "isError": true, "content": [{ "type": "text", "text": "<validation message>" }], "structuredContent": { "error": { "code": -32602, "message": "<validation message>", "data": { "tool": "warmhub_commit_submit", "errorCode": "VALIDATION_ERROR", "backendCode": "VALIDATION_ERROR", "expected": "one of the operation variants", "operations": [ "ADD shape: { operation:'add', kind:'shape', name, data }", "ADD thing: { operation:'add', kind:'thing', name, data }", "ADD assertion: { operation:'add', kind:'assertion', name, about, data }", "ADD collection: { operation:'add', kind:'collection', type, name, members }", "REVISE shape: { operation:'revise', kind:'shape', name, data }", "REVISE thing: { operation:'revise', kind:'thing', name, data }", "REVISE assertion: { operation:'revise', kind:'assertion', name, data }", "REVISE collection: { operation:'revise', kind:'collection', type, name, members }", "RETRACT: { operation:'retract', name, reason?, kind? }" ] } }, "auth": { "authenticated": true } }}The expected and operations fields are attached only for warmhub_commit_submit validation errors; validation errors from other tools continue to return data with just tool and errorCode. backendCode may also appear as a compatibility alias for errorCode; parse errorCode. The same variant list is also returned by warmhub_repo_describe under commitContract.operationVariants.
Repo-Scoped 404
Section titled “Repo-Scoped 404”POST /mcp/:org/:repo requires a Bearer token; unauthenticated POSTs return 401 before any repo lookup happens (see Authentication). For authenticated callers whose token cannot resolve the org or repo, the endpoint returns HTTP 404 with a plain Not Found body.