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

@sigilcore/mcp-proxy

v0.5.0

Published

Wraps MCP tool connections in Sigil Intent Attestations

Readme

@sigilcore/mcp-proxy

Wraps MCP tool connections in Sigil Intent Attestations. Every tool call is evaluated against your operator's warranty.md policy before it reaches the real MCP server.

MCP action taxonomy and trust

Governed MCP calls submit the namespaced action mcp.<serverId>.<toolName>. The proxy keeps the binding identity in metadata.serverId, the tool name in metadata.toolName, and the complete arguments in metadata.arguments. Sign matches policy against those exact metadata values. It never splits the action string, because server IDs may contain dots, slashes, URLs, or scoped package names.

Use a ## mcp block to allowlist servers and tools, block tool patterns, or place a tool behind a durable approval hold. A trailing * is the only wildcard form. Without a ## mcp block, every MCP action is denied.

The proxy always calls @sigilcore/agent-hooks with failMode: "closed". --unsafe-bypass remains an explicit emergency escape hatch and logs every ungoverned call. A normal client-side npm installation is not a trusted shim: its API key shares the agent environment. Only a controlled deployment with a dedicated credential inaccessible to the governed agent can satisfy a policy's require_shim: true or attested rule.

For PENDING, the proxy polls the authenticated tenant-scoped hold-status endpoint. The legacy APPROVED input alias and canonical ALLOWED status do not authorize the MCP call by themselves. The proxy submits the unchanged canonical intent to Sign again. It forwards the tool call only when that exact-intent retry produces an authorization capability. Denial, expiry, timeout, changed intent, consumed approval, a missing attestation, or any unexpected response fails closed.

Policy 2.2 result inspection

An operator can enable the Policy 2.2 response-disclosure path with an opaque inspection profile. The profile is not sufficient by itself: first pin the matching local verification context in sigil.config.json (replace every angle-bracket value with the exact values for the signed policy):

{
  "inspectionProfile": "operator-local-v1",
  "responsePolicyVerification": {
    "profile": "operator-local-v1",
    "publicKeyBase64url": "<operator-ed25519-public-key>",
    "issuer": "<issuer>",
    "keyId": "<key-id>",
    "tenantId": "<tenant-id>",
    "taskId": "<task-id>",
    "policyHash": "<lowercase-sha256>",
    "revocationEpoch": 0,
    "deterministicRulesetDigest": "<lowercase-sha256>",
    "classCatalogDigest": "<lowercase-sha256>"
  }
}

Then run the proxy with the same profile:

npx @sigilcore/mcp-proxy --inspection-profile operator-local-v1 -- npx @some/mcp-server

For an explicitly covered MCP tools/call, the proxy constructs the complete coverage token from its trusted serverId, one literal dot, and the exact SDK tool name. It compares the whole token byte for byte against the verified signed policy. It does not split, normalize, trim, case-fold, or infer a tool category.

The upstream tool runs at most once. Its decoded result is projected and evaluated locally. The original result is returned only after one bound ALLOW decision and one forward claim. BLOCK, malformed policy, coverage or digest mismatch, unsupported binary or mixed content, limit failure, cancellation, timeout, and evaluator failure return a stable proxy error without upstream content. When the tool completed, the error states that execution completed and result disclosure was denied.

Inspection profiles are mutually exclusive with --unsafe-bypass. They also refuse resources/read, prompts/get, subscriptions, and unknown methods, because those result types are outside Policy 2.2 coverage. Raw result bytes remain inside mcp-proxy and the local Agent Hooks evaluator. They are not sent to Sign or written to logs, metrics, state records, or error bodies.

Policy 2.3 durable scanner enforcement

Policy 2.3 adds operator-owned scanning, verified redaction, and durable multi-replica disclosure state. It is available through the startProxy library API. The command-line wrapper intentionally has no scanner endpoint or database credential surface: an operator host must inject both boundaries.

Construct PostgresExecutionLedger with a query client implementing the narrow PostgresQueryClient interface. A pg.Pool or pg.Client satisfies that structural interface. Construct the scanner client with an authenticated AuthenticatedScannerTransport from Agent Hooks, then pass both to startProxy as executionLedger and scannerClient.

