Skip to main content

Production MCP gateway: JWT auth, rate limiting, spending controls, audit log. mcp-guard serve --config mcp-guard.yaml

Project description

mcp-guard

CI PyPI License Python

Put auth, rate limits, spend caps, and audit logs in front of any MCP server โ€” without changing the server.

pip install "bonanza-mcp-guard[yaml]"
mcp-guard scan
mcp-guard serve --config mcp-guard.yaml

PyPI: package bonanza-mcp-guard (name mcp-guard was taken). CLI is still mcp-guard.

Demo

Sits in front of any MCP server over stdio. Zero required dependencies.

Complements static scanners like mcp-scan with a runtime stdio gateway (auth, limits, audit).

Why mcp-guard?

Without mcp-guard With mcp-guard
Any agent calls any tool Agent must authenticate (API key / JWT)
No spend ceiling Per-session spend caps, per-hour rate limits
No audit trail Every request logged to JSONL
Server exposed directly Gateway wraps server โ€” zero code changes

Complements static scanners like mcp-scan with a runtime stdio gateway (auth, limits, audit).


The problem

Security research in 2026 reported 1,800+ internet-exposed MCP endpoints with no authentication. Any MCP client can invoke tools with no identity, no spend ceiling, and no audit trail.

mcp-guard adds a gateway layer โ€” Claude Desktop, Cursor, Windsurf, or custom agents talk to mcp-guard; it talks to your real MCP server.


30-second try

pip install "bonanza-mcp-guard[yaml]"
mcp-guard scan

Example output:

๐Ÿ“ ~/Library/Application Support/Claude/claude_desktop_config.json
  โ„น๏ธ No mcpServers defined

Summary: 0 critical, 0 warnings

Then add a config and run the gateway:

mcp-guard serve --config mcp-guard.yaml

Wire into Claude Desktop:

{
  "mcpServers": {
    "guarded": {
      "command": "mcp-guard",
      "args": ["serve", "--config", "/path/to/mcp-guard.yaml"]
    }
  }
}

Quickstart

1. Install

pip install "bonanza-mcp-guard[yaml]"

1b. Audit your machine (no server needed)

mcp-guard scan

2. Configure (mcp-guard.yaml)

auth:
  mode: api_key
  keys:
    - "sk-agent-1"
    - "sk-agent-2"

servers:
  filesystem:
    command: npx @modelcontextprotocol/server-filesystem /data

policies:
  max_spend_per_session: 10.00
  audit_log: /var/log/mcp-guard.jsonl
  rate_limit:
    requests_per_minute: 100
    spend_per_hour_usd: 50.00

3. Agents include auth in requests

{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "_meta": { "api_key": "sk-agent-1" },
    "name": "wallet_request",
    "arguments": { "amount": 1.50 }
  }
}

Architecture

MCP Client (Claude Desktop / Cursor / custom agent)
    โ”‚
    โ–ผ  JSON-RPC over stdio
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  mcp-guard   โ”‚  auth โ†’ rate limit โ†’ spend check โ†’ audit
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
    โ”‚
    โ–ผ  forwards allowed requests
Your MCP Server (filesystem, wallet, fetch, anything)

1,168 lines of Python. Zero required dependencies.


Config reference

Key Type Default Description
auth.mode none | api_key | jwt none Authentication mode
auth.keys list[str] [] Valid API keys (mode=api_key)
auth.jwt_secret str โ€” HMAC-SHA256 secret (mode=jwt)
policies.rate_limit.requests_per_minute int โˆž Max requests per agent per minute
policies.rate_limit.spend_per_hour_usd float โˆž Max spend per agent per hour
policies.max_spend_per_session float โˆž Session spend cap
policies.require_approval_above float โˆž Threshold for manual approval
policies.audit_log str โ€” JSONL audit log path
servers map {} Backend MCP servers to proxy to

Authentication modes

API Key (simplest)

auth:
  mode: api_key
  keys:
    - "sk-agent-1"

Keys: _meta.api_key, _meta.token, Authorization: Bearer, or X-API-Key.

JWT (multi-agent)

auth:
  mode: jwt
  jwt_secret: "${JWT_SECRET}"
from mcp_guard.auth import create_jwt
token = create_jwt(secret="my-secret", agent_id="agent-007", ttl_seconds=3600)

None (dev/local)

auth:
  mode: none

Rate limiting & spending

policies:
  rate_limit:
    requests_per_minute: 60
    spend_per_hour_usd: 25.00
  max_spend_per_session: 10.00
  require_approval_above: 2.00

Spending tools: wallet_request, wallet_pay, x402_pay, etc. Blocked payments: JSON-RPC -32002.

Use with agent-budget (pip install bonanza-labs-agent-budget) for @budget on LLM calls.


Audit log

policies:
  audit_log: /var/log/mcp-guard.jsonl

Programmatic use

from mcp_guard import MCPProxy, GuardConfig

config = GuardConfig.from_dict({
    "auth": {"mode": "api_key", "keys": ["sk-abc"]},
    "policies": {"max_spend_per_session": 25.0},
})
proxy = MCPProxy.from_config(config)

Related (Bonanza Labs)

