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

@bounded-sh/observe-mcp

v0.1.1

Published

Bounded observe MCP wrapper: `bounded observe mcp -- <server>`. Faithfully proxies MCP JSON-RPC (local stdio, T9-clean; or streamable-HTTP passthrough) and reports every tools/call as an action-grade observe event. The sensor key IS the actor. Never break

Downloads

361

Readme

@bounded-sh/observe-mcp

bounded observe mcp — the MCP observe wrapper. It wraps an existing MCP server and reports every tool call as an action-grade observe event, without changing what the wrapped server does. One line to wrap; obviously safe.

Origin b in SPEC-OBSERVE-ENFORCE-CUSTODY.md (§3.1b, §3.1f, §3.2, §3.7, T9). NEW isolated package — evidence plane only, shares no code path with enforcement.

  • Local stdio wrapper (primary, T9-clean): spawns the target MCP server as a child and transparently proxies stdio JSON-RPC between the client (agent) and the server. Runs in-process on the customer's box — Bounded is never in the data path; if Bounded is down, the wrapped server is completely unaffected.
  • Streamable-HTTP passthrough (secondary): a transparent JSON/SSE reverse proxy in front of a remote MCP endpoint (Mode-B, by necessity for hosted MCP).

One-line wrap

Prefix your MCP server command with bounded observe mcp --:

# before
node my-mcp-server.js

# after (observed)
bounded-observe-mcp -- node my-mcp-server.js

Claude Code / Cursor mcp.json

Point the server command at the wrapper and pass the original command after --:

{
  "mcpServers": {
    "payments": {
      "command": "bounded-observe-mcp",
      "args": ["--", "node", "/abs/path/my-mcp-server.js"],
      "env": {
        "BOUNDED_SENSOR_TOKEN": "obs1.<keyId>.<sig>",   // the key IS the actor
        "BOUNDED_ORG": "acme-demo",
        "BOUNDED_ACTOR": "agent:refunds-bot"            // optional; else mcp:<keyId>
      }
    }
  }
}

The wrapped server behaves identically. The wrapper only observes; it never alters, blocks, or delays a tool call, and all its own logging goes to stderr (stdout stays the byte-clean MCP channel).

Remote MCP endpoint (HTTP)

bounded-observe-mcp --http --upstream https://remote-mcp.example.com/mcp
# prints:  [observe-mcp] listening http://127.0.0.1:<port> → https://remote-mcp.example.com/mcp
# point your MCP client at the printed local URL

What's captured

Per tools/call, one action event (or error on a failed/declined call):

| field | value | |---|---| | class | action (success) / error (JSON-RPC error or result.isError) | | rec | { rail: "mcp", action: "<tool>", registryVersion, fields? } | | dest | { host: "mcp://<serverName>", pathTemplate: "/<tool>", method: "POST" } (stdio) / upstream host (http) | | actor | { id, kind: "agent", grade: "attested" }the sensor key is the actor | | onBehalfOf | opaque end-customer id, if the client supplies params._meta["bounded/onBehalfOf"] | | status, dur_ms, bytes | HTTP-ish status, measured latency, request/response byte sizes |

serverName is learned from the server's own initialize response (serverInfo.name), overridable with --name. tools/list is observed to cache the tool catalog but is not emitted (action-grade by construction).

Events are batched (≤500), reported fire-and-forget to the ingest, and never block the JSON-RPC path. Reporting failures are retried once then dropped with an honest dropped counter; a kill switch (BOUNDED_OBSERVE_MCP_DISABLED=1) turns the wrapper into a pure passthrough with zero observation.

