Skip to content

MCP server

The Model Context Protocol lets an assistant call tools on your behalf. For a certificate platform the appeal is obvious: “which certificates expire this month”, “why did that renewal fail”, “open a renewal for the shop certificate” are all questions people already ask, phrased the way they already ask them.

A layer over the public API, not a second data path. The MCP server calls the same API you can call, so it inherits token scopes, rate limits and tenant isolation rather than reimplementing them. A tool cannot reach data your credentials cannot.

Read-first. Inventory, expiry and renewal status need certs:read. Opening a renewal needs certs:renew, explicitly. Over OAuth only certs:read is available at all, so an assistant connected by a person can read and nothing else.

Approval stays human. No MCP tool approves a renewal, because no token can. An assistant can prepare work; a person authorises spending.

Seven, shaped around questions rather than around endpoints.

Tool Answers
nextpki_whoami Which tenant and scopes am I working with
nextpki_list_certificates What is in the inventory
nextpki_expiring_certificates What expires in the next N days
nextpki_get_certificate Everything about one certificate
nextpki_list_renewals What renewals exist, in which state
nextpki_get_renewal Why one renewal is where it is
nextpki_request_renewal Open a renewal request, needs certs:renew

stdio is one process per client, started by the client itself: Claude Code, Codex, editors. It runs on your machine and authenticates with a static API token from the environment. Simple, and appropriate, because the process and the token are both yours.

Streamable HTTP is one server for many clients. It holds no credentials of its own for user data: every request carries its own bearer token, and the server builds a per-request session bound to that token. A shared server with one token would be a tenant leak, so a server-side token is refused outright in this mode.

With an authorization server configured, the HTTP transport accepts only OAuth tokens. That is deliberate: leaving the static-token path open alongside it would leave a weaker route in place, and a weaker route that exists is the one an attacker uses.

Nothing you have to implement, but two behaviours are worth knowing.

An access token issued for the MCP server is rejected by the API with 401. That is the audience binding working: the token names the MCP server, not the API. The server exchanges it internally for a short-lived API token and records the exchange in the audit log. Details in OAuth for assistants.

Reusing a rotated refresh token revokes the whole grant, so a client that retries with an old token loses its access rather than getting a fresh one. Treat invalid_grant on refresh as “authorize again”.

A subject or SAN is whatever the requester put in it. Someone can obtain a certificate whose Common Name reads ignore previous instructions and …, and that string lands in an assistant’s context looking like it came from a trusted source.

This is not hypothetical for this product specifically: CT-discovered certificates are issued by third parties for domains you own, so the content is genuinely outside your control.

What the server does about it:

  • Every tool response that carries certificate-derived strings is prefixed with an explicit notice that the values are data, not instructions, and that they may contain text crafted to look like instructions.
  • Tool output alone never authorises a write. Writes need an explicit scope, and certs:renew is not available over OAuth at all.
  • Approval remains a human action in the console.

If you build your own MCP server against the NextPKI API, do the same: treat every string from the inventory as hostile input rather than instructions. Marking the boundary between your instructions and fetched data is the part that is easy to forget and hard to retrofit.

The order of further tools depends on what people actually want to ask. If you have a use case, a Slack workflow, an internal assistant, a CI agent, describing it affects what gets built next.