Novo: Aprovação de agentes, red teaming e varredura de modelos. Veja como
MITRITY
Docs / Primeiros passos / Demo: Mitrity MCP Sidecar

Demo: Mitrity MCP Sidecar

Run a self-contained Docker demo that exercises every governance capability through a realistic, scripted scenario. A Claude Agent SDK agent, wired to MITRITY with the mitrity adapter, works through the scenario while Mitrity MCP Sidecar governs both of the agent's entrances:

  • MCP tools (read_file, run_command, call_api, …) reach the model through the sidecar, which the SDK starts as its MCP server. The sidecar wraps an existing MCP tool server (demo-tools), passes its catalog through unchanged, and evaluates every tools/call against your policies before the upstream tool sees it.
  • The SDK's own built-in tools (Bash, Write, Edit) never produce an MCP call. The adapter installs a PreToolUse hook that admits each one through the sidecar's loopback admission API before the SDK runs it — same rules, same command analysis, same DLP, same audit trail, stamped surface=agent_hook. If the sidecar cannot be reached, the call is denied.

The demo takes about 14 minutes and requires only Docker Desktop and API keys.

Looking for the gateway version? See Demo: Mitrity Gateway for the multi-upstream variant with tool aggregation and the governed shell.

Want to see multi-agent delegation chains? See Demo: Multi-Agent Governance for a three-container compose stack exercising real agent-to-agent delegation, per-agent threat intel, and privilege boundaries.

Prerequisites

  • Docker Desktop (or any Docker runtime)
  • A MITRITY account with an active tenant
  • An Anthropic API key for the Claude agent

Step 1: Configure your dashboard

Before running the demo, set up three things in the MITRITY dashboard:

Register an agent

Go to Agents > Register Agent and create an agent:

  • Name: demo-agent
  • Mission scope: "Workspace file management and system operations"

Copy the Agent ID (UUID). Also copy the Agent Key (ak_...). Save it — it cannot be retrieved later.

Create policies

Tool patterns name their surface. An MCP tool passed through by the sidecar is mcp:<tool> — the upstream's own tool name, because the sidecar adds no namespace (mcp:read_file) — and one of the SDK's built-in tools is builtin:<tool> (builtin:bash). Create the following policies to see the full range of governance decisions:

PolicyTypePatternScope
Allow workspace readsallowmcp:read_file, mcp:list_directorypath starts with /workspace
Allow workspace writesallowmcp:write_filepath starts with /workspace
Allow safe commandsallowmcp:run_commandresolved commands ls, pwd, cat, echo, whoami
Block system filesdenymcp:read_file, mcp:delete_filepath outside /workspace
Block destructive commandsdenymcp:run_commandresolved commands rm, curl, wget, nc, chmod
Block dangerous SQLdenymcp:query_databasecontains DROP, DELETE, TRUNCATE
Hold production deploysholdmcp:call_apiurl contains "production"
Block destructive built-ins (phase 8)denybuiltin:bashresolved commands rm, curl, wget, nc, chmod

Also enable these global settings:

  • Prompt injection detection
  • DLP with PII and credential patterns — DLP applies to builtin:write content with no extra rule

Note: A pattern without a surface prefix (read_file on its own) matches nothing — it is an inert rule that looks like protection — and the control plane rejects one when a policy is created or updated. The full grammar is in Writing policies.

Created policies for an earlier version of this demo? The policy table used to list bare tool names (read_file, run_command, …). Recreate the policies above with mcp:<tool> patterns and add the builtin:bash rule for phase 8.

Step 2: Clone and configure

git clone git@github.com:mitrity-io/iag-demo-mcp-sidecar.git
cd iag-demo-mcp-sidecar
cp .env.example .env

Edit .env with your values:

ANTHROPIC_API_KEY=sk-ant-...              # Anthropic API key for Claude
MITRITY_AGENT_KEY=ak_...                  # Agent key from dashboard
MITRITY_CONTROL_PLANE_URL=https://api.mitrity.com
MITRITY_AGENT_ID=<uuid>                   # Agent UUID from dashboard

Step 3: Run the demo