Project Role
agent-budget @budget(max_usd=โ€ฆ) for LLM + x402
bonanza-labs-fork-doctor Repo health before you ship

GitHub Action โ€” scan MCP configs on PRs

Automatically scan MCP config files in pull requests for security issues (missing auth, exposed remote URLs, no guard wrapper).

# .github/workflows/mcp-scan.yml โ€” already included in this repo
# Triggers on: **/claude_desktop_config.json, **/mcp.json, **/*mcp*.json/yaml

Add it to your repo:

uses: c6zks4gssn-droid/mcp-guard/.github/workflows/mcp-scan.yml@main

Or copy the workflow file directly. Fails PRs with critical findings and posts a comment with the full report.


Roadmap

v0.1.2 (next)

  • Docker image (docker run mcp-guard)
  • HTTP/SSE transport (mcp-guard serve-http)
  • Prometheus metrics endpoint (GET /metrics)
  • Approval queue โ€” hold tool calls above threshold for human approval
  • HTTP/SSE transport (not just stdio)
  • Tool allowlist/denylist per agent
  • Prometheus metrics endpoint

Future

  • Standalone GitHub Action (reusable workflow)
  • Web dashboard for audit log visualization
  • Multi-server routing (one gateway, many backends)
  • OAuth2 provider for agent-to-agent auth
  • Plugin system for custom policy checks

Launch: LAUNCH.md


Approval queue

When a spending tool call exceeds require_approval_above, the proxy holds it and returns error -32004 with the approval_id. A human reviews and approves/denies via the CLI:

policies:
  require_approval_above: 5.00
# List pending
mcp-guard approvals list --db ~/.mcp-guard/approvals.db

# Approve (short ID works)
mcp-guard approvals approve abc12345 --by admin

# Deny with reason
mcp-guard approvals deny abc12345 --by admin --reason "vendor untrusted"

Pending requests are persisted in SQLite โ€” survive restarts.


HTTP/SSE transport

For remote agents that connect over HTTP instead of stdio:

mcp-guard serve-http --config mcp-guard.yaml --port 8080

Endpoints:

Method Path Description
POST /rpc JSON-RPC request โ†’ response
GET /health Health check
GET /metrics Prometheus metrics

Auth over HTTP: X-API-Key header or Authorization: Bearer header.

curl -X POST http://localhost:8080/rpc \
  -H "Content-Type: application/json" \
  -H "X-API-Key: sk-agent-1" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

Docker

# Build
DOCKER_BUILDKIT=1 docker build -t mcp-guard .

# Run with config
DOCKER_BUILDKIT=1 docker run --rm -i \
  -v $(pwd)/mcp-guard.yaml:/etc/mcp-guard/config.yaml:ro \
  -v $(pwd)/logs:/var/log/mcp-guard \
  mcp-guard serve --config /etc/mcp-guard/config.yaml

Or with docker compose:

docker compose up

CI publishes to ghcr.io/c6zks4gssn-droid/mcp-guard on every tag.


Contributing

PRs welcome. The codebase is 1,168 lines across 8 modules โ€” small enough to hold in your head.

git clone https://github.com/c6zks4gssn-droid/mcp-guard
cd mcp-guard
pip install -e ".[yaml,dev]"
pytest

Project structure

mcp_guard/
โ”œโ”€โ”€ __main__.py    # CLI entry point (serve, scan)
โ”œโ”€โ”€ config.py      # GuardConfig + YAML/JSON loader
โ”œโ”€โ”€ auth.py        # API key + JWT providers
โ”œโ”€โ”€ proxy.py       # MCPProxy โ€” the intercept engine
โ”œโ”€โ”€ ratelimit.py   # Per-agent rate limiting
โ”œโ”€โ”€ audit.py       # JSONL audit logger
โ””โ”€โ”€ scan.py        # Local config scanner

License

Apache 2.0 ยท Bonanza Labs

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bonanza_mcp_guard-0.1.3.tar.gz (27.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

bonanza_mcp_guard-0.1.3-py3-none-any.whl (26.3 kB view details)

Uploaded Python 3

File details

Details for the file bonanza_mcp_guard-0.1.3.tar.gz.

File metadata

  • Download URL: bonanza_mcp_guard-0.1.3.tar.gz
  • Upload date:
  • Size: 27.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.5

File hashes

Hashes for bonanza_mcp_guard-0.1.3.tar.gz
Algorithm Hash digest
SHA256 38d71669c7476307e89a75d210f6480027590cf799a4ae6c2693f14759c51d19
MD5 fc441eae70c4fe65ef7a18497412c504
BLAKE2b-256 9dbe34ba06edea520e4dbacc7ce5a0a3d313d72dec69c22d35c927e875ff24b3

See more details on using hashes here.

File details

Details for the file bonanza_mcp_guard-0.1.3-py3-none-any.whl.

File metadata

File hashes

Hashes for bonanza_mcp_guard-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 260df446a585923f828f481ca06fdf3b647eea15ae06a7e42f000bf5e4443f38
MD5 582fc0663c07e22da48fd1b4a57db1a3
BLAKE2b-256 1ced6f6ce6c349b3d819d3001f6e67aedb22739c6c1a890f6616a3d514f33c68

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page