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

mcp-proxy-conductor

v1.0.0

Published

Local MCP proxy that aggregates dynamically managed downstream MCP servers, managed at runtime without restarting the client.

Readme

ai-conductor

A local MCP proxy / aggregator. You register it once with an MCP client (e.g. Claude Desktop or Claude Code), and it sits in front of multiple, dynamically managed downstream MCP servers.

Published on npm as mcp-proxy-conductor.

Why

Individual MCP servers are fiddly to set up and force an agent restart on every change. ai-conductor decouples that: downstream servers are added/removed at runtime, without restarting the upstream client. New tools appear immediately via MCP listChanged notifications.

  Claude (MCP client)
        │  upstream: stdio
        ▼
  ┌─────────────────────────┐
  │      ai-conductor       │   MCP server upstream, MCP client downstream
  └─────────────────────────┘
        │  downstream: stdio | Streamable HTTP | SSE
        ▼
  Server A   Server B   Server C  …  (managed at runtime)

Features

  • Runtime management of downstream servers via built-in meta-tools — no client restart.
  • Downstream transports: stdio, Streamable HTTP, SSE.
  • Aggregates tools, resources, and prompts from all downstreams, with per-server namespacing (serverId__name) so names never collide.
  • Lazy connections: downstreams connect on first use and disconnect after an idle timeout; capabilities are served from a cache so tools are advertised without connecting.
  • Credentials in the OS keychain — referenced from config, never stored in plaintext.
  • Restart without retyping — restart_server reconnects a downstream from its stored definition; a failed stdio connect is retried once, automatically.
  • Persistence — added servers are stored and reconnected (lazily) on the next start.

Requirements

  • Node.js ≥ 24

Install & register

Register ai-conductor with your MCP client. With the Claude Code CLI:

claude mcp add conductor -s user -- npx -y mcp-proxy-conductor

Or add it manually to your client's MCP config:

{
  "mcpServers": {
    "conductor": { "command": "npx", "args": ["-y", "mcp-proxy-conductor"] }
  }
}

Restart the client once. ai-conductor then exposes its meta-tools.

Managing downstream servers

Manage downstreams conversationally through the meta-tools:

  • add_server — add and connect a downstream server at runtime (persists).
    • id: unique, alphanumeric/hyphen, no underscores.
    • transport: one of
      • { "type": "stdio", "command": "...", "args": [...], "env": { ... } }
      • { "type": "http", "url": "https://…/mcp", "headers": { ... } }
      • { "type": "sse", "url": "https://…/sse", "headers": { ... } }
    • autoRetry (optional, default true): retry a failed connect once. stdio only — see Connection retries.
  • remove_server — disconnect and remove a downstream server (persists). Arg: id.
  • restart_server — reconnect a downstream from its stored definition. Arg: id. The stored config is left untouched, so a restart cannot damage the definition — unlike remove_server + add_server, which makes you retype the transport and silently drops whatever you forget. If the server does not come back, the resulting state is reported rather than thrown, and the definition survives.
  • list_servers — list managed servers with connection state (idle/connected/ error), whether capabilities come from cache, and capability counts.

Example

{
  "id": "filesystem",
  "transport": {
    "type": "stdio",
    "command": "npx",
    "args": ["-y", "@modelcontextprotocol/server-filesystem", "/some/dir"]
  }
}

Its tools then appear as filesystem__<toolname>, callable immediately — no restart.

Discovering servers from registries

Instead of typing transport details by hand, discover servers from MCP registries and install them through meta-tools:

  • list_registries — enumerate available registries with capability flags (canConnect, canDetectSecrets).
  • search_registry(query, sources?) — search for servers. Defaults to the official registry (registry.modelcontextprotocol.io); pass sources (ids from list_registries) to widen the search.
  • install_from_registry(ref, { id?, env?, secretBindings? }) — install a result by its ref. For entries that need secrets, store them with secret set and pass secretBindings: { ENV_NAME: "<keychain-name>" }; for required non-secret env, pass env: { ENV_NAME: "<value>" }.

Example: search, then install a server that needs a secret:

search_registry { "query": "filesystem" }
→ official:com.example/fs  (connectable, requiredSecrets: ["API_TOKEN"])

mcp-proxy-conductor secret set fs-token        # in your terminal
install_from_registry { "ref": "official:com.example/fs", "secretBindings": { "API_TOKEN": "fs-token" } }

Sources & capability asymmetry: the official registry provides structured run details and secret flags, so auto-connect and secret detection work fully. Glama is a discovery source (it lists servers but not a runnable command, so its entries are not auto-connectable — use the results to then add_server manually). Per-source failures are reported in the search result, never crashing the search.

Credentials

Secrets live in the OS keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service) — never in config.json and never passed through the chat.

1. Store a secret with the CLI (the value is read from hidden stdin, not the chat):

mcp-proxy-conductor secret set my-token
# or pipe it (e.g. in scripts):
printf '%s' "$MY_TOKEN" | mcp-proxy-conductor secret set my-token

# remove it again:
mcp-proxy-conductor secret rm my-token

2. Reference it in add_server via ${keychain:<name>}:

{
  "id": "uptime",
  "transport": {
    "type": "http",
    "url": "https://example.com/mcp",
    "headers": { "Authorization": "Bearer ${keychain:my-token}" }
  }
}

References are resolved at connect time. Supported placeholder schemes (usable in any env or headers value, and combinable within a string):

| Reference | Resolves from | |---|---| | ${keychain:NAME} | OS keychain (service mcp-proxy-conductor) | | ${env:VAR} | process environment | | ${VAR} | process environment (shorthand) |

Headless Linux without a running Secret Service daemon cannot use the keychain — use ${env:…} there instead. A missing or unreachable secret surfaces as an error state for that one downstream (visible in list_servers); other servers keep working.

Lazy connections

To scale to many downstreams, connections are late-bound: at startup nothing is connected — tools/resources/prompts are advertised from a persisted capability cache. A downstream connects on the first actual call and is evicted after an idle timeout (default 5 minutes, override with CONDUCTOR_IDLE_TIMEOUT_MS, in ms; 0 disables eviction). The first call to an idle server therefore pays a one-time connect latency.

Connection retries

A failed connect is retried once, and only for stdio downstreams: there, the second attempt spawns a fresh process and catches a server that died on startup. For http/sse the server is someone else's — retrying from this end changes nothing about its state, so we skip the doubled latency.

Deliberately exactly one attempt: no backoff, no loop. Switch it off per server with autoRetry: false — worth doing when a second spawn is expensive, has side effects, or just obscures what actually went wrong.

Configs written before autoRetry existed need no change; the field defaults to on.

Development

pnpm install
pnpm test        # vitest
pnpm typecheck
pnpm build       # tsup → dist/index.js

Status & limitations

Local, single-user focus. Known limitations:

  • No backoff: a failed stdio connect is retried once (see Connection retries), then gives up. A downstream that crashes while connected returns to idle and reconnects on the next call.
  • A downstream that holds the connection open but has stopped working still reports connected, and nothing retries it — calls go to a dead server until you restart_server it. Detecting that would need a retry at the call layer, which cannot safely repeat a non-idempotent tool call.
  • Change notifications are coarse (all listChanged types emitted on any change).
  • HTTP downstreams do not auto-fall back to SSE; the transport type is explicit.

Planned, not yet implemented: multi-tenant/SaaS mode.

License

MIT © Patrick Cornelißen