Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Requirements — 2026-07-28

Every normative clause of the 2026-07-28 specification that the validator’s registry carries — 501 in all, 181 judged from a recorded trace and 320 excluded with the reason below. A report names a clause by the ID used as each heading here; each entry quotes the specification verbatim and links to the published text. mcp-trace-validator requirements --revision 2026-07-28 --format json prints the same data as JSON.

BASE

BASE-041

MUST · binds the client and server

Cross-cutting concerns like logging and argument completion All implementations MUST support the base protocol, versioning, and the message patterns.

basic/index

Excluded. The umbrella clause the BASE area mechanizes requirement-by-requirement; it has no observable beyond its constituents. Same role as BASE-012 at 2025-11-25, widened by this revision from ‘base protocol and lifecycle management’ to ‘base protocol, versioning, and the message patterns’.

BASE-042

MUST · binds the client and server

All messages between MCP clients and servers MUST follow the JSON-RPC 2.0 specification.

basic/index#messages

Judged by base.jsonrpc-version.

BASE-043

MUST · binds the client and server

Requests MUST include a string or integer ID.

basic/index#requests

Judged by base.request-id-type.

BASE-044

MUST NOT · binds the client and server

Unlike base JSON-RPC, the ID MUST NOT be null.

basic/index#requests

Judged by base.request-id-not-null.

BASE-045

MUST NOT · binds the client and server

The request ID MUST NOT match the ID of any other request the sender has issued and not yet received a response for.

basic/index#requests

Judged by base.request-id-unique-in-flight.

BASE-046

MUST · binds the client and server

Result responses MUST include the same ID as the request they correspond to.

basic/index#result-responses

Judged by base.result-id-matches.

BASE-047

MUST · binds the client and server

Result responses MUST include a result field.

basic/index#result-responses

Judged by base.result-field.

BASE-048

MUST · binds the client and server

The result MUST include a resultType field to indicate the type of the result.

basic/index#result-responses

Judged by base.result-type-present.

BASE-049

MUST · binds the client

The set of supported ResultType values MUST be created from the set defined in the core protocol and include any additional values of supported extensions that are advertised via capabilities.

basic/index#result-responses

Excluded. The client’s set of supported ResultType values is internal state assembled from the core protocol plus its advertised extensions; a trace shows the values a server sent, never the set the client was willing to accept.

BASE-050

MUST · binds the client

A resultType of any value unrecognized by the client MUST be considered invalid.

basic/index#result-responses

Excluded. What a client ‘considers invalid’ is internal judgment. The observable consequence — a client refusing to proceed — is client conduct after receipt, outside a server-side trace, and indistinguishable from any other reason it stopped.

BASE-051

MUST · binds the client

For backward compatibility with servers implementing earlier protocol versions, which do not include resultType, clients MUST treat an absent resultType as "complete".

basic/index#result-responses

Excluded. The backward-compatibility rule binds the client’s interpretation of an absent field, which leaves no wire artifact: the trace records that resultType was absent, not that the client read it as complete.

BASE-052

MUST · binds the client and server

Error responses MUST include the same ID as the request they correspond to (except in error cases where the ID could not be read due a malformed request).

basic/index#error-responses

Judged by base.error-id-matches.

BASE-053

MUST · binds the client and server

Error responses MUST include an error field with a code and message.

basic/index#error-responses

Judged by base.error-shape.

BASE-054

MUST · binds the client and server

Error codes MUST be integers.

basic/index#error-responses

Judged by base.error-code-integer.

BASE-055

MUST NOT · binds the client and server

New codes MUST NOT be allocated in this sub-range

basic/index#error-codes

Excluded. Binds allocation — assigning a new meaning to a code in -32000..-32019 — which is an act of whoever defines codes, not a message. A code observed on the wire carries no record of when or by whom it was allocated, so a legacy code in use is indistinguishable from a newly allocated one. Its use is the sentence’s other half, BASE-083, which is a SHOULD NOT and is checked at that level: until 2026-10-04 this entry carried both halves at MUST NOT and reported every use of -32000 as a MUST failure.

BASE-083

SHOULD NOT · binds the client and server

new implementations SHOULD NOT use codes from this sub-range at all.

basic/index#error-codes

Judged by base.error-code-legacy-subrange.

BASE-056

MUST NOT · binds the client and server

Apart from -32002 (see below), receivers MUST NOT assume any specific meaning for these codes.

basic/index#error-codes

Excluded. What a receiver assumes about a legacy code’s meaning is internal; only conduct following from the assumption could surface, and attributing it requires the assumption. Same boundary as BASE-025 for reserved _meta keys.

BASE-057

MUST NOT · binds the client and server

Implementations MUST NOT emit any code from this sub-range that is not defined by this specification and MUST use defined codes only with their specified meanings.

basic/index#error-codes

Judged by base.error-code-reserved-subrange.

BASE-058

MUST NOT · binds the client and server

Implementations of this protocol version MUST NOT emit these codes:

basic/index#error-codes

Judged by base.error-code-withdrawn.

BASE-059

SHOULD · binds the client

Clients SHOULD still accept -32002 from servers implementing earlier versions.

basic/index#error-codes

Excluded. Client-side acceptance of a legacy code is internal handling; the trace records the -32002 a server sent, not whether the client honoured it. The emitting side is judged by BASE-058.

BASE-060

SHOULD · binds the client and server

New error codes for purposes not defined by this specification SHOULD be allocated outside the JSON-RPC reserved range (-32768 to -32000); the remainder of the integer space is available for application-defined errors.

basic/index#error-codes

Judged by base.error-code-application-range.

BASE-061

MUST NOT · binds the client and server

The receiver MUST NOT send a response.

basic/index#notifications

Excluded. A response to a notification carries no correlating ID, so it is indistinguishable on the wire from any other unsolicited response; unsolicited responses are flagged by base.result-id-matches and base.error-id-matches. Same reasoning as BASE-011 at 2025-11-25.

BASE-062

MUST NOT · binds the client and server

Notifications MUST NOT include an ID.

basic/index#notifications

Judged by base.notification-no-id.

BASE-063

MUST NOT · binds the server

Servers MUST NOT rely on prior requests over the same connection to establish context (e.g., capabilities, protocol version, client identity).

basic/index#statelessness

Excluded. Reliance is internal reasoning. A server that answers correctly may or may not have consulted prior requests, and one that errors may have done so for any reason; the trace shows the answer, not the inference behind it. The adjacent observable is that every request carries its own context, judged by BASE-030.

BASE-064

SHOULD · binds the server

Servers SHOULD be prepared to handle requests associated with multiple tasks, threads, or conversations.

basic/index#statelessness

Excluded. Preparedness is a property of the server’s implementation, not of any session it took part in; a trace that happens to interleave conversations evidences capability, while one that does not evidences nothing.

BASE-065

SHOULD NOT · binds the server

Servers SHOULD NOT require that a client reuse the same connection or process to perform related operations.

basic/index#statelessness

Excluded. Falsifying this needs a server refusing an operation because it arrived on a different connection — two correlated connections in one recording, which the trace vocabulary does not span: each recorded session is one transport.

BASE-066

SHOULD NOT · binds the client

Clients SHOULD NOT use an individual task, thread, or conversation as the lifetime boundary for the stdio process.

basic/index#statelessness

Excluded. Process lifetime is host-OS conduct outside the trace event vocabulary — transport-open/close/abort record that a transport ended, not what the client tied its lifetime to. Same boundary as LIFE-014 at 2025-11-25.

BASE-067

MUST · binds the client

State that needs to span multiple requests (e.g., long-running tasks, application-level handles) MUST be referenced by an explicit identifier the client passes on each request.

basic/index#statelessness

Excluded. Which state ‘needs to span multiple requests’ is server-internal; the trace shows the arguments a client passed, not whether they carried everything the server required. A violation surfaces only as the server failing for some other stated reason.

BASE-068

SHOULD NOT · binds the client and server

Implementations using an HTTP-based transport SHOULD conform to this specification, whereas implementations using STDIO transport SHOULD NOT follow this specification, and instead retrieve credentials from the environment.

basic/index#auth

Excluded. Credential retrieval from the environment is process-local conduct with no wire footprint, and the HTTP half defers to the authorization specification, whose clauses are entered on its own pages: AUTH-086 and AUTH-087 restate this sentence there, and the challenge clauses a recording can judge carry checks. Same decision as BASE-085 at 2025-11-25.

BASE-069

MUST · binds the client and server

Implementations MUST support at least 2020-12 and SHOULD document which additional dialects they support Recommendation:

basic/index#schema-dialect

Excluded. Dialect support is validation behavior inside each implementation; a trace shows schemas exchanged, not which dialects the receiver could handle. Same reasoning as BASE-013 at 2025-11-25.

BASE-070

MUST · binds the client and server

Clients and servers MUST support JSON Schema 2020-12 for schemas without an explicit $schema field Clients and servers MUST validate schemas according to their declared or default dialect.

basic/index#implementation-requirements

Excluded. Dialect support and validation are behavior inside each implementation; a trace shows schemas exchanged, not how the receiver processed them. Same reasoning as BASE-013/BASE-014 at 2025-11-25.

BASE-071

MUST · binds the client and server

They MUST handle unsupported dialects gracefully by returning an appropriate error indicating the dialect is not supported.

basic/index#implementation-requirements

Excluded. Graceful handling is receiver conduct; the trace would show an error, but not that it was raised for an unsupported dialect rather than any other malformed-schema reason. Same reasoning as BASE-015 at 2025-11-25.

BASE-072

SHOULD · binds the client and server

Clients and servers SHOULD document which schema dialects they support

basic/index#implementation-requirements

Excluded. Documentation is a property of the project, not of any session. Same reasoning as BASE-016 at 2025-11-25.

BASE-073

MUST · binds the client and server

Schemas MUST be valid according to their declared or default dialect

basic/index#schema-validation

Judged by base.schemas-valid-for-dialect.

BASE-074

MUST NOT · binds the client and server

Implementations MUST NOT automatically dereference $ref values that resolve to a network URI.

basic/index#$ref-resolution

Excluded. Whether an implementation dereferenced a $ref is an outbound fetch to a third party, not an MCP message; nothing in the recorded session distinguishes a resolved reference from an unresolved one.

BASE-075

MUST · binds the client and server

Implementations MAY offer an opt-in mode that fetches non-local $refs but it MUST be disabled by default and SHOULD enforce an allowlist of hosts or at minimum reject loopback, link-local, and private network addresses, apply timeouts and size limits, and log dereferenced URIs.

basic/index#$ref-resolution

Excluded. The default state of an opt-in mode, its allowlist, timeouts and logging are all implementation configuration; none appears in an MCP session.

BASE-076

SHOULD · binds the client and server

Schemas that fail to validate due to an unresolved external $ref SHOULD be rejected rather than silently treated as permissive.

basic/index#$ref-resolution

Excluded. Rejection happens inside the receiver’s schema validation; the trace shows the schema that was sent, not what the receiver did with an unresolvable reference.

BASE-077

SHOULD · binds the client and server

Implementations SHOULD apply reasonable bounds, such as a maximum schema depth, a cap on the total number of subschemas, or a per-validation time budget, to prevent a malicious schema from acting as a Denial-of-Service vector against the validator.

basic/index#composition-keyword-resource-use

Excluded. Depth caps, subschema counts and time budgets are validator-internal resource policy, invisible in the messages exchanged.

BASE-088

SHOULD · binds the client and server

Implementors are RECOMMENDED to use JSON Schema 2020-12.

basic/index#schema-dialect

Judged by base.schemas-use-2020-12.

BASE-025

MUST NOT · binds the client and server

Certain key names are reserved by MCP for protocol-level metadata, as specified below; implementations MUST NOT make assumptions about values at these keys.

basic/index#_meta

Excluded. What an implementation assumes is internal; only conduct that follows from an assumption could surface, and attributing it requires the assumption. Same clause and same reasoning as BASE-018 at 2025-11-25.

BASE-026

MUST · binds the client and server

If specified, MUST be a series of labels separated by dots (.), followed by a slash (/).

basic/index#_meta

Judged by base.meta-key-format.

BASE-027

MUST · binds the client and server

Labels MUST start with a letter and end with a letter or digit; interior characters can be letters, digits, or hyphens (-).

basic/index#_meta

Judged by base.meta-key-format.

BASE-028

SHOULD · binds the client and server

Implementations SHOULD use reverse DNS notation (e.g., com.example/ rather than example.com/).

basic/index#_meta

Excluded. Whether a syntactically valid prefix is reverse-DNS for its author cannot be decided without knowing the author’s domain. Same clause and same reasoning as BASE-021 at 2025-11-25.

BASE-029

MUST · binds the client and server

Unless empty, MUST begin and end with an alphanumeric character ([a-z0-9A-Z]).

basic/index#_meta

Judged by base.meta-key-format.

BASE-030

MUST · binds the client

