Skip to main content

mcp-switchboard

A single MCP connector that business users add to Claude or ChatGPT, fronting a catalogue of internal MCP servers. Instead of exposing hundreds of downstream tools, the gateway exposes three meta-tools and finds, authorises and runs the right tool on demand, as the signed-in user.

Status: proof of concept complete, concept proven. Built and tested locally on MCP sources, with auth types none and api_key, against mock data. Measured against the same models connected to the servers directly: through the switchboard, cost and accuracy per scenario stay flat as the tool count grows to ~500, and writes wait for the user's agreement. Direct connections carry every tool definition on every request. Findings and the ordered next steps: docs/poc-results.md. The task list is docs/ai-tool-gateway-poc-tasks.md; the benchmark is eval/README.md.

How it works

Meta-tool Purpose
search_tools Find tools for one need: permission filter, hybrid vector + keyword search, resolver tools for required IDs; abstains with no_confident_match
call_tool Run a tool: schema validation, role policy, per-source auth strategy, result shaping and handles, confirmation for writes (token, or MCP elicitation with GATEWAY_CONFIRM), prompt-injection flags, structured errors, audit
list_categories Browse what exists

Registration is declarative: scripts/catalogue.yaml lists the auth profiles, sources and reviewed tool descriptions, and the gateway applies it at startup (scripts/register_all.sh re-applies it). Listing a tool approves it; tools a server adds later stay out of search until they're added to the file. Postgres holds the search index and runtime state (handles, confirmations, logs).

The chat model plans and fills arguments. The gateway handles search, auth, policy, execution and audit. Downstream auth is pluggable per source through auth profiles (none, api_key today; entra_obo, service_mesh, … later).

Docs

Quick start

To run your own gateway, no clone needed: one command installs switchboard and creates a deployment repo (Dockerfile, catalogue, sign-in), then switchboard add onboards servers with Claude Code. Follow docs/quickstart.md.

curl -LsSf https://github.com/StephenFlavin/mcp-switchboard/releases/latest/download/install.sh | sh -s my-switchboard

The rest of this section sets up the POC for development and the evaluations. Requires Docker, uv and Node.js 20+ (for npx). Python 3.11 is installed by uv.

scripts/bootstrap.sh     # .env with fresh secrets, deps, mock data, containers, gateway on :8080, catalogue

Bootstrap also copes with corporate TLS proxies and a local Postgres on port 5432; see RUNBOOK.md if it stops. Afterwards, scripts/gateway.sh start|stop|restart|status manages the gateway.

The gateway serves MCP (streamable HTTP) at http://localhost:8080/mcp with three tools: search_tools, call_tool and list_categories. Point your agent at it, then try: "What's the total value of stock in the Hastings warehouse?"

Signing in. The gateway is its own OAuth authorization server (auth plan). When a client connects, it opens a browser at the gateway's login page. Out of the box there is one account, testUserOnly / doNotUse!, for local testing only: the gateway refuses to start with it when GATEWAY_ENV=production or GATEWAY_PUBLIC_HOSTS is set, unless GATEWAY_ALLOW_DEFAULT_USER=true. Add your own users and SSO providers (Entra ID, Google, Auth0, any OIDC provider) under inbound_auth: in the catalogue. Clients without OAuth support (the pi adapter, the eval harness) need GATEWAY_DEV_AUTH=true: no sign-in, and every caller is poc-user. A .env from an older bootstrap still has true, so set it to false to sign in.

Claude Code

claude mcp add --transport http tool-gateway http://localhost:8080/mcp

Codex

codex mcp add tool-gateway --url http://localhost:8080/mcp
codex mcp list           # tool-gateway should be listed as enabled

This writes the following to ~/.codex/config.toml, which you can also edit by hand:

[mcp_servers.tool-gateway]
url = "http://localhost:8080/mcp"

pi coding agent

pi has no built-in MCP support, so install the community pi-mcp-adapter package (third-party: review it before installing; it needs pi ≥ 0.84, published as @earendil-works/pi-coding-agent), then configure the server for your project:

pi install npm:pi-mcp-adapter
mkdir -p .pi && cat > .pi/mcp.json <<'JSON'
{
  "mcpServers": {
    "tool-gateway": { "url": "http://localhost:8080/mcp", "directTools": true }
  }
}
JSON
pi                        # from the repo root; trust the project server when asked

/mcp shows the server status.

directTools: true exposes the gateway's three meta-tools to pi directly. Without it, the adapter puts its own search proxy in front of the gateway's search, so the model has to search twice. Use ~/.config/mcp/mcp.json instead of .pi/mcp.json to make it available in every project. To run with a local model and score it on S1–S10, see RUNBOOK.md §8.

