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

@11ai/mcp-gate

v0.2.1

Published

Fail-closed MCP proxy that gates agent tool calls with Execution Governance.

Readme

@11ai/mcp-gate

npm version npm downloads CI License: Apache-2.0

A firewall for MCP tool calls. Add one line to your config — no code changes.

mcp-gate is a fail-closed stdio proxy that sits between any MCP client (Claude Desktop, Claude Code, Cursor, anything) and any MCP server. Every tools/call is checked against your policy before it's forwarded. Denied calls never reach the server — the client gets a JSON-RPC error and a signed receipt records the attempt.

No API key. No network. No telemetry.

One-line install

Wrap any MCP server by changing its command in your client config:

Before

{
  "command": "node",
  "args": ["their-server.js"]
}

After

{
  "command": "npx",
  "args": ["-y", "@11ai/mcp-gate", "--policy", "eg-policy.yaml", "--", "node", "their-server.js"]
}

That's it. initialize, tools/list, resources, and notifications pass through untouched. Only tools/call is gated.

Why you want this

MCP servers run with your credentials and your filesystem. A prompt-injected agent can call any tool the server exposes — exfiltrate secrets, POST data to attacker URLs, delete files. Reviewing logs afterward doesn't undo it.

mcp-gate decides before the call runs:

  • Deny by policy — block outbound calls carrying secret material, writes outside allowed paths, dangerous shell commands, whatever your policy says.
  • Fail-closed — engine error, timeout, malformed policy? The call is denied. There is no fail-open path.
  • Signed receipts — every allow and every deny is Ed25519-signed, SHA3-512 hashed, and chained. Verify the file offline with eg-verify, no access to the machine required.

What a denial looks like

The client receives a JSON-RPC error instead of a tool result, and the receipt log records:

{
  "tool": "http.post",
  "decision": "deny",
  "reason": "exfiltration: outbound call carrying secret material",
  "policyVersion": "starter-1",
  "sig": "…"
}

Policy

Start from the canonical starter policy and edit YAML — allow/deny rules per tool, argument matching, path and URL constraints. Full schema: docs/POLICY.md.

CLI reference

mcp-gate --policy <file> [options] -- <server-command> [args...]

| Flag | Purpose | | ------------------- | --------------------------------------------------------------------------------------------------------------------------------- | | --policy <path> | Policy file. Required unless EG_CONTROL_PLANE_URL is set. Malformed policy = every call denied. | | --receipts <path> | Append signed receipts here (default ./eg-receipts.jsonl). | | --key <path> | Ed25519 seed for a stable signing key. Without it a key is generated per run and receipts are not verifiable across restarts. | | --timeout <ms> | Policy evaluation timeout. A timeout is a deny. | | --name <name> | Tool namespace prefix. Defaults to a name derived from the wrapped command. See the warning below — this affects policy matching. | | --validate | Check the policy and exit. Starts no server, writes no receipts. Safe in CI. | | -h, --help | Show usage and exit 0. | | -- | Everything after is the wrapped server command, verbatim. |

Set --key before you rely on the receipts. Without it, a new signing key is generated per run and receipts cannot be verified across restarts. Each run's receipts still verify against that run's own key, so nothing looks broken — the failure only appears later, when you try to verify an older file and no longer have the key it was signed with. The gate warns on startup when it generates an ephemeral key.

--name is part of what your policy matches on. Tool calls are evaluated as <name>.<tool>, so a rule written for their-server.http_post stops matching if the prefix changes. The default is derived from the wrapped command, which means editing the command in your client config can change the prefix as a side effect — and a rule that no longer matches is a rule that no longer denies. Set --name explicitly and the prefix stops depending on how the server happens to be launched.

Validate a policy before you depend on it:

npx @11ai/mcp-gate --validate --policy eg-policy.yaml

Exits 0 with the policy version, or 1 naming the fault. This runs the engine's own parser rather than a schema check, so it catches what a schema cannot: a rule naming an actionClass that was never declared, and an argsPattern that is not a compilable regex. Both produce a policy that loads as valid YAML and then denies every call, which looks identical to a very strict policy.

Exit behavior: if the wrapped server exits, the gate exits with the same code. If the gate cannot start (bad policy, missing binary), it exits nonzero and no server starts — fail-closed extends to process lifecycle.

Works with

  • Claude Desktop / Claude Code — wrap any server in claude_desktop_config.json or .mcp.json
  • Cursor, Windsurf, any MCP client — anything that launches stdio MCP servers
  • Any MCP server — filesystem, GitHub, databases, browsers; the gate is server-agnostic

Versioning

Semver, tracks @11ai/execution-governance minors. The receipt format is versioned independently; old receipt files stay verifiable.

The @11ai packages

| Package | What it is | | ---------------------------------------------------------------------------------------- | ------------------------------------------------ | | @11ai/execution-governance | SDK: gate any function call, not just MCP. | | @11ai/mcp-gate | This package. | | @11ai/identity-oidc (coming) | OIDC-verified principals bound to every receipt. | | execution-governance on PyPI (coming) | Python SDK, cross-verifiable receipts. |

Part of Execution Governance

Built on @11ai/execution-governance — the SDK for gating any function call (not just MCP) with the same policy engine and receipt chain. Try the prompt-injection demo:

git clone https://github.com/11-11AI/execution-governance && cd execution-governance
npm install && npm run demo

License

Apache-2.0. Fully functional locally — no account, no hosted dependency. See LICENSE. LICENSING.md sets out, per component, what is open permanently and what is commercial: every part needed to verify a receipt is Apache-2.0 and stays that way.