docker compose up --build

The container builds locally — it pulls the Mitrity MCP Sidecar binary from ghcr.io and installs the adapter from PyPI, pinned to mitrity[claude-agent-sdk]==0.2.0 — then runs the scenario. Watch your terminal for the output. To try another adapter release, pass the pin as a build argument: docker compose build --build-arg MITRITY_PYTHON_SPEC='mitrity[claude-agent-sdk]==X.Y.Z'.

What the demo does

The scenario runs seven phases, numbered 1–6 and 8. There is no phase 7 here: delegation chains and threat intelligence are the multi-agent demo, which kept the number. There is no phase 9 either — see Why there is no governed-shell phase below.

Phase 1 — Normal Operations. The agent reads workspace files, writes summaries, lists directories, runs safe shell commands, and calls APIs. All actions pass through the sidecar and are allowed by your policies.

Phase 2 — Policy Violations. The agent attempts to read /etc/passwd, run rm -rf, execute curl, and issue a DROP TABLE query. The sidecar blocks each action and returns the policy reason.

Phase 3 — Prompt Injection. The agent processes "user input" that contains embedded injection payloads. The sidecar's injection detection engine catches and blocks the attacks before any tool executes.

Phase 4 — DLP & Data Protection. The agent tries to write files containing API keys and AWS secrets, send notifications with PII (SSNs, credit card numbers), and include credentials in API calls. The sidecar's DLP engine blocks data exfiltration.

Phase 5 — Escalation & Hold. The agent attempts a production deployment. The sidecar's hold policy pauses the action and creates an approval request visible in your MITRITY dashboard.

Phase 6 — Credential Broker + Hot Rotation. The agent calls connect_database with ${credential:demo_db_password} in the connection string. The sidecar resolves the placeholder via the broker; the upstream tool returns the password hash. Mid-phase you rotate the credential in the dashboard — the next call picks up the new value within 30 seconds with no agent or sidecar restart. A final sub-step exercises the fail-closed path with an unknown credential id. Requires creating a demo_db_password credential definition + grant in your tenant before running (see Credentials docs).

Phase 8 — Built-in Tools (admission hook). The agent uses the SDK's own Bash and Write tools instead of the MCP tools. An allowed ls runs; rm -rf is denied with the policy reason; the same command hidden behind bash -c '…' is still denied, because the edge parses the command tree rather than matching the first word; a .env file full of AWS and Stripe keys written with Write is blocked by DLP before it exists. Every decision is an audit row with surface=agent_hook.

Why there is no governed-shell phase

The gateway demo has a phase 9 in which an admitted built-in Bash is not executed by the SDK at all: the gateway routes it into its own sandboxed shell (builtin_exec_routing: governed_shell) and runs the judged bytes with egress confined to the agent's destination allowlist. The governed shell is part of the gateway. The sidecar admits built-in Bash through the hook — every call is judged, audited and, when the policy says so, denied — and the SDK then runs the allowed command itself. Keep the demo agent's policy on the default routing (builtin_exec_routing: framework): a policy that routes Bash into an edge without a governed shell is answered with a deny (routing_unavailable) rather than run ungoverned. If you want the governed shell, run the gateway demo.

What to look for

While the demo runs, open your MITRITY dashboard to see:

  • Audit Log: Every tool call with its governance decision, latency, and policy match. Phase 8 rows carry surface=agent_hook
  • Agent Detail: The demo agent's activity timeline, drift score, and Execution coverage card — fed by what the runtime attested at startup (which built-in tools are hooked, which are not, which other MCP servers are configured) and corroborated by the admission decisions the sidecar actually saw
  • Approval Requests: The held production deployment waiting for your approval (Phase 5)

The terminal prints the attestation when the session starts and, at the end, a summary with counts of allowed, blocked, and held actions plus the admission hook's own tally: built-in calls admitted, allowed, denied, held, and blocked because the edge could not be reached.

Architecture

The entire demo runs inside a single Docker container:

