Skip to main content

MCP Firewall Proxy — policy-based tool access control using NAIL effects

Project description

mcp-fw

CI PyPI version Python License: MIT

日本語版 README

MCP servers can read your files, run processes, and access the network — all without asking.

mcp-fw is a firewall proxy that sits between Claude Desktop and MCP servers. It uses NAIL effect labels to control exactly what each server can do.

By default, mcp-fw allows tools subject to effect policy, but blocks MCP resources and prompts unless you explicitly opt in with allow_resources: true / allow_prompts: true.

Claude Desktop  ←→  mcp-fw (proxy)  ←→  MCP Server
                     ↑
                  policy.yaml
                  allow: [FS, IO]
                  deny:  [NET]

Why

MCP servers are powerful — but there's no built-in permission model. A filesystem server could silently make network calls. An "everything" server could spawn processes.

mcp-fw enforces boundaries:

Effect What it controls Example
FS File read/write Read a file, list directory
IO General I/O stdin/stdout, echo
NET Network access HTTP requests, DNS
PROC Process execution Spawn subprocess, exec
TIME Time/clock access Get current time
RAND Randomness Generate random numbers

Quick Start

pip install mcp-fw

Commands

Primary CLI:

mcp-fw run --config policy.yaml --server filesystem [--verbose] [--log-file /path/to/file.log]
mcp-fw inspect --config policy.yaml --server filesystem
mcp-fw status --server filesystem
mcp-fw stop --server filesystem
mcp-fw claude-remove [--server filesystem]
mcp-fw menubar --config policy.yaml

Legacy shorthand still supported:

mcp-fw --config policy.yaml --server filesystem [--verbose] [--log-file /path/to/file.log]

Dedicated menubar entry point:

mcp-fw-menubar --config policy.yaml

1. Write a policy

# policy.yaml
servers:
  filesystem:
    command: npx
    args: ["@modelcontextprotocol/server-filesystem", "/tmp"]
    allow: [FS, IO]
    deny: [NET]

This lets the filesystem server read/write files (FS, IO) but blocks all network access (NET). It also keeps MCP resources and prompts blocked unless you explicitly enable them.

2. Point Claude Desktop to the proxy

In claude_desktop_config.json:

{
  "mcpServers": {
    "filesystem-fw": {
      "command": "mcp-fw",
      "args": ["--config", "/path/to/policy.yaml", "--server", "filesystem"]
    }
  }
}

That's it. Claude Desktop now talks to mcp-fw, which filters tools before forwarding to the real server.

If your server uses MCP resources or prompts, opt in explicitly:

servers:
  filesystem:
    allow_resources: true
    allow_prompts: true

To remove mcp-fw entries later:

mcp-fw claude-remove
# or only one server
mcp-fw claude-remove --server filesystem

3. See what happened

$ mcp-fw --config policy.yaml --server filesystem --verbose
2025-01-15 10:00:01 [INFO] Filtered 5 → 3 tools (allowed effects: ['FS', 'IO'])
2025-01-15 10:00:05 [WARNING] Blocked tool call: fetch_url

To stop a running proxy process:

mcp-fw stop --server filesystem

To inspect how NAIL classified tools before changing policy:

mcp-fw inspect --config policy.yaml --server filesystem

The output shows inferred effects, effective effects after overrides, whether an override changed classification, and the final allowed/blocked result.

Menubar App (macOS)

For a GUI experience:

pip install "mcp-fw[menubar]"
mcp-fw menubar --config policy.yaml
# or:
mcp-fw-menubar --config policy.yaml

A [FW] icon appears in your menubar:

[FW]
├── mcp-fw v0.2.8
├── ────────
├── ● filesystem
│   ├── Status: Running
│   ├── Checked = allowed, unchecked = blocked
│   ├── ────────
│   ├── [x] FS
│   ├── [x] IO
│   ├── [ ] NET          ← toggle effects live
│   ├── [ ] PROC
│   ├── Stop Proxy
│   └── ...
├── ○ everything
├── ────────
├── Edit Policy YAML
├── View Logs...
├── ────────
├── Sync to Claude Desktop
├── Remove from Claude Desktop
└── Quit
  • Toggle effects with checkboxes — checked means allowed, unchecked means blocked, and changes are written to policy.yaml instantly
  • Sync to Claude Desktop generates claude_desktop_config.json entries automatically
  • Stop Proxy terminates a running proxy process for a server
  • Remove from Claude Desktop deletes generated *-fw entries from claude_desktop_config.json
  • View Logs opens a live log viewer
  • Process monitor shows ● running / ○ stopped status per server

How It Works

1. Claude calls list_tools()
   → mcp-fw forwards to the real server
   → NAIL annotates each tool with effect labels
   → mcp-fw filters out tools that violate the policy
   → Claude only sees allowed tools

2. Claude calls a tool
   → mcp-fw checks if it's in the allowed set
   → Allowed: forward to server
   → Blocked: return error

The key insight: tools aren't just allowed or denied by name — they're classified by what they do (filesystem, network, process, etc.) using NAIL's effect system. This means mcp-fw can enforce policies on servers it has never seen before.

Policy Reference

servers:
  my-server:
    command: npx                    # server command
    args: ["@org/server", "/tmp"]   # command arguments
    allow: [FS, IO]                 # permitted effects (empty = all)
    deny: [NET]                     # blocked effects (overrides allow)
    allow_resources: false          # permit MCP resources API
    allow_prompts: false            # permit MCP prompts API
    tool_overrides:                 # per-tool effect corrections
      safe_fetch: [IO]             # override NAIL's auto-detection

Rules:

  • allow: [] (empty) = all effects permitted, then deny subtracts
  • allow: [FS, IO] = only these effects, then deny subtracts
  • deny always wins over allow
  • allow_resources and allow_prompts are explicit opt-ins; by default they are blocked
  • tool_overrides lets you correct NAIL's automatic effect detection for specific tools

License

MIT

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

mcp_fw-0.2.8.tar.gz (65.0 kB view details)

Uploaded Source

Built Distribution

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

mcp_fw-0.2.8-py3-none-any.whl (46.9 kB view details)

Uploaded Python 3

File details

Details for the file mcp_fw-0.2.8.tar.gz.

File metadata

  • Download URL: mcp_fw-0.2.8.tar.gz
  • Upload date:
  • Size: 65.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for mcp_fw-0.2.8.tar.gz
Algorithm Hash digest
SHA256 7868974fc3fa92a9b024411195a28a357a83e919ff3cc1cb7b598b604b6da66f
MD5 30f0df80465bdc7a62c1fe2799d7590a
BLAKE2b-256 0e3a0ce3d8cd40f93fa53e7adeea51c02be96c5bcc3ee0ca60bf83545852786b

See more details on using hashes here.

Provenance

The following attestation bundles were made for mcp_fw-0.2.8.tar.gz:

Publisher: publish.yml on zyom45/mcp-fw

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mcp_fw-0.2.8-py3-none-any.whl.

File metadata

  • Download URL: mcp_fw-0.2.8-py3-none-any.whl
  • Upload date:
  • Size: 46.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for mcp_fw-0.2.8-py3-none-any.whl
Algorithm Hash digest
SHA256 14d996b66ec36c79b23e9499016f58db1b8ed11d6f5479e643aaea1e0b3ba218
MD5 0b6f55730987a6db9e6c0de65583689a
BLAKE2b-256 5e5663fa11b069a1fbece7c700d585ef333195003ae3d60307e7ead2cbab2e27

See more details on using hashes here.

Provenance

The following attestation bundles were made for mcp_fw-0.2.8-py3-none-any.whl:

Publisher: publish.yml on zyom45/mcp-fw

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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