Repository navigation
Integrations agentgateway
Experimental: this works and is tested, but may change and gets less hardening than the stable core. It is tested against the protocol and the span attributes in agentgateway's source, not against a running agentgateway.
agentgateway (a Linux Foundation project) is a proxy for MCP, A2A and LLM traffic. Tracekit works with it in two ways, which you can use together:
The ext_mcp processor |
The OTLP import | |
|---|---|---|
| What it does | Decides each MCP tools/call in the signer before agentgateway forwards it, holds an ask for a person, and records the result |
Records each MCP tools/call agentgateway traced, after it ran |
| Gates calls | Yes, and fails closed | No |
| Arguments and results | Committed to by the signer | Not in agentgateway's spans |
| Evidence |
source: gateway, tier T2, when the agent reaches its MCP servers only through agentgateway |
source: import, tier T3: the spans were received |
agentgateway's mcpGuardrails policy can call a remote processor over gRPC (agentgateway.dev.ext_mcp.ExtMcp) before
it forwards an MCP request and again with the result. tracekit ext-mcp serve is that processor. It needs grpcio
and a v2 signer, and listens on loopback only, so run it next to agentgateway, in its pod or on its host:
pip install 'tracekit-ai[grpc]'
TRACEKIT_SIGNER=https://signer.internal:8443 TRACEKIT_SIGNER_CERT=tls/ext-mcp.pem TRACEKIT_SIGNER_KEY=tls/ext-mcp.key \
tracekit ext-mcp serve --listen 127.0.0.1:9091It reaches the signer as itself (TRACEKIT_SIGNER_TOKEN_FILE or TRACEKIT_SIGNER_CERT/_KEY). In signer.yaml, list
it under gateways and grant it the calls it makes for the agents:
gateways: ["mtls:spiffe://acme.org/tracekit-ext-mcp"]
authorize: {"mtls:spiffe://acme.org/tracekit-ext-mcp": [decide, complete, approval_request, approval_wait, approval_consume]}In agentgateway's config, add the processor to the MCP route's policies:
binds:
- port: 3000
listeners:
- routes:
- policies:
mcpGuardrails:
processors:
- kind: remote
host: 127.0.0.1:9091
methods: {"tools/call": full} # request and response
failureMode: failClosed # agentgateway's default: the processor unreachable denies the call
metadata:
caller: '"mtls:" + source.spiffeId' # who agentgateway authenticated, as the signer names them
tracekit_call: 'mcpGuardrails.tracekit_call' # carries the call's id to the response
backends:
- mcp:
targets:
- name: everything
stdio: {cmd: npx, args: ["-y", "@modelcontextprotocol/server-everything"]}-
callermust be the identity the agent's run token was issued to (scheme:subject). Build it from what agentgateway authenticated:source.spiffeIdwith client certificates,jwt.subwith JWT authentication. Never build it from a header the agent sets. - The agent registers its run with the signer and sends
X-Tracekit-Run: <run_id>.<run_token>on every MCP request to agentgateway, as it would to Tracekit's MCP gateway. agentgateway forwards the request's headers to the processor (unlessrequestHeadersfilters them out), and to HTTP MCP servers too, except on atools/callthe processor passes: its answer has agentgateway removeX-Tracekit-Runfirst. Other methods (tools/list, resources) don't reach the processor and still carry it. A run token is bound to the agent's identity, so it is no use to a server without the agent's credentials.
-
Decided as
mcp:<target>/<tool>, with its arguments, forcallerunder the agent's run token. That is the name the MCP gateway and the MCP adapter use, so one policy covers all three. The target and tool names are agentgateway's native ones (everything,echo), not its multiplexedeverything_echo. -
Allowed: the processor passes the call and agentgateway forwards it. agentgateway then sends the processor the
result, which completes the call (an
isErrorresult as an error). -
Refused: a deny, a rejected or expired approval, the signer unreachable, no run or caller, or params that don't
parse. The processor answers
PERMISSION_DENIEDwith the reason, which agentgateway returns to the agent as a tool error. The MCP server never sees the call. -
Ask: agentgateway gives a processor 10 seconds, so the processor can't hold a call for a person. It asks for
approval and refuses the call at once with
approval requested; make the same call again once a person approves it: a worker waiting on a person would hold up the other agents' calls. Approve it (tracekit approvals approve apr-…); the same call again, with the same run, caller, tool and arguments, then passes and uses up the approval. A call with other arguments asks again. -
Other methods pass undecided. List only
tools/callinmethods.
agentgateway's response hook carries neither the request nor a call id. So when the processor passes a call, it
returns the call's id as processor metadata tracekit_call, which agentgateway keeps with the request
(mcpGuardrails.tracekit_call in CEL); the tracekit_call metadata entry above sends it back with the result. The
processor could instead write the id into the request's _meta, but that reaches the MCP server, not the response
hook.
-
Records: a
policy.decisionfor each tools/call, committing to its arguments, naming the processor (via) and the agent (caller); approval records; atool.resultcommitting to the redacted result. Allsource: gateway, tier T2, as for the MCP gateway. -
T2 holds only if the agent reaches its MCP servers only through agentgateway and can't connect to the processor.
The processor takes whoever calls it for agentgateway, with its
callerand its results. -
Doesn't see errors: agentgateway sends a JSON-RPC error (an upstream failure, a timeout) to the agent without
calling the response hook. Such a call has a decision and no result; when its run ends the signer waits
gateway_wait_sand then writes aheld_call_unresolvedgap: the call may have run. So does a result over 64 MiB, which the processor refuses (RESOURCE_EXHAUSTED) and agentgateway'sfailClosedturns into an error. -
Doesn't check how agentgateway authenticated the agent. The signer checks that the run token was issued to
caller. -
Decides only tools/call:
resources/readandprompts/getgo through agentgateway unrecorded. -
Forgets on restart: the processor keeps pending asks and the calls awaiting their results in memory, up to
10,000 each. After a restart a retried call asks again, and the result of a call passed before it isn't recorded
(the run ends with a
held_call_unresolvedgap for it).
agentgateway exports one span per request. Point its tracing at the signer's
OTLP import (an otlp section in signer.yaml, and the otlp_import
grant for agentgateway's identity):
frontendPolicies:
tracing:
host: signer.internal:8443
protocol: http
path: /v1/traces
randomSampling: true
parentNotSampled: "true" # trace a request even when its traceparent says not to
policies:
backendTLS: {root: tls/tracekit-ca.pem, cert: tls/agentgateway.pem, key: tls/agentgateway.key}-
Recorded: each request span whose
mcp.method.nameistools/callbecomes atool.calland atool.result, namedmcp:<mcp.target>/<gen_ai.tool.name>like the processor's records. It failed when the span's status is an error or it carriesmcp.error.code. The outbound and guardrail spans under it (agentgateway.outbound.*) and other methods are skipped, so each call is recorded once. -
One run per trace. Unless the agent sends
traceparent, each request is its own trace, so its own run, closed as its span arrives. Withtraceparentthe request span has a parent agentgateway doesn't export, so the run stays open untilidle_sand counts against agentgateway'sopen_runs(100 by default) meanwhile. -
No arguments or results: agentgateway's spans carry the tool's name and outcome. Its tracing
attributescan add CEL values (mcp.tool.arguments,mcp.tool.result) asgen_ai.tool.call.argumentsandgen_ai.tool.call.result, which the import reads. - T3: the import proves the spans were received, nothing about completeness, and gates nothing. Only sampled requests are exported.
Limits lists these with what to do.
Generated from docs/ at v1.4.1. Edit the docs in the repository, not here.
Get started
- Quickstart: the v2 signer
- Quickstarts
- Quickstart: Claude Agent SDK
- Quickstart: a custom agent
- Quickstart: LangChain and LangGraph
- Quickstart: MCP client
- Quickstart: OpenAI Agents SDK
- Coding agents other than Claude Code
- tracekit doctor
- Walkthrough: Tracekit end to end
How it works
- How Tracekit works
- Overview
- The life of a tool call
- The evidence format
- Verification and assurance
- Witnesses and monitoring
- Policy
- Approvals
- Detection and containment
- Capture and completeness
- Custody
- Provenance and tracekit why
- Deployment and isolation
- Storage, durability and performance
- Integrations
- Security model
- Architecture
- tracekit why: architecture
Integrations
- Integrations
- Adapters
- OpenTelemetry
- Remote clients
- Kubernetes agent-sandbox
- agentgateway
- agentsh and Tracekit
- Browser Use
- Claude Agent SDK
- Claude Code's sandbox
- Codex's sandbox
- CrewAI
- Docker MCP Gateway
- E2B
- Falco
- Gemini CLI's sandbox
- Google ADK
- Haystack
- LangChain v1
- LiteLLM
- LlamaIndex
- MCP client
- microsandbox
- Microsoft Agent Framework
- OpenAI Agents SDK
- NVIDIA OpenShell
- Pydantic AI
- sandbox-runtime's proxy on its own
- Strands Agents
- Tetragon
- Vercel AI SDK
- Wassette
Policy and approvals
- Policy reference
- Approvals
- Findings
- Reading the model's reasoning
- Incidents and containment
- Webhooks
Deploy and operate
- Deploying the signer
- The signer as a container
- The signer on Kubernetes
- The compose stack
- Identity
- Tool executor
- MCP gateway
- LLM gateway
- Egress observation
- Witnesses
- Log monitor
- Record-key issuer
- Signer observability
- Viewer
- tracekit why: causal investigation and replay
- Migrating
- Platforms
Verify the evidence
- Reading a v2 verify report
- Evidence format v2
- Auditor guide
- Sample evidence bundle
- Signing
- What Tracekit guarantees
Security and privacy
- Threat model: the v2 signer
- Threat model: the v1 laptop signer
- HTTP security checklist
- Threat-model review packet
- Privacy
- Known limits and trade-offs
- What's stable
Compliance
- Compliance mapping
- EU AI Act
- ISO/IEC 42001
- NIST AI RMF and the Generative AI Profile
- OWASP Top 10 lists for LLM and agentic applications
Evaluation
Demos
- Demos
- Agent approvers within bounds
- Completeness and tamper evidence
- Detection and containment
- Network coverage: an egress observer
- Guardrails: allow, deny, or ask a person
- MCP tools, gated and recorded
- Prompt injection held by provenance
- Why: which input caused the action
Help