Demo: MCP execution binding — changed argument is blocked with mismatch evidence

EVE cryptographically binds the approved MCP request to the executed request. Any mutation between approval and execution is rejected before the side effect. This demo approves an MCP tool call, changes one approved argument at execution time, and shows the request is blocked with mismatch evidence.

Synthetic MCP server and recording tool. No production credentials.

Readiness

  • MCP execution binding: PILOT_READY.
  • MCP distributed deployment: distributed-pilot validated in the documented test topology.
  • Python only for MCP governance (mcp_gateway / embedded service modes).

Setup

# demo_mcp_binding.py — synthetic fixtures only
from core.eve_sdk import EVE

IDENT = {"tenant_id": "acme", "principal_id": "agent-1", "session_id": "sess-1"}
calls = []  # recording target for the synthetic MCP tool

def mcp_send_email(**kwargs):
    """Synthetic MCP tool. Records; sends nothing."""
    calls.append(kwargs)
    return {"message_id": "M-1", "status": "queued"}

eve = EVE(policy="lending_v1", mode="embedded")
APPROVED_ARGS = {"to": "compliance@acme.example", "subject": "Q3 report", "body": "attached"}

Code

# 1) Approve a specific MCP request. EVE binds intent + capability schema + server identity
#    + context digests to the approval.
approval = eve.approve_mcp_call(
    tool="send_email",
    arguments=APPROVED_ARGS,
    context=IDENT,
    server="mcp://mail.internal",
)
assert approval.approved

# 2) Execute EXACTLY the approved request -> digests match -> ALLOW -> tool runs once.
ok = eve.govern_mcp_call(
    tool="send_email",
    arguments=APPROVED_ARGS,             # unchanged
    context={**IDENT, "approval_id": approval.approval_id},
    server="mcp://mail.internal",
)
assert ok.allowed
if ok.allowed:
    mcp_send_email(**APPROVED_ARGS)
assert len(calls) == 1

# 3) Change ONE approved argument at execution time -> digest mismatch -> BLOCK.
tampered = dict(APPROVED_ARGS, to="attacker@evil.example")   # recipient changed
blocked = eve.govern_mcp_call(
    tool="send_email",
    arguments=tampered,
    context={**IDENT, "approval_id": approval.approval_id},
    server="mcp://mail.internal",
)
assert not blocked.allowed, "changed argument must be blocked"
assert len(calls) == 1, "mismatch must not execute the MCP tool"
print("decision:", blocked.action, blocked.reason_codes)

Expected decision

Step Verdict MCP tool executed
execute approved request unchanged ALLOW yes (1 recorded)
execute with changed to argument BLOCK (digest mismatch) no

Expected evidence

MCP execution evidence records the approved digests and the executed digests; on the tampered call they differ and the authorization is not consumed for the executed side effect:

{"action": "BLOCK",
 "mcp": {"approved_digests": "...", "executed_digests": "...(differ)...",
         "authorization_consumed": true},
 "reason_codes": ["...digest_mismatch..."],
 "certificate": {"content_hash": "...", "signature": "ed25519-...", "canon": "jcs-1"}}

Verification command

from core.eve_sdk import verify_evidence
v = verify_evidence("mcp_execution", blocked.certificate, expected_tenant="acme")
assert v["valid"], v.get("reason")
print("verify:", v["valid"])   # -> True

Zero-side-effect assertion

len(calls) == 1: only the unchanged, approved MCP request executed. The tampered request was rejected before mcp_send_email could run.

Cleanup

calls.clear()

No external state created.

Limitations

  • Binding provides at-most-once authorization consumption and approved-equals-executed matching. Remote outcomes are not assumed: an unknown remote outcome is recorded as OUTCOME_UNKNOWN and never silently retried.
  • Cross-process single-use consumption was validated across separate OS processes on one host with a PostgreSQL-authoritative backend; true multi-host consumption across networked machines is argued from PostgreSQL transactional guarantees, not yet demonstrated across hosts.
  • PILOT_READY, not production.
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.