ADR-0005: Rich capability manifest; MCP as projection¶
- Status: Accepted
- Date: 2026-04-12
Context¶
MCP's tools/list returns tool name + description + input JSON schema. That's sufficient for "call a named function" but insufficient for the kind of agent behavior Trails aims to enable:
- An agent deciding which of three capabilities is cheapest — needs cost estimates.
- An agent deciding whether to invoke a capability with side effects — needs side-effect declarations.
- An agent planning a sequence of invocations — needs preconditions and postconditions.
- An agent verifying consent or authority — needs policy metadata.
- An agent reasoning about capability versions — needs SemVer and
deprecatespointers. - An agent discovering compatible capabilities across services — needs shape IRIs, not just JSON schemas.
MCP exposes none of these. Adding them requires a richer capability descriptor.
Two framings:
- MCP-first. Treat
tools/listas canonical; bolt extensions as extra fields. Pragmatic, stays inside MCP ecosystem. Limits expressivity to what MCP allows. - Semantic-first. Define a rich JSON-LD capability descriptor as canonical; serve MCP
tools/listas a downgraded projection. Also project to OpenAPI for HTTP clients.
Decision¶
Semantic-first. Rich JSON-LD capability descriptor is canonical; MCP is one of three projections.
Canonical form (served at /.well-known/capabilities, JSON-LD):
- id, version (SemVer), description
- input_shape, output_shape — IRIs to SHACL shapes
- preconditions — structured (kind + parameters)
- side_effects — declared writes to named graphs, whether provenance is recorded, external API calls
- cost — token estimate, USD estimate, latency p50/p95
- policy_required — Cedar policy references
- idempotent — boolean; if true, idempotency_key is honored
- reasoning — none | rdfs | owl-rl
- deprecates — prior capability ID if this supersedes one
Projections (auto-generated):
- MCP (tools/list): name + description + inputSchema. Everything else discarded.
- OpenAPI (/openapi.json): operation with summary, requestBody (JSON Schema from input shape), responses, x-trails-* extensions for Trails-specific metadata.
- JSON-LD canonical (/.well-known/capabilities): the full descriptor.
Order of priority when they diverge: canonical form wins. If a field can't be expressed in MCP, it's silently dropped in the MCP projection, not lifted into description text.
Consequences¶
Positive¶
- Trails' thesis survives. Without preconditions, costs, and shape IRIs, Trails is just "FastAPI with RDF" — no differentiation. The rich manifest is the differentiator.
- MCP-speaking agents still work. They see a valid MCP tool list.
- Semantic-aware agents get more. They negotiate on the canonical form and use the metadata.
- OpenAPI compat lets legacy HTTP tooling work.
- Extensibility: adding a field is a canonical-form change; projections adapt or ignore.
Negative¶
- More to maintain. Three projections instead of one tool list.
- MCP ecosystem expectations — agents may not know to look at
/.well-known/capabilities. Mitigated by: - Including a
_trails:manifest_uriextension intools/listentries pointing to the rich descriptor. - Contributing extension proposals upstream to MCP for preconditions and costs.
- Semantic versioning drift between projections — e.g., MCP tool name changes vs canonical
idchanges. Solved by single source of truth in canonical form.
Non-consequences¶
- MCP protocol itself is unmodified — Trails is a fully compliant MCP server.
- Apps can opt out of rich manifest publication (
trails.toml: [capability.manifest] enabled = false) if an organization wants to ship MCP-only.
Revisit conditions¶
- If MCP adds official extension mechanisms (preconditions, cost hints), reduce projection gap and contribute canonical back.
- If a different protocol (A2A, ACP) dominates agent-to-capability discovery, add projections rather than replace canonical.
Update (2026-04-12) — Canonical field alignment¶
After the cross-doc alignment pass, the canonical capability descriptor field set is defined by 03-design-spec.md §3.2.5 (Rust CapabilityDescriptor struct) and §3.4.2 (JSON wire format). ADR-0005's original field list (above) predates ADR-0013 (ACT/ECT, assurance levels) and the regulated side-effect flag; it is retained as historical context. When this ADR and the design spec disagree, the design spec wins.
Canonical fields, in canonical order:
| # | Field | Source |
|---|---|---|
| 1 | id |
§3.2.5, §3.4.2 |
| 2 | version |
§3.2.5, §3.4.2 |
| 3 | description |
§3.2.5, §3.4.2 |
| 4 | input_shape |
§3.2.5, §3.4.2 |
| 5 | output_shape |
§3.2.5, §3.4.2 |
| 6 | preconditions |
§3.2.5, §3.4.2 |
| 7 | side_effects |
§3.2.5, §3.4.2 |
| 8 | cost |
§3.2.5, §3.4.2 |
| 9 | policy_required |
§3.2.5, §3.4.2 |
| 10 | idempotent |
§3.2.5, §3.4.2 |
| 11 | deprecates |
§3.2.5, §3.4.2 |
| 12 | reasoning |
§3.2.5, §3.4.2 |
| 13 | assurance |
§3.2.5, §3.4.2 (added per ADR-0013) |
| 14 | version_status |
§3.2.5, §3.4.2 |
The Decision and Consequences sections above are unchanged; only the field inventory is updated.