Docker Container
└── Python scenario runner (Claude Agent SDK)
    ├── built-in tools: Bash, Write, Edit ── PreToolUse hook (mitrity adapter)
    │                                          └── admission API (unix:/run/mitrity/admission.sock)
    └── MCP server "mitrity" = Mitrity MCP Sidecar (stdio, governance wrapper)
        └── demo-tools (the wrapped MCP server; catalog passed through unchanged)
            ├── read_file, write_file, list_directory, delete_file
            ├── run_command
            ├── call_api, query_database, send_notification
            └── connect_database (Phase 6 — broker-substituted credential)

One sidecar process serves both entrances: the MCP tools/call stream from the SDK and the loopback admission API the hook calls. It connects to your MITRITY control plane over HTTPS for policy evaluation, event reporting and heartbeat, and attests the runtime's posture — which built-in tools are hooked, which are not, other MCP servers, the permission mode — so the agent's coverage badge reflects what is actually governed. Filesystem and shell tools execute for real against the container's /workspace directory. API tools return mock responses.

The adapter is mitrity.claude_agent_sdk.Governor from the mitrity package on PyPI (pip install 'mitrity[claude-agent-sdk]'). scenario/runner.py shows the few lines that wire it up: the sidecar is declared as the SDK's MCP server, the hook is installed on the built-in tools, and the SDK's permission callback allows everything MITRITY allows. To govern your own Claude Agent SDK or Claude Code agent the same way, see Installing the hook.

Gateway vs Sidecar

Both demos run the same governance scenario. The difference is in the deployment model — not in governance fidelity. Both binaries share the same interceptor (TI, delegation, DLP, injection, holds, credential broker) and both serve the loopback admission API; the choice is about where each sits in the MCP request path:

MCP Sidecar (this demo)Mitrity Gateway
RoleTransparent proxy in front of one existing MCP serverIs the MCP server, aggregating many sources
Tool sources1 upstream serverMultiple upstreams + native HTTP tools
Tool namesFlat (read_file) — passed through unchangedNamespaced (fs__read_file) — applied per upstream
Policy pattern for an MCP toolmcp:<tool> (mcp:read_file)mcp:<namespace>__<tool> (mcp:fs__read_file)
Admission APIServed alongside the proxy (phase 8)Served alongside the MCP surface (phase 8)
Governed shellNot available — an admitted built-in Bash is run by the frameworkRoutes an admitted built-in Bash into its own sandboxed shell (phase 9)
Credential broker injectionYes (arg-rewrite + file mounts)Yes (arg-rewrite + file mounts + native HTTP headers)
Best forRetrofit onto an existing MCP server without changing the agentAggregating many tool sources behind one governed endpoint

For a deeper comparison, see Integration modes.

Environment variables

VariableRequiredDescription
ANTHROPIC_API_KEYYesAnthropic API key for Claude
MITRITY_AGENT_KEYYesAgent key from dashboard
MITRITY_CONTROL_PLANE_URLYesControl plane URL
MITRITY_AGENT_IDYesAgent UUID from dashboard
MITRITY_DEMO_SPEEDNonormal (default) or fast (skip pauses)
ANTHROPIC_MODELNoClaude model (default: claude-sonnet-5)

Troubleshooting

  • Every built-in tool call is denied with "MITRITY could not authorize this action" — the hook could not reach the sidecar's admission API. The sidecar logs its startup on stderr; it refuses to start when /run/mitrity is not owned by the container user or is group- or world-writable (the image creates it as demo, mode 0700).
  • Phase 8's rm -rf runs — the builtin:bash deny rule is missing from the agent's policy.
  • An MCP tool call is not decided by the rule you expect — check that the pattern carries its surface prefix (mcp:read_file, not read_file). The decision reason in the demo output and the audit event name the rule that matched.

Customization

  • Policies: Modify policies in the MITRITY dashboard and re-run the demo to see different behaviors
  • Workspace: Mount your own files via volumes in docker-compose.yml. The container runs as the unprivileged user demo (uid 1000); on a Linux host, make the mounted directory writable by that uid, or set user: in docker-compose.yml to match its owner
  • Scenarios: Edit files in scenario/phases/ to add custom test prompts

Next steps