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.
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.
Judged by base.jsonrpc-version.
BASE-043
MUST · binds the client and server
Requests MUST include a string or integer ID.
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.
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.
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.
Judged by base.result-id-matches.
BASE-047
MUST · binds the client and server
Result responses MUST include a
resultfield.
Judged by base.result-field.
BASE-048
MUST · binds the client and server
The
resultMUST include aresultTypefield to indicate the type of the result.
Judged by base.result-type-present.
BASE-049
MUST · binds the client
The set of supported
ResultTypevalues MUST be created from the set defined in the core protocol and include any additional values of supported extensions that are advertised via capabilities.
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
resultTypeof any value unrecognized by the client MUST be considered invalid.
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 absentresultTypeas"complete".
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).
Judged by base.error-id-matches.
BASE-053
MUST · binds the client and server
Error responses MUST include an
errorfield with acodeandmessage.
Judged by base.error-shape.
BASE-054
MUST · binds the client and server
Error codes MUST be integers.
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
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.
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.
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.
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:
Judged by base.error-code-withdrawn.
BASE-059
SHOULD · binds the client
Clients SHOULD still accept
-32002from servers implementing earlier versions.
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 (
-32768to-32000); the remainder of the integer space is available for application-defined errors.
Judged by base.error-code-application-range.
BASE-061
MUST NOT · binds the client and server
The receiver MUST NOT send a response.
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.
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).
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.
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.
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.
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.
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.
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:
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
$schemafield 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
Judged by base.schemas-valid-for-dialect.
BASE-074
MUST NOT · binds the client and server
Implementations MUST NOT automatically dereference
$refvalues that resolve to a network URI.
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.
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
$refSHOULD be rejected rather than silently treated as permissive.
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.
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.
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 (/).
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 (
-).
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 thanexample.com/).
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]).
Judged by base.meta-key-format.
BASE-030
MUST · binds the client
Client requests carry the following
io.modelcontextprotocol/*fields inmeta; fields marked as required MUST be included on every request.
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).
Judged by meta.missing-required-field-rejected.
BASE-032
MUST · binds the server
On HTTP, the response status MUST be
400 Bad Request.
Judged by meta.missing-required-field-http-status.
BASE-033
SHOULD · binds the client
Clients SHOULD include
io.modelcontextprotocol/clientInfoon every request unless specifically configured not to do so.
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.
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 aMissingRequiredClientCapabilityError(-32021) whosedata.requiredCapabilitieslists the missing capabilities.
Judged by meta.missing-capability-error.
BASE-036
MUST · binds the server
On HTTP, the response status MUST be
400 Bad Request.
Judged by meta.missing-capability-http-status.
BASE-037
SHOULD · binds the server
Servers SHOULD include the following
io.modelcontextprotocol/*field in every result’smeta, unless specifically configured not to do so, to identify themselves without relying on any prior connection state:
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.
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 includeio.modelcontextprotocol/subscriptionIdinmetaso the client can correlate the notification with the originating subscription request.
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.
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:
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(andimage/jpg) - JPEG images (safe, universal compatibility) Clients that support rendering icons SHOULD also support:
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:
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.
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.
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
Originheader 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
Originheader 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
Acceptheader listing bothapplication/jsonandtext/event-streamas 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 Acceptedwith 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) orContent-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: noheader 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-Versionheader.
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-28The header value MUST match theio.modelcontextprotocol/protocolVersionfield carried in the request body’smeta.
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 Requestand aHeaderMismatchJSON-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 Requestand 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 Foundand 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-Namesource 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-headeris 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-headerannotations, 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-headervalues: 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 allx-mcp-headervalues in theinputSchema; 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-headervalues: 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-headervalue 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-NameorMcp-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/callrequest 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
HeaderMismatcherror because requiredMcp-Param-*headers are missing or do not match the body, the client SHOULD calltools/listto check for changes to the tool’sinputSchema, 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-headervalues: MUST only be applied to properties that are statically reachable from the schema root: reachable via a chain consisting solely ofpropertieskeys.
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 RequestHTTP 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.0and42are 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 Requestand 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-NameandMcp-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-Versionheader 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 use400for [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/discoverlets a client query a server’s supported protocol versions, capabilities, and identity before sending any other requests. Servers MUST implement it.
Judged by discover.implemented.
DISC-002
SHOULD · binds the client
A client that supports both modern (per-request
meta) and legacy (initializehandshake) servers SHOULD sendserver/discoverfirst; see stdio: Backward Compatibility for the fallback rules.
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
serverInfois 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
UnsupportedProtocolVersionErrorlisting 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
supportedlist 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
metakey 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
initializerequest, 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/discoverfirst 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.
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
stderroutput and SHOULD NOT assumestderroutput indicates error conditions.
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
stdoutthat is not a valid MCP message.
Judged by transport.stdio-server-output-valid.
TRAN-118
MUST NOT · binds the client
The client MUST NOT write anything to the server’s
stdinthat is not a valid MCP message.
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.
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/subscriptionIdfield inmeta; 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/cancellednotification 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
initializehandshake SHOULD probe with [server/discover][server-discover] before sending any other request, setting its preferred modern version inmeta.
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-
initializerequests with implementation-defined errors (commonly-32601or-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
initializeand would process an era-ambiguous method (such astools/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, orelicitation/create) using the MRTR pattern.
Judged by transport.no-independent-server-requests.
MRTR-002
MUST · binds the client
Every request MUST include the required
metafields; seemeta.
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
InputRequiredResultresponses on any other client requests.
basic/patterns/mrtr#supported-requests
Judged by mrtr.input-required-supported-methods.
MRTR-005
MUST · binds the server
inputRequestskeys 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
inputRequestsvalues are request objects that MUST be one ofElicitRequest,CreateMessageRequest, orListRootsRequest
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
requestStatefield, servers MUST treatrequestStateas 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
requestStateinfluences 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
requestStatepayload 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
requestStatemust 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
inputRequestsorrequestStatein everyInputRequiredResultresponse.
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
inputRequeststhat 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 anyelicitation/createrequests in theinputRequestsfield.
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
inputRequestsor 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
InputRequiredResultthat contains theinputRequestsfield, 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
InputRequiredResultcontains therequestStatefield, 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
requestStatecontents.
basic/patterns/mrtr#client-requirements-basic-workflow
Judged by mrtr.request-state-echoed.
MRTR-018
MUST NOT · binds the client
If the
InputRequiredResultdoes not contain arequestStatefield, 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
idMUST 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
InputResponsesobject 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
InputResponsesobject, 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 newInputRequiredResultrequesting 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/acknowledgedas the first message carrying the subscription’s ID inmetaunderio.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/listenresponse 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/listenrequest 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/listento 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.
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/cancelledreferencing asubscriptions/listenrequest ID when it tears down that subscription stream
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/cancelledfor any other purpose.
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/cancellednotification 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/listenrequest, 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
progressvalue 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
messagefield 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
inputResponsesorrequestState—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
ttlMsis0, 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
ttlMsis 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
ttlMsis absent, clients SHOULD assume a default of0(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
ttlMsis negative, clients SHOULD ignore it and treat it as0.
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
ttlMsvalue 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
cacheScopeto 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/listresponse hascacheScope: "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"cacheScopemay 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
cacheScopealone 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
metafields; seemeta.
Judged by meta.required-request-fields.
COMP-007
MUST · binds the server
Servers that support completions MUST declare the
completionscapability:
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
metafields; seemeta.
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
nextCursoras 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
stderrfor stdio transports, or to OpenTelemetry for structured observability.
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
loggingcapability:
server/utilities/logging#capabilities
Judged by capabilities.logging-declared.
LOG-008
MUST NOT · binds the server
The server MUST NOT emit
notifications/messagefor 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/messageis request-scoped: the server MUST NOT deliver it on asubscriptions/listenstream 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/logLevelvalue carried in a request’smetais 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
metafields; seemeta.
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
toolscapability:
Judged by capabilities.tools-declared.
TOOL-020
MUST · binds the server
Servers that declare the
toolscapability MUST respond totools/listrequests with the set of tools currently available to the requesting client.
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.
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).
Judged by tools.deterministic-order.
TOOL-023
MUST · binds the client
Note that the JSON-RPC
idMUST 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
listChangedcapability SHOULD send a notification to clients that have opened asubscriptions/listenstream withtoolsListChanged: 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
$schemafield is present MUST be a valid JSON Schema object (notnull) For tools with no parameters, use one of these valid approaches:
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.
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).
Judged by tools.name-length.
TOOL-028
SHOULD · binds the client and server
Tool names SHOULD be considered case-sensitive.
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.
Judged by tools.name-charset.
TOOL-030
SHOULD · binds the server
Tool names SHOULD be unique within a server.
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
searchtool) and SHOULD implement a disambiguation strategy such as prefixing tool names with a server identifier.
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(fromserverInfo) is not guaranteed to be unique across servers and SHOULD NOT be relied upon for disambiguation.
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-headervalues: 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 allx-mcp-headervalues in theinputSchema; MUST only be applied to parameters with primitive types (integer, string, boolean).
Judged by transport.x-mcp-header-name-valid.
TOOL-034
MUST · binds the client
Constraints on
x-mcp-headervalues: Integer values MUST be within the safe range for integers represented using IEEE754 double-precision floating point numbers (−253+1 to 253−1)
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.
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.
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.
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
resourcescapability:
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.
Judged by tools.output-schema-structured-result.
TOOL-041
SHOULD · binds the client
Clients SHOULD validate structured results against this 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.
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
$refresolution requirements when validating tool inputs and outputs againstinputSchemaandoutputSchema; 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-headervalues: 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
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-headervalue violates these constraints.
Judged by transport.x-mcp-header-invalid-tool-not-called.
RES
RES-011
MUST · binds the client
Every request MUST include the required
metafields; seemeta.
Judged by meta.required-request-fields.
RES-012
MUST · binds the server
Servers that support resources MUST declare the
resourcescapability:
Judged by capabilities.resources-declared.
RES-013
MUST · binds the server
Servers that declare the
resourcescapability MUST respond toresources/listrequests with the set of resources currently available to the requesting client.
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.
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
listChangedcapability 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.
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.
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
-32603for 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
-32002as 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
contentsarray 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
metafields; seemeta.
Judged by meta.required-request-fields.
PROM-012
MUST · binds the server
Servers that support prompts MUST declare the
promptscapability in theirDiscoverResult:
Judged by capabilities.prompts-declared.
PROM-013
MUST · binds the server
Servers that declare the
promptscapability MUST respond toprompts/listrequests with the set of prompts currently available to the requesting client.
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.
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
listChangedcapability SHOULD send a notification to clients that have opened asubscriptions/listenstream withpromptsListChanged: 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.
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.
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:
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.
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
elicitationcapability in_meta.io.modelcontextprotocol/clientCapabilitieson each request:
client/elicitation#capabilities
Judged by elicitation.client-declares-capability.
ELIC-058
MUST · binds the client
Clients declaring the
elicitationcapability MUST support at least one mode (formorurl).
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
modefield 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 themodefield, 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", amessage, and include these additional parameters:
client/elicitation#url-mode-elicitation-requests
Judged by elicitation.url-parameters.
ELIC-065
MUST · binds the server
The
urlparameter 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.
subclaim)
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
urlfield 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.
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.
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.
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
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.
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.toolscapability 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.toolscapability.
client/sampling#tools-in-sampling
Judged by sampling.tools-declared.
SAMP-027
MUST · binds the client
Clients that support sampling MUST declare the
samplingcapability in_meta.io.modelcontextprotocol/clientCapabilitieson each request:
Judged by sampling.client-declares-capability.
SAMP-028
SHOULD · binds the server
Servers SHOULD avoid using these values (e.g. can just omit
includeContextsince it defaults to"none")
Judged by sampling.include-context-avoided.
SAMP-029
SHOULD NOT · binds the server
and SHOULD NOT use them unless the client declares
sampling.contextcapability.
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
ToolUseContentblocks MUST be followed by a user message that consists entirely ofToolResultContentblocks, with each tool use (e.g. withid: $id) matched by a corresponding tool result (withtoolUseId: $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
rolefield of"user"or"assistant"; and acontentfield representing the message data.
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.
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
maxTokensparameter.
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", eachToolUseContentitem is responded to with aToolResultContentitem with a matchingtoolUseId, 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
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.
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
rootscapability in_meta.io.modelcontextprotocol/clientCapabilitieson each request:
Judged by roots.client-declares-capability.
ROOT-014
MUST · binds the client
uri: Unique identifier for the root. This MUST be afile://URI in the current specification.
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
scopeparameter in theWWW-Authenticateheader 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
issuervalue 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 thestatevalue, 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
issparameter 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
issparameter MUST advertise this by settingauthorization_response_iss_parameter_supportedtotruein 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
issfrom 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
issvalue from theapplication/x-www-form-urlencodedresponse 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, orerror_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
resourceparameter: 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) andhttps://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_tokenin theirgrant_typesclient 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_accessinWWW-Authenticatescope or Protected Resource Metadatascopes_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 Forbiddenstatus code (per RFC 6750 Section 3.1);WWW-Authenticateheader with theBearerscheme 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
scopeparameter, 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_serversfield 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:
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-Authenticateheaders when present; otherwise, they MUST fall back to constructing and requesting the well-known URIs in the order listed above.
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-Authenticateheaders and respond appropriately toHTTP 401 Unauthorizedresponses from the MCP server.
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
issuervalue 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 fromhttps://attacker.example/.well-known/oauth-authorization-serverthat 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_idURL 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 theclient_idvalue 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_idmatches 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_typeduring 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 useapplication_type: "native"; Web applications (remote browser-based applications served from a non-local host) SHOULD useapplication_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
issueridentifier.
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
resourceparameter 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
localhostor 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
S256code 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_supportedis 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_supportedin 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_supportedin 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
resourceparameter 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.