Client requests carry the following io.modelcontextprotocol/* fields in meta; fields marked as required MUST be included on every request.

basic/index#_meta

Judged by meta.required-request-fields.

BASE-031

MUST · binds the server

A request missing any required field is malformed; the server MUST reject it with JSON-RPC error code -32602 (Invalid params).

basic/index#_meta

Judged by meta.missing-required-field-rejected.

BASE-032

MUST · binds the server

On HTTP, the response status MUST be 400 Bad Request.

basic/index#_meta

Judged by meta.missing-required-field-http-status.

BASE-033

SHOULD · binds the client

Clients SHOULD include io.modelcontextprotocol/clientInfo on every request unless specifically configured not to do so.

basic/index#_meta

Judged by meta.client-info-on-requests.

BASE-034

MUST NOT · binds the server

A server MUST NOT rely on capabilities the client has not declared.

basic/index#_meta

Judged by meta.no-undeclared-capability-reliance.

BASE-035

MUST · binds the server

If processing a request requires a capability the client did not include in io.modelcontextprotocol/clientCapabilities, the server MUST return a MissingRequiredClientCapabilityError (-32021) whose data.requiredCapabilities lists the missing capabilities.

basic/index#_meta

Judged by meta.missing-capability-error.

BASE-036

MUST · binds the server

On HTTP, the response status MUST be 400 Bad Request.

basic/index#_meta

Judged by meta.missing-capability-http-status.

BASE-037

SHOULD · binds the server

Servers SHOULD include the following io.modelcontextprotocol/* field in every result’s meta, unless specifically configured not to do so, to identify themselves without relying on any prior connection state:

basic/index#_meta

Judged by meta.server-info-on-results.

BASE-038

SHOULD NOT · binds the client and server

Implementations SHOULD NOT use them to change the behavior of the client or server, and SHOULD NOT rely on them for security decisions.

basic/index#_meta

Excluded. Self-reported identity is advisory; whether a peer let it change behavior or drive a security decision is internal reasoning with no wire footprint, the same boundary BASE-025 draws for reserved-key assumptions.

BASE-039

MUST · binds the server

On notifications delivered via a [subscriptions/listen][subscriptions-listen] stream, the server MUST include io.modelcontextprotocol/subscriptionId in meta so the client can correlate the notification with the originating subscription request.

basic/index#_meta

Judged by meta.subscription-id-present.

BASE-040

MUST · binds the client and server

When present, their values MUST follow W3C Trace Context and W3C Baggage formats respectively.

basic/index#_meta

Judged by meta.trace-context-format.

BASE-078

MUST · binds the client

Clients that support rendering icons MUST support at least the following MIME types:

basic/index#icons

Excluded. Icon rendering support is client-internal capability with no wire footprint; the conditional premise (that the client renders icons) is equally invisible. Same reasoning as BASE-022 at 2025-11-25.

BASE-079

SHOULD · binds the client

image/png - PNG images (safe, universal compatibility) image/jpeg (and image/jpg) - JPEG images (safe, universal compatibility) Clients that support rendering icons SHOULD also support:

basic/index#icons

Excluded. Extends the same client-internal rendering-support premise as the MUST above it; neither the support nor its absence reaches the wire.

BASE-080

MUST · binds the client

Consumers of icon metadata MUST take appropriate security precautions when handling icons to prevent compromise:

basic/index#icons

Excluded. The umbrella for consumer-side icon hygiene (fetch policy, size limits, origin checks) — all consumer-internal conduct after the recorded session ends. Same reasoning as BASE-023 at 2025-11-25.

BASE-081

MUST · binds the client

Clients MUST reject icon URIs that use unsafe schemes and redirects, such as javascript:, file:, ftp:, ws:, or local app URI schemes.

basic/index#icons

Excluded. Rejection is client-side handling after receipt; the trace records the icon metadata served, not what the client did with it. Same reasoning as BASE-024 at 2025-11-25.

BASE-084

MUST NOT · binds the server

Servers MUST NOT initiate JSON-RPC requests, and clients do not send JSON-RPC responses.

basic/patterns/index

Judged by transport.no-independent-server-requests.

TRAN

TRAN-050

MUST · binds the server

The server MUST provide a single HTTP endpoint path (hereafter referred to as the MCP endpoint) that supports POST.

basic/transports/streamable-http

Excluded. Endpoint topology — how many paths a server exposes and which methods each accepts — is deployment configuration; a recorded session shows one endpoint being used, never the set that exists. Same reasoning as TRAN-006 at 2025-11-25.

TRAN-051

MUST · binds the server

Servers MUST validate the Origin header on all incoming connections to prevent DNS rebinding attacks.

basic/transports/streamable-http#security-&-endpoint

Excluded. Origin validation is server-internal policy applied before any MCP message; the trace records admitted sessions, not the requests a policy refused. Same reasoning as TRAN-002 at 2025-11-25; the everything server’s policy middleware is tested directly in http_policy.rs.

TRAN-052

MUST · binds the server

If the Origin header is present and invalid, servers MUST respond with HTTP 403 Forbidden.

basic/transports/streamable-http#security-&-endpoint

Excluded. A refused request never becomes an MCP session, so the 403 it drew is outside what the tap records. Same reasoning as TRAN-007 at 2025-11-25; enforced in code and covered by the server’s own policy tests.

TRAN-053

SHOULD · binds the server

When running locally, servers SHOULD bind only to localhost (127.0.0.1) rather than all network interfaces (0.0.0.0).

basic/transports/streamable-http#security-&-endpoint

Excluded. Bind address is process configuration with no wire footprint. Same reasoning as TRAN-008 at 2025-11-25.

TRAN-054

SHOULD · binds the server

Servers SHOULD implement proper authentication for all connections.

basic/transports/streamable-http#security-&-endpoint

Excluded. Whether authentication is properly implemented is not decidable from one session’s headers: the client’s credential is never recorded, and the server’s validation of it is internal. What a recording does show — the challenge a protected server answers with — is judged under the authorization pages’ own clauses (AUTH-097, AUTH-124, AUTH-129–AUTH-133). Same reasoning as TRAN-009 at 2025-11-25.

TRAN-055

MUST · binds the client

Every JSON-RPC message sent from the client MUST be a new HTTP POST request to the MCP endpoint.

basic/transports/streamable-http#sending-messages

Excluded. Adds to TRAN-056’s verb obligation that each message ride a new POST to the MCP endpoint. A POST body is one JSON value, which a recorder writes as one payload, so more than one message in a POST is a non-object body — TRAN-059 judges that. What remains — that the request was new rather than reused, and was addressed to the MCP endpoint — leaves no trace: the endpoint is not recorded. Same split as TRAN-024/TRAN-049 at 2025-11-25.

TRAN-056

MUST · binds the client

The client MUST use HTTP POST to send JSON-RPC messages.

basic/transports/streamable-http#sending-messages

Judged by transport.client-messages-use-post.

TRAN-057

MUST · binds the client

The client MUST include an Accept header listing both application/json and text/event-stream as supported content types.

basic/transports/streamable-http#sending-messages

Judged by transport.client-post-accept-header.

TRAN-058

MUST · binds the client

The client MUST include the request metadata headers on each POST request.

basic/transports/streamable-http#sending-messages

Judged by transport.request-metadata-headers.

TRAN-059

MUST · binds the client

The body of the HTTP POST MUST be a single JSON-RPC request or notification.

basic/transports/streamable-http#sending-messages

Judged by transport.http-post-single-message.

TRAN-060

MUST NOT · binds the client

The client MUST NOT send JSON-RPC responses.

basic/transports/streamable-http#sending-messages

Judged by transport.client-no-responses.

TRAN-061

MUST · binds the server

If the server accepts it, the server MUST return HTTP status code 202 Accepted with no body.

basic/transports/streamable-http#sending-messages

Judged by transport.accepted-input-status.

TRAN-062

MUST · binds the server

If the server cannot accept it, it MUST return an HTTP error status code (e.g., 400 Bad Request).

basic/transports/streamable-http#sending-messages

Excluded. Which inputs a server declines to accept, and why, is server-internal admission policy; a declined request produces no MCP message to judge. Same reasoning as TRAN-028 at 2025-11-25.

TRAN-063

MUST · binds the server

If the body is a JSON-RPC request, the server MUST return either Content-Type: application/json (a single JSON object) or Content-Type: text/event-stream (an SSE response stream).

basic/transports/streamable-http#sending-messages

Judged by transport.success-content-type.

TRAN-064

MUST · binds the client

The client MUST support both.

basic/transports/streamable-http#sending-messages

Excluded. Client support for both response shapes is internal capability: a session that received one shape evidences nothing about the other. Same reasoning as TRAN-030 at 2025-11-25.

TRAN-065

MUST · binds the server

These notifications MUST relate to the originating client request.

basic/transports/streamable-http#receiving-messages

Excluded. Relatedness is semantic. A notification carries no id tying it to a request, so the trace cannot decide whether it ‘relates to’ the originating one. Same reasoning as TRAN-035 at 2025-11-25.

TRAN-066

MUST NOT · binds the server

The server MUST NOT send independent JSON-RPC requests on this stream.

basic/transports/streamable-http#receiving-messages

Judged by transport.no-independent-server-requests.

TRAN-067

SHOULD · binds the server

The final JSON-RPC response SHOULD terminate the stream.

basic/transports/streamable-http#receiving-messages

Excluded. Stream termination after the final response is SSE framing; the trace records messages and transport lifecycle, not whether the stream closed promptly afterwards. Same reasoning as TRAN-036 at 2025-11-25.

TRAN-068

SHOULD · binds the server

When initiating an SSE stream, servers SHOULD include the X-Accel-Buffering: no header in the HTTP response.

basic/transports/streamable-http#receiving-messages

Judged by transport.accel-buffering-header.

TRAN-069

MUST · binds the server

Closing the SSE response stream MUST be treated by the server as cancellation of that request.

basic/transports/streamable-http#cancellation

Excluded. How a server treats a closed stream is internal: cancellation is a decision, and the trace shows only that the transport ended. The observable consequence — messages sent afterwards — is TRAN-070’s business.

TRAN-070

MUST NOT · binds the server

The server SHOULD stop work on the cancelled request as soon as practical and MUST NOT send any further messages for it.

basic/transports/streamable-http#cancellation

Judged by transport.no-messages-after-cancellation.

TRAN-071

MUST · binds the client

Every POST request to the MCP endpoint MUST include an MCP-Protocol-Version header.

basic/transports/streamable-http#protocol-version-header

Judged by transport.protocol-version-header-present.

TRAN-072

MUST · binds the client

MCP-Protocol-Version: 2026-07-28 The header value MUST match the io.modelcontextprotocol/protocolVersion field carried in the request body’s meta.

basic/transports/streamable-http#protocol-version-header

Judged by transport.protocol-version-header-matches-body.

TRAN-073

MUST · binds the server

If the values do not match, the server MUST reject the request with 400 Bad Request and a HeaderMismatch JSON-RPC error (see Server Validation).

basic/transports/streamable-http#protocol-version-header

Judged by transport.version-mismatch-rejected.

TRAN-074

MUST · binds the server

If the server does not implement the requested protocol version (whether the version is unknown to the server, or is a known version the server has chosen not to support), it MUST respond with 400 Bad Request and an [UnsupportedProtocolVersionError][unsupported-version] listing its supported versions.

basic/transports/streamable-http#protocol-version-header

Judged by transport.unsupported-version-error-http, transport.unsupported-version-status.

TRAN-075

MUST · binds the server

If the server does not implement the requested RPC method, it MUST respond with 404 Not Found and a JSON-RPC error with code -32601 (Method not found).

basic/transports/streamable-http#protocol-version-header

Judged by transport.unknown-method-404.

TRAN-076

MUST · binds the server

A server that does not support such clients MUST reject a request without the header per Server Validation.

basic/transports/streamable-http#protocol-version-header

Excluded. Whether a server supports header-less clients is its own policy; a trace shows how it answered one request, not the policy behind it. The rejection shape, when it happens, is judged by TRAN-073.

TRAN-077

MUST · binds the client

If the Mcp-Name source value cannot be safely represented as a plain ASCII header value, clients MUST encode it using the Base64 sentinel format described in Value Encoding.

basic/transports/streamable-http#standard-request-headers

Judged by transport.header-value-encoding.

TRAN-078

MUST · binds the client

While the use of x-mcp-header is optional for servers, clients MUST support this feature.

basic/transports/streamable-http#custom-headers-from-tool-parameters

Excluded. Client support for x-mcp-header is internal capability. Its observable consequence — mirroring designated values into headers — is the next clause and is checked there.

TRAN-079

MUST · binds the client

When a server’s tool definition includes x-mcp-header annotations, conforming clients MUST mirror the designated parameter values into HTTP headers.

basic/transports/streamable-http#custom-headers-from-tool-parameters

Judged by transport.x-mcp-header-mirrored, transport.x-mcp-header-value-mirrored.

TRAN-080

MUST NOT · binds the server

Constraints on x-mcp-header values: MUST NOT be empty; MUST match HTTP field-name token syntax (1*tchar, RFC 9110 Section 5.1); MUST NOT contain control characters, including carriage return (CR, \r) or line feed (LF, \n); MUST be case-insensitively unique among all x-mcp-header values in the inputSchema; MUST only be applied to parameters with primitive types (integer, string, boolean).

basic/transports/streamable-http#schema-extension

Judged by transport.x-mcp-header-name-valid.

TRAN-081

MUST · binds the client

Constraints on x-mcp-header values: Integer values MUST be within the safe range for JavaScript (−253+1 to 253−1)

basic/transports/streamable-http#schema-extension

Judged by tools.x-mcp-header-integer-range.

TRAN-082

MUST NOT · binds the server

The chain MUST NOT pass through items (or any other array keyword), composition keywords (oneOf, anyOf, allOf, not), conditional keywords (if/then/else), or $ref.

basic/transports/streamable-http#schema-extension

Judged by transport.x-mcp-header-statically-reachable.

TRAN-083

MUST · binds the client

Clients using the Streamable HTTP transport MUST reject tool definitions where any x-mcp-header value violates these constraints.

basic/transports/streamable-http#schema-extension

Judged by transport.x-mcp-header-invalid-tool-not-called.

TRAN-084

MUST · binds the client

Rejection means the client MUST exclude the invalid tool from the result of tools/list.

basic/transports/streamable-http#schema-extension

Judged by transport.x-mcp-header-invalid-tool-not-called.

TRAN-085

SHOULD · binds the client

Clients SHOULD log a warning when rejecting a tool definition, including the tool name and the reason for rejection.

basic/transports/streamable-http#schema-extension

Excluded. Logging is client-internal diagnostics with no wire footprint.

TRAN-086

MUST · binds the client

Clients MUST encode parameter values before including them in HTTP headers to ensure safe transmission and prevent injection attacks.

basic/transports/streamable-http#value-encoding

Judged by transport.header-value-encoding.

TRAN-087

MUST · binds the client

When a value cannot be safely represented as a plain ASCII header value (e.g., it contains non-ASCII characters, control characters, or has leading/trailing whitespace), clients MUST use Base64 encoding of the UTF-8 representation with the following format:

basic/transports/streamable-http#value-encoding

Judged by transport.header-value-encoding.

TRAN-088

SHOULD · binds the client

Tool and prompt names are only SHOULD-constrained to header-safe characters, so a name (or resource URI) outside the safe set is carried as:

basic/transports/streamable-http#value-encoding

Excluded. A descriptive clause explaining why names are carried encoded, not an independent obligation; the encoding rule itself is checked on the clauses above.

TRAN-089

MUST · binds the client

These markers are case-sensitive and MUST appear exactly as shown (lowercase).

basic/transports/streamable-http#value-encoding

Judged by transport.sentinel-marker-case.

TRAN-090

MUST · binds the server

Servers and intermediaries that need to inspect these values MUST decode them accordingly.

basic/transports/streamable-http#value-encoding

Excluded. Decoding is what a receiver does internally before comparison; the trace shows the encoded value on the wire and the outcome, never the decode step.

TRAN-091

MUST · binds the server

In particular, servers MUST decode an encoded Mcp-Name or Mcp-Param-{Name} value before comparing it to the corresponding request body value during Server Validation.

basic/transports/streamable-http#value-encoding

Excluded. Same internal-decode boundary as the clause above: only the comparison’s outcome reaches the wire, and that is judged by TRAN-097.

TRAN-092

MUST · binds the client

To avoid ambiguity, clients MUST also Base64-encode any plain-ASCII value that matches the sentinel pattern (i.e., starts with =?base64? and ends with ?=).

basic/transports/streamable-http#value-encoding

Judged by transport.sentinel-pattern-encoded.

TRAN-093

MUST · binds the client

When constructing a tools/call request via HTTP transport, the client MUST:

basic/transports/streamable-http#client-behavior

Excluded. The umbrella introducing the client’s tools/call construction steps; each step is a clause of its own above, and the umbrella has no observable beyond them.

TRAN-094

SHOULD · binds the client

If the server rejects a request with a HeaderMismatch error because required Mcp-Param-* headers are missing or do not match the body, the client SHOULD call tools/list to check for changes to the tool’s inputSchema, then retry the original request with the appropriate headers.

basic/transports/streamable-http#client-behavior

Excluded. Whether a client re-fetched tools/list after a HeaderMismatch is recovery conduct; a later tools/list in the same recording is equally consistent with any other reason for calling it.

TRAN-137

MUST · binds the server

Constraints on x-mcp-header values: MUST only be applied to properties that are statically reachable from the schema root: reachable via a chain consisting solely of properties keys.

basic/transports/streamable-http#schema-extension

Judged by transport.x-mcp-header-statically-reachable.

TRAN-141

MUST · binds the client

These headers are REQUIRED for compliance.

basic/transports/streamable-http#standard-request-headers

Judged by transport.request-metadata-headers.

TRAN-095

MUST · binds the server

Intermediate servers that do not recognize an Mcp-Param-{Name} header MUST forward it and otherwise ignore it, as required by the [HTTP Semantics RFC][http-semantics].

basic/transports/streamable-http#server-behavior-for-custom-headers

Excluded. Intermediary behavior: a forwarding proxy is not a party to the MCP session, and the trace records the endpoints, not the hops between them.

TRAN-096

MUST · binds the server

Servers MUST reject requests with a recognized Mcp-Param-{Name} header that contains invalid characters (see Value Encoding).

basic/transports/streamable-http#server-behavior-for-custom-headers

Judged by transport.invalid-param-header-rejected.

TRAN-097

MUST · binds the server

Any server that processes the message body MUST validate that encoded header values, after decoding if Base64-encoded, match the corresponding values in the request body.

basic/transports/streamable-http#server-behavior-for-custom-headers

Judged by transport.header-body-match-validated.

TRAN-098

MUST · binds the server

Servers MUST reject requests with a 400 Bad Request HTTP status and JSON-RPC error code -32020 (HeaderMismatch) if any validation fails.

basic/transports/streamable-http#server-behavior-for-custom-headers

Judged by transport.header-mismatch-status.

TRAN-130

MUST · binds the client

Parameter value provided | Client MUST include the header

basic/transports/streamable-http#server-behavior-for-custom-headers

Judged by transport.x-mcp-header-mirrored.

TRAN-131

MUST · binds the server

Parameter value provided | Client MUST include the header | Server MUST validate header matches body

basic/transports/streamable-http#server-behavior-for-custom-headers

Judged by transport.header-body-match-validated.

TRAN-132

MUST · binds the client

Parameter value is null | Client MUST omit the header

basic/transports/streamable-http#server-behavior-for-custom-headers

Judged by transport.x-mcp-header-null-omitted.

TRAN-133

MUST NOT · binds the server

Parameter value is null | Client MUST omit the header | Server MUST NOT expect the header

basic/transports/streamable-http#server-behavior-for-custom-headers

Judged by transport.null-param-header-not-expected.

TRAN-134

MUST · binds the client

Parameter not in arguments | Client MUST omit the header

basic/transports/streamable-http#server-behavior-for-custom-headers

Judged by transport.x-mcp-header-absent-omitted.

TRAN-135

MUST NOT · binds the server

Parameter not in arguments | Client MUST omit the header | Server MUST NOT expect the header

basic/transports/streamable-http#server-behavior-for-custom-headers

Judged by transport.absent-param-header-not-expected.

TRAN-136

MUST · binds the server

Client omits header but value is in body | Non-conforming client | Server MUST reject the request

basic/transports/streamable-http#server-behavior-for-custom-headers

Judged by transport.missing-param-header-rejected.

TRAN-099

MUST · binds the client and server

Clients and servers MUST use case-insensitive comparisons for header names.

basic/transports/streamable-http#case-sensitivity

Excluded. Case-insensitive comparison is internal string handling. The trace lowercases header names on read (EventBody::Http), so a capture cannot even preserve the casing a party compared against.

TRAN-100

MUST · binds the server

Servers that process the request body MUST reject requests where the values specified in the headers do not match the corresponding values in the request body.

basic/transports/streamable-http#server-validation

Judged by transport.header-body-match-validated.

TRAN-101

SHOULD · binds the server

When validating integer parameter values, servers SHOULD compare the header value and the body value numerically rather than as strings (e.g., 42.0 and 42 are considered equal).

basic/transports/streamable-http#server-validation

Excluded. Numeric-versus-string comparison is internal; only the comparison’s verdict reaches the wire, and that is judged by TRAN-097.

TRAN-102

MUST · binds the server

When rejecting a request due to header validation failure, servers MUST return HTTP status 400 Bad Request and MUST include a JSON-RPC error response using the following error code:

basic/transports/streamable-http#server-validation

Judged by transport.header-mismatch-status.

TRAN-103

MUST · binds the server

For headers that permit the Base64 sentinel encoding (Mcp-Name and Mcp-Param-{Name}), servers MUST decode encoded values (see Value Encoding) before comparing them to the body value.

basic/transports/streamable-http#server-validation

Excluded. Same internal-decode boundary as the earlier decode clauses: the wire shows the encoded value and the outcome, not the decoding in between.

TRAN-104

MUST · binds the server

Intermediaries MUST return an appropriate HTTP error status (e.g., 400 Bad Request) for validation failures but are not required to return a JSON-RPC error response.

basic/transports/streamable-http#server-validation

Excluded. Intermediary behavior; see the forwarding clause above. An intermediary’s HTTP error never becomes an MCP message in this session.

TRAN-105

SHOULD · binds the server

Intermediaries that enforce policy based on mirrored headers (e.g., routing or rate-limiting by tenant) SHOULD verify that the MCP-Protocol-Version header indicates a version that requires header–body validation.

basic/transports/streamable-http#server-validation

Excluded. Intermediary policy enforcement, outside the recorded session’s endpoints.

TRAN-106

SHOULD · binds the server

If the version is older or the header is absent, the intermediary SHOULD reject the request rather than trusting unvalidated header values.

basic/transports/streamable-http#server-validation

Excluded. Intermediary rejection policy, outside the recorded session’s endpoints.

TRAN-107

SHOULD · binds the client

On 400 Bad Request, the client SHOULD inspect the response body before falling back: modern servers also use 400 for [UnsupportedProtocolVersionError][unsupported-version], MissingRequiredClientCapabilityError, and header-validation failures.

basic/transports/streamable-http#backward-compatibility

Excluded. Whether the client inspected a 400 body before falling back is internal reasoning; a subsequent fallback request is equally consistent with either.

TRAN-108

SHOULD · binds the server

A server that supports only this revision and receives such traffic from an older client SHOULD respond as follows:

basic/transports/streamable-http#earlier-streamable-http-revisions

Excluded. The umbrella introducing the backward-compatibility response table; each response it prescribes is a clause of its own, and the umbrella adds no separate observable.

TRAN-109

SHOULD NOT · binds the client and server

New implementations SHOULD NOT adopt it; existing implementations SHOULD migrate to Streamable HTTP.

basic/transports/streamable-http#http+sse-transport-2024-11-05

Excluded. Adopting or migrating away from a transport is a project decision, not a property of any session.

DISC

DISC-001

MUST · binds the server

server/discover lets a client query a server’s supported protocol versions, capabilities, and identity before sending any other requests. Servers MUST implement it.

server/discover

Judged by discover.implemented.

DISC-002

SHOULD · binds the client

A client that supports both modern (per-request meta) and legacy (initialize handshake) servers SHOULD send server/discover first; see stdio: Backward Compatibility for the fallback rules.

server/discover#when-to-call

Judged by discover.dual-era-probe-first.

DISC-003

SHOULD · binds the server

meta['io.modelcontextprotocol/serverInfo']: Name and version of the server software. Servers SHOULD include this field.

server/discover#discoverresult

Judged by discover.server-info-included.

DISC-004

SHOULD NOT · binds the client

serverInfo is self-reported by the server and is not verified by the protocol. It is intended for display, logging, and debugging. Clients SHOULD NOT use it to change their behavior, and SHOULD NOT rely on it for security decisions.

server/discover#discoverresult

Excluded. Binds what the client does with serverInfo after reading it — behaviour changes and security decisions are internal reasoning, and a trace records the messages, not the inferences drawn from them. Same boundary as BASE-022’s icon-consumer clauses.

VERS

VERS-001

MUST · binds the server

If the server does not implement the requested version (whether the version is unknown to the server, or is a known version the server has chosen not to support), it MUST respond with an UnsupportedProtocolVersionError listing the versions it does support:

basic/versioning#protocol-version-negotiation

Judged by transport.unsupported-version-error.

VERS-002

SHOULD · binds the client

The client SHOULD select a mutually supported version from the supported list and retry the request, or surface an error to the user if no compatible version exists.

basic/versioning#protocol-version-negotiation

Judged by versioning.retry-uses-supported-version.

VERS-003

MUST · binds the server

Servers MUST implement server/discover.

basic/versioning#protocol-version-negotiation

Judged by discover.implemented.

VERS-004

MUST · binds the client and server

Extension identifiers MUST follow the meta key naming rules, with a mandatory prefix.

basic/versioning#extension-negotiation

Judged by versioning.extension-identifier-format.

VERS-005

MUST · binds the client and server

If one party supports an extension but the other does not, the supporting party MUST either revert to core protocol behavior or reject the request with an appropriate error.

basic/versioning#extension-negotiation

Excluded. Both permitted responses are defined by the extension, not by this specification: what “core protocol behavior” looks like for a given extension, and which error is “appropriate”, are each stated in that extension’s own document. Where an official extension’s clauses are entered (tasks and skills, beside this revision), they judge exactly that, in the extension’s own block and never scored (ADR-0023): TASK-001, for one, is this clause for the tasks extension. Judging it here, among the core’s clauses, would let an optional extension’s behaviour move the core verdict.

VERS-006

SHOULD · binds the client and server

Extensions SHOULD document their expected fallback behavior.

basic/versioning#extension-negotiation

Excluded. Binds an extension’s documentation, not either party’s messages. The subject is not even a session participant: no recorded trace can be evidence about whether a document exists.

VERS-007

SHOULD · binds the client

Clients SHOULD cache the result for the lifetime of the server process (stdio) or origin (HTTP), and MAY persist it across restarts of the same server configuration, re-probing if the cached assumption later fails.

basic/versioning#backward-compatibility-with-initialization-based-versions

Excluded. The cached value is the era determination — client-internal state, and the clause’s horizon is the server process or origin, which outlives the recorded session. The one wire-visible candidate, a repeated probe, is not evidence: the clause’s own “re-probing if the cached assumption later fails” permits it.

VERS-008

SHOULD · binds the server

A server that supports only modern versions SHOULD name the protocol versions it supports in any error it returns to an initialize request, on any transport: legacy clients have no fall-forward mechanism, and this message may be the only diagnostic they can surface to users.

basic/versioning#backward-compatibility-with-initialization-based-versions

Judged by versioning.initialize-error-names-versions.

VERS-009

SHOULD · binds the client

Modern | Legacy | Fails. The server may reject the request with an implementation-defined error, stay silent, or even process an era-ambiguous method under legacy semantics. On stdio, clients SHOULD send server/discover first to fail deterministically; the client then surfaces an actionable error to the user.

basic/versioning#compatibility-matrix

Excluded. The compatibility matrix’s modern-client, legacy-server row. Its antecedent is the server being legacy, which is exactly what an unprobed exchange fails to reveal — the row itself says such a server may reject the request, stay silent, or process it under legacy semantics — and, as for TRAN-142, a recording cannot show that its first request was the client’s first. The dual-era form of the same advice is TRAN-128, judged where a session witnesses both eras.

TRAN

TRAN-110

MUST · binds the client and server

JSON-RPC messages MUST be UTF-8 encoded.

basic/transports/index#messages

Excluded. Restates TRAN-001 at 2025-11-25, whose exclusion this project already argued and which holds unchanged: trace documents are UTF-8 by construction, so recorded messages prove nothing was mis-encoded, and absence is not evidence because capture tooling drops undecodable bytes. Violations surface as capture-time parse failures, not trace findings.

TRAN-111

MUST · binds the client and server

A binding MUST deliver client-sent requests and notifications to the server, and server-sent responses and notifications to the client.

basic/transports/index#messages

Excluded. A delivery obligation, and a trace is a record of what arrived: a message the binding failed to deliver is absent from it, and an absent message is indistinguishable from one never sent. The clause’s converse — that no other direction exists — is a separate sentence and is enforced where it is stated: TRAN-060 and TRAN-118 for client responses, TRAN-066 and TRAN-120 for server-initiated requests.

TRAN-112

MUST · binds the client and server

Implementers who choose to support custom transports MUST preserve the JSON-RPC message format, the message patterns, and the per-request metadata model.

basic/transports/index#custom-transports

Excluded. No custom transport can appear in a trace: TransportKind admits stdio and streamable-http only, so the clause’s subject has no representation in the format this engine reads. What it requires preserved is exactly what the rest of this registry checks for the two standard bindings, against which a custom transport’s capture would have to be relabelled first.

TRAN-113

SHOULD · binds the client and server

Custom transports SHOULD document their connection establishment, message framing, and cancellation patterns to aid interoperability.

basic/transports/index#custom-transports

Excluded. Binds a transport’s documentation, not its messages. Same class as VERS-006: the artefact the clause requires is a document, and no session can be evidence about whether one exists.

TRAN-114

SHOULD · binds the client and server

Custom transports that run over a reliable bidirectional byte stream (e.g., Unix domain sockets or TCP) SHOULD reuse the stdio framing rather than defining a new one: the stdio binding is just newline-delimited JSON-RPC over a byte stream, and only its process-lifecycle rules are specific to standard streams.

basic/transports/index#custom-transports

Excluded. Binds the design of a transport that cannot be recorded as itself (see TRAN-112), and the property it asks for — which framing was reused — is settled before any message exists. Restated on the stdio page as TRAN-121, with the same reason.

TRAN-115

MUST NOT · binds the client and server

Messages are delimited by newlines, and MUST NOT contain embedded newlines.

basic/transports/stdio

Excluded. Restates TRAN-002 at 2025-11-25 verbatim, and its exclusion holds unchanged: framing is enforced at capture time, the JSON Lines trace format cannot represent an embedded-newline violation, and a parseable trace is evidence the rule held.

TRAN-116

SHOULD NOT · binds the client

The client MAY capture, forward, or ignore the server’s stderr output and SHOULD NOT assume stderr output indicates error conditions.

basic/transports/stdio

Excluded. Binds an inference the client draws from stderr — and stderr is not part of the recorded message stream at all, so neither the input to that inference nor the inference itself reaches a trace. Same boundary as TRAN-003 at 2025-11-25.

TRAN-117

MUST NOT · binds the server

The server MUST NOT write anything to its stdout that is not a valid MCP message.

basic/transports/stdio

Judged by transport.stdio-server-output-valid.

TRAN-118

MUST NOT · binds the client

The client MUST NOT write anything to the server’s stdin that is not a valid MCP message.

basic/transports/stdio

Judged by transport.stdio-client-input-valid.

TRAN-119

MUST NOT · binds the client

The client MUST NOT write JSON-RPC responses.

basic/transports/stdio#sending-messages

Judged by transport.client-no-responses.

TRAN-120

MUST NOT · binds the server

The server MUST NOT write JSON-RPC requests to stdout.

basic/transports/stdio#receiving-messages

Judged by transport.no-independent-server-requests.

TRAN-121

SHOULD · binds the client and server

Custom transports built on such streams SHOULD reuse this framing and the message rules on this page; only the subprocess-specific aspects (launch, stderr, shutdown by closing the stream, process restart) need channel-specific equivalents.

basic/transports/stdio

Excluded. The same clause as TRAN-114, stated from the stdio page’s side: a custom transport has no representation in the trace format, and which framing it reused is settled before any message exists.

TRAN-122

MUST · binds the client

Clients MUST correlate these using the io.modelcontextprotocol/subscriptionId field in meta; see [SubscriptionsListenRequest][subscriptions-listen-request].

basic/transports/stdio#receiving-messages

Excluded. Binds the client’s own correlation of notifications it received — bookkeeping inside the client, which produces no message. The wire-visible half of the same mechanism, that the server tags each notification with io.modelcontextprotocol/subscriptionId, is BASE-039 and is checked.

TRAN-123

MUST · binds the client

To cancel an in-flight request, the client MUST send a notifications/cancelled notification referencing the request’s ID.

basic/transports/stdio#cancellation

Judged by transport.cancel-notification-references-request.

TRAN-124

MUST NOT · binds the server

Servers SHOULD stop work on a cancelled request as soon as practical and MUST NOT send any further messages for it.

basic/transports/stdio#cancellation

Judged by transport.no-messages-after-cancel-notification.

TRAN-125

SHOULD · binds the client

The client SHOULD initiate shutdown by: Closing the input stream to the child process (the server); Waiting for the server to exit; If the server does not exit within a reasonable time, forcibly terminating the process using the mechanism appropriate for the operating system.

basic/transports/stdio#shutdown

Excluded. Stream closure, process waits and forced termination are host-OS actions outside the trace event vocabulary — the same reason LIFE-014 excludes the 2025-11-25 shutdown sequence. A transport-close lifecycle event records that the transport ended, not which party closed which stream or what it did next.

TRAN-126

SHOULD · binds the server

Servers SHOULD exit promptly when their standard input is closed or reads return end-of-file.

basic/transports/stdio#shutdown

Excluded. Both the trigger (stdin closing, or a read returning EOF) and the response (process exit) are host-OS events the trace vocabulary does not carry, and “promptly” is a duration — checks may not consult time, the same limit LIFE-015 records.

TRAN-127

SHOULD · binds the client

If the server process exits unexpectedly, the client SHOULD restart it.

basic/transports/stdio#unexpected-termination

Excluded. Process supervision: the antecedent is an unexpected exit and the obligation is to launch a new process, neither of which is a message. A restart also begins a new session, so the evidence would have to span two traces, and nothing in one identifies the other as its successor.

TRAN-128

SHOULD · binds the client

A client that supports both modern (per-request-metadata) MCP versions and a legacy version that requires an initialize handshake SHOULD probe with [server/discover][server-discover] before sending any other request, setting its preferred modern version in meta.

basic/transports/stdio#backward-compatibility

Judged by discover.dual-era-probe-first.

TRAN-129

MUST NOT · binds the client

The fallback MUST NOT be keyed to one specific error code: legacy servers respond to unknown pre-initialize requests with implementation-defined errors (commonly -32601 or -32602) or not at all.

basic/transports/stdio#backward-compatibility

Excluded. Binds the client’s decision function, not any message it sends. A session exhibits one probe answered by one error code and one decision taken; whether the client would have fallen back on a different code is a property of code paths that session never exercised, and no number of traces settles it.

TRAN-142

SHOULD · binds the client

A client that only supports modern versions does not need to probe, but probing is still RECOMMENDED: some legacy servers do not validate that a request arrives after initialize and would process an era-ambiguous method (such as tools/call) under legacy semantics.

basic/transports/stdio#backward-compatibility

Excluded. Asks a modern-only client to open with a server/discover probe, and a recording can show neither half. Not the antecedent: a modern-only client and a dual-era client whose server never forced a fallback send the same messages. Not the order: a modern stdio session has no handshake marking where it began, so a recording that opens on tools/call is equally one that started after the probe. The dual-era statement, TRAN-128, is judged by discover.dual-era-probe-first, which reports only where a session witnesses both eras; this clause offers no such witness.

MRTR

MRTR-001

MUST · binds the server

Servers MUST send server-to-client requests (such as roots/list, sampling/createMessage, or elicitation/create) using the MRTR pattern.

basic/patterns/mrtr

Judged by transport.no-independent-server-requests.

MRTR-002

MUST · binds the client

Every request MUST include the required meta fields; see meta.

basic/patterns/mrtr

Judged by meta.required-request-fields.

MRTR-003

MUST NOT · binds the client

Clients MUST NOT inspect, parse, modify, or make any assumptions about its contents.

basic/patterns/mrtr#inputrequiredresult

Judged by mrtr.request-state-echoed.

MRTR-004

MUST NOT · binds the server

Servers MUST NOT send InputRequiredResult responses on any other client requests.

basic/patterns/mrtr#supported-requests

Judged by mrtr.input-required-supported-methods.

MRTR-005

MUST · binds the server

inputRequests keys are server assigned identifiers and MUST be unique within the scope of the request.

basic/patterns/mrtr#server-requirements-basic-workflow

Excluded. JSON object members are unique by the time any check runs: a duplicate key is collapsed by the parser that reads the trace, so a violation cannot survive into the events a check sees. The same reason TRAN-110 and TRAN-115 exclude — the defect is destroyed at parse time, not judged and passed.

MRTR-006

MUST · binds the server

inputRequests values are request objects that MUST be one of ElicitRequest, CreateMessageRequest, or ListRootsRequest

basic/patterns/mrtr#server-requirements-basic-workflow

Judged by mrtr.input-request-methods.

MRTR-007

MUST · binds the server

If a client request contains a requestState field, servers MUST treat requestState as an attacker-controlled input.

basic/patterns/mrtr#server-requirements-basic-workflow

Excluded. A disposition toward an input, not an act: a server that treats state as trusted and one that treats it as hostile send the same messages until the state is actually tampered with, and even then what differs is the server’s internal decision. The consequences the clause draws from it — integrity protection and rejection — are MRTR-008, excluded for their own reasons.

MRTR-008

MUST · binds the server

If requestState influences authorization, resource access, or business logic, servers MUST protect its integrity (e.g. HMAC or AEAD) and MUST reject state that fails verification.

basic/patterns/mrtr#server-requirements-basic-workflow

Excluded. Both halves are invisible on the wire. requestState is opaque by construction — the specification’s own examples range over base64 JSON, encrypted JWTs and serialized binary — so no check can tell an HMAC-protected blob from an unprotected one. The antecedent is worse still: whether the state influences authorization is a fact about the server’s code. Verified instead by the implementation’s own tests, where the key is available.

MRTR-009

SHOULD · binds the server

To prevent replay, servers SHOULD include the following inside the integrity-protected requestState payload and verify each on receipt: the authenticated principal, rejecting state presented by a different principal. a short expiry (TTL), rejecting state presented after it lapses; an identifier for the originating request, e.g. the method name and a digest of its salient parameters, rejecting state presented on a request that does not match.

basic/patterns/mrtr#server-requirements-basic-workflow

Excluded. Names three fields that live inside the integrity-protected payload, which is opaque and generally encrypted — the trace carries the blob, never its contents. Two of the three also bind time and identity: expiry is a duration, which checks may not consult (LIFE-015), and the authenticated principal is not in the message.

MRTR-010

MUST · binds the server

Servers for which a given requestState must be consumed at most once (e.g., one-time redemptions) MUST enforce that invariant server-side.

basic/patterns/mrtr#server-requirements-basic-workflow

Excluded. The clause’s own words put the obligation server-side, and its antecedent — that this server’s states are single-use — is a property of the server’s design that no message declares. A trace showing one state presented twice would still not distinguish a violated invariant from a server for which none was ever claimed.

MRTR-011

MUST · binds the server

Servers MUST include at least one of inputRequests or requestState in every InputRequiredResult response.

basic/patterns/mrtr#server-requirements-basic-workflow

Judged by mrtr.input-required-has-content.

MRTR-012

MUST NOT · binds the server

Servers MUST NOT send an inputRequests that the client has not declared support for in its capabilities.

basic/patterns/mrtr#server-requirements-basic-workflow

Judged by meta.no-undeclared-capability-reliance.

MRTR-013

MUST NOT · binds the server

For example, if a client does not declare support for elicitation, the server MUST NOT include any elicitation/create requests in the inputRequests field.

basic/patterns/mrtr#server-requirements-basic-workflow

Judged by meta.no-undeclared-capability-reliance.

MRTR-014

MUST NOT · binds the server

Servers MUST NOT assume that clients will fulfill the inputRequests or retry the original request.

basic/patterns/mrtr#server-requirements-basic-workflow

Excluded. Forbids an assumption. Its wire-visible consequence would be a server that breaks when a client declines to retry, and a conforming session never exhibits that: the client either retries, which tells us nothing about the assumption, or does not, and the trace simply ends.

MRTR-015

MUST · binds the client

If a client receives an InputRequiredResult that contains the inputRequests field, the client MUST construct the requested inputs before retrying the original request.

basic/patterns/mrtr#client-requirements-basic-workflow

Judged by mrtr.retry-carries-input-responses.

MRTR-016

MUST · binds the client

If an InputRequiredResult contains the requestState field, the client MUST echo back the exact value of that field when retrying the original request.

basic/patterns/mrtr#client-requirements-basic-workflow

Judged by mrtr.request-state-echoed.

MRTR-017

MUST NOT · binds the client

Clients MUST NOT inspect, parse, modify, or make any assumptions about the requestState contents.

basic/patterns/mrtr#client-requirements-basic-workflow

Judged by mrtr.request-state-echoed.

MRTR-018

MUST NOT · binds the client

If the InputRequiredResult does not contain a requestState field, the client MUST NOT include one in the retry.

basic/patterns/mrtr#client-requirements-basic-workflow

Judged by mrtr.no-unsolicited-request-state.

MRTR-019

MUST · binds the client

The JSON-RPC id MUST be different between the initial request and the retry, as they are independent requests.

basic/patterns/mrtr#client-requirements-basic-workflow

Judged by mrtr.retry-id-differs.

MRTR-020

MUST NOT · binds the client

They MUST NOT be used for any other request that the client may be sending in parallel.

basic/patterns/mrtr#client-requirements-basic-workflow

Judged by mrtr.request-state-scoped-to-retry.

MRTR-021

SHOULD · binds the server

Servers SHOULD validate that the data provided by the client is a valid InputResponses object and that the information inside can be correctly parsed.

basic/patterns/mrtr#error-handling

Excluded. Binds an act of validation, whose outcome is the only thing that reaches the wire — and a server that validated and accepted is indistinguishable from one that never looked. The outcomes the specification does pin are separate clauses: MRTR-023 for what a rejection may ignore, MRTR-024 for what a shortfall must draw.

MRTR-022

SHOULD · binds the server

Protocol errors (malformed JSON, invalid schema, internal server errors) SHOULD return a JSON-RPC error response with an appropriate error code and message.

basic/patterns/mrtr#error-handling

Excluded. The antecedent is not identifiable from a trace: nothing in an exchange says whether the server met a protocol error, so an error response and a completed result are equally consistent with the clause. “Appropriate” is also unbounded — the clause names no code — and the shape an error must have regardless is BASE-052’s, which is checked.

MRTR-023

SHOULD · binds the server

If additional, unexpected parameters are provided in the InputResponses object, the server SHOULD ignore any information it does not recognize or need.

basic/patterns/mrtr#error-handling

Excluded. Requires an absence of consequence: a server that ignored an unexpected field and one that never read it produce identical sessions. The only failing form would be a server that rejected the request because of the extra field, and no error response says that was the reason.

MRTR-024

SHOULD · binds the server

If the client fails to send all the information requested in a previous InputRequests, and the missing information is necessary for the server to process the request, the server SHOULD respond with a new InputRequiredResult requesting the missing information again, rather than returning an error.

basic/patterns/mrtr#error-handling

Judged by mrtr.missing-input-reasked.

MRTR-025

MUST · binds the server

Servers MUST validate request state as described in the server requirements above.

basic/patterns/mrtr#security-considerations

Excluded. A pointer back to MRTR-007 and MRTR-008 rather than a new rule, and it inherits their reason: the state is an opaque blob, so no check can tell a validated one from an unvalidated one.

SUBS

SUBS-001

MUST NOT · binds the server

The server MUST NOT send notification types the client has not explicitly requested.

basic/patterns/subscriptions#opening-a-stream

Judged by subscriptions.only-requested-notifications.

SUBS-002

MUST NOT · binds the server

The server MUST send notifications/subscriptions/acknowledged as the first message carrying the subscription’s ID in meta under io.modelcontextprotocol/subscriptionId, and MUST NOT send any notification on the subscription before it.

basic/patterns/subscriptions#acknowledgment

Judged by subscriptions.acknowledgment-first.

SUBS-003

SHOULD · binds the client

The client SHOULD check the acknowledged filter against what it requested and handle any unsupported types gracefully.

basic/patterns/subscriptions#acknowledgment

Excluded. Comparing two things it already has and reacting well to the difference: both the comparison and “gracefully” are inside the client, and a client that never looked sends exactly the messages one that did would. The server’s side of the same exchange — honouring only what was requested — is SUBS-001 and is checked.

SUBS-004

MUST · binds the client

On stdio, where all messages share a single channel, clients MUST use this field to correlate notifications with their originating subscription.

basic/patterns/subscriptions#receiving-notifications

Excluded. The client’s own demultiplexing, which produces no message — the same clause TRAN-122 states from the stdio page, with the same reason. The wire-visible half, that the server tags every notification with io.modelcontextprotocol/subscriptionId, is BASE-039 and is checked.

SUBS-005

SHOULD · binds the server

The server tears it down (e.g., during shutdown) — it SHOULD send a successful subscriptions/listen response to signal a graceful end (see Graceful Closure), then close the stream.

basic/patterns/subscriptions#cancellation

Judged by subscriptions.graceful-close-result-shape.

SUBS-006

SHOULD · binds the server

When the server ends a subscription on its own initiative (for example, during shutdown), it SHOULD respond to the original subscriptions/listen request with a completion result before closing the stream.

basic/patterns/subscriptions#graceful-closure

Judged by subscriptions.graceful-close-result-shape.

SUBS-007

MUST · binds the client

On stdio, if the connection is terminated and then re-established, the client MUST re-send subscriptions/listen to re-establish its subscriptions — the server holds no subscription state across reconnections.

basic/patterns/subscriptions#graceful-closure

Excluded. The obligation begins after a re-established connection, which is a second session: the evidence would have to span two recordings, and nothing in either identifies the other as its predecessor. Same boundary as TRAN-127, which excludes the restart that precedes it.

CANC

CANC-001

SHOULD · binds the client

A client SHOULD send a cancellation notification to indicate that a request it previously issued should be terminated.

basic/patterns/cancellation

Excluded. The antecedent is the client’s wish to stop a request, which produces no message of its own: a session with no cancellation is indistinguishable from one where nothing was abandoned. The same boundary TRAN-123’s check records for the stdio half of this rule. What a cancellation looks like once sent is CANC-005’s.

CANC-002

MUST · binds the server

A server MUST send notifications/cancelled referencing a subscriptions/listen request ID when it tears down that subscription stream

basic/patterns/cancellation

Excluded. The antecedent — the server deciding to tear a subscription down — is internal, and a stream that simply stops is indistinguishable in a recording from one the client closed or the network lost, so a missing notification has no falsifier. The message itself, when sent, is accepted by the checks it would otherwise trip: meta.subscription-id-present (BASE-039) and subscriptions.only-requested-notifications (SUBS-001) both treat a notifications/cancelled whose requestId names a subscriptions/listen request as the stream’s own ending. Sending it for anything else is CANC-003’s and judged.

CANC-003

MUST NOT · binds the server

Servers MUST NOT send notifications/cancelled for any other purpose.

basic/patterns/cancellation

Judged by cancellation.server-cancels-only-subscriptions.

CANC-004

MUST · binds the server

The server MUST treat a client disconnect as cancellation of that request.

basic/patterns/cancellation#transport-specific-cancellation

Excluded. The cancellation page’s statement of TRAN-069, excluded for the same reason: how a server treats a closed stream is a decision, and the trace shows only that the transport ended. The observable consequence — anything sent for the request afterwards — is TRAN-070’s, judged by transport.no-messages-after-cancellation.

CANC-005

MUST · binds the client

The client MUST send a notifications/cancelled notification referencing the request ID.

basic/patterns/cancellation#transport-specific-cancellation

Judged by transport.cancel-notification-references-request.

CANC-006

SHOULD · binds the client and server

Implementations SHOULD establish timeouts for all sent requests, to prevent hung connections and resource exhaustion.

basic/patterns/cancellation#timeouts

Excluded. A timeout is a duration configured inside the sender, and checks may not consult time — the limit LIFE-015 records. A trace shows a request answered or not, never the deadline the sender held it to.

CANC-007

SHOULD · binds the client and server

When the request has not received a success or error response within the timeout period, the sender SHOULD cancel the request and stop waiting for a response.

basic/patterns/cancellation#timeouts

Excluded. The trigger is the sender’s own timeout expiring, which no message records and which checks may not compute from timestamps (LIFE-015’s limit). A cancellation that is sent is judged for its shape by CANC-005; whether a timeout prompted it is not on the wire.

CANC-008

SHOULD · binds the client and server

SDKs and other middleware SHOULD allow these timeouts to be configured on a per-request basis.

basic/patterns/cancellation#timeouts

Excluded. Binds an SDK’s programming interface — what its callers can configure — which has no protocol representation at all.

CANC-009

SHOULD · binds the client and server

However, implementations SHOULD always enforce a maximum timeout, regardless of progress notifications, to limit the impact of a misbehaving client or server.

basic/patterns/cancellation#timeouts

Excluded. A maximum timeout is a duration the sender enforces internally; checks may not consult time (LIFE-015), and a request still open when the recording ends says nothing about the deadline it would have hit.

CANC-010

MUST · binds the client and server

Cancellation notifications MUST only reference requests that: Were previously issued by the client; Are believed to still be in-progress

basic/patterns/cancellation#behavior-requirements

Excluded. Neither condition has a sound falsifier. A recording may begin mid-session, so a requestId the trace never saw issued may still have been — the reason transport.cancel-notification-references-request judges only that a request is named. “Believed to still be in-progress” is the sender’s belief, and the page’s own Timing Considerations make a cancellation that crosses the response on the wire conforming. The server-sent case is narrowed further by CANC-011, which is judged.

CANC-011

MUST · binds the server

Server-sent cancellation notifications MUST reference a subscriptions/listen request, to terminate that subscription stream

basic/patterns/cancellation#behavior-requirements

Judged by cancellation.server-cancels-only-subscriptions.

CANC-012

SHOULD · binds the server

Servers receiving cancellation notifications SHOULD: Stop processing the cancelled request; Free associated resources; Not send a response for the cancelled request

basic/patterns/cancellation#behavior-requirements

Excluded. Stopping work and freeing resources are internal. The one wire-visible item, not answering a cancelled request, is a MUST NOT on both transport pages and judged there at that strength: TRAN-124 (transport.no-messages-after-cancel-notification, stdio) and TRAN-070 (transport.no-messages-after-cancellation, Streamable HTTP). Judging it again here would report every such answer twice, once as a warning.

CANC-013

SHOULD · binds the client

The client SHOULD ignore any response to the cancelled request that arrives afterward

basic/patterns/cancellation#behavior-requirements

Excluded. Ignoring a response is the absence of a reaction inside the client; nothing it does with a late response reaches the wire.

CANC-014

MUST · binds the client and server

Both parties MUST handle these race conditions gracefully:

basic/patterns/cancellation#timing-considerations

Excluded. Graceful handling is internal; the race itself is what a recording shows, and the checks are built not to convict it — TRAN-124 reports a message after a cancellation only once the server has demonstrably read it, and the conforming stdio-cancellation-race trace pins that. A party that failed to handle the race would show it through some other clause’s violation, judged there.

CANC-015

SHOULD · binds the client and server

Both parties SHOULD log cancellation reasons for debugging

basic/patterns/cancellation#implementation-notes

Excluded. Logging is local diagnostics with no wire footprint.

CANC-016

SHOULD · binds the client

Application UIs SHOULD indicate when cancellation is requested

basic/patterns/cancellation#implementation-notes

Excluded. User-interface presentation, out by strategy rule 2: nothing a UI shows reaches the protocol.

CANC-017

SHOULD · binds the client and server

Invalid cancellation notifications SHOULD be ignored: Unknown request IDs; Already completed requests; Malformed notifications

basic/patterns/cancellation#error-handling

Excluded. Ignoring a notification is the absence of a reaction, which a trace cannot tell apart from the notification never mattering. The party that sent the invalid notification is judged instead, where it can be: CANC-005 for a cancellation naming no request, CANC-011 for a server cancelling anything but a subscription.

PROG

PROG-001

MUST · binds the client

Progress tokens MUST be a string or integer value

basic/patterns/progress#progress-flow

Judged by progress.token-type.

PROG-002

MUST · binds the client

Progress tokens can be chosen by the client using any means, but MUST be unique across all active requests.

basic/patterns/progress#progress-flow

Judged by progress.token-unique-in-flight.

PROG-003

MUST · binds the server

The progress value MUST increase with each notification, even if the total is unknown.

basic/patterns/progress#progress-flow

Judged by progress.value-increases.

PROG-004

SHOULD · binds the server

The message field SHOULD provide relevant human readable progress information.

basic/patterns/progress#progress-flow

Excluded. Whether a message is relevant and human readable is a judgment about its meaning, not its shape; any string satisfies the schema, and no mechanical reading of one decides relevance.

PROG-005

MUST · binds the server

Progress notifications MUST only reference tokens that: Were provided in an active request; Are associated with an in-progress operation

basic/patterns/progress#behavior-requirements

Judged by progress.no-progress-after-completion.

PROG-006

SHOULD · binds the client and server

Clients and servers SHOULD track active progress tokens

basic/patterns/progress#implementation-notes

Excluded. Tracking is bookkeeping inside each party. Its wire consequences are the MUST rows beside it, which are judged: a reused token (PROG-002) and progress for a finished request (PROG-005, PROG-008).

PROG-007

SHOULD · binds the client and server

Both parties SHOULD implement rate limiting to prevent flooding

basic/patterns/progress#implementation-notes

Excluded. A rate is messages per unit of time, and checks may not consult time — the limit LIFE-015 records. No count of notifications alone separates a flood from a long operation reporting often.

PROG-008

MUST · binds the server

Progress notifications MUST stop after completion

basic/patterns/progress#implementation-notes

Judged by progress.no-progress-after-completion.

CACH

CACH-001

MUST · binds the server

Servers MUST include caching hints on results with resultType: "complete" returned by the following operations: server/discover; tools/list; prompts/list; resources/list; resources/templates/list; resources/read

server/utilities/caching#cacheable-results

Judged by caching.hints-on-cacheable-results.

CACH-002

MUST NOT · binds the client

Clients MUST NOT serve a cached response for a request whose method or parameters differ from the request that produced it.

server/utilities/caching#cache-key

Excluded. Binds which cached response a client serves itself, and a cache hit is precisely the case where nothing reaches the wire. Serving from a cache produces no message: the client either sends a request or does not, and a session shows the request it sent, never the cached response it served instead.

CACH-003

MUST NOT · binds the client

Results produced by retrying a request through the multi round-trip requests mechanism—that is, requests carrying inputResponses or requestState—MUST NOT be cached, as they depend on inputs that are not part of the cache key.

server/utilities/caching#cache-key

Excluded. The prohibited act is caching, which happens inside the client and produces no message. Its server-side shadow is honoured by CACH-001’s check rather than left implicit: a complete result answering a request that carried inputResponses or requestState is not required to carry caching hints, because the specification does not ask a server to advertise freshness for a result nobody may cache.

CACH-004

SHOULD · binds the client

If ttlMs is 0, the response SHOULD be considered immediately stale.

server/utilities/caching#time-to-live-ttl-field

Excluded. Serving from a cache produces no message: the client either sends a request or does not, and a session shows the request it sent, never the cached response it served instead. The freshness rules are worse still — they are stated in terms of elapsed time, and checks may not consult time (LIFE-015).

CACH-005

SHOULD · binds the client

If ttlMs is positive, the client SHOULD consider the result fresh for that many milliseconds after receiving the response.

server/utilities/caching#time-to-live-ttl-field

Excluded. Serving from a cache produces no message: the client either sends a request or does not, and a session shows the request it sent, never the cached response it served instead. The freshness rules are worse still — they are stated in terms of elapsed time, and checks may not consult time (LIFE-015).

CACH-006

SHOULD · binds the client

If ttlMs is absent, clients SHOULD assume a default of 0 (immediately stale) and rely on their own caching heuristics or notifications.

server/utilities/caching#time-to-live-ttl-field

Excluded. Serving from a cache produces no message: the client either sends a request or does not, and a session shows the request it sent, never the cached response it served instead. The freshness rules are worse still — they are stated in terms of elapsed time, and checks may not consult time (LIFE-015).

CACH-007

SHOULD · binds the client

If ttlMs is negative, clients SHOULD ignore it and treat it as 0.

server/utilities/caching#time-to-live-ttl-field

Excluded. What a client concludes from a negative ttlMs stays inside it. The value itself is judged on the other side of the exchange: CACH-008 forbids a server from sending one.

CACH-008

MUST · binds the server

Servers MUST provide a ttlMs value that is >= 0.

server/utilities/caching#time-to-live-ttl-field

Judged by caching.ttl-non-negative.

CACH-009

SHOULD · binds the client

Once the TTL expires, the response is stale and the client SHOULD re-fetch on next access.

server/utilities/caching#freshness-calculation

Excluded. Serving from a cache produces no message: the client either sends a request or does not, and a session shows the request it sent, never the cached response it served instead. The freshness rules are worse still — they are stated in terms of elapsed time, and checks may not consult time (LIFE-015).

CACH-010

SHOULD NOT · binds the client

Clients SHOULD NOT treat TTL as a polling interval that triggers automatic background refetches.

server/utilities/caching#freshness-calculation

Excluded. Forbids a reason for sending requests, not the requests themselves: a poll and a genuine need look identical on the wire. Distinguishing them would mean inferring intent from inter-request timing, which checks may not consult.

CACH-011

MUST · binds the client

Implementations that do choose to poll MUST apply jitter and backoff.

server/utilities/caching#freshness-calculation

Excluded. Both the antecedent (this client is polling) and the obligation (its intervals are jittered and backed off) are properties of a request schedule, measurable only in elapsed time — which checks may not consult (LIFE-015) — and only across a run far longer than one recorded session.

CACH-019

MUST NOT · binds the client

Caches MUST NOT be shared across authorization contexts (e.g. a different access token requires a different cache).

server/utilities/caching#cache-scope-field

Excluded. A cache, and which authorization context may read from it, live inside the client or an intermediary: a hit serves a stored result without sending anything, so a cache shared across contexts produces no message. Nor does a trace carry the authorization context to compare: mcp-trace-capture records an allowlist of headers that never includes credentials, so no access token reaches the recording. Same boundary as CACH-002 (what a client may serve from its cache).

CACH-012

SHOULD · binds the client

When a cached page expires, the client SHOULD re-fetch that page using its cursor.

server/utilities/caching#interaction-with-pagination

Excluded. Serving from a cache produces no message: the client either sends a request or does not, and a session shows the request it sent, never the cached response it served instead. The freshness rules are worse still — they are stated in terms of elapsed time, and checks may not consult time (LIFE-015).

CACH-013

SHOULD · binds the client

Clients that require a consistent snapshot of the full list SHOULD re-fetch from the beginning (without a cursor).

server/utilities/caching#interaction-with-pagination

Excluded. The antecedent is a client requirement — that this client needs a consistent snapshot — which nothing on the wire declares. A client that paginates from a cursor is equally consistent with not needing one.

CACH-014

SHOULD · binds the client

If a cursor becomes invalid (e.g., the server returns an error for a previously valid cursor), the client SHOULD discard all cached pages and re-fetch from the beginning.

server/utilities/caching#interaction-with-pagination

Excluded. Discarding a cache is invisible, and the visible half — re-fetching from the beginning — is indistinguishable from an ordinary new list request. Serving from a cache produces no message: the client either sends a request or does not, and a session shows the request it sent, never the cached response it served instead.

CACH-015

MUST · binds the server

Servers MUST apply the same cacheScope to all response pages for a given list request.

server/utilities/caching#interaction-with-pagination

Judged by caching.page-scope-consistent.

CACH-016

MUST · binds the server

For example, if the first page of a tools/list response has cacheScope: "private", all subsequent pages for that request MUST also be "private".

server/utilities/caching#interaction-with-pagination

Judged by caching.page-scope-consistent.

CACH-017

MUST · binds the server

Servers MUST be aware that responses with a "public" cacheScope may be shared between callers even if the Result is coming from an authenticated endpoint.

server/utilities/caching#security-considerations

Excluded. Requires awareness. A server that has understood the sharing consequence and one that has not send the same bytes; what the clause is really asking for is the judgement CACH-018 then makes concrete, and that is excluded for its own reason.

CACH-018

MUST NOT · binds the server

MUST apply appropriate per-primitive access controls, and MUST NOT rely on cacheScope alone to prevent unauthorized access to primitives.

server/utilities/caching#security-considerations

Excluded. Access control happens before a response is composed, inside the server: a trace shows what one caller was given, never what a different caller would have been refused. Whether cacheScope was relied upon for that decision is a fact about the server’s code.

COMP

COMP-006

MUST · binds the client

Every request MUST include the required meta fields; see meta.

server/utilities/completion

Judged by meta.required-request-fields.

COMP-007

MUST · binds the server

Servers that support completions MUST declare the completions capability:

server/utilities/completion#capabilities

Judged by capabilities.completions-declared.

COMP-008

SHOULD · binds the server

Servers SHOULD return standard JSON-RPC errors for common failure cases: Method not found: -32601 (Capability not supported); Invalid prompt name: -32602 (Invalid params); Missing required arguments: -32602 (Invalid params); Internal errors: -32603 (Internal error)

server/utilities/completion#error-handling

Excluded. Each row’s antecedent is a server-side determination — that this prompt name is invalid, that a required argument is missing — and a trace shows the answer without the reason for it. An exchange ending in -32602 and one ending in a result are equally consistent with the clause, because nothing on the wire says which case the server was in.

COMP-009

SHOULD · binds the server

Servers SHOULD: Return suggestions sorted by relevance; Implement fuzzy matching where appropriate; Rate limit completion requests; Validate all inputs

server/utilities/completion#implementation-considerations

Excluded. Four quality properties, none of them a message shape: relevance ordering has no wire-observable definition, fuzzy matching is an algorithm choice, rate limiting is measured in elapsed time (LIFE-015), and validation that accepts leaves no trace.

COMP-010

SHOULD · binds the client

Clients SHOULD: Debounce rapid completion requests; Cache completion results where appropriate; Handle missing or partial results gracefully

server/utilities/completion#implementation-considerations

Excluded. Debouncing and caching are timing and cache-hit properties, both invisible for the reasons CACH-010 and CACH-002 record; “gracefully” describes what the client does after the response arrives, which is not a message.

COMP-011

MUST · binds the client and server

Implementations MUST: Validate all completion inputs; Implement appropriate rate limiting; Control access to sensitive suggestions; Prevent completion-based information disclosure

server/utilities/completion#security

Excluded. Security properties of an implementation, not of an exchange. A trace shows one completion answered for one caller; whether a different caller would have been refused, and whether the suggestions disclosed something they should not, are facts about the server’s data and policy rather than about the message.

PAGE

PAGE-006

MUST · binds the client

Every request MUST include the required meta fields; see meta.

server/utilities/pagination

Judged by meta.required-request-fields.

PAGE-007

MUST NOT · binds the client

The cursor is an opaque string token, representing a position in the result set; Page size is determined by the server, and clients MUST NOT assume a fixed page size

server/utilities/pagination#pagination-model

Excluded. Forbids an assumption. A client that assumed a fixed page size and one that did not send identical requests — the assumption only shows in how the client interprets what comes back, which is not on the wire.

PAGE-008

SHOULD · binds the server

Servers SHOULD: Provide stable cursors; Handle invalid cursors gracefully

server/utilities/pagination#implementation-guidelines

Excluded. Cursor stability is a property across time and sessions — the same cursor presented later must still resolve — which one recording cannot exhibit. The graceful half is stated concretely by PAGE-011, which is excluded at this revision for the reason it records.

PAGE-009

SHOULD · binds the client

Clients SHOULD: Treat a missing nextCursor as the end of results; Support both paginated and non-paginated flows

server/utilities/pagination#implementation-guidelines

Excluded. Both bind how a client reads a result it already has. Stopping because nextCursor was absent and stopping for any other reason produce the same session: no further request.

PAGE-010

MUST · binds the client

Clients MUST treat cursors as opaque tokens: Don’t make assumptions about cursor format; Don’t attempt to parse or modify cursors; Don’t make any determination based on cursor value other than whether a non-null value was provided (e.g. an empty string is a valid cursor and thus MUST NOT be treated as the end of results)

server/utilities/pagination#implementation-guidelines

Excluded. A recording’s witness for a cursor the client made up — one no result in the session issued — does not hold at this revision. 2026-07-28 drops 2025-11-25’s “Don’t persist cursors across sessions” and has no sessions to persist across; its caching page says “When a cached page expires, the client SHOULD re-fetch that page using its cursor”, a cursor issued before the recording began. A parsed or altered cursor is indistinguishable on the wire from such a one.

PAGE-011

SHOULD · binds the server

Invalid cursors SHOULD result in an error with code -32602 (Invalid params).

server/utilities/pagination#error-handling

Excluded. Whether a cursor is invalid is the server’s knowledge. At 2025-11-25 a cursor no result in the session issued witnesses it (cursors must not outlive a session, and 2025-11-25’s PAGE-003 judges that); at this revision a cursor issued before the recording began is a valid one the client should re-present (server/utilities/caching), so a server accepting it may be conforming. The everything server still rejects cursors its own scheme did not issue; the probe capture exercises that.

LOG

LOG-006

SHOULD NOT · binds the client and server

New implementations SHOULD NOT adopt it; existing implementations SHOULD migrate to logging to stderr for stdio transports, or to OpenTelemetry for structured observability.

server/utilities/logging

Excluded. Binds an adoption decision and a migration plan, neither of which is a message. A server that uses the feature is not thereby a new implementation, and a trace carries nothing that dates the code sending it.

LOG-007

MUST · binds the server

Servers that emit log message notifications MUST declare the logging capability:

server/utilities/logging#capabilities

Judged by capabilities.logging-declared.

LOG-008

MUST NOT · binds the server

The server MUST NOT emit notifications/message for a request that does not include this field.

server/utilities/logging#per-request-log-level

Judged by logging.level-requested.

LOG-009

MUST NOT · binds the server

notifications/message is request-scoped: the server MUST NOT deliver it on a subscriptions/listen stream or on any stream other than the one carrying the response to the request that set the log level.

server/utilities/logging#per-request-log-level

Judged by logging.not-on-subscription.

LOG-010

SHOULD · binds the server

If the io.modelcontextprotocol/logLevel value carried in a request’s meta is not a recognized log level, the server SHOULD reject that request with a standard JSON-RPC error: Invalid log level: -32602 (Invalid params); Internal errors: -32603 (Internal error)

server/utilities/logging#error-handling

Judged by logging.invalid-level-rejected.

LOG-011

SHOULD · binds the server

Servers SHOULD: Rate limit log messages; Include relevant context in data field; Use consistent logger names; Remove sensitive information

server/utilities/logging#implementation-considerations

Excluded. Rate limiting is measured in elapsed time (LIFE-015); “relevant context”, “consistent” logger names and “sensitive” information are judgements about the meaning of the payload, which this engine does not model.

LOG-012

MUST NOT · binds the server

Log messages MUST NOT contain: Credentials or secrets; Personal identifying information; Internal system details that could aid attacks

server/utilities/logging#security

Excluded. Requires classifying the meaning of arbitrary JSON. Whether a string is a credential, a person’s identity, or an internal detail that aids an attacker cannot be decided structurally, and a checker that guessed would report conforming servers while missing real leaks.

LOG-013

SHOULD · binds the client and server

Implementations SHOULD: Rate limit messages; Validate all data fields; Control log access; Monitor for sensitive content

server/utilities/logging#security

Excluded. Four operational practices of an implementation. Access control and monitoring happen outside the session entirely, and validation that accepts leaves nothing behind — the same reason MRTR-021 excludes.

TOOL

TOOL-016

MUST · binds the client

Every request MUST include the required meta fields; see meta.

server/tools

Judged by meta.required-request-fields.

TOOL-017

SHOULD · binds the client

For trust & safety and security, there SHOULD always be a human in the loop with the ability to deny tool invocations.

server/tools#user-interaction-model

Excluded. Binds the application’s user interface — what it shows, when it asks, whether a person is there. None of it is a message, and MCP deliberately does not mandate an interaction model.

TOOL-018

SHOULD · binds the client

Applications SHOULD: Provide UI that makes clear which tools are being exposed to the AI model; Insert clear visual indicators when tools are invoked; Present confirmation prompts to the user for operations, to ensure a human is in the loop

server/tools#user-interaction-model

Excluded. Binds the application’s user interface — what it shows, when it asks, whether a person is there. None of it is a message, and MCP deliberately does not mandate an interaction model.

TOOL-019

MUST · binds the server

Servers that support tools MUST declare the tools capability:

server/tools#capabilities

Judged by capabilities.tools-declared.

TOOL-020

MUST · binds the server

Servers that declare the tools capability MUST respond to tools/list requests with the set of tools currently available to the requesting client.

server/tools#capabilities

Judged by capabilities.tools-list-implemented.

TOOL-021

MUST NOT · binds the server

This set MAY be empty and MAY change over time (see List Changed Notification), but MUST NOT vary per-connection or as a side effect of other requests on the connection.

server/tools#capabilities

Excluded. Binds the set across connections and across other requests — two properties that need more than one session, or a second request whose effect on the first is invisible. A single recording shows one list at one moment.

TOOL-022

SHOULD · binds the server

Servers SHOULD return tools in a deterministic order (i.e., the same ordering across requests when the underlying set of tools has not changed).

server/tools#capabilities

Judged by tools.deterministic-order.

TOOL-023

MUST · binds the client

Note that the JSON-RPC id MUST be different between the initial request and the retry.

server/tools#input-required-tool-results

Judged by mrtr.retry-id-differs.

TOOL-024

SHOULD · binds the server

When the list of available tools changes, servers that declared the listChanged capability SHOULD send a notification to clients that have opened a subscriptions/listen stream with toolsListChanged: true:

server/tools#list-changed-notification

Excluded. The antecedent is that the underlying set changed, which happens inside the server and reaches the wire only as the notification the clause is asking for.

TOOL-025

MUST · binds the server

JSON Schema defining expected parameters Follows the JSON Schema usage guidelines Defaults to 2020-12 if no $schema field is present MUST be a valid JSON Schema object (not null) For tools with no parameters, use one of these valid approaches:

server/tools#tool

Judged by tools.input-schema-object.

TOOL-026

MUST · binds the client

For trust & safety and security, clients MUST consider tool annotations to be untrusted unless they come from trusted servers.

server/tools#tool

Excluded. “Consider untrusted” is a disposition toward data already received, and “trusted servers” is the client’s own configuration. Neither reaches the wire.

TOOL-027

SHOULD · binds the server

Tool names SHOULD be between 1 and 128 characters in length (inclusive).

server/tools#tool-names

Judged by tools.name-length.

TOOL-028

SHOULD · binds the client and server

Tool names SHOULD be considered case-sensitive.

server/tools#tool-names

Excluded. States how names are to be compared, not how they may be spelled. Two implementations differing on case sensitivity send identical messages until they disagree about a collision, and TOOL-030 already judges the collision.

TOOL-029

SHOULD NOT · binds the server

The following SHOULD be the only allowed characters: uppercase and lowercase ASCII letters (A-Z, a-z), digits (0-9), underscore (_), hyphen (-), and dot (.) Tool names SHOULD NOT contain spaces, commas, or other special characters.

server/tools#tool-names

Judged by tools.name-charset.

TOOL-030

SHOULD · binds the server

Tool names SHOULD be unique within a server.

server/tools#tool-names

Judged by tools.name-unique.

TOOL-031

SHOULD · binds the client

Clients or proxies that aggregate tools from multiple servers MAY encounter naming collisions (for example, two servers each exposing a search tool) and SHOULD implement a disambiguation strategy such as prefixing tool names with a server identifier.

server/tools#tool-names

Excluded. Binds a client aggregating several servers. One recorded session is one server, so the collision the clause is about cannot appear in it, and neither can the disambiguation strategy.

TOOL-032

SHOULD NOT · binds the client

The server name (from serverInfo) is not guaranteed to be unique across servers and SHOULD NOT be relied upon for disambiguation.

server/tools#tool-names

Excluded. Forbids relying on serverInfo for disambiguation — a client-side decision about data it holds. Binds what the client does with what it received; the reasoning leaves no message behind.

TOOL-033

MUST NOT · binds the server

Constraints on x-mcp-header values: MUST NOT be empty; MUST match HTTP field-name token syntax (1*tchar, RFC 9110 Section 5.1); MUST NOT contain control characters, including carriage return (CR, \r) or line feed (LF, \n); MUST be case-insensitively unique among all x-mcp-header values in the inputSchema; MUST only be applied to parameters with primitive types (integer, string, boolean).

server/tools#x-mcp-header

Judged by transport.x-mcp-header-name-valid.

TOOL-034

MUST · binds the client

Constraints on x-mcp-header values: Integer values MUST be within the safe range for integers represented using IEEE754 double-precision floating point numbers (−253+1 to 253−1)

server/tools#x-mcp-header

Judged by tools.x-mcp-header-integer-range.

TOOL-035

MUST · binds the client

Rejection means the client MUST exclude the invalid tool from the result of tools/list.

server/tools#x-mcp-header

Judged by transport.x-mcp-header-invalid-tool-not-called.

TOOL-036

SHOULD · binds the client

Clients SHOULD log a warning when rejecting a tool definition, including the tool name and the reason for rejection.

server/tools#x-mcp-header

Excluded. Binds the client’s log, which is not part of the session.

TOOL-037

SHOULD NOT · binds the server

Server developers SHOULD NOT mark sensitive parameters (passwords, API keys, tokens, PII) with x-mcp-header, as header values are visible to network intermediaries.

server/tools#x-mcp-header

Excluded. Requires deciding whether a parameter is sensitive — a judgement about the meaning of a name and its values, which this engine does not model. Same boundary as LOG-012.

TOOL-038

SHOULD · binds the server

Servers that use embedded resources SHOULD implement the resources capability:

server/tools#embedded-resources

Judged by capabilities.embedded-resource-declared.

TOOL-039

SHOULD · binds the server

For backwards compatibility, a tool that returns structured content SHOULD also return the serialized JSON in a TextContent block.

server/tools#structured-content

Judged by tools.structured-content-text.

TOOL-040

MUST · binds the server

Servers MUST provide structured results that conform to this schema.

server/tools#output-schema

Judged by tools.output-schema-structured-result.

TOOL-041

SHOULD · binds the client

Clients SHOULD validate structured results against this schema.

server/tools#output-schema

Excluded. Validation performed inside the client. A client that validated a structured result and one that did not send the same messages, and the clause does not say what a client does with a result that fails; the server half of the rule, TOOL-040, is judged.

TOOL-042

SHOULD · binds the client

Clients SHOULD provide tool execution errors to language models to enable self-correction.

server/tools#error-handling

Excluded. Binds what the client hands to a language model, which is downstream of the session entirely.

TOOL-043

MUST · binds the server

Servers MUST: Validate all tool inputs; Implement proper access controls; Rate limit tool invocations; Sanitize tool outputs

server/tools#security-considerations

Excluded. Four operational properties of the server — input validation, access control, rate limiting, output sanitization. A trace shows one call answered for one caller; whether another would have been refused, and whether the output was sanitized, are facts about the server’s code and data.

TOOL-044

SHOULD · binds the client

Clients SHOULD: Prompt for user confirmation on sensitive operations; Show tool inputs to the user before calling the server, to avoid malicious or accidental data exfiltration; Validate tool results before passing to LLM; Follow the $ref resolution requirements when validating tool inputs and outputs against inputSchema and outputSchema; Implement timeouts for tool calls; Log tool usage for audit purposes

server/tools#security-considerations

Excluded. Six client-side practices — confirmation prompts, showing inputs, validating results, $ref resolution, timeouts, audit logs. Each happens inside the client or in its UI; none is a message.

TOOL-045

MUST · binds the server

Constraints on x-mcp-header values: MUST only be applied to properties that are statically reachable from the schema root, as defined in Custom Headers from Tool Parameters, which also defines how header values are extracted from call arguments

server/tools#x-mcp-header

Judged by transport.x-mcp-header-statically-reachable.

TOOL-046

MUST · binds the client

Clients using the Streamable HTTP transport MUST reject tool definitions where any x-mcp-header value violates these constraints.

server/tools#x-mcp-header

Judged by transport.x-mcp-header-invalid-tool-not-called.

RES

RES-011

MUST · binds the client

Every request MUST include the required meta fields; see meta.

server/resources

Judged by meta.required-request-fields.

RES-012

MUST · binds the server

Servers that support resources MUST declare the resources capability:

server/resources#capabilities

Judged by capabilities.resources-declared.

RES-013

MUST · binds the server

Servers that declare the resources capability MUST respond to resources/list requests with the set of resources currently available to the requesting client.

server/resources#capabilities

Judged by capabilities.resources-list-implemented.

RES-014

MUST NOT · binds the server

This set MAY be empty and MAY change over time (see List Changed Notification), but MUST NOT vary per-connection or as a side effect of other requests on the connection.

server/resources#capabilities

Excluded. Binds the set across connections and across other requests — two properties that need more than one session, or a second request whose effect on the first is invisible. A single recording shows one list at one moment.

RES-015

SHOULD · binds the server

When the list of available resources changes, servers that declared the listChanged capability SHOULD send a notification:

server/resources#list-changed-notification

Excluded. The antecedent is that the underlying set changed, which happens inside the server and reaches the wire only as the notification the clause is asking for. A session with no notification is equally consistent with a list that never changed.

RES-016

SHOULD · binds the server

Servers SHOULD use this scheme only when the client is able to fetch and load the resource directly from the web on its own—that is, it doesn’t need to read the resource via the MCP server.

server/resources#https//

Excluded. Turns on whether the client can fetch the resource itself, which is a fact about the client and its network, not about any message. The server’s choice of scheme is visible; the condition that licenses it is not.

RES-017

SHOULD · binds the server

For other use cases, servers SHOULD prefer to use another URI scheme, or define a custom one, even if the server will itself be downloading resource contents over the internet.

server/resources#https//

Excluded. Design guidance about which scheme to prefer, resolved before a URI is ever minted. Whether “other use cases” applies is the server author’s judgement, and RES-018 checks the only part a trace can hold the result to: that a custom scheme is well-formed.

RES-018

MUST · binds the server

Custom URI schemes MUST be in accordance with RFC3986, taking the above guidance in to account.

server/resources#custom-uri-schemes

Judged by resources.uri-scheme-rfc3986.

RES-019

MUST · binds the server

If the requested resource does not exist, servers MUST return a JSON-RPC error with code -32602 (Invalid Params).

server/resources#error-handling

Excluded. The antecedent — that the requested resource does not exist — is the server’s own knowledge. An error and a result are both consistent with the clause, because nothing on the wire says which case the server was in. The one shape the clause rules out explicitly is checked, as RES-022.

RES-020

SHOULD · binds the server

Servers SHOULD return -32603 for internal errors.

server/resources#error-handling

Excluded. “Internal errors” names a class of server-side failure that no message declares membership of. Every error code is consistent with the clause unless the trace says what went wrong, and it never does.

RES-021

SHOULD · binds the client

For backwards compatibility, clients SHOULD also accept -32002 as a resource not found error, as earlier protocol versions used this code.

server/resources#error-handling

Excluded. Binds how a client interprets an error it received. Note the direction: BASE-058 forbids a 2026-07-28 server from emitting -32002, and this asks clients to keep accepting it from older ones — neither contradicts the other, and neither is visible in what the client sends.

RES-022

MUST NOT · binds the server

Servers MUST NOT return an empty contents array for a non-existent resource.

server/resources#error-handling

Judged by resources.read-contents-non-empty.

RES-023

MUST · binds the server

Servers MUST validate all resource URIs Access controls SHOULD be implemented for sensitive resources Binary data MUST be properly encoded Resource permissions SHOULD be checked before operations Servers MUST sanitize file paths to prevent directory traversal attacks when serving file:// resources

server/resources#security-considerations

Judged by resources.blob-base64.

PROM

PROM-011

MUST · binds the client

Every request MUST include the required meta fields; see meta.

server/prompts

Judged by meta.required-request-fields.

PROM-012

MUST · binds the server

Servers that support prompts MUST declare the prompts capability in their DiscoverResult:

server/prompts#capabilities

Judged by capabilities.prompts-declared.

PROM-013

MUST · binds the server

Servers that declare the prompts capability MUST respond to prompts/list requests with the set of prompts currently available to the requesting client.

server/prompts#capabilities

Judged by capabilities.prompts-list-implemented.

PROM-014

MUST NOT · binds the server

This set MAY be empty and MAY change over time (see List Changed Notification), but MUST NOT vary per-connection or as a side effect of other requests on the connection.

server/prompts#capabilities

Excluded. Binds the set across connections and across other requests — two properties that need more than one session, or a second request whose effect on the first is invisible. A single recording shows one list at one moment.

PROM-015

SHOULD · binds the server

When the list of available prompts changes, servers that declared the listChanged capability SHOULD send a notification to clients that have opened a subscriptions/listen stream with promptsListChanged: true:

server/prompts#list-changed-notification

Excluded. The antecedent is that the underlying set changed, which happens inside the server and reaches the wire only as the notification the clause is asking for. A session with no notification is equally consistent with a list that never changed.

PROM-016

MUST · binds the server

The image data MUST be base64-encoded and include a valid MIME type.

server/prompts#image-content

Judged by prompts.image-content-encoding.

PROM-017

MUST · binds the server

The audio data MUST be base64-encoded and include a valid MIME type.

server/prompts#audio-content

Judged by prompts.audio-content-encoding.

PROM-018

MUST · binds the server

Resources can contain either text or binary (blob) data and MUST include:

server/prompts#embedded-resources

Judged by prompts.embedded-resource-shape.

PROM-019

SHOULD · binds the server

Servers SHOULD return standard JSON-RPC errors for common failure cases:

server/prompts#error-handling

Excluded. Each row’s antecedent is a server-side determination — an invalid prompt name, a missing required argument — and the trace shows the answer without the reason. Same shape as COMP-008.

PROM-020

SHOULD · binds the client and server

Servers SHOULD validate prompt arguments before processing Clients SHOULD handle pagination for large prompt lists Both parties SHOULD respect capability negotiation

server/prompts#implementation-considerations

Judged by prompts.arguments-validated.

PROM-021

MUST · binds the client and server

Implementations MUST carefully validate all prompt inputs and outputs to prevent injection attacks or unauthorized access to resources.

server/prompts#security

Excluded. “Carefully validate to prevent injection attacks” is a property of the server’s handling, not of the message: a prompt that was validated and one that was not look identical when both are accepted. What a trace can hold an implementation to is the concrete shape rules, PROM-016 through PROM-020.

ELIC

ELIC-054

MUST NOT · binds the server

Servers MUST NOT use form mode elicitation to request sensitive information such as passwords, API keys, access tokens, or payment credentials

client/elicitation#user-interaction-model

Excluded. Whether a requested field is “sensitive information” — the page’s own definition is “secrets and credentials that grant access or authorize transactions” — is a judgement about meaning, not syntax: a schema property named token may be a display preference and one named answer may collect a password. A check would have to guess from field names, and a guess convicts conforming servers. The server’s author decides it; nothing in the message settles it.

ELIC-055

MUST · binds the server

Servers MUST use URL mode for interactions involving such sensitive information

client/elicitation#user-interaction-model

Excluded. The counterpart of the form mode prohibition, and blocked by the same judgement: that an interaction “involves such sensitive information” is a fact about what the user will be asked for, which no message states, so a form mode request cannot be shown to have needed URL mode.

ELIC-056

MUST · binds the client

MCP clients MUST: Provide UI that makes it clear which server is requesting information; Respect user privacy and provide clear decline and cancel options; For form mode, allow users to review and modify their responses before sending; For URL mode, clearly display the target domain/host and gather user consent before navigation to the target URL

client/elicitation#user-interaction-model

Excluded. Binds the client’s user interface — what it shows the user, offers them, or lets them do — and none of that reaches the wire: a recording carries the client’s messages, not its screens. The reference host this project ships has no interactive interface at all (it answers from its interaction script, crates/mcp-reference-host/src/handler.rs), so the clause is a host-implementation property, reviewed in the host, never judged from a trace.

ELIC-057

MUST · binds the client

Clients that support elicitation MUST declare the elicitation capability in _meta.io.modelcontextprotocol/clientCapabilities on each request:

client/elicitation#capabilities

Judged by elicitation.client-declares-capability.

ELIC-058

MUST · binds the client

Clients declaring the elicitation capability MUST support at least one mode (form or url).

client/elicitation#capabilities

Excluded. No declaration can violate it on the wire. The page makes an elicitation object naming neither mode “equivalent to declaring support for form mode only”, so every declared elicitation capability names at least one mode. What remains is whether the client can actually handle the mode it declared, which is internal: a client that cannot still returns a well-formed decline or cancel.

ELIC-059

MUST NOT · binds the server

Servers MUST NOT send elicitation requests with modes that are not supported by the client.

client/elicitation#capabilities

Judged by elicitation.mode-supported.

ELIC-060

MUST · binds the server

All elicitation requests MUST include the following parameters:

client/elicitation#elicitation-requests

Judged by elicitation.request-parameters.

ELIC-061

MUST · binds the client

Clients MUST treat requests without a mode field as form mode.

client/elicitation#elicitation-requests

Excluded. A reading, not an act, like MRTR-007: a client’s answers to a form mode request and to one without mode are the same messages (accept with content, decline, cancel), and content is optional in the result, so no answer shows which reading the client took. The server half — that such a request is form mode — is what elicitation.mode-supported and elicitation.form-schema-present apply.

ELIC-062

MUST · binds the server

Form mode elicitation requests MUST either specify mode: "form" or omit the mode field, and include these additional parameters:

client/elicitation#form-mode-elicitation-requests

Judged by elicitation.form-schema-present.

ELIC-063

SHOULD · binds the client

Clients that support defaults SHOULD pre-populate form fields with these values.

client/elicitation#requested-schema

Excluded. UI behaviour: pre-populating a form is what the user sees before submitting. The submitted content cannot show it — the user may change or clear every default — so no message carries the clause.

ELIC-064

MUST · binds the server

URL mode elicitation requests MUST specify mode: "url", a message, and include these additional parameters:

client/elicitation#url-mode-elicitation-requests

Judged by elicitation.url-parameters.

ELIC-065

MUST · binds the server

The url parameter MUST contain a valid URL.

client/elicitation#url-mode-elicitation-requests

Judged by elicitation.url-valid.

ELIC-066

SHOULD · binds the client

Clients SHOULD provide manual controls that let the user retry or cancel the original request (or otherwise resume interacting with the client).

client/elicitation#example-request-sensitive-data

Excluded. UI behaviour: the controls the client offers its user. The wire shows only whether a retry or cancellation was eventually sent, which a user may decline to do whatever controls exist.

ELIC-067

SHOULD NOT · binds the server

Servers SHOULD NOT assume that elicitation requests will always succeed

client/elicitation#error-handling

Excluded. Forbids an assumption. Its wire-visible consequence would be a server that breaks when an elicitation is declined, and the page leaves the server free to answer a declined retry with a result, an error or another round, so no answer is wrong on its face — the same reasoning as MRTR-014.

ELIC-068

MUST · binds the server

and MUST handle cases where the user declines or cancels the elicitation, or where the client fails to process the request.

client/elicitation#error-handling

Excluded. “Handle” names no observable outcome: the specification lets a server answer a declined, cancelled or failed elicitation with a result, an error or a further input_required round, and every one of those is handling. A server that fails to handle the case shows it only by breaking — a crash or a hang ends the recording rather than writing anything into it.

ELIC-069

MUST · binds the server

However, if state is stored, servers implementing elicitation MUST securely associate this state with individual users following the guidelines in the security best practices document. Specifically: State storage MUST be protected against unauthorized access; For remote MCP servers, user identification MUST be derived from credentials acquired via MCP authorization when possible (e.g. sub claim)

client/elicitation#statefulness

Excluded. Server-internal state handling. How a server stores per-user state, protects it and binds it to an identity happens behind its own storage and authorization, and the identity it binds to is established outside the session’s messages, by MCP authorization (whose pages this registry keeps out of scope, sources.json). Verified, where verified at all, by the server’s own security review and tests; at 2026-07-28 the state a client carries is requestState, opaque by construction (MRTR-008).

ELIC-070

MUST NOT · binds the server

MCP servers MUST NOT rely on URL mode elicitation to authorize users for themselves.

client/elicitation#url-mode-elicitation-for-oauth-flows

Excluded. Concerns what the server treats as authorization of its own users — an internal decision. A URL mode elicitation used to sign a user in to the server looks on the wire exactly like one used for a third-party grant; the difference is what the server does with the outcome.

ELIC-071

MUST NOT · binds the server

The third-party credentials MUST NOT transit through the MCP client

client/elicitation#understanding-the-distinction

Excluded. Third-party credentials are opaque strings whose provenance no message declares: a check cannot tell one in a result from any other string, and by design they never enter the session at all. The obligation is the server’s — credentials could only transit the client if the server sent them — and it is kept by the flow the server builds, outside the recording.

ELIC-072

MUST NOT · binds the server

The MCP server MUST NOT use the client’s credentials for the third-party service

client/elicitation#understanding-the-distinction

Excluded. Token passthrough happens between the server and the third-party service, outside the MCP session; the recording holds only the client–server exchange, in which the client’s credentials appear (as HTTP authorization) whether or not the server reuses them elsewhere.

ELIC-073

MUST · binds the server

The user MUST authorize the MCP server directly

client/elicitation#understanding-the-distinction

Excluded. By the clause’s own words the interaction “happens outside the MCP protocol, without involving the MCP client”: it is between the user’s browser and the server or a third-party authorization server, so a recording of the MCP session cannot contain it.

ELIC-074

MUST NOT · binds the server

The MCP server MUST NOT transmit credentials obtained through URL mode elicitation to the MCP client.

client/elicitation#understanding-the-distinction

Excluded. The same barrier as the transit clause: a credential obtained through URL mode elicitation is an opaque string whose provenance no message declares, so a check cannot tell one in a result from any other value the server returns.

ELIC-075

MUST · binds the server

Servers MUST bind elicitation requests to the client and user identity

client/elicitation#security-considerations

Excluded. Binding is server-internal state, and the identity it binds to is established by authorization outside the session’s messages, so no message shows whether an elicitation was bound to it.

ELIC-076

MUST · binds the client

Clients MUST provide clear indication of which server is requesting information

client/elicitation#security-considerations

Excluded. Binds the client’s user interface — what it shows the user, offers them, or lets them do — and none of that reaches the wire: a recording carries the client’s messages, not its screens. The reference host this project ships has no interactive interface at all (it answers from its interaction script, crates/mcp-reference-host/src/handler.rs), so the clause is a host-implementation property, reviewed in the host, never judged from a trace.

ELIC-077

SHOULD · binds the client

Clients SHOULD implement user approval controls

client/elicitation#security-considerations

Excluded. Binds the client’s user interface — what it shows the user, offers them, or lets them do — and none of that reaches the wire: a recording carries the client’s messages, not its screens. The reference host this project ships has no interactive interface at all (it answers from its interaction script, crates/mcp-reference-host/src/handler.rs), so the clause is a host-implementation property, reviewed in the host, never judged from a trace.

ELIC-078

SHOULD · binds the client

Clients SHOULD allow users to decline elicitation requests at any time

client/elicitation#security-considerations

Excluded. Binds the client’s user interface — what it shows the user, offers them, or lets them do — and none of that reaches the wire: a recording carries the client’s messages, not its screens. The reference host this project ships has no interactive interface at all (it answers from its interaction script, crates/mcp-reference-host/src/handler.rs), so the clause is a host-implementation property, reviewed in the host, never judged from a trace.

ELIC-079

SHOULD · binds the client

Clients SHOULD present elicitation requests in a way that makes it clear what information is being requested and why

client/elicitation#security-considerations

Excluded. Binds the client’s user interface — what it shows the user, offers them, or lets them do — and none of that reaches the wire: a recording carries the client’s messages, not its screens. The reference host this project ships has no interactive interface at all (it answers from its interaction script, crates/mcp-reference-host/src/handler.rs), so the clause is a host-implementation property, reviewed in the host, never judged from a trace.

ELIC-080

MUST NOT · binds the server

MCP servers requesting elicitation: MUST NOT include sensitive information about the end-user, including credentials, personally identifiable information, etc., in the URL sent to the client in a URL elicitation request.

client/elicitation#safe-url-handling

Excluded. Whether a URL’s path or query carries “sensitive information about the end-user” is a semantic judgement about opaque values — an identifier in a query may be a random nonce or an email address — so a check would convict on a guess. The page’s own examples put an elicitationId in the query, which is exactly the kind of value a pattern would misread.

ELIC-081

MUST NOT · binds the server

MCP servers requesting elicitation: MUST NOT provide a URL which is pre-authenticated to access a protected resource, as the URL could be used to impersonate the user by a malicious client.

client/elicitation#safe-url-handling

Excluded. Whether a URL grants access without further authentication is a property of the server it points to, observable only by dereferencing it — which a validator must not do (the client rules on the same page forbid even pre-fetching it), and which a recording does not contain.

ELIC-082

SHOULD NOT · binds the server

MCP servers requesting elicitation: SHOULD NOT include URLs intended to be clickable in any field of a form mode elicitation request.

client/elicitation#safe-url-handling

Excluded. Intent: the clause forbids URLs “intended to be clickable”, and a form’s message or a field’s description may mention a URL for reference. A check for URL-shaped text would convict a server for mentioning a link, and the intent itself is not on the wire.

ELIC-083

SHOULD · binds the server

MCP servers requesting elicitation: SHOULD use HTTPS URLs for non-development environments.

client/elicitation#safe-url-handling

Excluded. Its antecedent — that this is a non-development environment — is not in the trace. A loopback host suggests development without proving it, and a staging or internal host proves nothing either way, so an http URL is not by itself evidence of a violation. The scheme is recorded; the environment is not.

ELIC-084

MUST · binds the client

Clients implementing URL mode elicitation MUST handle URLs carefully to prevent users from unknowingly clicking malicious links.

client/elicitation#safe-url-handling

Excluded. Binds what the client does with a URL outside the MCP session — fetching it, opening it, displaying it — none of which is a message the session carries. The reference host never dereferences an elicitation URL: it answers URL mode from its interaction script and records the id (answer_elicitation, crates/mcp-reference-host/src/handler.rs).

ELIC-085

MUST NOT · binds the client

When handling URL mode elicitation requests, MCP clients: MUST NOT automatically pre-fetch the URL or any of its metadata.

client/elicitation#safe-url-handling

Excluded. Binds what the client does with a URL outside the MCP session — fetching it, opening it, displaying it — none of which is a message the session carries. The reference host never dereferences an elicitation URL: it answers URL mode from its interaction script and records the id (answer_elicitation, crates/mcp-reference-host/src/handler.rs).

ELIC-086

MUST NOT · binds the client

When handling URL mode elicitation requests, MCP clients: MUST NOT open the URL without explicit consent from the user.

client/elicitation#safe-url-handling

Excluded. Binds what the client does with a URL outside the MCP session — fetching it, opening it, displaying it — none of which is a message the session carries. The reference host never dereferences an elicitation URL: it answers URL mode from its interaction script and records the id (answer_elicitation, crates/mcp-reference-host/src/handler.rs).

ELIC-087

MUST · binds the client

When handling URL mode elicitation requests, MCP clients: MUST show the full URL to the user for examination before consent.

client/elicitation#safe-url-handling

Excluded. Binds the client’s user interface — what it shows the user, offers them, or lets them do — and none of that reaches the wire: a recording carries the client’s messages, not its screens. The reference host this project ships has no interactive interface at all (it answers from its interaction script, crates/mcp-reference-host/src/handler.rs), so the clause is a host-implementation property, reviewed in the host, never judged from a trace.

ELIC-088

MUST · binds the client

When handling URL mode elicitation requests, MCP clients: MUST open the URL provided by the server in a secure manner that does not enable the client or LLM to inspect the content or user inputs.

client/elicitation#safe-url-handling

Excluded. Binds what the client does with a URL outside the MCP session — fetching it, opening it, displaying it — none of which is a message the session carries. The reference host never dereferences an elicitation URL: it answers URL mode from its interaction script and records the id (answer_elicitation, crates/mcp-reference-host/src/handler.rs).

ELIC-089

SHOULD · binds the client

When handling URL mode elicitation requests, MCP clients: SHOULD highlight the domain of the URL to mitigate subdomain spoofing.

client/elicitation#safe-url-handling

Excluded. Binds the client’s user interface — what it shows the user, offers them, or lets them do — and none of that reaches the wire: a recording carries the client’s messages, not its screens. The reference host this project ships has no interactive interface at all (it answers from its interaction script, crates/mcp-reference-host/src/handler.rs), so the clause is a host-implementation property, reviewed in the host, never judged from a trace.

ELIC-090

SHOULD · binds the client

When handling URL mode elicitation requests, MCP clients: SHOULD have warnings for ambiguous/suspicious URIs (i.e., containing Punycode).

client/elicitation#safe-url-handling

Excluded. Binds the client’s user interface — what it shows the user, offers them, or lets them do — and none of that reaches the wire: a recording carries the client’s messages, not its screens. The reference host this project ships has no interactive interface at all (it answers from its interaction script, crates/mcp-reference-host/src/handler.rs), so the clause is a host-implementation property, reviewed in the host, never judged from a trace.

ELIC-091

SHOULD NOT · binds the client

When handling URL mode elicitation requests, MCP clients: SHOULD NOT render URLs as clickable in any field of an elicitation request, except for the url field in a URL elicitation request (with the restrictions detailed above).

client/elicitation#safe-url-handling

Excluded. Binds the client’s user interface — what it shows the user, offers them, or lets them do — and none of that reaches the wire: a recording carries the client’s messages, not its screens. The reference host this project ships has no interactive interface at all (it answers from its interaction script, crates/mcp-reference-host/src/handler.rs), so the clause is a host-implementation property, reviewed in the host, never judged from a trace.

ELIC-092

MUST NOT · binds the server

Servers MUST NOT rely on client-provided user identification without server verification, as this can be forged.

client/elicitation#identifying-the-user

Excluded. Server-internal: whether the server verified an identity before trusting it is a decision made with information — its authorization context — that the session’s messages do not carry.

ELIC-093

SHOULD · binds the server

Instead, servers SHOULD follow security best practices.

client/elicitation#identifying-the-user

Excluded. Points to a separate document whose practices are server-internal; nothing in the session’s messages shows which were followed.

ELIC-094

MUST NOT · binds the server

Servers MUST NOT request sensitive information (passwords, API keys, etc.) via form mode

client/elicitation#form-mode-security

Excluded. Whether a requested field is “sensitive information” — the page’s own definition is “secrets and credentials that grant access or authorize transactions” — is a judgement about meaning, not syntax: a schema property named token may be a display preference and one named answer may collect a password. A check would have to guess from field names, and a guess convicts conforming servers. The server’s author decides it; nothing in the message settles it.

ELIC-095

SHOULD · binds the client

Clients SHOULD validate all responses against the provided schema

client/elicitation#form-mode-security

Judged by elicitation.response-matches-schema.

ELIC-096

SHOULD · binds the server

Servers SHOULD validate received data matches the requested schema

client/elicitation#form-mode-security

Excluded. Binds an act of validation, as MRTR-021 does: the server’s outcome — accepting the data, re-asking, or failing — is the only thing that reaches the wire, and each is consistent with a server that validated and with one that did not.

ELIC-097

MUST · binds the server

The MCP Server MUST verify the identity of the user who opens the URL before accepting information.

client/elicitation#phishing

Excluded. Identity verification of the user who opens the URL happens between that user’s browser and the server, outside the MCP session; the recording carries the URL the server sent and the client’s accept, not who opened it.

ELIC-098

MUST · binds the server

To prevent this attack, the server MUST ensure that the user who started the elicitation request (the end-user who is accessing the server via the MCP client) is the same user who completes the authorization flow.

client/elicitation#phishing

Excluded. Identity verification of the user who opens the URL happens between that user’s browser and the server, outside the MCP session; the recording carries the URL the server sent and the client’s accept, not who opened it.

ELIC-099

MUST · binds the server

In all implementations, the server MUST ensure that the mechanism to determine the user’s identity is resilient to attacks where an attacker can modify the elicitation URL.

client/elicitation#phishing

Excluded. Identity verification of the user who opens the URL happens between that user’s browser and the server, outside the MCP session; the recording carries the URL the server sent and the client’s accept, not who opened it.

SAMP

SAMP-021

SHOULD NOT · binds the client and server

New implementations SHOULD NOT adopt it

client/sampling

Excluded. Whether an implementation is new is not in any message: a session using the feature is equally consistent with an existing implementation that has not yet migrated, which the sentence asks only to migrate.

SAMP-022

SHOULD · binds the client and server

existing implementations SHOULD migrate to integrating directly with LLM provider APIs.

client/sampling

Excluded. Asks for a migration over time, which one recording cannot show either way — a session that uses the feature may come from an implementation partway through migrating, and the feature remains in the specification until removal.

SAMP-023

SHOULD · binds the client

For trust & safety and security, there SHOULD always be a human in the loop with the ability to deny sampling requests.

client/sampling#user-interaction-model

Excluded. Policy and UI: whether a human reviews sampling requests, and whether they can deny one, is the client application’s design. A request answered with a result may have been approved by a person or by policy; nothing in the answer says which.

SAMP-024

SHOULD · binds the client

Applications SHOULD: Provide UI that makes it easy and intuitive to review sampling requests; Allow users to view and edit prompts before sending; Present generated responses for review before delivery

client/sampling#user-interaction-model

Excluded. Binds the client’s user interface — what it shows the user, offers them, or lets them do — and none of that reaches the wire: a recording carries the client’s messages, not its screens. The reference host this project ships has no interactive interface at all (it answers from its interaction script, crates/mcp-reference-host/src/handler.rs), so the clause is a host-implementation property, reviewed in the host, never judged from a trace.

SAMP-025

MUST · binds the client

Clients MUST declare support for tool use via the sampling.tools capability to receive tool-enabled sampling requests.

client/sampling#tools-in-sampling

Excluded. The precondition half of the sentence. A client that has not declared sampling.tools does nothing wrong by receiving a tool-enabled request — the server does, and the sentence’s other half (sampling.tools-declared) judges it. Nothing the client sends can break this half: the declaration is either made or not, and its absence becomes a violation only when such a request arrives, which is the server’s act.

SAMP-026

MUST NOT · binds the server

Servers MUST NOT send tool-enabled sampling requests to Clients that have not declared support for tool use via the sampling.tools capability.

client/sampling#tools-in-sampling

Judged by sampling.tools-declared.

SAMP-027

MUST · binds the client

Clients that support sampling MUST declare the sampling capability in _meta.io.modelcontextprotocol/clientCapabilities on each request:

client/sampling#capabilities

Judged by sampling.client-declares-capability.

SAMP-028

SHOULD · binds the server

Servers SHOULD avoid using these values (e.g. can just omit includeContext since it defaults to "none")

client/sampling#capabilities

Judged by sampling.include-context-avoided.

SAMP-029

SHOULD NOT · binds the server

and SHOULD NOT use them unless the client declares sampling.context capability.

client/sampling#capabilities

Judged by sampling.include-context-declared.

SAMP-030

MUST · binds the server

When a user message contains tool results (type: “tool_result”), it MUST contain ONLY tool results.

client/sampling#tool-result-messages

Judged by sampling.tool-results-only.

SAMP-031

MUST · binds the server

When using tool use in sampling, every assistant message containing ToolUseContent blocks MUST be followed by a user message that consists entirely of ToolResultContent blocks, with each tool use (e.g. with id: $id) matched by a corresponding tool result (with toolUseId: $id), before any other message.

client/sampling#tool-use-and-result-balance

Judged by sampling.tool-use-answered.

SAMP-032

MUST · binds the client

{mode: "required"}: Model MUST use at least one tool before completing

client/sampling#tool-choice-modes

Judged by sampling.tool-choice-required-honoured.

SAMP-033

MUST NOT · binds the client

{mode: "none"}: Model MUST NOT use any tools

client/sampling#tool-choice-modes

Judged by sampling.tool-choice-none-honoured.

SAMP-034

MUST · binds the client and server

Sampling messages MUST contain a role field of "user" or "assistant"; and a content field representing the message data.

client/sampling#messages

Judged by sampling.message-shape.

SAMP-035

SHOULD NOT · binds the client

The list of messages in a sampling request SHOULD NOT be retained between separate requests.

client/sampling#messages

Excluded. Retention is client-internal state: the next request’s messages are the server’s, and say nothing about what the client kept from the last one.

SAMP-036

MUST · binds the client

The client MUST respect the maxTokens parameter.

client/sampling#sampling-parameters

Excluded. A bound in the model’s tokens, and the tokenizer is the model’s: a validator cannot count the tokens of a result’s content without knowing which tokenizer produced it (the result’s model names the model, not its vocabulary), so an over-long answer cannot be shown.

SAMP-037

SHOULD · binds the client

Clients SHOULD implement user approval controls

client/sampling#security-considerations

Excluded. Binds the client’s user interface — what it shows the user, offers them, or lets them do — and none of that reaches the wire: a recording carries the client’s messages, not its screens. The reference host this project ships has no interactive interface at all (it answers from its interaction script, crates/mcp-reference-host/src/handler.rs), so the clause is a host-implementation property, reviewed in the host, never judged from a trace.

SAMP-038

SHOULD · binds the client and server

Both parties SHOULD validate message content

client/sampling#security-considerations

Excluded. Validation is internal; its outcome is whatever each party sends next, and the shape of what they send is judged directly by the clauses that constrain it (tool-message balance, message roles).

SAMP-039

SHOULD · binds the client

Clients SHOULD respect model preference hints

client/sampling#security-considerations

Excluded. Hints are advisory and mapping them is the client’s choice (the page: clients “MAY map hints to equivalent models from different providers”); the result’s model names what was used, but no rule says which model a hint selects, so no answer contradicts one.

SAMP-040

SHOULD · binds the client

Clients SHOULD implement rate limiting

client/sampling#security-considerations

Excluded. A request schedule: rate limiting is measured in elapsed time, which checks may not consult (LIFE-015, the time boundary in 02-architecture.md), and its threshold is the client’s own policy.

SAMP-041

MUST · binds the client and server

Both parties MUST handle sensitive data appropriately

client/sampling#security-considerations

Excluded. “Appropriately” names no observable criterion, and which data is sensitive is a semantic judgement about content (see the elicitation pages’ sensitive-information clauses): no message can be shown to have mishandled it.

SAMP-042

MUST · binds the server

Servers MUST ensure that when replying to a stopReason: "toolUse", each ToolUseContent item is responded to with a ToolResultContent item with a matching toolUseId, and that the user message contains only tool results (no other content types)

client/sampling#security-considerations

Judged by sampling.tool-use-answered, sampling.tool-results-only.

SAMP-043

SHOULD · binds the client and server

Both parties SHOULD implement iteration limits for tool loops

client/sampling#security-considerations

Excluded. A limit on a loop’s length is a policy whose threshold the page does not set: any finite loop in a recording is consistent with some limit, and an unbounded one cannot be recorded.

ROOT

ROOT-011

SHOULD NOT · binds the client and server

New implementations SHOULD NOT adopt it

client/roots

Excluded. Whether an implementation is new is not in any message: a session using the feature is equally consistent with an existing implementation that has not yet migrated, which the sentence asks only to migrate.

ROOT-012

SHOULD · binds the client and server

existing implementations SHOULD migrate to passing directories or files via tool parameters, resource URIs, or server configuration.

client/roots

Excluded. Asks for a migration over time, which one recording cannot show either way — a session that uses the feature may come from an implementation partway through migrating, and the feature remains in the specification until removal.

ROOT-013

MUST · binds the client

Clients that support roots MUST declare the roots capability in _meta.io.modelcontextprotocol/clientCapabilities on each request:

client/roots#capabilities

Judged by roots.client-declares-capability.

ROOT-014

MUST · binds the client

uri: Unique identifier for the root. This MUST be a file:// URI in the current specification.

client/roots#root

Judged by roots.uri-file-scheme.

ROOT-015

MUST · binds the client

Clients MUST: Only expose roots with appropriate permissions; Validate all root URIs to prevent path traversal; Implement proper access controls; Monitor root accessibility

client/roots#security-considerations

Excluded. Client-internal policy: which directories the user permitted, how paths are validated and accessed, and whether they remain reachable are facts about the client’s host system, not its messages. The one part a message carries — the URI’s form — is judged by roots.uri-file-scheme; a file:// URI with .. segments is still well formed, and whether it escapes a permitted directory depends on the filesystem.

ROOT-016

SHOULD · binds the server

Servers SHOULD: Handle cases where roots become unavailable; Respect root boundaries during operations; Validate all paths against provided roots

client/roots#security-considerations

Excluded. Server-internal: what the server does with roots — keeping within their boundaries, validating paths against them, coping when they vanish or change, caching them — happens in its own operations on its host, which the MCP session does not record.

ROOT-017

SHOULD · binds the client

Clients SHOULD: Prompt users for consent before exposing roots to servers; Provide clear user interfaces for root management; Validate root accessibility before exposing; Monitor for root changes

client/roots#implementation-guidelines

Excluded. UI and internal monitoring: consent prompts and root-management screens are the client’s interface, and checking or watching roots’ accessibility happens on its filesystem. A recording carries only the roots it finally reported.

ROOT-018

SHOULD · binds the server

Servers SHOULD: Check for roots capability before usage

client/roots#implementation-guidelines

Judged by roots.capability-checked.

ROOT-019

SHOULD · binds the server

Servers SHOULD: Respect root boundaries in operations; Cache root information appropriately

client/roots#implementation-guidelines

Excluded. Server-internal: what the server does with roots — keeping within their boundaries, validating paths against them, coping when they vanish or change, caching them — happens in its own operations on its host, which the MCP session does not record.

AUTH

AUTH-086

SHOULD · binds the client and server

Implementations using an HTTP-based transport SHOULD conform to this specification.

basic/authorization/index#protocol-requirements

Excluded. Conformance to the pages as a whole is what their own entries judge, clause by clause; the sentence adds no property of a message beyond them. It binds only implementations that support authorization at all, which the page makes OPTIONAL. Same sentence as BASE-068 on the basic page.

AUTH-087

SHOULD NOT · binds the client and server

Implementations using an STDIO transport SHOULD NOT follow this specification, and instead retrieve credentials from the environment.

basic/authorization/index#protocol-requirements

Excluded. A stdio session has no HTTP layer for a challenge or a token header to appear in, so a recording cannot show the specification being followed there; retrieving credentials from the environment is process-local conduct with no wire footprint. Same sentence as BASE-068 on the basic page.

AUTH-088

MUST · binds the client and server

Implementations using alternative transports MUST follow established security best practices for their protocol.

basic/authorization/index#protocol-requirements

Excluded. Binds transports other than the two this revision defines, which no recording of an MCP session over stdio or Streamable HTTP carries, and names no practice a check could hold a message to.

AUTH-089

MUST · binds the server

Authorization servers MUST implement OAuth 2.1 with appropriate security measures for both confidential and public clients.

basic/authorization/index#overview

Excluded. Binds the authorization server, the separate OAuth party the page’s Roles section places outside the MCP server. A client reaches it directly, never through the MCP endpoint, so a recording of the MCP exchanges holds none of its conduct.

AUTH-090

SHOULD · binds the client and server

Authorization servers and MCP clients SHOULD support OAuth Client ID Metadata Documents

basic/authorization/index#overview

Excluded. Support for a client registration mechanism is exercised between the client and the authorization server, off the MCP endpoint. Binds the authorization server, the separate OAuth party the page’s Roles section places outside the MCP server. A client reaches it directly, never through the MCP endpoint, so a recording of the MCP exchanges holds none of its conduct.

AUTH-091

MUST · binds the server

MCP servers MUST implement OAuth 2.0 Protected Resource Metadata (RFC9728).

basic/authorization/index#overview

Excluded. The Protected Resource Metadata document is not on the MCP endpoint, and a recording cannot show it. The resource_metadata URL names the server’s own address, which mcp-trace-capture does not rewrite, so a client fetches the document past the proxy; the well-known fallback is built from the proxy’s origin, and the proxy maps every path under the upstream’s (/.well-known/... reaches /mcp/.well-known/...), where no server serves it. Where a fetch does pass through, its http event records no request target, so its JSON body cannot be told from any other.

AUTH-092

MUST · binds the client

MCP clients MUST use OAuth 2.0 Protected Resource Metadata for authorization server discovery.

basic/authorization/index#overview

Excluded. Which document a client used to find its authorization server is visible only in fetches off the MCP endpoint. The Protected Resource Metadata document is not on the MCP endpoint, and a recording cannot show it. The resource_metadata URL names the server’s own address, which mcp-trace-capture does not rewrite, so a client fetches the document past the proxy; the well-known fallback is built from the proxy’s origin, and the proxy maps every path under the upstream’s (/.well-known/... reaches /mcp/.well-known/...), where no server serves it. Where a fetch does pass through, its http event records no request target, so its JSON body cannot be told from any other.

AUTH-093

MUST · binds the server

MCP authorization servers MUST provide at least one of the following discovery mechanisms:

basic/authorization/index#overview

Excluded. Binds the authorization server, the separate OAuth party the page’s Roles section places outside the MCP server. A client reaches it directly, never through the MCP endpoint, so a recording of the MCP exchanges holds none of its conduct.

AUTH-094

MUST · binds the client

MCP clients MUST support both discovery mechanisms to obtain the information required to interact with the authorization server.

basic/authorization/index#overview

Excluded. Conduct inside the client’s OAuth flow (authorization server metadata discovery), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records.

AUTH-095

MUST · binds the client and server

Implementations MUST follow the normative discovery requirements defined in Authorization Server Discovery.

basic/authorization/index#authorization-server-discovery

Excluded. Points at requirements stated elsewhere (the authorization-server-discovery page), each entered under its own id there; the sentence adds no obligation a recording could show apart from them.

AUTH-096

MUST · binds the client

Before initiating the authorization flow, MCP clients MUST obtain a client ID through one of three registration mechanisms: Client ID Metadata Documents, pre-registration, or Dynamic Client Registration, following the requirements and selection priority defined in Client Registration.

basic/authorization/index#client-registration

Excluded. Conduct inside the client’s OAuth flow (client registration), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records.

AUTH-097

SHOULD · binds the server

MCP servers SHOULD include a scope parameter in the WWW-Authenticate header as defined in RFC 6750 Section 3 to indicate the scopes required for accessing the resource.

basic/authorization/index#scope-selection-strategy

Judged by auth.challenge-scope.

AUTH-098

MUST NOT · binds the client

Clients MUST NOT assume any particular set relationship between the challenged scope set and scopes_supported.

basic/authorization/index#scope-selection-strategy

Excluded. Conduct inside the client’s OAuth flow (the scope it requests, whatever it assumes about scopes_supported), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records.

AUTH-099

MUST · binds the client

Clients MUST treat the scopes provided in the challenge as authoritative for the current operation.

basic/authorization/index#scope-selection-strategy

Excluded. Conduct inside the client’s OAuth flow (the scope it requests in its authorization request), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records.

AUTH-100

SHOULD · binds the client

When re-authorizing, clients SHOULD include these scopes alongside any previously granted scopes to avoid losing permissions needed for other operations

basic/authorization/index#scope-selection-strategy

Excluded. Conduct inside the client’s OAuth flow (the scope of its re-authorization request), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records.

AUTH-101

SHOULD · binds the server

Servers SHOULD strive for consistency in how they construct scope sets but they are not required to surface every dynamically issued scope through scopes_supported.

basic/authorization/index#scope-selection-strategy

Excluded. Striving for consistency is a design aim, not a property any one challenge has, and challenges for different operations legitimately name different scopes; scopes_supported lives in the Protected Resource Metadata document, which a recording does not carry.

AUTH-102

SHOULD · binds the client

When implementing authorization flows, MCP clients SHOULD follow the principle of least privilege by requesting only the scopes necessary for their intended operations.

basic/authorization/index#scope-selection-strategy

Excluded. Conduct inside the client’s OAuth flow (the scope of its authorization request), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records.

AUTH-103

SHOULD · binds the client

During the initial authorization handshake, MCP clients SHOULD follow this priority order for scope selection:

basic/authorization/index#scope-selection-strategy

Excluded. Conduct inside the client’s OAuth flow (the scope of its authorization request), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records.

AUTH-104

MUST · binds the client

Before redirecting the user-agent, the client MUST record the issuer value from the selected authorization server’s validated metadata document (see Authorization Server Metadata Discovery) and associate it with the same per-request record used to store the PKCE code verifier (and the state value, if used).

basic/authorization/index#authorization-response-validation

Excluded. Conduct inside the client’s OAuth flow (the issuer it records beside its PKCE verifier, which is the client’s own state), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records.

AUTH-105

SHOULD · binds the server

MCP authorization servers SHOULD include the iss parameter in authorization responses, including error responses, as defined in RFC9207 Section 2.

basic/authorization/index#authorization-response-validation

Excluded. Authorization responses reach the client through the user’s browser. Binds the authorization server, the separate OAuth party the page’s Roles section places outside the MCP server. A client reaches it directly, never through the MCP endpoint, so a recording of the MCP exchanges holds none of its conduct.

AUTH-106

MUST · binds the server

Authorization servers that include the iss parameter MUST advertise this by setting authorization_response_iss_parameter_supported to true in their metadata (RFC9207 Section 2.3).

basic/authorization/index#authorization-response-validation

Excluded. Binds the authorization server, the separate OAuth party the page’s Roles section places outside the MCP server. A client reaches it directly, never through the MCP endpoint, so a recording of the MCP exchanges holds none of its conduct.

AUTH-107

MUST · binds the client

On receiving the authorization response, MCP clients MUST apply the validation in RFC9207 Section 2.4 before transmitting the authorization code to any token endpoint:

basic/authorization/index#authorization-response-validation

Excluded. Conduct inside the client’s OAuth flow (the authorization response’s iss and the issuer recorded for it), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records.

AUTH-108

SHOULD · binds the server

A future revision of this specification is expected to upgrade authorization server inclusion of iss from SHOULD to MUST.

basic/authorization/index#authorization-response-validation

Excluded. Names the two keywords to describe a future revision’s intent; it binds no party at this one. The obligation it refers to is the authorization server’s SHOULD entered above, excluded for the reason given there.

AUTH-109

MUST NOT · binds the client

After decoding the iss value from the application/x-www-form-urlencoded response per RFC 9207 Section 2.4, clients MUST NOT apply scheme or host case folding, default-port elision, trailing-slash, or percent-encoding normalization (RFC 3986 Sections 6.2.2-6.2.3) before comparison.

basic/authorization/index#authorization-response-validation

Excluded. Conduct inside the client’s OAuth flow (the authorization response’s iss and the issuer recorded for it), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records.

AUTH-110

MUST NOT · binds the client

This validation applies equally to error responses - on mismatch the client MUST NOT act on or display error, error_description, or error_uri.

basic/authorization/index#authorization-response-validation

Excluded. Conduct inside the client’s OAuth flow (the authorization response’s iss and the issuer recorded for it), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records. Displaying an error is user interface besides.

AUTH-111

MUST · binds the client

MCP clients MUST implement Resource Indicators for OAuth 2.0 as defined in RFC 8707 to explicitly specify the target resource for which the token is being requested.

basic/authorization/index#resource-parameter-implementation

Excluded. Conduct inside the client’s OAuth flow (the resource parameter of its authorization and token requests), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records.

AUTH-112

MUST · binds the client

The resource parameter: MUST be included in both authorization requests and token requests.; MUST identify the MCP server that the client intends to use the token with.; MUST use the canonical URI of the MCP server as defined in RFC 8707 Section 2.

basic/authorization/index#resource-parameter-implementation

Excluded. Conduct inside the client’s OAuth flow (the resource parameter of its authorization and token requests), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records.

AUTH-113

SHOULD · binds the client

MCP clients SHOULD provide the most specific URI that they can for the MCP server they intend to access, following the guidance in RFC 8707.

basic/authorization/index#canonical-server-uri

Excluded. Conduct inside the client’s OAuth flow (the resource parameter of its authorization and token requests), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records.

AUTH-114

SHOULD · binds the client and server

While the canonical form uses lowercase scheme and host components, implementations SHOULD accept uppercase scheme and host components for robustness and interoperability.

basic/authorization/index#canonical-server-uri

Excluded. Accepting a URI is a comparison made by whoever receives the resource parameter or validates a token’s audience — the authorization server, or the MCP server inside its validation — and neither comparison is a message on the MCP endpoint.

AUTH-115

SHOULD · binds the client and server

While both https://mcp.example.com/ (with trailing slash) and https://mcp.example.com (without trailing slash) are technically valid absolute URIs according to RFC 3986, implementations SHOULD consistently use the form without the trailing slash for better interoperability unless the trailing slash is semantically significant for the specific resource.

basic/authorization/index#canonical-server-uri

Excluded. The canonical URI’s spelling appears in the resource parameter of requests to the authorization server and in token audiences, neither of which a recording of the MCP endpoint carries; and an http event records no request target, so not even the endpoint URL the client used is there.

AUTH-116

MUST · binds the client

MCP clients MUST send this parameter regardless of whether authorization servers support it.

basic/authorization/index#canonical-server-uri

Excluded. Conduct inside the client’s OAuth flow (the resource parameter of its authorization and token requests), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records.

AUTH-117

MUST · binds the client

Access token handling when making requests to MCP servers MUST conform to the requirements defined in OAuth 2.1 Section 5 “Resource Requests”.

basic/authorization/index#token-requirements

Excluded. Authorization is never in a trace: recorders keep headers by allowlist (RECORDED_HEADERS), and credentials stay off it by construction (docs/plan/05-security-model.md). Which requests carried a token, and which token, cannot be read back from a recording. The section’s other requirement, no token in the query string, has its own entry.

AUTH-118

MUST · binds the client

MCP client MUST use the Authorization request header field defined in OAuth 2.1 Section 5.1.1:

basic/authorization/index#token-requirements

Excluded. Authorization is never in a trace: recorders keep headers by allowlist (RECORDED_HEADERS), and credentials stay off it by construction (docs/plan/05-security-model.md). Which requests carried a token, and which token, cannot be read back from a recording.

AUTH-119

MUST · binds the client

Note that authorization MUST be included in every HTTP request from client to server.

basic/authorization/index#token-requirements

Excluded. Authorization is never in a trace: recorders keep headers by allowlist (RECORDED_HEADERS), and credentials stay off it by construction (docs/plan/05-security-model.md). Which requests carried a token, and which token, cannot be read back from a recording. A 401 to a request does not settle it either: an expired token draws the same answer as a missing one.

AUTH-120

MUST NOT · binds the client

Access tokens MUST NOT be included in the URI query string

basic/authorization/index#token-requirements

Excluded. An http event records the method, status and allowlisted headers, and no request target: neither the path nor the query string a request was sent to is in the trace, so a token in the URI cannot be seen. Recording the query to judge this would write into every trace the very credential the clause keeps out of URIs.

AUTH-121

MUST · binds the server

MCP servers, acting in their role as an OAuth 2.1 resource server, MUST validate access tokens as described in OAuth 2.1 Section 5.2.

basic/authorization/index#token-handling

Excluded. Token validation is decided inside the server, against a token the recording never holds (Authorization is not recorded). What the server says about the outcome is its challenge, judged where the page states what it must carry: the error-handling table and the 401 for invalid tokens.

AUTH-122

MUST · binds the server

MCP servers MUST validate that access tokens were issued specifically for them as the intended audience, according to RFC 8707 Section 2.

basic/authorization/index#token-handling

Excluded. Token validation is decided inside the server, against a token the recording never holds (Authorization is not recorded). What the server says about the outcome is its challenge, judged where the page states what it must carry: the error-handling table and the 401 for invalid tokens.

AUTH-123

MUST · binds the server

If validation fails, servers MUST respond according to OAuth 2.1 Section 5.3 error handling requirements.

basic/authorization/index#token-handling

Excluded. Whether validation failed is decided inside the server, against a token the recording never holds, and the sentence imports OAuth 2.1 Section 5.3 wholesale. What a recording can hold the response to is the page’s own statement of it: the status each declared error receives and the 401 for an invalid token, judged by auth.error-status and auth.invalid-token-401.

AUTH-124

MUST · binds the server

Invalid or expired tokens MUST receive a HTTP 401 response.

basic/authorization/index#token-handling

Judged by auth.invalid-token-401.

AUTH-125

MUST NOT · binds the client

MCP clients MUST NOT send tokens to the MCP server other than ones issued by the MCP server’s authorization server.

basic/authorization/index#token-handling

Excluded. Authorization is never in a trace: recorders keep headers by allowlist (RECORDED_HEADERS), and credentials stay off it by construction (docs/plan/05-security-model.md). Which requests carried a token, and which token, cannot be read back from a recording.

AUTH-126

MUST · binds the server

MCP servers MUST only accept tokens that are valid for use with their own resources.

basic/authorization/index#token-handling

Excluded. Token validation is decided inside the server, against a token the recording never holds (Authorization is not recorded). What the server says about the outcome is its challenge, judged where the page states what it must carry: the error-handling table and the 401 for invalid tokens.

AUTH-127

MUST NOT · binds the server

MCP servers MUST NOT accept or transit any other tokens.

basic/authorization/index#token-handling

Excluded. Token validation is decided inside the server, against a token the recording never holds (Authorization is not recorded). What the server says about the outcome is its challenge, judged where the page states what it must carry: the error-handling table and the 401 for invalid tokens. Transiting a token is a request to an upstream service, outside the MCP session.

AUTH-128

MUST · binds the client

MCP Clients that desire refresh tokens: MUST keep refresh tokens confidential in transit and storage as specified in OAuth 2.1 Section 4.3; SHOULD include refresh_token in their grant_types client metadata; MUST NOT assume refresh tokens will be issued; the AS retains discretion

basic/authorization/index#refresh-tokens

Excluded. Refresh tokens are issued and redeemed at the authorization server’s token endpoint and kept in the client’s storage; client metadata is registered with the authorization server. A client reaches it directly, never through the MCP endpoint, so a recording of the MCP exchanges holds none of its conduct.

AUTH-129

SHOULD NOT · binds the server

MCP Servers (Protected Resources) SHOULD NOT include offline_access in WWW-Authenticate scope or Protected Resource Metadata scopes_supported, as refresh tokens are not a resource requirement.

basic/authorization/index#refresh-tokens

Judged by auth.no-offline-access-challenge.

AUTH-130

MUST · binds the server

Servers MUST return appropriate HTTP status codes for authorization errors

basic/authorization/index#error-handling

Judged by auth.error-status.

AUTH-131

SHOULD · binds the server

When a client makes a request with an access token with insufficient scope during runtime operations, the server SHOULD respond with: HTTP 403 Forbidden status code (per RFC 6750 Section 3.1); WWW-Authenticate header with the Bearer scheme and additional parameters: error="insufficient_scope" - indicating the specific type of authorization failure; scope="required_scope1 required_scope2" - specifying the minimum scopes needed for the operation; resource_metadata - the URI of the Protected Resource Metadata document (for consistency with 401 responses)

basic/authorization/index#runtime-insufficient-scope-errors

Judged by auth.insufficient-scope-response.

AUTH-132

SHOULD · binds the server

Server Scope Management: When responding with insufficient scope errors, servers SHOULD include the scopes needed to satisfy the current operation in the scope parameter, consistent with RFC 6750 Section 3.1.

basic/authorization/index#runtime-insufficient-scope-errors

Judged by auth.insufficient-scope-names-scopes.

AUTH-133

SHOULD · binds the server

Whatever scope-inclusion strategy a server adopts, servers SHOULD include all scopes required for the current operation in a single challenge.

basic/authorization/index#runtime-insufficient-scope-errors

Judged by auth.single-challenge.

AUTH-134

SHOULD · binds the server

Servers SHOULD be consistent in their scope inclusion strategy to provide predictable behavior for clients.

basic/authorization/index#runtime-insufficient-scope-errors

Excluded. A strategy is a policy over every challenge the server issues, across sessions and users; one recording shows a few challenges for different operations, which legitimately name different scopes, and cannot tell an inconsistent strategy from a consistent one applied to different requests.

AUTH-135

SHOULD · binds the server

Servers SHOULD consider the user experience impact when determining which scopes to include in the response, as misconfigured scopes may require frequent user interaction.

basic/authorization/index#runtime-insufficient-scope-errors

Excluded. Binds the server’s deliberation, not a message: a challenge shows the scopes chosen, not whether their user experience impact was weighed.

AUTH-136

SHOULD · binds the client

Clients SHOULD respond to these errors by requesting a new access token with an increased set of scopes via a step-up authorization flow or handle the errors in other, appropriate ways.

basic/authorization/index#step-up-authorization-flow

Excluded. Conduct inside the client’s OAuth flow (the token request a step-up makes), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records. The clause also admits “other, appropriate ways”, which no message distinguishes.

AUTH-137

SHOULD · binds the client

Clients acting on behalf of a user SHOULD attempt the step-up authorization flow.

basic/authorization/index#step-up-authorization-flow

Excluded. Whether a client acts on behalf of a user or on its own (client_credentials) is a fact about its grant, which no MCP message states. Conduct inside the client’s OAuth flow (the step-up re-authorization), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records.

AUTH-138

SHOULD · binds the client

Clients SHOULD implement retry limits and SHOULD track scope upgrade attempts to avoid repeated failures for the same resource and operation combination.

basic/authorization/index#step-up-authorization-flow

Excluded. A limit is a property of the client’s implementation, which a session that simply stops retrying satisfies whatever the limit is; the page fixes no number (“no more than a few times”) a recording could be held to, and the attempts tracked are re-authorizations off the MCP endpoint.

AUTH-139

MUST · binds the server

Servers MUST account for scope hierarchies, where a broader scope implies narrower ones, when deciding whether a token is sufficient for an operation.

basic/authorization/index#step-up-authorization-flow

Excluded. The decision is made inside the server from the scopes a token carries, and the token is never recorded; a challenge shows the outcome, not the scopes it was decided against.

AUTH-140

MUST · binds the client and server

Implementations of this specification MUST follow the normative security requirements in Security Considerations

basic/authorization/index#security-considerations

Excluded. Points at requirements stated elsewhere (the security-considerations page), each entered under its own id there; the sentence adds no obligation a recording could show apart from them.

AUTH-141

MUST · binds the server

MCP servers MUST implement the OAuth 2.0 Protected Resource Metadata (RFC9728) specification to indicate the locations of authorization servers.

basic/authorization/authorization-server-discovery#authorization-server-location

Excluded. The Protected Resource Metadata document is not on the MCP endpoint, and a recording cannot show it. The resource_metadata URL names the server’s own address, which mcp-trace-capture does not rewrite, so a client fetches the document past the proxy; the well-known fallback is built from the proxy’s origin, and the proxy maps every path under the upstream’s (/.well-known/... reaches /mcp/.well-known/...), where no server serves it. Where a fetch does pass through, its http event records no request target, so its JSON body cannot be told from any other.

AUTH-142

MUST · binds the server

The Protected Resource Metadata document returned by the MCP server MUST include the authorization_servers field containing at least one authorization server.

basic/authorization/authorization-server-discovery#authorization-server-location

Excluded. The Protected Resource Metadata document is not on the MCP endpoint, and a recording cannot show it. The resource_metadata URL names the server’s own address, which mcp-trace-capture does not rewrite, so a client fetches the document past the proxy; the well-known fallback is built from the proxy’s origin, and the proxy maps every path under the upstream’s (/.well-known/... reaches /mcp/.well-known/...), where no server serves it. Where a fetch does pass through, its http event records no request target, so its JSON body cannot be told from any other.

AUTH-143

MUST · binds the client

Clients MUST maintain separate registration state (client credentials, tokens) per authorization server and MUST NOT assume that credentials valid for one authorization server will be accepted by another.

basic/authorization/authorization-server-discovery#authorization-server-location

Excluded. Registration state is the client’s own storage, and the credentials it holds are presented to authorization servers off the MCP endpoint — or, as tokens, in the Authorization header a recording never keeps.

AUTH-144

MUST · binds the server

MCP servers MUST implement one of the following discovery mechanisms to provide authorization server location information to MCP clients:

basic/authorization/authorization-server-discovery#protected-resource-metadata-discovery-requirements

Excluded. A disjunction whose second branch a recording cannot witness. A 401 whose challenge carries no resource_metadata is conforming when the server serves the well-known document instead, and that document is not in the trace: The Protected Resource Metadata document is not on the MCP endpoint, and a recording cannot show it. The resource_metadata URL names the server’s own address, which mcp-trace-capture does not rewrite, so a client fetches the document past the proxy; the well-known fallback is built from the proxy’s origin, and the proxy maps every path under the upstream’s (/.well-known/... reaches /mcp/.well-known/...), where no server serves it. Where a fetch does pass through, its http event records no request target, so its JSON body cannot be told from any other.

AUTH-145

MUST · binds the client

MCP clients MUST support both discovery mechanisms and use the resource metadata URL from the parsed WWW-Authenticate headers when present; otherwise, they MUST fall back to constructing and requesting the well-known URIs in the order listed above.

basic/authorization/authorization-server-discovery#protected-resource-metadata-discovery-requirements

Excluded. Which URLs the client requested next, and in what order, are fetches off the MCP endpoint. The Protected Resource Metadata document is not on the MCP endpoint, and a recording cannot show it. The resource_metadata URL names the server’s own address, which mcp-trace-capture does not rewrite, so a client fetches the document past the proxy; the well-known fallback is built from the proxy’s origin, and the proxy maps every path under the upstream’s (/.well-known/... reaches /mcp/.well-known/...), where no server serves it. Where a fetch does pass through, its http event records no request target, so its JSON body cannot be told from any other.

AUTH-146

MUST · binds the client

MCP clients MUST be able to parse WWW-Authenticate headers and respond appropriately to HTTP 401 Unauthorized responses from the MCP server.

basic/authorization/authorization-server-discovery#protected-resource-metadata-discovery-requirements

Excluded. Conduct inside the client’s OAuth flow (parsing the challenge, then the discovery, authorization and token requests that are the appropriate response to a 401), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records.

AUTH-147

MUST · binds the client

To handle different issuer URL formats and ensure interoperability with both OAuth 2.0 Authorization Server Metadata and OpenID Connect Discovery 1.0 specifications, MCP clients MUST attempt multiple well-known endpoints when discovering authorization server metadata.

basic/authorization/authorization-server-discovery#authorization-server-metadata-discovery

Excluded. Requests to the authorization server’s well-known endpoints, and what the client does with the documents they return. A client reaches it directly, never through the MCP endpoint, so a recording of the MCP exchanges holds none of its conduct.

AUTH-148

MUST · binds the client

For issuer URLs with path components (e.g., https://auth.example.com/tenant1), clients MUST try endpoints in the following priority order:

basic/authorization/authorization-server-discovery#authorization-server-metadata-discovery

Excluded. Requests to the authorization server’s well-known endpoints, and what the client does with the documents they return. A client reaches it directly, never through the MCP endpoint, so a recording of the MCP exchanges holds none of its conduct.

AUTH-149

MUST · binds the client

For issuer URLs without path components (e.g., https://auth.example.com), clients MUST try:

basic/authorization/authorization-server-discovery#authorization-server-metadata-discovery

Excluded. Requests to the authorization server’s well-known endpoints, and what the client does with the documents they return. A client reaches it directly, never through the MCP endpoint, so a recording of the MCP exchanges holds none of its conduct.

AUTH-150

MUST · binds the client

After retrieving a metadata document, MCP clients MUST validate it as required by RFC8414 Section 3.3 or OpenID Connect Discovery Section 4.3: the issuer value in the document MUST be identical to the issuer identifier used to construct the well-known URL. If they differ, the client MUST NOT use the metadata. For example, a document fetched from https://attacker.example/.well-known/oauth-authorization-server that contains "issuer": "https://honest.example" MUST be rejected.

basic/authorization/authorization-server-discovery#authorization-server-metadata-discovery

Excluded. Requests to the authorization server’s well-known endpoints, and what the client does with the documents they return. A client reaches it directly, never through the MCP endpoint, so a recording of the MCP exchanges holds none of its conduct.

AUTH-151

SHOULD · binds the client

Clients supporting all options SHOULD use the following priority order:

basic/authorization/client-registration

Excluded. Conduct inside the client’s OAuth flow (choosing a registration mechanism), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records.

AUTH-152

SHOULD · binds the client and server

MCP clients and authorization servers SHOULD support OAuth Client ID Metadata Documents as specified in OAuth Client ID Metadata Document for client registration.

basic/authorization/client-registration#client-id-metadata-documents

Excluded. Support for a client registration mechanism is exercised between the client and the authorization server, off the MCP endpoint. Binds the authorization server, the separate OAuth party the page’s Roles section places outside the MCP server. A client reaches it directly, never through the MCP endpoint, so a recording of the MCP exchanges holds none of its conduct.

AUTH-153

MUST · binds the client and server

MCP implementations supporting Client ID Metadata Documents MUST follow the requirements specified in OAuth Client ID Metadata Document.

basic/authorization/client-registration#implementation-requirements

Excluded. Points at requirements stated elsewhere (the Client ID Metadata Document draft, and the two lists that follow on this page), each entered under its own id there; the sentence adds no obligation a recording could show apart from them.

AUTH-154

MUST · binds the client

Clients MUST host their metadata document at an HTTPS URL following RFC requirements; The client_id URL MUST use the “https” scheme and contain a path component, e.g. https://example.com/client.json; The metadata document MUST include at least the following properties: client_id, client_name, redirect_uris; Clients MUST ensure the client_id value in the metadata matches the document URL exactly

basic/authorization/client-registration#implementation-requirements

Excluded. The metadata document is hosted by the client and fetched by the authorization server; neither request touches the MCP endpoint, and the client_id travels in the authorization request. A client reaches it directly, never through the MCP endpoint, so a recording of the MCP exchanges holds none of its conduct.

AUTH-155

MUST · binds the server

For Authorization Servers: SHOULD fetch metadata documents when encountering URL-formatted client_ids; MUST validate that the fetched document’s client_id matches the URL exactly; SHOULD cache metadata respecting HTTP cache headers; MUST validate redirect URIs presented in an authorization request against those in the metadata document; MUST validate the document structure is valid JSON and contains required fields; SHOULD follow the security considerations in Section 6 of Client ID Metadata Document and in Client ID Metadata Document Security

basic/authorization/client-registration#implementation-requirements

Excluded. Binds the authorization server, the separate OAuth party the page’s Roles section places outside the MCP server. A client reaches it directly, never through the MCP endpoint, so a recording of the MCP exchanges holds none of its conduct.

AUTH-156

SHOULD · binds the client

MCP clients SHOULD check for this capability and MAY fall back to Dynamic Client Registration or pre-registration if unavailable.

basic/authorization/client-registration#advertising-cimd-support

Excluded. Conduct inside the client’s OAuth flow (reading authorization server metadata and choosing a registration mechanism), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records.

AUTH-157

SHOULD · binds the client

MCP clients SHOULD support an option for static client credentials such as those supplied by a pre-registration flow.

basic/authorization/client-registration#pre-registration

Excluded. A configuration option of the client, exercised against the authorization server; no MCP message shows whether the option exists.

AUTH-158

MUST · binds the client

MCP clients MUST specify an appropriate application_type during Dynamic Client Registration.

basic/authorization/client-registration#application-type-and-redirect-uri-constraints

Excluded. Conduct inside the client’s OAuth flow (Dynamic Client Registration with the authorization server), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records.

AUTH-159

SHOULD · binds the client

Native applications (desktop applications, mobile apps, CLI tools, and locally-hosted web applications accessed via localhost) SHOULD use application_type: "native"; Web applications (remote browser-based applications served from a non-local host) SHOULD use application_type: "web"

basic/authorization/client-registration#application-type-and-redirect-uri-constraints

Excluded. Conduct inside the client’s OAuth flow (Dynamic Client Registration with the authorization server), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records. Which kind of application the client is, is not stated anywhere a recording reaches either.

AUTH-160

MUST · binds the client

MCP clients MUST be prepared to handle registration failures due to redirect URI constraints when authorization servers implement OIDC.

basic/authorization/client-registration#application-type-and-redirect-uri-constraints

Excluded. Conduct inside the client’s OAuth flow (Dynamic Client Registration with the authorization server), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records.

AUTH-161

SHOULD · binds the client

When a registration request is rejected, clients SHOULD surface a meaningful error to the user or developer.

basic/authorization/client-registration#application-type-and-redirect-uri-constraints

Excluded. Conduct inside the client’s OAuth flow (Dynamic Client Registration with the authorization server), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records. Surfacing an error is user interface besides.

AUTH-162

MUST · binds the client

Clients that use pre-registered credentials, or persist client credentials obtained via Dynamic Client Registration, MUST associate those credentials with the specific authorization server that issued them, keyed by the authorization server’s issuer identifier.

basic/authorization/client-registration#authorization-server-binding

Excluded. Client credentials are the client’s own stored state, presented to authorization servers off the MCP endpoint. A client reaches it directly, never through the MCP endpoint, so a recording of the MCP exchanges holds none of its conduct.

AUTH-163

MUST NOT · binds the client

When the authorization server changes (detected via updated protected resource metadata), clients MUST NOT reuse client credentials from a different authorization server and MUST re-register with the new authorization server.

basic/authorization/client-registration#authorization-server-binding

Excluded. Client credentials are the client’s own stored state, presented to authorization servers off the MCP endpoint. A client reaches it directly, never through the MCP endpoint, so a recording of the MCP exchanges holds none of its conduct. The change itself is detected in Protected Resource Metadata, which a recording does not carry.

AUTH-164

SHOULD · binds the client

If the authorization server indicated by protected resource metadata no longer matches the one the credentials were registered with, clients SHOULD surface an error rather than silently attempting to use mismatched credentials.

basic/authorization/client-registration#authorization-server-binding

Excluded. Client credentials are the client’s own stored state, presented to authorization servers off the MCP endpoint. A client reaches it directly, never through the MCP endpoint, so a recording of the MCP exchanges holds none of its conduct. Surfacing an error is user interface besides.

AUTH-165

MUST · binds the client and server

This document outlines security requirements that implementers MUST consider when building MCP clients and servers.

basic/authorization/security-considerations

Excluded. Points at requirements stated elsewhere (the sections of this page), each entered under its own id there; the sentence adds no obligation a recording could show apart from them.

AUTH-166

MUST · binds the client and server

Additionally, implementors MUST follow OAuth 2.1 security best practices as outlined in OAuth 2.1 Section 7. “Security Considerations”.

basic/authorization/security-considerations

Excluded. Imports OAuth 2.1 Section 7 wholesale. Its observable consequences for an MCP exchange are the challenge clauses this page states itself, judged under their own ids; the rest is implementation conduct (storage, transport configuration, the OAuth flow) with no footprint on the MCP endpoint.

AUTH-167

MUST · binds the client

MCP clients MUST include the resource parameter in authorization and token requests as specified in the Resource Parameter Implementation section

basic/authorization/security-considerations#token-audience-binding-and-validation

Excluded. Conduct inside the client’s OAuth flow (the resource parameter of its authorization and token requests), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records.

AUTH-168

MUST · binds the server

MCP servers MUST validate that tokens presented to them were specifically issued for their use

basic/authorization/security-considerations#token-audience-binding-and-validation

Excluded. Token validation is decided inside the server, against a token the recording never holds (Authorization is not recorded). What the server says about the outcome is its challenge, judged where the page states what it must carry: the error-handling table and the 401 for invalid tokens.

AUTH-169

MUST · binds the client and server

Clients and servers MUST implement secure token storage and follow OAuth best practices, as outlined in OAuth 2.1, Section 7.1.

basic/authorization/security-considerations#token-theft

Excluded. Token storage is local state of each party, and a token is never recorded: nothing on the wire shows how either party keeps one.

AUTH-170

SHOULD · binds the server

Authorization servers SHOULD issue short-lived access tokens to reduce the impact of leaked tokens.

basic/authorization/security-considerations#token-theft

Excluded. Binds the authorization server, the separate OAuth party the page’s Roles section places outside the MCP server. A client reaches it directly, never through the MCP endpoint, so a recording of the MCP exchanges holds none of its conduct.

AUTH-171

MUST · binds the server

For public clients, authorization servers MUST rotate refresh tokens as described in OAuth 2.1 Section 4.3.1 “Token Endpoint Extension”.

basic/authorization/security-considerations#token-theft

Excluded. Binds the authorization server, the separate OAuth party the page’s Roles section places outside the MCP server. A client reaches it directly, never through the MCP endpoint, so a recording of the MCP exchanges holds none of its conduct.

AUTH-172

MUST · binds the client and server

Implementations MUST follow OAuth 2.1 Section 1.5 “Communication Security”.

basic/authorization/security-considerations#communication-security

Excluded. Imports OAuth 2.1 Section 1.5 wholesale. Its observable consequences for an MCP exchange are the challenge clauses this page states itself, judged under their own ids; the rest is implementation conduct (storage, transport configuration, the OAuth flow) with no footprint on the MCP endpoint.

AUTH-173

MUST · binds the server

All authorization server endpoints MUST be served over HTTPS.

basic/authorization/security-considerations#communication-security

Excluded. Binds the authorization server, the separate OAuth party the page’s Roles section places outside the MCP server. A client reaches it directly, never through the MCP endpoint, so a recording of the MCP exchanges holds none of its conduct.

AUTH-174

MUST · binds the client

All redirect URIs MUST be either localhost or use HTTPS.

basic/authorization/security-considerations#communication-security

Excluded. Redirect URIs are registered with the authorization server and travel in authorization requests through the user’s browser. A client reaches it directly, never through the MCP endpoint, so a recording of the MCP exchanges holds none of its conduct.

AUTH-175

MUST · binds the client

To mitigate this, MCP clients MUST implement PKCE according to OAuth 2.1 Section 7.5.2 and MUST verify PKCE support before proceeding with authorization.

basic/authorization/security-considerations#authorization-code-protection

Excluded. Conduct inside the client’s OAuth flow (PKCE and the authorization server metadata it is verified against), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records.

AUTH-176

MUST · binds the client

MCP clients MUST use the S256 code challenge method when technically capable, as required by OAuth 2.1 Section 4.1.1.

basic/authorization/security-considerations#authorization-code-protection

Excluded. Conduct inside the client’s OAuth flow (PKCE and the authorization server metadata it is verified against), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records.

AUTH-177

MUST · binds the client

Since OAuth 2.1 and PKCE specifications do not define a mechanism for clients to discover PKCE support, MCP clients MUST rely on authorization server metadata to verify this capability:

basic/authorization/security-considerations#authorization-code-protection

Excluded. Conduct inside the client’s OAuth flow (PKCE and the authorization server metadata it is verified against), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records.

AUTH-178

MUST · binds the client

OAuth 2.0 Authorization Server Metadata: If code_challenge_methods_supported is absent, the authorization server does not support PKCE and MCP clients MUST refuse to proceed.

basic/authorization/security-considerations#authorization-code-protection

Excluded. Conduct inside the client’s OAuth flow (PKCE and the authorization server metadata it is verified against), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records.

AUTH-179

MUST · binds the client

MCP clients MUST verify the presence of code_challenge_methods_supported in the provider metadata response. If the field is absent, MCP clients MUST refuse to proceed.

basic/authorization/security-considerations#authorization-code-protection

Excluded. Conduct inside the client’s OAuth flow (PKCE and the authorization server metadata it is verified against), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records.

AUTH-180

MUST · binds the server

Authorization servers providing OpenID Connect Discovery 1.0 MUST include code_challenge_methods_supported in their metadata to ensure MCP compatibility.

basic/authorization/security-considerations#authorization-code-protection

Excluded. Binds the authorization server, the separate OAuth party the page’s Roles section places outside the MCP server. A client reaches it directly, never through the MCP endpoint, so a recording of the MCP exchanges holds none of its conduct.

AUTH-181

MUST · binds the client

MCP clients MUST have redirect URIs registered with the authorization server.

basic/authorization/security-considerations#open-redirection

Excluded. Conduct inside the client’s OAuth flow (client registration), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records.

AUTH-182

MUST · binds the server

Authorization servers MUST validate exact redirect URIs against pre-registered values to prevent redirection attacks.

basic/authorization/security-considerations#open-redirection

Excluded. Binds the authorization server, the separate OAuth party the page’s Roles section places outside the MCP server. A client reaches it directly, never through the MCP endpoint, so a recording of the MCP exchanges holds none of its conduct.

AUTH-183

SHOULD · binds the client

MCP clients SHOULD use and verify state parameters in the authorization code flow and discard any results that do not include or have a mismatch with the original state.

basic/authorization/security-considerations#open-redirection

Excluded. Conduct inside the client’s OAuth flow (the authorization code flow’s state), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records.

AUTH-184

MUST · binds the server

Authorization servers MUST take precautions to prevent redirecting user agents to untrusted URI’s, following suggestions laid out in OAuth 2.1 Section 7.12.2

basic/authorization/security-considerations#open-redirection

Excluded. Binds the authorization server, the separate OAuth party the page’s Roles section places outside the MCP server. A client reaches it directly, never through the MCP endpoint, so a recording of the MCP exchanges holds none of its conduct.

AUTH-185

SHOULD · binds the server

Authorization servers SHOULD only automatically redirect the user agent if it trusts the redirection URI.

basic/authorization/security-considerations#open-redirection

Excluded. Binds the authorization server, the separate OAuth party the page’s Roles section places outside the MCP server. A client reaches it directly, never through the MCP endpoint, so a recording of the MCP exchanges holds none of its conduct.

AUTH-186

MUST · binds the server

When implementing Client ID Metadata Documents, authorization servers MUST consider the security implications detailed in OAuth Client ID Metadata Document, Section 6.

basic/authorization/security-considerations#client-id-metadata-document-security

Excluded. Binds the authorization server, the separate OAuth party the page’s Roles section places outside the MCP server. A client reaches it directly, never through the MCP endpoint, so a recording of the MCP exchanges holds none of its conduct.

AUTH-187

SHOULD · binds the server

Authorization servers fetching metadata documents SHOULD consider Server-Side Request Forgery (SSRF) risks

basic/authorization/security-considerations#authorization-server-abuse-protection

Excluded. Binds the authorization server, the separate OAuth party the page’s Roles section places outside the MCP server. A client reaches it directly, never through the MCP endpoint, so a recording of the MCP exchanges holds none of its conduct.

AUTH-188

MUST · binds the server

Authorization servers: SHOULD display additional warnings for localhost-only redirect URIs; MUST clearly display the redirect URI hostname during authorization

basic/authorization/security-considerations#localhost-redirect-uri-risks

Excluded. What the authorization server shows the user during authorization is consent UI in the user’s browser. Binds the authorization server, the separate OAuth party the page’s Roles section places outside the MCP server. A client reaches it directly, never through the MCP endpoint, so a recording of the MCP exchanges holds none of its conduct.

AUTH-189

MUST · binds the server

MCP proxy servers using static client IDs MUST obtain user consent for each dynamically registered client before forwarding to third-party authorization servers (which may require additional consent).

basic/authorization/security-considerations#confused-deputy-problem

Excluded. Consent is obtained in the user’s browser, and the forwarding is the proxy server’s own OAuth flow with a third-party authorization server; neither is a message on the MCP endpoint the recording captures.

AUTH-190

MUST · binds the server

MCP servers MUST validate access tokens before processing the request, ensuring the access token is issued specifically for the MCP server, and take all necessary steps to ensure no data is returned to unauthorized parties.

basic/authorization/security-considerations#access-token-privilege-restriction

Excluded. Token validation is decided inside the server, against a token the recording never holds (Authorization is not recorded). What the server says about the outcome is its challenge, judged where the page states what it must carry: the error-handling table and the 401 for invalid tokens. A result returned to an unauthorized party would need the request’s credential to show, and that is the header a recording never keeps.

AUTH-191

MUST · binds the server

A MCP server MUST follow the guidelines in OAuth 2.1 - Section 5.2 to validate inbound tokens.

basic/authorization/security-considerations#access-token-privilege-restriction

Excluded. Token validation is decided inside the server, against a token the recording never holds (Authorization is not recorded). What the server says about the outcome is its challenge, judged where the page states what it must carry: the error-handling table and the 401 for invalid tokens.

AUTH-192

MUST · binds the server

MCP servers MUST only accept tokens specifically intended for themselves and MUST reject tokens that do not include them in the audience claim or otherwise verify that they are the intended recipient of the token.

basic/authorization/security-considerations#access-token-privilege-restriction

Excluded. Token validation is decided inside the server, against a token the recording never holds (Authorization is not recorded). What the server says about the outcome is its challenge, judged where the page states what it must carry: the error-handling table and the 401 for invalid tokens.

AUTH-193

MUST NOT · binds the server

The MCP server MUST NOT pass through the token it received from the MCP client.

basic/authorization/security-considerations#access-token-privilege-restriction

Excluded. Passthrough is a request from the MCP server to an upstream API, outside the MCP session; the recording holds the client–server exchange only, and not even the token the client sent (Authorization is never recorded).

AUTH-194

MUST · binds the client

MCP clients MUST implement and use the resource parameter as defined in RFC 8707 - Resource Indicators for OAuth 2.0 to explicitly specify the target resource for which the token is being requested.

basic/authorization/security-considerations#access-token-privilege-restriction

Excluded. Conduct inside the client’s OAuth flow (the resource parameter of its authorization and token requests), which runs between the client, the user’s browser and the authorization server, off the MCP endpoint. A recording of the MCP exchanges carries none of it; the only trace the flow leaves there is the token in Authorization, which capture never records.