Skip to main content

Context-saving MCP switchboard for AI agents - lazy-load tools, resources, and prompts only when needed

Project description

🔀 mcp-switch

Give your AI agent only the MCP capabilities it needs, right when it needs them.

mcp-switch is a context-saving MCP switchboard for AI agents. It lazy-loads tools, resources, and prompts on demand so Claude Code, Cursor, Codex, Hermes, OpenClaw, and similar clients stay fast, focused, and less confused by giant tool lists.

Version PyPI License

Python MCP

Claude Code Cursor Codex Windsurf


Why?

When you connect MCP servers to your AI agent, every tool gets loaded at once - even the ones your agent doesn't need right now.

The more tools an agent sees, the slower and less accurate it gets. It's like giving someone a toolbox with 50 tools when they just need a screwdriver.

mcp-switch fixes this. Your agent starts with just 5 simple tools:

Tool What it does
list_namespaces "What tool groups are available?"
load_namespace "Give me the database tools"
unload_namespace "I'm done, put them away"
load_group "Give me all the dev tools at once"
unload_group "Put all the dev tools away"

When the agent needs database tools, it loads them. When it's done, it puts them back. Clean, fast, focused.

Without mcp-switch vs With mcp-switch

- You: "Fix the CSS on the navbar"
- Agent sees: 46 tools (database, GitHub, Slack, Docker, Kubernetes...)
- Agent: gets distracted, picks wrong tools, slower response

+ You: "Fix the CSS on the navbar"
+ Agent sees: 5 tools (list, load, unload, load_group, unload_group)
+ Agent: focuses entirely on your request, fast response
+
+ You: "Now check the database for user records"
+ Agent: loads database tools, runs query, done

How It Works

flowchart TB
    Agent["🤖 AI Agent<br/><i>Claude Code / Cursor / Codex / Hermes / OpenClaw</i>"]

    subgraph Router["mcp-switch"]
        Meta["5 Meta-Tools<br/>list_namespaces · load_namespace · unload_namespace<br/>load_group · unload_group"]
        Registry["Registry"]
        Meta --> Registry
    end

    Agent -- "MCP (stdio)" --> Meta

    subgraph Backends["Backends (lazy-started on demand)"]
        MCP1["🔌 MCP Backend<br/>postgres"]
        MCP2["🔌 MCP Backend<br/>github"]
        CLI1["⚡ CLI Backend<br/>git, docker, system"]
    end

    Registry -. "load_namespace('postgres')" .-> MCP1
    Registry -. "load_namespace('github')" .-> MCP2
    Registry -. "load_namespace('git')" .-> CLI1
    Registry -. "load_group('dev')" .-> CLI1

    MCP1 -- "stdio" --> S1["mcp-server-postgres"]
    MCP2 -- "stdio" --> S2["mcp-server-github"]

    subgraph Features["What gets proxied"]
        Tools["🛠️ Tools"]
        Resources["📦 Resources"]
        Prompts["💬 Prompts"]
    end

    Registry --> Features

The agent asks mcp-switch what's available, loads what it needs, and unloads when done:

Agent: What tool groups do you have?
-> list_namespaces()
-> ["postgres", "github", "docker", "git"]

Agent: I need database tools.
-> load_namespace("postgres")
-> 5 tools, 2 resources, 1 prompt now available

Agent: Done with the database.
-> unload_namespace("postgres")
-> Database tools/resources/prompts removed, back to just 5 meta-tools

Agent: I need all dev tools.
-> load_group("dev")
-> git, docker, system namespaces loaded at once

What Gets Proxied

mcp-switch doesn't just proxy tools — it also passes through resources and prompts from your backends:

Capability Description How it works
Tools Functions the agent can call Loaded on load_namespace, routed on call_tool
Resources Data the agent can read (files, schemas, etc.) Listed via list_resources, read via read_resource
Prompts Reusable prompt templates Listed via list_prompts, fetched via get_prompt

When a namespace is loaded, all three capabilities are registered with the router. When it's unloaded, they're all removed together.


New in v0.2.0

🗂️ Namespace Groups

Define groups of related namespaces in your config and load/unload them in one call:

groups:
  dev:
    - git
    - docker
    - system
  data:
    - postgres
    - github
Agent: I need all my dev tools.
-> load_group("dev")
-> git, docker, and system namespaces loaded at once

Agent: Done with dev work.
-> unload_group("dev")
-> All three namespaces unloaded

⏱️ Idle TTL Auto-Unload

Set a per-namespace idle_ttl (in seconds) and mcp-switch will automatically unload namespaces that haven't been used recently:

namespaces:
  postgres:
    type: mcp
    command: "uvx mcp-server-postgres"
    args: ["--connection-string", "postgresql://localhost/mydb"]
    description: "Query and manage PostgreSQL databases"
    idle_ttl: 300  # Unload after 5 minutes of inactivity

This keeps your agent's context clean without manual cleanup. Set idle_ttl: 0 (the default) to disable auto-unload for a namespace.