PII posture (default-deny)

  • Metadata by default. Only the tool name, status, latency, byte sizes, and actor leave the process by default. Request/response contents never do.
  • Manifest-allowed arg values only. A small allow-set of action-grade, non-PII scalar keys (amounts, currency, quantity, reason, status, …) may have their value captured into rec.fields (see "Amounts" below). Extend it with --capture <field> / BOUNDED_CAPTURE_FIELDS=a,b.
  • Hard PII denylist (L2). A compiled-in denylist (email, phone, card, ssn, token, secret, name, address, …) blocks any PII-shaped arg key from ever being captured — it overrides the allow-set and is not runtime-configurable. The ingest independently re-applies the same key denylist and an L4 value scrubber (Luhn/email/JWT) server-side. Defense in depth: a bad manifest cannot leak PII.
  • Server-authoritative scope. org/sensor are stamped by ingest from the key; the wrapper never sends them, so a misconfigured org cannot leak or spoof.

Actor = key (§3.1f, U20)

A minted sensor key is an attested credential, so every event is attributed to an attested agent actor. The id defaults to mcp:<keyId> (derived from the token) and can be overridden per-server with --actor / BOUNDED_ACTOR. An asserted _meta.onBehalfOf names the end-customer but never the actor.

Amounts (envelope v1 → v2)

Amounts (and other allowed scalar values) ride rec.fields. The wrapper attaches them optimistically and then runs every event through the shared validateAndFilterEvent (the exact L3 filter ingest runs) before sending — so it always sends the already-filtered result:

  • On the v2 envelope (current: EVENT_SCHEMA_VERSION = 2), rec.fields survives and issue_refund { amount_cents: 4900 } is captured as rec.fields.amount_cents = 4900.
  • On a v1 envelope, rec.fields is stripped and only the fact of the call + its actor transit.

This is one code path with zero version branching: the wrapper emits v = whatever the bundled observe-shared reports, so rebuilding against a new envelope is the only step needed. (This package was built against the v2 observe-shared — amounts transit today; verified live.)

Config

Flags or env (flag wins). --capture is repeatable.

| flag | env | default | |---|---|---| | --token | BOUNDED_SENSOR_TOKEN | (required) obs1.<keyId>.<sig> | | --org | BOUNDED_ORG | (logs/self-filter only; ingest stamps authoritatively) | | --actor | BOUNDED_ACTOR | mcp:<keyId> | | --name | BOUNDED_MCP_SERVER_NAME | serverInfo.name / mcp | | --ingest | BOUNDED_INGEST_BASE | prod ingest | | --capture <f> | BOUNDED_CAPTURE_FIELDS=a,b | built-in safe set | | --on-behalf-of | BOUNDED_ON_BEHALF_OF | (none) | | --http / --upstream | BOUNDED_MCP_HTTP / BOUNDED_MCP_UPSTREAM | stdio mode | | --port | BOUNDED_MCP_PORT | ephemeral (http mode) | | --flush-ms | BOUNDED_FLUSH_MS | 2000 | | --debug | BOUNDED_DEBUG | off | | (kill switch) | BOUNDED_OBSERVE_MCP_DISABLED=1 | pure passthrough |

Build / test

npm run build        # esbuild bundle -> dist/cli.js (bin) + dist/index.js
npm run typecheck
npm test             # vitest: passthrough fidelity, event shape, redaction, latency, http
npm run test:live    # LIVE prod: mint key -> wrap mock server -> verify events land -> revoke

npm run test:live needs the org acme-demo ADMIN_SECRET at /tmp/observe-admin-secret.txt (or $OBSERVE_ADMIN_SECRET). It drives the mock server through the wrapper against prod ingest and verifies the rail:mcp events land (rollup deltas + raw R2 evidence readback) with the attested agent actor and the captured refund amount, then revokes the key.

Embedding as bounded observe mcp

The bin bounded-observe-mcp is also the body of the bounded observe mcp subcommand: runMcpObserve(argv, env) is exported from the package entry, and the arg parser tolerates a leading observe mcp, so a parent bounded CLI can mount it directly. Other building blocks (runStdioProxy, runHttpProxy, Observer, Reporter, buildActionEvent) are exported for reuse.