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

@tournesol-tag/mcp-bridge

v0.1.5

Published

TAG MCP bridge — runs your local MCP server and proxies stdio ↔ TAG relay WebSocket so hosted TAG / engine can call your tools (J1, ADR-033).

Readme

@tournesol-tag/mcp-bridge

CLI that proxies a local MCP server to TAG over a reverse WebSocket relay, so a hosted TAG instance (or the TAG engine) can call tools that only exist on your laptop or inside your VPN.

 hosted TAG  ──HTTPS──►  TAG MCP relay  ──reverse WS──►  tag-mcp-bridge  ──stdio──►  your MCP server

You run tag-mcp-bridge locally. It dials out to the relay (so no inbound ports), keeps the MCP child process warm, and translates relay RPC envelopes into MCP JSON-RPC requests (tools/list, tools/call).

See ADR-033 for the full design.


Quick start (easiest path)

The fastest way to wire this up to your local MCP server:

  1. Install the CLI (see below): npm install -g @tournesol-tag/mcp-bridge

  2. In hosted TAG, open My MCP Bridge (left nav). That page shows:

    • your relay URL (the --relay value),
    • a Generate token button (the --token value, valid 30 days),
    • a ready-to-paste tag-mcp-bridge … command with both already filled in.
  3. Copy that command, append --mcp-cmd "<how you start your MCP server>", and run it on the machine where your MCP server lives. Example:

    tag-mcp-bridge \
      --relay  https://tag-mcp-relay.<your-env>.azurecontainerapps.io \
      --token  "$TOKEN_FROM_UI" \
      --mcp-cmd "python -m my_tools.server"
  4. Keep it running under screen, pm2, or systemd so it survives reboots. Hosted workflows that reference your tools will get a 503 while it's offline.

That's it — no inbound ports, no DNS, no public hostname for your machine. The bridge dials out to the relay. The rest of this README is reference detail.


Install

npm (recommended)

npm install -g @tournesol-tag/[email protected]
# or run ad-hoc without installing
npx @tournesol-tag/[email protected] --help

0.1.2 (2026-06) adds a pre-flight binary check on --mcp-cmd so a missing interpreter fails fast with an actionable message, plus an automatic pythonpython3 fallback (with a warning) for Debian/Ubuntu hosts that ship only python3. See the spawn … ENOENT entry under Troubleshooting.

Docker

docker pull ghcr.io/jaimetournesol/mcp-bridge:latest
docker run --rm ghcr.io/jaimetournesol/mcp-bridge --help

Usage

tag-mcp-bridge — proxy a local MCP server to TAG via reverse-WS

Usage:
  tag-mcp-bridge --relay <url> --token <jwt> --mcp-cmd <cmd> [--dev-id <id>] [-- <mcp-args>]

Flags:
  --relay <url>     Relay base URL, e.g. https://tag-mcp-relay.example.com
                    Env: TAG_RELAY_URL
  --token <jwt>     Bridge JWT (sub=dev:<id>, scope=["bridge"])
                    Env: TAG_BRIDGE_TOKEN
  --dev-id <id>     Optional; derived from JWT subject if omitted.
  --mcp-cmd <cmd>   Shell-style command to spawn the MCP server.
                    Quoted form: --mcp-cmd "python -m tariff_tools.server"
                    Env: TAG_MCP_CMD
  --mcp-env <k=v>   Extra env var for the MCP child. Repeatable.
  --                Everything after this is appended to the MCP child argv.

Reconnect: exponential backoff up to 30s. SIGINT to stop cleanly.

Example

export TAG_RELAY_URL="https://tag-mcp-relay.example.com"   # shown on the My MCP Bridge page
export TAG_BRIDGE_TOKEN="eyJhbGciOiJSUzI1NiIs..."          # Generate token on the My MCP Bridge page

tag-mcp-bridge \
  --relay  "$TAG_RELAY_URL" \
  --token  "$TAG_BRIDGE_TOKEN" \
  --mcp-cmd "python -m tariff_tools.server" \
  --mcp-env "NEO4J_URL=bolt://localhost:7687" \
  --mcp-env "API_KEY=local-dev"

