Skip to content

The check inventory

passmcp runs 131 checks across 9 phases.

22 of them apply only to a server that is a program rather than a URL, and replace the ones that have no meaning over a pipe. A run reports every check it did not make, by id and with the reason, rather than leaving it out.

130 of those are fixed, and 1 is a family whose id is built at run time — one check per value the run encounters, marked * below.

This file is generated from the source: every check is created through (*Session).check(id, title), and this table is those call sites. CI fails when it drifts, so the figure passmcp publishes is the figure it implements.

A check may be reached from more than one branch — a handshake can fail in several ways and report the same id. The count is of distinct ids, because that is what a reader sees in a report.

net — 6 checks

Check What it looks for
net.dns Hostname resolves
net.scheme Endpoint uses HTTPS
net.tcp TCP connection
net.tls TLS handshake and certificate
net.tls.cert Certificate validity window
net.tls.version TLS version is 1.2 or newer

discovery — 16 checks

Check What it looks for
discovery.as Authorization server metadata (RFC 8414 / OIDC)
discovery.as.grants Grant types advertised
discovery.as.https Authorization server uses HTTPS
discovery.as.pkce PKCE S256 advertised
discovery.assemble Assemble discovery
discovery.challenge WWW-Authenticate challenge
discovery.challenge.scope Challenge advertises required scope
discovery.creds_unused Credentials supplied to an open server
discovery.dpop Proof-of-possession tokens (DPoP, RFC 9449)
discovery.enterprise_managed Enterprise-Managed Authorization (ID-JAG)
discovery.first_contact Unauthenticated first contact
discovery.override Discovery bypassed by --token-url
discovery.override.build Override endpoints
discovery.prm Protected resource metadata
discovery.prm.resource PRM resource matches endpoint
discovery.registration Client registration path

auth — 10 checks

Check What it looks for
auth.mode Credentials
auth.registration Client identity
auth.rejects_garbage Server rejects an invalid token
auth.source.* (title computed at run time) — one per value encountered
auth.token Token acquisition
auth.token.expiry Token lifetime
auth.token.scope Granted scope covers requested scope
auth.token.type Token type
auth.unauthenticated_tools Tools reachable without credentials
auth.wrong_audience Server rejects a token minted for another resource

handshake — 8 checks

Check What it looks for
handshake.capabilities Capabilities advertised
handshake.initialize initialize succeeds
handshake.instructions Server instructions
handshake.protocol_era Protocol generation
handshake.protocol_version Negotiated protocol version
handshake.server_info Server identifies itself
handshake.session Mcp-Session-Id issued
handshake.stateless Stateless session setup

protocol — 19 checks

Check What it looks for
protocol.accept_header Request without Accept header
protocol.bogus_session Unknown session id is rejected
protocol.deprecated_features Removed mechanisms are gone
protocol.extensions Advertised extensions
protocol.get_stream GET on the MCP endpoint
protocol.id_echo Response id matches request id
protocol.invalid_params tools/call without a name is rejected
protocol.malformed_json Malformed JSON is rejected
protocol.mrtr Requests for client input are answerable
protocol.origin A foreign Origin is rejected
protocol.ping (title computed at run time)
protocol.routing_headers Mirrored routing headers are validated
protocol.tasks.capability Task methods require the declared capability
protocol.tasks.lifecycle A task reaches a terminal state and keeps it
protocol.tasks.undeclared No task is returned to a client that did not ask for one
protocol.tasks.unknown_id An unknown task id is refused
protocol.unknown_method Unknown method returns -32601
protocol.unknown_tool Unknown tool is reported
protocol.version_header Bad MCP-Protocol-Version is rejected

catalog — 30 checks

