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


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.2.tar.gz (23.7 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.2-py3-none-any.whl (23.0 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: bonanza_mcp_guard-0.1.2.tar.gz
  • Upload date:
  • Size: 23.7 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.2.tar.gz
Algorithm Hash digest
SHA256 05dbb8b345415f041ffeaee2985cf13297a48371331c3cfcadbfa9e270625e82
MD5 157689c1bdb5ce9c68b90a3f5fec71c8
BLAKE2b-256 6acc338a00a3d72cc693f27a00839ecb5b887892b5dd1893b72423a6a25287a3

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for bonanza_mcp_guard-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 8575bb9689f8acbf28c9557eb28278d65e68a9a5ec91bfc37c8aceb299e9aae6
MD5 765667c4b789f08a858c40d19f9bddd5
BLAKE2b-256 fdd5fd48c881f9bed794b54581b8a6568b823612bfee0f6778bda8db1a4e7eac

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