A transparent proxy that intercepts high-risk tool calls with OTP approval.
π₯ MCP Action Firewall
Works with any MCP-compatible agent
A transparent MCP proxy that intercepts dangerous tool calls and requires OTP-based human approval before execution. Acts as a circuit breaker between your AI agent and any MCP server.
How It Works
ββββββββββββ stdin/stdout ββββββββββββββββββββ stdin/stdout ββββββββββββββββββββ
β AI Agent β ββββββββββββββββββΊ β MCP Action β ββββββββββββββββββΊ β Target MCP Serverβ
β (Claude) β β Firewall β β (e.g. Stripe) β
ββββββββββββ ββββββββββββββββββββ ββββββββββββββββββββ
β
Policy Engine
βββββββββββββββββ
β Allow? Block? β
β Generate OTP β
βββββββββββββββββ
MCP servers don't run like web servers β there's no background process on a port. Instead, your AI agent (Claude, Cursor, etc.) spawns the MCP server as a subprocess and talks to it over stdin/stdout. When the chat ends, the process dies.
The firewall inserts itself into that chain:
Without firewall:
Claude ββspawnsβββΊ mcp-server-stripe
With firewall:
Claude ββspawnsβββΊ mcp-action-firewall ββspawnsβββΊ mcp-server-stripe
So you just replace the server command in your MCP client config with the firewall, and tell the firewall what the original command was:
Before (direct):
{ "command": "uvx", "args": ["mcp-server-stripe", "--api-key", "sk_test_..."] }
After (wrapped with firewall):
{ "command": "uv", "args": ["run", "mcp-action-firewall", "--target", "mcp-server-stripe --api-key sk_test_..."] }
Then the firewall applies your security policy:
- β
Safe calls (e.g.
get_balance) β forwarded immediately - π Dangerous calls (e.g.
delete_user) β blocked, OTP generated - π Agent asks user for the code β user replies β agent calls
firewall_confirmβ original action executes
Installation
pip install mcp-action-firewall
# or
uvx mcp-action-firewall --help
Quick Start β MCP Client Configuration
Add the firewall as a wrapper around any MCP server in your client config:
{
"mcpServers": {
"stripe": {
"command": "uv",
"args": ["run", "mcp-action-firewall", "--target", "mcp-server-stripe --api-key sk_test_abc123"]
}
}
}
That's it. Everything after --target is the full shell command to launch the real MCP server β including its own flags like --api-key. The firewall doesn't touch those args, it just spawns the target and sits in front of it.
More Examples
Claude Desktop with per-server rules
{
"mcpServers": {
"stripe": {
"command": "uv",
"args": [
"run", "mcp-action-firewall",
"--target", "uvx mcp-server-stripe --api-key sk_test_...",
"--name", "stripe"
]
},
"database": {
"command": "uv",
"args": [
"run", "mcp-action-firewall",
"--target", "uvx mcp-server-postgre
Tools (1)
firewall_confirmConfirms a pending high-risk action using an OTP code.Configuration
{"mcpServers": {"stripe": {"command": "uv", "args": ["run", "mcp-action-firewall", "--target", "mcp-server-stripe --api-key sk_test_abc123"]}}}