DEVELOPMENT DOCUMENTATION / MCP
Make local tools reachable by authorized agents.
Model Context Protocol exposes tools and related protocol exchanges. Agent Uplink transports selected MCP profiles to fixed local HTTP services or supervised stdio servers.
Compatibility profiles
| Profile | Lifecycle | HTTP surface | Stdio ownership |
|---|---|---|---|
| mcp-2026-07-28 | Discovery and per-request metadata; no lifecycle translation. | POST; GET and DELETE answered 405 before backend dispatch. | One child per request; no cross-request child state. |
| mcp-2025-11-25 | Initialize lifecycle and session ownership. | POST, GET and DELETE. | One child per session. |
These are the repository's pinned profiles, not a claim to support every MCP revision. The bridge forwards raw JSON-RPC bytes rather than retyping messages and dropping unknown metadata.
Local export choices
- HTTP: a locally configured backend destination, not a caller-supplied URL.
- Stdio: a fixed local executable and launch policy, supervised by the device.
- Consumer: an authorized application calls the enrolled device/service route; a tool name is not an authorization grant.
Provision and call
Use examples/m6-catalog-mcp.toml with the fresh-catalog workflow. Set the catalog and device export to the same pinned MCP profile and enable it in the relay's [http_forward] profiles. The consumer route is /v1/devices/{device_id}/services/{service_id}/http/mcp, with token scope and grant http:invoke.
The relay drops User-Agent, Accept-Encoding, Accept-Language and Sec-Fetch-Mode request headers, which curl, Python httpx and Node's built-in fetch send by default; they are never forwarded to the device. Any other header the profile does not list is refused with 400 HTTP_INVALID_HEAD, and the error names the header. Provisioning regression gates use synthetic backends and do not establish compatibility with every MCP server.
Limits and interoperability
| Area | Current scope |
|---|---|
| Pinned interoperability | The official rmcp 3.4.0 fixture exercises the two profiles; this is not certification of every SDK or server. |
| Request size | Default 1 MiB, configured ceiling 16 MiB. |
| JSON response | Default 8 MiB, ceiling 64 MiB; enforced on the device. |
| Cumulative SSE response | Default 64 MiB, ceiling 1 GiB. |
| Consumer transport | HTTP/1.1 and HTTP/2 accepted by the profile; full cross-client coverage remains separate. |
Do not assume
Browser access, unrestricted headers, OAuth flows, Last-Event-ID replay, every resources/prompts/sampling/elicitation exchange, and cross-platform child cleanup are not blanket supported. Header allowlists differ by profile. In particular, the browser Origin/CORS profile is not delivered.
Isolation evidence
The repository now records scoped verification of session isolation, correlation, revocation and unknown outcomes on the real multi-relay path. Selected hosted Linux gates passed, including ten isolation runs at fc5dde3. The real-path gate's retained-OPEN rule was corrected (task row M3-31): the relay now publishes a stream's reclamation when the stream closes, the gate waits for earlier requests to be reclaimed before it measures, and it requires the journal to return to that baseline. Before the settle wait, the full M3 suite passed ten runs on hosted Linux probe runners; after it, the real-path gate alone passed twelve hosted probe runs. The suite is added as its own CI job; probe runs are not a record of repeated main CI results. This is not full MCP conformance or interoperability certification beyond the pinned fixtures and client.
Failure behavior
A transport interruption is not proof that a tool did not run. Respect explicit unknown outcomes and cancellation semantics. Do not blindly retry a side-effecting tool call.
The pinned rmcp client can release a POST event stream after receiving its final JSON-RPC response but before the tunnel's END/FIN arrives. The relay does not read message bodies, so it cannot tell that release from one in the middle of a call. It records it as its own outcome, released, with the transport reset HTTP_CANCELLED, and the device's record says whether the call completed (task row M3-32). Distinguish the protocol result from the transport log, and do not repeat a completed side effect merely because that log says cancelled. These runtime tests were not rerun for this website review.
Source & review
Reviewed against cb94dc3ccbf4 on 2026-09-25. Based on docs/mcp.md, docs/tasks.md, crates/tunnel-mcp. Historical test evidence is not a new test run.