MCP normative requirements, every revision, both sides
WP6 output 1. Merged from five area sweeps (wp6-raw/A..E.md, which keep the per-area source lists, conventions and implied-details notes). Sources: prose of every page under docs/specification/<rev>/, schema/<rev>/schema.ts doc comments, docs/extensions/tasks/overview.mdx.
Columns: id | revs (a range a..b when unchanged) | side | level | area | quote | URL | applies to mcpx as server | as client | changes (non-empty = the obligation differs in another revision or is contradicted elsewhere; the full list is revision-conflicts.md).
Conventions carried from the sweeps: level (schema) / (implied) / (lowercase) / (changelog) qualifiers mark where the keyword came from; side also uses auth-server and intermediary where the spec addresses them. The two mcpx columns are a reviewer’s notes, not a status: the status of each requirement is conformance-matrix.md, computed from the tests. A note containing the word gap (any case) claims mcpx does not meet the requirement; TestMatrix (internal/conformance) fails when a cell carrying that claim has a covering test, so a note cannot keep claiming a gap after the fix lands, nor a test pass while a note says it should not. Anchors are heading slugs derived by hand, not checked against the live site. 2024-11-05 and 2025-03-26 have no schema page; schema-only rows for them link GitHub schema.ts.
Counts
788 rows (815 before de-duplication; 27 cross-area duplicates folded, listed at the end). 418 rows carry a changes note.
A row counts in every revision its range covers.
| revision | total | auth-server | both | client | intermediary | server |
|---|---|---|---|---|---|---|
| 2024-11-05 | 183 | 0 | 63 | 59 | 0 | 61 |
| 2025-03-26 | 253 | 0 | 85 | 80 | 0 | 88 |
| 2025-06-18 | 292 | 2 | 93 | 95 | 0 | 102 |
| 2025-11-25 | 464 | 3 | 166 | 140 | 0 | 155 |
| 2026-07-28 | 556 | 3 | 123 | 183 | 3 | 244 |
Most 2025-11-25 growth is the tasks page (57 rows) and the elicitation rewrite; most 2026-07-28 growth is discover, versioning, MRTR, subscriptions, caching and the transport rewrite.
Lifecycle, versioning, messages, errors, _meta, JSON Schema, ping
| id | revs | side | level | area | quote | url | mcpx-as-server | mcpx-as-client | changes |
|---|---|---|---|---|---|---|---|---|---|
| messages-all-messages-follow-jsonrpc-2 | 2024-11-05..2026-07-28 | both | MUST | messages | “All messages between MCP clients and servers MUST follow the JSON-RPC 2.0 specification.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#messages | yes, except batches (see batch row) and parse-error id (see error-id row) | yes | 2024-11-05 also states it on basic/messages (“All messages in MCP MUST follow…”). “Follow JSON-RPC 2.0” imports batch support and id: null on parse errors, which MCP later narrows — see Conflicts C1, C4 |
| lifecycle-implementations-support-base-and-lifecycle | 2024-11-05..2025-11-25 | both | MUST | lifecycle | “All implementations MUST support the base protocol and lifecycle management components.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/index | yes | yes | Replaced in 2026-07-28 by next row |
| versioning-implementations-support-base-versioning-patterns | 2026-07-28 | both | MUST | versioning | “All implementations MUST support the base protocol, versioning, and the message patterns.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index | partial: request/response and MRTR yes; subscriptions/listen yes; versioning partial (discover shape wrong, see versioning rows) | partial: modern path exists; does not retry on -32022 | Lifecycle requirement dropped; “message patterns” includes MRTR and subscribe/notify |
| messages-other-components-may | 2024-11-05..2026-07-28 | both | MAY | messages | “Other components MAY be implemented based on the specific needs of the application.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index | yes | yes | |
| messages-request-id-string-or-integer | 2024-11-05..2026-07-28 | both | MUST | messages | “Requests MUST include a string or integer ID.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#requests | yes (server-initiated ids are negative integers) | yes (atomic int counter) | |
| messages-request-id-not-null | 2024-11-05..2026-07-28 | both | MUST NOT | messages | “Unlike base JSON-RPC, the ID MUST NOT be null.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#requests | yes | yes | |
| messages-request-id-unique-per-session | 2024-11-05..2025-11-25 | both | MUST NOT | messages | “The request ID MUST NOT have been previously used by the requestor within the same session.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/index#requests | yes (monotonic counter per Conn) | yes (monotonic counter per Client) | Relaxed in 2026-07-28 (next row). Conflict C2 |
| messages-request-id-unique-among-in-flight | 2026-07-28 | both | MUST NOT | messages | “The request ID MUST NOT match the ID of any other request the sender has issued and not yet received a response for.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#requests | n/a (modern server sends no requests) | yes | Reuse after response becomes legal; changelog item 9 still says re-issue “with a new request ID” — Conflict C2 |
| messages-requests-client-to-server-only | 2026-07-28 | both | (definitional) | messages | “Requests are sent from the client to the server, to initiate an operation.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#requests | n/a on modern path; on legacy path mcpx still sends elicitation/sampling requests (allowed there) | yes: answers ping/roots/elicitation/sampling requests from legacy servers | 2024-11-05..2025-11-25: “from the client to the server or vice versa”. Normative MUST NOT is in patterns row below |
| messages-servers-must-not-initiate-requests | 2026-07-28 | server | MUST NOT | messages | “Servers MUST NOT initiate JSON-RPC requests, and clients do not send JSON-RPC responses.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/index | yes on modern requests (input_required instead); legacy connections still get wire requests | n/a | New. Legal-then-forbidden: every legacy server-initiated request (ping, sampling, roots, elicitation). Conflict C3 |
| messages-response-same-id | 2024-11-05..2025-06-18 | both | MUST | messages | “Responses MUST include the same ID as the request they correspond to.” | https://modelcontextprotocol.io/specification/2025-06-18/basic/index#responses | yes for requests; no for parse errors (id omitted) | yes | Split in 2025-11-25 into result/error rows; error ID exception added. Conflict C4 |
| messages-response-result-xor-error | 2024-11-05..2025-06-18 | both | MUST / MUST NOT | messages | “Either a result or an error MUST be set. A response MUST NOT set both.” | https://modelcontextprotocol.io/specification/2025-06-18/basic/index#responses | yes (Result is omitempty: a nil result would violate; not observed on handled paths) | yes | Re-expressed as two shapes in 2025-11-25 |
| messages-result-response-same-id | 2025-11-25..2026-07-28 | both | MUST | messages | “Result responses MUST include the same ID as the request they correspond to.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#result-responses | yes | yes | |
| messages-result-response-has-result | 2025-11-25..2026-07-28 | both | MUST | messages | “Result responses MUST include a result field.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#result-responses | yes | yes | |
| messages-result-any-object | 2025-03-26..2026-07-28 | both | MAY | messages | “The result MAY follow any JSON object structure.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#result-responses | yes | yes | 2024-11-05: lowercase “Results can follow any JSON object structure” (basic/index) |
| messages-error-response-same-id-unless-unreadable | 2025-11-25..2026-07-28 | both | MUST | errors | “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).” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#error-responses | yes (parse error omits id — permitted here by schema id?) | yes | Schema JSONRPCErrorResponse.id became optional in 2025-11-25; before, JSONRPCError.id: RequestId was required. Conflict C4 |
| errors-error-has-code-and-message | 2024-11-05..2026-07-28 | both | MUST | errors | “Error responses MUST include an error field with a code and message.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#error-responses | yes | yes | 2024-11-05 lowercase “errors must include an error code and message at minimum”; 2025-03-26..2025-06-18 “errors MUST include an error code and message at minimum” |
| errors-codes-integers | 2024-11-05..2026-07-28 | both | MUST | errors | “Error codes MUST be integers.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#error-responses | yes | yes | |
| errors-message-concise-single-sentence | 2024-11-05..2026-07-28 | both | SHOULD | errors | “The message SHOULD be limited to a concise single sentence.” (schema) | https://modelcontextprotocol.io/specification/2026-07-28/schema#error | partly: some messages embed Go error strings | n/a (sends no errors except to server requests) | |
| errors-data-may | 2026-07-28 | both | MAY | errors | “Error responses MAY include a data member with additional information of any type” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#error-responses | yes | n/a | Earlier revisions: schema data?: unknown, no prose |
| errors-standard-jsonrpc-codes | 2026-07-28 | both | (definitional) | errors | “MCP uses the standard JSON-RPC 2.0 error codes (-32700, -32600 to -32603) for general protocol failures.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#error-codes | yes | n/a | |
| errors-legacy-subrange-no-new-codes | 2026-07-28 | both | MUST NOT / SHOULD NOT | errors | “New codes MUST NOT be allocated in this sub-range, and new implementations SHOULD NOT use codes from this sub-range at all.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#error-codes | yes (uses none in -32000..-32019) | yes | Schema comment calls the sub-range “implementation-defined”, not “legacy” — Conflict C10 |
| errors-receivers-no-meaning-for-legacy-subrange | 2026-07-28 | both | MUST NOT | errors | “Apart from -32002 (see below), receivers MUST NOT assume any specific meaning for these codes.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#error-codes | yes | yes (treats as opaque upstream errors) | Legacy SDK codes (e.g. -32001 request timeout in TS SDK) lose any shared meaning |
| errors-reserved-subrange-only-spec-codes | 2026-07-28 | both | MUST NOT / MUST | errors | “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.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#error-codes | yes (-32022 only, and with its meaning; also emits -32022 to legacy initialize — see negotiation rows) | n/a | 2025-11-25 used -32042 (URL elicitation) in this sub-range; 2026 draft history renumbered -32001/-32003/-32004 → -32020/-32021/-32022 |
| errors-do-not-emit-32002-and-32042 | 2026-07-28 | both | MUST NOT | errors | “Implementations of this protocol version MUST NOT emit these codes:” (-32002, -32042) | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#error-codes | yes (mcpx emits neither) | n/a | Both were legal (and -32002 the specified code) in earlier revisions. Conflict C11 |
| errors-client-accept-32002-from-legacy | 2026-07-28 | client | SHOULD | errors | “Clients SHOULD still accept -32002 from servers implementing earlier versions.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#error-codes | n/a | yes (passes upstream errors through) | |
| errors-local-errors-not-mistaken-for-peer | 2026-07-28 | both | should (lowercase) | errors | “Implementations surfacing local errors in JSON-RPC-shaped structures should ensure they cannot be mistaken for errors received from the peer.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#error-codes | partly: proxy re-emits upstream failures as its own JSON-RPC errors / isError results; origin is text-only | n/a | Not RFC 2119 (lowercase) but matters for a proxy: mcpx is exactly the case of relaying local vs peer errors |
| errors-new-codes-outside-jsonrpc-range | 2026-07-28 | both | SHOULD | errors | “New error codes for purposes not defined by this specification SHOULD be allocated outside the JSON-RPC reserved range (-32768 to -32000)” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#error-codes | yes (defines none) | n/a | |
| errors-method-not-found-for-unadvertised-capability | 2026-07-28 | server | (schema guidance) | errors | “a server returns this error when a client invokes a method the server does not implement — either a genuinely unknown method, or one gated behind a server capability the server did not advertise” (schema) | https://modelcontextprotocol.io/specification/2026-07-28/schema#methodnotfounderror | no: mcpx answers methods it did not advertise for that revision (accept-liberally, e.g. resources/subscribe from modern) | n/a | Directly opposes mcpx’s “accept liberally” rule for gated methods; wording is descriptive, not RFC keyword |
| messages-notification-no-response | 2025-03-26..2026-07-28 | both | MUST NOT | messages | “The receiver MUST NOT send a response.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#notifications | yes (handle returns nil for notifications; HTTP 202) | yes | Implicit from JSON-RPC in 2024-11-05 |
| messages-notification-no-id | 2024-11-05..2026-07-28 | both | MUST NOT | messages | “Notifications MUST NOT include an ID.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#notifications | yes | yes | |
| messages-batch-may-send-must-receive | 2025-03-26 | both | MAY / MUST | messages | “MCP implementations MAY support sending JSON-RPC batches, but MUST support receiving JSON-RPC batches.” | https://modelcontextprotocol.io/specification/2025-03-26/basic/index#batching | no: stdio server unmarshals each line into one request object; an array gets -32700 | yes on HTTP responses (mcpclient/http.go accepts a batch array); stdio not checked | Removed in 2025-06-18 (changelog “Remove support for JSON-RPC batching”). Conflict C1 |
| lifecycle-initialize-not-in-batch | 2025-03-26 | client | MUST NOT | lifecycle | “The initialize request MUST NOT be part of a JSON-RPC batch” | https://modelcontextprotocol.io/specification/2025-03-26/basic/lifecycle#initialization | n/a | yes (never batches) | Only meaningful in 2025-03-26 |
| lifecycle-initialization-first-interaction | 2024-11-05..2025-11-25 | both | MUST | lifecycle | “The initialization phase MUST be the first interaction between client and server.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#initialization | not enforced: requests before/without initialize are served as 2025-03-26 (accept-liberally) | yes (legacy mode sends initialize first) | Removed in 2026-07-28 (no handshake); a dual-era server cannot enforce it because modern requests have no initialize |
| lifecycle-client-sends-initialize | 2024-11-05..2025-11-25 | client | MUST | lifecycle | “The client MUST initiate this phase by sending an initialize request containing:” version, capabilities, implementation info | https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#initialization | n/a | yes | Removed 2026-07-28 |
| lifecycle-server-responds-caps-and-info | 2024-11-05..2025-11-25 | server | MUST | lifecycle | “The server MUST respond with its own capabilities and information” | https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#initialization | yes (capabilities per negotiated revision, serverInfo, instructions) | n/a | Removed 2026-07-28 |
| lifecycle-client-sends-initialized-after-init | 2024-11-05..2025-11-25 | client | MUST | lifecycle | “After successful initialization, the client MUST send an initialized notification” | https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#initialization | n/a (accepts notifications/initialized and bare initialized, does not require it) | yes | Removed 2026-07-28 |
| lifecycle-client-no-requests-before-init-response | 2024-11-05..2025-11-25 | client | SHOULD NOT | lifecycle | “The client SHOULD NOT send requests other than pings before the server has responded to the initialize request.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#initialization | n/a | yes | 2026 dual-era clients send server/discover before initialize as a probe — legal only because that probe precedes the decision to be legacy |
| lifecycle-server-no-requests-before-initialized | 2024-11-05..2025-11-25 | server | SHOULD NOT | lifecycle | “The server SHOULD NOT send requests other than pings and logging before receiving the initialized notification.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#initialization | yes (asks only inside a client call, which follows initialize) | n/a | “logging” is a notification, not a request — Conflict C8 |
| lifecycle-client-sends-supported-version | 2024-11-05..2025-11-25 | client | MUST | versioning | “In the initialize request, the client MUST send a protocol version it supports.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#version-negotiation | n/a | yes (2025-11-25) | |
| lifecycle-client-sends-latest-version | 2024-11-05..2025-11-25 | client | SHOULD | versioning | “This SHOULD be the latest version supported by the client.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#version-negotiation | n/a | yes (latest legacy; 2026-07-28 cannot be sent over initialize) | |
| lifecycle-client-may-support-older | 2024-11-05..2025-11-25 | client | MAY | versioning | “The latest version of the Model Context Protocol that the client supports. The client MAY decide to support older versions as well.” (schema) | https://modelcontextprotocol.io/specification/2025-11-25/schema#initializerequestparams | n/a | yes (accepts any version back — see client-disconnect row) | |
| lifecycle-server-echoes-supported-version | 2024-11-05..2025-11-25 | server | MUST | versioning | “If the server supports the requested protocol version, it MUST respond with the same version.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#version-negotiation | yes (legacy versions echoed) | n/a | |
| lifecycle-server-counteroffers-version | 2024-11-05..2025-11-25 | server | MUST | versioning | “Otherwise, the server MUST respond with another protocol version it supports.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#version-negotiation | no: negotiate() returns “” and mcpx answers -32022 with the legacy list (e.g. a 2024-11-05 client, or 2026-07-28 over initialize) instead of a result carrying another version | n/a | The page’s own example answers with an error (-32602) instead — Conflict C5. mcpx’s -32022 is a 2026-only code sent on a legacy exchange |
| lifecycle-server-counteroffers-latest | 2024-11-05..2025-11-25 | server | SHOULD | versioning | “This SHOULD be the latest version supported by the server.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#version-negotiation | no (no counter-offer at all) | n/a | |
| lifecycle-client-disconnects-on-unsupported-version | 2024-11-05..2025-11-25 | client | SHOULD (prose) / MUST (schema) | versioning | prose: “If the client does not support the version in the server’s response, it SHOULD disconnect.” schema: “If the client cannot support this version, it MUST disconnect.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#version-negotiation | n/a | no: initializeLegacy records ir.ProtocolVersion as Negotiated without checking it (a 2024-11-05 or unknown answer is accepted) | Prose vs schema — Conflict C6 |
| lifecycle-http-protocol-version-header | 2025-06-18..2025-11-25 | client | MUST | versioning | “If using HTTP, the client MUST include the MCP-Protocol-Version: <protocol-version> HTTP header on all subsequent requests to the MCP server.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#version-negotiation | n/a | not verified here (transport owner) | 2026-07-28: header on every request, must match _meta (transport area) |
| lifecycle-capabilities-establish-session-features | 2024-11-05..2025-11-25 | both | (definitional) | lifecycle | “Client and server capabilities establish which optional protocol features will be available during the session.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#capability-negotiation | yes (per-Conn caps recorded at initialize) | yes | 2026: per-request clientCapabilities; server caps via server/discover |
| lifecycle-respect-negotiated-version-and-capabilities-should | 2024-11-05..2025-03-26 | both | SHOULD | lifecycle | “Both parties SHOULD: Respect the negotiated protocol version; Only use capabilities that were successfully negotiated” | https://modelcontextprotocol.io/specification/2025-03-26/basic/lifecycle#operation | yes (downgrade(), capability gates) | yes | Upgraded to MUST in 2025-06-18 (changelog item 9) |
| lifecycle-respect-negotiated-version-and-capabilities-must | 2025-06-18..2025-11-25 | both | MUST | lifecycle | “Both parties MUST: Respect the negotiated protocol version; Only use capabilities that were successfully negotiated” | https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#operation | partly: sends only negotiated shapes; accepts un-negotiated methods (tasks/*, subscriptions/listen) by design — receiving is not “using” | partly: only uses server caps it saw; Complete gated on completions | Conflict C7 (accept-liberally vs MUST). 2026: architecture “Both parties must respect declared capabilities throughout the interaction” (lowercase) |
| lifecycle-stdio-client-shutdown-sequence | 2024-11-05..2025-11-25 | client | SHOULD | lifecycle | “the client SHOULD initiate shutdown by: 1. First, closing the input stream to the child process … 2. … SIGTERM … 3. Sending SIGKILL” | https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#stdio | n/a | yes (mcpclient/stdio.go closes stdin, waits with timeout, then kills) — ordering beyond that not verified | Moved to transports/stdio in 2026-07-28 (transport area) |
| lifecycle-stdio-server-may-exit | 2024-11-05..2025-11-25 | server | MAY | lifecycle | “The server MAY initiate shutdown by closing its output stream to the client and exiting.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#stdio | yes (exits on stdin EOF) | yes (treats Recv error as connection failure) | |
| lifecycle-http-shutdown-closing-connection | 2024-11-05..2025-11-25 | both | (definitional) | lifecycle | “For HTTP transports, shutdown is indicated by closing the associated HTTP connection(s).” | https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#http | yes (+ DELETE drops session) | yes | |
| lifecycle-prepared-for-error-cases | 2024-11-05..2025-11-25 | both | SHOULD | lifecycle | “Implementations SHOULD be prepared to handle these error cases:” (version mismatch, capability failure, request timeouts) | https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#error-handling | partly | partly: version mismatch not handled (see disconnect row) | 2024-11-05 list: “Initialize request timeout”, “Shutdown timeout”; 2025-03-26+: “Request timeouts” |
| lifecycle-timeouts-all-requests-2024 | 2024-11-05 | both | SHOULD | lifecycle | “Implementations SHOULD implement appropriate timeouts for all requests, to prevent hung connections and resource exhaustion.” | https://modelcontextprotocol.io/specification/2024-11-05/basic/lifecycle#error-handling | n/a (2024-11-05 not served) | yes (pool call timeout, HTTP client timeout) | Replaced by the Timeouts section in 2025-03-26 |
| lifecycle-timeouts-establish | 2025-03-26..2025-11-25 | both | SHOULD | lifecycle | “Implementations SHOULD establish timeouts for all sent requests, to prevent hung connections and resource exhaustion.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#timeouts | yes (proto.askTimeout on server-initiated requests) | yes | 2026-07-28 moves the same text to basic/patterns/cancellation#timeouts (cancellation owner) |
| lifecycle-timeouts-cancel-on-expiry | 2025-03-26..2025-11-25 | both | SHOULD | lifecycle | “the sender SHOULD issue a cancellation notification for that request and stop waiting for a response.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#timeouts | not verified | no: mcpclient/http.go comment records cancellation was made best-effort then removed | 2026 wording: “the sender SHOULD cancel the request” (cancellation page) |
| lifecycle-timeouts-per-request-configurable | 2025-03-26..2025-11-25 | both | SHOULD | lifecycle | “SDKs and other middleware SHOULD allow these timeouts to be configured on a per-request basis.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#timeouts | partly (global settings) | yes (CallTimeout) | mcpx is “other middleware” |
| lifecycle-timeouts-may-reset-on-progress | 2025-03-26..2025-11-25 | both | MAY | lifecycle | “Implementations MAY choose to reset the timeout clock when receiving a progress notification” | https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#timeouts | n/a | not verified | |
| lifecycle-timeouts-max-regardless-of-progress | 2025-03-26..2025-11-25 | both | SHOULD | lifecycle | “implementations SHOULD always enforce a maximum timeout, regardless of progress notifications” | https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#timeouts | yes (askTimeout, askRounds) | yes | |
| lifecycle-cancel-not-initialize | 2024-11-05..2025-11-25 | client | MUST NOT | lifecycle | “A client MUST NOT attempt to cancel its initialize request.” (schema) | https://modelcontextprotocol.io/specification/2025-11-25/schema#cancellednotification | n/a | yes | Gone in 2026 (no initialize) |
| lifecycle-instructions-may-go-in-system-prompt | 2024-11-05..2025-11-25 | client | MAY | lifecycle | “For example, this information MAY be added to the system prompt.” (schema, InitializeResult.instructions) | https://modelcontextprotocol.io/specification/2025-11-25/schema#initializeresult | yes (sends instructions) | yes (stores Instructions) | 2026: DiscoverResult.instructions, no RFC keyword. Field appears in 2024-11-05 schema although the 2024-11-05 lifecycle example lacks it (example added 2025-03-26) |
| lifecycle-capability-sets-open | 2024-11-05..2026-07-28 | both | (definitional) | lifecycle | “Known capabilities are defined here, in this schema, but this is not a closed set: any client can define its own, additional capabilities.” (schema) | https://modelcontextprotocol.io/specification/2026-07-28/schema#clientcapabilities | yes (tolerates unknown keys) | yes | 2026 adds extensions map; tasks leaves core caps (2025-11-25 only) |
| lifecycle-implementation-name-version-required | 2024-11-05..2026-07-28 | both | REQUIRED (schema field) | lifecycle | name: string; version: string required on Implementation | https://modelcontextprotocol.io/specification/2026-07-28/schema#implementation | yes | yes | title added 2025-06-18; icons, description, websiteUrl added 2025-11-25. mcpx sends none of the optional fields |
| lifecycle-include-context-only-if-declared | 2025-11-25..2026-07-28 | server | SHOULD | lifecycle | “If not declared, servers SHOULD only use includeContext: \"none\" (or omit it).” (schema, ClientCapabilities.sampling.context) | https://modelcontextprotocol.io/specification/2026-07-28/schema#clientcapabilities | yes (passes upstream sampling through; does not add includeContext) | n/a | Sampling-area detail located in capability schema |
| ping-receiver-responds-promptly-empty | 2024-11-05..2025-11-25 | both | MUST | ping | “The receiver MUST respond promptly with an empty response” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/ping#behavior-requirements | yes ({}; plus resultType if request had modern _meta) | yes (answer() returns {}) | Removed in 2026-07-28 (changelog item 5; absent from schema). Conflict C3 |
| ping-either-party-may-initiate | 2024-11-05..2025-11-25 | both | (definitional) | ping | “Either the client or server can initiate a ping by sending a ping request.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/ping#overview | mcpx never pings its clients | Client.Ping exists but no periodic caller found | |
| ping-sender-may-consider-stale | 2024-11-05..2025-11-25 | both | MAY | ping | “If no response is received within a reasonable timeout period, the sender MAY: Consider the connection stale; Terminate the connection; Attempt reconnection procedures” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/ping#behavior-requirements | n/a | n/a (does not ping) | |
| ping-periodic-pings | 2024-11-05..2025-11-25 | both | SHOULD | ping | “Implementations SHOULD periodically issue pings to detect connection health” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/ping#implementation-considerations | no (not-implemented-by-choice: HTTP is per-request, stdio exits on EOF) | no (not-implemented-by-choice; pool detects dead processes on use) | Uncertain whether a pool health check uses ping — not found in grep |
| ping-frequency-configurable | 2024-11-05..2025-11-25 | both | SHOULD | ping | “The frequency of pings SHOULD be configurable” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/ping#implementation-considerations | n/a | n/a | |
| ping-timeouts-appropriate | 2024-11-05..2025-11-25 | both | SHOULD | ping | “Timeouts SHOULD be appropriate for the network environment” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/ping#implementation-considerations | n/a | n/a | |
| ping-avoid-excessive | 2024-11-05..2025-11-25 | both | SHOULD | ping | “Excessive pinging SHOULD be avoided to reduce network overhead” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/ping#implementation-considerations | yes | yes | |
| ping-timeout-is-connection-failure | 2024-11-05..2025-11-25 | both | SHOULD | ping | “Timeouts SHOULD be treated as connection failures” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/ping#error-handling | n/a | n/a | |
| ping-multiple-failures-may-reset | 2024-11-05..2025-11-25 | both | MAY | ping | “Multiple failed pings MAY trigger connection reset” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/ping#error-handling | n/a | n/a | |
| ping-log-failures | 2024-11-05..2025-11-25 | both | SHOULD | ping | “Implementations SHOULD log ping failures for diagnostics” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/ping#error-handling | n/a | n/a | |
| ping-schema-receiver-must-respond | 2024-11-05..2025-11-25 | both | must (lowercase) | ping | “The receiver must promptly respond, or else may be disconnected.” (schema) | https://modelcontextprotocol.io/specification/2025-11-25/schema#pingrequest | yes | yes | |
| meta-reserved-for-mcp | 2024-11-05..2025-03-26 | both | (definitional) | meta | “This result property is reserved by the protocol to allow clients and servers to attach additional metadata to their responses.” (schema) | GH(2025-03-26) Result._meta | yes | yes | No key-format rules before 2025-06-18; progressToken the only named key |
| meta-no-assumptions-on-reserved-keys | 2025-06-18..2026-07-28 | both | MUST NOT | meta | “implementations MUST NOT make assumptions about values at these keys.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#meta | yes | yes | 2025-06-18/2025-11-25: “MUST NOT” not bolded, same force |
| meta-prefix-label-format | 2025-06-18..2026-07-28 | both | MUST | meta | “If specified, MUST be a series of labels separated by dots (.), followed by a slash (/).” / “Labels MUST start with a letter and end with a letter or digit” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#meta | yes (only io.modelcontextprotocol/*) | yes | |
| meta-reserved-prefix-2025-06-18 | 2025-06-18 | both | (reservation) | meta | “Any prefix beginning with zero or more valid labels, followed by modelcontextprotocol or mcp, followed by any valid label, is reserved for MCP use.” | https://modelcontextprotocol.io/specification/2025-06-18/basic/index#meta | n/a | n/a | Replaced 2025-11-25 by reverse-DNS rule; the two rules reserve different sets — Conflict C9 |
| meta-reverse-dns-should | 2025-11-25..2026-07-28 | both | SHOULD | meta | “Implementations SHOULD use reverse DNS notation (e.g., com.example/ rather than example.com/).” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#meta | yes | yes | |
| meta-reserved-prefix-second-label | 2025-11-25..2026-07-28 | both | (reservation) | meta | “Any prefix where the second label is modelcontextprotocol or mcp is reserved for MCP use.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#meta | yes | yes | Conflict C9 |
| meta-name-format | 2025-06-18..2026-07-28 | both | MUST / MAY | meta | “Unless empty, MUST begin and end with an alphanumeric character ([a-z0-9A-Z]).” / “MAY contain hyphens (-), underscores (_), dots (.), and alphanumerics in between.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#meta | yes | yes | |
| meta-schema-may-reserve-names | 2025-06-18..2026-07-28 | both | (reservation) | meta | “definitions in the schema may reserve particular names for purpose-specific metadata” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#meta | yes | yes | 2026 page drops this sentence from prose; retained in schema MetaObject comment |
| meta-progress-token-receiver-not-obligated | 2024-11-05..2026-07-28 | both | (definitional) | meta | “The receiver is not obligated to provide these notifications.” (schema, _meta.progressToken) | https://modelcontextprotocol.io/specification/2026-07-28/schema#requestmetaobject | yes | yes | Unprefixed reserved key — exception to prefix rule, never stated as such (only traceparent etc. are called an “exception”) |
| meta-request-params-meta-required | 2026-07-28 | client | MUST / REQUIRED | meta | “fields marked as required MUST be included on every request.” (protocolVersion, clientCapabilities) | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#meta | n/a | yes (withMeta on every modern request) | Schema makes RequestParams._meta non-optional, hence every request needs params — Conflict C12 |
| meta-server-rejects-missing-required-field | 2026-07-28 | server | MUST | meta | “A request missing any required field is malformed; the server MUST reject it with JSON-RPC error code -32602 (Invalid params). On HTTP, the response status MUST be 400 Bad Request.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#meta | no (not-implemented-by-choice: a request with no _meta is treated as legacy / 2025-03-26, which a dual-era server has to do) | n/a | Conflicts with versioning matrix “exact code is implementation-defined” for initialize — Conflict C13 |
| meta-client-should-send-clientinfo | 2026-07-28 | client | SHOULD | meta | “Clients SHOULD include io.modelcontextprotocol/clientInfo on every request unless specifically configured not to do so.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#meta | n/a | yes | |
| meta-server-no-undeclared-client-capabilities | 2026-07-28 | server | MUST NOT | meta | “A server MUST NOT rely on capabilities the client has not declared.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#meta | yes (Peer.CanElicit/CanSample read per-request caps) | n/a | Legacy analogue is lifecycle “Only use capabilities that were successfully negotiated” |
| meta-server-no-infer-caps-from-prior | 2026-07-28 | server | MUST NOT | meta | “Servers MUST NOT infer capabilities from prior requests.” (schema) | https://modelcontextprotocol.io/specification/2026-07-28/schema#requestmetaobject | yes for modern requests; a request without _meta on a Conn that initialized falls back to Conn caps (legacy semantics) | n/a | |
| errors-missing-required-client-capability | 2026-07-28 | server | MUST | errors | “the server MUST return a MissingRequiredClientCapabilityError (-32021) whose data.requiredCapabilities lists the missing capabilities. On HTTP, the response status MUST be 400 Bad Request.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#meta | n/a in practice: mcpx never requires a client capability; questions a client cannot answer go to the broker | n/a | |
| meta-server-should-send-serverinfo | 2026-07-28 | server | SHOULD | meta | “Servers SHOULD include the following io.modelcontextprotocol/* field in every result’s _meta” (serverInfo) | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#meta | no: not stamped on results; server/discover puts serverInfo top-level instead of _meta | n/a | Replaces InitializeResult.serverInfo |
| meta-info-not-for-behavior-or-security | 2026-07-28 | both | SHOULD NOT | meta | “Implementations SHOULD NOT use them to change the behavior of the client or server, and SHOULD NOT rely on them for security decisions.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#meta | yes (clientInfo not used for decisions, as far as read) | yes | Earlier revisions silent; legacy SDKs commonly branch on clientInfo.name |
| meta-subscription-id-on-listen-notifications | 2026-07-28 | server | MUST | meta | “the server MUST include io.modelcontextprotocol/subscriptionId in _meta” (listen-stream notifications) | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#meta | no: id sent only in notifications/subscriptions/acknowledged params, not _meta of each pushed notification | n/a | Subscriptions owner should confirm |
| meta-otel-keys-w3c-format | 2026-07-28 | both | MUST | meta | “When present, their values MUST follow W3C Trace Context and W3C Baggage formats respectively.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#meta | n/a (does not emit); passes through? not verified | n/a | Unprefixed exception to the prefix rule |
| meta-extension-ids-follow-meta-rules | 2026-07-28 | both | MUST | versioning | “Extension identifiers MUST follow the _meta key naming rules, with a mandatory prefix.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/versioning#extension-negotiation | yes (io.modelcontextprotocol/tasks) | n/a (declares no extensions) | |
| meta-icons-client-mime-support | 2025-11-25..2026-07-28 | client | MUST / SHOULD | meta | “Clients that support rendering icons MUST support at least the following MIME types:” png, jpeg; “SHOULD also support” svg, webp | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#icons | n/a | n/a (renders no icons) | |
| meta-icons-consumer-security | 2025-11-25..2026-07-28 | client | MUST | meta | “Consumers of icon metadata MUST take appropriate security precautions when handling icons to prevent compromise” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#icons | n/a | n/a (never fetches icons; passes metadata through) | |
| meta-icons-reject-unsafe-schemes | 2025-11-25..2026-07-28 | client | MUST | meta | “Clients MUST reject icon URIs that use unsafe schemes and redirects, such as javascript:, file:, ftp:, ws:, or local app URI schemes.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#icons | n/a | n/a (does not dereference). Downstream host must do it | |
| meta-icons-may-limit-size | 2025-11-25..2026-07-28 | client | MAY | meta | “Consumers MAY set limits for image and content size.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#icons | n/a | n/a | |
| meta-icons-same-origin | 2025-11-25..2026-07-28 | client | SHOULD | meta | “Consumers SHOULD take steps to ensure URLs serving icons are from the same domain as the client/server or a trusted domain.” (schema) | https://modelcontextprotocol.io/specification/2026-07-28/schema#icon | n/a | n/a | A proxy re-serving upstream icons changes “the server” origin — see Implied I12 |
| json-schema-default-2020-12 | 2025-11-25..2026-07-28 | both | (definitional) | json-schema | “When a schema does not include a $schema field, it defaults to JSON Schema 2020-12” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#schema-dialect | yes (own schemas are dialect-neutral) | n/a | Earlier revisions: no dialect stated |
| json-schema-may-declare-dialect | 2025-11-25..2026-07-28 | both | MAY | json-schema | “Schemas MAY include a $schema field to specify a different dialect” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#schema-dialect | yes (passes upstream $schema through) | yes | |
| json-schema-support-2020-12 | 2025-11-25..2026-07-28 | both | MUST | json-schema | “Clients and servers MUST support JSON Schema 2020-12 for schemas without an explicit $schema field” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#implementation-requirements | not verified: mcpx does not appear to validate tool arguments against schemas (no validator in mcpserver) | n/a (passes through) | |
| json-schema-validate-per-dialect-and-error-on-unsupported | 2025-11-25..2026-07-28 | both | MUST | json-schema | “Clients and servers MUST validate schemas according to their declared or default dialect. They MUST handle unsupported dialects gracefully by returning an appropriate error” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#implementation-requirements | no (no validation; a proxy forwarding opaque schemas arguably does not “handle” them) | no | Uncertain what “validate schemas” binds a pass-through proxy to |
| json-schema-document-dialects | 2025-11-25..2026-07-28 | both | SHOULD | json-schema | “Clients and servers SHOULD document which schema dialects they support” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#implementation-requirements | yes: documented in docs/schema-validation.md (Dialect policy table) | yes: documented in docs/schema-validation.md (Dialect policy table) | |
| json-schema-recommend-2020-12 | 2025-11-25..2026-07-28 | both | RECOMMENDED | json-schema | “Implementors are RECOMMENDED to use JSON Schema 2020-12.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#schema-dialect | yes | n/a | |
| json-schema-schemas-valid | 2025-11-25..2026-07-28 | both | MUST | json-schema | “Schemas MUST be valid according to their declared or default dialect” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#schema-validation | yes for own tools (compacted literal schemas, test-checked); upstream schemas passed through unchecked | n/a | |
| json-schema-no-network-ref | 2026-07-28 | both | MUST NOT | json-schema | “Implementations MUST NOT automatically dereference $ref values that resolve to a network URI.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#ref-resolution | yes (never dereferences) | yes | New in 2026 (SEP-2106) |
| json-schema-remote-ref-opt-in-off-by-default | 2026-07-28 | both | MAY / MUST / SHOULD | json-schema | “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” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#ref-resolution | n/a | n/a | |
| json-schema-reject-unresolved-ref | 2026-07-28 | both | SHOULD | json-schema | “Schemas that fail to validate due to an unresolved external $ref SHOULD be rejected rather than silently treated as permissive.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#ref-resolution | no (no validation) | no | |
| json-schema-bound-composition-cost | 2026-07-28 | both | SHOULD | json-schema | “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” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#composition-keyword-resource-use | yes: schemaval bounds schema documents at 1 MiB (MaxSchemaBytes) | yes: schemaval bounds schema documents at 1 MiB (MaxSchemaBytes) | |
| versioning-server-unsupported-version-error | 2026-07-28 | server | MUST | versioning | “it MUST respond with an UnsupportedProtocolVersionError listing the versions it does support” | https://modelcontextprotocol.io/specification/2026-07-28/basic/versioning#protocol-version-negotiation | yes (-32022, data.supported, data.requested) | n/a | |
| versioning-unsupported-version-http-400 | 2026-07-28 | server | MUST | errors | “For HTTP, the response status code MUST be 400 Bad Request.” (schema, UnsupportedProtocolVersionError) | https://modelcontextprotocol.io/specification/2026-07-28/schema#unsupportedprotocolversionerror | no: ServeHTTP writes every JSON-RPC response with 200 | n/a | Same MUST on HeaderMismatchError and MissingRequiredClientCapabilityError |
| errors-header-mismatch-http-400 | 2026-07-28 | server | MUST | errors | “For HTTP, the response status code MUST be 400 Bad Request.” (schema, HeaderMismatchError) | https://modelcontextprotocol.io/specification/2026-07-28/schema#headermismatcherror | partly: 400, but body is {"error": "..."} not a JSON-RPC error with -32020 | n/a | A dual-era client then cannot recognise it as a modern error and falls back to legacy — see I7 |
| versioning-client-retry-with-supported | 2026-07-28 | client | SHOULD | versioning | “The client SHOULD select a mutually supported version from the supported list and retry the request, or surface an error to the user if no compatible version exists.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/versioning#protocol-version-negotiation | n/a | no: isVersionError stops and returns the error; no retry from data.supported | |
| versioning-server-must-implement-discover | 2026-07-28 | server | MUST | versioning | “Servers MUST implement server/discover.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/versioning#protocol-version-negotiation | partial: answers, but with protocolVersions (spec: supportedVersions), serverInfo top-level (spec: _meta), no ttlMs/cacheScope | partial: parses protocolVersions, so a spec-conformant server’s supportedVersions is missed → “no shared protocol version” | Discover owner should re-check; mcpx client and server share the same wrong field name, so they interoperate with each other only |
| versioning-client-may-discover-first | 2026-07-28 | client | MAY | versioning | “Clients MAY call it before sending any other requests to learn the server’s supported versions up front, but are not required to” | https://modelcontextprotocol.io/specification/2026-07-28/basic/versioning#protocol-version-negotiation | n/a | yes (always does, in modern mode) | |
| versioning-extension-fallback-or-reject | 2026-07-28 | both | MUST | versioning | “the supporting party MUST either revert to core protocol behavior or reject the request with an appropriate error.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/versioning#extension-negotiation | yes for tasks: a task handle only when the client asked with task; otherwise core result | n/a | Tasks extension says servers may return handles unsolicited (changelog item 6) — tasks owner to reconcile |
| versioning-extensions-document-fallback | 2026-07-28 | both | SHOULD | versioning | “Extensions SHOULD document their expected fallback behavior.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/versioning#extension-negotiation | n/a | n/a | Binds extension authors |
| versioning-dual-era-server-may | 2026-07-28 | server | MAY | versioning | “A server that wishes to support both legacy clients … and modern clients … MAY implement both behaviors.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/versioning#backward-compatibility-with-initialization-based-versions | yes (dual-era) | n/a | |
| versioning-era-cache | 2026-07-28 | client | SHOULD / MAY | versioning | “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.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/versioning#backward-compatibility-with-initialization-based-versions | n/a | partly: Client.Era per connection (= per process on stdio); not cached per HTTP origin or across restarts (each pooled instance probes) | See I1 |
| versioning-modern-only-server-names-versions-to-initialize | 2026-07-28 | server | SHOULD | versioning | “A server that supports only modern versions SHOULD name the protocol versions it supports in any error it returns to an initialize request, on any transport” | https://modelcontextprotocol.io/specification/2026-07-28/basic/versioning#backward-compatibility-with-initialization-based-versions | n/a (dual-era); for an initialize naming an unsupported version it does name the legacy list | n/a | |
| versioning-modern-client-probe-legacy-stdio | 2026-07-28 | client | SHOULD | versioning | “On stdio, clients SHOULD send server/discover first to fail deterministically” (Modern client, Legacy server) | https://modelcontextprotocol.io/specification/2026-07-28/basic/versioning#compatibility-matrix | n/a | n/a unless protocol: force-discover; then discover is first (yes) | Also stdio page: “probing is still RECOMMENDED” |
| versioning-dual-era-client-probe-discover-first-stdio | 2026-07-28 | client | SHOULD | versioning | “A client that supports both modern … and a legacy version … SHOULD probe with server/discover before sending any other request” (stdio page) | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio#backward-compatibility | n/a | no, by choice: probes legacy initialize first (“nearly every server in existence is legacy”) | Versioning page defers to binding pages; the SHOULD lives in the transport page |
| versioning-fallback-not-keyed-to-one-code | 2026-07-28 | client | MUST NOT | versioning | “The fallback MUST NOT be keyed to one specific error code” (stdio page) | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio#backward-compatibility | n/a | yes (falls back on any error except -32022) | mcpx inverts the probe order, so the rule applies to its legacy→modern fallback by analogy only |
| versioning-dual-era-http-detect | 2026-07-28 | client | MAY / SHOULD | versioning | “MAY detect which era the server implements by attempting a modern request first. On 400 Bad Request, the client SHOULD inspect the response body before falling back” (streamable-http page) | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#backward-compatibility | n/a | n/a (legacy first) | Versioning matrix says “4xx”, binding page says “400” — Conflict C14 |
| versioning-dual-era-server-selects-by-opening | 2026-07-28 | server | (normative description) | versioning | “A request carrying modern per-request _meta is served statelessly according to this revision. An initialize request selects legacy semantics, scoped to the stdio process (stdio) or the session (HTTP)” | https://modelcontextprotocol.io/specification/2026-07-28/basic/versioning#compatibility-matrix | yes, plus a third case the spec does not define: no _meta and no initialize → served as 2025-03-26 | n/a | See I4 |
| versioning-dual-era-both-concurrently | 2026-07-28 | server | MAY | versioning | “A dual-era server MAY serve both eras concurrently on the same endpoint or process.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/versioning#compatibility-matrix | yes | n/a | |
| lifecycle-stateless-no-reliance-on-prior-requests | 2026-07-28 | server | MUST NOT | lifecycle | “Servers MUST NOT rely on prior requests over the same connection to establish context (e.g., capabilities, protocol version, client identity).” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#statelessness | yes for version/caps of modern requests | n/a | Opposite of legacy lifecycle, where the initialize context governs the whole session |
| lifecycle-stateless-multiple-conversations | 2026-07-28 | server | SHOULD | lifecycle | “Servers SHOULD be prepared to handle requests associated with multiple tasks, threads, or conversations.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#statelessness | yes | n/a | |
| lifecycle-stateless-no-connection-reuse-required | 2026-07-28 | server | SHOULD NOT | lifecycle | “Servers SHOULD NOT require that a client reuse the same connection or process to perform related operations.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#statelessness | no: requestState is HMAC-bound to the connection it was issued on, and a request with no session gets no token (questions go to the broker) | n/a | Deliberate security trade-off in mcpx (docs/protocol.md §3.3) — see I3 |
| lifecycle-stateless-client-process-lifetime | 2026-07-28 | client | SHOULD NOT | lifecycle | “Clients SHOULD NOT use an individual task, thread, or conversation as the lifetime boundary for the stdio process.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#statelessness | n/a | yes (pooled by scope key, kept warm across calls) | |
| lifecycle-stateless-explicit-handles | 2026-07-28 | both | MUST | lifecycle | “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.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#statelessness | yes (task ids, requestState) — but HTTP also issues Mcp-Session-Id to modern clients on server/discover, which 2026 removed | n/a | Changelog item 1: servers “use explicit, server-minted handles passed as ordinary tool arguments” |
| messages-patterns-notifications-scoped-to-request | 2026-07-28 | server | MAY | messages | “While the request is in flight, the server MAY send notifications scoped to it, such as notifications/progress and notifications/message.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/index#request-and-response | yes | n/a | |
| messages-resulttype-required | 2026-07-28 | server | MUST | messages | “The result MUST include a resultType field to indicate the type of the result.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#result-responses | yes (stamped complete when request carried modern _meta) | n/a | Includes EmptyResult (schema EmptyResult = Result) |
| messages-resulttype-extension-values | 2026-07-28 | both | MAY / MUST | messages | “Extensions MAY add additional ResultType values. The set of supported ResultType values MUST be created from the set defined in the core protocol and include any additional values of supported extensions that are advertised via capabilities.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#resulttype | yes (only core values) | partly | |
| messages-resulttype-unknown-invalid | 2026-07-28 | client | MUST | messages | “A resultType of any value unrecognized by the client MUST be considered invalid.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#resulttype | n/a | no: anything other than input_required is treated as complete (client.go:665) | |
| messages-resulttype-absent-means-complete | 2026-07-28 | client | MUST | messages | “clients MUST treat an absent resultType as \"complete\".” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#resulttype | n/a | yes | Schema words it as “a server implementing an earlier protocol version” — a 2026 server omitting it is non-conformant but indistinguishable; see I9 |
| messages-resulttype-server-must-include | 2026-07-28 | server | MUST | messages | “Servers implementing this protocol version MUST include this field.” (schema, Result.resultType) | https://modelcontextprotocol.io/specification/2026-07-28/schema#result | yes on modern requests; stripped for legacy by downgrade() | n/a | |
| authorization-http-should-conform-stdio-should-not | 2025-03-26..2026-07-28 | both | SHOULD / SHOULD NOT | authorization | “Implementations using an HTTP-based transport SHOULD conform to this specification, whereas implementations using STDIO transport SHOULD NOT follow this specification” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#auth | not-implemented-by-choice (no OAuth; loopback / unix socket) | not-implemented-by-choice (no OAuth to upstreams) | Listed here because it is on basic/index; authorization owner covers detail |
| authorization-custom-auth-may | 2024-11-05..2026-07-28 | both | MAY | authorization | “clients and servers MAY negotiate their own custom authentication and authorization strategies.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#auth | n/a | n/a | 2024-11-05: auth “not currently part of the core MCP specification” |
| security-implementors-guidelines | 2024-11-05..2026-07-28 | both | SHOULD | (security; not in area list) | “implementors SHOULD: 1. Build robust consent and authorization flows into their applications …” | https://modelcontextprotocol.io/specification/2026-07-28/index#implementation-guidelines | partly (elicitation broker; no auth on /mcp beyond loopback) | n/a | The “Key Principles” list uses lowercase must — informative. 2026 drops “LLM Sampling Controls” principle |
| deprecated-should-not-adopt | 2026-07-28 | both | SHOULD NOT / SHOULD | versioning | “new implementations SHOULD NOT adopt it, and existing implementations SHOULD migrate before the feature’s earliest removal.” | https://modelcontextprotocol.io/specification/2026-07-28/deprecated#deprecated | Roots/Sampling/Logging/HTTP+SSE: mcpx relays sampling, accepts logging/setLevel, does not serve HTTP+SSE | declares roots and (conditionally) sampling to upstreams | Deprecated: Roots, Sampling, Logging, DCR (2026-07-28); includeContext thisServer/allServers (2025-11-25); HTTP+SSE (2025-03-26) |
Transports (stdio, HTTP+SSE, Streamable HTTP) and authorization
| id | revs | side | level | area | quote | url | mcpx-as-server | mcpx-as-client | changes |
|---|---|---|---|---|---|---|---|---|---|
| transport-jsonrpc-utf8 | 2025-03-26..2026-07-28 | both | MUST | messages | “JSON-RPC messages MUST be UTF-8 encoded.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports#messages | yes — Go encoding/json emits UTF-8 | yes — same | Absent from 2024-11-05 transports page (JSON-RPC implies it). Moved to transports/index in 2026. |
| transport-client-should-support-stdio | 2024-11-05..2025-11-25 | client | SHOULD | transport-stdio | “Clients SHOULD support stdio whenever possible.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports | n/a | yes — StdioTransport | Sentence dropped in 2026-07-28 (index lists stdio without the SHOULD). |
| transport-custom-preserve-jsonrpc-and-lifecycle | 2024-11-05..2025-11-25 | both | MUST | transport-stdio | “MUST ensure they preserve the JSON-RPC message format and lifecycle requirements defined by MCP” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#custom-transports | yes — mcpx’s only non-standard surface is /v1 REST, which is not an MCP transport | n/a | Replaced in 2026 by next row (“lifecycle” → “message patterns” + “per-request metadata model”). |
| transport-custom-preserve-patterns-and-metadata | 2026-07-28 | both | MUST | transport-stdio | “MUST preserve the JSON-RPC message format, the message patterns, and the per-request metadata model” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports#custom-transports | n/a (no custom MCP transport) | n/a | |
| transport-custom-document-patterns | 2024-11-05..2026-07-28 | both | SHOULD | transport-stdio | “Custom transports SHOULD document their specific connection establishment and message exchange patterns” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports#custom-transports | n/a | n/a | 2026 wording: “connection establishment, message framing, and cancellation patterns”. |
| transport-custom-byte-stream-reuses-stdio-framing | 2026-07-28 | both | SHOULD | transport-stdio | “Custom transports that run over a reliable bidirectional byte stream … SHOULD reuse the stdio framing” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports#custom-transports | n/a | n/a | Also stated on the stdio page. |
| transport-binding-message-directions | 2026-07-28 | both | MUST | messages | “A binding MUST deliver client-sent requests and notifications to the server, and server-sent responses and notifications to the client.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports#messages | yes for modern clients; for legacy sessions mcpx also sends requests (allowed by the legacy revision) | yes | New: no server→client requests, no client→server responses. Contradicts 2025-* (see Conflicts C1). |
| transport-binding-may-mirror-metadata | 2026-07-28 | both | MAY | messages | “A binding MAY additionally mirror selected body fields into envelope metadata.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports#request-metadata | — | — | “The body remains the source of truth”. |
| stdio-no-embedded-newlines | 2024-11-05..2026-07-28 | both | MUST NOT | transport-stdio | “Messages are delimited by newlines, and MUST NOT contain embedded newlines.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio | yes — json.Encoder escapes newlines | yes | |
| stdio-message-may-be-batch | 2025-03-26 | both | MAY (implied) | transport-stdio | “Messages may be JSON-RPC requests, notifications, responses—or a JSON-RPC batch containing one or more requests and/or notifications.” | https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#stdio | yes — ServeStdio answers a 2025-03-26 batch with an array (isBatch, internal/mcpserver/server.go); tested, see conformance-matrix.md | partial — never sends batches; does not parse batch replies on stdio | Removed 2025-06-18 (Conflicts C2). |
| stdio-message-is-single | 2025-06-18..2026-07-28 | both | MUST (implied) | transport-stdio | “Messages are individual JSON-RPC requests, notifications, or responses.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio | yes | yes | 2026: “Each message is a single JSON-RPC request, notification, or response.” |
| stdio-server-may-log-to-stderr | 2024-11-05..2026-07-28 | server | MAY | transport-stdio | “The server MAY write UTF-8 strings to its standard error (stderr) for logging purposes.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio | yes | n/a | 2025-11-25+ broadened: “for any logging purposes including informational, debug, and error messages”. |
| stdio-client-may-capture-stderr | 2024-11-05..2026-07-28 | client | MAY | transport-stdio | “Clients MAY capture, forward, or ignore this logging.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio | n/a | yes — ring buffer + optional StderrTo | |
| stdio-client-stderr-not-error | 2025-11-25..2026-07-28 | client | SHOULD NOT | transport-stdio | “SHOULD NOT assume stderr output indicates error conditions.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio | n/a | yes — stderr only attached to error messages when the process already failed | New in 2025-11-25. |
| stdio-server-stdout-only-mcp | 2024-11-05..2026-07-28 | server | MUST NOT | transport-stdio | “The server MUST NOT write anything to its stdout that is not a valid MCP message.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio | yes (logs go to stderr; not exhaustively verified) | n/a | |
| stdio-client-stdin-only-mcp | 2024-11-05..2026-07-28 | client | MUST NOT | transport-stdio | “The client MUST NOT write anything to the server’s stdin that is not a valid MCP message.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio | n/a | yes | |
| stdio-client-no-responses | 2026-07-28 | client | MUST NOT | transport-stdio | “The client MUST NOT write JSON-RPC responses.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio#sending-messages | n/a | yes to a modern server (mcpx answers only legacy servers’ requests) | Legal and required in 2024-11-05..2025-11-25 (C1). |
| stdio-server-no-requests | 2026-07-28 | server | MUST NOT | transport-stdio | “The server MUST NOT write JSON-RPC requests to stdout.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio#receiving-messages | yes — modern clients get input_required; wire requests only to legacy clients | n/a | C1. |
| stdio-client-correlates-subscription-id | 2026-07-28 | client | MUST | transport-stdio | “Clients MUST correlate these using the io.modelcontextprotocol/subscriptionId field in _meta” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio#receiving-messages | n/a | uncertain — not checked whether mcpx opens subscriptions/listen upstream | |
| stdio-client-cancel-by-notification | 2026-07-28 | client | MUST | transport-stdio | “To cancel an in-flight request, the client MUST send a notifications/cancelled notification referencing the request’s ID.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio#cancellation | n/a | yes — sent on its own background context | Also cancellation page. |
| stdio-server-stop-cancelled-work | 2026-07-28 | server | SHOULD | transport-stdio | “Servers SHOULD stop work on a cancelled request as soon as practical” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio#cancellation | yes — notifications/cancelled cancels the request context the backend runs under (Conn.track); tested, see conformance-matrix.md | n/a | |
| stdio-server-silent-after-cancel | 2026-07-28 | server | MUST NOT | transport-stdio | “MUST NOT send any further messages for it.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio#cancellation | uncertain — mcpx may still write the response when the upstream call returns | n/a | Earlier revs: cancellation page says receivers “SHOULD” not respond (not my area). |
| stdio-server-cancelled-only-for-listen | 2026-07-28 | server | MUST NOT | transport-stdio | “On stdio, the server also sends this notification, solely to terminate a subscriptions/listen stream … Servers MUST NOT use this notification to cancel any other request.” (schema.ts CancelledNotification) | https://modelcontextprotocol.io/specification/2026-07-28/schema#cancellednotification | uncertain — check stopListen on stdio | n/a | Conflicts with cancellation page scope (C12). |
| stdio-client-shutdown-sequence | 2026-07-28 | client | SHOULD | transport-stdio | “The client SHOULD initiate shutdown by: 1. Closing the input stream … 2. Waiting … 3. … forcibly terminating” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio#shutdown | n/a | yes — close stdin, SIGTERM pgid, then SIGKILL | Earlier revs put this on the lifecycle page (not my area). |
| stdio-server-exit-on-eof | 2026-07-28 | server | SHOULD | transport-stdio | “Servers SHOULD exit promptly when their standard input is closed or reads return end-of-file.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio#shutdown | yes — scan loop ends, waits for in-flight | n/a | |
| stdio-server-may-close-stdout | 2026-07-28 | server | MAY | transport-stdio | “The server MAY initiate shutdown by closing its output stream to the client and exiting.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio#shutdown | — | must tolerate — yes (Recv returns exit error) | |
| stdio-client-restart-crashed-server | 2026-07-28 | client | SHOULD | transport-stdio | “If the server process exits unexpectedly, the client SHOULD restart it.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio#unexpected-termination | n/a | uncertain — pool respawns on next use (not verified) | Relies on statelessness; for a legacy server the restart needs a new initialize (implied). |
| stdio-dual-era-client-probe-discover | 2026-07-28 | client | SHOULD | transport-stdio | “SHOULD probe with server/discover before sending any other request, setting its preferred modern version in _meta.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio#backward-compatibility | n/a | not-implemented-by-choice — default probes legacy initialize first (protocol: prefer-discover flips it) | Versioning page matrix repeats this. |
| stdio-no-fallback-on-modern-error | 2026-07-28 | client | MUST NOT (informal “Do not”) | transport-stdio | “Use one of the versions in its advertised supported list. Do not fall back to initialize.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio#backward-compatibility | n/a | yes — isVersionError stops the fallback (string match on -32022) | |
| stdio-modern-only-client-probe | 2026-07-28 | client | RECOMMENDED | transport-stdio | “A client that only supports modern versions does not need to probe, but probing is still RECOMMENDED” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio#backward-compatibility | n/a | force-discover probes discover — yes | |
| http-sse-server-validate-origin | 2024-11-05 | server | MUST | transport-http-sse | “Servers MUST validate the Origin header on all incoming connections to prevent DNS rebinding attacks” | https://modelcontextprotocol.io/specification/2024-11-05/basic/transports#security-warning | not-implemented-by-choice — mcpx does not serve HTTP+SSE | n/a | |
| http-sse-server-bind-localhost | 2024-11-05 | server | SHOULD | transport-http-sse | “When running locally, servers SHOULD bind only to localhost (127.0.0.1)” | https://modelcontextprotocol.io/specification/2024-11-05/basic/transports#security-warning | not-implemented-by-choice | n/a | |
| http-sse-server-authenticate | 2024-11-05 | server | SHOULD | transport-http-sse | “Servers SHOULD implement proper authentication for all connections” | https://modelcontextprotocol.io/specification/2024-11-05/basic/transports#security-warning | not-implemented-by-choice | n/a | |
| http-sse-server-two-endpoints | 2024-11-05 | server | MUST | transport-http-sse | “The server MUST provide two endpoints: 1. An SSE endpoint … 2. A regular HTTP POST endpoint” | https://modelcontextprotocol.io/specification/2024-11-05/basic/transports#http-with-sse | not-implemented-by-choice — floor is 2025-03-26 | n/a | |
| http-sse-server-endpoint-event | 2024-11-05 | server | MUST | transport-http-sse | “When a client connects, the server MUST send an endpoint event containing a URI for the client to use for sending messages.” | https://modelcontextprotocol.io/specification/2024-11-05/basic/transports#http-with-sse | not-implemented-by-choice | gap if a 2024-11-05 remote is configured — no SSE client | |
| http-sse-client-post-to-endpoint | 2024-11-05 | client | MUST | transport-http-sse | “All subsequent client messages MUST be sent as HTTP POST requests to this endpoint.” | https://modelcontextprotocol.io/specification/2024-11-05/basic/transports#http-with-sse | n/a | not-implemented (no HTTP+SSE client) | |
| http-sse-server-messages-as-sse-events | 2024-11-05 | server | MUST (implied) | transport-http-sse | “Server messages are sent as SSE message events, with the message content encoded as JSON in the event data.” | https://modelcontextprotocol.io/specification/2024-11-05/basic/transports#http-with-sse | not-implemented-by-choice | not-implemented | |
| http-sse-deprecated-no-new-adoption | 2026-07-28 | both | SHOULD NOT | transport-http-sse | “New implementations SHOULD NOT adopt it; existing implementations SHOULD migrate to Streamable HTTP.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#httpsse-transport-2024-11-05 | yes | yes | “Replaced” since 2025-03-26 without a keyword; formally Deprecated (SEP-2596) in 2026. |
| http-sse-server-backcompat-host-both | 2025-03-26..2026-07-28 | server | should (lowercase) | transport-http-sse | “Continue to host both the SSE and POST endpoints of the old transport, alongside the new "MCP endpoint"” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#httpsse-transport-2024-11-05 | not-implemented-by-choice | n/a | Optional; “possible to combine the old POST endpoint and the new MCP endpoint”. |
| http-sse-client-backcompat-probe-any-4xx | 2025-03-26..2025-06-18 | client | should (lowercase) | transport-http-sse | “If it fails with an HTTP 4xx status code (e.g., 405 Method Not Allowed or 404 Not Found): Issue a GET request … expecting … an endpoint event” | https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#backwards-compatibility | n/a | not-implemented — no GET fallback | Narrowed twice (C9). |
| http-sse-client-backcompat-probe-400-404-405 | 2025-11-25 | client | should (lowercase) | transport-http-sse | “If it fails with the following HTTP status codes "400 Bad Request", "404 Not Found" or "405 Method Not Allowed"” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#backwards-compatibility | n/a | not-implemented | C9. |
| http-sse-client-backcompat-probe-non-modern-body | 2026-07-28 | client | should (lowercase) | transport-http-sse | “fails with HTTP status code 400 Bad Request, 404 Not Found, or 405 Method Not Allowed and the response body is not a recognized modern JSON-RPC error” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#httpsse-transport-2024-11-05 | n/a | not-implemented | C9. Probe is now “POST a request” (not InitializeRequest). |
| streamable-http-server-single-endpoint-post-get | 2025-03-26..2025-11-25 | server | MUST | transport-streamable-http | “The server MUST provide a single HTTP endpoint path … that supports both POST and GET methods.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#streamable-http | yes — GET “supported” by answering 405, which the GET section permits | n/a | |
| streamable-http-server-single-endpoint-post | 2026-07-28 | server | MUST | transport-streamable-http | “The server MUST provide a single HTTP endpoint path … that supports POST.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http | yes | n/a | GET dropped. |
| streamable-http-server-validate-origin | 2025-03-26..2026-07-28 | server | MUST | transport-streamable-http | “Servers MUST validate the Origin header on all incoming connections to prevent DNS rebinding attacks” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#security–endpoint | yes — ServeHTTP refuses a foreign Origin (originAllowed, internal/mcpserver/server.go, #198); /v1 too (internal/daemon/origin.go, #267); tested, see conformance-matrix.md | n/a | |
| streamable-http-server-403-invalid-origin | 2025-11-25..2026-07-28 | server | MUST | transport-streamable-http | “If the Origin header is present and invalid, servers MUST respond with HTTP 403 Forbidden.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#security–endpoint | yes — 403 with an id-less JSON-RPC error (as above); tested, see conformance-matrix.md | n/a | Added 2025-11-25 (PR #1439). Body MAY be JSON-RPC error with no id. |
| streamable-http-server-bind-localhost | 2025-03-26..2026-07-28 | server | SHOULD | transport-streamable-http | “When running locally, servers SHOULD bind only to localhost (127.0.0.1)” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#security–endpoint | yes — daemon default loopback; --address 0.0.0.0 is opt-in with a warning | n/a | |
| streamable-http-server-authenticate | 2025-03-26..2026-07-28 | server | SHOULD | transport-streamable-http | “Servers SHOULD implement proper authentication for all connections.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#security–endpoint | not-implemented-by-choice — /mcp is unauthenticated, like /v1 | n/a | |
| streamable-http-client-post-every-message | 2025-03-26..2026-07-28 | client | MUST | transport-streamable-http | “Every JSON-RPC message sent from the client MUST be a new HTTP POST request to the MCP endpoint.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#sending-messages | n/a | yes | |
| streamable-http-client-accept-both | 2025-03-26..2026-07-28 | client | MUST | transport-streamable-http | “The client MUST include an Accept header, listing both application/json and text/event-stream” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#sending-messages | does not check (lenient) | yes | |
| streamable-http-post-body-may-batch | 2025-03-26 | client | MUST | transport-streamable-http | “The body of the POST request MUST be one of the following: A single JSON-RPC request, notification, or response; An array batching one or more requests and/or notifications; An array batching one or more responses” | https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#sending-messages-to-the-server | gap for 2025-03-26 — batch body → parse error 400 | yes (never batches); parses batch replies | Batching removed 2025-06-18 (C2). |
| streamable-http-post-body-single | 2025-06-18..2025-11-25 | client | MUST | transport-streamable-http | “The body of the POST request MUST be a single JSON-RPC request, notification, or response.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#sending-messages-to-the-server | yes | yes | |
| streamable-http-post-body-request-or-notification | 2026-07-28 | client | MUST / MUST NOT | transport-streamable-http | “The body of the HTTP POST MUST be a single JSON-RPC request or notification. The client MUST NOT send JSON-RPC responses.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#sending-messages | accepts responses anyway (for legacy sessions) — liberal accept | yes to modern servers | C1. |
| streamable-http-client-sends-metadata-headers | 2026-07-28 | client | MUST | transport-streamable-http | “The client MUST include the request metadata headers on each POST request.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#sending-messages | n/a | yes — Mcp-Method/Mcp-Name and Mcp-Param-* on every modern POST (internal/mcpclient/headers.go); tested, see conformance-matrix.md | Notification POST headers undefined (C11). |
| streamable-http-server-202-for-non-request | 2025-03-26..2026-07-28 | server | MUST | transport-streamable-http | “If the server accepts the input, the server MUST return HTTP status code 202 Accepted with no body.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#sending-messages | yes — notifications and client responses → 202 | tolerates 202 and 204 | Input set: responses/notifications (2025-03-26: “solely of (any number of)”), response/notification (2025-06-18..2025-11-25), notification only (2026). |
| streamable-http-server-error-status-if-rejected | 2025-03-26..2026-07-28 | server | MUST | transport-streamable-http | “If the server cannot accept the input, it MUST return an HTTP error status code (e.g., 400 Bad Request).” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#sending-messages | yes — unknown reply id → 400 (body is not JSON-RPC; MAY) | n/a | Body MAY be a JSON-RPC error with no id. |
| streamable-http-server-json-or-sse-for-request | 2025-03-26..2026-07-28 | server | MUST | transport-streamable-http | “the server MUST either return Content-Type: text/event-stream … or Content-Type: application/json” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#sending-messages | yes — JSON unless it must ask/stream, then SSE lazily | n/a | |
| streamable-http-client-supports-json-and-sse | 2025-03-26..2026-07-28 | client | MUST | transport-streamable-http | “The client MUST support both these cases.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#sending-messages | n/a | yes | |
| streamable-http-sse-includes-response | 2025-03-26..2025-11-25 | server | SHOULD | transport-streamable-http | “The SSE stream SHOULD eventually include a JSON-RPC response for the JSON-RPC request sent in the POST body.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#sending-messages-to-the-server | yes | n/a | 2025-03-26: one response per request, MAY be batched. |
| streamable-http-post-sse-may-carry-requests | 2025-03-26..2025-11-25 | server | MAY | transport-streamable-http | “The server MAY send JSON-RPC requests and notifications before sending the JSON-RPC response. These messages SHOULD relate to the originating client request.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#sending-messages-to-the-server | yes — elicitation/create/sampling on the POST’s stream (legacy sessions) | yes — handles requests found on the stream | Forbidden in 2026 (C1). |
| streamable-http-sse-notifications-must-relate | 2026-07-28 | server | MUST | transport-streamable-http | “These notifications MUST relate to the originating client request.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#receiving-messages | yes | n/a | Was SHOULD in 2025-* (C3). |
| streamable-http-sse-no-requests | 2026-07-28 | server | MUST NOT | transport-streamable-http | “The server MUST NOT send independent JSON-RPC requests on this stream.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#receiving-messages | yes for modern requests | n/a | C1. |
| streamable-http-sse-not-closed-before-response | 2025-03-26..2025-06-18 | server | SHOULD NOT | transport-streamable-http | “The server SHOULD NOT close the SSE stream before sending the JSON-RPC response for the received JSON-RPC request, unless the session expires.” | https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#sending-messages-to-the-server | yes | n/a | Replaced 2025-11-25 by polling rules (C4). |
| streamable-http-server-may-terminate-on-session-expiry | 2025-11-25 | server | MAY | transport-streamable-http | “The server MAY terminate the SSE stream if the session expires.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#sending-messages-to-the-server | — | — | |
| streamable-http-server-terminates-sse-after-response | 2025-03-26..2026-07-28 | server | SHOULD | transport-streamable-http | “After the JSON-RPC response has been sent, the server SHOULD terminate the SSE stream.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#receiving-messages | yes | n/a | 2025-03-26/06-18 “close”; 2025-11-25 “terminate” (stream vs connection distinction); 2026 “The final JSON-RPC response SHOULD terminate the stream.” Not for subscriptions/listen streams. |
| streamable-http-sse-priming-event | 2025-11-25 | server | SHOULD | transport-streamable-http | “The server SHOULD immediately send an SSE event consisting of an event ID and an empty data field in order to prime the client to reconnect” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#sending-messages-to-the-server | not-implemented-by-choice — no event ids, no resumability | must tolerate an empty data event — yes (skipped) | Removed 2026 (C5). |
| streamable-http-server-may-close-connection-keep-stream | 2025-11-25 | server | MAY | transport-streamable-http | “the server MAY close the connection (without terminating the SSE stream) at any time” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#sending-messages-to-the-server | not used | gap — a server that does this loses mcpx the response (no reconnect) | C4, C5. |
| streamable-http-client-polls-after-close | 2025-11-25 | client | SHOULD | transport-streamable-http | “The client SHOULD then "poll" the SSE stream by attempting to reconnect.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#sending-messages-to-the-server | n/a | yes — reconnects with GET and Last-Event-ID after retry (internal/mcpclient/http.go); tested, see conformance-matrix.md | |
| streamable-http-server-sends-retry-before-close | 2025-11-25 | server | SHOULD | transport-streamable-http | “it SHOULD send an SSE event with a standard retry field before closing the connection.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#sending-messages-to-the-server | n/a (never closes early) | n/a | |
| streamable-http-client-respects-retry | 2025-11-25 | client | MUST | transport-streamable-http | “The client MUST respect the retry field, waiting the given number of milliseconds before attempting to reconnect.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#sending-messages-to-the-server | n/a | vacuously yes (never reconnects); retry: lines ignored | |
| streamable-http-disconnect-not-cancel | 2025-03-26..2025-11-25 | both | SHOULD NOT | transport-streamable-http | “Disconnection SHOULD NOT be interpreted as the client cancelling its request.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#sending-messages-to-the-server | uncertain — handler runs on r.Context(), so a disconnect cancels mcpx-side waiting for a legacy client too | n/a | Inverted in 2026 (C6). |
| streamable-http-client-cancel-by-notification | 2025-03-26..2025-11-25 | client | SHOULD | transport-streamable-http | “To cancel, the client SHOULD explicitly send an MCP CancelledNotification.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#sending-messages-to-the-server | n/a | yes | 2026: “no notifications/cancelled message is expected” (C6). |
| streamable-http-server-may-resume | 2025-03-26..2025-11-25 | server | MAY | transport-streamable-http | “To avoid message loss due to disconnection, the server MAY make the stream resumable.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#sending-messages-to-the-server | not-implemented-by-choice | n/a | Removed 2026 (C5). |
| streamable-http-close-is-cancel | 2026-07-28 | server | MUST | transport-streamable-http | “Closing the SSE response stream MUST be treated by the server as cancellation of that request.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#cancellation | partial — request ctx cancels; upstream call not interrupted | n/a | Cancellation page: “The server MUST treat a client disconnect as cancellation” (covers JSON responses too). C6. |
| streamable-http-stop-cancelled-work | 2026-07-28 | server | SHOULD | transport-streamable-http | “The server SHOULD stop work on the cancelled request as soon as practical” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#cancellation | yes — a closed POST stream cancels the backend call; tested, see conformance-matrix.md | n/a | |
| streamable-http-silent-after-cancel | 2026-07-28 | server | MUST NOT | transport-streamable-http | “MUST NOT send any further messages for it.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#cancellation | yes (stream is gone) | n/a | |
| streamable-http-client-may-get | 2025-03-26..2025-11-25 | client | MAY | transport-streamable-http | “The client MAY issue an HTTP GET to the MCP endpoint.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#listening-for-messages-from-the-server | n/a | not-implemented-by-choice — never opens GET (so unsolicited list_changed from legacy HTTP upstreams is missed) | Removed 2026. |
| streamable-http-get-accept-sse | 2025-03-26..2025-11-25 | client | MUST | transport-streamable-http | “The client MUST include an Accept header, listing text/event-stream” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#listening-for-messages-from-the-server | n/a | n/a (no GET) | |
| streamable-http-get-sse-or-405 | 2025-03-26..2025-11-25 | server | MUST | transport-streamable-http | “The server MUST either return Content-Type: text/event-stream in response to this HTTP GET, or else return HTTP 405 Method Not Allowed” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#listening-for-messages-from-the-server | yes — 405 | n/a | |
| streamable-http-get-stream-unrelated | 2025-03-26..2025-11-25 | server | SHOULD | transport-streamable-http | “These messages SHOULD be unrelated to any concurrently-running JSON-RPC request from the client.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#listening-for-messages-from-the-server | n/a (405) | n/a | |
| streamable-http-get-no-responses | 2025-03-26..2025-11-25 | server | MUST NOT | transport-streamable-http | “The server MUST NOT send a JSON-RPC response on the stream unless resuming a stream associated with a previous client request.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#listening-for-messages-from-the-server | n/a | n/a | |
| streamable-http-get-close-any-time | 2025-03-26..2025-11-25 | both | MAY | transport-streamable-http | “The server MAY close the SSE stream at any time. The client MAY close the SSE stream at any time.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#listening-for-messages-from-the-server | — | — | 2025-11-25 adds: closing connection without terminating stream SHOULD follow polling (send retry). |
| streamable-http-multiple-streams | 2025-03-26..2025-11-25 | client | MAY | transport-streamable-http | “The client MAY remain connected to multiple SSE streams simultaneously.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#multiple-connections | must handle — yes (one goroutine per stream) | yes | |
| streamable-http-no-broadcast | 2025-03-26..2025-11-25 | server | MUST / MUST NOT | transport-streamable-http | “The server MUST send each of its JSON-RPC messages on only one of the connected streams; that is, it MUST NOT broadcast” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#multiple-connections | yes — each frame goes to its request’s stream | n/a | 2026: implied by request-scoped streams, but listen stream + request stream could both qualify (see Implied). |
| streamable-http-event-id-unique | 2025-03-26..2025-11-25 | server | MUST | transport-streamable-http | “If present, the ID MUST be globally unique across all streams within that session—or all streams with that specific client” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#resumability-and-redelivery | n/a (no ids) | n/a | |
| streamable-http-event-id-encodes-stream | 2025-11-25 | server | SHOULD | transport-streamable-http | “Event IDs SHOULD encode sufficient information to identify the originating stream” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#resumability-and-redelivery | n/a | n/a | |
| streamable-http-client-resume-with-last-event-id | 2025-03-26..2025-11-25 | client | SHOULD | transport-streamable-http | “it SHOULD issue an HTTP GET to the MCP endpoint, and include the Last-Event-ID header” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#resumability-and-redelivery | n/a | not-implemented | 2025-11-25: “Resumption is always via HTTP GET with Last-Event-ID” regardless of POST/GET origin. |
| streamable-http-server-no-cross-stream-replay | 2025-03-26..2025-11-25 | server | MUST NOT | transport-streamable-http | “The server MUST NOT replay messages that would have been delivered on a different stream.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#resumability-and-redelivery | n/a | n/a | |
| streamable-http-no-resumability | 2026-07-28 | both | — (statement) | transport-streamable-http | “Resumable SSE streams via Last-Event-ID are not supported.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#receiving-messages | yes | yes | C5. |
| streamable-http-client-reissue-broken-request | 2026-07-28 | client | MUST (changelog) | transport-streamable-http | “A broken response stream loses the in-flight request; clients MUST re-issue it as a new request with a new request ID” | https://modelcontextprotocol.io/specification/2026-07-28/changelog | n/a | not verified — pool retry behaviour unknown | MUST exists only in the changelog, not on the transport page (C10). |
| streamable-http-server-may-assign-session | 2025-03-26..2025-11-25 | server | MAY | transport-streamable-http | “A server using the Streamable HTTP transport MAY assign a session ID at initialization time, by including it in an Mcp-Session-Id header on the HTTP response containing the InitializeResult.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#session-management | yes — on initialize | n/a | 2025-11-25 spells it MCP-Session-Id (case-insensitive). mcpx also mints on server/discover (2026: SHOULD NOT). |
| streamable-http-session-id-secure | 2025-03-26..2025-11-25 | server | SHOULD | transport-streamable-http | “The session ID SHOULD be globally unique and cryptographically secure” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#session-management | yes — 16 random bytes (falls back to literal sess-0 if crypto/rand fails) | n/a | |
| streamable-http-session-id-visible-ascii | 2025-03-26..2025-11-25 | server | MUST | transport-streamable-http | “The session ID MUST only contain visible ASCII characters (ranging from 0x21 to 0x7E).” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#session-management | yes — sess-<hex> | n/a | |
| streamable-http-client-handles-session-securely | 2025-11-25 | client | MUST | transport-streamable-http | “The client MUST handle the session ID in a secure manner” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#session-management | n/a | yes (in memory only; trace redaction not checked) | New 2025-11-25. |
| streamable-http-client-echoes-session | 2025-03-26..2025-11-25 | client | MUST | transport-streamable-http | “clients using the Streamable HTTP transport MUST include it in the Mcp-Session-Id header on all of their subsequent HTTP requests.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#session-management | n/a | yes — also sends it to modern servers (2026 server SHOULD ignore) | |
| streamable-http-server-400-missing-session | 2025-03-26..2025-11-25 | server | SHOULD | transport-streamable-http | “Servers that require a session ID SHOULD respond to requests without an Mcp-Session-Id header (other than initialization) with HTTP 400 Bad Request.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#session-management | n/a — mcpx does not require one (stateless fallback) | n/a | |
| streamable-http-server-404-terminated-session | 2025-03-26..2025-11-25 | server | MUST | transport-streamable-http | “The server MAY terminate the session at any time, after which it MUST respond to requests containing that session ID with HTTP 404 Not Found.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#session-management | yes — an ended or unknown session id is 404; tested, see conformance-matrix.md | n/a | |
| streamable-http-client-reinit-on-404 | 2025-03-26..2025-11-25 | client | MUST | transport-streamable-http | “it MUST start a new session by sending a new InitializeRequest without a session ID attached.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#session-management | n/a | yes — a session 404 triggers one re-initialize (no session id on it) and one retry on the new session; tested, see conformance-matrix.md | Under 2026 a 404 means “method not found” (C7). |
| streamable-http-client-delete-session | 2025-03-26..2025-11-25 | client | SHOULD | transport-streamable-http | “Clients that no longer need a particular session … SHOULD send an HTTP DELETE to the MCP endpoint with the Mcp-Session-Id header” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#session-management | accepts — 204 | yes — on Close | |
| streamable-http-server-may-405-delete | 2025-03-26..2025-11-25 | server | MAY | transport-streamable-http | “The server MAY respond to this request with HTTP 405 Method Not Allowed” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#session-management | chooses 204 | tolerates any status | |
| streamable-http-protocol-version-header-is-negotiated | 2025-06-18..2025-11-25 | client | SHOULD | transport-streamable-http | “The protocol version sent by the client SHOULD be the one negotiated during initialization.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#protocol-version-header | n/a | yes — the header carries the negotiated revision; tested, see conformance-matrix.md | |
| streamable-http-server-assumes-2025-03-26 | 2025-06-18..2025-11-25 | server | SHOULD | transport-streamable-http | “if the server does not receive an MCP-Protocol-Version header, and has no other way to identify the version … the server SHOULD assume protocol version 2025-03-26.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#protocol-version-header | yes — 2025-03-26 is mcpx’s floor/default | n/a | 2026 makes it MAY and conditional (C8). |
| streamable-http-server-400-unsupported-version-header | 2025-06-18..2025-11-25 | server | MUST | transport-streamable-http | “If the server receives a request with an invalid or unsupported MCP-Protocol-Version, it MUST respond with 400 Bad Request.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#protocol-version-header | yes — an unsupported MCP-Protocol-Version is 400; tested, see conformance-matrix.md | n/a | |
| streamable-http-auth-discovery-version-header | 2025-03-26 | client | SHOULD | authorization | “MCP clients SHOULD include the header MCP-Protocol-Version: <protocol-version> during Server Metadata Discovery” | https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization#server-metadata-discovery-headers | n/a | n/a (no OAuth) | Header appears in auth before the transport defines it (2025-06-18); example value is 2024-11-05 (C13). |
| streamable-http-protocol-version-header-every-post | 2026-07-28 | client | MUST | transport-streamable-http | “Every POST request to the MCP endpoint MUST include an MCP-Protocol-Version header.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#protocol-version-header | n/a | yes | Now includes the first request (no handshake). |
| streamable-http-protocol-version-header-matches-meta | 2026-07-28 | both | MUST | transport-streamable-http | “The header value MUST match the io.modelcontextprotocol/protocolVersion field … the server MUST reject the request with 400 Bad Request and a HeaderMismatch JSON-RPC error” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#protocol-version-header | partial — 400, but body {"error": "..."}, not JSON-RPC -32020 | yes — header follows frame _meta | schema.ts RequestMetaObject repeats (without naming HeaderMismatch). |
| streamable-http-unsupported-version-400 | 2026-07-28 | server | MUST | transport-streamable-http | “it MUST respond with 400 Bad Request and an UnsupportedProtocolVersionError listing its supported versions.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#protocol-version-header | uncertain — -32022 exists; HTTP status for it not verified | n/a | schema.ts: “For HTTP, the response status code MUST be 400 Bad Request.” |
| streamable-http-missing-capability-400 | 2026-07-28 | server | MUST | transport-streamable-http | “For HTTP, the response status code MUST be 400 Bad Request.” (schema.ts MissingRequiredClientCapabilityError) | https://modelcontextprotocol.io/specification/2026-07-28/schema#missingrequiredclientcapabilityerror | uncertain — mcpx asks via broker rather than erroring | n/a | |
| streamable-http-unknown-method-404 | 2026-07-28 | server | MUST | transport-streamable-http | “If the server does not implement the requested RPC method, it MUST respond with 404 Not Found and a JSON-RPC error with code -32601” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#protocol-version-header | yes — -32601 is HTTP 404 on the modern path; tested, see conformance-matrix.md | must not mistake it for a dead session/legacy server — partial (any 404 → error) | C7. |
| streamable-http-missing-version-header-legacy | 2026-07-28 | server | MAY / MUST | transport-streamable-http | “MAY treat a request that omits the header as protocol version 2025-03-26. A server that does not support such clients MUST reject a request without the header” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#protocol-version-header | yes (MAY branch) | n/a | C8. |
| streamable-http-standard-headers-required | 2026-07-28 | client | REQUIRED | transport-streamable-http | “Mcp-Method … All requests; Mcp-Name … tools/call, resources/read, prompts/get requests. These headers are REQUIRED for compliance.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#standard-request-headers | n/a | yes (standardHeaders, internal/mcpclient/headers.go); tested, see conformance-matrix.md | SEP-2243. |
| streamable-http-mcp-name-base64 | 2026-07-28 | client | MUST | transport-streamable-http | “If the Mcp-Name source value cannot be safely represented as a plain ASCII header value, clients MUST encode it using the Base64 sentinel format” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#standard-request-headers | n/a | yes (mcpheaders.Encode, internal/mcpheaders); tested, see conformance-matrix.md | |
| streamable-http-x-mcp-header-server-may | 2026-07-28 | server | MAY | transport-streamable-http | “MCP servers MAY designate specific tool parameters to be mirrored into HTTP headers using an x-mcp-header extension property” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#custom-headers-from-tool-parameters | not used; but mcpx re-exports upstream tool schemas — an upstream x-mcp-header passes through, obliging mcpx’s HTTP clients and mcpx’s own validation (see Implied) | — | |
| streamable-http-x-mcp-header-client-must-mirror | 2026-07-28 | client | MUST | transport-streamable-http | “clients MUST support this feature. When a server’s tool definition includes x-mcp-header annotations, conforming clients MUST mirror the designated parameter values into HTTP headers.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#custom-headers-from-tool-parameters | n/a | yes (mcpheaders.Values, internal/mcpheaders); tested, see conformance-matrix.md | |
| streamable-http-x-mcp-header-constraints | 2026-07-28 | server | MUST / MUST NOT | transport-streamable-http | “MUST NOT be empty; MUST match HTTP field-name token syntax; … case-insensitively unique; … only … primitive types … Parameters with type number are not permitted; … statically reachable” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#schema-extension | n/a unless passing through upstream annotations | n/a | Integer values MUST be within ±(2^53−1). |
| streamable-http-client-rejects-invalid-x-mcp-header | 2026-07-28 | client | MUST | transport-streamable-http | “Clients using the Streamable HTTP transport MUST reject tool definitions where any x-mcp-header value violates these constraints. … MUST exclude the invalid tool from the result of tools/list.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#schema-extension | n/a | yes (checkToolHeaders, internal/mcpclient/modern.go); tested, see conformance-matrix.md | “SHOULD log a warning”; stdio clients MAY ignore annotations. |
| streamable-http-param-value-encoding | 2026-07-28 | client | MUST | transport-streamable-http | “Clients MUST encode parameter values before including them in HTTP headers … clients MUST use Base64 encoding of the UTF-8 representation” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#value-encoding | n/a | yes (mcpheaders.Encode); tested, see conformance-matrix.md | Markers =?base64?…?= “MUST appear exactly as shown (lowercase)”; sentinel-lookalike plain values MUST also be encoded. |
| streamable-http-server-decodes-before-compare | 2026-07-28 | server | MUST | transport-streamable-http | “servers MUST decode an encoded Mcp-Name or Mcp-Param-{Name} value before comparing it to the corresponding request body value” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#value-encoding | yes — encoded header values are decoded before comparison; tested, see conformance-matrix.md | n/a | Also intermediaries “that need to inspect”. |
| streamable-http-client-header-construction | 2026-07-28 | client | MUST | transport-streamable-http | “When constructing a tools/call request via HTTP transport, the client MUST: 1. Extract … 2. Append the Mcp-Method header … 5. Append a Mcp-Param-{Name}: {Value} header” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#client-behavior | n/a | yes (mcpheaders.Values); tested, see conformance-matrix.md | Omit header when value null/absent (table). |
| streamable-http-client-relist-on-header-mismatch | 2026-07-28 | client | SHOULD | transport-streamable-http | “the client SHOULD call tools/list to check for changes to the tool’s inputSchema, then retry” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#client-behavior | n/a | yes — re-lists tools and retries once on -32020 (toolCallHeaders, internal/mcpclient/modern.go); tested, see conformance-matrix.md | |
| streamable-http-intermediary-forwards-unknown-param | 2026-07-28 | intermediary | MUST | transport-streamable-http | “Intermediate servers that do not recognize an Mcp-Param-{Name} header MUST forward it and otherwise ignore it” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#server-behavior-for-custom-headers | n/a — mcpx is not an HTTP intermediary; it terminates MCP and re-originates | n/a | |
| streamable-http-server-validates-param-headers | 2026-07-28 | server | MUST | transport-streamable-http | “Any server that processes the message body MUST validate that encoded header values … match … Servers MUST reject requests with a 400 Bad Request HTTP status and JSON-RPC error code -32020” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#server-behavior-for-custom-headers | yes — Mcp-Param-* headers are checked against the x-mcp-header annotations of the tool named (checkParamHeaders, internal/mcpserver/transport.go, via mcpheaders.Check); tested, see conformance-matrix.md | n/a | Server MUST reject a recognized Mcp-Param with invalid chars; MUST reject when header omitted but body has value; MUST NOT expect header for null/absent. |
| streamable-http-header-names-case-insensitive | 2026-07-28 | both | MUST | transport-streamable-http | “Clients and servers MUST use case-insensitive comparisons for header names. Header values … are case-sensitive.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#case-sensitivity | yes (Go canonicalizes) | yes | Explains why Mcp-Session-Id→MCP-Session-Id rename (2025-11-25) is harmless. |
| streamable-http-server-rejects-header-body-mismatch | 2026-07-28 | server | MUST | transport-streamable-http | “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.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#server-validation | partial — only version | n/a | Includes “A required standard header … is missing”. |
| streamable-http-header-mismatch-400-jsonrpc | 2026-07-28 | server | MUST | transport-streamable-http | “servers MUST return HTTP status 400 Bad Request and MUST include a JSON-RPC error response using the following error code: -32020” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#server-validation | yes — 400 with a JSON-RPC -32020 body carrying the request id; tested, see conformance-matrix.md | n/a | Code was -32001 in drafts (changelog minor 12). |
| streamable-http-numeric-compare | 2026-07-28 | server | SHOULD | transport-streamable-http | “servers SHOULD compare the header value and the body value numerically rather than as strings” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#server-validation | n/a | n/a | |
| streamable-http-intermediary-http-error | 2026-07-28 | intermediary | MUST | transport-streamable-http | “Intermediaries MUST return an appropriate HTTP error status … but are not required to return a JSON-RPC error response.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#server-validation | n/a | client must tolerate non-JSON-RPC 400 — yes | |
| streamable-http-intermediary-reject-unvalidated-version | 2026-07-28 | intermediary | SHOULD | transport-streamable-http | “Intermediaries that enforce policy based on mirrored headers … SHOULD reject the request rather than trusting unvalidated header values.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#server-validation | n/a | n/a | |
| streamable-http-x-accel-buffering | 2026-07-28 | server | SHOULD | transport-streamable-http | “When initiating an SSE stream, servers SHOULD include the X-Accel-Buffering: no header” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#receiving-messages | yes | n/a | |
| streamable-http-sse-comment-keepalive | 2026-07-28 | both | should/must (lowercase) | transport-streamable-http | “servers are encouraged to periodically emit an SSE comment line … clients must ignore such lines and must not treat them as malformed input.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#receiving-messages | not verified for subscriptions/listen | yes — : lines skipped | Inside a <Note>; lowercase. |
| streamable-http-modern-only-server-legacy-traffic | 2026-07-28 | server | SHOULD | transport-streamable-http | “HTTP GET or DELETE to the MCP endpoint: respond with 405 Method Not Allowed. An Mcp-Session-Id header …: ignore it, and do not mint or echo session IDs. A Last-Event-ID header: ignore it” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#earlier-streamable-http-revisions | n/a as written (mcpx is dual-era, not modern-only) — but mcpx mints a session on server/discover for modern clients by choice (to bind requestState) | n/a | Scoped to “a server that supports only this revision”. |
| authz-optional | 2025-03-26..2026-07-28 | both | OPTIONAL | authorization | “Authorization is OPTIONAL for MCP implementations.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization#protocol-requirements | not-implemented-by-choice — mcpx does no OAuth | not-implemented-by-choice | Every other authz row applies only “When supported”. |
| authz-http-should-conform | 2025-03-26..2026-07-28 | both | SHOULD | authorization | “Implementations using an HTTP-based transport SHOULD conform to this specification.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization#protocol-requirements | not-implemented-by-choice | not-implemented-by-choice — static headers | |
| authz-stdio-use-environment | 2025-03-26..2026-07-28 | both | SHOULD NOT | authorization | “Implementations using an STDIO transport SHOULD NOT follow this specification, and instead retrieve credentials from the environment.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization#protocol-requirements | yes | yes — env auth type for stdio children | |
| authz-alt-transport-best-practice | 2025-03-26..2026-07-28 | both | MUST | authorization | “Implementations using alternative transports MUST follow established security best practices for their protocol.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization#protocol-requirements | n/a | n/a | |
| authz-implement-oauth21 | 2025-03-26 | both | MUST | authorization | “MCP auth implementations MUST implement OAuth 2.1 with appropriate security measures for both confidential and public clients.” | https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization#overview | not-implemented-by-choice | not-implemented-by-choice | 2025-06-18+: subject becomes “Authorization servers” (next row). |
| authz-as-implements-oauth21 | 2025-06-18..2026-07-28 | auth-server | MUST | authorization | “Authorization servers MUST implement OAuth 2.1 with appropriate security measures for both confidential and public clients.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization#overview | n/a | n/a | |
| authz-dcr-should | 2025-03-26..2025-06-18 | both | SHOULD | authorization | “MCP clients and servers SHOULD support the OAuth 2.0 Dynamic Client Registration Protocol” | https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization#dynamic-client-registration | not-implemented-by-choice | not-implemented-by-choice | 2025-06-18 subject “MCP clients and authorization servers”. Demoted to MAY 2025-11-25 (C14). |
| authz-dcr-may-deprecated | 2025-11-25..2026-07-28 | client, auth-server | MAY | authorization | “MCP clients and authorization servers MAY support the OAuth 2.0 Dynamic Client Registration Protocol” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization/client-registration#dynamic-client-registration | n/a | not-implemented-by-choice | Deprecated 2026 (PR #2858). |
| authz-rfc8414-server-should-client-must | 2025-03-26 | both | SHOULD / MUST | authorization | “MCP servers SHOULD and MCP clients MUST implement OAuth 2.0 Authorization Server Metadata (RFC8414). Servers that do not support Authorization Server Metadata MUST follow the default URI schema.” | https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization#overview | not-implemented-by-choice | not-implemented-by-choice | MCP server = AS in 2025-03-26; separated 2025-06-18 (C15). |
| authz-grant-types | 2025-03-26 | server | SHOULD | authorization | “MCP servers SHOULD support the OAuth grant types that best align with the intended audience.” | https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization#oauth-grant-types | not-implemented-by-choice | n/a | |
| authz-401-when-unauthorized | 2025-03-26 | server | MUST | authorization | “When authorization is required and not yet proven by the client, servers MUST respond with HTTP 401 Unauthorized.” | https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization#example-authorization-code-grant | not-implemented-by-choice | must react to 401 — reports error | Later revs keep 401 via error table + WWW-Authenticate. |
| authz-base-url-discards-path | 2025-03-26 | client | MUST | authorization | “The authorization base URL MUST be determined from the MCP server URL by discarding any existing path component.” | https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization#authorization-base-url | n/a | not-implemented-by-choice | Removed 2025-06-18; later revs use path-aware well-known URIs (C15). |
| authz-default-endpoints-fallback | 2025-03-26 | client | MUST | authorization | “clients MUST use the following default endpoint paths … Clients MUST first attempt to discover endpoints via the metadata document before falling back” | https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization#fallbacks-for-servers-without-metadata-discovery | not-implemented-by-choice | not-implemented-by-choice | /authorize, /token, /register; removed 2025-06-18. |
| authz-bearer-header | 2025-03-26..2026-07-28 | client | MUST | authorization | “MCP client MUST use the Authorization request header field … Authorization: Bearer <access-token>” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization#token-requirements | n/a | partial — static configured bearer is sent this way; not OAuth-obtained | |
| authz-token-every-request | 2025-03-26..2026-07-28 | client | MUST | authorization | “authorization MUST be included in every HTTP request from client to server” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization#token-requirements | n/a | yes for configured headers (POST and DELETE) | 2025-*: “even if they are part of the same logical session”; clause dropped 2026 (no sessions). |
| authz-no-token-in-query | 2025-03-26..2026-07-28 | client | MUST NOT | authorization | “Access tokens MUST NOT be included in the URI query string” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization#token-requirements | n/a | conflict — mcpauth offers a query auth type; using it with a token violates this | |
| authz-server-validates-token | 2025-03-26..2026-07-28 | server | MUST | authorization | “MCP servers, acting in their role as an OAuth 2.1 resource server, MUST validate access tokens … Invalid or expired tokens MUST receive a HTTP 401 response.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization#token-handling | not-implemented-by-choice | n/a | 2025-03-26: “Resource servers MUST validate”. |
| authz-server-validates-audience | 2025-06-18..2026-07-28 | server | MUST | authorization | “MCP servers MUST validate that access tokens were issued specifically for them as the intended audience” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization#token-handling | not-implemented-by-choice | n/a | Repeated in Security Considerations (Token Audience Binding; Access Token Privilege Restriction). |
| authz-client-sends-only-own-as-tokens | 2025-06-18..2026-07-28 | client | MUST NOT | authorization | “MCP clients MUST NOT send tokens to the MCP server other than ones issued by the MCP server’s authorization server.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization#token-handling | n/a | operator’s responsibility (static config per server) | |
| authz-accept-only-own-tokens | 2025-06-18..2026-07-28 | server | MUST | authorization | “MCP servers MUST only accept tokens that are valid for use with their own resources. MCP servers MUST NOT accept or transit any other tokens.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization#token-handling | not-implemented-by-choice (accepts no tokens) | n/a | 2025-06-18 said “Authorization servers MUST only accept tokens…” — subject corrected 2025-11-25 (C16). |
| authz-no-token-passthrough | 2025-06-18..2026-07-28 | server | MUST NOT | authorization | “The MCP server MUST NOT pass through the token it received from the MCP client.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization/security-considerations#access-token-privilege-restriction | yes — downstream request headers are not forwarded upstream; upstream credentials come from config (believed; not traced end to end) | n/a | Key rule for a proxy. |
| authz-error-status-codes | 2025-03-26..2026-07-28 | server | MUST | authorization | “Servers MUST return appropriate HTTP status codes for authorization errors: 401 … 403 … 400” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization#error-handling | not-implemented-by-choice | n/a | |
| authz-2025-03-26-security-list | 2025-03-26 | both | MUST / SHOULD | authorization | “1. Clients MUST securely store tokens … 2. Servers SHOULD enforce token expiration and rotation 3. All authorization endpoints MUST be served over HTTPS 4. Servers MUST validate redirect URIs … 5. Redirect URIs MUST be either localhost URLs or HTTPS URLs” | https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization#security-considerations | not-implemented-by-choice | not-implemented-by-choice | Later revs move 3–5 to auth-server/client rows below. |
| authz-2025-03-26-implementation-reqs | 2025-03-26 | both | MUST / REQUIRED / SHOULD | authorization | “1. Implementations MUST follow OAuth 2.1 security best practices 2. PKCE is REQUIRED for all clients 3. Token rotation SHOULD be implemented 4. Token lifetimes SHOULD be limited” | https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization#implementation-requirements | not-implemented-by-choice | not-implemented-by-choice | |
| authz-third-party-session-binding | 2025-03-26 | server | MAY / MUST | authorization | “MCP servers MAY support delegated authorization through third-party authorization servers … MCP servers implementing third-party authorization MUST: 1. Maintain secure mapping … 2. Validate third-party token status … 3. … lifecycle management 4. Handle third-party token expiration and renewal” | https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization#session-binding-requirements | not-implemented-by-choice | n/a | Also “servers MUST: 1. Validate all redirect URIs 2. Securely store third-party credentials 3. … session timeout handling 4. Consider … token chaining 5. … error handling” (#security-considerations-1). Section removed 2025-06-18; replaced by token-passthrough ban. |
| authz-server-prm-rfc9728 | 2025-06-18..2026-07-28 | both | MUST | authorization | “MCP servers MUST implement OAuth 2.0 Protected Resource Metadata (RFC9728). MCP clients MUST use OAuth 2.0 Protected Resource Metadata for authorization server discovery.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization#overview | not-implemented-by-choice | not-implemented-by-choice | |
| authz-prm-lists-authorization-servers | 2025-06-18..2026-07-28 | server | MUST | authorization | “The Protected Resource Metadata document returned by the MCP server MUST include the authorization_servers field containing at least one authorization server.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization/authorization-server-discovery#authorization-server-location | not-implemented-by-choice | n/a | |
| authz-as-metadata-rfc8414 | 2025-06-18 | both | MUST | authorization | “Authorization servers MUST provide OAuth 2.0 Authorization Server Metadata (RFC8414). MCP clients MUST use the OAuth 2.0 Authorization Server Metadata.” | https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization#overview | n/a | not-implemented-by-choice | Relaxed 2025-11-25 to RFC8414 or OIDC (next row). |
| authz-as-metadata-rfc8414-or-oidc | 2025-11-25..2026-07-28 | both | MUST | authorization | “MCP authorization servers MUST provide at least one of the following discovery mechanisms: RFC8414 … OpenID Connect Discovery 1.0. MCP clients MUST support both discovery mechanisms” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization#overview | n/a | not-implemented-by-choice | |
| authz-401-www-authenticate | 2025-06-18 | server | MUST | authorization | “MCP servers MUST use the HTTP header WWW-Authenticate when returning a 401 Unauthorized to indicate the location of the resource server metadata URL” | https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization#authorization-server-location | not-implemented-by-choice | n/a | Relaxed 2025-11-25 (SEP-985) to header or well-known (C17). |
| authz-prm-discovery-header-or-well-known | 2025-11-25..2026-07-28 | both | MUST | authorization | “MCP servers MUST implement one of the following discovery mechanisms … MCP clients MUST support both discovery mechanisms and use the resource metadata URL from the parsed WWW-Authenticate headers when present; otherwise, they MUST fall back to constructing and requesting the well-known URIs in the order listed above.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization/authorization-server-discovery#protected-resource-metadata-discovery-requirements | not-implemented-by-choice | not-implemented-by-choice | Order: path-inserted /.well-known/oauth-protected-resource/<path>, then root. |
| authz-client-parses-www-authenticate | 2025-06-18..2026-07-28 | client | MUST | authorization | “MCP clients MUST be able to parse WWW-Authenticate headers and respond appropriately to HTTP 401 Unauthorized responses” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization/authorization-server-discovery#protected-resource-metadata-discovery-requirements | n/a | not-implemented-by-choice (401 is surfaced as an error) | |
| authz-client-rfc8414-discovery | 2025-06-18 | client | MUST | authorization | “MCP clients MUST follow the OAuth 2.0 Authorization Server Metadata RFC8414 specification to obtain the information required to interact with the authorization server.” | https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization#server-metadata-discovery | n/a | not-implemented-by-choice | |
| authz-client-as-discovery-order | 2025-11-25..2026-07-28 | client | MUST | authorization | “MCP clients MUST attempt multiple well-known endpoints … For issuer URLs with path components … clients MUST try endpoints in the following priority order” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization/authorization-server-discovery#authorization-server-metadata-discovery | n/a | not-implemented-by-choice | |
| authz-client-validates-issuer-in-metadata | 2026-07-28 | client | MUST / MUST NOT | authorization | “the issuer value in the document MUST be identical to the issuer identifier used to construct the well-known URL. If they differ, the client MUST NOT use the metadata.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization/authorization-server-discovery#authorization-server-metadata-discovery | n/a | not-implemented-by-choice | New 2026. |
| authz-client-per-as-registration-state | 2026-07-28 | client | MUST / MUST NOT | authorization | “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.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization/authorization-server-discovery#authorization-server-location | n/a | not-implemented-by-choice | |
| authz-resource-indicator | 2025-06-18..2026-07-28 | client | MUST | authorization | “MCP clients MUST implement Resource Indicators for OAuth 2.0 as defined in RFC 8707 … The resource parameter: 1. MUST be included in both authorization requests and token requests. 2. MUST identify the MCP server … 3. MUST use the canonical URI” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization#resource-parameter-implementation | n/a | not-implemented-by-choice | Plus “MUST send this parameter regardless of whether authorization servers support it.” |
| authz-canonical-uri-guidance | 2025-06-18..2026-07-28 | both | SHOULD | authorization | “MCP clients SHOULD provide the most specific URI … implementations SHOULD accept uppercase scheme and host components … SHOULD consistently use the form without the trailing slash” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization#canonical-server-uri | n/a | n/a | |
| authz-secure-token-storage | 2025-06-18..2026-07-28 | both | MUST | authorization | “Clients and servers MUST implement secure token storage and follow OAuth best practices” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization/security-considerations#token-theft | n/a | applies to configured secrets — mcpauth redacts in traces; storage is the config file (operator’s) | |
| authz-as-short-lived-and-rotate | 2025-06-18..2026-07-28 | auth-server | SHOULD / MUST | authorization | “Authorization servers SHOULD issue short-lived access tokens … For public clients, authorization servers MUST rotate refresh tokens” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization/security-considerations#token-theft | n/a | n/a | |
| authz-https-and-redirect-uris | 2025-06-18..2026-07-28 | both | MUST | authorization | “1. All authorization server endpoints MUST be served over HTTPS. 1. All redirect URIs MUST be either localhost or use HTTPS.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization/security-considerations#communication-security | n/a | n/a | |
| authz-pkce | 2025-06-18 | client | MUST | authorization | “MCP clients MUST implement PKCE according to OAuth 2.1 Section 7.5.2.” | https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization#authorization-code-protection | n/a | not-implemented-by-choice | |
| authz-pkce-verify-s256 | 2025-11-25..2026-07-28 | client, auth-server | MUST | authorization | “MUST verify PKCE support before proceeding … MUST use the S256 code challenge method when technically capable … If code_challenge_methods_supported is absent … MCP clients MUST refuse to proceed.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization/security-considerations#authorization-code-protection | n/a | not-implemented-by-choice | AS offering OIDC Discovery “MUST include code_challenge_methods_supported”. |
| authz-open-redirection | 2025-06-18..2026-07-28 | client, auth-server | MUST / SHOULD | authorization | “MCP clients MUST have redirect URIs registered … Authorization servers MUST validate exact redirect URIs … MCP clients SHOULD use and verify state parameters … Authorization servers MUST take precautions” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization/security-considerations#open-redirection | n/a | not-implemented-by-choice | |
| authz-proxy-consent-per-client | 2025-06-18..2026-07-28 | server | MUST | authorization | “MCP proxy servers using static client IDs MUST obtain user consent for each dynamically registered client before forwarding to third-party authorization servers” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization/security-considerations#confused-deputy-problem | not-implemented-by-choice — mcpx is a proxy but runs no OAuth for either side | n/a | Directly addresses mcpx’s shape if it ever adds OAuth. |
| authz-client-registration-required | 2026-07-28 | client | MUST | authorization | “Before initiating the authorization flow, MCP clients MUST obtain a client ID through one of three registration mechanisms” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization#client-registration | n/a | not-implemented-by-choice | |
| authz-registration-priority | 2025-11-25..2026-07-28 | client | SHOULD | authorization | “Clients supporting all options SHOULD follow the following priority order: 1. … pre-registered … 2. … Client ID Metadata Documents … 3. … Dynamic Client Registration … 4. Prompt the user” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization/client-registration | n/a | not-implemented-by-choice | |
| authz-cimd | 2025-11-25..2026-07-28 | client, auth-server | SHOULD / MUST | authorization | “MCP clients and authorization servers SHOULD support OAuth Client ID Metadata Documents … Clients MUST host their metadata document at an HTTPS URL … The client_id URL MUST use the "https" scheme and contain a path component … MUST include at least … client_id, client_name, redirect_uris … MUST ensure the client_id value … matches” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization/client-registration#implementation-requirements | n/a | not-implemented-by-choice | AS: MUST validate client_id match, redirect URIs, JSON structure; SHOULD fetch, cache. Clients “SHOULD check for this capability and MAY fall back”. |
| authz-preregistration | 2025-11-25..2026-07-28 | client | SHOULD | authorization | “MCP clients SHOULD support an option for static client credentials such as those supplied by a pre-registration flow.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization/client-registration#pre-registration | n/a | n/a (no OAuth client) | |
| authz-dcr-application-type | 2026-07-28 | client | MUST / SHOULD | authorization | “MCP clients MUST specify an appropriate application_type during Dynamic Client Registration … Native applications … SHOULD use application_type: \"native\" … MCP clients MUST be prepared to handle registration failures” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization/client-registration#application-type-and-redirect-uri-constraints | n/a | not-implemented-by-choice | SEP-837. |
| authz-credentials-bound-to-issuer | 2026-07-28 | client | MUST / MUST NOT | authorization | “MUST associate those credentials with the specific authorization server that issued them, keyed by the authorization server’s issuer identifier … clients MUST NOT reuse client credentials from a different authorization server and MUST re-register” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization/client-registration#authorization-server-binding | n/a | not-implemented-by-choice | Pre-registered mismatch: “SHOULD surface an error”. |
| authz-scope-in-challenge | 2025-11-25..2026-07-28 | both | SHOULD / MUST / MUST NOT | authorization | “MCP servers SHOULD include a scope parameter in the WWW-Authenticate header … Clients MUST NOT assume any particular set relationship between the challenged scope set and scopes_supported. Clients MUST treat the scopes provided in the challenge as authoritative” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization#scope-selection-strategy | not-implemented-by-choice | not-implemented-by-choice | 2026 adds “When re-authorizing, clients SHOULD include these scopes alongside any previously granted scopes”. |
| authz-scope-selection-order | 2025-11-25..2026-07-28 | client | SHOULD | authorization | “MCP clients SHOULD follow this priority order for scope selection: 1. Use scope parameter … 2. … use all scopes defined in scopes_supported” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization#scope-selection-strategy | n/a | not-implemented-by-choice | |
| authz-insufficient-scope-403 | 2025-11-25..2026-07-28 | server | SHOULD | authorization | “the server SHOULD respond with: HTTP 403 Forbidden … WWW-Authenticate header with … error=\"insufficient_scope\" … scope= … resource_metadata” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization#runtime-insufficient-scope-errors | not-implemented-by-choice | n/a | What scope contains changed (C18). |
| authz-all-scopes-single-challenge | 2026-07-28 | server | SHOULD | authorization | “servers SHOULD include all scopes required for the current operation in a single challenge.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization#runtime-insufficient-scope-errors | not-implemented-by-choice | n/a | |
| authz-step-up | 2025-11-25..2026-07-28 | client | SHOULD / MAY | authorization | “Clients SHOULD respond to these errors by requesting a new access token with an increased set of scopes … Clients SHOULD implement retry limits” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization#step-up-authorization-flow | n/a | not-implemented-by-choice | 2026 step 2: union of previously requested and challenged scopes (C18). |
| authz-server-scope-hierarchy | 2026-07-28 | server | MUST | authorization | “Servers MUST account for scope hierarchies, where a broader scope implies narrower ones” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization#step-up-authorization-flow | not-implemented-by-choice | n/a | |
| authz-cimd-as-security | 2025-11-25..2026-07-28 | auth-server | MUST / SHOULD | authorization | “authorization servers MUST consider the security implications … SHOULD consider SSRF … SHOULD display additional warnings for localhost-only redirect URIs … MUST clearly display the redirect URI hostname” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization/security-considerations#client-id-metadata-document-security | n/a | n/a | |
| authz-iss-validation | 2026-07-28 | client, auth-server | MUST / SHOULD / MUST NOT | authorization | “the client MUST record the issuer value … authorization servers SHOULD include the iss parameter … MUST advertise … authorization_response_iss_parameter_supported … clients MUST apply the validation in RFC9207 Section 2.4 before transmitting the authorization code … MUST NOT apply scheme or host case folding … on mismatch the client MUST NOT act on or display error” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization#authorization-response-validation | n/a | not-implemented-by-choice | SEP-2468. Table: supported=true + iss absent → reject. |
| authz-refresh-tokens | 2026-07-28 | client, server | MUST / SHOULD / MAY / MUST NOT / SHOULD NOT | authorization | “MUST keep refresh tokens confidential … SHOULD include refresh_token in their grant_types … MAY add offline_access … MUST NOT assume refresh tokens will be issued … MCP Servers … SHOULD NOT include offline_access” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization#refresh-tokens | not-implemented-by-choice | not-implemented-by-choice | |
| authz-follow-security-considerations | 2025-06-18..2026-07-28 | both | MUST | authorization | “Implementations MUST follow OAuth 2.1 security best practices as laid out in OAuth 2.1 Section 7.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization/security-considerations | not-implemented-by-choice | not-implemented-by-choice | 2026 also: “Implementations of this specification MUST follow the normative security requirements in Security Considerations”. |
Cancellation, progress, pagination, logging, completion, tasks, caching, MRTR, subscriptions
| id | revs | side | level | area | quote | url | mcpx-as-server | mcpx-as-client | changes |
|---|---|---|---|---|---|---|---|---|---|
| cancellation-ref-same-direction-in-progress | 2024-11-05..2025-11-25 | both | MUST | cancellation | “Cancellation notifications MUST only reference requests that: Were previously issued in the same direction; Are believed to still be in-progress” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/cancellation#behavior-requirements | yes — mcpx cancels only its own negative-id server→client requests on timeout (mcpserver/conn.go:263-266) | yes — cancels only its own timed-out request id (mcpclient/client.go:710-716) | narrowed in 2026 (next row) |
| cancellation-ref-client-issued-in-progress | 2026-07-28 | both | MUST | cancellation | “Cancellation notifications MUST only reference requests that: Were previously issued by the client; Are believed to still be in-progress” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/cancellation#behavior-requirements | yes (vacuous: sends none to modern clients) | yes | “same direction” → “by the client” |
| cancellation-client-must-not-cancel-initialize | 2024-11-05..2025-11-25 | client | MUST NOT | cancellation | “The initialize request MUST NOT be cancelled by clients” (schema: “A client MUST NOT attempt to cancel its initialize request.”) | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/cancellation#behavior-requirements | n/a | no — initialize goes through call→roundTrip, which sends notifications/cancelled on any ctx timeout (mcpclient/client.go:269, :710-716) | removed in 2026 (no initialize) |
| cancellation-task-use-tasks-cancel | 2025-11-25 | both | MUST | cancellation | “For task-augmented requests, the tasks/cancel request MUST be used instead of the notifications/cancelled notification.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/cancellation#behavior-requirements | yes (mcpx never cancels a task it requested) | yes (never task-augments upstream) | new in 2025-11-25; gone in 2026 core |
| cancellation-requestid-required-non-task-forbidden-task | 2025-11-25 | both | MUST / MUST NOT | cancellation | schema CancelledNotificationParams.requestId: “This MUST be provided for cancelling non-task requests. This MUST NOT be used for cancelling tasks (use the tasks/cancel request instead).” | https://modelcontextprotocol.io/specification/2025-11-25/schema#cancellednotificationparams | yes | yes | schema-only phrasing; 2024–2025-06 schemas have no such text |
| cancellation-receiver-should-stop-free-no-response | 2024-11-05..2025-11-25 | both | SHOULD | cancellation | “Receivers of cancellation notifications SHOULD: Stop processing the cancelled request; Free associated resources; Not send a response for the cancelled request” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/cancellation#behavior-requirements | no — recorded only (mcpserver/server.go:1521-1538); upstream call not interrupted (docs/protocol.md §6) | not-implemented — mcpclient has no handler for an inbound notifications/cancelled (legacy server cancelling its own elicitation) | receiver narrowed to server in 2026 |
| cancellation-server-should-stop-free-no-response | 2026-07-28 | server | SHOULD | cancellation | “Servers receiving cancellation notifications SHOULD: Stop processing…; Free associated resources; Not send a response…” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/cancellation#behavior-requirements | no — as above | n/a | side narrowed |
| cancellation-receiver-may-ignore | 2024-11-05..2025-11-25 | both | MAY | cancellation | “Receivers MAY ignore cancellation notifications if: The referenced request is unknown; Processing has already completed; The request cannot be cancelled” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/cancellation#behavior-requirements | yes | yes | |
| cancellation-server-may-ignore | 2026-07-28 | server | MAY | cancellation | “Servers MAY ignore cancellation notifications if: …” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/cancellation#behavior-requirements | yes | n/a | side narrowed |
| cancellation-sender-ignore-late-response | 2024-11-05..2025-11-25 | both | SHOULD | cancellation | “The sender of the cancellation notification SHOULD ignore any response to the request that arrives afterward” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/cancellation#behavior-requirements | yes — pending entry deleted on timeout (conn.go:249-253) | yes — pending entry deleted (client.go:710-713) | |
| cancellation-client-ignore-late-response | 2026-07-28 | client | SHOULD | cancellation | “The client SHOULD ignore any response to the cancelled request that arrives afterward” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/cancellation#behavior-requirements | n/a | yes | side narrowed |
| cancellation-handle-races | 2024-11-05..2026-07-28 | both | MUST | cancellation | “Both parties MUST handle these race conditions gracefully” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/cancellation#timing-considerations | yes (cancel is a map write; late cancel harmless) | yes | |
| cancellation-log-reasons | 2024-11-05..2026-07-28 | both | SHOULD | cancellation | “Both parties SHOULD log cancellation reasons for debugging” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/cancellation#implementation-notes | yes — reason kept and passed to OnCancel | no evidence of logging inbound reasons | |
| cancellation-ui-indicate | 2024-11-05..2026-07-28 | both | SHOULD | cancellation | “Application UIs SHOULD indicate when cancellation is requested” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/cancellation#implementation-notes | n/a (no UI) | n/a (no UI) | |
| cancellation-ignore-invalid | 2024-11-05..2026-07-28 | both | SHOULD | cancellation | “Invalid cancellation notifications SHOULD be ignored: Unknown request IDs; Already completed requests; Malformed notifications” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/cancellation#error-handling | yes — malformed params dropped (server.go:1526) | yes (ignored entirely) | |
| cancellation-processing-should-cease | 2024-11-05..2026-07-28 | both (receiver) | SHOULD | cancellation | schema: “This notification indicates that the result will be unused, so any associated processing SHOULD cease.” | https://modelcontextprotocol.io/specification/2026-07-28/schema#cancellednotification | no (see stop row) | not-implemented | |
| cancellation-client-should-send | 2026-07-28 | client | SHOULD | cancellation | “A client SHOULD send a cancellation notification to indicate that a request it previously issued should be terminated.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/cancellation | n/a | yes | new; conflicts with HTTP rule, see Conflicts C3 |
| cancellation-server-must-send-cancelled-on-listen-teardown | 2026-07-28 | server | MUST | cancellation | “A server MUST send notifications/cancelled referencing a subscriptions/listen request ID when it tears down that subscription stream” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/cancellation | no — nothing sends it; comment at server.go:623-627 claims “the transport sends the terminating notifications/cancelled”, no such code exists (only conn.go:265, which is for elicitation timeouts) | n/a | new; conflicts with subscriptions page, see C1 |
| cancellation-server-only-for-listen | 2026-07-28 | server | MUST NOT / MUST | cancellation | “Servers MUST NOT send notifications/cancelled for any other purpose.” + “Server-sent cancellation notifications MUST reference a subscriptions/listen request” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/cancellation#behavior-requirements | yes for modern peers — conn.go:265 only fires on legacy wire requests; a modern connection never gets a server request | n/a | legal→forbidden vs ≤2025-11-25, see C2 |
| cancellation-http-disconnect-is-cancel | 2026-07-28 | server | MUST | cancellation | “Streamable HTTP: Closing the SSE response stream is the cancellation signal. The server MUST treat a client disconnect as cancellation of that request.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/cancellation#transport-specific-cancellation | no — no path from request ctx to the upstream call (docs/protocol.md §6) | n/a | reverses ≤2025-11-25 transport rule — C4 |
| cancellation-http-no-messages-after-close | 2026-07-28 | server | MUST NOT / SHOULD | cancellation | “The server SHOULD stop work on the cancelled request as soon as practical and MUST NOT send any further messages for it.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#cancellation | yes (stream gone, nothing written) — stop-work SHOULD: no | n/a | |
| cancellation-stdio-client-must-send | 2026-07-28 | client | MUST | cancellation | “stdio: There is no per-request stream to close. The client MUST send a notifications/cancelled notification referencing the request ID.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/cancellation#transport-specific-cancellation | n/a | yes on stdio; on legacy-era HTTP it also POSTs notifications/cancelled; on a 2026-07-28 HTTP upstream it sends none — cancelled() returns early for an HTTP transport with a meta version set (internal/mcpclient/modern.go:582) and closing the response stream is the cancellation signal, which 2026 calls the expected behaviour for that transport | new |
| cancellation-timeouts-establish | 2026-07-28 | both | SHOULD | cancellation | “Implementations SHOULD establish timeouts for all sent requests” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/cancellation#timeouts | yes (proto.askTimeout) | yes (pool.callTimeout) | new |
| cancellation-timeout-then-cancel | 2026-07-28 | both | SHOULD | cancellation | “the sender SHOULD cancel the request and stop waiting for a response” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/cancellation#timeouts | yes (legacy only) | yes | new |
| cancellation-timeouts-per-request-configurable | 2026-07-28 | both | SHOULD | cancellation | “SDKs and other middleware SHOULD allow these timeouts to be configured on a per-request basis.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/cancellation#timeouts | no — global settings | no — per-server/global | new; mcpx is “middleware” |
| cancellation-max-timeout-despite-progress | 2026-07-28 | both | SHOULD (+MAY) | cancellation | “Implementations MAY choose to reset the timeout clock when receiving a progress notification … SHOULD always enforce a maximum timeout” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/cancellation#timeouts | yes (fixed timeout, no reset) | yes | new |
| progress-token-string-or-int | 2024-11-05..2026-07-28 | both (requester) | MUST | progress | “Progress tokens MUST be a string or integer value” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/progress#progress-flow | n/a (as a server mcpx never requests progress; a host’s token is relayed back verbatim) | yes — the token mcpx sends upstream is a string, mcpx-<n> (#212) | |
| progress-token-unique-sender | 2024-11-05..2025-11-25 | both | MUST | progress | “Progress tokens can be chosen by the sender using any means, but MUST be unique across all active requests.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/progress#progress-flow | yes (vacuous) | yes (vacuous) | |
| progress-token-unique-client | 2026-07-28 | client | MUST | progress | “Progress tokens can be chosen by the client using any means, but MUST be unique across all active requests.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/progress#progress-flow | n/a | yes (vacuous) | sender→client |
| progress-receiver-may-send | 2024-11-05..2025-11-25 | both | MAY | progress | “The receiver MAY then send progress notifications containing: The original progress token; The current progress value so far; An optional “total” value“ | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/progress#progress-flow | not-implemented-by-choice — no notifications/progress in mcpserver; upstream progress is not forwarded downstream | n/a (never receives requests with tokens) | |
| progress-server-may-send | 2026-07-28 | server | MAY | progress | “The server MAY send progress notifications to report the status of requests the client has issued.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/progress | not-implemented-by-choice | n/a | client can no longer send progress — C6 |
| progress-must-increase | 2024-11-05..2026-07-28 | both (notifier) | MUST | progress | “The progress value MUST increase with each notification, even if the total is unknown.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/progress#progress-flow | yes (vacuous) | n/a | schema says lowercase “should increase” — C7 |
| progress-message-human-readable | 2025-03-26..2026-07-28 | both (notifier) | SHOULD | progress | “The message field SHOULD provide relevant human readable progress information.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/progress#progress-flow | yes (vacuous) | n/a | message added 2025-03-26 |
| progress-only-active-tokens | 2024-11-05..2026-07-28 | both (notifier) | MUST | progress | “Progress notifications MUST only reference tokens that: Were provided in an active request; Are associated with an in-progress operation” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/progress#behavior-requirements | yes (vacuous) | n/a | |
| progress-receiver-may-skip | 2024-11-05..2025-11-25 | both | MAY | progress | “Receivers of progress requests MAY: Choose not to send any progress notifications; Send notifications at whatever frequency…; Omit the total value if unknown” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/progress#behavior-requirements | yes | yes | |
| progress-server-may-skip | 2026-07-28 | server | MAY | progress | “Servers receiving a request with a progress token MAY: Choose not to send any progress notifications; …” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/progress#behavior-requirements | yes | n/a | side narrowed |
| progress-task-token-lives-with-task | 2025-11-25 | both (receiver) | MUST | progress | “the progressToken provided in the original request MUST continue to be used for progress notifications throughout the task’s lifetime, even after the CreateTaskResult has been returned” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/progress#behavior-requirements | yes (vacuous) | n/a | removed from 2026 core |
| progress-task-same-token | 2025-11-25 | both (receiver) | MUST | progress | “Progress notifications for tasks MUST use the same progressToken that was provided in the initial task-augmented request” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/progress#behavior-requirements | yes (vacuous) | n/a | |
| progress-task-stop-at-terminal | 2025-11-25 | both (receiver) | MUST | progress | “Progress notifications for tasks MUST stop after the task reaches a terminal status (completed, failed, or cancelled)” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/progress#behavior-requirements | yes (vacuous) | n/a | |
| progress-track-tokens | 2024-11-05..2026-07-28 | both | SHOULD | progress | “Senders and receivers SHOULD track active progress tokens” (2026: “Clients and servers …”) | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/progress#implementation-notes | n/a | no — OnProgress passes every token through untracked (client.go:487-493) | wording only |
| progress-rate-limit | 2024-11-05..2026-07-28 | both | SHOULD | progress | “Both parties SHOULD implement rate limiting to prevent flooding” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/progress#implementation-notes | yes (sends none) | no inbound rate limiting | |
| progress-stop-after-completion | 2024-11-05..2026-07-28 | both (notifier) | MUST | progress | “Progress notifications MUST stop after completion” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/progress#implementation-notes | yes (vacuous) | n/a | |
| progress-http-notifications-relate-to-request | 2026-07-28 | server | MUST | progress | “The server MAY send JSON-RPC notifications — for example, notifications/progress or notifications/message — before the final response. These notifications MUST relate to the originating client request.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#receiving-messages | yes (vacuous) | n/a | transport page; listed here because it scopes progress/log delivery |
| pagination-no-fixed-page-size | 2024-11-05..2026-07-28 | client | MUST NOT | pagination | “Page size is determined by the server, and clients MUST NOT assume a fixed page size” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/pagination#pagination-model | n/a | yes — loops on nextCursor (client.go:740-770, :815-825) | |
| pagination-stable-cursors | 2024-11-05..2026-07-28 | server | SHOULD | pagination | “Servers SHOULD: Provide stable cursors” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/pagination#implementation-guidelines | partial — cursor is base64 o:<offset> (server.go:1499-1501); shifts if the aggregated list changes between pages | n/a | |
| pagination-invalid-cursor-graceful | 2024-11-05..2026-07-28 | server | SHOULD | pagination | “Handle invalid cursors gracefully” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/pagination#implementation-guidelines | yes (silently restarts at 0) | n/a | |
| pagination-missing-nextcursor-end | 2024-11-05..2026-07-28 | client | SHOULD | pagination | “Clients SHOULD: Treat a missing nextCursor as the end of results” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/pagination#implementation-guidelines | n/a | yes | |
| pagination-support-both-flows | 2024-11-05..2026-07-28 | client | SHOULD | pagination | “Support both paginated and non-paginated flows” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/pagination#implementation-guidelines | n/a | yes | |
| pagination-cursor-opaque | 2024-11-05..2026-07-28 | client | MUST | pagination | “Clients MUST treat cursors as opaque tokens: Don’t make assumptions about cursor format; Don’t attempt to parse or modify cursors” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/pagination#implementation-guidelines | n/a | yes | |
| pagination-no-persist-across-sessions | 2024-11-05..2025-11-25 | client | MUST | pagination | “Don’t persist cursors across sessions” | https://modelcontextprotocol.io/specification/2025-11-25/server/utilities/pagination#implementation-guidelines | n/a | yes (cursors are loop-local) | removed in 2026 (replaced by next row) |
| pagination-empty-cursor-not-end | 2026-07-28 | client | MUST NOT | pagination | “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)” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/pagination#implementation-guidelines | yes (mcpx never emits "") | no — if res.NextCursor == "" { break } (client.go:744, :766, :820); the string field cannot distinguish absent from "" | new; legal-to-end → forbidden — C5 |
| pagination-invalid-cursor-32602 | 2024-11-05..2026-07-28 | server | SHOULD | pagination | “Invalid cursors SHOULD result in an error with code -32602 (Invalid params).” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/pagination#error-handling | no — undecodable cursor → page 0, out-of-range → empty page (server.go:1483-1491) | n/a | |
| logging-declare-capability | 2024-11-05..2026-07-28 | server | MUST | logging | “Servers that emit log message notifications MUST declare the logging capability” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/logging#capabilities | yes (vacuous: emits none, declares none — server.go:1398-1403). docs/protocol.md §2.2 says logging ✓ for legacy and “removed in 2026-07-28”; both wrong vs code and vs spec (2026 deprecates, keeps logging? in schema line 808) | n/a | 2026 adds deprecation banner |
| logging-client-may-setlevel | 2024-11-05..2025-11-25 | client | MAY | logging | “To configure the minimum log level, clients MAY send a logging/setLevel request” | https://modelcontextprotocol.io/specification/2025-11-25/server/utilities/logging#setting-log-level | accepted, {} (server.go:565-571) | yes — SetLevel (client.go:574) | removed in 2026 (changelog item 5) |
| logging-setlevel-at-or-above | 2024-11-05..2025-11-25 | server | should (schema) | logging | schema: “The server should send all logs at this level and higher (i.e., more severe) to the client as notifications/message.” | https://modelcontextprotocol.io/specification/2025-11-25/schema#setlevelrequestparams | yes (vacuous) | n/a | |
| logging-unset-server-chooses | 2024-11-05..2025-11-25 | server | MAY | logging | schema: “If no logging/setLevel request has been sent from the client, the server MAY decide which messages to send automatically.” | https://modelcontextprotocol.io/specification/2025-11-25/schema#loggingmessagenotification | yes | n/a (mcpx receives upstream logs from any era) | legal→forbidden in 2026 — C8 |
| logging-no-message-without-loglevel | 2026-07-28 | server | MUST NOT | logging | “include io.modelcontextprotocol/logLevel in the request’s _meta. The server MUST NOT emit notifications/message for a request that does not include this field.” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/logging#per-request-log-level | yes (vacuous) | not-implemented — never sends logLevel upstream, yet listens for notifications/message (client.go:480-486), so from a conforming modern server it gets none | new; schema RequestMetaObject repeats it |
| logging-request-scoped-only | 2026-07-28 | server | MUST NOT | logging | “notifications/message is request-scoped: the server MUST NOT deliver it on a subscriptions/listen stream or on any stream other than the one carrying the response to the request that set the log level.” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/logging#per-request-log-level | yes (vacuous) | n/a | new |
| logging-may-send-before-response | 2026-07-28 | server | MAY | logging | “the server MAY send notifications/message notifications at or above the requested level on the response stream of that request, before the final response.” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/logging#per-request-log-level | not-implemented-by-choice | n/a | new |
| logging-errors-setlevel | 2024-11-05..2025-11-25 | server | SHOULD | logging | “Servers SHOULD return standard JSON-RPC errors …: Invalid log level: -32602 (Invalid params); Configuration errors: -32603 (Internal error)” | https://modelcontextprotocol.io/specification/2025-11-25/server/utilities/logging#error-handling | no — logging/setLevel returns {} for any level | n/a | |
| logging-invalid-loglevel-reject-request | 2026-07-28 | server | SHOULD | logging | “If the io.modelcontextprotocol/logLevel value carried in a request’s _meta is not a recognized log level, the server SHOULD reject that request with a standard JSON-RPC error” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/logging#error-handling | no — _meta.logLevel never inspected | n/a | now rejects the carrying request (e.g. a tools/call) |
| logging-server-hygiene | 2024-11-05..2026-07-28 | server | SHOULD | logging | “Servers SHOULD: Rate limit log messages; Include relevant context in data field; Use consistent logger names; Remove sensitive information” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/logging#implementation-considerations | yes (vacuous) | n/a | |
| logging-no-secrets-pii | 2024-11-05..2026-07-28 | both (emitter) | MUST NOT | logging | “Log messages MUST NOT contain: Credentials or secrets; Personal identifying information; Internal system details that could aid attacks” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/logging#security | yes (vacuous) | relevant only if mcpx ever relays upstream notifications/message downstream — it does not | |
| logging-impl-validate-control | 2024-11-05..2026-07-28 | both | SHOULD | logging | “Implementations SHOULD: Rate limit messages; Validate all data fields; Control log access; Monitor for sensitive content” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/logging#security | yes (vacuous) | partial | |
| logging-deprecated | 2026-07-28 | both | SHOULD NOT / SHOULD | logging | “New implementations SHOULD NOT adopt it; existing implementations SHOULD migrate to logging to stderr for stdio transports, or to OpenTelemetry” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/logging | yes (does not adopt) | n/a | new (SEP-2577) |
| completion-declare-capability | 2025-03-26..2026-07-28 | server | MUST | completion | “Servers that support completions MUST declare the completions capability” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/completion#capabilities | yes (server.go:1402) | yes — asks upstream only if it declared completions (docs/protocol.md §4.3) | absent in 2024-11-05 (no capability existed) — C9 |
| completion-max-100 | 2024-11-05..2026-07-28 | server | descr. + schema | completion | “Maximum 100 items per response”; schema: “Must not exceed 100 items.” @maxItems 100 | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/completion#completion-results | unverified — did not check truncation in s.complete | should truncate upstream values if relaying | |
| completion-server-should | 2024-11-05..2026-07-28 | server | SHOULD | completion | “Servers SHOULD: Return suggestions sorted by relevance; Implement fuzzy matching where appropriate; Rate limit completion requests; Validate all inputs” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/completion#implementation-considerations | yes — suggestions ranked by relevance (exact > prefix > substring tiers, rankCompletions in internal/daemon/ops.go, #2388) and completion requests rate limited per caller (completion.perMinute) and per server (completion.serverPerMinute) at the /v1 choke point (#2387); inputs validated (see completion-errors) | n/a | retired the stale wording that said values were matched by substring and sorted alphabetically — local matching was prefix-only (hasPrefixFold) before #2388 |
| completion-client-should | 2024-11-05..2026-07-28 | client | SHOULD | completion | “Clients SHOULD: Debounce rapid completion requests; Cache completion results where appropriate; Handle missing or partial results gracefully” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/completion#implementation-considerations | n/a | partial — falls back to cache with "source":"cache" | |
| completion-security | 2024-11-05..2026-07-28 | both | MUST | completion | “Implementations MUST: Validate all completion inputs; Implement appropriate rate limiting; Control access to sensitive suggestions; Prevent completion-based information disclosure” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/completion#security | partial — inputs validated and rate limiting implemented per caller (completion.perMinute) and per server (completion.serverPerMinute) (#2387); control of access to sensitive suggestions and prevention of completion-based information disclosure still pending principals (#1968) / permissive-auth (#1972) | n/a | |
| completion-errors | 2025-03-26..2026-07-28 | server | SHOULD | completion | “Method not found: -32601 (Capability not supported); Invalid prompt name: -32602; Missing required arguments: -32602; Internal errors: -32603” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/completion#error-handling | unverified | n/a | added 2025-03-26 |
| completion-context-arguments | 2025-06-18..2026-07-28 | client | should (lowercase) | completion | “clients should include previous completions in the context.arguments object to provide context for subsequent requests.” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/completion#requesting-completions | n/a | pass-through of caller’s params | added 2025-06-18 |
| tasks-declare-capability | 2025-11-25 | both (receiver) | MUST | tasks | “Servers and clients that support task-augmented requests MUST declare a tasks capability during initialization.” (schema: “receivers MUST declare support for task augmentation of specific request types”) | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#capabilities | yes | not-implemented-by-choice (mcpx declares no client tasks; upstream cannot task-augment sampling/elicitation to it) | → extension in 2026 |
| tasks-augment-only-if-declared | 2025-11-25 | both (requestor) | SHOULD | tasks | “Requestors SHOULD only augment requests with a task if the corresponding capability has been declared by the receiver.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#capability-negotiation | yes (never augments) | yes (never augments) | |
| tasks-no-capability-no-tasks | 2025-11-25 | both (requestor) | SHOULD NOT | tasks | “If capabilities.tasks is not defined, the peer SHOULD NOT attempt to create tasks during requests.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#capability-negotiation | yes | yes | |
| tasks-tool-no-cap-no-augment | 2025-11-25 | client | MUST NOT | tasks | “If a server’s capabilities do not include tasks.requests.tools.call, then clients MUST NOT attempt to use task augmentation on that server’s tools” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#tool-level-negotiation | n/a | yes | |
| tasks-tool-forbidden-default | 2025-11-25 | both | MUST NOT / SHOULD | tasks | “If execution.taskSupport is not present or "forbidden", clients MUST NOT attempt to invoke the tool as a task. Servers SHOULD return a -32601 (Method not found) error if a client attempts to do so. This is the default behavior.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#tool-level-negotiation | no — mcpx publishes no execution.taskSupport on any tool (no occurrence in code), so every tool defaults to forbidden, yet it accepts task on every tools/call (server.go:481-501) instead of -32601. Net: its tasks.requests.tools.call declaration is unusable by a conforming client | n/a | |
| tasks-tool-optional | 2025-11-25 | client | MAY | tasks | “If execution.taskSupport is "optional", clients MAY invoke the tool as a task or as a normal request.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#tool-level-negotiation | not-implemented (never advertises optional) | n/a | |
| tasks-tool-required | 2025-11-25 | both | MUST | tasks | “If execution.taskSupport is "required", clients MUST invoke the tool as a task. Servers MUST return a -32601 (Method not found) error if a client does not attempt to do so.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#tool-level-negotiation | n/a (never required) | n/a — mcpx reads upstream execution.taskSupport to serve its own clients, but never task-augments the upstream call; a required upstream tool that enforces it would fail | conflicts with -32600 MAY — C10 |
| tasks-requestor-may-ttl | 2025-11-25 | both (requestor) | MAY | tasks | “Requestors MAY include a ttl value indicating the desired task lifetime duration (in milliseconds) since its creation.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#creating-tasks | honoured (wantsTask) | n/a | |
| tasks-poll-respect-interval | 2025-11-25 | both (requestor) | SHOULD | tasks | “Requestors SHOULD respect the pollInterval provided in responses when determining polling frequency.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#getting-tasks | n/a | n/a (no upstream tasks) | |
| tasks-poll-until-terminal | 2025-11-25 | both (requestor) | SHOULD | tasks | “Requestors SHOULD continue polling until the task reaches a terminal status … or until encountering the input_required status.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#getting-tasks | n/a | n/a | |
| tasks-sse-client-may-disconnect | 2025-11-25 | client | MAY / MUST | tasks | “clients MAY disconnect from an SSE stream opened by the server in response to a tasks/get request at any time … all implementations MUST continue to comply with the existing Streamable HTTP transport specification.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#getting-tasks | yes (tasks/get answered as JSON) | n/a | same note on tasks/result |
| tasks-status-notification-optional | 2025-11-25 | both | MAY / MUST NOT | tasks | “Receivers MAY send notifications/tasks/status notifications when a task’s status changes.” “Requestors MUST NOT rely on receiving the notifications/tasks/status notification” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#task-notifications | not-implemented-by-choice (sends none) | yes — dropped, polls (docs/protocol.md §4.2) | |
| tasks-status-notification-no-related-task | 2025-11-25 | both (receiver) | SHOULD NOT | tasks | “the notifications/tasks/status notification SHOULD NOT include the io.modelcontextprotocol/related-task metadata” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#task-notifications | yes (vacuous) | n/a | |
| tasks-receiver-without-cap-ignore | 2025-11-25 | both (receiver) | MUST | tasks | “Receivers that do not declare the task capability for a request type MUST process requests of that type normally, ignoring any task-augmentation metadata if present.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#task-support-and-handling | yes — task honoured only on tools/call | n/a — mcpx declares no client task caps; unverified whether it strips task from an upstream sampling/createMessage | |
| tasks-receiver-may-require | 2025-11-25 | both (receiver) | MAY | tasks | “Receivers that declare the task capability for a request type MAY return an error for non-task-augmented requests” / “-32600 (Invalid request)” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#task-support-and-handling | not used | n/a | -32600 here vs -32601 for tools — C10 |
| tasks-id-string-receiver-unique | 2025-11-25 | both (receiver) | MUST | tasks | “Task IDs MUST be a string value.” “…MUST be generated by the receiver…” “…MUST be unique among all tasks controlled by the receiver.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#task-id-requirements | yes — tsk- + 16 hex from crypto/rand (tasks/tasks.go:86-90) | n/a | |
| tasks-begin-working | 2025-11-25 | both (receiver) | MUST | tasks | “Tasks MUST begin in the working status when created.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#task-status-lifecycle | yes | n/a | |
| tasks-valid-transitions | 2025-11-25 | both (receiver) | MUST | tasks | “Receivers MUST only transition tasks through the following valid paths” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#task-status-lifecycle | yes — SetStatus is a no-op on terminal; not otherwise validated (tasks.go:185-191) | n/a | |
| tasks-terminal-immutable | 2025-11-25 | both (receiver) | MUST NOT | tasks | “Tasks with a completed, failed, or cancelled status are in a terminal state and MUST NOT transition to any other status” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#task-status-lifecycle | yes (tasks.go:122-124, :201) | n/a | extension says cancel may still end non-cancelled — C11 |
| tasks-input-required-move | 2025-11-25 | both (receiver) | SHOULD | tasks | “When the task receiver has messages for the requestor that are necessary to complete the task, the receiver SHOULD move the task to the input_required status.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#input-required-status | yes (SetTaskStatus) | n/a | |
| tasks-input-request-related-task | 2025-11-25 | both (receiver) | MUST | tasks | “The receiver MUST include the io.modelcontextprotocol/related-task metadata in the request to associate it with the task.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#input-required-status | no — no related-task anywhere in mcpx; an elicitation/create raised by a task-run tools/call goes out untagged | n/a | |
| tasks-requestor-input-required-call-result | 2025-11-25 | both (requestor) | SHOULD | tasks | “When the requestor encounters the input_required status, it SHOULD preemptively call tasks/result.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#input-required-status | n/a | n/a | |
| tasks-leave-input-required | 2025-11-25 | both (receiver) | SHOULD | tasks | “When the receiver receives all required input, the task SHOULD transition out of input_required status” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#input-required-status | unverified | n/a | |
| tasks-sse-any-stream | 2025-11-25 | client | SHOULD | tasks | “clients SHOULD expect messages to be delivered on any SSE stream, including the HTTP GET stream.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#input-required-status | n/a | n/a | |
| tasks-sse-no-upgrade-get | 2025-11-25 | server | SHOULD NOT | tasks | “Where possible, servers SHOULD NOT upgrade to an SSE stream in response to a tasks/get request” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#input-required-status | yes | n/a | |
| tasks-timestamps | 2025-11-25 | both (receiver) | MUST | tasks | “Receivers MUST include a createdAt … timestamp in all task responses” / “…MUST include a lastUpdatedAt …” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#ttl-and-resource-management | yes (tasks.go:30-31) | n/a | |
| tasks-ttl-override-report | 2025-11-25 | both (receiver) | MAY / MUST | tasks | “Receivers MAY override the requested ttl duration.” “Receivers MUST include the actual ttl duration (or null for unlimited) in tasks/get responses.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#ttl-and-resource-management | yes | n/a | |
| tasks-delete-after-ttl | 2025-11-25 | both (receiver) | MAY | tasks | “After a task’s ttl lifetime has elapsed, receivers MAY delete the task and its results, regardless of the task status.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#ttl-and-resource-management | yes (tasks.go:148-153, also cancels the work) | n/a | |
| tasks-poll-interval | 2025-11-25 | both | MAY / SHOULD | tasks | “Receivers MAY include a pollInterval value … Requestors SHOULD respect this value when provided.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#ttl-and-resource-management | yes (1000 ms) | n/a | |
| tasks-return-createtaskresult | 2025-11-25 | both (receiver) | MUST / SHOULD | tasks | “Receivers that accept a task-augmented request MUST return a CreateTaskResult as the response. This result SHOULD be returned as soon as possible after accepting the task.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#result-retrieval | yes ({"task": …}, server.go:500) | n/a | |
| tasks-result-terminal-final | 2025-11-25 | both (receiver) | MUST | tasks | “…for a task in a terminal status … it MUST return the final result of the underlying request, whether that is a successful result or a JSON-RPC error.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#result-retrieval | yes (mcpserver/tasks.go:104-118) | n/a | |
| tasks-result-blocks | 2025-11-25 | both (receiver) | MUST | tasks | “…in any other non-terminal status (working or input_required), it MUST block the response until the task reaches a terminal status.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#result-retrieval | yes (st.Result(ctx,…)) | n/a | removed in extension (no tasks/result) |
| tasks-result-exact | 2025-11-25 | both (receiver) | MUST | tasks | “receivers MUST return from tasks/result exactly what the underlying request would have returned” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#result-retrieval | yes; except a cancelled task’s tasks/result returns whatever the aborted goroutine yielded — unverified | n/a | |
| tasks-related-task-all-messages | 2025-11-25 | both | MUST | tasks | “All requests, notifications, and responses related to a task MUST include the io.modelcontextprotocol/related-task key in their _meta field” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#associating-task-related-messages | no | n/a | internally contradicted — C12 |
| tasks-taskid-param-authoritative | 2025-11-25 | both | MUST / SHOULD NOT | tasks | “the taskId parameter in the request MUST be used as the source of truth … Requestors SHOULD NOT include io.modelcontextprotocol/related-task metadata in these requests, and receivers MUST ignore such metadata” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#associating-task-related-messages | yes | n/a | |
| tasks-no-related-task-in-get-list-cancel-results | 2025-11-25 | both (receiver) | SHOULD NOT | tasks | “for the tasks/get, tasks/list, and tasks/cancel operations, receivers SHOULD NOT include io.modelcontextprotocol/related-task metadata in the result messages” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#associating-task-related-messages | yes | n/a | |
| tasks-result-response-related-task | 2025-11-25 | both (receiver) | MUST | tasks | “The tasks/result operation MUST include this metadata in its response, as the result structure itself does not contain the task ID.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#related-task-metadata | no — reply(result) untagged (mcpserver/tasks.go:118) | n/a | |
| tasks-list-paginate | 2025-11-25 | both (receiver) | SHOULD / MUST | tasks | “Receivers SHOULD use cursor-based pagination…” “Receivers MUST include a nextCursor in the response if more tasks are available.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#task-listing | yes (mcpserver/tasks.go:89-95) | n/a | tasks/list removed in extension |
| tasks-list-cursor-opaque | 2025-11-25 | both (requestor) | MUST | tasks | “Requestors MUST treat cursors as opaque tokens and not attempt to parse or modify them.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#task-listing | n/a | n/a | |
| tasks-get-implies-list | 2025-11-25 | both (receiver) | MUST | tasks | “If a task is retrievable via tasks/get for a requestor, it MUST be retrievable via tasks/list for that requestor.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#task-listing | yes (one global store) | n/a | |
| tasks-cancel-terminal-reject | 2025-11-25 | both (receiver) | MUST | tasks | “Receivers MUST reject cancellation requests for tasks already in a terminal status … with error code -32602 (Invalid params).” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#task-cancellation | no — Cancel returns the terminal snapshot as success (tasks/tasks.go:194-206, mcpserver/tasks.go:120-125) | n/a | |
| tasks-cancel-transition-before-response | 2025-11-25 | both (receiver) | SHOULD / MUST | tasks | “receivers SHOULD attempt to stop the task execution and MUST transition the task to cancelled status before sending the response.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#task-cancellation | yes | n/a | extension: cooperative, not obliged — C11 |
| tasks-cancelled-sticky | 2025-11-25 | both (receiver) | MUST | tasks | “Once a task is cancelled, it MUST remain in cancelled status even if execution continues to completion or fails.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#task-cancellation | yes (tasks.go:122-124) | n/a | reversed by extension — C11 |
| tasks-cancelled-may-delete | 2025-11-25 | both | MAY / SHOULD NOT | tasks | “receivers MAY delete cancelled tasks at their discretion at any time” “Requestors SHOULD NOT rely on cancelled tasks being retained” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#task-cancellation | yes | n/a | |
| tasks-protocol-errors | 2025-11-25 | both (receiver) | MUST | tasks | “Receivers MUST return standard JSON-RPC errors …: Invalid or nonexistent taskId …: -32602; Invalid or nonexistent cursor in tasks/list: -32602; Attempt to cancel a task already in a terminal status: -32602; Internal errors: -32603” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#protocol-errors | partial — unknown taskId → -32602 yes; bad cursor → silently page 0 (no); terminal cancel → success (no) | n/a | |
| tasks-informative-errors | 2025-11-25 | both (receiver) | SHOULD | tasks | “Receivers SHOULD provide informative error messages to describe the cause of errors.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#protocol-errors | yes (“no task X; it may have expired”) | n/a | |
| tasks-failed-status-message | 2025-11-25 | both (receiver) | SHOULD | tasks | “The tasks/get response SHOULD include a statusMessage field with diagnostic information about the failure.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#task-execution-errors | partial — set for JSON-RPC faults, empty for isError tool results (tasks.go:127-139) | n/a | |
| tasks-result-same-error | 2025-11-25 | both (receiver) | MUST | tasks | “If the underlying request resulted in a JSON-RPC error, tasks/result MUST return that same JSON-RPC error.” / “…MUST return a successful JSON-RPC response containing that result.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#task-execution-errors | yes | n/a | |
| tasks-bind-auth-context | 2025-11-25 | both (receiver) | MUST | tasks | “When an authorization context is provided, receivers MUST bind tasks to said context.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#task-isolation-and-access-control | not-implemented-by-choice — mcpx has no authorization context (no OAuth) | n/a | |
| tasks-document-unbound | 2025-11-25 | both (receiver) | SHOULD | tasks | “receivers SHOULD document this limitation clearly, as task results may be accessible to any requestor that can guess the task ID.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#task-isolation-and-access-control | not found in docs/protocol.md | n/a | |
| tasks-unbound-secure-ids | 2025-11-25 | both (receiver) | MUST | tasks | “If context-binding is unavailable, receivers MUST generate cryptographically secure task IDs with enough entropy to prevent guessing” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#task-isolation-and-access-control | borderline — CSPRNG yes, 64 bits; “enough” undefined | n/a | |
| tasks-unidentified-no-list | 2025-11-25 | both (receiver) | SHOULD NOT | tasks | “receivers that cannot identify requestors SHOULD NOT declare the tasks.list capability” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#task-isolation-and-access-control | no — declares tasks.list (server.go:1411-1412) and tasks/list returns every task in the daemon across all connections | n/a | |
| tasks-bound-reject-foreign | 2025-11-25 | both (receiver) | MUST | tasks | “If context-binding is available, receivers MUST reject tasks/get, tasks/result, and tasks/cancel requests for tasks that do not belong to the same authorization context…” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#task-isolation-and-access-control | n/a (no context) | n/a | |
| tasks-rate-limit | 2025-11-25 | both (receiver) | SHOULD | tasks | “receivers SHOULD implement rate limiting on task operations to prevent denial-of-service and enumeration attacks.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#task-isolation-and-access-control | no | n/a | |
| tasks-resource-limits | 2025-11-25 | both (receiver) | SHOULD | tasks | “Enforce limits on concurrent tasks per requestor; Enforce maximum ttl durations …; Clean up expired tasks promptly; Document maximum supported ttl…” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#resource-management | partial — expiry yes; no max ttl clamp found, no concurrency cap | n/a | |
| tasks-audit | 2025-11-25 | both | SHOULD | tasks | “Receivers SHOULD: Log task creation, completion, and retrieval events…” / “Requestors SHOULD: Log task lifecycle events…” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#audit-and-logging | unverified | n/a | |
| ext-tasks-client-declare-per-request | 2026-07-28 (ext) | client | must (informal) | tasks | “The client includes io.modelcontextprotocol/tasks in its per-request capabilities.” | docs/extensions/tasks/overview.mdx#how-tasks-work | n/a | not-implemented-by-choice | replaces 2025-11-25 initialize capability |
| ext-tasks-server-advertise-discover | 2026-07-28 (ext) | server | must (informal) | tasks | “Include the extension in your server/discover capabilities” | docs/extensions/tasks/overview.mdx#for-mcp-servers | yes (extensions["io.modelcontextprotocol/tasks"], server.go:1415-1417) | n/a | |
| ext-tasks-never-unsolicited | 2026-07-28 (ext) | server | must (informal) | tasks | “Before returning a CreateTaskResult, verify that the client included the extension in its per-request capabilities. Never return a task to a client that did not declare support.” | docs/extensions/tasks/overview.mdx#for-mcp-servers | partial — returns a task only when the request carried a task param; never checks the extension capability | n/a | changelog wording “unsolicited” — C13 |
| ext-tasks-server-decides | 2026-07-28 (ext) | server | descr. | tasks | “The server decides per-request whether to create a task. Clients opt in once via the extension capability … No per-tool warmup or per-request flag.” | docs/extensions/tasks/overview.mdx#why-not-just-block | no — mcpx uses the 2025-11-25 per-request task flag, which the extension removed | n/a | model reversed vs 2025-11-25 |
| ext-tasks-durable-before-response | 2026-07-28 (ext) | server | must (informal) | tasks | “The task must be durably created before sending the response.” | docs/extensions/tasks/overview.mdx#for-mcp-servers | no in the crash sense — in-memory per-daemon store (tasks/tasks.go:73-76) | n/a | |
| ext-tasks-createtaskresult-shape | 2026-07-28 (ext) | server | must (informal) | tasks | “respond with resultType: "task" and a Task object containing a unique taskId, initial status, ttlMs, and pollIntervalMs.” | docs/extensions/tasks/overview.mdx#for-mcp-servers | no — {"task":{…,"ttl","pollInterval"}} + resultType:"complete" stamped by server.go:452-453 | n/a | field renames vs 2025-11-25 |
| ext-tasks-get-carries-result | 2026-07-28 (ext) | server | must (informal) | tasks | “Return the current task state on each poll. For terminal states, include the result (on completed) or error (on failed) field.” | docs/extensions/tasks/overview.mdx#for-mcp-servers | no — result only via tasks/result | n/a | tasks/result removed (changelog 6) |
| ext-tasks-get-input-requests | 2026-07-28 (ext) | server | descr. | tasks | “If the task moves to input_required, the tasks/get response includes an inputRequests map” | docs/extensions/tasks/overview.mdx#how-tasks-work | no | n/a | |
| ext-tasks-update | 2026-07-28 (ext) | server | must (informal) | tasks | “Accept inputResponses keyed to outstanding inputRequests. Acknowledge with an empty result. Ignore responses for unknown or already-satisfied keys.” | docs/extensions/tasks/overview.mdx#for-mcp-servers | not-implemented (tasks/update absent → -32601) | n/a | new method |
| ext-tasks-cancel-cooperative | 2026-07-28 (ext) | server | must (informal) | tasks | “Acknowledge cancellation requests with an empty result. Honor them when possible, but cancellation is cooperative — the task may still reach a non-cancelled terminal status.” | docs/extensions/tasks/overview.mdx#for-mcp-servers | no — returns Task snapshot, forces cancelled | n/a | reverses 2025-11-25 — C11 |
| ext-tasks-client-polymorphic | 2026-07-28 (ext) | client | must (informal) | tasks | “be prepared to receive either the standard result or a CreateTaskResult with resultType: "task".” | docs/extensions/tasks/overview.mdx#for-mcp-clients | n/a | not-implemented-by-choice (does not declare the extension, so should never receive one) | |
| ext-tasks-client-poll | 2026-07-28 (ext) | client | must (informal) | tasks | “Call tasks/get with the returned taskId, respecting the pollIntervalMs value. Continue polling until the task reaches a terminal status” | docs/extensions/tasks/overview.mdx#for-mcp-clients | n/a | not-implemented-by-choice | |
| ext-tasks-client-persist-ids | 2026-07-28 (ext) | client | must (informal) | tasks | “Store task IDs durably so polling can resume after a client crash or restart.” | docs/extensions/tasks/overview.mdx#for-mcp-clients | n/a | not-implemented-by-choice | |
| ext-tasks-notifications-via-listen | 2026-07-28 (ext) | both | descr. (MAY) | tasks | “Servers can push status updates via notifications/tasks. Clients opt into these through the subscriptions/listen mechanism.” | docs/extensions/tasks/overview.mdx#notifications | yes — taskIds agreed for known visible tasks; notifications/tasks carries the DetailedTask (mcpserver/listen.go watchTasks) | not-implemented | notifications/tasks/status → notifications/tasks; not in SubscriptionFilter of core schema |
| caching-server-must-hint | 2026-07-28 | server | MUST* | caching | “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” (schema: ttlMs, cacheScope required on CacheableResult) | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/caching#cacheable-results | no — ttlMs/cacheScope appear nowhere in mcpx | n/a | new; changelog item 5 omits server/discover — C14 |
| caching-input-required-no-hints | 2026-07-28 | server | descr. | caching | “Interim results with resultType: "input_required" … are not cacheable and carry no caching hints.” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/caching#cacheable-results | yes | n/a | |
| caching-key-method-params | 2026-07-28 | client | MUST NOT | caching | “Clients MUST NOT serve a cached response for a request whose method or parameters differ from the request that produced it.” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/caching#cache-key | n/a | yes as far as seen (per-server list caches, invalidated on list_changed) | |
| caching-no-cache-mrtr-retries | 2026-07-28 | client | MUST NOT | caching | “requests carrying inputResponses or requestState—MUST NOT be cached” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/caching#cache-key | n/a | yes (only lists cached; resources/read retries not cached — unverified) | |
| caching-ttl-zero-stale | 2026-07-28 | client | SHOULD | caching | “If ttlMs is 0, the response SHOULD be considered immediately stale.” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/caching#time-to-live-ttl-field | n/a | no — ttlMs ignored; list cache lives until list_changed | |
| caching-ttl-positive-fresh | 2026-07-28 | client | SHOULD | caching | “If ttlMs is positive, the client SHOULD consider the result fresh for that many milliseconds after receiving the response.” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/caching#time-to-live-ttl-field | n/a | no | |
| caching-ttl-absent-zero | 2026-07-28 | client | SHOULD | caching | “If ttlMs is absent, clients SHOULD assume a default of 0 (immediately stale)” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/caching#time-to-live-ttl-field | n/a | no — legacy upstream lists are cached indefinitely | |
| caching-ttl-negative-zero | 2026-07-28 | client | SHOULD | caching | “If ttlMs is negative, clients SHOULD ignore it and treat it as 0.” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/caching#time-to-live-ttl-field | n/a | no | |
| caching-ttl-non-negative | 2026-07-28 | server | MUST | caching | “Servers MUST provide a ttlMs value that is >= 0.” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/caching#time-to-live-ttl-field | no (absent) | n/a | |
| caching-stale-refetch | 2026-07-28 | client | SHOULD | caching | “Once the TTL expires, the response is stale and the client SHOULD re-fetch on next access.” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/caching#freshness-calculation | n/a | no | |
| caching-ttl-not-poll | 2026-07-28 | client | SHOULD NOT / MUST | caching | “Clients SHOULD NOT treat TTL as a polling interval… Implementations that do choose to poll MUST apply jitter and backoff.” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/caching#freshness-calculation | n/a | yes (no TTL polling) | |
| caching-may-refetch-early-serve-stale | 2026-07-28 | client | MAY | caching | “Clients MAY re-fetch before the TTL expires…” “Clients MAY serve stale responses if errors occur during re-fetching” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/caching#freshness-calculation | n/a | yes (serves cache on error) | |
| caching-public-shareable | 2026-07-28 | both | MAY | caching | “"public" … Any client, shared gateway, or caching proxy MAY store and serve the cached response to any user.” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/caching#cache-scope-field | n/a | relevant — mcpx is a “shared gateway” | |
| caching-private-no-cross-auth | 2026-07-28 | both (any cache) | MUST NOT | caching | “Caches MUST NOT be shared across authorization contexts (e.g. a different access token requires a different cache).” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/caching#cache-scope-field | n/a | at risk — mcpx ignores cacheScope and re-serves an upstream’s cached lists/reads to every downstream client; safe only while each upstream sees one mcpx credential and every downstream is the same user | |
| caching-notification-invalidates | 2026-07-28 | client | descr. (lowercase should) | caching | “the notification invalidates the cached response and it should be considered immediately stale.” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/caching#interaction-with-notifications | n/a | yes (client.go:494-499 invalidate) — but modern upstreams only notify over subscriptions/listen, which mcpx never opens | |
| caching-page-refetch | 2026-07-28 | client | SHOULD | caching | “When a cached page expires, the client SHOULD re-fetch that page using its cursor.” / “…SHOULD re-fetch from the beginning (without a cursor).” / “If a cursor becomes invalid … SHOULD discard all cached pages and re-fetch from the beginning.” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/caching#interaction-with-pagination | n/a | partial — always re-fetches whole list | |
| caching-page-same-scope | 2026-07-28 | server | MUST | caching | “Servers MUST apply the same cacheScope to all response pages for a given list request.” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/caching#interaction-with-pagination | no (absent) | n/a | |
| caching-server-access-control | 2026-07-28 | server | MUST* / MUST NOT* | caching | “Servers MUST be aware that responses with a "public" cacheScope may be shared…” “MUST apply appropriate per-primitive access controls, and MUST NOT rely on cacheScope alone to prevent unauthorized access to primitives.” | https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/caching#security-considerations | n/a until hints are emitted; mcpx has no per-primitive access control (see authorization area) | n/a | |
| mrtr-server-requests-via-mrtr | 2026-07-28 | server | MUST | mrtr | “Servers MUST send server-to-client requests (such as roots/list, sampling/createMessage, or elicitation/create) using the MRTR pattern. The previous pattern of server-initiated requests is no longer supported.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/mrtr | yes for modern clients (mcpserver/ask.go:262); legacy clients get wire requests, correctly | n/a | legal→forbidden — C2 |
| mrtr-requeststate-opaque-client | 2026-07-28 | client | MUST NOT | mrtr | “Clients MUST NOT inspect, parse, modify, or make any assumptions about its contents.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/mrtr#inputrequiredresult | n/a | yes (mcpclient/modern.go:144-186 copies bytes) | |
| mrtr-supported-requests-only | 2026-07-28 | server | MAY / MUST NOT | mrtr | “Servers MAY send InputRequiredResult responses on the following client requests: prompts/get, resources/read, tools/call” “Servers MUST NOT send InputRequiredResult responses on any other client requests.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/mrtr#supported-requests | yes (only tools/call) | should reject/ignore on others — unverified | |
| mrtr-inputrequests-keys-values | 2026-07-28 | server | MUST | mrtr | “inputRequests keys … MUST be unique within the scope of the request.” “values are request objects that MUST be one of ElicitRequest, CreateMessageRequest, or ListRootsRequest” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/mrtr#server-requirements-basic-workflow | yes | n/a | |
| mrtr-requeststate-attacker-controlled | 2026-07-28 | server | MUST | mrtr | “servers MUST treat requestState as an attacker-controlled input. If requestState influences authorization, resource access, or business logic, servers MUST protect its integrity (e.g. HMAC or AEAD) and MUST reject state that fails verification.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/mrtr#server-requirements-basic-workflow | yes — HMAC-SHA256, per-process key (mcpserver/state.go) | n/a | |
| mrtr-requeststate-replay-fields | 2026-07-28 | server | SHOULD | mrtr | “servers SHOULD include … the authenticated principal …; a short expiry (TTL) …; an identifier for the originating request, e.g. the method name and a digest of its salient parameters” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/mrtr#server-requirements-basic-workflow | partial — connection id (no principal exists), expiry, call id; no method/params digest | n/a | |
| mrtr-single-use-enforced | 2026-07-28 | server | MUST | mrtr | “Servers for which a given requestState must be consumed at most once … MUST enforce that invariant server-side.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/mrtr#server-requirements-basic-workflow | unverified whether a resumed call id can be resumed twice | n/a | |
| mrtr-at-least-one-field | 2026-07-28 | server | MUST | mrtr | “Servers MUST include at least one of inputRequests or requestState in every InputRequiredResult response.” (schema same) | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/mrtr#server-requirements-basic-workflow | yes | n/a | |
| mrtr-only-declared-capabilities | 2026-07-28 | server | MUST NOT | mrtr | “Servers MUST NOT send an inputRequests that the client has not declared support for in its capabilities.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/mrtr#server-requirements-basic-workflow | yes (per-request caps, docs/protocol.md §3.1) | n/a | |
| mrtr-no-assume-retry | 2026-07-28 | server | MUST NOT / MAY | mrtr | “Servers MUST NOT assume that clients will fulfill the inputRequests or retry the original request. Servers MAY choose to return an InputRequiredResult on multiple attempts” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/mrtr#server-requirements-basic-workflow | yes (proto.askTTL, askRounds) | n/a | |
| mrtr-client-fulfil-before-retry | 2026-07-28 | client | MUST / MAY | mrtr | “the client MUST construct the requested inputs before retrying the original request. If the InputRequiredResult does not contain the inputRequests field, the client MAY retry the original request immediately.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/mrtr#client-requirements-basic-workflow | n/a | yes | |
| mrtr-client-echo-state | 2026-07-28 | client | MUST / MUST NOT | mrtr | “the client MUST echo back the exact value of that field when retrying … If the InputRequiredResult does not contain a requestState field, the client MUST NOT include one in the retry.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/mrtr#client-requirements-basic-workflow | n/a | yes (modern.go:172-186) | |
| mrtr-new-id-on-retry | 2026-07-28 | client | MUST | mrtr | “The JSON-RPC id MUST be different between the initial request and the retry” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/mrtr#client-requirements-basic-workflow | n/a | yes (fresh id per round trip) | |
| mrtr-no-cross-request-use | 2026-07-28 | client | MUST NOT | mrtr | “They MUST NOT be used for any other request that the client may be sending in parallel.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/mrtr#client-requirements-basic-workflow | n/a | yes | |
| mrtr-server-validate-responses | 2026-07-28 | server | SHOULD | mrtr | “Servers SHOULD validate that the data provided by the client is a valid InputResponses object” / “…SHOULD ignore any information it does not recognize” / “…SHOULD respond with a new InputRequiredResult requesting the missing information again, rather than returning an error.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/mrtr#error-handling | unverified | n/a | |
| subscriptions-list-changed-should-notify | 2024-11-05..2025-11-25 | server | SHOULD | subscriptions | “When the list of available resources changes, servers that declared the listChanged capability SHOULD send a notification” (same for tools, prompts) | https://modelcontextprotocol.io/specification/2025-11-25/server/resources#list-changed-notification | partial — declared only when the connection can push (server.go:1389-1403); unverified that a legacy connection receives list_changed without a listen stream (restartListen is only called from listen/subscribe) | yes — consumes and invalidates | delivered unsolicited ≤2025-11-25; only via listen in 2026 |
| subscriptions-list-changed-via-listen | 2026-07-28 | server | SHOULD | subscriptions | “capability SHOULD send a notification to clients that have opened a subscriptions/listen stream with…” | https://modelcontextprotocol.io/specification/2026-07-28/server/tools#list-changed-notification | partial (envelope wrong, see below) | not-implemented — mcpx never opens subscriptions/listen upstream | |
| subscriptions-resources-updated-only-if-subscribed | 2024-11-05..2025-11-25 | server | should (schema) | subscriptions | schema: “This should only be sent if the client previously sent a resources/subscribe request.” | https://modelcontextprotocol.io/specification/2025-11-25/schema#resourceupdatednotification | yes | yes — sends resources/subscribe (client.go:532-542) | resources/subscribe removed 2026 (changelog 4) |
| subscriptions-only-requested-types | 2026-07-28 | server | MUST NOT | subscriptions | “The server MUST NOT send notification types the client has not explicitly requested.” (schema SubscriptionFilter, SubscriptionsListenRequestParams same) | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/subscriptions#opening-a-stream | yes (cli/serve.go:726-742) — but legacy resources/subscribe calls restartListen with a URI-only filter, dropping any list-changed kinds the same connection had | n/a | |
| subscriptions-ack-first-with-id | 2026-07-28 | server | MUST / MUST NOT | subscriptions | “The server MUST send notifications/subscriptions/acknowledged as the first message carrying the subscription’s ID in _meta under io.modelcontextprotocol/subscriptionId, and MUST NOT send any notification on the subscription before it.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/subscriptions#acknowledgment | no — id placed in params.subscriptionId, not _meta (server.go:637-639); ack is pushed after restartListen starts the goroutine, so a first event can race ahead of it | n/a | new |
| subscriptions-stdio-ack-order-per-id | 2026-07-28 | server | MAY | subscriptions | “On stdio … this ordering is defined per subscription ID and not per channel: messages belonging to other subscriptions MAY be interleaved before it.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/subscriptions#acknowledgment | n/a | n/a | |
| subscriptions-ack-reports-agreed-subset | 2026-07-28 | server | descr. (schema-required field) | subscriptions | “The notifications field in the acknowledgment reflects the subset the server agreed to honor. Notification types the server does not support are omitted.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/subscriptions#acknowledgment | no — notifications (required in SubscriptionsAcknowledgedNotificationParams) is omitted | n/a | |
| subscriptions-client-check-ack | 2026-07-28 | client | SHOULD | subscriptions | “The client SHOULD check the acknowledged filter against what it requested and handle any unsupported types gracefully.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/subscriptions#acknowledgment | n/a | not-implemented | |
| subscriptions-tag-every-notification | 2026-07-28 | server | MUST | subscriptions | basic/index: “On notifications delivered via a subscriptions/listen stream, the server MUST include io.modelcontextprotocol/subscriptionId in _meta”; schema NotificationMetaObject: “server MUST include this key on every notification delivered via a subscriptions/listen stream” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#meta | no — no code writes io.modelcontextprotocol/subscriptionId | n/a | subscriptions page itself only says “carry” (no keyword) |
| subscriptions-stdio-client-correlate | 2026-07-28 | client | MUST | subscriptions | “On stdio, where all messages share a single channel, clients MUST use this field to correlate notifications with their originating subscription.” (stdio.mdx repeats) | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/subscriptions#receiving-notifications | n/a | not-implemented (no listen upstream) | |
| subscriptions-multiple-concurrent | 2026-07-28 | client | MAY | subscriptions | “A client MAY have multiple active subscriptions concurrently … Each subscription is identified by the JSON-RPC request ID of its subscriptions/listen request” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/subscriptions#multiple-concurrent-subscriptions | no — one stream per Conn; a second listen silently replaces the first (server.go:1421-1444), and the first listen request is never answered or cancelled | n/a | |
| subscriptions-server-teardown-respond | 2026-07-28 | server | SHOULD | subscriptions | “The server tears it down (e.g., during shutdown) — it SHOULD send a successful subscriptions/listen response to signal a graceful end … then close the stream.” / Graceful Closure: “it SHOULD respond to the original subscriptions/listen request with a completion result before closing the stream.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/subscriptions#graceful-closure | no — listen handler returns nil and nothing ever answers it (server.go:640) | n/a | contradicts cancellation MUST — C1 |
| subscriptions-listen-result-meta | 2026-07-28 | server | schema-required | subscriptions | schema SubscriptionsListenResult { _meta: SubscriptionsListenResultMetaObject } — “io.modelcontextprotocol/subscriptionId: RequestId” (required), “equals this response’s id” | https://modelcontextprotocol.io/specification/2026-07-28/schema#subscriptionslistenresult | no (no response) | n/a | |
| subscriptions-client-reconnect-on-drop | 2026-07-28 | client | MAY | subscriptions | “a transport that closes without it indicates an unexpected disconnect, which the client MAY treat as a trigger to reconnect.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/subscriptions#graceful-closure | n/a | n/a | |
| subscriptions-stdio-resubscribe | 2026-07-28 | client | MUST | subscriptions | “On stdio, if the connection is terminated and then re-established, the client MUST re-send subscriptions/listen … — the server holds no subscription state across reconnections.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/subscriptions#graceful-closure | yes (state dies with Conn) | n/a | |
| subscriptions-request-scoped-not-on-listen | 2026-07-28 | server | descr. (bold “not”) | subscriptions | “Request-scoped notifications like notifications/progress and notifications/message are not delivered on the listen stream — they flow only on the response stream of the request they relate to.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#receiving-messages | yes (vacuous) | n/a |
Tools, resources, prompts, discover
| id | revs | side | level | area | quote | url | mcpx-as-server | mcpx-as-client | changes |
|---|---|---|---|---|---|---|---|---|---|
| tools-human-in-loop-deny | 2024-11-05 – 2026-07-28 | client | SHOULD | tools | “there SHOULD always be a human in the loop with the ability to deny tool invocations” | 2026-07-28/server/tools#user-interaction-model | no — host-application duty; mcpx is not the host | not-implemented-by-choice — mcpx is not the UI; elicitation broker is the only human channel | |
| tools-ui-expose-indicate-confirm | 2024-11-05 – 2026-07-28 | client | SHOULD | tools | “Applications SHOULD: Provide UI that makes clear which tools are being exposed… Insert clear visual indicators… Present confirmation prompts” | 2026-07-28/server/tools#user-interaction-model | no — host duty | not-implemented-by-choice — no UI in the proxy path | |
| tools-declare-capability | 2024-11-05 – 2026-07-28 | server | MUST | tools | “Servers that support tools MUST declare the tools capability” | 2026-07-28/server/tools#capabilities | yes — declared all revs (protocol.md §2.2) | no (server obligation); mcpx relies on it | where declared changes: initialize (legacy) vs DiscoverResult (2026); tools page doesn’t say where |
| tools-list-changed-means-emit | 2024-11-05 – 2026-07-28 | server | (definition) | tools | “listChanged indicates whether the server will emit notifications when the list of available tools changes” | 2026-07-28/server/tools#capabilities | yes — declared only when a notifier exists (§2.2) | yes — should only expect notifications when declared | |
| tools-list-changed-notify | 2024-11-05 – 2025-11-25 | server | SHOULD | tools | “servers that declared the listChanged capability SHOULD send a notification” | 2025-11-25/server/tools#list-changed-notification | yes | no | changed in 2026 (only to listen streams) |
| tools-list-changed-notify-to-listeners | 2026-07-28 | server | SHOULD | tools | “SHOULD send a notification to clients that have opened a subscriptions/listen stream with toolsListChanged: true” | 2026-07-28/server/tools#list-changed-notification | yes — “only the four notification kinds the filter names” | yes — must open listen with toolsListChanged to receive | CHANGED: legacy sends on session; 2026 only on opted-in stream |
| tools-list-must-respond-when-declared | 2026-07-28 | server | MUST | tools | “Servers that declare the tools capability MUST respond to tools/list requests with the set of tools currently available to the requesting client” | 2026-07-28/server/tools#capabilities | yes | no | new in 2026 (implicit before) |
| tools-list-not-per-connection | 2026-07-28 | server | MUST NOT | tools | “MUST NOT vary per-connection or as a side effect of other requests on the connection” | 2026-07-28/server/tools#capabilities | yes — must hold; check: mcpx Conn state (subscriptions, caps) must not filter the list | no | CHANGED: legacy servers could legitimately vary per session |
| tools-list-may-vary-by-auth | 2026-07-28 | server | MAY | tools | “The set MAY vary by the authorization presented on the request” | 2026-07-28/server/tools#capabilities | not-implemented-by-choice — mcpx does no auth | no | new |
| tools-list-may-be-empty-change | 2026-07-28 | server | MAY | tools | “This set MAY be empty and MAY change over time” | 2026-07-28/server/tools#capabilities | yes | yes — tolerate empty lists | |
| tools-list-deterministic-order | 2026-07-28 | server | SHOULD | tools | “Servers SHOULD return tools in a deterministic order” | 2026-07-28/server/tools#capabilities | yes — must verify s.Tools() ordering is stable (pagination via opaque cursor depends on it anyway) | no | new (changelog “Minor” #3) |
| tools-annotations-untrusted | 2025-03-26 – 2026-07-28 | client | MUST | tools | “clients MUST consider tool annotations to be untrusted unless they come from trusted servers” | 2026-07-28/server/tools#tool | yes — mcpx forwards upstream annotations; downstream must treat them as upstream’s, mcpx must not launder trust | yes — mcpx must not act on upstream annotations | new in 2025-03-26 (annotations added) |
| tools-annotations-hints-no-decisions | 2025-03-26 – 2026-07-28 | client | should (lowercase, schema) | tools | “Clients should never make tool use decisions based on ToolAnnotations received from untrusted servers.” | 2026-07-28/schema#toolannotations | n/a | yes | schema-only, lowercase |
| tools-inputschema-valid-not-null | 2025-11-25 – 2026-07-28 | server | MUST | tools / json-schema | “MUST be a valid JSON Schema object (not null)” | 2026-07-28/server/tools#tool | yes — generated ops must emit object schemas, forwarded ones should be checked | yes — tolerate/flag invalid upstream | explicit from 2025-11-25; schema required type:"object" since 2024-11-05 |
| tools-inputschema-type-object-root | 2024-11-05 – 2026-07-28 | server | REQUIRED (schema) | tools / json-schema | “Tool arguments are always JSON objects, so type: \"object\" is required at the root.” | 2026-07-28/schema#tool | yes | yes | 2026 comment adds “any JSON Schema 2020-12 keyword may appear”; earlier schemas only allowed properties/required shape |
| tools-inputschema-no-params-recommended | 2025-11-25 – 2026-07-28 | server | RECOMMENDED | tools | “{ \"type\": \"object\", \"additionalProperties\": false } - Recommended” | 2026-07-28/server/tools#tool | yes | no | |
| tools-schema-default-2020-12 | 2025-11-25 – 2026-07-28 | both | (definition) | json-schema | “Defaults to 2020-12 if no $schema field is present” | 2026-07-28/server/tools#tool | yes | yes | 2025-11-25 is when $schema/dialects arrive |
| tools-x-mcp-header-may | 2026-07-28 | server | MAY | tools | “Properties MAY include an x-mcp-header annotation to expose parameter values as HTTP headers” | 2026-07-28/server/tools#tool | not-implemented-by-choice — mcpx-generated tools need none; forwarded upstream schemas may carry it | yes — must handle when upstream declares it | new |
| tools-x-mcp-header-not-empty | 2026-07-28 | server | MUST NOT | tools | “MUST NOT be empty” | 2026-07-28/server/tools#x-mcp-header | yes if forwarding upstream schemas verbatim | yes (validation side, see reject row) | new |
| tools-x-mcp-header-tchar | 2026-07-28 | server | MUST | tools | “MUST match HTTP field-name token syntax (1*tchar…)” | 2026-07-28/server/tools#x-mcp-header | same | same | new |
| tools-x-mcp-header-no-ctl | 2026-07-28 | server | MUST NOT | tools | “MUST NOT contain control characters, including carriage return… or line feed” | 2026-07-28/server/tools#x-mcp-header | same | same | new |
| tools-x-mcp-header-unique-ci | 2026-07-28 | server | MUST | tools | “MUST be case-insensitively unique among all x-mcp-header values in the inputSchema” | 2026-07-28/server/tools#x-mcp-header | same | same | new |
| tools-x-mcp-header-primitive-only | 2026-07-28 | server | MUST | tools | “MUST only be applied to parameters with primitive types (integer, string, boolean). Parameters with type number are not permitted.” | 2026-07-28/server/tools#x-mcp-header | same | same | new |
| tools-x-mcp-header-int-safe-range | 2026-07-28 | server | MUST | tools | “Integer values MUST be within the safe range for integers represented using IEEE754 double-precision” | 2026-07-28/server/tools#x-mcp-header | same | same | new |
| tools-x-mcp-header-statically-reachable | 2026-07-28 | server | MUST | tools | “MUST only be applied to properties that are statically reachable from the schema root” | 2026-07-28/server/tools#x-mcp-header | same | same | new |
| tools-x-mcp-header-reject-excludes | 2026-07-28 | client | MUST | tools | “Rejection means the client MUST exclude the invalid tool from the result of tools/list” | 2026-07-28/server/tools#x-mcp-header | no | yes — excluded from what mcpx re-exposes too | new |
| tools-x-mcp-header-reject-log | 2026-07-28 | client | SHOULD | tools | “Clients SHOULD log a warning when rejecting a tool definition, including the tool name and the reason” | 2026-07-28/server/tools#x-mcp-header | no | yes | new |
| tools-x-mcp-header-stdio-may-ignore | 2026-07-28 | client | MAY | tools | “Clients using other transports (e.g., stdio) MAY ignore x-mcp-header annotations entirely” | 2026-07-28/server/tools#x-mcp-header | no | yes — stdio upstreams | new |
| tools-x-mcp-header-no-secrets | 2026-07-28 | server | SHOULD NOT | tools | “Server developers SHOULD NOT mark sensitive parameters (passwords, API keys, tokens, PII) with x-mcp-header” | 2026-07-28/server/tools#x-mcp-header | yes (own tools) | no | new |
| tools-name-length | 2025-11-25 – 2026-07-28 | server | SHOULD | tools | “Tool names SHOULD be between 1 and 128 characters in length (inclusive).” | 2026-07-28/server/tools#tool-names | yes — namespaced names (server+tool) can exceed 128; check | no (tolerate) | new 2025-11-25 (SEP-986) |
| tools-name-case-sensitive | 2025-11-25 – 2026-07-28 | both | SHOULD | tools | “Tool names SHOULD be considered case-sensitive.” | 2026-07-28/server/tools#tool-names | yes | yes | new 2025-11-25 |
| tools-name-charset | 2025-11-25 – 2026-07-28 | server | SHOULD | tools | “The following SHOULD be the only allowed characters: uppercase and lowercase ASCII letters (A-Z, a-z), digits (0-9), underscore (_), hyphen (-), and dot (.)” | 2026-07-28/server/tools#tool-names | yes — namespacing separator must be one of _ - . | yes — upstream names outside charset must be tolerated/mapped | new 2025-11-25 |
| tools-name-no-special | 2025-11-25 – 2026-07-28 | server | SHOULD NOT | tools | “Tool names SHOULD NOT contain spaces, commas, or other special characters.” | 2026-07-28/server/tools#tool-names | yes | no | new |
| tools-name-unique-in-server | 2025-11-25 – 2026-07-28 | server | SHOULD | tools | “Tool names SHOULD be unique within a server.” | 2026-07-28/server/tools#tool-names | yes — mcpx is one server to its client; aggregated names must be unique | no | new |
| tools-aggregator-disambiguate | 2026-07-28 | client | SHOULD | tools | “Clients or proxies that aggregate tools from multiple servers… SHOULD implement a disambiguation strategy such as prefixing tool names with a server identifier.” | 2026-07-28/server/tools#tool-names | yes — addressed at mcpx by name (“proxies”) | yes | new; applies in spirit to all revs |
| tools-aggregator-not-by-servername | 2026-07-28 | client | SHOULD NOT | tools | “The server name (from serverInfo) is not guaranteed to be unique across servers and SHOULD NOT be relied upon for disambiguation.” | 2026-07-28/server/tools#tool-names | yes — prefix with mcpx’s config key, not upstream serverInfo.name | yes | new |
| tools-call-input-required-may | 2026-07-28 | server | MAY | tools / mrtr | “Servers MAY respond to tools/call with an InputRequiredResult” | 2026-07-28/server/tools#input-required-tool-results | yes — viaAsk (§3.3) | yes — must resolve and retry | new |
| tools-call-inputrequests-declared-only | 2026-07-28 | server | MUST NOT | tools / mrtr | “Servers MUST NOT send an inputRequests that the client has not declared support for in its capabilities.” (mrtr.mdx) | 2026-07-28/basic/patterns/mrtr | yes — §3.1 table enforces it | no | new; cross-page, affects tools/call, prompts/get, resources/read |
| tools-result-iserror-for-tool-errors | 2024-11-05 – 2026-07-28 | server | SHOULD | tools | “Any errors that originate from the tool SHOULD be reported inside the result object, with isError set to true, not as an MCP protocol-level error response.” | 2026-07-28/schema#calltoolresult | yes — server.go tools/call returns isError | yes — forwards upstream isError unchanged | schema comment, unchanged |
| tools-result-lookup-errors-protocol | 2024-11-05 – 2026-07-28 | server | should (lowercase) | tools | “any errors in finding the tool… should be reported as an MCP error response” | 2026-07-28/schema#calltoolresult | yes — an unknown tool is -32602 (internal/mcpserver/server.go no tool named, #284); tested, see conformance-matrix.md | yes | |
| tools-error-unknown-tool-protocol | 2024-11-05 – 2026-07-28 | server | (classification) | tools | “Protocol Errors … Unknown tool” ; example code -32602 | 2026-07-28/server/tools#error-handling | yes (as above); tested, see conformance-matrix.md | yes | |
| tools-error-invalid-args-protocol | 2024-11-05 – 2025-06-18 | server | (classification) | tools | “Protocol Errors: Standard JSON-RPC errors for issues like: … Invalid arguments” | 2025-06-18/server/tools#error-handling | yes — mcpx returns isError for dispatch failures, which the later rule prefers; acceptable to legacy clients | yes | CHANGED in 2025-11-25 |
| tools-error-input-validation-execution | 2025-11-25 – 2026-07-28 | server | (classification) | tools | “Tool Execution Errors … Input validation errors (e.g., date in wrong format, value out of range)”; only “Malformed requests (requests that fail to satisfy CallToolRequest schema)” stay protocol errors | 2026-07-28/server/tools#error-handling | yes | yes | CHANGED from “Invalid arguments” (SEP-1303) |
| tools-client-exec-errors-to-llm | 2025-11-25 – 2026-07-28 | client | SHOULD | tools | “Clients SHOULD provide tool execution errors to language models to enable self-correction.” | 2026-07-28/server/tools#error-handling | no | yes — must pass isError results through, not convert to protocol errors | new 2025-11-25 |
| tools-client-protocol-errors-to-llm-may | 2025-11-25 – 2026-07-28 | client | MAY | tools | “Clients MAY provide protocol errors to language models” | 2026-07-28/server/tools#error-handling | no | yes | new |
| tools-embedded-resource-may | 2024-11-05 – 2026-07-28 | server | MAY | tools | “Resources MAY be embedded” | 2026-07-28/server/tools#embedded-resources | yes — resource_link→resource downgrade (§2.3) | yes | |
| tools-embedded-implies-resources-cap | 2025-06-18 – 2026-07-28 | server | SHOULD | tools | “Servers that use embedded resources SHOULD implement the resources capability” | 2026-07-28/server/tools#embedded-resources | yes — declared; but downgraded links become embedded resources whose URIs are upstream’s, not readable via mcpx unless proxied | no | new 2025-06-18 |
| tools-resource-link-may | 2025-06-18 – 2026-07-28 | server | MAY | tools | “A tool MAY return links to Resources” | 2026-07-28/server/tools#resource-links | yes (≥2025-06-18); downgraded for 2025-03-26 | yes | new 2025-06-18 |
| tools-resource-link-may-not-listed | 2025-06-18 – 2026-07-28 | both | (note) | tools | “Resource links returned by tools are not guaranteed to appear in the results of a resources/list request.” | 2026-07-28/server/tools#resource-links | yes | yes | |
| tools-structured-also-text | 2025-06-18 – 2026-07-28 | server | SHOULD | tools | “For backwards compatibility, a tool that returns structured content SHOULD also return the serialized JSON in a TextContent block.” | 2026-07-28/server/tools#structured-content | yes — and for 2025-03-26 structuredContent removed + rendered (§2.3) | no | new 2025-06-18 |
| tools-structured-any-json | 2026-07-28 | server | (type) | tools | “This can be any JSON value (object, array, string, number, boolean, or null)” | 2026-07-28/server/tools#structured-content | yes — must NOT send non-object structuredContent to 2025-06-18/2025-11-25 clients | yes — accept any JSON from modern upstream | CHANGED: 2025-06-18/11-25 schema { [key: string]: unknown } (object only) |
| tools-structured-object-only | 2025-06-18 – 2025-11-25 | server | (type, schema) | tools | “structuredContent?: { [key: string]: unknown };” | 2025-11-25/schema#calltoolresult | yes — downgrade must wrap/strip non-object values | yes | CHANGED in 2026 |
| tools-output-schema-conform | 2025-06-18 – 2026-07-28 | server | MUST | tools | “Servers MUST provide structured results that conform to this schema.” | 2026-07-28/server/tools#output-schema | yes — for forwarded tools mcpx passes upstream’s; if it rewrites structuredContent it must still conform | no | |
| tools-output-schema-client-validate | 2025-06-18 – 2026-07-28 | client | SHOULD | tools | “Clients SHOULD validate structured results against this schema.” | 2026-07-28/server/tools#output-schema | no | yes — not-implemented-by-choice likely; pass-through | |
| tools-output-schema-object-root | 2025-06-18 – 2025-11-25 | server | (type, schema) | tools | “Currently restricted to type: "object" at the root level.” | 2025-11-25/schema#tool | yes — must not forward non-object outputSchema to legacy clients | yes | CHANGED in 2026: “This can be any valid JSON Schema 2020-12.” |
| tools-display-name-precedence | 2025-06-18 – 2026-07-28 | client | (rule) | tools | “Display name precedence order is: title, annotations.title, then name.” | 2026-07-28/schema#tool | yes | yes | |
| tools-server-sec-validate-inputs | 2024-11-05 – 2026-07-28 | server | MUST | tools | “Servers MUST: Validate all tool inputs; Implement proper access controls; Rate limit tool invocations; Sanitize tool outputs” | 2026-07-28/server/tools#security-considerations | yes — rate limiting / access control: not-implemented-by-choice (loopback, no auth, protocol.md §5) | no | |
| tools-client-sec | 2024-11-05 – 2025-11-25 | client | SHOULD | tools | “Clients SHOULD: Prompt for user confirmation…; Show tool inputs…; Validate tool results before passing to LLM; Implement timeouts for tool calls; Log tool usage for audit purposes” | 2025-11-25/server/tools#security-considerations | no | yes — timeouts + logging (logstore) yes; confirmation not-implemented-by-choice | |
| tools-client-sec-ref-resolution | 2026-07-28 | client | SHOULD | tools / json-schema | “Follow the $ref resolution requirements when validating tool inputs and outputs” | 2026-07-28/server/tools#security-considerations | no | yes if validating; otherwise n/a | added 2026 |
| resources-declare-capability | 2024-11-05 – 2026-07-28 | server | MUST | resources | “Servers that support resources MUST declare the resources capability” | 2026-07-28/server/resources#capabilities | yes | no | |
| resources-subscribe-cap-meaning-legacy | 2024-11-05 – 2025-11-25 | server | (definition) | resources | “subscribe: whether the client can subscribe to be notified of changes to individual resources.” | 2025-11-25/server/resources#capabilities | yes — declared | yes — call resources/subscribe only if declared | CHANGED meaning 2026 |
| resources-subscribe-cap-meaning-2026 | 2026-07-28 | server | (definition) | resources | “subscribe : whether the server supports resource-specific update notifications for resources requested through subscriptions/listen using the resourceSubscriptions filter.” | 2026-07-28/server/resources#capabilities | yes | yes — only send resourceSubscriptions if declared | CHANGED |
| resources-cap-features-independent | 2024-11-05 – 2026-07-28 | server | MAY | resources | “Servers may advertise either feature independently, together or neither.” / “Servers that support neither… may omit it” | 2026-07-28/server/resources#capabilities | yes | yes — resources: {} is valid | |
| resources-list-must-respond-when-declared | 2026-07-28 | server | MUST | resources | “Servers that declare the resources capability MUST respond to resources/list requests with the set of resources currently available to the requesting client.” | 2026-07-28/server/resources#capabilities | yes — returns [] when no backend | no | new |
| resources-list-not-per-connection | 2026-07-28 | server | MUST NOT | resources | “MUST NOT vary per-connection or as a side effect of other requests on the connection” | 2026-07-28/server/resources#capabilities | yes | no | CHANGED (new constraint) |
| resources-list-may-vary-by-auth | 2026-07-28 | server | MAY | resources | “The set MAY vary by the authorization presented on the request” | 2026-07-28/server/resources#capabilities | not-implemented-by-choice — no auth | no | new |
| resources-list-changed-notify | 2024-11-05 – 2026-07-28 | server | SHOULD | resources | “servers that declared the listChanged capability SHOULD send a notification” | 2026-07-28/server/resources#list-changed-notification | yes | yes | text unchanged in 2026 but see Conflicts C3 |
| resources-read-multiple-may | 2026-07-28 | server | MAY | resources | “Servers MAY return multiple resource contents in response to a single resources/read request.” | 2026-07-28/server/resources#reading-resources | yes (single today) | yes — must accept arrays of >1 | explicit only in 2026; schema always allowed an array |
| resources-read-input-required-may | 2026-07-28 | server | MAY | resources / mrtr | “Servers MAY also respond to resources/read with an InputRequiredResult” | 2026-07-28/server/resources#reading-resources | yes — viaAsk | yes | new |
| resources-read-https-direct-may | 2026-07-28 | client | may (lowercase) | resources | “if the scheme of uri is https://, clients may fetch the resource directly from the web” | 2026-07-28/server/resources#reading-resources | no | not-implemented-by-choice | new in 2026 prose |
| resources-subscribe-rpc | 2024-11-05 – 2025-11-25 | client | (optional) | resources / subscriptions | “The protocol supports optional subscriptions to resource changes. Clients can subscribe to specific resources” (resources/subscribe) | 2025-11-25/server/resources#subscriptions | yes — accepted in any era (protocol.md §2.1) | yes — legacy upstreams | REMOVED in 2026 |
| resources-unsubscribe-follows-subscribe | 2024-11-05 – 2025-11-25 | client | should (lowercase, schema) | resources / subscriptions | “This should follow a previous resources/subscribe request.” | 2025-11-25/schema#unsubscriberequest | yes | yes | removed 2026 |
| resources-subscribe-via-listen | 2026-07-28 | client | (mechanism) | resources / subscriptions | “Clients subscribe to change notifications for specific resources by sending a subscriptions/listen request with the resource URIs listed in notifications.resourceSubscriptions.” | 2026-07-28/server/resources#subscriptions | yes — any era | yes — modern upstreams | CHANGED: replaces resources/subscribe |
| resources-updated-may-be-subresource | 2024-11-05 – 2026-07-28 | client | (note, schema) | resources | “This might be a sub-resource of the one that the client actually subscribed to.” | 2026-07-28/schema#resourceupdatednotification | yes — fan-out must match by prefix/subresource, not equality | yes | |
| resources-https-only-if-client-fetchable | 2024-11-05 – 2026-07-28 | server | SHOULD | resources | “Servers SHOULD use this scheme only when the client is able to fetch and load the resource directly from the web on its own” | 2026-07-28/server/resources#https | yes | no | |
| resources-https-else-other-scheme | 2024-11-05 – 2026-07-28 | server | SHOULD | resources | “servers SHOULD prefer to use another URI scheme, or define a custom one” | 2026-07-28/server/resources#https | yes | no | |
| resources-file-xdg-mime-may | 2024-11-05 – 2026-07-28 | server | MAY | resources | “MCP servers MAY identify file:// resources with an XDG MIME type, like inode/directory” | 2026-07-28/server/resources#file | yes | yes — accept | |
| resources-custom-scheme-rfc3986 | 2025-06-18 – 2026-07-28 | server | MUST | resources | “Custom URI schemes MUST be in accordance with RFC3986” | 2026-07-28/server/resources#custom-uri-schemes | yes — any mcpx-minted URIs (namespacing upstream URIs) must stay RFC3986 | no | new 2025-06-18 |
| resources-not-found-32002 | 2024-11-05 – 2025-11-25 | server | SHOULD | resources / errors | “Servers SHOULD return standard JSON-RPC errors for common failure cases: Resource not found: -32002” | 2025-11-25/server/resources#error-handling | yes — -32002 with data.uri through 2025-11-25, -32602 in 2026-07-28 (codeResourceNotFoundLegacy); tested, see conformance-matrix.md | yes — accept -32002 | CHANGED 2026 |
| resources-internal-32603 | 2024-11-05 – 2026-07-28 | server | SHOULD | resources / errors | “Internal errors: -32603” / “Servers SHOULD return -32603 for internal errors.” | 2026-07-28/server/resources#error-handling | yes — backend read failures are -32603 (codeInternal); tested, see conformance-matrix.md | yes | |
| resources-not-found-32602 | 2026-07-28 | server | MUST | resources / errors | “If the requested resource does not exist, servers MUST return a JSON-RPC error with code -32602 (Invalid Params).” | 2026-07-28/server/resources#error-handling | yes | yes | CHANGED from SHOULD -32002 |
| resources-client-accept-32002 | 2026-07-28 | client | SHOULD | resources / errors | “clients SHOULD also accept -32002 as a resource not found error” | 2026-07-28/server/resources#error-handling | no | yes — legacy upstreams | new |
| resources-no-empty-contents-for-missing | 2026-07-28 | server | MUST NOT | resources | “Servers MUST NOT return an empty contents array for a non-existent resource.” | 2026-07-28/server/resources#error-handling | yes | yes — treat empty as “exists, no content” | new (applies sensibly to all eras) |
| resources-sec-validate-uris | 2024-11-05 – 2026-07-28 | server | MUST | resources | “Servers MUST validate all resource URIs” | 2026-07-28/server/resources#security-considerations | yes | no | |
| resources-sec-access-control | 2024-11-05 – 2026-07-28 | server | SHOULD | resources | “Access controls SHOULD be implemented for sensitive resources” | 2026-07-28/server/resources#security-considerations | not-implemented-by-choice — no auth | no | |
| resources-sec-binary-encoded | 2024-11-05 – 2026-07-28 | server | MUST | resources | “Binary data MUST be properly encoded” | 2026-07-28/server/resources#security-considerations | yes — mcpx read path returns text only; blobs from upstream must be passed as base64 blob | yes | |
| resources-sec-permissions | 2024-11-05 – 2026-07-28 | server | SHOULD | resources | “Resource permissions SHOULD be checked before operations” | 2026-07-28/server/resources#security-considerations | not-implemented-by-choice | no | |
| resources-sec-file-traversal | 2026-07-28 | server | MUST | resources | “Servers MUST sanitize file paths to prevent directory traversal attacks when serving file:// resources” | 2026-07-28/server/resources#security-considerations | yes only if mcpx serves file:// itself; forwarding delegates to upstream | no | new |
| resources-annotations-defs | 2025-06-18 – 2026-07-28 | both | (definition) | resources | “priority: A number from 0.0 to 1.0”; “audience… Valid values are \"user\" and \"assistant\"”; “lastModified: An ISO 8601 formatted timestamp” | 2026-07-28/server/resources#annotations | yes — pass through | yes | lastModified new in 2025-06-18; audience/priority in schema since 2024-11-05 |
| prompts-declare-capability | 2024-11-05 – 2025-11-25 | server | MUST | prompts | “Servers that support prompts MUST declare the prompts capability during initialization” | 2025-11-25/server/prompts#capabilities | yes | no | CHANGED location |
| prompts-declare-capability-discover | 2026-07-28 | server | MUST | prompts | “Servers that support prompts MUST declare the prompts capability in their DiscoverResult” | 2026-07-28/server/prompts#capabilities | yes — but mcpx’s DiscoverResult field names are wrong (see discover rows) | no | CHANGED |
| prompts-list-must-respond-when-declared | 2026-07-28 | server | MUST | prompts | “Servers that declare the prompts capability MUST respond to prompts/list requests with the set of prompts currently available to the requesting client.” | 2026-07-28/server/prompts#capabilities | yes | no | new |
| prompts-list-not-per-connection | 2026-07-28 | server | MUST NOT | prompts | “MUST NOT vary per-connection or as a side effect of other requests on the connection” | 2026-07-28/server/prompts#capabilities | yes | no | new |
| prompts-list-may-vary-by-auth | 2026-07-28 | server | MAY | prompts | “The set MAY vary by the authorization presented on the request” | 2026-07-28/server/prompts#capabilities | not-implemented-by-choice | no | new |
| prompts-list-changed-notify | 2024-11-05 – 2025-11-25 | server | SHOULD | prompts | “servers that declared the listChanged capability SHOULD send a notification” | 2025-11-25/server/prompts#list-changed-notification | yes | yes | CHANGED 2026 |
| prompts-list-changed-notify-to-listeners | 2026-07-28 | server | SHOULD | prompts | “SHOULD send a notification to clients that have opened a subscriptions/listen stream with promptsListChanged: true” | 2026-07-28/server/prompts#list-changed-notification | yes | yes | CHANGED |
| prompts-get-input-required-may | 2026-07-28 | server | MAY | prompts / mrtr | “Servers MAY also respond to prompts/get with an InputRequiredResult” | 2026-07-28/server/prompts#getting-a-prompt | yes — viaAsk | yes | new |
| prompts-image-base64-mime | 2024-11-05 – 2026-07-28 | server | MUST | prompts | “The image data MUST be base64-encoded and include a valid MIME type.” | 2026-07-28/server/prompts#image-content | yes (forwarded) | yes | |
| prompts-audio-base64-mime | 2025-03-26 – 2026-07-28 | server | MUST (not bolded) | prompts | “The audio data MUST be base64-encoded and include a valid MIME type.” | 2026-07-28/server/prompts#audio-content | yes | yes | new 2025-03-26 |
| prompts-resource-link-may | 2026-07-28 | server | MAY | prompts | “Prompt messages MAY include links to Resources” | 2026-07-28/server/prompts#resource-links | yes | yes | prose new in 2026; see Conflicts C9 |
| prompts-embedded-must-include | 2024-11-05 – 2026-07-28 | server | MUST | prompts | “Resources can contain either text or binary (blob) data and MUST include: A valid resource URI; The appropriate MIME type; Either text content or base64-encoded blob data” | 2026-07-28/server/prompts#embedded-resources | yes | yes | see Conflicts C8 (schema: mimeType optional) |
| prompts-errors-32602-32603 | 2024-11-05 – 2026-07-28 | server | SHOULD | prompts / errors | “Invalid prompt name: -32602… Missing required arguments: -32602… Internal errors: -32603” | 2026-07-28/server/prompts#error-handling | yes — unknown prompt -32602, backend failure -32603; tested, see conformance-matrix.md | yes | |
| prompts-validate-args | 2024-11-05 – 2026-07-28 | server | SHOULD | prompts | “Servers SHOULD validate prompt arguments before processing” | 2026-07-28/server/prompts#implementation-considerations | yes | no | |
| prompts-client-paginate | 2024-11-05 – 2026-07-28 | client | SHOULD | prompts / pagination | “Clients SHOULD handle pagination for large prompt lists” | 2026-07-28/server/prompts#implementation-considerations | no | yes — follow nextCursor upstream | |
| prompts-respect-capability-negotiation | 2024-11-05 – 2026-07-28 | both | SHOULD | prompts | “Both parties SHOULD respect capability negotiation” | 2026-07-28/server/prompts#implementation-considerations | yes | yes | |
| prompts-validate-io | 2024-11-05 – 2026-07-28 | both | MUST | prompts | “Implementations MUST carefully validate all prompt inputs and outputs to prevent injection attacks or unauthorized access to resources.” | 2026-07-28/server/prompts#security | yes | yes | |
| meta-request-required-fields | 2026-07-28 | client | MUST | meta | “Every request MUST include the required _meta fields” (tools/resources/prompts page notes) | 2026-07-28/server/tools | yes (checks inbound) | yes — every modern upstream request | new |
| cache-ttl-scope-required | 2026-07-28 | server | REQUIRED (schema) | caching | ttlMs: number; cacheScope: "public" | "private"; (non-optional on CacheableResult) | 2026-07-28/schema#discoverresult | yes — ttlMs/cacheScope on discover, the three lists, templates/list and resources/read (internal/mcpserver/server.go cacheable); tested, see conformance-matrix.md | yes — may use for upstream cache | new |
| discover-client-may-call | 2026-07-28 | client | MAY | discover | “Clients MAY call it but are not required to” (schema); “Calling server/discover is optional for clients” | 2026-07-28/server/discover#when-to-call | no | yes | new |
| discover-supportedversions | 2026-07-28 | server | REQUIRED (schema) | discover | “supportedVersions: Protocol versions the server supports.” | 2026-07-28/server/discover#discoverresult | yes — supportedVersions (#224); tested, see conformance-matrix.md | yes — read supportedVersions | new |
| discover-client-choose-from-list | 2026-07-28 | client | should (lowercase) | discover | “The client should choose one of these for subsequent requests.” | 2026-07-28/server/discover#discoverresult | no | yes | new |
| discover-capabilities | 2026-07-28 | server | REQUIRED (schema) | discover | “capabilities: Capabilities the server supports” | 2026-07-28/server/discover#discoverresult | yes | yes | replaces InitializeResult.capabilities |
| discover-serverinfo-in-meta | 2026-07-28 | server | SHOULD | discover | “_meta['io.modelcontextprotocol/serverInfo']: Name and version of the server software. Servers SHOULD include this field.” | 2026-07-28/server/discover#discoverresult | yes — _meta[io.modelcontextprotocol/serverInfo], no top-level serverInfo; tested, see conformance-matrix.md | yes | CHANGED location vs InitializeResult.serverInfo (top-level, required) |
| discover-serverinfo-not-for-behavior | 2026-07-28 | client | SHOULD NOT | discover | “Clients SHOULD NOT use it to change their behavior, and SHOULD NOT rely on it for security decisions.” | 2026-07-28/server/discover#discoverresult | no | yes | new |
| discover-instructions-optional | 2026-07-28 | server | MAY | discover | “instructions: Optional natural-language guidance for LLMs”; schema: “should not duplicate information already in tool descriptions” | 2026-07-28/server/discover#discoverresult | yes | yes | legacy counterpart in InitializeResult |
| discover-cacheable | 2026-07-28 | server | REQUIRED (schema) | discover / caching | “This operation supports caching.” ; DiscoverResult extends CacheableResult | 2026-07-28/server/discover#response | yes — ttlMs/cacheScope; tested, see conformance-matrix.md | yes | new |
| discover-resulttype | 2026-07-28 | server | MUST | discover / meta | example "resultType": "complete"; Result: “Servers implementing this protocol version MUST include this field.” | 2026-07-28/server/discover#response | yes if discover goes through the resultType stamping path — verify | yes | new |
| discover-request-meta-required | 2026-07-28 | client | MUST | discover / meta | “The request carries no body parameters beyond the standard _meta” (+ required _meta fields) | 2026-07-28/server/discover#request | yes | yes | new |
Roots, sampling, elicitation
| id | revs | side | level | area | quote | url | mcpx-as-server | mcpx-as-client | changes |
|---|---|---|---|---|---|---|---|---|---|
| roots-client-declare-capability-at-initialize | 2024-11-05 – 2025-11-25 | client | MUST | roots | “Clients that support roots MUST declare the roots capability during initialization” | https://modelcontextprotocol.io/specification/2025-11-25/client/roots#capabilities | n/a (mcpx never asks a downstream client for roots) | yes — declared in initialize (roots:{listChanged:false}) | replaced in 2026-07-28 by per-request _meta |
| roots-client-declare-capability-per-request-meta | 2026-07-28 | client | MUST | roots | “Clients that support roots MUST declare the roots capability in _meta.io.modelcontextprotocol/clientCapabilities on each request” | https://modelcontextprotocol.io/specification/2026-07-28/client/roots#capabilities | n/a | yes — withMeta stamps caps on every modern request; note mcpx sends roots:{listChanged:false} where the 2026 schema type is roots?: {} (extra key; harmless under open objects) | new; listChanged gone |
| roots-client-listchanged-must-notify | 2024-11-05 – 2025-11-25 | client | MUST | roots | “When roots change, clients that support listChanged MUST send a notification” | https://modelcontextprotocol.io/specification/2025-11-25/client/roots#root-list-changes | n/a | no — mcpx declares listChanged:false, so the obligation never attaches | removed in 2026-07-28 (notifications/roots/list_changed removed, changelog item 5) |
| roots-server-list-via-input-required | 2026-07-28 | server | MUST (via MRTR note) | roots | “servers send an InputRequiredResult containing a roots/list request” | https://modelcontextprotocol.io/specification/2026-07-28/client/roots#listing-roots | not-implemented-by-choice — mcpx answers roots itself and never asks downstream | yes — resolveInput answers roots/list inside inputRequests via the same answer() as legacy | legacy: server sends roots/list as a JSON-RPC request |
| roots-uri-must-be-file-scheme | 2024-11-05 – 2026-07-28 | client | MUST | roots | “This MUST be a file:// URI in the current specification.” (schema: “This must start with file:// for now.”) | https://modelcontextprotocol.io/specification/2026-07-28/client/roots#root | n/a | yes — roots come from config; whether config rejects non-file:// was not verified | |
| roots-client-only-expose-permitted-roots | 2024-11-05 – 2026-07-28 | client | MUST | roots | “Clients MUST: - Only expose roots with appropriate permissions” | https://modelcontextprotocol.io/specification/2026-07-28/client/roots#security-considerations | n/a | yes — operator-configured roots are the permission decision | |
| roots-client-validate-uris-path-traversal | 2024-11-05 – 2026-07-28 | client | MUST | roots | “Validate all root URIs to prevent path traversal” | https://modelcontextprotocol.io/specification/2026-07-28/client/roots#security-considerations | n/a | yes — not verified that configured roots are validated | |
| roots-client-implement-access-controls | 2024-11-05 – 2026-07-28 | client | MUST | roots | “Implement proper access controls” | https://modelcontextprotocol.io/specification/2026-07-28/client/roots#security-considerations | n/a | yes | contradicts 2026 intro “informational guidance rather than an access-control mechanism” (see Conflicts) |
| roots-client-monitor-accessibility | 2024-11-05 – 2026-07-28 | client | MUST | roots | “Monitor root accessibility” | https://modelcontextprotocol.io/specification/2026-07-28/client/roots#security-considerations | n/a | yes — not done (static config) | |
| roots-server-handle-unavailable-roots | 2024-11-05 – 2026-07-28 | server | SHOULD | roots | “Servers SHOULD: - Handle cases where roots become unavailable” | https://modelcontextprotocol.io/specification/2026-07-28/client/roots#security-considerations | n/a (mcpx does not consume roots) | n/a (peer’s duty) | |
| roots-server-respect-boundaries | 2024-11-05 – 2026-07-28 | server | SHOULD | roots | “Respect root boundaries during operations” | https://modelcontextprotocol.io/specification/2026-07-28/client/roots#security-considerations | n/a | n/a (peer’s duty) | repeated under Implementation Guidelines |
| roots-server-validate-paths-against-roots | 2024-11-05 – 2026-07-28 | server | SHOULD | roots | “Validate all paths against provided roots” | https://modelcontextprotocol.io/specification/2026-07-28/client/roots#security-considerations | n/a | n/a (peer’s duty) | |
| roots-client-prompt-consent-before-exposing | 2024-11-05 – 2026-07-28 | client | SHOULD | roots | “Prompt users for consent before exposing roots to servers” | https://modelcontextprotocol.io/specification/2026-07-28/client/roots#implementation-guidelines | n/a | yes — config is the consent; no prompt | |
| roots-client-provide-root-management-ui | 2024-11-05 – 2026-07-28 | client | SHOULD | roots | “Provide clear user interfaces for root management” | https://modelcontextprotocol.io/specification/2026-07-28/client/roots#implementation-guidelines | n/a | yes — config file only | |
| roots-client-validate-accessibility-before-exposing | 2024-11-05 – 2026-07-28 | client | SHOULD | roots | “Validate root accessibility before exposing” | https://modelcontextprotocol.io/specification/2026-07-28/client/roots#implementation-guidelines | n/a | yes | |
| roots-client-monitor-root-changes | 2024-11-05 – 2026-07-28 | client | SHOULD | roots | “Monitor for root changes” | https://modelcontextprotocol.io/specification/2026-07-28/client/roots#implementation-guidelines | n/a | yes | 2026 keeps this although it removed the change notification |
| roots-server-check-capability-before-use | 2024-11-05 – 2026-07-28 | server | SHOULD | roots | “Check for roots capability before usage” | https://modelcontextprotocol.io/specification/2026-07-28/client/roots#implementation-guidelines | n/a | n/a (peer’s duty) | hardened to MUST NOT in 2026 by mrtr (row mrtr-server-no-undeclared-input-requests) |
| roots-server-handle-list-changes | 2024-11-05 – 2025-11-25 | server | SHOULD | roots | “Handle root list changes gracefully” | https://modelcontextprotocol.io/specification/2025-11-25/client/roots#implementation-guidelines | n/a | n/a | removed in 2026-07-28 |
| roots-server-cache-root-information | 2024-11-05 – 2026-07-28 | server | SHOULD | roots | “Cache root information appropriately” | https://modelcontextprotocol.io/specification/2026-07-28/client/roots#implementation-guidelines | n/a | n/a | in 2026 there is no session to cache against (see Implied) |
| roots-client-return-jsonrpc-errors | 2024-11-05 – 2025-11-25 | client | SHOULD | roots | “Clients SHOULD return standard JSON-RPC errors for common failure cases: - Client does not support roots: -32601 (Method not found) - Internal errors: -32603” | https://modelcontextprotocol.io/specification/2025-11-25/client/roots#error-handling | n/a | yes — unknown methods get -32601; roots always answered | 2026: “the client does not need to replay the initial call with an error message” — no error path |
| roots-deprecated-new-impls-should-not-adopt | 2026-07-28 | both | SHOULD NOT | roots | “New implementations SHOULD NOT adopt it” | https://modelcontextprotocol.io/specification/2026-07-28/client/roots | not-implemented-by-choice (never asks) | yes — mcpx is an existing implementation; keeps answering | new (SEP-2577) |
| roots-deprecated-existing-should-migrate | 2026-07-28 | both | SHOULD | roots | “existing implementations SHOULD migrate to passing directories or files via tool parameters, resource URIs, or server configuration” | https://modelcontextprotocol.io/specification/2026-07-28/client/roots | n/a | yes — configured roots already are server configuration; migration is upstream’s | new |
| sampling-human-in-loop-can-deny | 2024-11-05 – 2026-07-28 | client | SHOULD | sampling | “there SHOULD always be a human in the loop with the ability to deny sampling requests” | https://modelcontextprotocol.io/specification/2026-07-28/client/sampling#user-interaction-model | n/a (downstream’s duty; mcpx forwards) | yes — delegated to broker/downstream client; mcpx itself has no model | |
| sampling-app-review-ui | 2024-11-05 – 2026-07-28 | client | SHOULD | sampling | “Provide UI that makes it easy and intuitive to review sampling requests” | https://modelcontextprotocol.io/specification/2026-07-28/client/sampling#user-interaction-model | n/a | yes — delegated | |
| sampling-app-view-edit-prompts | 2024-11-05 – 2026-07-28 | client | SHOULD | sampling | “Allow users to view and edit prompts before sending” | https://modelcontextprotocol.io/specification/2026-07-28/client/sampling#user-interaction-model | n/a | yes — delegated | |
| sampling-app-review-responses | 2024-11-05 – 2026-07-28 | client | SHOULD | sampling | “Present generated responses for review before delivery” | https://modelcontextprotocol.io/specification/2026-07-28/client/sampling#user-interaction-model | n/a | yes — delegated | |
| sampling-client-declare-capability-at-initialize | 2024-11-05 – 2025-11-25 | client | MUST | sampling | “Clients that support sampling MUST declare the sampling capability during initialization” | https://modelcontextprotocol.io/specification/2025-11-25/client/sampling#capabilities | n/a | yes — declared only when a handler is installed | replaced in 2026-07-28 |
| sampling-client-declare-capability-per-request-meta | 2026-07-28 | client | MUST | sampling | “Clients that support sampling MUST declare the sampling capability in _meta.io.modelcontextprotocol/clientCapabilities on each request” | https://modelcontextprotocol.io/specification/2026-07-28/client/sampling#capabilities | n/a | yes | new |
| sampling-client-declare-tools-capability | 2025-11-25 – 2026-07-28 | client | MUST | sampling | “Clients MUST declare support for tool use via the sampling.tools capability to receive tool-enabled sampling requests.” | https://modelcontextprotocol.io/specification/2026-07-28/client/sampling#tools-in-sampling | n/a | yes — mcpx never declares sampling.tools | new in 2025-11-25 |
| sampling-server-no-tools-without-capability | 2025-11-25 – 2026-07-28 | server | MUST NOT | sampling | “Servers MUST NOT send tool-enabled sampling requests to Clients that have not declared support for tool use via the sampling.tools capability.” | https://modelcontextprotocol.io/specification/2026-07-28/client/sampling#tools-in-sampling | yes — Question.Sendable refuses a tools-carrying sampling question unless the peer declared sampling.tools (Peer.CanSampleTools) | n/a (peer’s duty) | new in 2025-11-25 |
| sampling-client-error-on-tools-without-capability | 2025-11-25 – 2026-07-28 | client | MUST | sampling | “The client MUST return an error if this field is provided but ClientCapabilities.sampling.tools is not declared.” (schema, on tools and on toolChoice) | https://modelcontextprotocol.io/specification/2026-07-28/schema#createmessagerequestparams | n/a | yes — checked in mcpclient answer(): a request carrying tools or toolChoice is refused -32602 naming sampling.tools before the handler runs, in both eras (in 2026 the refusal surfaces as the call’s error, there being no error slot in inputResponses) | new in 2025-11-25 |
| sampling-server-includecontext-only-with-context-capability | 2025-11-25 – 2026-07-28 | server | SHOULD NOT | sampling | “Servers SHOULD avoid using these values … and SHOULD NOT use them unless the client declares sampling.context capability.” (schema: “If not declared, servers SHOULD only use includeContext: \"none\" (or omit it).”) | https://modelcontextprotocol.io/specification/2026-07-28/client/sampling#capabilities | yes — Question.paramsFor drops includeContext unless the peer declared sampling.context (Peer.CanSampleContext) | n/a (peer’s duty); mcpx declares no sampling.context | “soft-deprecated” in 2025-11-25 → “deprecated” (SEP-2596) in 2026-07-28; obligation text unchanged |
| sampling-server-avoid-includecontext-values | 2025-11-25 – 2026-07-28 | server | SHOULD | sampling | “Servers SHOULD avoid using these values (e.g. can just omit includeContext since it defaults to \"none\")” | https://modelcontextprotocol.io/specification/2026-07-28/client/sampling#capabilities | yes (as above) | n/a | |
| sampling-deprecated-new-impls-should-not-adopt | 2026-07-28 | both | SHOULD NOT | sampling | “New implementations SHOULD NOT adopt it; existing implementations SHOULD migrate to integrating directly with LLM provider APIs.” | https://modelcontextprotocol.io/specification/2026-07-28/client/sampling | yes — mcpx forwards; pass-through, not adoption | yes | new (SEP-2577) |
| sampling-tool-result-message-only-tool-results | 2025-11-25 – 2026-07-28 | both | MUST | sampling | “When a user message contains tool results (type: "tool_result"), it MUST contain ONLY tool results.” | https://modelcontextprotocol.io/specification/2026-07-28/client/sampling#tool-result-messages | yes — pass-through; mcpx does not rewrite messages | yes — pass-through | new |
| sampling-tool-use-result-balance | 2025-11-25 – 2026-07-28 | both | MUST | sampling | “every assistant message containing ToolUseContent blocks MUST be followed by a user message that consists entirely of ToolResultContent blocks, with each tool use … matched by a corresponding tool result” | https://modelcontextprotocol.io/specification/2026-07-28/client/sampling#tool-use-and-result-balance | yes — pass-through | yes — pass-through | new |
| sampling-server-answer-every-tooluse | 2025-11-25 – 2026-07-28 | server | MUST | sampling | “Servers MUST ensure that when replying to a stopReason: \"toolUse\", each ToolUseContent item is responded to with a ToolResultContent item with a matching toolUseId” | https://modelcontextprotocol.io/specification/2026-07-28/client/sampling#security-considerations | yes — upstream’s content, forwarded | n/a | new |
| sampling-toolresult-id-must-match-tooluse | 2025-11-25 – 2026-07-28 | both | MUST | sampling | “This MUST match the ID from a previous ToolUseContent.” | https://modelcontextprotocol.io/specification/2026-07-28/schema#toolresultcontent | yes — ids must not be rewritten in transit | yes | new |
| sampling-toolchoice-required-model-must-use-tool | 2025-11-25 – 2026-07-28 | client | MUST | sampling | “{mode: \"required\"}: Model MUST use at least one tool before completing” | https://modelcontextprotocol.io/specification/2026-07-28/client/sampling#tool-choice-modes | n/a | n/a — mcpx never declares tools | new |
| sampling-toolchoice-none-model-must-not-use-tools | 2025-11-25 – 2026-07-28 | client | MUST NOT | sampling | “{mode: \"none\"}: Model MUST NOT use any tools” | https://modelcontextprotocol.io/specification/2026-07-28/client/sampling#tool-choice-modes | n/a | n/a | new |
| sampling-parallel-tool-toggle-extension-only | 2025-11-25 – 2026-07-28 | client | MAY | sampling | “Implementations wrapping providers that support disabling parallel tool use MAY expose this as an extension, but it is not part of the core MCP specification.” | https://modelcontextprotocol.io/specification/2026-07-28/client/sampling#parallel-tool-use | n/a | n/a | |
| sampling-tooluse-meta-preserve | 2025-11-25 – 2026-07-28 | client (text says “Clients”; see Conflicts) | SHOULD | sampling | “Clients SHOULD preserve this field when including tool uses in subsequent sampling requests to enable caching optimizations.” (same on ToolResultContent._meta) | https://modelcontextprotocol.io/specification/2026-07-28/schema#toolusecontent | yes — forward _meta on content blocks untouched | yes | new |
| sampling-toolresult-structured-conform-outputschema | 2025-11-25 – 2026-07-28 | both | SHOULD | sampling | “If the tool defined an outputSchema, this SHOULD conform to that schema.” | https://modelcontextprotocol.io/specification/2026-07-28/schema#toolresultcontent | yes — pass-through | yes — pass-through | |
| sampling-message-must-have-role-and-content | 2026-07-28 | both | MUST | sampling | “Sampling messages MUST contain a role field of \"user\" or \"assistant\"; and a content field representing the message data.” | https://modelcontextprotocol.io/specification/2026-07-28/client/sampling#messages | yes | yes — daemon fills a missing role/model in results (hooks.go:223-229) | prose new in 2026; schema had the fields required since 2024-11-05 |
| sampling-messages-not-retained-between-requests | 2026-07-28 | client | SHOULD NOT | sampling | “The list of messages in a sampling request SHOULD NOT be retained between separate requests.” | https://modelcontextprotocol.io/specification/2026-07-28/client/sampling#messages | n/a | yes — broker persists questions in SQLite (docs/elicitation.md §3); a sampling question’s messages are retained (conflict with this SHOULD NOT; unverified whether params are stored) | new in 2026 |
| sampling-client-must-respect-maxtokens | 2026-07-28 | client | MUST | sampling | “The client MUST respect the maxTokens parameter.” | https://modelcontextprotocol.io/specification/2026-07-28/client/sampling#sampling-parameters | yes — forward maxTokens unchanged | yes — delegated to whoever samples | new in 2026 prose |
| sampling-client-may-sample-fewer-tokens | 2024-11-05 – 2026-07-28 | client | MAY | sampling | “The client MAY choose to sample fewer tokens than the requested maximum.” | https://modelcontextprotocol.io/specification/2026-07-28/schema#createmessagerequestparams | n/a | yes | 2024-11-05/2025-03-26 wording “as requested by the server. The client MAY choose to sample fewer tokens than requested.” |
| sampling-client-may-ignore-temperature-stop-metadata | 2026-07-28 | client | MAY | sampling | “The client MAY modify or ignore temperature, stopSequences and metadata.” | https://modelcontextprotocol.io/specification/2026-07-28/client/sampling#sampling-parameters | n/a | yes | new prose |
| sampling-client-may-ignore-model-preferences | 2024-11-05 – 2026-07-28 | client | MAY | sampling | “The server’s preferences for which model to select. The client MAY ignore these preferences.” | https://modelcontextprotocol.io/specification/2026-07-28/schema#createmessagerequestparams | n/a | yes | |
| sampling-client-may-modify-system-prompt | 2024-11-05 – 2026-07-28 | client | MAY | sampling | “The client MAY modify or omit this prompt.” (2026 prose adds “without communicating this to the server”) | https://modelcontextprotocol.io/specification/2026-07-28/client/sampling#system-prompt | n/a | yes — daemon uses systemPrompt as the question’s message (hooks.go:194) | 2026 adds prose section |
| sampling-client-may-ignore-includecontext | 2024-11-05 – 2026-07-28 | client | MAY | sampling | “The client MAY modify or ignore this field without communicating this to the server.” | https://modelcontextprotocol.io/specification/2026-07-28/client/sampling#context-inclusion | n/a | yes — mcpx has no context to include | schema-only until 2026 |
| sampling-hints-evaluated-in-order | 2024-11-05 – 2026-07-28 | client | MUST | sampling | “If multiple hints are specified, the client MUST evaluate them in order (such that the first match is taken).” | https://modelcontextprotocol.io/specification/2026-07-28/schema#modelpreferences | yes — forward hints order unchanged | yes — delegated | |
| sampling-hints-over-priorities | 2024-11-05 – 2026-07-28 | client | SHOULD | sampling | “The client SHOULD prioritize these hints over the numeric priorities, but MAY still use the priorities to select from ambiguous matches.” | https://modelcontextprotocol.io/specification/2026-07-28/schema#modelpreferences | n/a | yes — delegated | |
| sampling-hint-name-substring | 2024-11-05 – 2026-07-28 | client | SHOULD | sampling | “The client SHOULD treat this as a substring of a model name” | https://modelcontextprotocol.io/specification/2026-07-28/schema#modelhint | n/a | yes — delegated | |
| sampling-hint-may-map-provider | 2024-11-05 – 2026-07-28 | client | MAY | sampling | “Clients MAY map hints to equivalent models from different providers” | https://modelcontextprotocol.io/specification/2026-07-28/client/sampling#model-hints | n/a | yes | |
| sampling-stopreason-custom-values | 2024-11-05 – 2026-07-28 | client | MAY | sampling | “implementations MAY provide their own arbitrary values” (schema: “open string”) | https://modelcontextprotocol.io/specification/2026-07-28/client/sampling#result-fields | yes — must pass unknown stopReason through | yes | prose added 2026; toolUse value added 2025-11-25 |
| sampling-client-errors-user-rejected | 2024-11-05 – 2025-06-18 | client | SHOULD | sampling | “Clients SHOULD return errors for common failure cases” (example code -1, “User rejected sampling request”) | https://modelcontextprotocol.io/specification/2025-06-18/client/sampling#error-handling | yes — downstream error must be relayed upstream as an error | yes — “a decline becomes an error, since the specification has no decline result for sampling” (docs/protocol.md §4.1) | |
| sampling-client-errors-user-rejected-and-tool-shape | 2025-11-25 | client | SHOULD | sampling | “User rejected sampling request: -1 - Tool result missing in request: -32602 (Invalid params) - Tool results mixed with other content: -32602 (Invalid params)” | https://modelcontextprotocol.io/specification/2025-11-25/client/sampling#error-handling | yes (relay) | yes — -1/-32602 not specifically produced; handler errors become -32603 (modern.go:125) | removed in 2026-07-28 |
| sampling-client-user-approval-controls | 2024-11-05 – 2026-07-28 | client | SHOULD | sampling | “Clients SHOULD implement user approval controls” | https://modelcontextprotocol.io/specification/2026-07-28/client/sampling#security-considerations | n/a | yes — broker policy/audience | |
| sampling-both-validate-message-content | 2024-11-05 – 2026-07-28 | both | SHOULD | sampling | “Both parties SHOULD validate message content” | https://modelcontextprotocol.io/specification/2026-07-28/client/sampling#security-considerations | yes | yes | |
| sampling-client-respect-hints | 2024-11-05 – 2026-07-28 | client | SHOULD | sampling | “Clients SHOULD respect model preference hints” | https://modelcontextprotocol.io/specification/2026-07-28/client/sampling#security-considerations | n/a | yes — delegated | |
| sampling-client-rate-limit | 2024-11-05 – 2026-07-28 | client | SHOULD | sampling | “Clients SHOULD implement rate limiting” | https://modelcontextprotocol.io/specification/2026-07-28/client/sampling#security-considerations | n/a | yes — proto.samplingPerMinute (60) per server and proto.samplingSessionPerMinute (20) per session, fixed window; a refused request reaches no handler (#2192) | |
| sampling-both-handle-sensitive-data | 2024-11-05 – 2026-07-28 | both | MUST | sampling | “Both parties MUST handle sensitive data appropriately” | https://modelcontextprotocol.io/specification/2026-07-28/client/sampling#security-considerations | yes — prompts/completions pass through mcpx and its log | yes — same | |
| sampling-both-iteration-limits-tool-loops | 2025-11-25 – 2026-07-28 | both | SHOULD | sampling | “Both parties SHOULD implement iteration limits for tool loops” | https://modelcontextprotocol.io/specification/2026-07-28/client/sampling#security-considerations | yes — proto.askRounds covers 2026 retries | yes | new |
| elicitation-server-no-sensitive-info | 2025-06-18 | server | MUST NOT | elicitation | “Servers MUST NOT use elicitation to request sensitive information.” | https://modelcontextprotocol.io/specification/2025-06-18/client/elicitation#user-interaction-model | yes — mcpx cannot vet upstream content; forwards form questions as-is | n/a (peer’s duty) | narrowed to form mode in 2025-11-25 |
| elicitation-server-no-sensitive-info-in-form-mode | 2025-11-25 – 2026-07-28 | server | MUST NOT | elicitation | “Servers MUST NOT use form mode elicitation to request sensitive information such as passwords, API keys, access tokens, or payment credentials” (restated: “Servers MUST NOT request sensitive information (passwords, API keys, etc.) via form mode”) | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#user-interaction-model | yes — pass-through of upstream’s form; mcpx’s own questions must comply | n/a | |
| elicitation-server-sensitive-via-url-mode | 2025-11-25 – 2026-07-28 | server | MUST | elicitation | “Servers MUST use URL mode for interactions involving such sensitive information” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#user-interaction-model | yes — mcpx raises no url-mode question of its own (docs/protocol.md §6) | n/a | new in 2025-11-25 |
| elicitation-app-show-requesting-server | 2025-06-18 | client | SHOULD | elicitation | “Applications SHOULD: - Provide UI that makes it clear which server is requesting information” (also “Clients SHOULD provide clear indication of which server is requesting information”) | https://modelcontextprotocol.io/specification/2025-06-18/client/elicitation#security-considerations | yes — message rewritten “ | yes — broker records Server | promoted to MUST in 2025-11-25 |
| elicitation-client-show-requesting-server | 2025-11-25 – 2026-07-28 | client | MUST | elicitation | “Clients MUST provide clear indication of which server is requesting information” (and “MCP clients MUST: - Provide UI that makes it clear which server is requesting information”) | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#security-considerations | yes — rewrite above; without it the downstream would only see “mcpx” | yes — delegated | was SHOULD |
| elicitation-app-review-modify-responses | 2025-06-18 | client | SHOULD | elicitation | “Allow users to review and modify their responses before sending” | https://modelcontextprotocol.io/specification/2025-06-18/client/elicitation#user-interaction-model | n/a | yes — delegated | promoted |
| elicitation-client-form-review-modify-responses | 2025-11-25 – 2026-07-28 | client | MUST | elicitation | “For form mode, allow users to review and modify their responses before sending” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#user-interaction-model | n/a | yes — delegated; broker auto-policy answers bypass review (see Implied) | was SHOULD |
| elicitation-app-decline-cancel-options | 2025-06-18 | client | SHOULD | elicitation | “Respect user privacy and provide clear decline and cancel options” | https://modelcontextprotocol.io/specification/2025-06-18/client/elicitation#user-interaction-model | n/a | yes — mcpx elicit decline/cancel | promoted |
| elicitation-client-decline-cancel-options | 2025-11-25 – 2026-07-28 | client | MUST | elicitation | “Respect user privacy and provide clear decline and cancel options” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#user-interaction-model | n/a | yes — broker keeps decline ≠ cancel; expiry answers cancel | was SHOULD |
| elicitation-client-url-show-domain-and-consent | 2025-11-25 – 2026-07-28 | client | MUST | elicitation | “For URL mode, clearly display the target domain/host and gather user consent before navigation to the target URL” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#user-interaction-model | n/a | yes — mcpx declares form only upstream, so url mode should not arrive; broker/TUI must meet it if it does | new |
| elicitation-client-declare-capability-at-initialize | 2025-06-18 – 2025-11-25 | client | MUST | elicitation | “Clients that support elicitation MUST declare the elicitation capability during initialization” | https://modelcontextprotocol.io/specification/2025-11-25/client/elicitation#capabilities | n/a | yes — elicitation: {} | replaced in 2026 |
| elicitation-client-declare-capability-per-request-meta | 2026-07-28 | client | MUST | elicitation | “Clients that support elicitation MUST declare the elicitation capability in _meta.io.modelcontextprotocol/clientCapabilities on each request” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#capabilities | yes — mcpx must read the capability from this request’s _meta, not a prior one | yes | new |
| elicitation-empty-capability-means-form-only | 2025-11-25 – 2026-07-28 | both | (definition) | elicitation | “For backwards compatibility, an empty capabilities object is equivalent to declaring support for form mode only” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#capabilities | yes — CanElicit("url") requires elicitation.url | yes — mcpx’s {} therefore declares form only | new |
| elicitation-client-support-at-least-one-mode | 2025-11-25 – 2026-07-28 | client | MUST | elicitation | “Clients declaring the elicitation capability MUST support at least one mode (form or url).” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#capabilities | n/a | yes — form | new |
| elicitation-server-no-undeclared-modes | 2025-11-25 – 2026-07-28 | server | MUST NOT | elicitation | “Servers MUST NOT send elicitation requests with modes that are not supported by the client.” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#capabilities | yes — CanElicit gates url on elicitation.url and on revision; url questions otherwise stay with the broker | n/a | new |
| elicitation-server-may-request-during-client-request | 2026-07-28 | server | MAY | elicitation | “Servers MAY request information from a user during the processing of a client request, by sending an InputRequiredResult containing an elicitation/create request.” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#elicitation-requests | yes — modern downstream gets input_required | yes — resolveInput | legacy: a server-initiated request |
| elicitation-request-must-include-mode-and-message | 2025-11-25 – 2026-07-28 | server | MUST | elicitation | “All elicitation requests MUST include the following parameters: … mode … Optional for form mode … message” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#elicitation-requests | yes | n/a | self-contradictory on mode (Conflicts) |
| elicitation-server-may-omit-mode-for-form | 2025-11-25 – 2026-07-28 | server | MAY | elicitation | “For backwards compatibility, servers MAY omit the mode field for form mode elicitation requests.” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#elicitation-requests | yes — mcpx strips mode for 2025-06-18 clients | n/a | |
| elicitation-client-missing-mode-is-form | 2025-11-25 – 2026-07-28 | client | MUST | elicitation | “Clients MUST treat requests without a mode field as form mode.” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#elicitation-requests | n/a | yes — hooks.go:133 defaults to form | |
| elicitation-form-request-shape | 2025-11-25 – 2026-07-28 | server | MUST | elicitation | “Form mode elicitation requests MUST either specify mode: \"form\" or omit the mode field, and include these additional parameters: requestedSchema” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#form-mode-elicitation-requests | yes | n/a | 2025-06-18: message+requestedSchema required by schema only |
| elicitation-form-schema-flat-primitives | 2025-06-18 – 2026-07-28 | server | MUST (schema-structural) | elicitation | “form mode elicitation schemas are limited to flat objects with primitive properties only” / schema: “Only top-level properties are allowed, without nesting.” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#requested-schema | yes — pass-through; a 2025-06-18 downstream cannot parse default, oneOf, arrays (added 2025-11-25) — not downgraded by mcpx (unverified) | n/a | 2025-11-25 adds defaults, titled/untitled single/multi-select enums; enumNames becomes LegacyTitledEnumSchema |
| elicitation-client-prepopulate-defaults | 2025-11-25 – 2026-07-28 | client | SHOULD | elicitation | “Clients that support defaults SHOULD pre-populate form fields with these values.” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#requested-schema | n/a | yes — delegated | new (SEP-1034); keyword not bolded |
| elicitation-url-request-shape-with-id | 2025-11-25 | server | MUST | elicitation | “URL mode elicitation requests MUST specify mode: \"url\", a message, and include these additional parameters: url … elicitationId” | https://modelcontextprotocol.io/specification/2025-11-25/client/elicitation#url-mode-elicitation-requests | yes — a url question from a 2026 upstream forwarded to a 2025-11-25 downstream needs a synthesized elicitationId (unverified that mcpx does this) | n/a | elicitationId removed in 2026-07-28 |
| elicitation-url-request-shape | 2026-07-28 | server | MUST | elicitation | “URL mode elicitation requests MUST specify mode: \"url\", a message, and include these additional parameters: url” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#url-mode-elicitation-requests | yes — paramsFor strips elicitationId only for clients older than 2025-11-25, so a 2025-11-25 upstream’s id reaches a 2026 downstream (extra field) | n/a | changed |
| elicitation-url-must-be-valid | 2025-11-25 – 2026-07-28 | server | MUST | elicitation | “The url parameter MUST contain a valid URL.” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#url-mode-elicitation-requests | yes — pass-through | n/a | |
| elicitation-client-elicitationid-opaque | 2025-11-25 | client | MUST | elicitation | “The ID of the elicitation, which must be unique within the context of the server. The client MUST treat this ID as an opaque value.” | https://modelcontextprotocol.io/specification/2025-11-25/schema#elicitrequesturlparams | n/a | yes — carried, not parsed | removed 2026 |
| elicitation-server-may-send-complete-notification | 2025-11-25 | server | MAY | elicitation | “Servers MAY send a notifications/elicitation/complete notification when an out-of-band interaction started by URL mode elicitation is completed.” | https://modelcontextprotocol.io/specification/2025-11-25/client/elicitation#completion-notifications-for-url-mode-elicitation | yes — events.go:264 emits it downstream | yes — client.go:501 listens | removed 2026 |
| elicitation-complete-only-to-initiating-client | 2025-11-25 | server | MUST | elicitation | “MUST only send the notification to the client that initiated the elicitation request.” | https://modelcontextprotocol.io/specification/2025-11-25/client/elicitation#completion-notifications-for-url-mode-elicitation | yes — must route by the connection the question went to, not broadcast (unverified which) | n/a | removed 2026 |
| elicitation-complete-must-carry-id | 2025-11-25 | server | MUST | elicitation | “MUST include the elicitationId established in the original elicitation/create request.” | https://modelcontextprotocol.io/specification/2025-11-25/client/elicitation#completion-notifications-for-url-mode-elicitation | yes — id must be the one the downstream saw | n/a | removed 2026 |
| elicitation-client-ignore-unknown-complete | 2025-11-25 | client | MUST | elicitation | “MUST ignore notifications referencing unknown or already-completed IDs.” | https://modelcontextprotocol.io/specification/2025-11-25/client/elicitation#completion-notifications-for-url-mode-elicitation | n/a | yes | removed 2026 |
| elicitation-client-may-auto-retry-on-complete | 2025-11-25 | client | MAY | elicitation | “MAY wait for this notification to automatically retry requests that received a URLElicitationRequiredError” | https://modelcontextprotocol.io/specification/2025-11-25/client/elicitation#completion-notifications-for-url-mode-elicitation | n/a | yes | removed 2026 |
| elicitation-client-manual-retry-cancel-controls | 2025-11-25 – 2026-07-28 | client | SHOULD | elicitation | “Clients SHOULD provide manual controls that let the user retry or cancel the original request (or otherwise resume interacting with the client).” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#example-request-sensitive-data | n/a | yes — mcpx elicit CLI/TUI | 2025-11-25: “SHOULD still provide … if the notification never arrives” |
| elicitation-server-may-return-url-required-error | 2025-11-25 | server | MAY | elicitation | “the server MAY return a URLElicitationRequiredError (code -32042)” | https://modelcontextprotocol.io/specification/2025-11-25/client/elicitation#url-elicitation-required-error | yes — relay upstream -32042 only to a downstream that declared elicitation.url (unverified) | yes — must parse -32042 data (unverified) | removed 2026; code reserved |
| elicitation-url-required-error-only-when-required | 2025-11-25 | server | MUST NOT | elicitation | “The server MUST NOT return this error except when URL mode elicitation is required.” | https://modelcontextprotocol.io/specification/2025-11-25/client/elicitation#url-elicitation-required-error | yes | n/a | removed 2026 |
| elicitation-url-required-error-lists-elicitations | 2025-11-25 | server | MUST | elicitation | “The error MUST include a list of elicitations that are required to complete before the original can be retried.” | https://modelcontextprotocol.io/specification/2025-11-25/client/elicitation#url-elicitation-required-error | yes | n/a | removed 2026 |
| elicitation-url-required-error-url-mode-with-id | 2025-11-25 | server | MUST | elicitation | “Any elicitations returned in the error MUST be URL mode elicitations and have an elicitationId property.” | https://modelcontextprotocol.io/specification/2025-11-25/client/elicitation#url-elicitation-required-error | yes | n/a | removed 2026 |
| elicitation-server-must-return-32042 | 2025-11-25 | server | MUST | elicitation | “Servers MUST return standard JSON-RPC errors for common failure cases: - When a request cannot be processed until an elicitation is completed: -32042” | https://modelcontextprotocol.io/specification/2025-11-25/client/elicitation#error-handling | yes | n/a | conflicts with the MAY above (Conflicts) |
| elicitation-client-32602-on-undeclared-mode | 2025-11-25 | client | MUST | elicitation | “Clients MUST return standard JSON-RPC errors … Server sends an elicitation/create request with a mode not declared in client capabilities: -32602 (Invalid params)” | https://modelcontextprotocol.io/specification/2025-11-25/client/elicitation#error-handling | n/a | yes — an undeclared mode is -32602 (elicitModeDeclared, internal/mcpclient/modern.go); tested, see conformance-matrix.md | removed 2026 |
| elicitation-no-32042-in-2026 | 2026-07-28 | both | MUST NOT | elicitation | “Implementations of this protocol version MUST NOT emit these codes: … -32042 — URL elicitation required (2025-11-25 only).” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#error-codes | yes — must not relay a legacy upstream’s -32042 verbatim to a 2026 downstream | yes | new |
| elicitation-server-state-bound-to-user | 2025-11-25 | server | MUST | elicitation | “Servers implementing elicitation MUST securely associate this state with individual users” | https://modelcontextprotocol.io/specification/2025-11-25/client/elicitation#statefulness | yes — broker binds questions to session/connection | n/a | 2026 makes it conditional |
| elicitation-server-stored-state-bound-to-user | 2026-07-28 | server | MUST | elicitation | “if state is stored, servers implementing elicitation MUST securely associate this state with individual users” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#statefulness | yes — mcpx stores (broker + daemon task) so it binds; requestState carries connection id | n/a | conditional |
| elicitation-state-not-session-id-alone | 2025-11-25 | server | MUST NOT | elicitation | “State MUST NOT be associated with session IDs alone” | https://modelcontextprotocol.io/specification/2025-11-25/client/elicitation#statefulness | yes — GAP: mcpx binds to MCPX_SESSION_ID/connection, i.e. session identity alone (no user auth exists) | n/a | removed 2026 |
| elicitation-state-storage-protected | 2025-11-25 – 2026-07-28 | server | MUST | elicitation | “State storage MUST be protected against unauthorized access” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#statefulness | yes — broker SQLite is local-user only; /v1/elicit over a non-loopback port is not protected | n/a | |
| elicitation-remote-user-id-from-authorization | 2025-11-25 – 2026-07-28 | server | MUST | elicitation | “For remote MCP servers, user identification MUST be derived from credentials acquired via MCP authorization when possible (e.g. sub claim)” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#statefulness | not-implemented-by-choice — mcpx does no OAuth; “when possible” is not met on --address 0.0.0.0 | n/a | |
| elicitation-server-must-not-self-authorize-via-url | 2025-11-25 – 2026-07-28 | server | MUST NOT | elicitation | “MCP servers MUST NOT rely on URL mode elicitation to authorize users for themselves.” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#url-mode-elicitation-for-oauth-flows | yes — mcpx raises none | n/a | |
| elicitation-third-party-creds-not-via-client | 2025-11-25 – 2026-07-28 | server | MUST NOT | elicitation | “The third-party credentials MUST NOT transit through the MCP client” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#understanding-the-distinction | yes — mcpx is in the path only for the URL, not the credential | yes | |
| elicitation-no-token-passthrough | 2025-11-25 – 2026-07-28 | server | MUST NOT | elicitation | “The MCP server MUST NOT use the client’s credentials for the third-party service” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#understanding-the-distinction | not-implemented-by-choice (no OAuth) | n/a | |
| elicitation-user-authorizes-server-directly | 2025-11-25 – 2026-07-28 | server | MUST | elicitation | “The user MUST authorize the MCP server directly” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#understanding-the-distinction | yes — pass-through URL opens the upstream directly | n/a | |
| elicitation-server-not-transmit-url-creds-to-client | 2025-11-25 – 2026-07-28 | server | MUST NOT | elicitation | “The MCP server MUST NOT transmit credentials obtained through URL mode elicitation to the MCP client.” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#understanding-the-distinction | yes | n/a | |
| elicitation-server-handle-decline-cancel-failure | 2026-07-28 | server | SHOULD NOT / MUST | elicitation | “Servers SHOULD NOT assume that elicitation requests will always succeed, and MUST handle cases where the user declines or cancels the elicitation, or where the client fails to process the request.” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#error-handling | yes — mcpx as server re-asks up to askRounds / hands back cancel | n/a | replaces 2025-11-25 error-code MUSTs |
| elicitation-server-bind-to-client-and-user | 2025-11-25 – 2026-07-28 | server | MUST | elicitation | “Servers MUST bind elicitation requests to the client and user identity” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#security-considerations | yes — per-connection correlation; ambiguous shared scope goes to broker (docs/protocol.md §3.4) | n/a | new in 2025-11-25 |
| elicitation-client-user-approval-controls | 2025-06-18 – 2026-07-28 | client | SHOULD | elicitation | “Clients SHOULD implement user approval controls” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#security-considerations | n/a | yes — broker policy | |
| elicitation-client-allow-decline-any-time | 2025-06-18 – 2026-07-28 | client | SHOULD | elicitation | “Clients SHOULD allow users to decline elicitation requests at any time” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#security-considerations | n/a | yes | |
| elicitation-client-rate-limit | 2025-06-18 – 2025-11-25 | client | SHOULD | elicitation | “Clients SHOULD implement rate limiting” | https://modelcontextprotocol.io/specification/2025-11-25/client/elicitation#security-considerations | n/a | yes — proto.elicitationPerMinute (30) per server, fixed window; a refused request reaches no handler and is not answered cancel (#2192) | removed in 2026-07-28 |
| elicitation-client-clear-what-and-why | 2025-06-18 – 2026-07-28 | client | SHOULD | elicitation | “Clients SHOULD present elicitation requests in a way that makes it clear what information is being requested and why” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#security-considerations | yes — forward message intact (only prefixed) | yes — delegated | |
| elicitation-both-validate-against-schema | 2025-06-18 | both | SHOULD | elicitation | “Both parties SHOULD validate elicitation content against the provided schema” | https://modelcontextprotocol.io/specification/2025-06-18/client/elicitation#security-considerations | yes | yes | split per side in 2025-11-25 |
| elicitation-client-validate-responses | 2025-11-25 – 2026-07-28 | client | SHOULD | elicitation | “Clients SHOULD validate all responses against the provided schema” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#form-mode-security | n/a | yes — broker records problems on answers (routes_proto.go:446) | |
| elicitation-server-validate-received-data | 2025-11-25 – 2026-07-28 | server | SHOULD | elicitation | “Servers SHOULD validate received data matches the requested schema” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#form-mode-security | yes — mcpx as server should validate before relaying upstream | n/a | |
| elicitation-url-no-sensitive-user-info | 2025-11-25 – 2026-07-28 | server | MUST NOT | elicitation | “MUST NOT include sensitive information about the end-user, including credentials, personally identifiable information, etc., in the URL” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#safe-url-handling | yes — pass-through; mcpx must not append its own session/ids to the URL | n/a | |
| elicitation-url-not-pre-authenticated | 2025-11-25 – 2026-07-28 | server | MUST NOT | elicitation | “MUST NOT provide a URL which is pre-authenticated to access a protected resource” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#safe-url-handling | yes | n/a | |
| elicitation-no-clickable-urls-in-form | 2025-11-25 – 2026-07-28 | server | SHOULD NOT | elicitation | “SHOULD NOT include URLs intended to be clickable in any field of a form mode elicitation request.” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#safe-url-handling | yes — the “(via mcpx)” prefix adds no URL | n/a | |
| elicitation-url-https-outside-dev | 2025-11-25 – 2026-07-28 | server | SHOULD | elicitation | “SHOULD use HTTPS URLs for non-development environments.” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#safe-url-handling | yes — pass-through | n/a | |
| elicitation-client-handle-urls-carefully | 2025-11-25 – 2026-07-28 | client | MUST | elicitation | “Clients implementing URL mode elicitation MUST handle URLs carefully to prevent users from unknowingly clicking malicious links.” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#safe-url-handling | n/a | yes — if the TUI/plugin offers to open a URL (docs/elicitation.md §5.6) | |
| elicitation-client-no-url-prefetch | 2025-11-25 – 2026-07-28 | client | MUST NOT | elicitation | “MUST NOT automatically pre-fetch the URL or any of its metadata.” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#safe-url-handling | yes — a proxy must not fetch/validate the URL in transit either (implied) | yes | |
| elicitation-client-no-open-without-consent | 2025-11-25 – 2026-07-28 | client | MUST NOT | elicitation | “MUST NOT open the URL without explicit consent from the user.” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#safe-url-handling | n/a | yes — broker auto rules must never “accept” a url question (implied) | |
| elicitation-client-show-full-url | 2025-11-25 – 2026-07-28 | client | MUST | elicitation | “MUST show the full URL to the user for examination before consent.” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#safe-url-handling | yes — URL must reach the downstream unmodified | yes | |
| elicitation-client-open-url-securely | 2025-11-25 – 2026-07-28 | client | MUST | elicitation | “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.” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#safe-url-handling | n/a | yes — url questions must not route to the agent audience | |
| elicitation-client-highlight-domain | 2025-11-25 – 2026-07-28 | client | SHOULD | elicitation | “SHOULD highlight the domain of the URL to mitigate subdomain spoofing.” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#safe-url-handling | n/a | yes | |
| elicitation-client-warn-punycode | 2025-11-25 – 2026-07-28 | client | SHOULD | elicitation | “SHOULD have warnings for ambiguous/suspicious URIs (i.e., containing Punycode).” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#safe-url-handling | n/a | yes | |
| elicitation-client-no-clickable-except-url-field | 2025-11-25 – 2026-07-28 | client | SHOULD NOT | elicitation | “SHOULD NOT render URLs as clickable in any field of an elicitation request, except for the url field in a URL elicitation request” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#safe-url-handling | n/a | yes | |
| elicitation-server-no-trust-client-user-id | 2025-11-25 – 2026-07-28 | server | MUST NOT | elicitation | “Servers MUST NOT rely on client-provided user identification without server verification, as this can be forged.” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#identifying-the-user | yes — GAP-ish: MCPX_SESSION_ID is client-provided; the signed requestState binds to a connection mcpx issued, which is the verification | n/a | |
| elicitation-server-follow-best-practices | 2025-11-25 – 2026-07-28 | server | SHOULD | elicitation | “Instead, servers SHOULD follow security best practices.” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#identifying-the-user | yes | n/a | |
| elicitation-url-verify-opening-user | 2025-11-25 – 2026-07-28 | server | MUST | elicitation | “The MCP Server MUST verify the identity of the user who opens the URL before accepting information.” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#phishing | n/a — mcpx issues no URL; the upstream that does sees mcpx’s identity, not the end user’s | n/a | |
| elicitation-url-same-user-start-and-complete | 2025-11-25 – 2026-07-28 | server | MUST | elicitation | “the server MUST ensure that the user who started the elicitation request … is the same user who completes the authorization flow.” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#phishing | n/a (see Implied: shared pooled upstream) | n/a | |
| elicitation-url-identity-resilient-to-url-tampering | 2025-11-25 – 2026-07-28 | server | MUST | elicitation | “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.” | https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation#phishing | n/a | n/a | |
| elicitation-task-related-id-shared | 2025-11-25 | server | MUST | elicitation | “an elicitation that a task-augmented tool call depends on MUST share the same related task ID with that tool call’s task.” | https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks#associating-task-related-messages | yes — when mcpx forwards an upstream question for a task-augmented downstream call, _meta["io.modelcontextprotocol/related-task"] must name mcpx’s task id, not upstream’s (unverified) | yes — must accept/ignore it | tasks core only in 2025-11-25 |
| mrtr-input-request-type-restricted | 2026-07-28 | server | MUST | mrtr | “inputRequests values are request objects that MUST be one of ElicitRequest, CreateMessageRequest, or ListRootsRequest” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/mrtr#server-requirements-basic-workflow | yes — ping or custom upstream requests cannot be carried downstream in 2026 | yes — others answered -32601 in legacy; in 2026 no slot to refuse | new |
| mrtr-server-reask-missing-rather-than-error | 2026-07-28 | server | SHOULD | mrtr | “the server SHOULD respond with a new InputRequiredResult requesting the missing information again, rather than returning an error.” | https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/mrtr#error-handling | yes | n/a | |
| mrtr-missing-capability-error-32021 | 2026-07-28 | server | MUST | errors (roots/sampling/elicitation) | “If processing a request requires a capability the client did not include in io.modelcontextprotocol/clientCapabilities, the server MUST return a MissingRequiredClientCapabilityError (-32021)” | https://modelcontextprotocol.io/specification/2026-07-28/basic/index#meta | yes — conflicts with mcpx’s broker fallback when the downstream lacks elicitation (see Conflicts) | yes — must surface -32021 from upstream (mcpx always declares elicitation, so should not see it for elicitation) | new |
Folded duplicates
Same requirement found by two sweeps with the same revision range; the second id was dropped in favour of the first.
| dropped | kept |
|---|---|
| stdio-fallback-not-keyed-to-one-code | versioning-fallback-not-keyed-to-one-code |
| streamable-http-client-sends-protocol-version-header | lifecycle-http-protocol-version-header |
| streamable-http-dual-era-client-detect | versioning-dual-era-http-detect |
| cancellation-schema-server-stdio-only-listen | stdio-server-cancelled-only-for-listen |
| mrtr-server-never-initiates | messages-servers-must-not-initiate-requests |
| tools-x-mcp-header-client-reject | streamable-http-client-rejects-invalid-x-mcp-header |
| tools-call-retry-new-id | mrtr-new-id-on-retry |
| resources-updated-only-after-subscribe | subscriptions-resources-updated-only-if-subscribed |
| resources-listen-no-unrequested | subscriptions-only-requested-types |
| resources-listen-subscriptionid | meta-subscription-id-on-listen-notifications |
| meta-missing-required-reject | meta-server-rejects-missing-required-field |
| meta-no-infer-capabilities | meta-server-no-infer-caps-from-prior |
| meta-no-rely-undeclared-cap | meta-server-no-undeclared-client-capabilities |
| meta-missing-cap-error | errors-missing-required-client-capability |
| meta-clientinfo-should | meta-client-should-send-clientinfo |
| meta-serverinfo-every-result | meta-server-should-send-serverinfo |
| meta-info-not-for-behavior | meta-info-not-for-behavior-or-security |
| meta-resulttype-required | messages-resulttype-server-must-include |
| meta-resulttype-absent-is-complete | messages-resulttype-absent-means-complete |
| cache-private-no-shared | caching-private-no-cross-auth |
| discover-must-implement | versioning-server-must-implement-discover |
| discover-dual-client-stdio-first | versioning-dual-era-client-probe-discover-first-stdio |
| mrtr-server-must-use-mrtr-for-client-features | mrtr-server-requests-via-mrtr |
| mrtr-server-no-undeclared-input-requests | mrtr-only-declared-capabilities |
| mrtr-input-required-only-on-three-methods | mrtr-supported-requests-only |
| mrtr-server-must-not-assume-fulfilment | mrtr-no-assume-retry |
| mrtr-client-must-construct-inputs-before-retry | mrtr-client-fulfil-before-retry |
Pairs that look alike but cover different ranges were kept apart on purpose, because the requirement moved page in 2026-07-28 (timeouts moved from lifecycle to cancellation; stdio shutdown moved from lifecycle to transports/stdio).