Skip to content

Limits: the MCP wrapper, gateway, A2A and demo

The limits of deedglass mcp wrap, the MCP HTTP gateway, /mcp/native, mcp serve, deedglass a2a proxy and the Acme demo stack.

  • Edge-reported results are the edge’s word. A call the wrapper forwards is sealed L0 VERIFIED with method edge_reported when the server says it succeeded; a server that lies is believed until the Witness checks the system of record (Postgres, in gateway mode).
  • Only tools/call is governed. resources/*, prompts/*, completion/complete, subscriptions/listen and the 2025-era server-to-client requests (sampling/createMessage, elicitation/create, roots/list) pass through ungoverned in v1 (MCP.md).
  • A server that acts outside MCP isn’t stopped. The wrapper governs the calls a client makes; it can’t see what the server does on its own.
  • An approved call runs only in the wrapper process that created it. After a restart the wrapper looks the approval up (GET /v1/approvals/{id}, S22) and asks the model to make the call again; it never runs the earlier call.
  • A report that never lands leaves the action executing until its deadline (gate.edge_result_timeout), when the Gate seals it UNVERIFIABLE (edge_lost).
  • Hiding tools is advisory. tools/list leaves out tools the policy always denies, but a client can still call one by name; the Gate then denies it and seals a deed.
  • A changed tool definition is refused until restart. There is no way yet to accept a new definition without restarting the wrapper.
  • Path rules compare text. A policy can’t see where a symlink points; the server resolves it.
  • No signed intents from MCP clients. An agent in required intent mode can’t act through the wrapper (S09).

The MCP gateway, /mcp/native and mcp serve (S15)

Section titled “The MCP gateway, /mcp/native and mcp serve (S15)”
  • Two ways to declare an upstream. Since S18 an org adds a remote MCP server as an mcp_http connector with its credential in the vault. A deedglass.yaml upstream (mcp.upstreams) is served to every org on the instance; its headers_from_env is dev only (prod refuses it), and its name wins over an org’s connector of the same name.
  • mcp_http connectors don’t listen for notifications/tools/list_changed: the pool is sessionless, so a renamed or new tool appears when the tool cache expires (tools_ttl_ms).
  • No SSE streaming of progress from upstream servers; answers are single JSON objects.
  • Resources and prompts are not governed (mcp.passthrough forwards and logs them).
  • No OAuth token exchange with upstreams; an upstream that only accepts OAuth can’t be fronted.
  • Upstream results are the upstream’s word (L0 reported) until the Witness.
  • A Claude Desktop remote connector can’t reach a local Deedglass; it uses deedglass mcp serve.
  • The bridge doesn’t send Mcp-Param-* headers, so a modern client calling an upstream tool that declares x-mcp-header through deedglass mcp serve --connector <name> is refused (-32020). No native tool declares one today.
  • deedglass_check_approval looks the action up by approval id through the actions_approval index (S22, migration 0021).
  • The upstream pool’s sessions are per instance and in memory; a legacy upstream that loses its session gets one reconnect for tools/list, never for tools/call.
  • The demo’s MCP entries use the database owner’s credentials on purpose (acme_owner), so the only difference between orders and orders-direct on screen is Deedglass in the path. Agents should never get owner credentials; S17’s native Postgres connector uses a least-privilege role with its password in the vault.
  • Demo secrets are local-only: examples/demo/.env and .demo-keys are random, 0600 and git-ignored, and every port binds to 127.0.0.1. The stack is for local demos, never a server.
  • orders-direct bypasses Deedglass: it exists for the contrast shot only.

TY-08, INSTALL_CLIENTS.md. Each snippet is yours to add; none is on by default.

  • Checked against docs, not against running agents. Each client’s input and answer format comes from its own hooks page (dated in internal/shellguard/clients.go). The goldens feed the guard those documented shapes; no test drives Codex, Gemini CLI, Copilot or Cursor end to end, and the weekly hook-clients job only installs the npm releases and records their versions.
  • Deny where there is no ask. Codex doesn’t support ask yet and Gemini CLI has none, so there a match denies; Copilot’s cloud agent and autopilot turn ask into deny themselves.
  • Fails open. Without a deedglass on the agent’s PATH, or when the guard can’t read its input, every client runs the command unchecked (Copilot’s snippet ends in || true for this). In Cursor no output counts as a hook failure; Cursor lets the command go on unless failClosed is set, which this hook must not set.
  • No VS Code hook, no Windows for Copilot, no Cursor CLI claim. VS Code’s docs don’t name its terminal tool; the Copilot snippet has no powershell command; Cursor’s docs don’t say whether its CLI runs beforeShellExecution. Gemini CLI’s successor, Antigravity CLI, isn’t checked.

TY-07, A2A.md. deedglass a2a proxy is opt-in; nothing goes through it unless your agent is pointed at it.

  • Claimed only, for the peer’s own work. Deedglass records what the remote agent answered; it can’t see what that agent did. A Checked or Proven verdict exists only for the remote agent’s own tool calls that go through Deedglass, and those are separate actions.
  • The chain is mostly reported. Only the last two hops are Deedglass’s own (the agent whose key made the call, and the peer URL the operator set). Earlier hops are what the calling agent sent, and a remote agent that doesn’t pass the chain on breaks it.
  • JSON-RPC over HTTP, A2A 1.0 only. The gRPC and HTTP+JSON bindings, A2A 0.3 (requests without A2A-Version), and JSON-RPC batches are refused. The proxy’s card lists only its JSON-RPC interface and drops the peer’s card signatures, which no longer match the rewritten card.
  • Not followed after the answer. A task left working, waiting for input or for auth is sealed UNVERIFIABLE; later GetTask answers and push notifications are passed through or not seen, and never change the record.
  • Approvals live in one proxy process. A call waiting for a person runs only when the same request comes back to the same proxy; after a restart it has to be made again (a new action).
  • One key, shared with the caller. The proxy listens on loopback and needs the agent’s own key as a bearer token on every JSON-RPC request; browser requests and non-loopback Host names are refused. Any local process that holds that key acts as the agent, which it could do against the server directly anyway. Agents whose intent mode is required can’t use it: the proxy doesn’t sign intents.
  • Tested against a fake peer. The goldens and TestA2ALive use a fake A2A agent written from the v1.0.1 spec; no third-party A2A server or SDK is in CI.