Metadata-Version: 2.4
Name: mcp-switch
Version: 0.1.1
Summary: JIT Namespace Loader for AI Agent Tools - an MCP server that proxies other MCP servers and CLI tools with lazy loading
Project-URL: Homepage, https://github.com/Zer0Wav3s/mcp-switch
Project-URL: Repository, https://github.com/Zer0Wav3s/mcp-switch
Project-URL: Issues, https://github.com/Zer0Wav3s/mcp-switch/issues
Author: ZeroWaves
License-Expression: MIT
License-File: LICENSE
Keywords: agent,ai,claude-code,codex,cursor,hermes,lazy-loading,mcp,model-context-protocol,namespace,proxy,tools
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.10
Requires-Dist: click>=8.0
Requires-Dist: mcp>=1.0.0
Requires-Dist: pyyaml>=6.0
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Description-Content-Type: text/markdown

<div align="center">

# 🔀 mcp-switch

**JIT Namespace Loader for AI Agent Tools**

Instead of loading 50 tool schemas into context, agents see 3 meta-tools.
Load only what you need, when you need it.

[![Version](https://img.shields.io/badge/Version-0.1.1-FF4B4B?style=for-the-badge&logo=github&logoColor=white)](#)
[![PyPI](https://img.shields.io/pypi/v/mcp-switch?style=for-the-badge&logo=pypi&logoColor=white&color=3775A9)](https://pypi.org/project/mcp-switch/)
[![License](https://img.shields.io/badge/License-MIT-22C55E?style=for-the-badge)](LICENSE)

[![Python](https://img.shields.io/badge/Python_3.10+-3776AB?style=for-the-badge&logo=python&logoColor=white)](https://www.python.org/)
[![MCP](https://img.shields.io/badge/MCP_Protocol-000000?style=for-the-badge&logo=data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48Y2lyY2xlIGN4PSIxMiIgY3k9IjEyIiByPSIxMCIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIyIi8+PC9zdmc+&logoColor=white)](https://modelcontextprotocol.io/)

[![Claude Code](https://img.shields.io/badge/Claude_Code-D4A574?style=for-the-badge&logo=anthropic&logoColor=black)](https://docs.anthropic.com/en/docs/claude-code)
[![Cursor](https://img.shields.io/badge/Cursor-000000?style=for-the-badge&logo=cursor&logoColor=white)](https://cursor.sh)
[![Codex](https://img.shields.io/badge/Codex-412991?style=for-the-badge&logo=openai&logoColor=white)](https://github.com/openai/codex)
[![Windsurf](https://img.shields.io/badge/Windsurf-09B6A2?style=for-the-badge&logo=codeium&logoColor=white)](https://codeium.com/windsurf)

</div>

---

## The Problem

Every MCP server you add dumps **all its tool schemas** into the agent's context window at startup:

| Server | Tools |
|--------|-------|
| PostgreSQL | 5 tools |
| GitHub | 12 tools |
| Slack | 8 tools |
| Docker | 6 tools |
| Kubernetes | 15 tools |
| **Total** | **46 tool schemas** |

**46 tool definitions** compete for the LLM's attention on every single request - even when the agent is just writing CSS. Attention dilution from irrelevant tools measurably degrades reasoning quality.

### Before vs After

```diff
- Agent context: [46 tool schemas loaded]
- User: "Fix the CSS padding on the navbar"
- Agent: *wades through postgres, k8s, slack tools to find the right one*

+ Agent context: [3 tool schemas loaded]
+ User: "Fix the CSS padding on the navbar"
+ Agent: *focuses on the task, no irrelevant tools*
+
+ User: "Now check the database for user records"
+ Agent: *calls load_namespace("postgres")*
+ Agent: [3 meta-tools + 5 postgres tools] *queries directly*
```

---

## How It Works

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

    subgraph Router["mcp-switch"]
        Meta["3 Meta-Tools<br/>list_namespaces · load_namespace · unload_namespace"]
        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

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

**3 meta-tools** give the agent on-demand access to any namespace:

```
list_namespaces()
-> ["postgres", "github", "docker", "slack", "git"]

load_namespace("postgres")
-> Starts backend, adds tools: postgres__query, postgres__list_tables, ...
-> Sends tools/list_changed notification to client

unload_namespace("postgres")
-> Removes tools, optionally stops backend, frees context
```

---

## 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](https://docs.astral.sh/uv/getting-started/installation/) 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:

```bash
# 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](#step-2-connect-to-your-agent) and create a config manually - see [Configuration](#configuration).

### Step 2: Connect to Your Agent

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

<details>
<summary><img src="https://img.shields.io/badge/Claude_Code-D4A574?style=flat-square&logo=anthropic&logoColor=black" alt="Claude Code" height="20"/> <strong>Claude Code</strong></summary>

#### Option A: One-liner

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

#### Option B: Project config (`.mcp.json`)

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

</details>

<details>
<summary><img src="https://img.shields.io/badge/Cursor-000000?style=flat-square&logo=cursor&logoColor=white" alt="Cursor" height="20"/> <strong>Cursor</strong></summary>

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

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

</details>

<details>
<summary><img src="https://img.shields.io/badge/Codex-412991?style=flat-square&logo=openai&logoColor=white" alt="Codex" height="20"/> <strong>OpenAI Codex</strong></summary>

Add to your Codex MCP config:

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

</details>

<details>
<summary><img src="https://img.shields.io/badge/Claude_Desktop-D4A574?style=flat-square&logo=anthropic&logoColor=black" alt="Claude Desktop" height="20"/> <strong>Claude Desktop</strong></summary>

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

```json
{
  "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.

</details>

<details>
<summary><img src="https://img.shields.io/badge/Windsurf-09B6A2?style=flat-square&logo=codeium&logoColor=white" alt="Windsurf" height="20"/> <strong>Windsurf</strong></summary>

Add to your Windsurf MCP config:

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

</details>

<details>
<summary><img src="https://img.shields.io/badge/Cline-5A67D8?style=flat-square" alt="Cline" height="20"/> <strong>Cline</strong></summary>

Add to Cline MCP settings:

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

</details>

<details>
<summary><img src="https://img.shields.io/badge/Hermes-FF6B35?style=flat-square" alt="Hermes" height="20"/> <strong>Hermes</strong></summary>

Add to `~/.hermes/config.yaml`:

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

</details>

<details>
<summary><img src="https://img.shields.io/badge/OpenClaw-1a1a2e?style=flat-square" alt="OpenClaw" height="20"/> <strong>OpenClaw</strong></summary>

Add to your OpenClaw MCP config:

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

</details>

<details>
<summary><img src="https://img.shields.io/badge/VS_Code-007ACC?style=flat-square&logo=visual-studio-code&logoColor=white" alt="VS Code" height="20"/> <strong>VS Code Copilot</strong></summary>

Add to `.vscode/mcp.json`:

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

</details>

<details>
<summary><img src="https://img.shields.io/badge/Amazon_Q-FF9900?style=flat-square&logo=amazon&logoColor=white" alt="Amazon Q" height="20"/> <strong>Amazon Q CLI</strong></summary>

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

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

</details>

<details>
<summary><strong>Any Other MCP Client</strong></summary>

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.

</details>

---

## Configuration

### Quick Start: Import Existing

```bash
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`:

```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"

  github:
    type: mcp
    command: "npx"
    args: ["-y", "@modelcontextprotocol/server-github"]
    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
```

### 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

```bash
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.

```yaml
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}"
```

### `cli` - Wrap Shell Commands

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

```yaml
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
```

---

## Example: Agent in Action

```
User: "Fix the CSS padding on the navbar"
Agent: *3 meta-tools in context, focuses on the task*

User: "Now check the database for user records"
Agent: I'll load the database tools.
-> list_namespaces()
-> ["postgres", "github", "docker", "git"]

-> load_namespace("postgres")
-> 5 tools added: postgres__query, postgres__list_tables, ...

-> postgres__query({"sql": "SELECT * FROM users LIMIT 10"})
-> *returns results*

Agent: Done with the database, freeing context.
-> unload_namespace("postgres")
-> 5 tools removed
```

---

## License

MIT - see [LICENSE](LICENSE).