Setup

No Python install needed. Every setup below uses uvx which runs packages on-the-fly (like npx for Python).

Don't have uvx? Install uv first: curl -LsSf https://astral.sh/uv/install.sh | sh

Step 1: Import Your Existing MCP Config

If you already have MCP servers configured in Claude Desktop, Cursor, or VS Code, mcp-switch can import them automatically:

# Auto-detect and import from Claude Desktop, Cursor, VS Code, or Windsurf
uvx mcp-switch init

# Or import from a specific config file
uvx mcp-switch init --from ~/.config/claude/claude_desktop_config.json

This creates ~/.config/mcp-switch/config.yaml from your existing setup. No rewriting configs by hand.

Don't have existing MCP servers? Skip to Step 2 and create a config manually - see Configuration.

Step 2: Connect to Your Agent

Pick your agent and add one config block. That's the entire setup.

Claude Code Claude Code

Option A: One-liner

claude mcp add router -- uvx mcp-switch serve --config ~/.config/mcp-switch/config.yaml

Option B: Project config (.mcp.json)

{
  "mcpServers": {
    "router": {
      "command": "uvx",
      "args": ["mcp-switch", "serve", "--config", "~/.config/mcp-switch/config.yaml"]
    }
  }
}
Cursor Cursor

Add to Cursor Settings > MCP Servers, or create .cursor/mcp.json:

{
  "mcpServers": {
    "router": {
      "command": "uvx",
      "args": ["mcp-switch", "serve", "--config", "~/.config/mcp-switch/config.yaml"]
    }
  }
}
Codex OpenAI Codex

Add to your Codex MCP config:

{
  "mcpServers": {
    "router": {
      "command": "uvx",
      "args": ["mcp-switch", "serve", "--config", "~/.config/mcp-switch/config.yaml"]
    }
  }
}
Claude Desktop Claude Desktop

Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):

{
  "mcpServers": {
    "router": {
      "command": "uvx",
      "args": ["mcp-switch", "serve", "--config", "~/.config/mcp-switch/config.yaml"]
    }
  }
}

Pro tip: Move your existing mcpServers entries into mcp-switch.yaml as namespaces, then replace them all with the single router entry above. You go from N server configs to 1.

Windsurf Windsurf

Add to your Windsurf MCP config:

{
  "mcpServers": {
    "router": {
      "command": "uvx",
      "args": ["mcp-switch", "serve", "--config", "~/.config/mcp-switch/config.yaml"]
    }
  }
}
Cline Cline

Add to Cline MCP settings:

{
  "mcpServers": {
    "router": {
      "command": "uvx",
      "args": ["mcp-switch", "serve", "--config", "~/.config/mcp-switch/config.yaml"]
    }
  }
}
Hermes Hermes

Add to ~/.hermes/config.yaml:

mcp_servers:
  router:
    command: uvx
    args: ["mcp-switch", "serve", "--config", "~/.config/mcp-switch/config.yaml"]
OpenClaw OpenClaw

Add to your OpenClaw MCP config:

{
  "mcpServers": {
    "router": {
      "command": "uvx",
      "args": ["mcp-switch", "serve", "--config", "~/.config/mcp-switch/config.yaml"]
    }
  }
}
VS Code VS Code Copilot

Add to .vscode/mcp.json:

{
  "servers": {
    "router": {
      "command": "uvx",
      "args": ["mcp-switch", "serve", "--config", "~/.config/mcp-switch/config.yaml"]
    }
  }
}
Amazon Q Amazon Q CLI

Add to ~/.aws/amazonq/mcp.json:

{
  "mcpServers": {
    "router": {
      "command": "uvx",
      "args": ["mcp-switch", "serve", "--config", "~/.config/mcp-switch/config.yaml"]
    }
  }
}
Any Other MCP Client

The pattern is always the same. Point your client at:

  • Command: uvx
  • Args: ["mcp-switch", "serve", "--config", "~/.config/mcp-switch/config.yaml"]

mcp-switch speaks stdio MCP, which every compliant client supports.


Configuration

Quick Start: Import Existing

uvx mcp-switch init

Auto-detects Claude Desktop, Cursor, VS Code, and Windsurf configs and converts them.

Manual Config

Create ~/.config/mcp-switch/config.yaml:

namespaces:
  # Proxy to real MCP servers (lazy startup)
  postgres:
    type: mcp
    command: "uvx mcp-server-postgres"
    args: ["--connection-string", "postgresql://localhost/mydb"]
    description: "Query and manage PostgreSQL databases"
    idle_ttl: 300  # Auto-unload after 5 min of inactivity (0 = disabled)

  github:
    type: mcp
    command: "uvx mcp-server-github"
    args: ["--repo", "owner/repo"]
    description: "Manage GitHub repos, issues, PRs"
    env:
      GITHUB_TOKEN: "${GITHUB_TOKEN}"

  # Wrap CLI commands as tools (no server needed)
  git:
    type: cli
    description: "Git version control"
    tools:
      git_status:
        command: "git status --porcelain"
        description: "Show working tree status"
      git_log:
        command: "git log --oneline -20"
        description: "Show recent commits"
      git_diff:
        command: "git diff"
        description: "Show unstaged changes"

  docker:
    type: cli
    description: "Docker container management"
    tools:
      docker_ps:
        command: "docker ps --format 'table {{.Names}}\t{{.Status}}'"
        description: "List running containers"
      docker_logs:
        command: "docker logs {container}"
        description: "Show container logs"
        parameters:
          container:
            type: string
            description: "Container name or ID"
            required: true

# Groups: load/unload multiple namespaces at once
groups:
  dev:
    - git
    - docker
  data:
    - postgres
    - github

Config Locations (checked in order)

  1. ./mcp-switch.yaml
  2. ./mcp-switch.yml
  3. ~/.config/mcp-switch/config.yaml
  4. ~/.mcp-switch.yaml

Or explicit: uvx mcp-switch serve --config /path/to/config.yaml

Validate Your Config

uvx mcp-switch validate
uvx mcp-switch list

Namespace Types

mcp - Proxy to MCP Servers

Connects to a real MCP server via stdio. The backend starts lazily when the namespace is first loaded and stops when unloaded. Tools, resources, and prompts are all proxied.

postgres:
  type: mcp
  command: "uvx mcp-server-postgres"
  args: ["--connection-string", "postgresql://localhost/mydb"]
  description: "Query and manage PostgreSQL databases"
  env:
    DB_PASSWORD: "${DB_PASSWORD}"
  idle_ttl: 300  # Optional: auto-unload after 5 minutes of inactivity

cli - Wrap Shell Commands

Turns shell commands into MCP tools. No server process needed. Parameters use {name} template substitution.

git:
  type: cli
  description: "Git version control"
  tools:
    git_status:
      command: "git status --porcelain"
      description: "Show working tree status"
    git_diff:
      command: "git diff {file}"
      description: "Show changes for a specific file"
      parameters:
        file:
          type: string
          description: "File path to diff"
          required: true

Namespace Groups

Groups let you load or unload several related namespaces in a single call — perfect when your agent needs a whole set of tools at once.

# In your config.yaml
groups:
  dev:
    - git
    - docker
    - system
  data:
    - postgres
    - github

The agent uses load_group("dev") and unload_group("dev") instead of loading each namespace individually.


Idle TTL Auto-Unload

Add idle_ttl to any namespace to have it automatically unloaded after a period of inactivity:

namespaces:
  postgres:
    type: mcp
    command: "uvx mcp-server-postgres"
    description: "Query and manage PostgreSQL databases"
    idle_ttl: 300  # 5 minutes
  • The timer resets every time any tool, resource, or prompt in the namespace is used.
  • A background check runs every 60 seconds.
  • Set idle_ttl: 0 or omit it to keep the namespace loaded until manually unloaded.

See It in Action

You:   "Fix the CSS padding on the navbar"
Agent: (only sees 5 tools - stays focused, fixes the CSS immediately)

You:   "Now check the database for user records"
Agent: "Let me grab the database tools."
       -> load_namespace("postgres")  -- 5 database tools, 2 resources, 1 prompt appear
       -> postgres__query("SELECT * FROM users LIMIT 10")
       -> shows you the results

Agent: "All done, putting the database tools away."
       -> unload_namespace("postgres")  -- back to just 5 meta-tools

You:   "Set up my dev environment"
Agent: "Loading all dev tools."
       -> load_group("dev")  -- git, docker, system all loaded at once

Agent: "Done with dev work, cleaning up."
       -> unload_group("dev")  -- all three namespaces unloaded

License

MIT © 2026 ZeroWaves — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mcp_switch-0.2.1.tar.gz (31.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mcp_switch-0.2.1-py3-none-any.whl (29.1 kB view details)

Uploaded Python 3

File details

Details for the file mcp_switch-0.2.1.tar.gz.

File metadata

  • Download URL: mcp_switch-0.2.1.tar.gz
  • Upload date:
  • Size: 31.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for mcp_switch-0.2.1.tar.gz
Algorithm Hash digest
SHA256 221f9c35cac8c676394f1fa89c36c837023534838510db84848d72219098fcf4
MD5 9003e70695804849e330611b73f74a9a
BLAKE2b-256 06e7414e09bc4c80fe8bd742b30bf3091a635386220e665de23d41c3441a88a1

See more details on using hashes here.

File details

Details for the file mcp_switch-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: mcp_switch-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 29.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for mcp_switch-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 12124f8ae0691736527dee5c2caf0091265e49b5b878d4775c3707b9bbdd0e33
MD5 301e11a9e2d754bd3c5619c0a7f131b6
BLAKE2b-256 3906e523316c6824bc629f529070db169580f78f863f23876d030229db639ece

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page