npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@vikingowl/mcp-firewall

v1.0.1

Published

Security firewall proxy for MCP servers — policy enforcement, redaction, sandboxing, and supply chain controls

Readme

mcp-firewall

A security firewall proxy for Model Context Protocol (MCP) servers. Sits between your AI client and downstream MCP servers, enforcing policy, redacting sensitive data, sandboxing processes, and verifying supply chain integrity.

Features

  • Policy Engine — CEL-based rules with allow, deny, and prompt effects. First-match-wins evaluation, fail-closed on error.
  • Interactive Approvalprompt effect triggers MCP elicitation for user confirmation, with configurable timeout.
  • Redaction — Regex patterns applied to tool input arguments and output content before they reach the client.
  • Process Sandbox — Per-downstream Linux sandboxing via user/network namespaces and Landlock LSM filesystem restrictions. Graceful degradation on unsupported platforms.
  • Supply Chain Controls — SHA-256 hash pinning and path allowlisting for downstream binaries, verified before any process is spawned.
  • Multi-Server Proxy — Route multiple downstream MCP servers through a single firewall with __-namespaced tools and resources.
  • Multi-Profile Config — Named configuration profiles with environment-based selection and workspace-scoped local overrides (restrict-only merge).
  • Audit Logging — Structured JSON logs with append-only SHA-256 hash chain, tracking policy decisions, redaction, sandbox status, and hash verification.
  • Introspection — Built-in explain_effective_policy tool returns the resolved configuration with provenance annotations.

Installation

npx (recommended for MCP clients)

npx -y @vikingowl/mcp-firewall --config /path/to/config.yaml

Go install

go install github.com/VikingOwl91/mcp-firewall/cmd/mcp-firewall@latest

GitHub Releases

Download prebuilt binaries from GitHub Releases for Linux, macOS, and Windows (amd64/arm64).

Quick Start

1. Create a config file

npx -y @vikingowl/mcp-firewall --init
# Creates ~/.mcp-firewall/config.yaml with a commented template

2. Move your existing MCP servers into the firewall config

Take the servers from your MCP client config and add them as downstreams in ~/.mcp-firewall/config.yaml. For example, if your client config looks like this:

{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"]
    },
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/projects"]
    }
  }
}

Move them into the firewall config as downstreams:

downstreams:
  github:
    command: npx
    args: ["-y", "@modelcontextprotocol/server-github"]
  filesystem:
    command: npx
    args: ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/projects"]

policy:
  default: deny
  rules:
    - name: allow-safe-tools
      expression: 'tool.name == "search" || tool.name == "list"'
      effect: allow
    - name: prompt-for-writes
      expression: 'tool.name.startsWith("write")'
      effect: prompt
      message: "This tool will modify data. Approve?"

3. Replace your MCP client config with the firewall

Replace all your server entries with a single firewall entry:

{
  "mcpServers": {
    "firewall": {
      "command": "npx",
      "args": ["-y", "@vikingowl/mcp-firewall", "--config", "~/.mcp-firewall/config.yaml"]
    }
  }
}

All your servers are now proxied through the firewall. Tools are namespaced automatically (e.g., github__create_issue, filesystem__read_file), and all requests go through policy evaluation, redaction, and audit logging.

4. Run directly (optional)

mcp-firewall --config config.yaml

Configuration

Minimal Config

downstreams:
  echo:
    command: ./my-echo-server

Full Reference

# Downstream MCP servers
downstreams:
  myserver:
    command: /usr/local/bin/my-server    # Executable path
    args: ["--flag"]                      # Command arguments
    env: ["API_KEY=secret"]               # Environment variables
    timeout: 10s                          # Per-downstream timeout override
    sandbox: strict                       # Sandbox profile name (or "none")
    hash: "sha256:abc123..."              # SHA-256 hash pin

# Policy engine
policy:
  default: deny                           # Default effect: allow | deny
  rules:
    - name: rule-name
      expression: 'CEL expression'        # Must evaluate to bool
      effect: allow                       # allow | deny | prompt
      message: "Custom prompt message"    # Optional, for prompt effect

# Redaction
redaction:
  patterns:
    - name: api-keys
      pattern: 'sk-[a-zA-Z0-9]{32}'      # Regex pattern

# Supply chain controls
supply_chain:
  allowed_paths:
    - /usr/local/bin
    - ~/trusted-tools

