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

@soterai/mcp-gateway

v0.2.0

Published

SoterAI MCP Gateway — inline MCP enforcement proxy with policy-based tool-call interception, approval workflow, and result secret-scanning. Zero-dependency, works with any MCP-aware AI stack.

Readme

@soterai/mcp-gateway

Inline Model Context Protocol (MCP) enforcement proxy with policy-based tool-call interception, human-in-the-loop approval, and result secret-scanning. Zero-dependency at runtime, TypeScript-native.

Sponsored by SoterAI.

What it does

MCP Client (Claude, Cursor, your agent, …)
    │  JSON-RPC (HTTP or stdio)
    ▼
┌──────────────────────────────────────────────┐
│  @soterai/mcp-gateway                        │
│  ─────────────────────────                   │
│  1. SessionManager   — identity binding,     │
│     tenant/project isolation, session TTL    │
│  2. evaluatePolicy   — your callback decides │
│     ALLOW / DENY / ASK / REDACT per call     │
│  3. ApprovalManager  — one-shot execution    │
│     tokens with expiry for ASK verdicts      │
│  4. MCPResultInspector — secret/PII redaction │
│     on tool responses before they leave      │
│  5. Evidence log     — every decision gets   │
│     a trace ID, hash, risk score             │
└──────────────────────────────────────────────┘
    │
    ▼
Upstream MCP server (the real tool host)

A tool call that violates policy is never forwarded upstream. An approval-gated call executes exactly once per approval token. Secrets in the tool response are always redacted before the client sees them.

Why this instead of raw MCP

| Capability | raw MCP | @soterai/mcp-gateway | | ----------------------------------- | ------- | -------------------- | | Per-tool allow / deny decisions | ❌ | ✅ via evaluatePolicy | | Approval workflow with one-shot tokens | ❌ | ✅ | | Secret / PII redaction in results | ❌ | ✅ | | Tenant / project session isolation | ❌ | ✅ | | Rate limiting | ❌ | ✅ | | Circuit breaker on upstream failure | ❌ | ✅ | | Rate-limited, auth-token-gated HTTP | ❌ | ✅ | | Audit evidence (trace IDs, hashes) | ❌ | ✅ |

Install

npm install @soterai/mcp-gateway

Node ≥ 18 required (uses native fetch, crypto.randomUUID).

Quick start — CLI

# Proxy stdio: start the gateway around a local MCP server
npx soterai-mcp-gateway --stdio "npx -y @modelcontextprotocol/server-filesystem /tmp"

# Proxy HTTP: forward to a remote MCP endpoint
npx soterai-mcp-gateway --url http://localhost:8080/mcp --port 47322

The gateway listens on 127.0.0.1:47322 by default. Point your MCP client at http://127.0.0.1:47322/mcp.

Quick start — library

import { MCPJsonRpcGateway, DEFAULT_GATEWAY_CONFIG } from "@soterai/mcp-gateway";

const gateway = new MCPJsonRpcGateway(
  {
    ...DEFAULT_GATEWAY_CONFIG,
    upstreamEndpoint: { transport: "http", address: "http://localhost:8080/mcp" },
    tenant: "my-tenant",
    project: "my-project",
    protectionMode: "standard",
  },
  {
    evaluatePolicy: ({ serverName, toolName, args }) => {
      // Return ALLOW / DENY / ASK / REDACT
      if (toolName === "shell_exec") {
        return {
          action: "DENY",
          riskScore: 95,
          reasonCodes: ["SHELL_EXEC_DISABLED"],
          categories: ["shell"],
          explanation: "Shell execution is disabled by policy",
          redactedArgsPreview: "",
        };
      }
      if (toolName === "filesystem_write") {
        return {
          action: "ASK",
          riskScore: 60,
          reasonCodes: ["WRITE_NEEDS_APPROVAL"],
          categories: ["filesystem"],
          explanation: "Filesystem write requires approval",
          redactedArgsPreview: "",
        };
      }
      return {
        action: "ALLOW",
        riskScore: 0,
        reasonCodes: [],
        categories: [],
        explanation: "Allowed",
        redactedArgsPreview: "",
      };
    },
  }
);

// Feed JSON-RPC messages in (from an HTTP route, stdio, or a socket)
const response = await gateway.processMessage(
  { jsonrpc: "2.0", method: "tools/call", params: { name: "read_file", arguments: { path: "/etc/passwd" } }, id: 1 },
  { tenant: "my-tenant", project: "my-project", clientId: "client-1", userId: "user:alice" },
);

Policy callback contract

evaluatePolicy(request: {
  serverName: string;     // upstream server identity if known
  toolName: string;       // e.g. "read_file"
  args: Record<string, unknown>; // already-sanitized arguments
  protectionMode?: string; // observe | standard | strict | enterprise_locked | air_gapped
}) => {
  action: "ALLOW" | "DENY" | "ASK" | "REDACT" | "TRANSFORM" | "BLOCK" | "QUARANTINE" | "ABSTAIN";
  riskScore: number;      // 0..100
  reasonCodes: string[];
  categories: string[];
  explanation: string;
  redactedArgsPreview: string;
}
  • ALLOW — forward to upstream and return the result
  • DENY / BLOCK — return an isError result; never touches upstream
  • ASK — mint an approval ID, hold the call until approved via HTTP route
  • REDACT — execute but run the result inspector on the response
  • ABSTAIN — recorded as an abstention; fails closed when failClosed

HTTP routes

MCPServer exposes:

| Path | Method | Purpose | | ----------------------------- | ------ | ------------------------------ | | /mcp | POST | JSON-RPC endpoint | | /health | GET | Liveness + version | | /session/:id/approvals | POST | Approve a pending tools/call | | /approvals/:approvalId | GET | Inspect an approval |

import { MCPServer } from "@soterai/mcp-gateway";

const server = new MCPServer({
  config: {
    ...DEFAULT_GATEWAY_CONFIG,
    upstreamEndpoint: { transport: "http", address: "http://localhost:8080/mcp" },
    authToken: process.env.SOTERAI_MCP_TOKEN,
  },
  deps: { evaluatePolicy: myPolicy },
  port: 47322,
});
await server.start();

Evidence

Every enforcement decision appends to the gateway's evidence log (gateway.getEvidenceLog()):

{
  traceId: string;          // UUIDv4 for correlation
  enforcement: "ALLOW" | "BLOCK" | "ASK" | "REDACT" | ...;
  toolName: string;
  riskScore: number;
  requestHash: string;      // SHA-256 of canonical args
  timestampMs: number;
  /* … plus approval / decision metadata */
}

This shape matches the SoterAI Command Layer so existing dashboards and compliance tooling work unchanged.

Security

  • Auth: bearer token check when authToken is set
  • Isolation: tenant/project/client-bound sessions with TTL
  • Rate limiting: 120 req/min per client by default
  • Circuit breaker: trips after 5 consecutive upstream failures
  • Payload bounds: 1 MiB body, 500 KiB result, per-arg length cap
  • Fail-closed: policy errors block the call when failClosed: true

License

MIT — see LICENSE.