Skip to main content
Glama
yuzu-octopus

mcp-pool

mcp-pool

MCP Key Pool Proxy — pool multiple API keys across upstream MCP servers to distribute rate limits.

How it works

mcp-pool is itself an MCP server. You configure one or more "pools" — each pool represents one upstream MCP server type (e.g. Brave Search) with N API keys.

  • 1 subprocess per pool at a time, not per key. No warm standby processes.

  • On rate-limit or transport error, the current upstream is closed and a new one spawns with the next key (~1-2s failover).

  • Tools are exposed with {poolName}__ prefix to avoid name collisions.

  • See Sharing for how several agents share one set of upstreams.

Related MCP server: Tavily MCP Key Pool

Sharing

The first agent connection starts a daemon, a detached local process that owns the upstreams. Every later agent connects to that same daemon instead of spawning its own copies, so N agents cost 1 upstream per pool rather than N. When the last agent disconnects, the daemon exits after a grace period.

  • Pools are keyed by config file, so different configs get different daemons.

  • A hard-killed daemon leaves a stale socket; the next agent detects it, removes it, and starts a fresh daemon.

  • Pass --local to opt out and run a standalone single-process server.

Runtime state lives in ~/.mcp-pool/, not /tmp, so the path is stable regardless of the child environment.

Config

pools:
  brave-search:
    command: bunx
    args: ["-y", "@brave/brave-search-mcp-server"]
    keys:
      - {BRAVE_API_KEY: "sk-first"}
      - {BRAVE_API_KEY: "sk-second"}
    rateLimitPatterns:
      - "rate_limit_exceeded"
      - "too many requests"

Field

Description

command

Executable to spawn (required)

args

CLI arguments

keys

Array of environment-variable objects, one per key (at least 1); values may be literal strings or ${NAME} references

rateLimitPatterns

Regex patterns matched against tool error text (required, at least 1 — safety gate)

cooldownSeconds

Seconds a rate-limited key is skipped; defaults to 300

cwd

Working directory for the upstream process

Config paths (first found wins): --config <path>, ./mcp-pool.yaml, ./.mcp-pool.yaml, ~/.config/mcp-pool/mcp-pool.yaml.

Values support ${VAR} expansion from environment variables. An undefined reference is a configuration error.

Web server mode

mcp-pool --http --port 3000

Serves the pooled tools over MCP Streamable HTTP at http://host:port/mcp, so remote clients and non-stdio hosts can use the same pools. GET /health returns pool count. Bind to 0.0.0.0 (--host 0.0.0.0) to accept remote connections; the default 127.0.0.1 is local only.

Usage

{
  "mcpServers": {
    "mcp-pool": {
      "command": "bunx",
      "args": ["mcp-pool@0.2.0", "--config", "/path/to/mcp-pool.yaml"]
    }
  }
}

Tool names are prefixed: brave-search__brave_web_search. The client calls the prefixed name; mcp-pool strips the prefix and routes to the correct upstream.

Pass --verbose for per-request trace logs.

Logging

All logs are JSON lines on stderr (stdout is reserved for MCP protocol):

{"ts":"...","level":"info","pool":"brave-search","event":"upstream_start","keyIndex":0}
{"ts":"...","level":"warn","pool":"brave-search","event":"rate_limited","upstream":0}
{"ts":"...","level":"error","pool":"brave-search","event":"upstream_error","upstream":0,"error":"..."}

Design

  • Lazy failover: 1 process per pool. Rate-limited/crashed keys are closed and replaced with the next key on demand; rate-limited keys are skipped for cooldownSeconds (300 seconds by default).

  • Serialized swaps: the promise-chain mutex covers only the state swap (spawn, close, cursor move), not the in-flight call, so concurrent callers still reach the upstream in parallel.

  • Shared daemon: one daemon per config serves every agent, so upstreams are not duplicated per agent. See Sharing.

  • Tool validation: each spawned upstream's tools are validated against the cached set (by name→schema map, order-independent).

  • rateLimitPatterns is required: without explicit patterns, all isError results are terminal — no retries. Use [".*"] for blanket retry on read-only pools.

  • Stdio upstreams only: upstream MCP servers are spawned as subprocesses.

Development

bun install --frozen-lockfile
bun run lint
bun run typecheck
bun run test
bun run smoke
bun run build
bun run check:package

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    A proxy MCP server that connects to Tavily's official Streamable HTTP MCP, managing multiple API keys and automatically switching to the next one when the current key's quota is exhausted.
    5
    11 npm
    1
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Exposes pooled Tavily API keys through an MCP streamable HTTP endpoint, providing search, extract, crawl, map, research, and pool status tools with automatic key rotation and quota management.
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    Pools multiple Tavily API keys into a single local MCP server with round-robin rotation and automatic failover, exposing Tavily search, extract, crawl, map, and research tools to AI agents via stdio.
    6
    1
    MIT