Policy enforcement for MCP agents

Intercept
Every
Tool Call.

A transparent proxy between your AI agent and its MCP server. Define policies in YAML. Every tool call is evaluated, logged, and governed before it reaches upstream.

Install Read the docs

Enforcement Log

$ intercept -c policy.yaml \
  -- npx -y server-github

# Agent calls delete_repository...

[INTERCEPT POLICY DENIED]
Repository deletion is not
permitted via AI agents

# Agent calls create_issue (6th)...

[INTERCEPT POLICY DENIED]
Hourly limit of 5 new issues
reached

01 / The Problem

No Guardrails

Agents call tools with no spending limits, no rate limits, no access control. Prompt-based safety is probabilistic—it works until it doesn't. There is no hard stop.

02 / The Mechanism

Block at the Wire

Transparent proxy at the MCP transport layer. YAML policies compiled to deterministic rules. Stateful evaluation with sliding-window counters. Blocked before it reaches upstream.

03 / The Outcome

Total Control

Rate limits, spend caps, argument validation, unconditional blocks. Shadow mode to observe before enforcing. The agent cannot reason around it.

Real Policies, Real Enforcement

From the policy reference. Every snippet runs as-is.

Server Rule Policy YAML
GitHub Block repo deletion
delete_repository:
  rules:
    - name: "block repo deletion"
      action: "deny"
      on_deny: "Repo deletion not permitted"
GitHub Rate-limit issue creation
create_issue:
  rules:
    - name: "hourly issue limit"
      rate_limit: 5/hour
      on_deny: "Hourly limit of 5 new issues reached"
Stripe Daily spend cap ($10k)
create_charge:
  rules:
    - name: "daily spend cap"
      conditions:
        - path: "state.create_charge.daily_spend"
          op: "lte"
          value: 1000000
      on_deny: "Daily spending cap of $10,000.00 reached"
      state:
        counter: "daily_spend"
        window: "day"
        increment_from: "args.amount"
Stripe Currency restriction
create_charge:
  rules:
    - name: "allowed currencies"
      conditions:
        - path: "args.currency"
          op: "in"
          value: ["usd", "eur"]
      on_deny: "Only USD and EUR charges are permitted"
Any Global rate limit
"*":
  rules:
    - name: "global rate limit"
      rate_limit: 60/minute
Any Allowlist mode
version: "1"
default: deny    # only listed tools are permitted

tools:
  read_file:
    rules: []    # allowed, no additional checks
  create_issue:
    rules:
      - name: "hourly limit"
        rate_limit: 5/hour

Three Commands to Enforcement

Scan discovers your tools. You write the rules. Intercept enforces them.

01 / Scan

Discover

Connect to any MCP server and generate a policy scaffold. Every tool is listed with its parameters as comments.

intercept scan -o policy.yaml \
  -- npx -y server-github

02 / Edit

Define

Add rules to the generated YAML. Rate limits, spend caps, unconditional blocks. The scaffold shows you what's available.

delete_repository:
  rules:
    - name: "block deletion"
      action: "deny"
      on_deny: "Not permitted"

03 / Run

Enforce

Start the proxy. It launches the upstream server, proxies all MCP traffic, and enforces your policy on every tool call.

intercept -c policy.yaml \
  -- npx -y server-github

How It Works

One proxy. Every tool call evaluated before reaching upstream.

01

Intercept

Agent sends a tool call. Intercept captures it at the MCP transport layer before it reaches the server.

02

Evaluate

Policy engine checks the call against YAML-defined rules, conditions, and stateful counters.

03

Decide

Allow: forward to upstream server. Deny: return the reason to the agent. No ambiguity.

04

Track

Update counters, log the decision. If upstream fails, roll back the increment automatically.

Built for Production

State Backends

SQLite + Redis

SQLite by default—zero config, works out of the box. Redis for shared state across multiple Intercept instances. Key prefixing for namespace isolation.

Event Logging

Structured Audit Trail

Every decision logged as newline-delimited JSON. Tool name, result, rule name. Arguments hashed for privacy. 7-day auto-retention.

Hot Reload

Edit Without Restart

Intercept watches the policy file. Save and new rules take effect immediately. Invalid config is rejected—previous rules stay active. Counters are never reset.

Drop Into Any MCP Client

Point your .mcp.json at Intercept instead of the server. Works with Claude Code, Claude Desktop, or any MCP client.

Local Server (stdio)

Intercept launches the server as a child process and proxies stdin/stdout.

{
  "mcpServers": {
    "github": {
      "command": "intercept",
      "args": [
        "-c", "policy.yaml",
        "--",
        "npx", "-y",
        "@modelcontextprotocol/server-github"
      ],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "..."
      }
    }
  }
}

Remote Server (--upstream)

Intercept bridges stdio to HTTP. The agent spawns Intercept; Intercept talks to the remote server.

{
  "mcpServers": {
    "stripe": {
      "command": "intercept",
      "args": [
        "-c", "policy.yaml",
        "--upstream",
        "https://mcp.stripe.com",
        "--header",
        "Authorization: Bearer tok"
      ]
    }
  }
}
"Why not prompt guardrails?"

Prompts are probabilistic. The model can ignore, misinterpret, or be injected past them. Intercept is deterministic—the tool call is physically blocked at the wire before it reaches the server.

"What if the state backend is down?"

Fail-closed by default. Tool calls requiring state evaluation are denied until the backend recovers. Configurable with --state-fail-mode open for non-critical setups.

"Does the agent know?"

Intercept is fully transparent. The agent sees the same tools, same names, same behaviour. It only becomes aware when a policy denies a call—it receives a denial message explaining why.

"Can I update policies live?"

Yes. Intercept watches the policy file and hot-reloads on save. New rules take effect immediately. Invalid config is rejected; previous config stays active. Counters are never reset.

"What about allowlist mode?"

Set default: deny at the top of your policy. Only tools explicitly listed are permitted—everything else is rejected before rules are even evaluated.

"What transports are supported?"

Stdio with child process, stdio bridged to a remote HTTP server (--upstream), and HTTP/SSE. Transport is auto-detected from flags. See the CLI reference.

Install Intercept

go install github.com/policylayer/intercept@latest

Then: intercept scan -o policy.yaml -- npx -y @modelcontextprotocol/server-github