Skip to content

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 deprecates pointers.
  • 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:

  1. MCP-first. Treat tools/list as canonical; bolt extensions as extra fields. Pragmatic, stays inside MCP ecosystem. Limits expressivity to what MCP allows.
  2. Semantic-first. Define a rich JSON-LD capability descriptor as canonical; serve MCP tools/list as 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 - reasoningnone | 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_uri extension in tools/list entries 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 id changes. 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.