Govern an MCP server

Put EVE in front of an MCP (Model Context Protocol) tool server so an approved request is cryptographically bound to the request that actually executes. Any mutation between approval and execution is rejected before the side effect, and single-use authorizations are consumed atomically.

Prerequisites

  • The EVE MCP governance path (Python), mounted with authenticated middleware so identity is server-derived.
  • A PostgreSQL backend if you want cross-process single-use consumption.
  • Synthetic MCP tools for testing; no production credentials.

Installation

MCP governance runs in the EVE service (Python). Mount the MCP gateway and the authenticated identity middleware, and configure the PostgreSQL consumption backend (migration 2026_07_20_mcp_auth).

Runnable code

Conceptually, an MCP tool call is governed in two steps: authorize, then execute with binding enforcement.

# 1) Governance authorizes an MCP request; identity is server-derived from the
#    authenticated context (tenant, principal, session).
decision = eve.govern_tool_call(
    tool="mcp:filesystem.write",
    arguments={"path": "/reports/out.txt", "contents": "hello"},
    context={"tenant_id": "acme", "principal_id": "agent-1", "session_id": "sess-1"},
)

# 2) At execution time, EVE enforces that the executed request matches the approved
#    request (intent, capability schema, server identity, context digests) and that
#    the single-use authorization has not already been consumed.

Server-derived identity is authoritative: if a payload or header asserts a different tenant/principal/session, the request is rejected.

Expected result

  • A request that matches its approval executes once.
  • A request mutated after approval (different path, arguments, or target server) is rejected before the side effect with a binding reason code.
  • A replayed single-use authorization is rejected — only the first consumer wins.

Evidence output

mcp execution evidence{approved_digests == executed_digests, authorization_consumed: true}

A forged identity header produces MCP_UNTRUSTED_PROXY_IDENTITY. In the distributed test topology, 50 processes racing one authorization yield exactly 1 OK, 49 REPLAY, and 1 recorded side effect.

Verification

Verify the MCP execution evidence offline the same way as any EVE evidence (see verify-evidence-offline.md); it confirms the approved and executed digests match and that the authorization was consumed once.

Failure example

If a remote MCP call's outcome is unknown (network partition, timeout), EVE records OUTCOME_UNKNOWN and does not silently retry. This preserves at-most-once authorization consumption.

Production considerations

  • Mount the authenticated identity middleware; without it, server-derived identity cannot be enforced. Reverse-proxy identity headers are treated as untrusted.
  • Use a real PostgreSQL backend for cross-process consumption; the transactional consume is what makes one authorization single-use across processes.
  • Sequence state and budgets are per-session and in-process in the pilot; durable multi-instance state is a deployment concern.

Limitations

  • MCP execution binding is PILOT_READY. It guarantees at-most-once authorization consumption and approved==executed binding. It does not provide remote exactly-once execution; unknown remote outcomes are recorded as OUTCOME_UNKNOWN, never silently retried.
  • Distributed single-use consumption was validated on a real PostgreSQL across separate OS processes on one host. True multi-host consumption across networked machines is argued from PostgreSQL transactional guarantees, not yet demonstrated across hosts. This is a distributed-pilot, not production.
  • Authenticated MCP identity requires the auth middleware to be mounted; forged proxy headers are rejected as untrusted.

Next step

Add adversarial regression coverage for your MCP configuration with run-a-red-team-suite.md, or scan incoming files with scan-an-artifact.md.

Part of the EVE AI Core control plane Deterministic AI Governance Control Plane → Policy decisions that return the same result for the same input every time, before execution.