Blog · announcement

Verification is now a tool call

The MintID client family grew a third member — not another language, a protocol. An MCP server exposes the three frozen verifier-service operations as tools any agent framework can call, with the same closed reason-code vocabulary: a rejection stays a decision, now readable by an agent.

The unit of consumption on the agentic web turned out not to be the page or the endpoint. It is the tool. Anthropic ships finance agents wired to MCP connectors; Cloudflare meters and monetizes MCP tools at the edge. When the surface an agent reaches for is a tool listing, anything that wants to be part of an agent’s workflow has to be a tool — and identity verification is no exception.

So the MintID client family grew a third member. Not another language: a protocol. @mintid/verifier-mcp is a Model Context Protocol server that exposes MintID verification to any MCP-capable framework as three tools over stdio — and it carries exactly the same discipline as every client before it.

Three tools, one frozen contract

The server exposes the three operations of the frozen verifier-service contract and nothing else: mintid_build_info, mintid_create_challenge and mintid_validate_presentation. Challenge → presentation → decision, driven from an agent runtime without writing glue and without the agent framework learning OpenID4VP or the HTTP contract.

It is transport-only in the strictest sense. It wraps the existing TypeScript client — its only dependency — and adds zero external runtime dependencies: the JSON-RPC framing is a few dozen auditable lines, not a framework. It contains no cryptography and no policy. Nonce, session id and the ten-second expiry are generated by the verifying core; no tool argument can mention them, let alone move them. The contract itself is untouched — the same v1 every other client speaks.

The property that survives the protocol hop

The part worth dwelling on is what happens when verification fails. In the MintID clients, a rejection is a decision, not an error. That distinction usually dies at the first protocol boundary, where every non-happy path collapses into an exception and the caller learns only that something went wrong.

It survives here. When an agent submits a presentation that fails — a replayed nonce, a stale status root, a missing predicate — the tool call succeeds and returns accepted: false with a reason_code from the same closed vocabulary every other client sees. Only transport failures are tool errors: a body the service cannot parse, or proven chain state being unavailable — which fails closed, never open.

The consequence is not cosmetic. An agent that receives accepted: false plus a named reason can reason about it: ask the holder for a fresher presentation, escalate to a human, decline the transaction, log a decision. An agent that receives a generic error can only retry blindly — which is the behaviour every fraud team dreads and every rate limiter punishes.

Registering it, and where it must live

Registration is one stanza in your agent runtime’s MCP configuration:

{
  "mcpServers": {
    "mintid-verifier": {
      "command": "mintid-verifier-mcp",
      "args": ["--service-url", "http://127.0.0.1:8471"]
    }
  }
}

Note the address. That 127.0.0.1 is the whole architecture in one line: the server is part of your verifier deployment, run inside your perimeter, pointed exclusively at your own service instance. There is no MintID endpoint in the path, and there is no version of this where there is one. Embedded, not hosted is not a deployment preference — outsourcing the service outsources the decision itself, which the protocol’s paid-verification permission does not cover. The server itself persists nothing and logs nothing; your service keeps the only decision record.

Why a protocol, not a fourth language

The multi-language strategy is deliberately conservative: one audited verification pipeline, embedded in Python, with thin clients delegating to a service you host. Adding MCP does not bend that rule — it applies it one layer up. The MCP server is a client of a client: it can no more skip an acceptance condition than the TypeScript client it wraps, because neither of them verifies anything.

What it changes is who can call. Until now, integrating MintID meant a backend engineer writing code against a contract. Now an agent framework can list verification alongside its other tools, and an autonomous workflow can check whether its counterparty is backed by an accountable human the same way it checks anything else. That is the integration point agent KYC was always going to need, and it is now a working artifact rather than a roadmap line.

The usual honesty, unchanged: the protocol is research-stage. The proof engine does not verify proofs yet — it is a pinned, fail-closed stub, and nothing about this connector changes that. What exists today is the transport, the contract and the decision vocabulary, built and tested. The integration docs say exactly which is which.

What does the MintID MCP server actually do?
It exposes the three operations of the frozen verifier-service contract — build info, create challenge, validate presentation — as Model Context Protocol tools over stdio. An agent framework lists them and calls them like any other tool, without learning OpenID4VP or the HTTP contract.
Is this a MintID-hosted verification endpoint?
No, and it never will be. The server runs inside your own perimeter, next to the verifier service you deploy yourself, and points exclusively at that instance. Outsourcing the service would outsource the decision itself — which the protocol’s paid-verification permission explicitly does not cover.
What happens when a presentation is rejected?
The tool call succeeds and returns accepted: false with a reason code from the same closed vocabulary every other client sees. Only transport failures — an unparseable body, or proven chain state being unavailable, which fails closed — surface as tool errors. An agent can reason about a rejection instead of retrying blindly.
Can the MCP layer weaken a verification?
No. It is transport-only: no cryptography, no policy, no acceptance knob. The nonce, the session id and the ten-second expiry are generated by the verifying core, and no tool argument can mention them. If a change to this package ever looked like a verification feature, it would belong to the service instead.

Verification, where your agents already are

Three tools over stdio, pointed at the verifier service you deploy yourself. Same checks, same reason codes, no new trust boundary.