Other clients

  • MCP Inspector: npx @modelcontextprotocol/inspector, then connect to http://localhost:8080/mcp (streamable HTTP)
  • Claude Desktop, claude.ai, ChatGPT: see RUNBOOK.md. Web clients need a public URL (scripts/tunnel.sh, mock data only).

The admin API is at /admin. Every route except /admin/health needs Authorization: Bearer $GATEWAY_ADMIN_TOKEN, or a signed-in user's token with a role in inbound_auth.adminRoles (default gateway-admin).

Manual setup (what bootstrap does)
cp .env.example .env                 # set GATEWAY_ADMIN_TOKEN and PRICING_API_KEY
uv sync
uv run python mocks/seed.py          # mocks/mock.db + eval/expected.json
docker compose up -d --wait          # Postgres (:5433) + the mock services
scripts/decision.sh up               # optional: the decision model for reranking (DECISION_PROVIDER,
                                     # default Laya, built here; jev/clm/systemone skip that)
uv run python scripts/fetch_model.py # embedding model
scripts/gateway.sh start             # or: uv run uvicorn gateway.main:app --port 8080
# the gateway applies scripts/catalogue.yaml at startup; after editing it: scripts/register_all.sh

Onboarding a source

catalogue add takes a new MCP server, or a REST API with an OpenAPI spec, to a pull request: it probes the source, asks what only a person can answer, has an enricher write descriptions and example questions, and writes the catalogue, lock and enhanced files. The enricher is the template (the default) or a coding harness you already have installed and logged in to: no API key. Today that is Claude Code.

uv run python -m gateway.registry.catalogue add          # asks; add --help lists every flag

The same run without prompts, for a REST API, with Claude Code writing the wording:

uv run python -m gateway.registry.catalogue add --no-input \
  --type openapi --spec https://erp.internal/openapi.json --base-url https://erp.internal/api \
  --allow --id erp --auth api_key --key-ref ERP_API_KEY --roles ops \
  --default-categories hr-records --harness claude --model sonnet --yes

Steps, flags, the answers file and troubleshooting are in RUNBOOK.md, section 10. The design is in the onboarding plan and the OpenAPI source plan.

Test and evaluate

uv run pytest                                          # unit + integration (needs Postgres)
uv run ruff check && uv run ruff format --check
uv run python eval/search_eval.py --engine embeddings  # recall@k, abstain, latency
uv run python scripts/synth_catalogue.py               # +422 search-only tools, then:
uv run python eval/search_eval.py --catalogue synthetic
uv run python eval/token_report.py                     # S1 tokens: handles off/on, composite
uv run python eval/run_scenarios.py                    # S1-S10 through headless Claude Code
uv run python eval/run_scenarios.py --client pi --model <provider/id> --label pi-local  # or pi
uv run python eval/run_scenarios.py --client pi --model <provider/id> --label pi-local-direct --direct  # no gateway
scripts/eval_scale.sh <label>=<provider/model>          # switchboard vs direct MCP at 32-512 tools
uv run python -m gateway.registry.catalogue describe     # render the gateway's own descriptions
scripts/build_catalogue.sh                              # build-time step: enhance descriptions, check

Licence

Use it under the PolyForm Noncommercial 1.0.0 or the PolyForm Small Business 1.0.0 licence, whichever fits you; commercial use that neither covers needs a commercial licence from the copyright holder (LICENSE.md). Contributions need the CLA (CONTRIBUTING.md).

Metadata

Release files for mcp-switchboard 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mcp-switchboard 0.1.0
File Size Uploaded
mcp_switchboard-0.1.0.tar.gz 242.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for mcp-switchboard 0.1.0
File Interpreter ABI Platform
mcp_switchboard-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 498.3 kB

Release files / mcp_switchboard-0.1.0.tar.gz

Download URL mcp_switchboard-0.1.0.tar.gz
Size 242.6 kB
Tags Source
SHA-256 checksum
How to use checksums
9f8fa9a55b1a6ef3fc8ab7c79a96ddb917fb98f7cbbd483833574703638bf107
BLAKE2b-256 checksum
How to use checksums
e7662e4688b6e118584a7e0ea632c6ec5e0b890d427ae4711237fdd7672ac045
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

Release files / mcp_switchboard-0.1.0-py3-none-any.whl

Download URL mcp_switchboard-0.1.0-py3-none-any.whl
Size 255.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4ccb611d600f79a0b63282d3225da9f3543d6790f8a5483d2ee80d59bdb16dba
BLAKE2b-256 checksum
How to use checksums
2ff17d1baa05f3feafe89040b5fd2f4b42c753fbf75607a96bd7f578bcc00909
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

Release history Release notifications | RSS feed

0.1.1

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page