From ba3f5fa095b48b9ed1fa421fe71eba66b01fc699 Mon Sep 17 00:00:00 2001 From: Alfredo Metere Date: Fri, 22 May 2026 22:10:41 -0700 Subject: [PATCH 1/6] Add SEP-0000: Attested Tool-Server Admission (ATSA) --- seps/0000-attested-tool-server-admission.md | 323 ++++++++++++++++++++ 1 file changed, 323 insertions(+) create mode 100644 seps/0000-attested-tool-server-admission.md diff --git a/seps/0000-attested-tool-server-admission.md b/seps/0000-attested-tool-server-admission.md new file mode 100644 index 000000000..5c4750ec5 --- /dev/null +++ b/seps/0000-attested-tool-server-admission.md @@ -0,0 +1,323 @@ +# SEP-0000: Attested Tool-Server Admission (ATSA) + +- **Status**: Draft +- **Type**: Standards Track +- **Created**: 2026-05-22 +- **Author(s)**: Alfredo Metere (@metereconsulting) <alfredo.metere@enclawed.com>, Enclawed LLC +- **Sponsor**: None (seeking) +- **PR**: (to be assigned — rename this file to `NNNN-attested-tool-server-admission.md` once the PR number is known) +- **Preprint**: doi:10.5281/zenodo.20349263 +- **Requires**: RFC 2119, RFC 8174, RFC 8615 (Well-Known URIs), RFC 8032 (Ed25519) + +The key words **MUST**, **MUST NOT**, **REQUIRED**, **SHALL**, **SHOULD**, +**SHOULD NOT**, **MAY**, and **OPTIONAL** are to be interpreted as in RFC 2119 +and RFC 8174. + +## Abstract + +MCP standardizes how a host and a tool server exchange messages, but not *trust*: +a host reads a server's self-declared tool list and dispatches calls with no +notion of which servers it may use, at what sensitivity, or which of a server's +tools are in bounds. This SEP adds an **optional, purely additive** admission +layer: a server publishes a small, offline-signed *clearance assertion* at a +well-known URI; a host verifies it against a locally pinned trust root before any +tool dispatch; admitting a server is kept distinct from authorizing its tools via +a closed per-server tool allow-list; and every admission decision is auditable. +No existing MCP message changes shape, and an unextended host ignores the +mechanism and behaves exactly as today. + +## Motivation + +A host today takes a server's identity (beyond its TLS certificate) and its +advertised tool list on faith. A prompt-injected model can therefore drive a +destructive tool on any server it connects to. This is exploitable in **every** +deployment; for a single operator it is a risk they absorb, but for a regulated +operator it is disqualifying — and, lacking any admission record, unauditable. +NIST SP 800-53 expects least-privilege access enforcement (AC-3/AC-6), +information-flow enforcement between sensitivity levels (AC-4), and an audit +record of access decisions (AU-2/AU-9); none can be satisfied if the host has no +notion of which server is which, at what level, or which tools are in bounds. + +The existing specification provides no place to express any of this. TLS proves +the host reached the named endpoint; MCP's authorization profile proves the user +may use the server; neither answers the missing third question — *is this server +one the host is authorized to use as a tool provider, and at what sensitivity?* + +## Specification + +### Discovery + +A server **MAY** advertise an attestation two interoperable ways: + +1. **Well-known resource.** The server **SHOULD** serve a *Server Attestation + Document* (SAD) at `/.well-known/mcp-attestation` on the same origin as its + MCP endpoint, over TLS. +2. **In-band.** A server **MAY** return the SAD in the `initialize` result under + an experimental capability key. + +A conforming host **MUST** attempt (1), **MAY** attempt (2), and **MUST** treat +the absence of both as *unattested*, applying its configured posture (see +*Backward Compatibility*). + +### Server Attestation Document (SAD) + +A JSON object. **REQUIRED** fields: `v` (integer `1`); `id` (stable server +identity); `publisher`; `version`; `clearance` (a canonical name or alias of a +level in a named, totally ordered classification scheme); `capabilities` (string +array that **MUST** contain `"mcp-server"`); `signerKeyId` (identifies a key in +the host trust root); `signature` (base64 detached signature over the canonical +body). **OPTIONAL**, and part of the signed body when present: `netAllowedHosts` +(string array — when non-empty, binds the SAD to those origins) and +`verification` (string, e.g. `"tested"`). Verifiers **MUST** ignore unknown +fields and **MUST NOT** include them in the canonical body until a future `v` +registers them. (Formal JSON Schema: see the reference implementation.) + +### Canonicalization and signature + +The canonical body is the deterministic JSON serialization of every registered +field except `signature`, with object keys in sorted order, array members +sorted, and an absent `signerKeyId` serialized as `null`. Signer and verifier +**MUST** compute the signature over exactly these bytes. The reference profile +uses Ed25519; a profile **MAY** substitute another suite if signer and verifier +agree. + +### Host verification rules + +Before treating a connection as *admitted*, a host **MUST** evaluate the +following in order and **MUST** deny on the first failure: + +1. the SAD parses and its `capabilities` contain `"mcp-server"`; +2. `signerKeyId` and `signature` are present; +3. `signerKeyId` resolves to a key in the trust root; +4. that key's validity window (`notAfter`, if set) includes now; +5. the key is approved for the asserted `clearance`; +6. the `signature` verifies over the canonical body; +7. `clearance` dominates the host's required level (numeric rank comparison); +8. if `netAllowedHosts` is non-empty, the connected origin is a member. + +A host in a deny-by-default (high-assurance) posture **MUST** reject an +unattested or failing server; a permissive host **SHOULD** surface the failure +and **MUST NOT** silently treat it as success. + +### Tool authorization + +Admitting a server **MUST NOT** be read as authorizing all its tools. A host +**SHOULD** keep a per-server allow-list and **MUST** deny a `tools/call` for any +tool absent from it *before* any network dispatch, regardless of what +`tools/list` advertises. Per-tool `clearance` **MAY** be added in a future `v`. + +### Audit + +A conforming host **SHOULD** append a tamper-evident record for every admission +decision (allow / deny / warn) and every tool-authorization denial, carrying the +resolved `signerKeyId`/`clearance` or the denial reason. + +### Trust establishment + +How the trust root is provisioned, pinned, and sealed is **deployment policy and +out of scope of this wire format**. Profiles **MAY** anchor it in a pinned key +set, X.509 chains, SPIFFE SVIDs, or a sigstore-style transparency log; the +verification rules are independent of the choice. + +### Error signalling + +When a host rejects a server for an attestation reason and surfaces it in-band, +it **SHOULD** carry a machine-readable `data.reason`, one per verification rule: +`not_mcp_server` (1), `unsigned` (2), `signer_not_trusted` (3), `signer_expired` +(4), `signer_not_approved` (5), `bad_signature` (6), `below_required` (7), +`host_not_bound` (8), and `tool_not_admitted` (tool authorization). + +### Compatibility, versioning, negotiation + +`v` versions the document; a verifier **MUST** reject versions it does not +understand. The extension is purely additive: an unextended host never fetches +the SAD, an unextended server never sees the host-side allow-list, and a host +**MUST** interoperate with unattested servers under its posture — enabling +incremental rollout. + +## Rationale + +### Why a spec extension rather than a per-vendor layer + +The mechanism can be implemented above MCP today — but *additive* is not +*interoperable*. Bolted on by one vendor, attestation secures only that vendor's +island; a server's signed clearance document is meaningful only to hosts that +already agreed, out of band, on its shape and verification order. The payoff +("this server is attested" as a claim any host can check; servers publishing one +document instead of N vendor dialects; SDKs shipping the gate on by default) only +materializes once a single format is agreed, and only the spec owner can mint +that Schelling point. That the mechanism rides entirely above MCP is what makes +adoption cheap and low-risk, not a reason to defer it. + +### Design decisions + +- **Offline, detached signature.** Admission requires no online call to a third + party; the host verifies against a locally pinned trust root. This keeps + admission available and fast and avoids a runtime dependency on the signer's + infrastructure. +- **Well-known URI for discovery.** A host can evaluate admission *before* + committing to a session, and the mechanism rides the established RFC 8615 + pattern instead of inventing a new one. +- **Admission separated from tool authorization.** Admitting a server says + nothing about which of its tools are in bounds. The closed per-server + allow-list is enforced before any network dispatch, defeating a prompt-injected + model that requests a tool the server advertises but the host never approved. +- **Numeric clearance ranks in a named, totally ordered scheme.** Dominance is a + single comparison; naming the scheme lets different sensitivity vocabularies + (government, healthcare, finance) coexist and interoperate. +- **Canonicalization fixes the signed bytes.** Sorted keys, sorted arrays, absent + `signerKeyId` as `null`, `signature` excluded — so signer and verifier agree on + exactly what was signed regardless of JSON serializer. + +### Alternatives considered + +- **Leave it to each vendor / keep it an extension only.** Rejected: additive ≠ + interoperable (above). Extensions are the right place to *experiment*; this + pattern has finished experimenting (production + evaluation), and its remaining + value is gated on a single agreed format that only the spec can supply. +- **In-band capability only, no well-known document.** Rejected: discovery must be + possible *before* a connection is trusted, but `initialize` already implies a + session. The well-known fetch lets a host decide admission before it commits. +- **mTLS / client certificates.** Rejected: TLS answers "did I reach the named + endpoint," not "is this server cleared to operate at this sensitivity, and which + of its tools are in bounds." Orthogonal; ATSA composes with it. +- **OAuth-style bearer token.** Rejected: that is *user*-authorization ("may this + user use this server"), a different question from host admission ("may this host + use this server as a tool provider, at what level"). ATSA composes with MCP's + authorization profile. +- **Trusting `clearance` embedded in `tools/list`.** Rejected: the tool list is + unsigned and self-declared; trust cannot rest on it. The signed SAD is the + anchor; the allow-list is host-side state. +- **Online (OCSP-style) revocation as a v1 requirement.** Deferred: it adds an + availability dependency at admission time. v1 enforces per-signer `notAfter`; + online revocation is future work (see *Open questions*). + +### Related work + +- **Artifact attestation.** sigstore, The Update Framework (TUF), and in-toto + apply "verify a signed claim against a trusted root before use" to software + supply chains. ATSA applies the same discipline to MCP server admission. +- **Well-known discovery precedent.** OAuth 2.0 Authorization Server Metadata + (RFC 8414), `security.txt` (RFC 9116), and OpenID Connect Discovery all ride + RFC 8615 without forking the base protocols they extend. + +### Design-principles alignment + +This proposal is written against the MCP [design +principles](https://modelcontextprotocol.io/community/design-principles): + +- **Demonstration over deliberation.** The mechanism is in production in the open + `enclawed-oss` distribution, with a JSON Schema, conformance vectors, 48 + hermetic tests, an LLM-driven adversarial campaign (27,025 tool-name evasions + + 14,378 forged assertions, all denied), and a live Google Workspace end-to-end + run. The SEP is written from what the prototype taught, not from theory. +- **Standardization over innovation.** ATSA codifies a pattern already proven in a + shipping host/server pair; it invents no new primitive. The + signed-document-at-a-well-known-URI shape is the one OAuth metadata, + `security.txt`, and OpenID discovery already use. +- **Convergence over choice.** One signed-attestation format, one verification + ordering — so "this server is attested" becomes a claim *any* host can check and + a server publishes *once*, instead of N mutually unintelligible vendor dialects. + Only the spec owner can mint that single path. +- **Interoperability over optimization.** It degrades gracefully: capability + negotiation gates in-band discovery, an unextended host never fetches the SAD, + an unextended server never sees the allow-list, and a conforming host **MUST** + still interoperate with unattested servers under its configured posture. Nothing + requires every participant to be equally capable. +- **Composability over specificity** *(objection addressed).* A reviewer may ask + whether this can be built from existing primitives. It can — and is, today, + above MCP — which is exactly why adoption is cheap. But composability gives each + vendor an island, not interoperability: a server cannot publish one document + every host understands until the shape and verification order are agreed in one + place. The SEP adds exactly one document and one ordering — the minimum that + turns a per-vendor capability into an ecosystem one. +- **Stability over velocity** *(objection addressed).* Because the addition is + permanent, it is deliberately small: one well-known document, one optional + `initialize` capability, zero changes to any existing message. An unextended + implementation is byte-for-byte unaffected, so the permanent cost to client + implementers is bounded to those who opt in. +- **Capability over compensation.** ATSA does not compensate for a temporary model + weakness. A more capable model that is prompt-injected is *more* dangerous, not + less; the trust and authorization gap it closes is independent of model quality + and does not fade as models improve. +- **Pragmatism over purity.** Trust-root provisioning is left to deployment policy + rather than mandated, because operators' PKI realities differ. The wire format + is fixed; the anchoring is not. + +## Backward Compatibility + +None broken. The SAD lives at a well-known URI (RFC 8615); the tool allow-list is +host-side state; no existing MCP message changes shape. This is the additive +discipline that let OAuth, `security.txt`, and OpenID discovery ride the +well-known mechanism without forking the protocols they extended. A host with no +required level and an empty allow-list policy behaves exactly as a host does +today. + +## Security Implications + +The design resists confused-deputy tool invocation (tool authorization), server +impersonation and cross-origin replay (rules 3/6/8), level escalation (the level +is inside the signed body), and signer-key aging (rule 4). Out of scope and +delegated to other layers: content inspection of admitted connections, and the +behavior of a correctly-admitted, correctly-cleared server within its allowed +tools. The trust root is the root of all guarantees; its provisioning and sealing +are deployment policy (see *Trust establishment*), and a compromised signer key +is bounded by `notAfter` until online revocation (future work) lands. + +## Reference Implementation + +A production reference implementation ships in the open `enclawed-oss` +distribution — — at +`extensions/mcp-attested` (with a first-party Google Workspace bridge at +`extensions/mcp-google-workspace`). It includes a JSON Schema, an error registry, +and machine-checkable conformance vectors. + +### Prototype and evaluation + +Per the SEP process (explore → prototype → write the SEP from what the prototype +taught): the mechanism is implemented and in production, and is evaluated in the +companion preprint. Every stated guarantee is backed by an executable test driven +by an LLM-generated adversarial corpus: + +- **48 hermetic tests** (44 under `vitest`, 4 under `node:test`) exercise every + verification rule and the tool-authorization rule. +- A local-LLM (Ollama) **coverage campaign** generated **27,025 unique tool-name + evasions** (case/Unicode/whitespace/separator/path/near-miss tricks) — all + denied, zero leaked network writes — and **14,378 unique forged clearance + assertions** — all rejected. +- A **live end-to-end** run drove a real Google Workspace MCP endpoint through the + gate: the allow-listed tool was admitted and dispatched; out-of-allow-list tools + were denied before any network call. + +### Conformance (prerequisite for Final) + +Per [SEP-2484](https://modelcontextprotocol.io/seps/2484-conformance-tests-required-for-final-seps), +a Standards Track SEP with observable protocol behavior must, before reaching +`Final`, land a conformance scenario in the +[conformance repository](https://github.com/modelcontextprotocol/conformance) +plus a `sep-NNNN.yaml` traceability file mapping every MUST/MUST NOT and +SHOULD/SHOULD NOT in this *Specification* to a check ID. This SEP is written to +make that mechanical: each verification rule (1–8), the tool-authorization rule, +and the audit and versioning requirements are already enumerated as +machine-checkable conformance vectors in the reference implementation. The +traceability file and scenario will be supplied against the draft spec-version tag +once a sponsor is engaged and the SEP number is assigned. + +## Open questions / future work + +- Per-tool (vs. per-server) clearance. +- A short-lived `notBefore`/expiry on the assertion itself and an online + (OCSP-style) revocation channel for compromised signer keys, beyond the + per-signer `notAfter` already enforced. +- Reconciling the `clearance` field with MCP's evolving authorization profile and + capability-negotiation handshake. + +## References + +- Companion preprint: *Attested Tool-Server Admission: A Security Extension to the + Model Context Protocol* — archived at Zenodo, doi:10.5281/zenodo.20349263 + (arXiv ID forthcoming; PDF in this package). +- RFC 2119 / RFC 8174 (requirement keywords), RFC 8414 (OAuth AS Metadata), + RFC 8615 (Well-Known URIs), RFC 8032 (Ed25519), RFC 9116 (`security.txt`). +- Reference implementation: — + `extensions/mcp-attested`. From a0229bfb42039ed58232793b33d277daa722705a Mon Sep 17 00:00:00 2001 From: Alfredo Metere Date: Fri, 22 May 2026 22:14:00 -0700 Subject: [PATCH 2/6] Rename SEP to assigned number 2777; set heading + PR link --- seps/2777-attested-tool-server-admission.md | 323 ++++++++++++++++++++ 1 file changed, 323 insertions(+) create mode 100644 seps/2777-attested-tool-server-admission.md diff --git a/seps/2777-attested-tool-server-admission.md b/seps/2777-attested-tool-server-admission.md new file mode 100644 index 000000000..8e15c25b2 --- /dev/null +++ b/seps/2777-attested-tool-server-admission.md @@ -0,0 +1,323 @@ +# SEP-2777: Attested Tool-Server Admission (ATSA) + +- **Status**: Draft +- **Type**: Standards Track +- **Created**: 2026-05-22 +- **Author(s)**: Alfredo Metere (@metereconsulting) <alfredo.metere@enclawed.com>, Enclawed LLC +- **Sponsor**: None (seeking) +- **PR**: https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2777 +- **Preprint**: doi:10.5281/zenodo.20349263 +- **Requires**: RFC 2119, RFC 8174, RFC 8615 (Well-Known URIs), RFC 8032 (Ed25519) + +The key words **MUST**, **MUST NOT**, **REQUIRED**, **SHALL**, **SHOULD**, +**SHOULD NOT**, **MAY**, and **OPTIONAL** are to be interpreted as in RFC 2119 +and RFC 8174. + +## Abstract + +MCP standardizes how a host and a tool server exchange messages, but not *trust*: +a host reads a server's self-declared tool list and dispatches calls with no +notion of which servers it may use, at what sensitivity, or which of a server's +tools are in bounds. This SEP adds an **optional, purely additive** admission +layer: a server publishes a small, offline-signed *clearance assertion* at a +well-known URI; a host verifies it against a locally pinned trust root before any +tool dispatch; admitting a server is kept distinct from authorizing its tools via +a closed per-server tool allow-list; and every admission decision is auditable. +No existing MCP message changes shape, and an unextended host ignores the +mechanism and behaves exactly as today. + +## Motivation + +A host today takes a server's identity (beyond its TLS certificate) and its +advertised tool list on faith. A prompt-injected model can therefore drive a +destructive tool on any server it connects to. This is exploitable in **every** +deployment; for a single operator it is a risk they absorb, but for a regulated +operator it is disqualifying — and, lacking any admission record, unauditable. +NIST SP 800-53 expects least-privilege access enforcement (AC-3/AC-6), +information-flow enforcement between sensitivity levels (AC-4), and an audit +record of access decisions (AU-2/AU-9); none can be satisfied if the host has no +notion of which server is which, at what level, or which tools are in bounds. + +The existing specification provides no place to express any of this. TLS proves +the host reached the named endpoint; MCP's authorization profile proves the user +may use the server; neither answers the missing third question — *is this server +one the host is authorized to use as a tool provider, and at what sensitivity?* + +## Specification + +### Discovery + +A server **MAY** advertise an attestation two interoperable ways: + +1. **Well-known resource.** The server **SHOULD** serve a *Server Attestation + Document* (SAD) at `/.well-known/mcp-attestation` on the same origin as its + MCP endpoint, over TLS. +2. **In-band.** A server **MAY** return the SAD in the `initialize` result under + an experimental capability key. + +A conforming host **MUST** attempt (1), **MAY** attempt (2), and **MUST** treat +the absence of both as *unattested*, applying its configured posture (see +*Backward Compatibility*). + +### Server Attestation Document (SAD) + +A JSON object. **REQUIRED** fields: `v` (integer `1`); `id` (stable server +identity); `publisher`; `version`; `clearance` (a canonical name or alias of a +level in a named, totally ordered classification scheme); `capabilities` (string +array that **MUST** contain `"mcp-server"`); `signerKeyId` (identifies a key in +the host trust root); `signature` (base64 detached signature over the canonical +body). **OPTIONAL**, and part of the signed body when present: `netAllowedHosts` +(string array — when non-empty, binds the SAD to those origins) and +`verification` (string, e.g. `"tested"`). Verifiers **MUST** ignore unknown +fields and **MUST NOT** include them in the canonical body until a future `v` +registers them. (Formal JSON Schema: see the reference implementation.) + +### Canonicalization and signature + +The canonical body is the deterministic JSON serialization of every registered +field except `signature`, with object keys in sorted order, array members +sorted, and an absent `signerKeyId` serialized as `null`. Signer and verifier +**MUST** compute the signature over exactly these bytes. The reference profile +uses Ed25519; a profile **MAY** substitute another suite if signer and verifier +agree. + +### Host verification rules + +Before treating a connection as *admitted*, a host **MUST** evaluate the +following in order and **MUST** deny on the first failure: + +1. the SAD parses and its `capabilities` contain `"mcp-server"`; +2. `signerKeyId` and `signature` are present; +3. `signerKeyId` resolves to a key in the trust root; +4. that key's validity window (`notAfter`, if set) includes now; +5. the key is approved for the asserted `clearance`; +6. the `signature` verifies over the canonical body; +7. `clearance` dominates the host's required level (numeric rank comparison); +8. if `netAllowedHosts` is non-empty, the connected origin is a member. + +A host in a deny-by-default (high-assurance) posture **MUST** reject an +unattested or failing server; a permissive host **SHOULD** surface the failure +and **MUST NOT** silently treat it as success. + +### Tool authorization + +Admitting a server **MUST NOT** be read as authorizing all its tools. A host +**SHOULD** keep a per-server allow-list and **MUST** deny a `tools/call` for any +tool absent from it *before* any network dispatch, regardless of what +`tools/list` advertises. Per-tool `clearance` **MAY** be added in a future `v`. + +### Audit + +A conforming host **SHOULD** append a tamper-evident record for every admission +decision (allow / deny / warn) and every tool-authorization denial, carrying the +resolved `signerKeyId`/`clearance` or the denial reason. + +### Trust establishment + +How the trust root is provisioned, pinned, and sealed is **deployment policy and +out of scope of this wire format**. Profiles **MAY** anchor it in a pinned key +set, X.509 chains, SPIFFE SVIDs, or a sigstore-style transparency log; the +verification rules are independent of the choice. + +### Error signalling + +When a host rejects a server for an attestation reason and surfaces it in-band, +it **SHOULD** carry a machine-readable `data.reason`, one per verification rule: +`not_mcp_server` (1), `unsigned` (2), `signer_not_trusted` (3), `signer_expired` +(4), `signer_not_approved` (5), `bad_signature` (6), `below_required` (7), +`host_not_bound` (8), and `tool_not_admitted` (tool authorization). + +### Compatibility, versioning, negotiation + +`v` versions the document; a verifier **MUST** reject versions it does not +understand. The extension is purely additive: an unextended host never fetches +the SAD, an unextended server never sees the host-side allow-list, and a host +**MUST** interoperate with unattested servers under its posture — enabling +incremental rollout. + +## Rationale + +### Why a spec extension rather than a per-vendor layer + +The mechanism can be implemented above MCP today — but *additive* is not +*interoperable*. Bolted on by one vendor, attestation secures only that vendor's +island; a server's signed clearance document is meaningful only to hosts that +already agreed, out of band, on its shape and verification order. The payoff +("this server is attested" as a claim any host can check; servers publishing one +document instead of N vendor dialects; SDKs shipping the gate on by default) only +materializes once a single format is agreed, and only the spec owner can mint +that Schelling point. That the mechanism rides entirely above MCP is what makes +adoption cheap and low-risk, not a reason to defer it. + +### Design decisions + +- **Offline, detached signature.** Admission requires no online call to a third + party; the host verifies against a locally pinned trust root. This keeps + admission available and fast and avoids a runtime dependency on the signer's + infrastructure. +- **Well-known URI for discovery.** A host can evaluate admission *before* + committing to a session, and the mechanism rides the established RFC 8615 + pattern instead of inventing a new one. +- **Admission separated from tool authorization.** Admitting a server says + nothing about which of its tools are in bounds. The closed per-server + allow-list is enforced before any network dispatch, defeating a prompt-injected + model that requests a tool the server advertises but the host never approved. +- **Numeric clearance ranks in a named, totally ordered scheme.** Dominance is a + single comparison; naming the scheme lets different sensitivity vocabularies + (government, healthcare, finance) coexist and interoperate. +- **Canonicalization fixes the signed bytes.** Sorted keys, sorted arrays, absent + `signerKeyId` as `null`, `signature` excluded — so signer and verifier agree on + exactly what was signed regardless of JSON serializer. + +### Alternatives considered + +- **Leave it to each vendor / keep it an extension only.** Rejected: additive ≠ + interoperable (above). Extensions are the right place to *experiment*; this + pattern has finished experimenting (production + evaluation), and its remaining + value is gated on a single agreed format that only the spec can supply. +- **In-band capability only, no well-known document.** Rejected: discovery must be + possible *before* a connection is trusted, but `initialize` already implies a + session. The well-known fetch lets a host decide admission before it commits. +- **mTLS / client certificates.** Rejected: TLS answers "did I reach the named + endpoint," not "is this server cleared to operate at this sensitivity, and which + of its tools are in bounds." Orthogonal; ATSA composes with it. +- **OAuth-style bearer token.** Rejected: that is *user*-authorization ("may this + user use this server"), a different question from host admission ("may this host + use this server as a tool provider, at what level"). ATSA composes with MCP's + authorization profile. +- **Trusting `clearance` embedded in `tools/list`.** Rejected: the tool list is + unsigned and self-declared; trust cannot rest on it. The signed SAD is the + anchor; the allow-list is host-side state. +- **Online (OCSP-style) revocation as a v1 requirement.** Deferred: it adds an + availability dependency at admission time. v1 enforces per-signer `notAfter`; + online revocation is future work (see *Open questions*). + +### Related work + +- **Artifact attestation.** sigstore, The Update Framework (TUF), and in-toto + apply "verify a signed claim against a trusted root before use" to software + supply chains. ATSA applies the same discipline to MCP server admission. +- **Well-known discovery precedent.** OAuth 2.0 Authorization Server Metadata + (RFC 8414), `security.txt` (RFC 9116), and OpenID Connect Discovery all ride + RFC 8615 without forking the base protocols they extend. + +### Design-principles alignment + +This proposal is written against the MCP [design +principles](https://modelcontextprotocol.io/community/design-principles): + +- **Demonstration over deliberation.** The mechanism is in production in the open + `enclawed-oss` distribution, with a JSON Schema, conformance vectors, 48 + hermetic tests, an LLM-driven adversarial campaign (27,025 tool-name evasions + + 14,378 forged assertions, all denied), and a live Google Workspace end-to-end + run. The SEP is written from what the prototype taught, not from theory. +- **Standardization over innovation.** ATSA codifies a pattern already proven in a + shipping host/server pair; it invents no new primitive. The + signed-document-at-a-well-known-URI shape is the one OAuth metadata, + `security.txt`, and OpenID discovery already use. +- **Convergence over choice.** One signed-attestation format, one verification + ordering — so "this server is attested" becomes a claim *any* host can check and + a server publishes *once*, instead of N mutually unintelligible vendor dialects. + Only the spec owner can mint that single path. +- **Interoperability over optimization.** It degrades gracefully: capability + negotiation gates in-band discovery, an unextended host never fetches the SAD, + an unextended server never sees the allow-list, and a conforming host **MUST** + still interoperate with unattested servers under its configured posture. Nothing + requires every participant to be equally capable. +- **Composability over specificity** *(objection addressed).* A reviewer may ask + whether this can be built from existing primitives. It can — and is, today, + above MCP — which is exactly why adoption is cheap. But composability gives each + vendor an island, not interoperability: a server cannot publish one document + every host understands until the shape and verification order are agreed in one + place. The SEP adds exactly one document and one ordering — the minimum that + turns a per-vendor capability into an ecosystem one. +- **Stability over velocity** *(objection addressed).* Because the addition is + permanent, it is deliberately small: one well-known document, one optional + `initialize` capability, zero changes to any existing message. An unextended + implementation is byte-for-byte unaffected, so the permanent cost to client + implementers is bounded to those who opt in. +- **Capability over compensation.** ATSA does not compensate for a temporary model + weakness. A more capable model that is prompt-injected is *more* dangerous, not + less; the trust and authorization gap it closes is independent of model quality + and does not fade as models improve. +- **Pragmatism over purity.** Trust-root provisioning is left to deployment policy + rather than mandated, because operators' PKI realities differ. The wire format + is fixed; the anchoring is not. + +## Backward Compatibility + +None broken. The SAD lives at a well-known URI (RFC 8615); the tool allow-list is +host-side state; no existing MCP message changes shape. This is the additive +discipline that let OAuth, `security.txt`, and OpenID discovery ride the +well-known mechanism without forking the protocols they extended. A host with no +required level and an empty allow-list policy behaves exactly as a host does +today. + +## Security Implications + +The design resists confused-deputy tool invocation (tool authorization), server +impersonation and cross-origin replay (rules 3/6/8), level escalation (the level +is inside the signed body), and signer-key aging (rule 4). Out of scope and +delegated to other layers: content inspection of admitted connections, and the +behavior of a correctly-admitted, correctly-cleared server within its allowed +tools. The trust root is the root of all guarantees; its provisioning and sealing +are deployment policy (see *Trust establishment*), and a compromised signer key +is bounded by `notAfter` until online revocation (future work) lands. + +## Reference Implementation + +A production reference implementation ships in the open `enclawed-oss` +distribution — — at +`extensions/mcp-attested` (with a first-party Google Workspace bridge at +`extensions/mcp-google-workspace`). It includes a JSON Schema, an error registry, +and machine-checkable conformance vectors. + +### Prototype and evaluation + +Per the SEP process (explore → prototype → write the SEP from what the prototype +taught): the mechanism is implemented and in production, and is evaluated in the +companion preprint. Every stated guarantee is backed by an executable test driven +by an LLM-generated adversarial corpus: + +- **48 hermetic tests** (44 under `vitest`, 4 under `node:test`) exercise every + verification rule and the tool-authorization rule. +- A local-LLM (Ollama) **coverage campaign** generated **27,025 unique tool-name + evasions** (case/Unicode/whitespace/separator/path/near-miss tricks) — all + denied, zero leaked network writes — and **14,378 unique forged clearance + assertions** — all rejected. +- A **live end-to-end** run drove a real Google Workspace MCP endpoint through the + gate: the allow-listed tool was admitted and dispatched; out-of-allow-list tools + were denied before any network call. + +### Conformance (prerequisite for Final) + +Per [SEP-2484](https://modelcontextprotocol.io/seps/2484-conformance-tests-required-for-final-seps), +a Standards Track SEP with observable protocol behavior must, before reaching +`Final`, land a conformance scenario in the +[conformance repository](https://github.com/modelcontextprotocol/conformance) +plus a `sep-NNNN.yaml` traceability file mapping every MUST/MUST NOT and +SHOULD/SHOULD NOT in this *Specification* to a check ID. This SEP is written to +make that mechanical: each verification rule (1–8), the tool-authorization rule, +and the audit and versioning requirements are already enumerated as +machine-checkable conformance vectors in the reference implementation. The +traceability file and scenario will be supplied against the draft spec-version tag +once a sponsor is engaged and the SEP number is assigned. + +## Open questions / future work + +- Per-tool (vs. per-server) clearance. +- A short-lived `notBefore`/expiry on the assertion itself and an online + (OCSP-style) revocation channel for compromised signer keys, beyond the + per-signer `notAfter` already enforced. +- Reconciling the `clearance` field with MCP's evolving authorization profile and + capability-negotiation handshake. + +## References + +- Companion preprint: *Attested Tool-Server Admission: A Security Extension to the + Model Context Protocol* — archived at Zenodo, doi:10.5281/zenodo.20349263 + (arXiv ID forthcoming; PDF in this package). +- RFC 2119 / RFC 8174 (requirement keywords), RFC 8414 (OAuth AS Metadata), + RFC 8615 (Well-Known URIs), RFC 8032 (Ed25519), RFC 9116 (`security.txt`). +- Reference implementation: — + `extensions/mcp-attested`. From 9b1ef6ac7f5b728cc260be69b5e672a8009fb781 Mon Sep 17 00:00:00 2001 From: Alfredo Metere Date: Fri, 22 May 2026 22:14:02 -0700 Subject: [PATCH 3/6] Remove 0000 placeholder (renamed to 2777) --- seps/0000-attested-tool-server-admission.md | 323 -------------------- 1 file changed, 323 deletions(-) delete mode 100644 seps/0000-attested-tool-server-admission.md diff --git a/seps/0000-attested-tool-server-admission.md b/seps/0000-attested-tool-server-admission.md deleted file mode 100644 index 5c4750ec5..000000000 --- a/seps/0000-attested-tool-server-admission.md +++ /dev/null @@ -1,323 +0,0 @@ -# SEP-0000: Attested Tool-Server Admission (ATSA) - -- **Status**: Draft -- **Type**: Standards Track -- **Created**: 2026-05-22 -- **Author(s)**: Alfredo Metere (@metereconsulting) <alfredo.metere@enclawed.com>, Enclawed LLC -- **Sponsor**: None (seeking) -- **PR**: (to be assigned — rename this file to `NNNN-attested-tool-server-admission.md` once the PR number is known) -- **Preprint**: doi:10.5281/zenodo.20349263 -- **Requires**: RFC 2119, RFC 8174, RFC 8615 (Well-Known URIs), RFC 8032 (Ed25519) - -The key words **MUST**, **MUST NOT**, **REQUIRED**, **SHALL**, **SHOULD**, -**SHOULD NOT**, **MAY**, and **OPTIONAL** are to be interpreted as in RFC 2119 -and RFC 8174. - -## Abstract - -MCP standardizes how a host and a tool server exchange messages, but not *trust*: -a host reads a server's self-declared tool list and dispatches calls with no -notion of which servers it may use, at what sensitivity, or which of a server's -tools are in bounds. This SEP adds an **optional, purely additive** admission -layer: a server publishes a small, offline-signed *clearance assertion* at a -well-known URI; a host verifies it against a locally pinned trust root before any -tool dispatch; admitting a server is kept distinct from authorizing its tools via -a closed per-server tool allow-list; and every admission decision is auditable. -No existing MCP message changes shape, and an unextended host ignores the -mechanism and behaves exactly as today. - -## Motivation - -A host today takes a server's identity (beyond its TLS certificate) and its -advertised tool list on faith. A prompt-injected model can therefore drive a -destructive tool on any server it connects to. This is exploitable in **every** -deployment; for a single operator it is a risk they absorb, but for a regulated -operator it is disqualifying — and, lacking any admission record, unauditable. -NIST SP 800-53 expects least-privilege access enforcement (AC-3/AC-6), -information-flow enforcement between sensitivity levels (AC-4), and an audit -record of access decisions (AU-2/AU-9); none can be satisfied if the host has no -notion of which server is which, at what level, or which tools are in bounds. - -The existing specification provides no place to express any of this. TLS proves -the host reached the named endpoint; MCP's authorization profile proves the user -may use the server; neither answers the missing third question — *is this server -one the host is authorized to use as a tool provider, and at what sensitivity?* - -## Specification - -### Discovery - -A server **MAY** advertise an attestation two interoperable ways: - -1. **Well-known resource.** The server **SHOULD** serve a *Server Attestation - Document* (SAD) at `/.well-known/mcp-attestation` on the same origin as its - MCP endpoint, over TLS. -2. **In-band.** A server **MAY** return the SAD in the `initialize` result under - an experimental capability key. - -A conforming host **MUST** attempt (1), **MAY** attempt (2), and **MUST** treat -the absence of both as *unattested*, applying its configured posture (see -*Backward Compatibility*). - -### Server Attestation Document (SAD) - -A JSON object. **REQUIRED** fields: `v` (integer `1`); `id` (stable server -identity); `publisher`; `version`; `clearance` (a canonical name or alias of a -level in a named, totally ordered classification scheme); `capabilities` (string -array that **MUST** contain `"mcp-server"`); `signerKeyId` (identifies a key in -the host trust root); `signature` (base64 detached signature over the canonical -body). **OPTIONAL**, and part of the signed body when present: `netAllowedHosts` -(string array — when non-empty, binds the SAD to those origins) and -`verification` (string, e.g. `"tested"`). Verifiers **MUST** ignore unknown -fields and **MUST NOT** include them in the canonical body until a future `v` -registers them. (Formal JSON Schema: see the reference implementation.) - -### Canonicalization and signature - -The canonical body is the deterministic JSON serialization of every registered -field except `signature`, with object keys in sorted order, array members -sorted, and an absent `signerKeyId` serialized as `null`. Signer and verifier -**MUST** compute the signature over exactly these bytes. The reference profile -uses Ed25519; a profile **MAY** substitute another suite if signer and verifier -agree. - -### Host verification rules - -Before treating a connection as *admitted*, a host **MUST** evaluate the -following in order and **MUST** deny on the first failure: - -1. the SAD parses and its `capabilities` contain `"mcp-server"`; -2. `signerKeyId` and `signature` are present; -3. `signerKeyId` resolves to a key in the trust root; -4. that key's validity window (`notAfter`, if set) includes now; -5. the key is approved for the asserted `clearance`; -6. the `signature` verifies over the canonical body; -7. `clearance` dominates the host's required level (numeric rank comparison); -8. if `netAllowedHosts` is non-empty, the connected origin is a member. - -A host in a deny-by-default (high-assurance) posture **MUST** reject an -unattested or failing server; a permissive host **SHOULD** surface the failure -and **MUST NOT** silently treat it as success. - -### Tool authorization - -Admitting a server **MUST NOT** be read as authorizing all its tools. A host -**SHOULD** keep a per-server allow-list and **MUST** deny a `tools/call` for any -tool absent from it *before* any network dispatch, regardless of what -`tools/list` advertises. Per-tool `clearance` **MAY** be added in a future `v`. - -### Audit - -A conforming host **SHOULD** append a tamper-evident record for every admission -decision (allow / deny / warn) and every tool-authorization denial, carrying the -resolved `signerKeyId`/`clearance` or the denial reason. - -### Trust establishment - -How the trust root is provisioned, pinned, and sealed is **deployment policy and -out of scope of this wire format**. Profiles **MAY** anchor it in a pinned key -set, X.509 chains, SPIFFE SVIDs, or a sigstore-style transparency log; the -verification rules are independent of the choice. - -### Error signalling - -When a host rejects a server for an attestation reason and surfaces it in-band, -it **SHOULD** carry a machine-readable `data.reason`, one per verification rule: -`not_mcp_server` (1), `unsigned` (2), `signer_not_trusted` (3), `signer_expired` -(4), `signer_not_approved` (5), `bad_signature` (6), `below_required` (7), -`host_not_bound` (8), and `tool_not_admitted` (tool authorization). - -### Compatibility, versioning, negotiation - -`v` versions the document; a verifier **MUST** reject versions it does not -understand. The extension is purely additive: an unextended host never fetches -the SAD, an unextended server never sees the host-side allow-list, and a host -**MUST** interoperate with unattested servers under its posture — enabling -incremental rollout. - -## Rationale - -### Why a spec extension rather than a per-vendor layer - -The mechanism can be implemented above MCP today — but *additive* is not -*interoperable*. Bolted on by one vendor, attestation secures only that vendor's -island; a server's signed clearance document is meaningful only to hosts that -already agreed, out of band, on its shape and verification order. The payoff -("this server is attested" as a claim any host can check; servers publishing one -document instead of N vendor dialects; SDKs shipping the gate on by default) only -materializes once a single format is agreed, and only the spec owner can mint -that Schelling point. That the mechanism rides entirely above MCP is what makes -adoption cheap and low-risk, not a reason to defer it. - -### Design decisions - -- **Offline, detached signature.** Admission requires no online call to a third - party; the host verifies against a locally pinned trust root. This keeps - admission available and fast and avoids a runtime dependency on the signer's - infrastructure. -- **Well-known URI for discovery.** A host can evaluate admission *before* - committing to a session, and the mechanism rides the established RFC 8615 - pattern instead of inventing a new one. -- **Admission separated from tool authorization.** Admitting a server says - nothing about which of its tools are in bounds. The closed per-server - allow-list is enforced before any network dispatch, defeating a prompt-injected - model that requests a tool the server advertises but the host never approved. -- **Numeric clearance ranks in a named, totally ordered scheme.** Dominance is a - single comparison; naming the scheme lets different sensitivity vocabularies - (government, healthcare, finance) coexist and interoperate. -- **Canonicalization fixes the signed bytes.** Sorted keys, sorted arrays, absent - `signerKeyId` as `null`, `signature` excluded — so signer and verifier agree on - exactly what was signed regardless of JSON serializer. - -### Alternatives considered - -- **Leave it to each vendor / keep it an extension only.** Rejected: additive ≠ - interoperable (above). Extensions are the right place to *experiment*; this - pattern has finished experimenting (production + evaluation), and its remaining - value is gated on a single agreed format that only the spec can supply. -- **In-band capability only, no well-known document.** Rejected: discovery must be - possible *before* a connection is trusted, but `initialize` already implies a - session. The well-known fetch lets a host decide admission before it commits. -- **mTLS / client certificates.** Rejected: TLS answers "did I reach the named - endpoint," not "is this server cleared to operate at this sensitivity, and which - of its tools are in bounds." Orthogonal; ATSA composes with it. -- **OAuth-style bearer token.** Rejected: that is *user*-authorization ("may this - user use this server"), a different question from host admission ("may this host - use this server as a tool provider, at what level"). ATSA composes with MCP's - authorization profile. -- **Trusting `clearance` embedded in `tools/list`.** Rejected: the tool list is - unsigned and self-declared; trust cannot rest on it. The signed SAD is the - anchor; the allow-list is host-side state. -- **Online (OCSP-style) revocation as a v1 requirement.** Deferred: it adds an - availability dependency at admission time. v1 enforces per-signer `notAfter`; - online revocation is future work (see *Open questions*). - -### Related work - -- **Artifact attestation.** sigstore, The Update Framework (TUF), and in-toto - apply "verify a signed claim against a trusted root before use" to software - supply chains. ATSA applies the same discipline to MCP server admission. -- **Well-known discovery precedent.** OAuth 2.0 Authorization Server Metadata - (RFC 8414), `security.txt` (RFC 9116), and OpenID Connect Discovery all ride - RFC 8615 without forking the base protocols they extend. - -### Design-principles alignment - -This proposal is written against the MCP [design -principles](https://modelcontextprotocol.io/community/design-principles): - -- **Demonstration over deliberation.** The mechanism is in production in the open - `enclawed-oss` distribution, with a JSON Schema, conformance vectors, 48 - hermetic tests, an LLM-driven adversarial campaign (27,025 tool-name evasions + - 14,378 forged assertions, all denied), and a live Google Workspace end-to-end - run. The SEP is written from what the prototype taught, not from theory. -- **Standardization over innovation.** ATSA codifies a pattern already proven in a - shipping host/server pair; it invents no new primitive. The - signed-document-at-a-well-known-URI shape is the one OAuth metadata, - `security.txt`, and OpenID discovery already use. -- **Convergence over choice.** One signed-attestation format, one verification - ordering — so "this server is attested" becomes a claim *any* host can check and - a server publishes *once*, instead of N mutually unintelligible vendor dialects. - Only the spec owner can mint that single path. -- **Interoperability over optimization.** It degrades gracefully: capability - negotiation gates in-band discovery, an unextended host never fetches the SAD, - an unextended server never sees the allow-list, and a conforming host **MUST** - still interoperate with unattested servers under its configured posture. Nothing - requires every participant to be equally capable. -- **Composability over specificity** *(objection addressed).* A reviewer may ask - whether this can be built from existing primitives. It can — and is, today, - above MCP — which is exactly why adoption is cheap. But composability gives each - vendor an island, not interoperability: a server cannot publish one document - every host understands until the shape and verification order are agreed in one - place. The SEP adds exactly one document and one ordering — the minimum that - turns a per-vendor capability into an ecosystem one. -- **Stability over velocity** *(objection addressed).* Because the addition is - permanent, it is deliberately small: one well-known document, one optional - `initialize` capability, zero changes to any existing message. An unextended - implementation is byte-for-byte unaffected, so the permanent cost to client - implementers is bounded to those who opt in. -- **Capability over compensation.** ATSA does not compensate for a temporary model - weakness. A more capable model that is prompt-injected is *more* dangerous, not - less; the trust and authorization gap it closes is independent of model quality - and does not fade as models improve. -- **Pragmatism over purity.** Trust-root provisioning is left to deployment policy - rather than mandated, because operators' PKI realities differ. The wire format - is fixed; the anchoring is not. - -## Backward Compatibility - -None broken. The SAD lives at a well-known URI (RFC 8615); the tool allow-list is -host-side state; no existing MCP message changes shape. This is the additive -discipline that let OAuth, `security.txt`, and OpenID discovery ride the -well-known mechanism without forking the protocols they extended. A host with no -required level and an empty allow-list policy behaves exactly as a host does -today. - -## Security Implications - -The design resists confused-deputy tool invocation (tool authorization), server -impersonation and cross-origin replay (rules 3/6/8), level escalation (the level -is inside the signed body), and signer-key aging (rule 4). Out of scope and -delegated to other layers: content inspection of admitted connections, and the -behavior of a correctly-admitted, correctly-cleared server within its allowed -tools. The trust root is the root of all guarantees; its provisioning and sealing -are deployment policy (see *Trust establishment*), and a compromised signer key -is bounded by `notAfter` until online revocation (future work) lands. - -## Reference Implementation - -A production reference implementation ships in the open `enclawed-oss` -distribution — — at -`extensions/mcp-attested` (with a first-party Google Workspace bridge at -`extensions/mcp-google-workspace`). It includes a JSON Schema, an error registry, -and machine-checkable conformance vectors. - -### Prototype and evaluation - -Per the SEP process (explore → prototype → write the SEP from what the prototype -taught): the mechanism is implemented and in production, and is evaluated in the -companion preprint. Every stated guarantee is backed by an executable test driven -by an LLM-generated adversarial corpus: - -- **48 hermetic tests** (44 under `vitest`, 4 under `node:test`) exercise every - verification rule and the tool-authorization rule. -- A local-LLM (Ollama) **coverage campaign** generated **27,025 unique tool-name - evasions** (case/Unicode/whitespace/separator/path/near-miss tricks) — all - denied, zero leaked network writes — and **14,378 unique forged clearance - assertions** — all rejected. -- A **live end-to-end** run drove a real Google Workspace MCP endpoint through the - gate: the allow-listed tool was admitted and dispatched; out-of-allow-list tools - were denied before any network call. - -### Conformance (prerequisite for Final) - -Per [SEP-2484](https://modelcontextprotocol.io/seps/2484-conformance-tests-required-for-final-seps), -a Standards Track SEP with observable protocol behavior must, before reaching -`Final`, land a conformance scenario in the -[conformance repository](https://github.com/modelcontextprotocol/conformance) -plus a `sep-NNNN.yaml` traceability file mapping every MUST/MUST NOT and -SHOULD/SHOULD NOT in this *Specification* to a check ID. This SEP is written to -make that mechanical: each verification rule (1–8), the tool-authorization rule, -and the audit and versioning requirements are already enumerated as -machine-checkable conformance vectors in the reference implementation. The -traceability file and scenario will be supplied against the draft spec-version tag -once a sponsor is engaged and the SEP number is assigned. - -## Open questions / future work - -- Per-tool (vs. per-server) clearance. -- A short-lived `notBefore`/expiry on the assertion itself and an online - (OCSP-style) revocation channel for compromised signer keys, beyond the - per-signer `notAfter` already enforced. -- Reconciling the `clearance` field with MCP's evolving authorization profile and - capability-negotiation handshake. - -## References - -- Companion preprint: *Attested Tool-Server Admission: A Security Extension to the - Model Context Protocol* — archived at Zenodo, doi:10.5281/zenodo.20349263 - (arXiv ID forthcoming; PDF in this package). -- RFC 2119 / RFC 8174 (requirement keywords), RFC 8414 (OAuth AS Metadata), - RFC 8615 (Well-Known URIs), RFC 8032 (Ed25519), RFC 9116 (`security.txt`). -- Reference implementation: — - `extensions/mcp-attested`. From 11ce94591155bc23c4c0453498d4492867e8d5a3 Mon Sep 17 00:00:00 2001 From: Alfredo Metere Date: Fri, 22 May 2026 22:26:24 -0700 Subject: [PATCH 4/6] Format SEP with Prettier; generate SEP docs (mdx, index, docs.json) --- docs/docs.json | 3 +- .../2777-attested-tool-server-admission.mdx | 336 ++++++++++++++++++ docs/seps/index.mdx | 3 +- seps/2777-attested-tool-server-admission.md | 52 +-- 4 files changed, 366 insertions(+), 28 deletions(-) create mode 100644 docs/seps/2777-attested-tool-server-admission.mdx diff --git a/docs/docs.json b/docs/docs.json index 281d10280..dbf8cde98 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -455,7 +455,8 @@ "seps/2106-json-schema-2020-12", "seps/2164-resource-not-found-error", "seps/2484-conformance-tests-required-for-final-seps", - "seps/2596-spec-feature-lifecycle-and-deprecation" + "seps/2596-spec-feature-lifecycle-and-deprecation", + "seps/2777-attested-tool-server-admission" ] } ] diff --git a/docs/seps/2777-attested-tool-server-admission.mdx b/docs/seps/2777-attested-tool-server-admission.mdx new file mode 100644 index 000000000..f5ce1e0ac --- /dev/null +++ b/docs/seps/2777-attested-tool-server-admission.mdx @@ -0,0 +1,336 @@ +--- +title: "SEP-2777: Attested Tool-Server Admission (ATSA)" +sidebarTitle: "SEP-2777: Attested Tool-Server Admission (ATSA)" +description: "Attested Tool-Server Admission (ATSA)" +--- + +
+ + Draft + + + Standards Track + +
+ +| Field | Value | +| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **SEP** | 2777 | +| **Title** | Attested Tool-Server Admission (ATSA) | +| **Status** | Draft | +| **Type** | Standards Track | +| **Created** | 2026-05-22 | +| **Author(s)** | Alfredo Metere ([@metereconsulting](https://github.com/metereconsulting)) <alfredo.metere[@enclawed](https://github.com/enclawed).com>, Enclawed LLC | +| **Sponsor** | None (seeking) | +| **PR** | [#2777](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2777) | + +--- + +## Abstract + +MCP standardizes how a host and a tool server exchange messages, but not _trust_: +a host reads a server's self-declared tool list and dispatches calls with no +notion of which servers it may use, at what sensitivity, or which of a server's +tools are in bounds. This SEP adds an **optional, purely additive** admission +layer: a server publishes a small, offline-signed _clearance assertion_ at a +well-known URI; a host verifies it against a locally pinned trust root before any +tool dispatch; admitting a server is kept distinct from authorizing its tools via +a closed per-server tool allow-list; and every admission decision is auditable. +No existing MCP message changes shape, and an unextended host ignores the +mechanism and behaves exactly as today. + +## Motivation + +A host today takes a server's identity (beyond its TLS certificate) and its +advertised tool list on faith. A prompt-injected model can therefore drive a +destructive tool on any server it connects to. This is exploitable in **every** +deployment; for a single operator it is a risk they absorb, but for a regulated +operator it is disqualifying — and, lacking any admission record, unauditable. +NIST SP 800-53 expects least-privilege access enforcement (AC-3/AC-6), +information-flow enforcement between sensitivity levels (AC-4), and an audit +record of access decisions (AU-2/AU-9); none can be satisfied if the host has no +notion of which server is which, at what level, or which tools are in bounds. + +The existing specification provides no place to express any of this. TLS proves +the host reached the named endpoint; MCP's authorization profile proves the user +may use the server; neither answers the missing third question — _is this server +one the host is authorized to use as a tool provider, and at what sensitivity?_ + +## Specification + +### Discovery + +A server **MAY** advertise an attestation two interoperable ways: + +1. **Well-known resource.** The server **SHOULD** serve a _Server Attestation + Document_ (SAD) at `/.well-known/mcp-attestation` on the same origin as its + MCP endpoint, over TLS. +2. **In-band.** A server **MAY** return the SAD in the `initialize` result under + an experimental capability key. + +A conforming host **MUST** attempt (1), **MAY** attempt (2), and **MUST** treat +the absence of both as _unattested_, applying its configured posture (see +_Backward Compatibility_). + +### Server Attestation Document (SAD) + +A JSON object. **REQUIRED** fields: `v` (integer `1`); `id` (stable server +identity); `publisher`; `version`; `clearance` (a canonical name or alias of a +level in a named, totally ordered classification scheme); `capabilities` (string +array that **MUST** contain `"mcp-server"`); `signerKeyId` (identifies a key in +the host trust root); `signature` (base64 detached signature over the canonical +body). **OPTIONAL**, and part of the signed body when present: `netAllowedHosts` +(string array — when non-empty, binds the SAD to those origins) and +`verification` (string, e.g. `"tested"`). Verifiers **MUST** ignore unknown +fields and **MUST NOT** include them in the canonical body until a future `v` +registers them. (Formal JSON Schema: see the reference implementation.) + +### Canonicalization and signature + +The canonical body is the deterministic JSON serialization of every registered +field except `signature`, with object keys in sorted order, array members +sorted, and an absent `signerKeyId` serialized as `null`. Signer and verifier +**MUST** compute the signature over exactly these bytes. The reference profile +uses Ed25519; a profile **MAY** substitute another suite if signer and verifier +agree. + +### Host verification rules + +Before treating a connection as _admitted_, a host **MUST** evaluate the +following in order and **MUST** deny on the first failure: + +1. the SAD parses and its `capabilities` contain `"mcp-server"`; +2. `signerKeyId` and `signature` are present; +3. `signerKeyId` resolves to a key in the trust root; +4. that key's validity window (`notAfter`, if set) includes now; +5. the key is approved for the asserted `clearance`; +6. the `signature` verifies over the canonical body; +7. `clearance` dominates the host's required level (numeric rank comparison); +8. if `netAllowedHosts` is non-empty, the connected origin is a member. + +A host in a deny-by-default (high-assurance) posture **MUST** reject an +unattested or failing server; a permissive host **SHOULD** surface the failure +and **MUST NOT** silently treat it as success. + +### Tool authorization + +Admitting a server **MUST NOT** be read as authorizing all its tools. A host +**SHOULD** keep a per-server allow-list and **MUST** deny a `tools/call` for any +tool absent from it _before_ any network dispatch, regardless of what +`tools/list` advertises. Per-tool `clearance` **MAY** be added in a future `v`. + +### Audit + +A conforming host **SHOULD** append a tamper-evident record for every admission +decision (allow / deny / warn) and every tool-authorization denial, carrying the +resolved `signerKeyId`/`clearance` or the denial reason. + +### Trust establishment + +How the trust root is provisioned, pinned, and sealed is **deployment policy and +out of scope of this wire format**. Profiles **MAY** anchor it in a pinned key +set, X.509 chains, SPIFFE SVIDs, or a sigstore-style transparency log; the +verification rules are independent of the choice. + +### Error signalling + +When a host rejects a server for an attestation reason and surfaces it in-band, +it **SHOULD** carry a machine-readable `data.reason`, one per verification rule: +`not_mcp_server` (1), `unsigned` (2), `signer_not_trusted` (3), `signer_expired` +(4), `signer_not_approved` (5), `bad_signature` (6), `below_required` (7), +`host_not_bound` (8), and `tool_not_admitted` (tool authorization). + +### Compatibility, versioning, negotiation + +`v` versions the document; a verifier **MUST** reject versions it does not +understand. The extension is purely additive: an unextended host never fetches +the SAD, an unextended server never sees the host-side allow-list, and a host +**MUST** interoperate with unattested servers under its posture — enabling +incremental rollout. + +## Rationale + +### Why a spec extension rather than a per-vendor layer + +The mechanism can be implemented above MCP today — but _additive_ is not +_interoperable_. Bolted on by one vendor, attestation secures only that vendor's +island; a server's signed clearance document is meaningful only to hosts that +already agreed, out of band, on its shape and verification order. The payoff +("this server is attested" as a claim any host can check; servers publishing one +document instead of N vendor dialects; SDKs shipping the gate on by default) only +materializes once a single format is agreed, and only the spec owner can mint +that Schelling point. That the mechanism rides entirely above MCP is what makes +adoption cheap and low-risk, not a reason to defer it. + +### Design decisions + +- **Offline, detached signature.** Admission requires no online call to a third + party; the host verifies against a locally pinned trust root. This keeps + admission available and fast and avoids a runtime dependency on the signer's + infrastructure. +- **Well-known URI for discovery.** A host can evaluate admission _before_ + committing to a session, and the mechanism rides the established RFC 8615 + pattern instead of inventing a new one. +- **Admission separated from tool authorization.** Admitting a server says + nothing about which of its tools are in bounds. The closed per-server + allow-list is enforced before any network dispatch, defeating a prompt-injected + model that requests a tool the server advertises but the host never approved. +- **Numeric clearance ranks in a named, totally ordered scheme.** Dominance is a + single comparison; naming the scheme lets different sensitivity vocabularies + (government, healthcare, finance) coexist and interoperate. +- **Canonicalization fixes the signed bytes.** Sorted keys, sorted arrays, absent + `signerKeyId` as `null`, `signature` excluded — so signer and verifier agree on + exactly what was signed regardless of JSON serializer. + +### Alternatives considered + +- **Leave it to each vendor / keep it an extension only.** Rejected: additive ≠ + interoperable (above). Extensions are the right place to _experiment_; this + pattern has finished experimenting (production + evaluation), and its remaining + value is gated on a single agreed format that only the spec can supply. +- **In-band capability only, no well-known document.** Rejected: discovery must be + possible _before_ a connection is trusted, but `initialize` already implies a + session. The well-known fetch lets a host decide admission before it commits. +- **mTLS / client certificates.** Rejected: TLS answers "did I reach the named + endpoint," not "is this server cleared to operate at this sensitivity, and which + of its tools are in bounds." Orthogonal; ATSA composes with it. +- **OAuth-style bearer token.** Rejected: that is _user_-authorization ("may this + user use this server"), a different question from host admission ("may this host + use this server as a tool provider, at what level"). ATSA composes with MCP's + authorization profile. +- **Trusting `clearance` embedded in `tools/list`.** Rejected: the tool list is + unsigned and self-declared; trust cannot rest on it. The signed SAD is the + anchor; the allow-list is host-side state. +- **Online (OCSP-style) revocation as a v1 requirement.** Deferred: it adds an + availability dependency at admission time. v1 enforces per-signer `notAfter`; + online revocation is future work (see _Open questions_). + +### Related work + +- **Artifact attestation.** sigstore, The Update Framework (TUF), and in-toto + apply "verify a signed claim against a trusted root before use" to software + supply chains. ATSA applies the same discipline to MCP server admission. +- **Well-known discovery precedent.** OAuth 2.0 Authorization Server Metadata + (RFC 8414), `security.txt` (RFC 9116), and OpenID Connect Discovery all ride + RFC 8615 without forking the base protocols they extend. + +### Design-principles alignment + +This proposal is written against the MCP [design +principles](https://modelcontextprotocol.io/community/design-principles): + +- **Demonstration over deliberation.** The mechanism is in production in the open + `enclawed-oss` distribution, with a JSON Schema, conformance vectors, 48 + hermetic tests, an LLM-driven adversarial campaign (27,025 tool-name evasions + + 14,378 forged assertions, all denied), and a live Google Workspace end-to-end + run. The SEP is written from what the prototype taught, not from theory. +- **Standardization over innovation.** ATSA codifies a pattern already proven in a + shipping host/server pair; it invents no new primitive. The + signed-document-at-a-well-known-URI shape is the one OAuth metadata, + `security.txt`, and OpenID discovery already use. +- **Convergence over choice.** One signed-attestation format, one verification + ordering — so "this server is attested" becomes a claim _any_ host can check and + a server publishes _once_, instead of N mutually unintelligible vendor dialects. + Only the spec owner can mint that single path. +- **Interoperability over optimization.** It degrades gracefully: capability + negotiation gates in-band discovery, an unextended host never fetches the SAD, + an unextended server never sees the allow-list, and a conforming host **MUST** + still interoperate with unattested servers under its configured posture. Nothing + requires every participant to be equally capable. +- **Composability over specificity** _(objection addressed)._ A reviewer may ask + whether this can be built from existing primitives. It can — and is, today, + above MCP — which is exactly why adoption is cheap. But composability gives each + vendor an island, not interoperability: a server cannot publish one document + every host understands until the shape and verification order are agreed in one + place. The SEP adds exactly one document and one ordering — the minimum that + turns a per-vendor capability into an ecosystem one. +- **Stability over velocity** _(objection addressed)._ Because the addition is + permanent, it is deliberately small: one well-known document, one optional + `initialize` capability, zero changes to any existing message. An unextended + implementation is byte-for-byte unaffected, so the permanent cost to client + implementers is bounded to those who opt in. +- **Capability over compensation.** ATSA does not compensate for a temporary model + weakness. A more capable model that is prompt-injected is _more_ dangerous, not + less; the trust and authorization gap it closes is independent of model quality + and does not fade as models improve. +- **Pragmatism over purity.** Trust-root provisioning is left to deployment policy + rather than mandated, because operators' PKI realities differ. The wire format + is fixed; the anchoring is not. + +## Backward Compatibility + +None broken. The SAD lives at a well-known URI (RFC 8615); the tool allow-list is +host-side state; no existing MCP message changes shape. This is the additive +discipline that let OAuth, `security.txt`, and OpenID discovery ride the +well-known mechanism without forking the protocols they extended. A host with no +required level and an empty allow-list policy behaves exactly as a host does +today. + +## Security Implications + +The design resists confused-deputy tool invocation (tool authorization), server +impersonation and cross-origin replay (rules 3/6/8), level escalation (the level +is inside the signed body), and signer-key aging (rule 4). Out of scope and +delegated to other layers: content inspection of admitted connections, and the +behavior of a correctly-admitted, correctly-cleared server within its allowed +tools. The trust root is the root of all guarantees; its provisioning and sealing +are deployment policy (see _Trust establishment_), and a compromised signer key +is bounded by `notAfter` until online revocation (future work) lands. + +## Reference Implementation + +A production reference implementation ships in the open `enclawed-oss` +distribution — — at +`extensions/mcp-attested` (with a first-party Google Workspace bridge at +`extensions/mcp-google-workspace`). It includes a JSON Schema, an error registry, +and machine-checkable conformance vectors. + +### Prototype and evaluation + +Per the SEP process (explore → prototype → write the SEP from what the prototype +taught): the mechanism is implemented and in production, and is evaluated in the +companion preprint. Every stated guarantee is backed by an executable test driven +by an LLM-generated adversarial corpus: + +- **48 hermetic tests** (44 under `vitest`, 4 under `node:test`) exercise every + verification rule and the tool-authorization rule. +- A local-LLM (Ollama) **coverage campaign** generated **27,025 unique tool-name + evasions** (case/Unicode/whitespace/separator/path/near-miss tricks) — all + denied, zero leaked network writes — and **14,378 unique forged clearance + assertions** — all rejected. +- A **live end-to-end** run drove a real Google Workspace MCP endpoint through the + gate: the allow-listed tool was admitted and dispatched; out-of-allow-list tools + were denied before any network call. + +### Conformance (prerequisite for Final) + +Per [SEP-2484](https://modelcontextprotocol.io/seps/2484-conformance-tests-required-for-final-seps), +a Standards Track SEP with observable protocol behavior must, before reaching +`Final`, land a conformance scenario in the +[conformance repository](https://github.com/modelcontextprotocol/conformance) +plus a `sep-NNNN.yaml` traceability file mapping every MUST/MUST NOT and +SHOULD/SHOULD NOT in this _Specification_ to a check ID. This SEP is written to +make that mechanical: each verification rule (1–8), the tool-authorization rule, +and the audit and versioning requirements are already enumerated as +machine-checkable conformance vectors in the reference implementation. The +traceability file and scenario will be supplied against the draft spec-version tag +once a sponsor is engaged and the SEP number is assigned. + +## Open questions / future work + +- Per-tool (vs. per-server) clearance. +- A short-lived `notBefore`/expiry on the assertion itself and an online + (OCSP-style) revocation channel for compromised signer keys, beyond the + per-signer `notAfter` already enforced. +- Reconciling the `clearance` field with MCP's evolving authorization profile and + capability-negotiation handshake. + +## References + +- Companion preprint: _Attested Tool-Server Admission: A Security Extension to the + Model Context Protocol_ — archived at Zenodo, doi:10.5281/zenodo.20349263 + (arXiv ID forthcoming; PDF in this package). +- RFC 2119 / RFC 8174 (requirement keywords), RFC 8414 (OAuth AS Metadata), + RFC 8615 (Well-Known URIs), RFC 8032 (Ed25519), RFC 9116 (`security.txt`). +- Reference implementation: — + `extensions/mcp-attested`. diff --git a/docs/seps/index.mdx b/docs/seps/index.mdx index ff09a3642..f2a6fe0cd 100644 --- a/docs/seps/index.mdx +++ b/docs/seps/index.mdx @@ -12,8 +12,8 @@ Specification Enhancement Proposals (SEPs) are the primary mechanism for proposi ## Summary +- **Draft**: 5 - **Final**: 32 -- **Draft**: 4 - **Accepted**: 4 - **In-review**: 1 @@ -21,6 +21,7 @@ Specification Enhancement Proposals (SEPs) are the primary mechanism for proposi | SEP | Title | Status | Type | Created | | ------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------- | ---------------------------------------------------- | ---------------- | ---------- | +| [SEP-2777](/seps/2777-attested-tool-server-admission) | Attested Tool-Server Admission (ATSA) | Draft | Standards Track | 2026-05-22 | | [SEP-2663](/seps/2663-tasks-extension) | Tasks Extension | Final | Extensions Track | 2026-04-27 | | [SEP-2596](/seps/2596-spec-feature-lifecycle-and-deprecation) | Specification Feature Lifecycle and Deprecation Policy | Draft | Process | 2026-04-17 | | [SEP-2577](/seps/2577-deprecate-roots-sampling-and-logging) | Deprecate Roots, Sampling, and Logging | Final | Standards Track | 2026-04-14 | diff --git a/seps/2777-attested-tool-server-admission.md b/seps/2777-attested-tool-server-admission.md index 8e15c25b2..c8994f59d 100644 --- a/seps/2777-attested-tool-server-admission.md +++ b/seps/2777-attested-tool-server-admission.md @@ -15,11 +15,11 @@ and RFC 8174. ## Abstract -MCP standardizes how a host and a tool server exchange messages, but not *trust*: +MCP standardizes how a host and a tool server exchange messages, but not _trust_: a host reads a server's self-declared tool list and dispatches calls with no notion of which servers it may use, at what sensitivity, or which of a server's tools are in bounds. This SEP adds an **optional, purely additive** admission -layer: a server publishes a small, offline-signed *clearance assertion* at a +layer: a server publishes a small, offline-signed _clearance assertion_ at a well-known URI; a host verifies it against a locally pinned trust root before any tool dispatch; admitting a server is kept distinct from authorizing its tools via a closed per-server tool allow-list; and every admission decision is auditable. @@ -40,8 +40,8 @@ notion of which server is which, at what level, or which tools are in bounds. The existing specification provides no place to express any of this. TLS proves the host reached the named endpoint; MCP's authorization profile proves the user -may use the server; neither answers the missing third question — *is this server -one the host is authorized to use as a tool provider, and at what sensitivity?* +may use the server; neither answers the missing third question — _is this server +one the host is authorized to use as a tool provider, and at what sensitivity?_ ## Specification @@ -49,15 +49,15 @@ one the host is authorized to use as a tool provider, and at what sensitivity?* A server **MAY** advertise an attestation two interoperable ways: -1. **Well-known resource.** The server **SHOULD** serve a *Server Attestation - Document* (SAD) at `/.well-known/mcp-attestation` on the same origin as its +1. **Well-known resource.** The server **SHOULD** serve a _Server Attestation + Document_ (SAD) at `/.well-known/mcp-attestation` on the same origin as its MCP endpoint, over TLS. 2. **In-band.** A server **MAY** return the SAD in the `initialize` result under an experimental capability key. A conforming host **MUST** attempt (1), **MAY** attempt (2), and **MUST** treat -the absence of both as *unattested*, applying its configured posture (see -*Backward Compatibility*). +the absence of both as _unattested_, applying its configured posture (see +_Backward Compatibility_). ### Server Attestation Document (SAD) @@ -83,7 +83,7 @@ agree. ### Host verification rules -Before treating a connection as *admitted*, a host **MUST** evaluate the +Before treating a connection as _admitted_, a host **MUST** evaluate the following in order and **MUST** deny on the first failure: 1. the SAD parses and its `capabilities` contain `"mcp-server"`; @@ -103,7 +103,7 @@ and **MUST NOT** silently treat it as success. Admitting a server **MUST NOT** be read as authorizing all its tools. A host **SHOULD** keep a per-server allow-list and **MUST** deny a `tools/call` for any -tool absent from it *before* any network dispatch, regardless of what +tool absent from it _before_ any network dispatch, regardless of what `tools/list` advertises. Per-tool `clearance` **MAY** be added in a future `v`. ### Audit @@ -139,8 +139,8 @@ incremental rollout. ### Why a spec extension rather than a per-vendor layer -The mechanism can be implemented above MCP today — but *additive* is not -*interoperable*. Bolted on by one vendor, attestation secures only that vendor's +The mechanism can be implemented above MCP today — but _additive_ is not +_interoperable_. Bolted on by one vendor, attestation secures only that vendor's island; a server's signed clearance document is meaningful only to hosts that already agreed, out of band, on its shape and verification order. The payoff ("this server is attested" as a claim any host can check; servers publishing one @@ -155,7 +155,7 @@ adoption cheap and low-risk, not a reason to defer it. party; the host verifies against a locally pinned trust root. This keeps admission available and fast and avoids a runtime dependency on the signer's infrastructure. -- **Well-known URI for discovery.** A host can evaluate admission *before* +- **Well-known URI for discovery.** A host can evaluate admission _before_ committing to a session, and the mechanism rides the established RFC 8615 pattern instead of inventing a new one. - **Admission separated from tool authorization.** Admitting a server says @@ -172,16 +172,16 @@ adoption cheap and low-risk, not a reason to defer it. ### Alternatives considered - **Leave it to each vendor / keep it an extension only.** Rejected: additive ≠ - interoperable (above). Extensions are the right place to *experiment*; this + interoperable (above). Extensions are the right place to _experiment_; this pattern has finished experimenting (production + evaluation), and its remaining value is gated on a single agreed format that only the spec can supply. - **In-band capability only, no well-known document.** Rejected: discovery must be - possible *before* a connection is trusted, but `initialize` already implies a + possible _before_ a connection is trusted, but `initialize` already implies a session. The well-known fetch lets a host decide admission before it commits. - **mTLS / client certificates.** Rejected: TLS answers "did I reach the named endpoint," not "is this server cleared to operate at this sensitivity, and which of its tools are in bounds." Orthogonal; ATSA composes with it. -- **OAuth-style bearer token.** Rejected: that is *user*-authorization ("may this +- **OAuth-style bearer token.** Rejected: that is _user_-authorization ("may this user use this server"), a different question from host admission ("may this host use this server as a tool provider, at what level"). ATSA composes with MCP's authorization profile. @@ -190,7 +190,7 @@ adoption cheap and low-risk, not a reason to defer it. anchor; the allow-list is host-side state. - **Online (OCSP-style) revocation as a v1 requirement.** Deferred: it adds an availability dependency at admission time. v1 enforces per-signer `notAfter`; - online revocation is future work (see *Open questions*). + online revocation is future work (see _Open questions_). ### Related work @@ -216,28 +216,28 @@ principles](https://modelcontextprotocol.io/community/design-principles): signed-document-at-a-well-known-URI shape is the one OAuth metadata, `security.txt`, and OpenID discovery already use. - **Convergence over choice.** One signed-attestation format, one verification - ordering — so "this server is attested" becomes a claim *any* host can check and - a server publishes *once*, instead of N mutually unintelligible vendor dialects. + ordering — so "this server is attested" becomes a claim _any_ host can check and + a server publishes _once_, instead of N mutually unintelligible vendor dialects. Only the spec owner can mint that single path. - **Interoperability over optimization.** It degrades gracefully: capability negotiation gates in-band discovery, an unextended host never fetches the SAD, an unextended server never sees the allow-list, and a conforming host **MUST** still interoperate with unattested servers under its configured posture. Nothing requires every participant to be equally capable. -- **Composability over specificity** *(objection addressed).* A reviewer may ask +- **Composability over specificity** _(objection addressed)._ A reviewer may ask whether this can be built from existing primitives. It can — and is, today, above MCP — which is exactly why adoption is cheap. But composability gives each vendor an island, not interoperability: a server cannot publish one document every host understands until the shape and verification order are agreed in one place. The SEP adds exactly one document and one ordering — the minimum that turns a per-vendor capability into an ecosystem one. -- **Stability over velocity** *(objection addressed).* Because the addition is +- **Stability over velocity** _(objection addressed)._ Because the addition is permanent, it is deliberately small: one well-known document, one optional `initialize` capability, zero changes to any existing message. An unextended implementation is byte-for-byte unaffected, so the permanent cost to client implementers is bounded to those who opt in. - **Capability over compensation.** ATSA does not compensate for a temporary model - weakness. A more capable model that is prompt-injected is *more* dangerous, not + weakness. A more capable model that is prompt-injected is _more_ dangerous, not less; the trust and authorization gap it closes is independent of model quality and does not fade as models improve. - **Pragmatism over purity.** Trust-root provisioning is left to deployment policy @@ -261,7 +261,7 @@ is inside the signed body), and signer-key aging (rule 4). Out of scope and delegated to other layers: content inspection of admitted connections, and the behavior of a correctly-admitted, correctly-cleared server within its allowed tools. The trust root is the root of all guarantees; its provisioning and sealing -are deployment policy (see *Trust establishment*), and a compromised signer key +are deployment policy (see _Trust establishment_), and a compromised signer key is bounded by `notAfter` until online revocation (future work) lands. ## Reference Implementation @@ -296,7 +296,7 @@ a Standards Track SEP with observable protocol behavior must, before reaching `Final`, land a conformance scenario in the [conformance repository](https://github.com/modelcontextprotocol/conformance) plus a `sep-NNNN.yaml` traceability file mapping every MUST/MUST NOT and -SHOULD/SHOULD NOT in this *Specification* to a check ID. This SEP is written to +SHOULD/SHOULD NOT in this _Specification_ to a check ID. This SEP is written to make that mechanical: each verification rule (1–8), the tool-authorization rule, and the audit and versioning requirements are already enumerated as machine-checkable conformance vectors in the reference implementation. The @@ -314,8 +314,8 @@ once a sponsor is engaged and the SEP number is assigned. ## References -- Companion preprint: *Attested Tool-Server Admission: A Security Extension to the - Model Context Protocol* — archived at Zenodo, doi:10.5281/zenodo.20349263 +- Companion preprint: _Attested Tool-Server Admission: A Security Extension to the + Model Context Protocol_ — archived at Zenodo, doi:10.5281/zenodo.20349263 (arXiv ID forthcoming; PDF in this package). - RFC 2119 / RFC 8174 (requirement keywords), RFC 8414 (OAuth AS Metadata), RFC 8615 (Well-Known URIs), RFC 8032 (Ed25519), RFC 9116 (`security.txt`). From f27a859e15f50d8cf6e05892a2fb9c3ddae618c5 Mon Sep 17 00:00:00 2001 From: Alfredo Metere Date: Fri, 22 May 2026 22:32:10 -0700 Subject: [PATCH 5/6] Fix MDX: use markdown links instead of autolinks in the SEP --- docs/seps/2777-attested-tool-server-admission.mdx | 4 ++-- seps/2777-attested-tool-server-admission.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/seps/2777-attested-tool-server-admission.mdx b/docs/seps/2777-attested-tool-server-admission.mdx index f5ce1e0ac..93622968b 100644 --- a/docs/seps/2777-attested-tool-server-admission.mdx +++ b/docs/seps/2777-attested-tool-server-admission.mdx @@ -280,7 +280,7 @@ is bounded by `notAfter` until online revocation (future work) lands. ## Reference Implementation A production reference implementation ships in the open `enclawed-oss` -distribution — — at +distribution — [github.com/enclawed/enclawed-oss](https://github.com/enclawed/enclawed-oss) — at `extensions/mcp-attested` (with a first-party Google Workspace bridge at `extensions/mcp-google-workspace`). It includes a JSON Schema, an error registry, and machine-checkable conformance vectors. @@ -332,5 +332,5 @@ once a sponsor is engaged and the SEP number is assigned. (arXiv ID forthcoming; PDF in this package). - RFC 2119 / RFC 8174 (requirement keywords), RFC 8414 (OAuth AS Metadata), RFC 8615 (Well-Known URIs), RFC 8032 (Ed25519), RFC 9116 (`security.txt`). -- Reference implementation: — +- Reference implementation: [github.com/enclawed/enclawed-oss](https://github.com/enclawed/enclawed-oss) — `extensions/mcp-attested`. diff --git a/seps/2777-attested-tool-server-admission.md b/seps/2777-attested-tool-server-admission.md index c8994f59d..2cef2f444 100644 --- a/seps/2777-attested-tool-server-admission.md +++ b/seps/2777-attested-tool-server-admission.md @@ -267,7 +267,7 @@ is bounded by `notAfter` until online revocation (future work) lands. ## Reference Implementation A production reference implementation ships in the open `enclawed-oss` -distribution — — at +distribution — [github.com/enclawed/enclawed-oss](https://github.com/enclawed/enclawed-oss) — at `extensions/mcp-attested` (with a first-party Google Workspace bridge at `extensions/mcp-google-workspace`). It includes a JSON Schema, an error registry, and machine-checkable conformance vectors. @@ -319,5 +319,5 @@ once a sponsor is engaged and the SEP number is assigned. (arXiv ID forthcoming; PDF in this package). - RFC 2119 / RFC 8174 (requirement keywords), RFC 8414 (OAuth AS Metadata), RFC 8615 (Well-Known URIs), RFC 8032 (Ed25519), RFC 9116 (`security.txt`). -- Reference implementation: — +- Reference implementation: [github.com/enclawed/enclawed-oss](https://github.com/enclawed/enclawed-oss) — `extensions/mcp-attested`. From e103f1a2fb03f3fd49ae5dc5e9e19aef63455a6e Mon Sep 17 00:00:00 2001 From: Alfredo Metere Date: Thu, 28 May 2026 08:54:35 -0700 Subject: [PATCH 6/6] Renumber SEP to assigned PR number 2809 The original PR (#2777) was closed by accident; GitHub refused to reopen it because the head fork had been deleted in the meantime. This branch is re-submitted as PR #2809, so the SEP file name, title, table fields, and index entries are updated to match the new number. No specification content changes. --- docs/docs.json | 2 +- ...ission.mdx => 2809-attested-tool-server-admission.mdx} | 8 ++++---- docs/seps/index.mdx | 2 +- ...dmission.md => 2809-attested-tool-server-admission.md} | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) rename docs/seps/{2777-attested-tool-server-admission.mdx => 2809-attested-tool-server-admission.mdx} (98%) rename seps/{2777-attested-tool-server-admission.md => 2809-attested-tool-server-admission.md} (99%) diff --git a/docs/docs.json b/docs/docs.json index dbf8cde98..963c88d8d 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -456,7 +456,7 @@ "seps/2164-resource-not-found-error", "seps/2484-conformance-tests-required-for-final-seps", "seps/2596-spec-feature-lifecycle-and-deprecation", - "seps/2777-attested-tool-server-admission" + "seps/2809-attested-tool-server-admission" ] } ] diff --git a/docs/seps/2777-attested-tool-server-admission.mdx b/docs/seps/2809-attested-tool-server-admission.mdx similarity index 98% rename from docs/seps/2777-attested-tool-server-admission.mdx rename to docs/seps/2809-attested-tool-server-admission.mdx index 93622968b..216e6a1e9 100644 --- a/docs/seps/2777-attested-tool-server-admission.mdx +++ b/docs/seps/2809-attested-tool-server-admission.mdx @@ -1,6 +1,6 @@ --- -title: "SEP-2777: Attested Tool-Server Admission (ATSA)" -sidebarTitle: "SEP-2777: Attested Tool-Server Admission (ATSA)" +title: "SEP-2809: Attested Tool-Server Admission (ATSA)" +sidebarTitle: "SEP-2809: Attested Tool-Server Admission (ATSA)" description: "Attested Tool-Server Admission (ATSA)" --- @@ -15,14 +15,14 @@ description: "Attested Tool-Server Admission (ATSA)" | Field | Value | | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **SEP** | 2777 | +| **SEP** | 2809 | | **Title** | Attested Tool-Server Admission (ATSA) | | **Status** | Draft | | **Type** | Standards Track | | **Created** | 2026-05-22 | | **Author(s)** | Alfredo Metere ([@metereconsulting](https://github.com/metereconsulting)) <alfredo.metere[@enclawed](https://github.com/enclawed).com>, Enclawed LLC | | **Sponsor** | None (seeking) | -| **PR** | [#2777](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2777) | +| **PR** | [#2809](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2809) | --- diff --git a/docs/seps/index.mdx b/docs/seps/index.mdx index f2a6fe0cd..65f161d9e 100644 --- a/docs/seps/index.mdx +++ b/docs/seps/index.mdx @@ -21,7 +21,7 @@ Specification Enhancement Proposals (SEPs) are the primary mechanism for proposi | SEP | Title | Status | Type | Created | | ------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------- | ---------------------------------------------------- | ---------------- | ---------- | -| [SEP-2777](/seps/2777-attested-tool-server-admission) | Attested Tool-Server Admission (ATSA) | Draft | Standards Track | 2026-05-22 | +| [SEP-2809](/seps/2809-attested-tool-server-admission) | Attested Tool-Server Admission (ATSA) | Draft | Standards Track | 2026-05-22 | | [SEP-2663](/seps/2663-tasks-extension) | Tasks Extension | Final | Extensions Track | 2026-04-27 | | [SEP-2596](/seps/2596-spec-feature-lifecycle-and-deprecation) | Specification Feature Lifecycle and Deprecation Policy | Draft | Process | 2026-04-17 | | [SEP-2577](/seps/2577-deprecate-roots-sampling-and-logging) | Deprecate Roots, Sampling, and Logging | Final | Standards Track | 2026-04-14 | diff --git a/seps/2777-attested-tool-server-admission.md b/seps/2809-attested-tool-server-admission.md similarity index 99% rename from seps/2777-attested-tool-server-admission.md rename to seps/2809-attested-tool-server-admission.md index 2cef2f444..57cf4073c 100644 --- a/seps/2777-attested-tool-server-admission.md +++ b/seps/2809-attested-tool-server-admission.md @@ -1,11 +1,11 @@ -# SEP-2777: Attested Tool-Server Admission (ATSA) +# SEP-2809: Attested Tool-Server Admission (ATSA) - **Status**: Draft - **Type**: Standards Track - **Created**: 2026-05-22 - **Author(s)**: Alfredo Metere (@metereconsulting) <alfredo.metere@enclawed.com>, Enclawed LLC - **Sponsor**: None (seeking) -- **PR**: https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2777 +- **PR**: https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2809 - **Preprint**: doi:10.5281/zenodo.20349263 - **Requires**: RFC 2119, RFC 8174, RFC 8615 (Well-Known URIs), RFC 8032 (Ed25519)