Every Policy 2.3 tools/call must also carry a caller-issued invocation key in params._meta["io.sigil/idempotency-key"]. The key is an opaque 1–128 character ASCII token beginning with an alphanumeric character. Reuse it for transport retries of one invocation and generate a new value for each deliberate call, including repeated calls with identical tool arguments. The proxy hashes the key into its durable execution identity, never logs or persists the raw value, and blocks before upstream execution when the key is absent or malformed.

The PostgreSQL adapter initializes sigil_execution_ledger and stores only execution metadata, state, timestamps, and SHA-256 bindings. It never stores a request body, response body, projection bytes, scanner body, or finding content. Create and transition operations use compare-and-swap updates. A forward claim succeeds once only, including under multi-replica contention. After restart, reconcileStranded terminally blocks abandoned work and never re-executes the upstream tool. purgeExpired respects legalHold metadata. Database unavailability blocks before upstream execution.

Scanner projection bytes cross only the injected authenticated operator transport. Required scanner authentication, deadline, transport, schema, binding, size, class, confidence, offset, or evidence failures block result disclosure. Optional scanner failure preserves the signed optional behavior. Disposition precedence is BLOCK, then REDACT, then ALLOW; observe-only findings do not change disposition. Verified redactions must map wholly to UTF-8 boundaries inside one projection record. The proxy applies them to a clone of the decoded MCP result, preserves the result shape, binds the disclosed-result digest in the atomic forward claim, and fails closed on any mapping or shape ambiguity.

Quick Start

# Install
npm install -g @sigilcore/mcp-proxy

# Set your API key
export SIGIL_API_KEY=sk_sigil_YOUR_KEY

# Generate sigil.config.json, then replace the expectedPolicyHash placeholder
# with the lowercase SHA-256 hash of the policy this proxy must enforce
mcp-proxy --init

# Wrap any MCP server after the policy hash is pinned
mcp-proxy -- npx @some/mcp-server

The generated placeholder is intentionally not runnable. Default enforcement fails startup until decisionVerification.expectedPolicyHash contains the exact lowercase policy hash.

MCP Client Config

Change one line in your MCP client config:

{
  "mcpServers": {
    "postgres": {
      "command": "npx",
      "args": ["@sigilcore/mcp-proxy", "--", "npx", "@some/pg-mcp"]
    }
  }
}

Configuration

Generate a starter config: npx @sigilcore/mcp-proxy --init

Precedence: CLI flags > environment variables > config file > defaults.

| CLI Flag | Env Var | Config Key | Default | |---|---|---|---| | --key | SIGIL_API_KEY | (env only) | (required) | | --sign-url | SIGIL_SIGN_URL | signUrl | https://sign.sigilcore.com | | --log-level | SIGIL_LOG_LEVEL | logLevel | info | | --server-id | — | serverId | derived from command/URL | | --server-name | — | serverName | same as serverId | | --pending-timeout | SIGIL_PENDING_TIMEOUT | pendingTimeout | 30000 | | --unsafe-bypass | (CLI only) | (CLI only) | false | | --inspection-profile | SIGIL_RESPONSE_INSPECTION_PROFILE | inspectionProfile | disabled | | --max-in-flight-results | SIGIL_MAX_IN_FLIGHT_RESULTS | maxInFlightResults | 16 | | — | — | decisionVerification | { "mode": "enforce" } | | --remote | — | — | — | | --port | — | — | auto |

signUrl must always be an exact canonical HTTPS origin. The proxy rejects HTTP, paths, credentials, query strings, and fragments before it opens either the Sign connection or the wrapped MCP connection.

Decision verification

Signed decision verification defaults to enforce. Startup fails before any network connection unless configuration supplies a lowercase SHA-256 policy hash. An unsigned or unverifiable success response cannot reach the wrapped MCP server. The proxy accepts APPROVED only as a deprecated input alias and emits ALLOWED in decision logs.