You should see:

[tag-mcp-bridge] dev=alice relay=https://tag-mcp-relay.example.com mcp="python -m tariff_tools.server "
[tag-mcp-bridge] ws connected
[tag-mcp-bridge] mcp child ready (15 tools)

Then any hosted workflow whose serviceUrls.<name> resolves to your bridge will route tool calls to your local MCP server.

Docker example

docker run --rm -i \
  -e TAG_RELAY_URL="https://tag-mcp-relay.example.com" \
  -e TAG_BRIDGE_TOKEN="$TAG_BRIDGE_TOKEN" \
  -e TAG_MCP_CMD="python -m tariff_tools.server" \
  ghcr.io/jaimetournesol/mcp-bridge:latest \
    --relay "$TAG_RELAY_URL" --token "$TAG_BRIDGE_TOKEN" --mcp-cmd "$TAG_MCP_CMD"

Note: the MCP child runs inside the container. If your tool needs Python or other binaries, build a derived image with your runtime preinstalled and keep the tag-mcp-bridge ENTRYPOINT.


How tokens are issued

The simplest path is the My MCP Bridge page in hosted TAG — click Generate token. Under the hood it calls the TAG API:

POST /api/me/relay-bridge-token
Authorization: Bearer <your-tag-session>

The relay URL is likewise available from that page, or directly:

GET /api/me/relay-bridge-info
Authorization: Bearer <your-tag-session>
→ { "relayUrl": "https://tag-mcp-relay.<env>.azurecontainerapps.io" }

The bridge JWT is valid 30 days, with sub: "dev:<your-id>" and scope: ["bridge"]. The bridge decodes the sub claim to know which dev slot to claim on the relay (no verification — the relay enforces it).


Troubleshooting

ws connect failed: 401 Token expired or wrong relay. Re-issue from POST /me/bridge/token and re-check --relay.

ws connect failed: ENOTFOUND Relay hostname unreachable from this machine. Try curl -I $TAG_RELAY_URL.

mcp child exited: 127 --mcp-cmd resolves to a binary that isn't on PATH (or inside the container image, if you're running in Docker). Run the command standalone to isolate.

spawn python ENOENT / Error: spawn <name> ENOENT The bridge couldn't find the binary you asked it to run. Most common cause on Debian/Ubuntu hosts: python isn't installed by default (only python3). The bridge auto-falls-back to python3 when it can, and prints a warning; for any other missing binary you'll get a clear pre-flight error. Three fixes:

  • Use python3 explicitly: --mcp-cmd "python3 -m my_tools.server"
  • Install the symlink package: apt-get install -y python-is-python3
  • Pass an absolute path: --mcp-cmd "/usr/bin/python3 -m my_tools.server"

Bridge keeps reconnecting in a loop Each disconnect backs off exponentially up to 30 seconds and retries forever. If the relay is up but the bridge keeps dropping, check:

  • another bridge process is already holding your dev slot (last writer wins — kill the old one with pkill -f tag-mcp-bridge),
  • your laptop sleep/wake is breaking the TCP keepalive (the bridge will recover on the next wake; this is by design).

MCP session resets between calls The bridge keeps one MCP child for its entire lifetime, so tool state is preserved across relay reconnects. If you see state loss, the MCP child itself probably crashed and was respawned — check stderr.


Development

git clone https://github.com/jaimetournesol/TAG
cd TAG
pnpm install
pnpm --filter @tournesol-tag/mcp-bridge build
pnpm --filter @tournesol-tag/mcp-bridge test

Source lives in apps/mcp-bridge/src/:

| file | purpose | |----------------------|------------------------------------------------| | cli.ts | argv parsing, env fallbacks, signal handling | | bridge.ts | WS lifecycle, RPC envelope translation | | mcp-stdio.ts | spawn MCP child, frame JSON-RPC over stdio | | protocol.ts | relay envelope schema (Zod-free, hand-rolled) | | backoff.ts | exponential backoff with jitter, capped at 30s |


License

MIT — see LICENSE.