docs: scaffold trust/privacy extension repo from SEP-1913 carve
Carve the schema-bearing parts of SEP-1913 into three independent experimental extensions, per @localden's "narrower first cut" ask and the Tool Annotations IG's 2026-05-28 extension-first decision: - io.modelcontextprotocol/trust-annotations (headline): narrow data-classification taxonomy (sensitive, untrusted) + open-ended evidenceRef pointer. - io.modelcontextprotocol/action-metadata: carries forward SEP-2061 (inputMetadata/returnMetadata/outcomes + requiresReview). - io.modelcontextprotocol/ifc-fides: FIDES information-flow control as a profile of evidenceRef, not a wire root. Adds repo meta (README, MAINTAINERS, CONTRIBUTING, LICENSE) and docs (sep-disposition, intent-comment, decisions, open-questions, trust-model, related-work). FIDES demoted to a profile; DataClass and requiresReview rehomed; maliciousActivityHint and propagation parked on the SEP-1913 umbrella. Citations index on public sources only. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
fe722986ff
commit
2aea5dc6be
1 changed files with 1022 additions and 1 deletions
179
specification/draft/trust-annotations.mdx
Normal file
179
specification/draft/trust-annotations.mdx
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
---
|
||||
title: Trust Annotations
|
||||
extension_identifier: io.modelcontextprotocol/trust-annotations
|
||||
status: Draft (experimental)
|
||||
maintainers:
|
||||
- "@SamMorrowDrums"
|
||||
- "@rreichel3"
|
||||
related:
|
||||
- https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1913
|
||||
- https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2133-extensions.md
|
||||
---
|
||||
|
||||
> ⚠️ **Experimental draft skeleton.** This document captures the agreed shape
|
||||
> and the open questions. Normative text is intentionally thin pending
|
||||
> reference-implementation validation. Substantive discussion happens on PRs
|
||||
> against this file and on [SEP-1913](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1913).
|
||||
|
||||
## Abstract
|
||||
|
||||
This extension defines a small, stable, scheme-agnostic vocabulary for
|
||||
classifying **data in transit** through MCP tool results, plus an optional
|
||||
`evidenceRef` pointer that lets a deployment attach richer, out-of-band
|
||||
evidence without growing the on-wire schema. It is the headline extension of
|
||||
the Tool Annotations IG's trust work; other extensions (information-flow
|
||||
control, action metadata) compose with it rather than duplicating it.
|
||||
|
||||
The design follows the [@localden](https://github.com/localden) review steer on
|
||||
SEP-1913 — take a *narrow first cut* of the taxonomy and avoid hard-to-remove
|
||||
schema — while preserving the layered "small annotation on the wire, rich
|
||||
evidence out-of-band" consensus that emerged in the SEP-1913 thread.
|
||||
|
||||
## Motivation
|
||||
|
||||
Data crosses tool boundaries today with no standardized markers for whether it
|
||||
is sensitive or whether it originated from an untrusted source. Clients and
|
||||
hosts are left to infer this from tool names or model behavior. Two coarse,
|
||||
broadly-applicable signals cover the majority of client-actionable cases:
|
||||
|
||||
- **`sensitive`** — the content should be treated as confidential (PII,
|
||||
credentials, proprietary data). Drives consent prompts and egress policy.
|
||||
- **`untrusted`** — the content originated from an open-world / attacker-
|
||||
influenceable source (web pages, third-party email, user-generated content).
|
||||
Drives prompt-injection defenses.
|
||||
|
||||
Anything richer than these two booleans is deliberately **not** on the wire; it
|
||||
hangs off `evidenceRef` (see below).
|
||||
|
||||
## Specification
|
||||
|
||||
### Dependencies
|
||||
|
||||
This extension depends only on the base MCP `_meta` mechanism. It does not
|
||||
require Tool Resolution ([SEP-1862](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1862)),
|
||||
though it composes with it.
|
||||
|
||||
### Annotation shape
|
||||
|
||||
Trust annotations are carried under the extension-namespaced `_meta` key on a
|
||||
`CallToolResult` (and MAY appear on an individual `ContentBlock` — see
|
||||
[Attachment point](#attachment-point)).
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"_meta": {
|
||||
"io.modelcontextprotocol/trust-annotations": {
|
||||
"sensitive": true, // optional boolean
|
||||
"untrusted": true, // optional boolean
|
||||
"evidenceRef": { // optional pointer, see below
|
||||
"type": "data-class.v1",
|
||||
"digest": "sha256:…",
|
||||
"canonicalization": "cbor/rfc8949",
|
||||
"schema": "https://…/data-class.v1.json",
|
||||
"ref": "audit://…" // optional locator
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Both booleans are optional and default to `false`/absent. Absence MUST be
|
||||
treated as "no claim made," never as "asserted false."
|
||||
|
||||
### The `evidenceRef` slot
|
||||
|
||||
`evidenceRef` is the extension point that keeps the wire schema small while
|
||||
letting deployments attach arbitrarily rich evidence. Its shape (adapted from
|
||||
the SEP-1913 discussion):
|
||||
|
||||
| Field | Required | Meaning |
|
||||
| :--- | :--- | :--- |
|
||||
| `type` | yes | **Open string** naming the class of the referenced record. NOT an enum. Examples: `"data-class.v1"`, `"ifc.fides.v1"`, `"sequence"`, `"policy-decision"`. |
|
||||
| `digest` | yes | Hash of the referenced record, so a client holding the data can re-derive it. |
|
||||
| `canonicalization` | yes | How the digest was computed (e.g. `"cbor/rfc8949"`), so the client can re-hash independently. |
|
||||
| `schema` | recommended | Identifier/version of the record `ref` resolves to. |
|
||||
| `ref` | optional | Locator into the deployment's audit/evidence stream. |
|
||||
|
||||
> **Normative intent:** `type` MUST remain an open string. Narrowing it to a
|
||||
> closed enum would foreclose the capability-token, cosigning, and
|
||||
> sequence-shape models raised in SEP-1913 review. A non-binding **registry**
|
||||
> of well-known `type` values is maintained in this repo; unknown `type` values
|
||||
> MUST be safely ignorable by a client that does not understand them (the
|
||||
> `digest`/`canonicalization` pair is still a usable, bounded signal).
|
||||
|
||||
This single slot subsumes the previously separate `attestationChainRef` /
|
||||
`policyDecisionRef` ideas — both become `type` values.
|
||||
|
||||
### Coarse vs. rich classification (DataClass)
|
||||
|
||||
SEP-1913 carried a four-level data classification
|
||||
(`public` / `personal` / `confidential` / `highly_confidential`) plus a
|
||||
regulatory scope (e.g. `confidential:hipaa`). **This extension deliberately
|
||||
keeps only the coarse `sensitive` boolean on the wire.** Richer classification
|
||||
is recovered as an `evidenceRef` profile:
|
||||
|
||||
```jsonc
|
||||
"evidenceRef": {
|
||||
"type": "data-class.v1",
|
||||
// record resolves to e.g. { "class": "highly_confidential", "regulatory": ["hipaa"] }
|
||||
"digest": "sha256:…",
|
||||
"canonicalization": "cbor/rfc8949"
|
||||
}
|
||||
```
|
||||
|
||||
This is an explicit scope decision: the binary lives on the wire for universal
|
||||
client actionability; the taxonomy lives behind a profile so it can evolve
|
||||
without a breaking schema change.
|
||||
|
||||
### Attachment point
|
||||
|
||||
Annotations attach at the **`CallToolResult` level by default.** A server MAY
|
||||
additionally annotate an individual `ContentBlock` when it has reason to
|
||||
localize the signal (e.g. one search result among many is untrusted). When both
|
||||
are present, the content-block annotation refines the result-level one for that
|
||||
block; it MUST NOT *weaken* a result-level claim (union semantics — once
|
||||
`true`, stays `true`).
|
||||
|
||||
### Lifecycle and `list_changed`
|
||||
|
||||
Trust annotations defined here are **response-level**: they describe a specific
|
||||
tool result and are not part of the tool *definition*. They therefore do **not**
|
||||
participate in `tools/list_changed`. (If a future revision attaches trust
|
||||
vocabulary to tool definitions, that surface would follow `list_changed`; this
|
||||
draft does not.)
|
||||
|
||||
### Propagation
|
||||
|
||||
This extension does **not** specify session-level escalation/propagation rules.
|
||||
Those remain an [open question](../../docs/open-questions.md) on the SEP-1913
|
||||
umbrella. A host MAY implement propagation locally; this extension only
|
||||
standardizes the per-result annotation.
|
||||
|
||||
## Reference implementation
|
||||
|
||||
[`kapil8811/mcp-trust-annotations`](https://github.com/kapil8811/mcp-trust-annotations)
|
||||
— a Python SDK with a `@trust_annotated` decorator, `to_wire`/`from_wire`
|
||||
round-tripping, a policy engine (audit/warn/enforce), a healthcare-scenario
|
||||
demo, and an LLM-based usability study (138 tests). The SDK predates this
|
||||
narrowed shape and is being aligned to the two-boolean + `evidenceRef` model.
|
||||
|
||||
## Trust model
|
||||
|
||||
Enforcement does not rest on developer honesty. See
|
||||
[docs/trust-model.md](../../docs/trust-model.md): registries and marketplaces
|
||||
verifying annotations are the enforcement layer; the annotation is a *claim*,
|
||||
and `evidenceRef` is how that claim is made checkable.
|
||||
|
||||
## Open questions
|
||||
|
||||
- Is `sensitive` the right single coarse signal, or do we need `sensitive` +
|
||||
the `data-class.v1` profile from day one?
|
||||
- Exact required-vs-recommended split on `evidenceRef` fields.
|
||||
- Whether content-block-level annotation needs a worked multi-result example
|
||||
before the draft is implementable.
|
||||
|
||||
## Changelog
|
||||
|
||||
| Date | Change |
|
||||
| ---------- | ------------------------------------------------------------- |
|
||||
| 2026-06-10 | Initial draft skeleton. Narrowed to `sensitive` + `untrusted` + `evidenceRef`; DataClass demoted to a profile; `requires_review` moved to `action-metadata`. |
|
||||
Loading…
Reference in a new issue