Docs
Security

API Key and MCP Route Boundary

How personal API keys and OAuth 2.1 access tokens are restricted to cataloged tool routes via HMAC provenance signatures, what routes external tokens cannot reach, and how the tool catalog enforces this boundary across the CLI, stdio MCP server, and hosted MCP endpoint.

MarkDocket exposes its tool surface through two external token types — personal API keys (used by the CLI and direct integrations) and OAuth 2.1 access tokens (used by the hosted MCP endpoint and browser-authenticated CLI sessions). Neither token type can call arbitrary API routes. Instead, all external-token requests must pass through a catalog-derived provenance gate enforced by an HMAC signature before any internal route is reached.

The Two External Token Types

Token typeIssued byPrimary entry pointExecution transport
Personal API keyMarkDocket dashboard or CLI markdocket login --password/v1/tools REST gatewayDirect bearer auth to cataloged routes
OAuth 2.1 access tokenBrowser OAuth flow (markdocket login) or third-party MCP client/mcp hosted Streamable HTTP endpointResource-bound; cannot call /api/* directly

Both token types ultimately execute the same cataloged tools. The difference is in the execution path and the resource binding applied at issuance.

The Catalog HMAC Provenance Gate

When either token type triggers a tool call, the platform adds an HMAC provenance signature before dispatching to any internal route. This signature encodes:

  • The exact HTTP method and path being requested
  • The caller's bearer token
  • The semantic scope of the operation
  • A timestamp

The API server verifies this signature on every inbound request that arrives bearing a personal API key or OAuth access token. A request that lacks a valid signature — or that presents a signature for a different method, path, or token — is rejected before any handler runs.

The HMAC proof is generated by the catalog execution layer, not by the caller. External clients cannot construct or forge it; the signature is created server-side as part of dispatching through the tool catalog.

This means:

  • Only cataloged tools can be reached. A route that shares the /api/ prefix with cataloged routes but has no catalog entry is permanently unreachable from external tokens, regardless of URL guessing.
  • Adding a new tool to the catalog automatically grants access. No additional gateway configuration is needed; the catalog registration is the authorization step.
  • Replay and path-swapping attacks are not possible. The signature binds the exact method and path, so a captured proof for one tool cannot be reused against a different route.

OAuth Access Tokens Are Resource-Bound

OAuth 2.1 access tokens issued through the hosted MCP flow carry a resource binding to the /mcp endpoint. They cannot be used directly against /api/* routes — the API server rejects them at the auth layer before any route handler is reached.

This is by design: browser-authenticated CLI sessions and third-party MCP clients use executeRemoteMcpTool(), which opens a per-invocation MCP StreamableHTTPClientTransport connection to /mcp. The hosted endpoint handles the HMAC signing internally before any internal dispatch occurs.

Password-mode CLI sessions (markdocket login --password) produce a session token rather than an OAuth access token. These sessions call /api/ routes directly via bearer auth and are not resource-bound to the MCP endpoint. The CLI automatically dispatches through the correct execution path based on the session type.

Personal API Keys and the /v1/tools Gateway

Personal API keys authenticate at /v1/tools, the REST gateway for catalog tool calls. The executeCatalogToolWithTrace() path used by API-key sessions adds the HMAC catalog proof header before any internal /api/ call is made. The API server then verifies the signature against the catalog entry for that tool.

The gateway enforces one additional requirement for write-mutating calls: an Idempotency-Key header must be present. The server persists idempotency keys to deduplicate retried requests.

What External Tokens Cannot Reach

The following surfaces are explicitly outside the route boundary for both personal API keys and OAuth access tokens:

  • Billing management routes — subscription changes, payment methods, invoice access
  • Device pairing routes — the /api/devices one-time pairing code flow used by the Desktop companion
  • Credential management routes — password changes, two-factor enrollment, session management
  • Raw internal API routes — any /api/* path that does not have a corresponding catalog entry
  • Agent-only tools — tools such as web_search, classify_goods, and attachment_list that exist in the agent's internal registry but are excluded from the external catalog via EXTERNAL_TOOL_EXCLUSIONS

The OAuth consent page presented during the browser login flow explicitly discloses these exclusions to the user before they grant access.

The Tool Catalog as the Boundary Definition

The canonical tool catalog lives in the @markdocket/cli package and is the single source of truth for every external-facing tool surface: the CLI, the stdio MCP server, the /v1/tools REST gateway, and the hosted /mcp endpoint all derive their tool registries from the same catalog with no duplication.

The agent's internal registry is a superset of the catalog. Agent-only tools that depend on AI Gateway credentials or durable chat session state are excluded from the external catalog and are therefore unreachable from any external token, regardless of the provenance mechanism.

Agent internal registry (superset)
  └── External catalog (EXTERNAL_TOOL_EXCLUSIONS applied)
        ├── CLI commands (markdocket call <name>)
        ├── stdio MCP server tools
        ├── /v1/tools REST gateway  ← personal API keys
        └── /mcp hosted endpoint    ← OAuth 2.1 access tokens

MCP behavioral hints (readOnlyHint, idempotentHint, destructiveHint) are derived automatically from the HTTP method and read/write metadata already present on each tool definition — there is no separate annotation registry to maintain.

MCP Tool Response Size Management

Before returning a tool result over the MCP transport, the platform applies domain-aware compaction. Polling tools have intermediate data stripped from their responses, while final result tools pass through in full. If the compacted result still exceeds the size limit, the first 150,000 characters are returned as a preview with a truncated: true indicator rather than an error, so MCP clients always receive a usable response.

Summary of Protections

ProtectionPersonal API keyOAuth access token
HMAC catalog provenance requiredYesYes (applied internally by /mcp)
Resource binding to entry pointNo (uses /v1/tools)Yes (bound to /mcp)
Direct /api/* accessBlocked without valid HMAC proofBlocked entirely
Agent-only tools accessibleNoNo
Billing / device / credential routesNoNo
Idempotency-Key required for writesYesYes (enforced by catalog layer)

The combination of catalog-derived routing, HMAC provenance signing, and OAuth resource binding means that the external tool surface is closed by default: only explicitly cataloged tools at explicitly registered entry points can be reached with external credentials.

On this page