Skip to content

ADR-0008: MCP primary, HTTP secondary

  • Status: Accepted
  • Date: 2026-04-12

Context

Trails serves capabilities to two audiences: agents and humans. Transport options:

  1. HTTP/REST primary, MCP secondary. Rails-era default. Agents speak MCP via a shim; humans hit REST.
  2. MCP primary, HTTP secondary. Agents are the design-target audience; humans get HTTP as a convenience.
  3. Dual-primary. Both transports peers; canonical spec split evenly.
  4. Protocol-agnostic core. No transport is primary; all are adapters.

The distinction matters because primary means: when the canonical capability manifest changes and a field can't be projected to a transport, that transport degrades, not the canonical form. Choosing which transport shapes the framework's natural DX.

Decision

MCP is the primary transport; HTTP is secondary.

  • MCP server is auto-mounted by default; MCP is the protocol the framework's conventions optimize for.
  • HTTP (FastAPI) adapter is auto-mounted but can be disabled per-app.
  • OpenAPI is generated from capability descriptors for legacy HTTP clients.
  • When a capability descriptor field can't be expressed in MCP, the field is projected away in the MCP tools/list response — but the canonical JSON-LD descriptor remains at /.well-known/capabilities (see ADR-0005).
  • Content negotiation on the HTTP side: Accept: text/markdown for humans, application/ld+json for semantic clients, application/json for plain JSON.

Consequences

Positive

  • Matches the thesis. Agents are the primary consumer; the framework should treat them as first-class.
  • Aligns with emerging standards. MCP is becoming the de facto agent-to-tool protocol.
  • Cleaner identity story. MCP servers can present consistent DID-based identity without HTTP-session baggage.
  • Natural bi-modal rendering. Humans get HTML/Markdown; agents get JSON-LD — both driven from the same template.

Negative

  • Most production tooling (reverse proxies, WAFs, rate limiters, LB) assumes HTTP. Mitigated by HTTP always being available; MCP rides over HTTP/SSE anyway.
  • MCP ecosystem is young. Spec still evolving. Mitigated by tracking MCP releases and keeping projection layer thin.
  • Some deployments may want MCP off entirely. Mitigated by [transport.mcp] enabled = false config.

Non-consequences

  • HTTP is not deprecated or second-class in implementation; it's just not where the canonical shape lives.
  • Authentication works identically on both transports (biscuit + DID).

Revisit conditions

  • If MCP is superseded or fragments into incompatible variants, re-evaluate. The protocol-agnostic core design (ADR-0005) makes this manageable — we'd add a new projection, not rewrite.
  • If the user base shifts strongly toward HTTP-only semantic services, we can re-balance primary/secondary without breaking apps.