Check What it looks for
catalog.baseline The catalogue is the one that was approved
catalog.budget.tokens Catalogue fits a context budget
catalog.cache_hints The catalogue says whether it can be cached
catalog.empty Server exposes something
catalog.names.confusable Names use a single script
catalog.personal_data (title computed at run time)
catalog.prompts.descriptions Prompts and arguments are described
catalog.prompts.list prompts/list
catalog.resources.list resources/list
catalog.resources.mime Resources declare mimeType
catalog.resources.templates resources/templates/list
catalog.resources.uris Resource URIs are absolute
catalog.semantic.ambiguity Parameters are described well enough to use
catalog.text.comments Catalog text carries no hidden comments
catalog.text.cross_server_shadowing No description governs another configured server's tool
catalog.text.encoded Catalog text is written, not encoded
catalog.text.hidden Catalog text has nothing hidden in it
catalog.text.instructions Catalog text describes rather than instructs
catalog.text.secret_paths Catalog text names no credential locations
catalog.text.shadowing Catalog text governs only its own tool
catalog.tools.annotation_honesty readOnlyHint agrees with what the tool says it does
catalog.tools.annotations Tools declare behaviour annotations
catalog.tools.descriptions Every tool has a useful description
catalog.tools.idempotency Tools say whether a repeated call is safe
catalog.tools.input_schema inputSchema is a JSON Schema object
catalog.tools.list tools/list
catalog.tools.output_schema Tools declare outputSchema
catalog.tools.title Tools have a human title
catalog.tools.unique Tool names are unique
catalog.toxic_combination No tool pair reads private data and sends it out

execution — 9 checks

Check What it looks for
execution.content Results validate against outputSchema
execution.error_guidance Rejected calls say how to succeed
execution.output_injection Tool results describe rather than instruct
execution.payload_size Results leave room for the conversation
execution.policy Safety policy
execution.prompts Prompt rendering
execution.resources Resource reads
execution.tools Tool invocations
execution.validation Tools reject missing required arguments

performance — 6 checks

Check What it looks for
performance.concurrency (title computed at run time)
performance.ping (title computed at run time)
performance.rate_limit Server rate-limits an unthrottled burst
performance.throttle Burst was throttled
performance.tools Tool latency profile
performance.warmup Cold vs warm call

resilience — 5 checks

Check What it looks for
resilience.session_reinit Client recovers from a lost session
resilience.soak_memory Resident memory over a long run of calls
resilience.stateless Requests do not depend on the connection
resilience.token_refresh Token source can renew
resilience.upstream_down Tool calls with every upstream unreachable

a2a — 4 checks

These run only under passmcp a2a check, against an agent that speaks the Agent2Agent protocol rather than MCP. They are not a phase of an MCP run: they read the agent's Agent Card and make one unauthenticated read, and the id names the protocol because that is the first thing a reader needs to know about them.

Check What it looks for
a2a.card_schema Agent Card is a valid A2A v1 card
a2a.card_signature Agent Card signature verifies
a2a.transport Agent Card served over HTTPS
a2a.unauthenticated Agent refuses requests without credentials

egress — 2 checks

These run only when the server is a program and --watch-egress was given. They belong to the resilience phase, at the end of the run, because where a server went is only fully answered once it has had the whole run to go there. The id names the observation rather than the phase, because that is what a reader is looking for.

Check What it looks for
egress.hosts Where the server connected
egress.undeclared_host The server went only where it was expected to

fs — 2 checks

These run only when the server is a program and --plant-canaries was given. They belong to the resilience phase: the decoys are planted before the process starts and read back after it ends, so the answer is only complete once the run is. The id names what was watched rather than the phase, because that is what a reader is looking for.

Check What it looks for
fs.canary_exfiltrated Nothing planted left the machine
fs.credential_probe The server left the planted credentials alone

stdio — 12 checks

These run only when the server is a program rather than a URL. They belong to the connectivity and resilience phases, not to a phase of their own: a pipe has no name to resolve and no session to lose, so they take the place of the checks that do.

Check What it looks for
stdio.alive Server survived the run
stdio.bind_all Server listens on no public interface
stdio.clean_exit Server stopped when its input closed
stdio.environment Environment handed to the server
stdio.launch_config Launch commands carry no shell, download or secret
stdio.no_zombie The server left nothing running
stdio.post_init_connections No connection nobody asked for, after the handshake
stdio.post_init_processes Processes started after the handshake
stdio.post_init_writes No writes outside the working directory, after the handshake
stdio.process Server process is running
stdio.stderr What the server logged
stdio.stdout_clean Nothing but MCP messages on stdout

supply — 2 checks

These run only when the server is a program, and read the file rather than ask the server anything. They belong to the connectivity phase, which is where passmcp establishes what it is talking to; the id names what was read because that is what a reader is looking for.

Check What it looks for
supply.buildinfo What the server binary is made of
supply.provenance The binary can be traced to a commit