Policy enforcement layer between AI agents and MCP servers — intercept, validate, and secure every tool call before it reaches the upstream.
AI agents are powerful, but they can also be dangerous. A single errant DROP TABLE or rm -rf / can destroy hours of work. This project sits between your AI agent and your MCP servers, acting as a security guard for every tool invocation — rate limiting, argument validation, cost tracking, read-only enforcement, and human-in-the-loop approval chains.
If you're deploying AI agents that talk to databases, filesystems, or any MCP server, this is your safety net.
┌─────────────────┐ ┌──────────────────────┐ ┌─────────────────┐
│ AI Agent │────▶│ tool-use-firewall │────▶│ Upstream MCP │
│ (Claude, │ │ (Interceptor │ │ Server │
│ GPT, etc.) │◀────│ Pipeline) │◀────│ (Database, │
└─────────────────┘ └──────────────────────┘ │ Filesystem, │
│ Network, etc.) │
└─────────────────┘
The interceptor pipeline enforces policies in strict order:
Request → Rate Limiter → Cost Tracker → Secret Scanner → Argument Validator
→ Schema Validator → Policy Engine → Read-Only Check → Anomaly Detector
→ Approval Workflow → Audit Logger → Upstream
Stages are registered only when enabled in the policy (e.g. secret scanning, schema validation, and anomaly detection are opt-in). Inbound JSON-RPC frames may be single messages or batches (top-level arrays); each tools/call in a batch is intercepted independently.
Data flow details and state management: ARCHITECTURE.md
- Rule evaluation — Block, allow, or require approval by tool name, argument values, and custom conditions
- Priority-based matching — Rules evaluated in priority order; first match wins
- Glob pattern matching —
db.*matchesdb.execute,db.query, etc.
- Token bucket algorithm — Global, per-tool, and per-session limits
- Bounded memory — TTL-based eviction prevents memory exhaustion
- Burst capacity — Configurable burst allowance for traffic spikes
- SQL injection detection — Pattern matching against known dangerous patterns
- Shell injection prevention — Blocks metacharacters like
;,&&,`,$() - Custom regex patterns — User-defined validation per tool/argument
- JSON Schema validation — Validate
tools/callarguments against the upstream's advertisedinputSchema - ReDoS protection — All regex patterns validated for safety before compilation
- Outbound secret detection — Block tool calls whose arguments contain API keys, tokens, or other secrets
- Custom patterns — Define named patterns per deployment
- Behavioral baselines — Flags tool calls that deviate from a session's recent pattern
- Configurable sensitivity — Tune the window size and threshold per policy
- Global toggle — Block all write operations when enabled
- Per-tool exceptions — Allow-list for read-only safe tools
- Break-glass tokens — Timing-safe bypass for emergencies
- Per-session budgets — Enforce cost limits for expensive tool calls
- Tool-level pricing — Assign costs per invocation
- Configurable action — Block or warn when budget exceeded
- Multi-level chains — Require approval from multiple groups
- Timeout handling — Expired approvals automatically denied
- Multiple interfaces — HTTP API, CLI prompts, webhook, Slack, and Discord notifications
- Auto-approval — Optionally auto-approve trusted tools after a threshold of safe calls
- Rate-limited API — Per-IP token bucket on the approval HTTP endpoint
- Structured JSON — Every decision recorded with full context
- Sensitive data redaction — API keys, tokens, emails automatically redacted
- Level control —
none,summary, orfullverbosity - File & sidecar output — Write events to a rotating local file (daily/size rotation, max-files retention, gzip) and/or forward them over HTTP to a sidecar/SIEM endpoint (stdout is reserved for the MCP JSON-RPC stream)
- stdio & HTTP — Run as a stdio proxy (default) or expose an HTTP transport
- Multi-upstream — Route tools to different upstream MCP servers by glob pattern
- Time windows — Restrict rules to specific days/hours with timezone support
- Policy hot-reload — Edits to the policy file are picked up without a restart
- Dry-run / shadow mode — Log what would be blocked without enforcing
- Prometheus metrics — Optional
/metricsendpoint (requests, blocks, approvals, latency) --initscaffolding — Generate a starter policy from the upstream'stools/list--validatelinting — Validate a policy (schema + ReDoS) in CI without booting the proxy
The published entry point is tool-use-firewall, which ships the tool-use-firewall binary and pulls in the @reaatech/tool-use-firewall-* packages. Run it without installing via npx:
npx tool-use-firewall \
--config ./policy.yaml \
--upstream node ./my-mcp-server.jsOr install the CLI globally:
npm install -g tool-use-firewall
tool-use-firewall --config ./policy.yaml --upstream node ./my-mcp-server.jsRequires Node.js ≥ 20.
tool-use-firewallis a thin alias for@reaatech/tool-use-firewall-server— use whichever name you prefer. For a narrower dependency surface, import the scoped@reaatech/tool-use-firewall-*packages directly.
Generate a starter policy from your upstream server's tool list, then run the firewall against it:
# 1. Scaffold a policy.generated.yaml from the upstream's tools/list
tool-use-firewall --init --upstream node ./my-mcp-server.js
# 2. Validate it (schema + ReDoS checks) — exits non-zero on failure, good for CI
tool-use-firewall --validate ./policy.generated.yaml
# 3. Run the proxy
tool-use-firewall --config ./policy.generated.yaml --upstream node ./my-mcp-server.jsTo plug into an MCP client (e.g. Claude Desktop), point the client at the firewall instead of the upstream:
{
"mcpServers": {
"my-server": {
"command": "npx",
"args": [
"@reaatech/tool-use-firewall-server",
"--config", "/abs/path/to/policy.yaml",
"--upstream", "node",
"--", "/abs/path/to/my-mcp-server.js"
]
}
}
}With the human-in-the-loop approval API enabled:
export APPROVAL_API_TOKEN="$(openssl rand -hex 32)"
tool-use-firewall \
--config ./policy.yaml \
--upstream node ./my-mcp-server.js \
--approval-port 8080Use --upstream-args for container/scripted environments where the upstream command and its args are a single string:
tool-use-firewall --config ./policy.yaml --upstream node --upstream-args "./my-mcp-server.js --port 9000"import { MCPProxyServer } from '@reaatech/tool-use-firewall-server';
const server = new MCPProxyServer({
policyPath: './policy.yaml',
upstreamCommand: 'node',
upstreamArgs: ['./my-mcp-server.js'],
});
await server.start();git clone https://github.com/reaatech/tool-use-firewall.git
cd tool-use-firewall
pnpm install
pnpm build
pnpm test
# Run the local build against an example upstream
pnpm dev -- --config ./policies/default.yaml --upstream node ./examples/basic-proxy/upstream-server.jstool-use-firewall --config <path> --upstream <command> [options]
| Flag | Description |
|---|---|
--config, -c <path> |
Path to the policy YAML file (required to run the proxy) |
--upstream, -u <command> |
Command to spawn the upstream MCP server (required to run the proxy) |
--upstream-args <string> |
Space-separated args for the upstream, for scripted environments |
--approval-port <port> |
Port for the human-in-the-loop approval HTTP API |
--http-port <port> |
Port for the HTTP transport |
--dry-run |
Shadow mode: log what would be blocked without enforcing |
--init |
Scaffold a policy.generated.yaml from the upstream's tools/list |
--validate <path> |
Validate a policy (schema + ReDoS) and exit non-zero on failure |
--help, -h |
Show help |
--version, -v |
Show version |
Arguments after a literal -- are forwarded to the upstream:
tool-use-firewall --config p.yaml --upstream node -- ./mcp-server.js --port 9000| Package | Description | Dependencies |
|---|---|---|
core |
Types, error classes, logger, redactor, safe-regex | (none) |
config |
Policy YAML schema (Zod) and loader | core, yaml, zod |
policies |
Policy engine, rate limiter, cost tracker, validators | core, config |
approvals |
Approval workflow, HTTP API, CLI/webhook approvers | core, config, policies, express, zod |
audit |
Audit logging with redaction | core, config |
server |
MCP proxy server, CLI, interceptor pipeline | core, config, policies, approvals, audit |
See policies/ for example YAML files:
| Policy | Description |
|---|---|
default.yaml |
Sensible defaults — rate limits, SQL safety, shell safety |
database-safe.yaml |
Database-focused policy with strict SQL validation |
read-only.yaml |
Read-only mode with bypass token support |
| Document | Content |
|---|---|
| ARCHITECTURE.md | System design, pipeline flow, resource management |
| CONTRIBUTING.md | Development setup, conventional commits, PR process |
| AGENTS.md | Coding conventions and guidance for AI agents |
| SECURITY.md | Security policy and vulnerability reporting |
| Layer | Technology |
|---|---|
| Language | TypeScript 5.8 (strict mode) |
| Runtime | Node.js ≥ 20 |
| Package manager | pnpm 10 (workspaces) |
| Build | tsup + Turborepo |
| Lint & format | Biome |
| Testing | Vitest |
| Validation | Zod |
| Schema | YAML |
Contributions are welcome. See CONTRIBUTING.md for the full workflow:
- Fork the repo, create a feature branch
- Write code with tests (
vitest), lint withbiome - Run
pnpm lint && pnpm testbefore committing - Use Conventional Commits
- Open a PR