# Sandbox profiles
sandbox_profiles:
  custom:
    network: false                        # Block network access
    env_allowlist: [PATH, HOME]           # Env var whitelist
    fs_deny: [/root, /sys]               # Deny filesystem access
    fs_allow_ro: [/etc, /usr]            # Read-only access
    fs_allow_rw: [/tmp]                  # Read-write access
    workspace: true                      # Allow workspace directory access

# Global settings
timeout: 30s                              # Default tool/resource timeout
approval_timeout: 2m                      # Interactive approval timeout
max_output_bytes: 524288                  # Output truncation limit
log_level: info                           # debug | info | warn | error

CEL Expression Variables

| Variable | Type | Description | |----------|------|-------------| | method | string | Request method ("tools/call", "resources/read", etc.) | | server | string | Downstream alias | | tool.name | string | Tool name (when method == "tools/call") | | tool.arguments | map | Tool arguments (when method == "tools/call") | | resource.uri | string | Resource URI (when method == "resources/read") |

Use has() guards for optional fields: has(tool.arguments.filename) && tool.arguments.filename.startsWith("/etc")

Profiles

Define named configuration profiles for different environments:

# Inline defaults (used when no profile is selected)
downstreams:
  myserver:
    command: ./server

policy:
  default: allow

# Named profiles
profiles:
  production:
    downstreams:
      myserver:
        command: /opt/server
        sandbox: strict
        hash: "sha256:..."
    policy:
      default: deny
      rules:
        - name: allow-reads
          expression: 'tool.name.startsWith("read")'
          effect: allow

Select a profile:

mcp-firewall --config config.yaml --profile production
# or
MCP_FIREWALL_PROFILE=production mcp-firewall --config config.yaml

Local Overrides

Place a .mcp-firewall/config.yaml in your workspace directory to add restrictions:

# Local overrides can only add restrictions, not loosen them
policy:
  rules:
    - name: block-dangerous
      expression: 'tool.name == "delete_everything"'
      effect: deny

redaction:
  patterns:
    - name: internal-tokens
      pattern: 'ghp_[a-zA-Z0-9]{36}'

Local overrides are automatically detected from the working directory, or specify explicitly:

mcp-firewall --config config.yaml --workspace /path/to/project

Restrictions: Local overrides cannot modify downstreams, profiles, supply_chain, or policy.default. Deny/prompt rules are prepended; allow rules are rejected unless the base config enables allow_expansion. Timeouts can only be lowered.

CLI Flags

| Flag | Default | Description | |------|---------|-------------| | --config | ~/.mcp-firewall/config.yaml | Path to config file | | --init | | Create default config file and exit | | --profile | (env/inline) | Config profile name | | --workspace | (auto-detect) | Workspace directory for local overrides | | --generate-lockfile | | Compute SHA-256 hashes for all downstreams and print YAML | | --version | | Print version and exit |

Supply Chain Verification

Pin downstream binaries to known hashes:

# Generate hashes for all downstreams
mcp-firewall --config config.yaml --generate-lockfile

Output:

downstreams:
  myserver:
    hash: "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"

Copy the hash values into your config. The firewall will verify each binary before spawning it.

Introspection

The firewall exposes an explain_effective_policy tool that returns the resolved configuration as JSON, including:

  • Active profile and local override path
  • Merged policy rules with source provenance (inline, profile:name, local)
  • Redaction patterns with provenance
  • Sandbox capabilities and per-downstream profiles
  • Supply chain verification results

Audit Logging

All requests are logged to stderr as structured JSON with:

  • Policy decision (allow/deny/prompt) and matching rule
  • Redaction status
  • Sandbox level (full/partial/minimal)
  • Hash verification status
  • Approval action (accept/decline/cancel/timeout/unsupported)
  • Sequential hash chain (audit_seq, entry_hash, prev_hash) for tamper detection

Platform Support

| Feature | Linux | macOS | Windows | |---------|-------|-------|---------| | Policy engine | Yes | Yes | Yes | | Redaction | Yes | Yes | Yes | | Interactive approval | Yes | Yes | Yes | | Sandbox (namespaces) | Yes | No* | No* | | Sandbox (Landlock) | Yes (5.13+) | No* | No* | | Supply chain | Yes | Yes | Yes |

*Sandbox features gracefully degrade to minimal isolation on unsupported platforms. Use strict mode in sandbox profiles to fail instead of degrading.

License

MIT