CI also runs a fail-closed type-assertion gate across all runtime source. It rejects every non-const as assertion and every angle-bracket assertion, independent of aliases, conditional types, mapped types, or container shape. Only TypeScript's literal-narrowing as const form is allowed; it cannot mint or coerce an authorization capability and the production typecheck remains mandatory. This prevents syntactic wrappers from forging the capability required by the governed-forward helper.

The proxy obtains verification keys from the configured Sign origin's bounded multi-key JWKS. Agent Hooks caches the complete overlap set for five minutes and refreshes once when a new key ID appears. A cold-cache JWKS outage denies the request with key_unavailable. A warm cache continues to verify every key in the overlap set during an outage. This permits a Sign key rotation without a single-key client lock.

An optional pinnedJwk takes precedence over JWKS. Use it only to hold one known-good key during an incident. A static single-key pin does not follow a normal Sign rotation automatically.

Enforce startup validates the policy hash, optional public JWK, and canonical HTTPS Sign origin before it opens either network connection:

{
  "decisionVerification": {
    "mode": "enforce",
    "expectedPolicyHash": "<lowercase-sha256>",
    "pinnedJwk": {
      "kty": "OKP",
      "crv": "Ed25519",
      "kid": "<key-id>",
      "x": "<base64url-public-key>",
      "use": "sig",
      "key_ops": ["verify"],
      "alg": "EdDSA"
    },
    "attestationIssuer": "sigil-core"
  }
}

pinnedJwk and attestationIssuer are optional. expectedPolicyHash is required. To restore the compatibility path during an availability incident, set mode to warn explicitly and roll back the package under the approved runbook. Warn mode still verifies and reports signed responses, but it permits a legacy unsigned success response.

Release verification runs a deterministic 29-case enforce-mode batch and named clock-skew, cold-cache outage, rotation-overlap, oversize, and tamper drills. The batch fails on any unexpected valid-case verification failure, accepted tamper, or legacy-path fallback.

Server Identity

  • serverId — Binding identity (security-critical). Used in txCommit preimage and policy evaluation. Auto-derived from the package name (stdio) or full URL (HTTP) if not set.
  • serverName — Display label (logs only). Defaults to serverId.

Unsafe Bypass

The proxy is fail-closed by default. When no HTTP response is received from Sign, tool calls are blocked.

To allow ungoverned calls during Sign outages, use the --unsafe-bypass CLI flag. This flag is intentionally not available as an env var or config file option — it must be visible in your MCP client config:

npx @sigilcore/mcp-proxy --unsafe-bypass -- npx @some/mcp-server

Every bypassed call emits an ungoverned_tool_call error-level log. Only an explicit in-memory transport fail-open capability minted by Agent Hooks after a no-response request can activate bypass. failOpen and SIGIL_UNREACHABLE strings from a response are not trusted. Reached redirects, malformed, unverifiable, 429, and 5xx responses, arbitrary authorization exceptions, and auth failures (401/403) are never bypassed. Startup fails if an inspection profile is also configured.

HTTP/SSE Transport

Proxy a remote MCP server:

npx @sigilcore/mcp-proxy --remote https://api.example.com/mcp

Upstream Authentication

Remote MCP servers often require auth. Configure upstream headers in your config file using environment variable references:

{
  "upstream": {
    "headers": {
      "Authorization": "Bearer $UPSTREAM_TOKEN",
      "X-Custom-Header": "$CUSTOM_HEADER_VALUE"
    }
  }
}

All header values must reference at least one $IDENTIFIER env var. Raw secrets are rejected at load time.

Convenience shortcut for Authorization header:

export SIGIL_UPSTREAM_AUTH="Bearer sk-abc123..."
npx @sigilcore/mcp-proxy --remote https://api.example.com/mcp

Extractors

Map tool arguments to Sigil policy fields in sigil.config.json:

{
  "extractors": {
    "fetch": { "url": "url" },
    "write_file": { "path": "path" }
  }
}

Error Codes

  • -32001 — Sigil policy denial (DENIED, fail-closed, hold timeout)
  • -32002 — Sigil authentication failure (invalid API key)
  • -32004 — method refused because its result is outside the active inspection profile

License

MIT