agent-bom includes a runtime security proxy (agent-bom proxy) that sits between MCP clients and servers, intercepting JSON-RPC messages in real time. This guide covers sidecar deployment, detector configuration, enforcement modes, and alert routing.
The proxy interposes on the stdio channel between an MCP client (Claude Desktop, Cursor, VS Code, etc.) and an MCP server. Every JSON-RPC message passes through the proxy, which:
- Logs every
tools/callinvocation to a JSONL audit trail - Detects anomalous or dangerous tool usage via seven inline detectors
- Enforces policy rules — optionally blocking tool calls that violate policy
- Tracks declared vs. actual tool usage (drift detection)
- Measures latency, call counts, and blocked-call metrics
| Detector | What it catches | Default mode |
|---|---|---|
| Tool drift | Tools invoked at runtime that were not declared in the tools/list response. Indicates a server exposing undeclared capabilities. |
Log |
| Argument analysis | Tool call arguments that match blocked regex patterns defined in policy (e.g., path traversal, SQL injection payloads). | Log |
| Credential leak | Arguments containing patterns that look like API keys, tokens, passwords, or connection strings being passed to tools. | Log |
| Rate limiting | Abnormal call frequency for a single tool within a time window — detects runaway loops or abuse. | Log |
| Sequence analysis | Suspicious sequences of tool calls (e.g., list_files followed by read_file on every file, or exec after write_file). |
Log |
| Response inspection | Cloaking, invisible Unicode, SVG/script payloads, and poisoned response content. | Log |
| Vector DB injection | Retrieved prompt chunks or vector-backed content attempting to coerce downstream tools or agents. | Log |
Build the slim runtime image:
docker build -f deploy/docker/Dockerfile.runtime -t agent-bom-runtime .Run as a wrapper around any MCP server:
docker run --rm \
-v $(pwd)/audit-logs:/var/log/agent-bom \
agent-bom-runtime \
--log /var/log/agent-bom/audit.jsonl \
--block-undeclared \
-- npx -y @modelcontextprotocol/server-filesystem /workspaceUse the provided deploy/docker-compose.runtime.yml for a complete sidecar example:
docker compose -f deploy/docker-compose.runtime.yml upThis starts:
- A filesystem MCP server (
npx @modelcontextprotocol/server-filesystem) - The agent-bom proxy sidecar intercepting all traffic
- Audit logs written to
./audit-logs/audit.jsonlon the host
Deploy the proxy as a sidecar container in the same pod as your MCP server:
apiVersion: apps/v1
kind: Deployment
metadata:
name: mcp-server
spec:
replicas: 1
selector:
matchLabels:
app: mcp-server
template:
metadata:
labels:
app: mcp-server
spec:
containers:
# MCP server container
- name: mcp-server
image: node:20-slim
command: ["npx", "-y", "@modelcontextprotocol/server-filesystem", "/workspace"]
volumeMounts:
- name: workspace
mountPath: /workspace
# agent-bom runtime proxy sidecar
- name: agent-bom-proxy
image: agent-bom-runtime:latest
args:
- "--log"
- "/var/log/agent-bom/audit.jsonl"
- "--block-undeclared"
- "--"
- "npx"
- "-y"
- "@modelcontextprotocol/server-filesystem"
- "/workspace"
volumeMounts:
- name: audit-logs
mountPath: /var/log/agent-bom
- name: workspace
mountPath: /workspace
volumes:
- name: workspace
emptyDir: {}
- name: audit-logs
persistentVolumeClaim:
claimName: audit-logs-pvcFor production Kubernetes deployments, mount the policy file from a ConfigMap:
volumes:
- name: policy
configMap:
name: agent-bom-policy# In the proxy container:
volumeMounts:
- name: policy
mountPath: /etc/agent-bom/policy.json
subPath: policy.jsonThen add --policy /etc/agent-bom/policy.json to the proxy args.
The proxy supports two operational modes:
All tool calls are allowed through. Every invocation is recorded in the JSONL audit log with full metadata (tool name, truncated arguments, timestamp). Use this mode to build a baseline of normal behavior before enabling enforcement.
agent-bom proxy --log audit.jsonl -- npx @mcp/server-filesystem /workspaceFor Claude Desktop, Claude Code, and Cortex JSON configs, you can auto-wrap eligible stdio servers:
agent-bom proxy-configure --log-dir ~/.agent-bom/logs --detect-credentialsAdd --apply to persist the wrapped config entries.
If you need cross-agent correlation and the broader 8-detector runtime engine, use agent-bom runtime protect --shield alongside or upstream of the proxy pipeline.
Add --block-undeclared and/or --policy policy.json to actively block tool calls:
agent-bom proxy \
--log audit.jsonl \
--policy policy.json \
--block-undeclared \
-- npx @mcp/server-filesystem /workspaceBlocked calls receive a JSON-RPC error response (code: -32600) and are recorded in the audit log with "policy": "blocked" and the reason.
Every tool call is appended to the JSONL log file as a single-line JSON object:
{"ts": "2026-02-26T12:00:00Z", "type": "tools/call", "tool": "read_file", "args": {"path": "/etc/passwd"}, "policy": "blocked", "reason": "Argument 'path' matches blocked pattern '/etc/(passwd|shadow)'"}When the proxy shuts down, it writes a summary record:
{"ts": "2026-02-26T12:05:00Z", "type": "proxy_summary", "uptime_seconds": 300.0, "total_tool_calls": 42, "total_blocked": 3, "calls_by_tool": {"read_file": 30, "write_file": 12}, "blocked_by_reason": {"policy": 2, "undeclared": 1}, "latency": {"min_ms": 1.2, "max_ms": 450.0, "avg_ms": 23.5, "p50_ms": 15.0, "p95_ms": 120.0, "count": 42}, "messages_client_to_server": 50, "messages_server_to_client": 48}Use the agent-bom watch command alongside the proxy to route alerts to Slack, Teams, or PagerDuty:
# In one terminal: run the proxy
agent-bom proxy --log audit.jsonl -- npx @mcp/server-filesystem /workspace
# In another terminal: watch the audit log and send alerts
agent-bom watch --webhook https://hooks.slack.com/services/T.../B.../xxx --log alerts.jsonlCompares the set of tools declared in the server's tools/list response against actual tools/call invocations. If a tool is called that was never declared, the proxy flags it as drift. This catches servers that expose hidden capabilities not visible during initial handshake.
Enable blocking with --block-undeclared.
Evaluates tool call arguments against regex patterns defined in a policy file. Common patterns include path traversal (../../etc/passwd), SQL injection payloads, and shell metacharacters. Each policy rule specifies an arg_pattern map of argument name to regex.
Scans tool call arguments for patterns that resemble secrets: API keys (prefixed strings like sk-, ghp_, AKIA), bearer tokens, connection strings with embedded passwords, and base64-encoded credentials. Prevents AI agents from inadvertently passing secrets to MCP tools.
Tracks call frequency per tool within a sliding time window. Detects runaway loops where an AI agent repeatedly calls the same tool (e.g., exec or write_file) in rapid succession, which may indicate a prompt injection driving automated actions.
Analyzes the order of tool calls to detect suspicious multi-step patterns. For example: list_directory followed by read_file on every discovered file (bulk exfiltration), or write_file followed by exec (code injection + execution).
Scans tool responses for cloaking tricks, invisible Unicode, SVG/script payloads, and other content that tries to smuggle instructions back into the agent.
Detects prompt-coercion or poisoning patterns from retrieval-backed tools and escalates them when the response clearly comes from vector or RAG-like sources.
agent-bom proxy --log /var/log/agent-bom/audit.jsonl \
-- npx @modelcontextprotocol/server-filesystem /workspaceagent-bom proxy \
--policy policy.json \
--log /var/log/agent-bom/audit.jsonl \
--block-undeclared \
-- npx @modelcontextprotocol/server-filesystem /workspace{
"rules": [
{
"id": "block-sensitive-paths",
"action": "block",
"arg_pattern": {
"path": "(/etc/(passwd|shadow|sudoers)|/root/\\.ssh)"
}
},
{
"id": "block-exec-tools",
"action": "block",
"block_tools": ["exec", "run_command", "shell"]
},
{
"id": "block-sql-injection",
"action": "block",
"arg_pattern": {
"query": "(DROP\\s+TABLE|DELETE\\s+FROM|UNION\\s+SELECT|;\\s*--)"
}
}
]
}Point Claude Desktop at the proxy instead of the raw MCP server:
{
"mcpServers": {
"filesystem": {
"command": "agent-bom",
"args": [
"proxy",
"--log", "/var/log/agent-bom/audit.jsonl",
"--policy", "/etc/agent-bom/policy.json",
"--block-undeclared",
"--",
"npx", "@modelcontextprotocol/server-filesystem", "/workspace"
]
}
}
}Use the runtime container directly from Claude Desktop:
{
"mcpServers": {
"filesystem": {
"command": "docker",
"args": [
"run", "--rm", "-i",
"-v", "./workspace:/workspace",
"-v", "./audit-logs:/var/log/agent-bom",
"agent-bom-runtime:latest",
"--log", "/var/log/agent-bom/audit.jsonl",
"--block-undeclared",
"--",
"npx", "-y", "@modelcontextprotocol/server-filesystem", "/workspace"
]
}
}
}Pre-built K8s manifests are available in deploy/k8s/:
| Manifest | Purpose |
|---|---|
namespace.yaml |
Creates the agent-bom namespace |
rbac.yaml |
ServiceAccount + ClusterRole (pod/namespace read) + ClusterRoleBinding |
cronjob.yaml |
Scheduled vulnerability scan every 6 hours across all namespaces |
daemonset.yaml |
Runtime protection monitor on every node via agent-bom protect --mode http |
sidecar-example.yaml |
MCP server + agent-bom proxy sidecar deployment example |
kubectl apply -f deploy/k8s/namespace.yaml
kubectl apply -f deploy/k8s/rbac.yaml
kubectl apply -f deploy/k8s/cronjob.yamlTo enable runtime monitoring on all nodes:
kubectl apply -f deploy/k8s/daemonset.yamlA Helm chart is provided in deploy/helm/agent-bom/ for customizable deployments:
# Install with defaults (scheduled scanner only)
helm install agent-bom deploy/helm/agent-bom/ -n agent-bom --create-namespace
# Enable runtime monitoring DaemonSet
helm install agent-bom deploy/helm/agent-bom/ -n agent-bom --create-namespace \
--set monitor.enabled=true
# Custom scan schedule (every 2 hours)
helm install agent-bom deploy/helm/agent-bom/ -n agent-bom --create-namespace \
--set scanner.schedule="0 */2 * * *"| Value | Default | Description |
|---|---|---|
scanner.enabled |
true |
Deploy the CronJob scanner |
scanner.schedule |
0 */6 * * * |
Cron schedule for scans |
scanner.allNamespaces |
true |
Scan all namespaces |
monitor.enabled |
false |
Deploy the DaemonSet runtime monitor |
monitor.port |
8423 |
HTTP port for the protect endpoint |
rbac.create |
true |
Create ClusterRole + ClusterRoleBinding |
To run the agent-bom proxy as a sidecar alongside your MCP server pod, see deploy/k8s/sidecar-example.yaml. The sidecar:
- Intercepts all JSON-RPC traffic between client and server
- Logs tool calls to
/var/log/agent-bom/audit.jsonl - Detects credential leaks and blocks undeclared tools
- Exposes Prometheus metrics on port 8422
Apply the example:
kubectl apply -f deploy/k8s/sidecar-example.yamlThe proxy exposes Prometheus-compatible metrics on port 8422 (configurable via --metrics-port):
agent-bom proxy --metrics-port 8422 --log audit.jsonl -- npx @mcp/server-filesystem /workspaceGET http://localhost:8422/metrics returns:
agent_bom_proxy_tool_calls_total{tool="read_file"} 42
agent_bom_proxy_blocked_total{reason="policy"} 3
agent_bom_proxy_uptime_seconds 300.5
agent_bom_proxy_total_tool_calls 45
agent_bom_proxy_total_blocked 3
agent_bom_proxy_latency_ms{quantile="0.5"} 15.0
agent_bom_proxy_latency_ms{quantile="0.95"} 120.0
agent_bom_proxy_replay_rejections_total 0
agent_bom_proxy_messages_total{direction="client_to_server"} 50
agent_bom_proxy_messages_total{direction="server_to_client"} 48
The sidecar example includes Prometheus annotations for auto-discovery:
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8422"
prometheus.io/path: "/metrics"To disable metrics, set --metrics-port 0.
A pre-built Grafana dashboard is available at deploy/grafana/grafana-agent-bom.json. Import it into Grafana (Dashboards > Import) to get:
- Severity distribution (donut + trend lines)
- Top blast radius scores and EPSS probabilities
- Per-agent vulnerability and credential exposure tables
- Proxy runtime panels (call rate, block reasons, latency p50/p95, replay rejections)
See deploy/grafana/README.md for setup details.