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

@priventai/mcp-gateway

v0.2.0

Published

Privent MCP Gateway — wrap any MCP server (stdio or Streamable HTTP) and enforce tokenization on tool-call arguments and results (ADR 0001 enforcement path)

Downloads

183

Readme

@priventai/mcp-gateway (PoC)

Enforcement path for Privent MCP — monorepo package under privent-mcp (ADR 0001 / PRI-169).

MCP Client (Claude Desktop / Cursor / Inspector)
        │  Streamable HTTP or stdio
        ▼
  @priventai/mcp-gateway   ← this package
        │  proxies tools/list + tools/call
        │  protects tool-call ARGUMENTS before forwarding (default on, MCP-002)
        │  protects tool RESULT text → risk + vault tokenize
        ▼
  Upstream MCP server (any) — Streamable HTTP URL or stdio subprocess

Assist @priventai/mcp-server (repo root) remains optional tools. This gateway is where traffic must pass for E1.

Wrap a stdio server (the config-swap path)

Most local MCP servers are stdio subprocesses ("command": "npx", "args": [...] in a client config). The gateway spawns and fronts one itself via PRIVENT_UPSTREAM_MCP_CMD:

export PRIVENT_API_KEY=sk-...
export PRIVENT_UPSTREAM_MCP_CMD='npx -y @modelcontextprotocol/server-filesystem "/Users/you/Documents"'
pnpm gateway:start        # stdio downstream — for Claude Desktop / Cursor entries

Rules, each load-bearing:

  • One of URL or CMD, never both. Both set is a boot refusal, not a silent priority — a priority order would hide which upstream the gateway actually fronts.
  • CMD is one quoted string. Quote arguments containing spaces ("..." or '...'). No shell ever re-parses it — the child is spawned with shell: false — the quoting exists only to express argv items with spaces.
  • The child inherits your environment minus the PRIVENT_ namespace. Upstream servers keep getting their own credentials (GITHUB_TOKEN, …) exactly as if the client had spawned them directly; the Privent credential is never handed to a third-party process. Consequence: an upstream that itself wants PRIVENT_API_KEY (a middleware-wrapped server) cannot get it through the gateway.
  • If the upstream dies, the gateway dies — one structured stderr record ("event":"upstream_closed"), then exit 1. A dead upstream has no traffic to fail open with (ADR K3 governs protection failures, not upstream death); the client sees exactly what a direct child death looks like. No reconnect loop, deliberately.
  • Windows: npx shims cannot be spawned under shell: false (same constraint scripts/verify-published-install.mjs documents) — point CMD at node <absolute path to the server's entry> instead.

Copy-paste client entries: examples/claude_desktop_config.gateway.json and examples/cursor.gateway.mcp.json (local-path form — the package is not on npm yet, and an npx instruction that cannot succeed is MCP-013's defect).

Local PoC (K2)

  1. Run an upstream MCP over Streamable HTTP (example: another process on :3001/mcp) — or use PRIVENT_UPSTREAM_MCP_CMD above and skip the separate process.
  2. Configure env and start gateway on :8090:
# from repo root
pnpm install
pnpm gateway:build

export PRIVENT_UPSTREAM_MCP_URL=http://127.0.0.1:3001/mcp
export PRIVENT_BASE_URL=https://api.privent.ai
export PRIVENT_API_KEY=sk-...
export MCP_PORT=8090
# optional: PRIVENT_GATEWAY_PROTECT_MODE=fail_closed
# optional: PRIVENT_GATEWAY_PROTECT=0  # list/proxy only, no tokenize
# optional: PRIVENT_GATEWAY_PROTECT_INPUT=0  # stop protecting tool-call arguments (default on)
# optional: PRIVENT_GATEWAY_AUDIT_INGEST=0  # stderr only, no /v1/audit/events

# OAuth edge (PRI-170 / ADR K4) — HTTP only; stdio still uses PRIVENT_API_KEY
# export PRIVENT_AUTH_MODE=oauth
# export PRIVENT_OAUTH_JWKS_URL=https://auth.example.com/.well-known/jwks.json
# export PRIVENT_OAUTH_ISSUER=https://auth.example.com/
# export PRIVENT_OAUTH_AUDIENCE=privent-mcp-gateway
# export PRIVENT_OAUTH_RESOURCE=http://127.0.0.1:8090/mcp
# export PRIVENT_OAUTH_AUTHORIZATION_SERVERS=https://auth.example.com

pnpm gateway:start:http
  1. Point the client at http://127.0.0.1:8090/mcp (not the upstream).
  2. Discovery: GET /.well-known/oauth-protected-resource (resource + AS list). Health: GET /healthz includes auth_mode.

Cursor sketch

{
  "mcpServers": {
    "upstream-via-privent": {
      "url": "http://127.0.0.1:8090/mcp"
    }
  }
}

(Exact Cursor remote MCP config may vary by version. In oauth mode send Authorization: Bearer <access_token> on initialize.)

Behavior (ADR)

| Topic | PoC default | |-------|-------------| | Protect | Tool-call arguments (every string leaf, any depth — default on since MCP-002) AND tool result text blocks via /v1/risk/score + vault find-or-create | | Upstream | PRIVENT_UPSTREAM_MCP_URL (Streamable HTTP) or PRIVENT_UPSTREAM_MCP_CMD (stdio subprocess) — exactly one | | Fail mode | fail-open + stderr protection.* + best-effort POST /v1/audit/events | | Non-text blocks | PRIVENT_GATEWAY_NONTEXT_BLOCKS = pass (default: forward + protection.skipped) / strip (placeholder text block) / refuse (error result). structuredContent strings are protected like text and survive all three; _meta is audited on pass, dropped on strip/refuse (MCP-003 / MCP-027, ADR 0001 amendment) | | Audit | tool_call, protection.applied / skipped / unavailable (PRI-164 gateway half) | | Identity | HTTP: api_key (default) or oauth + required JWKS claim map (K4); stdio: API key only | | Boot | Refuses with no PRIVENT_API_KEY and no OAuth JWKS, both fail modes (MCP-006 — "nothing set" is never an intentional production config). HTTP-only escape hatch for per-request-Bearer topologies: PRIVENT_GATEWAY_ALLOW_NO_CREDENTIALS=1, announced as credentials=none_allowed on every boot line | | Hosted GA | Same package; deploy as service (follow-up) |

Spike notes (PRI-167 / PRI-169 / PRI-170)

  1. SDK-level proxy (this PoC): Server handlers forward tools/list + tools/call to upstream Client — cleaner than raw JSON-RPC re-encode for tool surface.
  2. Streamable HTTP both sides: client→gateway and gateway→upstream.
  3. stdio downstream supported (pnpm gateway:start) for local IDE; stdio upstream via PRIVENT_UPSTREAM_MCP_CMD (this section's earlier "upstream still HTTP" limitation is closed).
  4. Resources/prompts not proxied yet (tools-only PoC).
  5. OAuth edge on HTTP initialize (JWKS required in oauth mode; 401 on missing/invalid bearer or missing JWKS).

Scripts

| Script | Meaning | |--------|---------| | pnpm gateway:build | Compile this package | | pnpm gateway:start:http | Listen /mcp + /healthz | | pnpm gateway:test | Unit tests |