POST /v1/mcp — a stateless Streamable HTTP endpoint speaking JSON-RPC 2.0.
It accepts both connection shapes the protocol defines: the legacy
initialize-handshake flow (initialize, ping, tools/list, tools/call)
and the 2026-07-28 stateless core (server/discover, tools/list,
tools/call), where every request carries its own context. Every tool is one
reviewed API operation; a tools/call is compiled into the equivalent REST
request and dispatched through the same router as every other client, so
authentication, Workspace binding, budgets, policy, and audit behave exactly as
documented in this reference. There is no second enforcement path to reason
about.
This endpoint is for driving the Checkfu platform from your coding agent
or MCP client. It is distinct from the harness-facing MCP endpoint at
/v1/runtime/mcp/{connection_id}, which serves a Run’s connected tool catalog
to the executing harness — see Capabilities. You
call the first; your agents’ runtimes use the second.Connect a client
The CLI registers the server with your coding agent and keeps the bearer out of the config file. Prefer a Principal credential: the written entry referencesCHECKFU_PRINCIPAL_ACCESS_CREDENTIAL, and the server binds its Workspace and
Principal rather than trusting client-selected headers.
CHECKFU_PRINCIPAL_ACCESS_CREDENTIAL in the environment that starts the
client. Principal mode rejects Workspace selectors: the credential’s retained
authority supplies it. API-key mode remains available as
checkfu connect --credential api-key; export a Workspace-bound CHECKFU_API_KEY.
The endpoint does not require Checkfu’s dated Checkfu-Version REST
header — synthesized REST dispatches carry the latest version internally.
Issue and manage a Principal credential
Use an existing Workspace identity-administration API key to issue the bearer for one live Principal. Thesecret appears in exactly this response and is
never readable or replayed again:
audience defaults to api_mcp for compatibility. It is immutable and keeps
this bearer out of the A2A server; issue a separate a2a
credential when an external agent needs that protocol edge.
List credential metadata at /v1/principals/{principal_id}/access-credentials
or read one at /v1/principal-access-credentials/{id} without exposing its
secret. Rotate with POST /v1/principal-access-credentials/{id}/rotate, or revoke with POST /v1/principal-access-credentials/{id}/revoke; both take
expected_generation_number and a
fresh Idempotency-Key. Rotation invalidates the old bearer immediately and
returns the replacement once. Revocation is irreversible. Suspending or
deleting the Principal also denies the next request.
The Principal catalog is a closed read-only set: exact AgentDefinition,
MemoryStore, and SurfaceScope reads for which the Principal holds the matching
live PermissionAssignment and survives ActionPolicy evaluation. List, search, and direct calls use
that same set. Consequential operations and reads without an exact resource
mapping are absent, and guessing their tool names is denied.
OAuth discovery
A stock MCP client that sends a request to/v1/mcp without a valid bearer
receives a 401 whose WWW-Authenticate header carries a
resource_metadata_url. Fetching that URL returns an
RFC 9728 protected-resource
metadata document naming this resource and pointing at Checkfu as its own
authorization server. The corresponding
.well-known/oauth-authorization-server
document is honest about the model: Checkfu does not implement a standard
OAuth authorization-code flow (D95 rejected a full authorization server; it
may layer on without changing authority), so grant_types_supported is empty
and service_documentation points here. A client that requires a standard
flow learns it is not available; a client that can use a bearer discovers
that it needs one and where to obtain it.
Because Checkfu is also an OAuth client when connecting to external MCP
servers, its custody adapter validates the RFC 9207
iss parameter in every authorization redirect whose server includes one,
refusing a mismatch before the authorization code is redeemed. Client
registration uses RFC 7591 dynamic registration (D215), deduplicated to one
client per integration; Client ID Metadata Documents will replace DCR on the
specification’s own removal clock, not before summer 2027.
Checkfu speaks two MCP connection shapes on the same endpoint, and a stock
client may open with either.
The legacy shape (2025-06-18 / 2025-11-25) begins with a conforming
initialize request containing protocolVersion, capabilities, and
clientInfo, then sends notifications/initialized. A client requesting
either legacy version receives that version back, and an unsupported requested
version receives the baseline 2025-06-18. After initialization, send the
negotiated version in MCP-Protocol-Version on every request.
The 2026-07-28 stateless shape has no handshake. Each request is
self-contained: it carries io.modelcontextprotocol/protocolVersion,
io.modelcontextprotocol/clientCapabilities, and optionally
io.modelcontextprotocol/clientInfo in request _meta, and sets the routable
Mcp-Method (and Mcp-Name for tools/call) headers plus
MCP-Protocol-Version: 2026-07-28, which must agree with _meta. Probe with
server/discover to learn the supported versions and capabilities; the result
of every request carries resultType (an absent field reads as "complete",
so legacy clients are unaffected). ping and initialize are not served on
this shape; a 2026-07-28 client uses server/discover instead.
Checkfu supports MCP 2026-07-28, 2025-11-25, and 2025-06-18. MCP
interprets an omitted MCP-Protocol-Version header as legacy 2025-03-26;
Checkfu does not claim that batching-era protocol, so an omitted header or a
legacy version Checkfu does not serve is rejected with -32600. On the
stateless 2026-07-28 shape, a _meta version Checkfu does not serve answers
UnsupportedProtocolVersionError (-32022) listing the supported set, and a
MCP-Protocol-Version header that disagrees with _meta — or a Mcp-Method /
Mcp-Name header that disagrees with the body — answers
HeaderMismatchError (-32020).
Send each request as application/json. JSON-RPC requests and final responses
are each limited to 4 MiB, and a synthesized REST result may contribute at
most 1 MiB before MCP framing. The endpoint accepts no query parameter except
one optional catalog, whose value must be exactly compact or full.
Because this is a bearer-authenticated non-browser endpoint, requests carrying
an Origin header are rejected before authentication or body processing.
The tool catalog
tools/list returns a curated compact catalog — the core Session journey
(create, drive, read the ledger, fork, diff), agents, runs, ActionApprovals, memory,
and usage — plus checkfu_search_operations, which searches every projected
operation by name or capability. Any operation search returns is callable as a
tool without being listed, so the compact default never limits what an agent
can do; it only keeps the advertised catalog small. ?catalog=full lists
every projected operation instead.
Tool names are operationIds with the group separator flattened:
sessions.createSession becomes sessions_createSession. Arguments are
nested as { "path": { … }, "query": { … }, "body": { … } } matching the
operation’s documented parameters. Mutation tools whose REST operation accepts
an idempotency header require idempotency_key and refuse the call when it is
missing. Keys are 1–255 non-space printable ASCII characters; reuse the same key
on retries. Mutations without REST idempotency support do not advertise a key
and retain their documented compare-and-swap or idempotent-delete semantics. Tool
annotations carry readOnlyHint and destructiveHint from the same reviewed
registry that produces this reference.
Operations that accept or return credentials, single-use proofs, pairing
material, or capability URLs remain REST-only so those values never enter a
model transcript. Multipart uploads and tar imports or exports are also
REST-only because the generic MCP bridge carries JSON.
REST failures come back as tool results with isError: true and the complete
wire error body, so an agent can read the reason and
self-correct — a 404 names the missing resource, a 400 names the invalid
field, a 429 names the exhausted budget.