AI agents make tool calls one at a time. Creating 10 GitHub issues? That's 10 sequential round-trips. Fetching data from 3 different servers? 3 serial waits.
callmux sits between your agent and any MCP server, adding capabilities the original doesn't have:
| Without callmux | With callmux |
|---|---|
10 sequential create_issue calls |
1 callmux_batch call |
| 5 independent reads, one after another | 1 callmux_parallel call |
| Read > transform > write chain | 1 callmux_pipeline call |
| Same data fetched 3 times per session | Cached after first call |
Agent (Claude, Codex, etc.) callmux adds:
│ ┌─────────────────────┐
│ stdio │ callmux_parallel │
▼ │ callmux_batch │
┌─────────┐ │ callmux_pipeline │
│ callmux │──── stdio ───▶ Local │ callmux_cache_clear │
└─────────┤ Server │ callmux_status │
│ │ └─────────────────────┘
│ └──── http/sse ──▶ Remote Server
│
└──── stdio ───▶ Local Server 2 (optional)
Why Tool Call Reduction Matters
The speed improvement from parallelization is obvious. The less obvious - and bigger - win is context pollution.
Every tool call in an LLM conversation adds three things to the context window:
| Component | Typical tokens | Reduced by callmux? |
|---|---|---|
| Payload (parameters + result data) | 200–1,000 | No - same data either way |
| Structural overhead (JSON wrappers, role markers, function name) | 50–100 per call | Yes - 1 wrapper instead of N |
| Intermediate reasoning ("Now I'll fetch the next one…") | 50–300 per call | Yes - eliminated entirely |
The payload is a wash - the same data moves whether it's 7 calls or 1 batched call. But structural overhead and intermediate reasoning scale linearly with call count, and they're pure waste.
Example: 7 sequential tool calls vs. 1 callmux_parallel call
| Without callmux | With callmux | |
|---|---|---|
| Structural overhead | 7 × ~75 = 525 tokens | 1 × ~75 = 75 tokens |
| Intermediate reasoning | 6 × ~150 = 900 tokens | 0 tokens |
| Total pollution | ~1,425 tokens | ~75 tokens |
That's ~19:1 reduction in context pollution from a 7:1 reduction in tool calls.
The compounding effect
Context is cumulative. Each subsequent API turn re-processes everything before it:
Turn 1: base_context + call₁
Turn 2: base_context + call₁ + result₁ + reasoning₁ + call₂
Turn 3: base_context + call₁ + result₁ + reasoning₁ + call₂ + result₂ + reasoning₂ + call₃
⋮
Total input tokens processed across N sequential calls grows quadratically. With callmux, it's one roundtrip. Over a session with dozens of multi-call operations, the cumulative difference is dramatic:
- Longer sessions - context fills slower, compaction happens later, less work is lost
- Lower cost - fewer input tokens processed across API roundtrips
- Better output quality - the model spends attention on your conversation, not on re-reading filler from 40 turns ago
In real-world usage, callmux typically reduces tool calls to ~15% of the original count - which translates to roughly 5–8% of the context pollution when accounting for eliminated reasoning turns and the compounding effect.
Install
No install needed. Use npx:
npx -y callmux -- npx -y @modelcontextprotocol/server-github
Or install globally:
npm install -g callmux
Quick Start
Claude Code
Add to ~/.claude.json or project .mcp.json:
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "callmux", "--", "npx", "-y", "@modelcontextprotocol/server-github"]
}
}
}Done. Claude now sees all GitHub tools plus the callmux_* meta-tools.
More: tool filtering, caching, env vars, multi-server
Filter tools and enable caching:
{
"mcpServers": {
"github": {
"command": "npx",
"args": [
"-y", "callmux",
"--tools", "create_issue,get_issue,list_issues,search_issues",
"--env", "GITHUB_TOKEN=ghp_xxx",
"--cache", "60",
"--cache-allow", "get_*,list_*,search_*",
"--", "npx", "-y", "@modelcontextprotocol/server-github"
]
}
}
}Multiple servers via config file:
Create ~/.config/callmux/config.json (or run callmux setup):
{
"servers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": { "GITHUB_TOKEN": "ghp_xxx" },
"tools": ["create_issue", "get_issue", "list_issues", "search_issues"]
},
"linear": {
"command": "npx",
"args": ["-y", "@linear/mcp-server"],
"env": { "LINEAR_API_KEY": "lin_api_..." }
}
},
"cacheTtlSeconds": 60,
"maxConcurrency": 20
}Then in your MCP config:
{
"mcpServers": {
"callmux": {
"command": "npx",
"args": ["-y", "callmux"]
}
}
}callmux auto-discovers ~/.config/callmux/config.json. With multiple servers, tools are namespaced: github__create_issue, linear__list_issues.
Codex
Add to ~/.codex/config.toml:
[mcp_servers.github] command = "npx" args = ["-y", "callmux", "--", "npx", "-y", "@modelcontextprotocol/server-github"]
Or use the Codex CLI:
codex mcp add github -- npx -y callmux -- npx -y @modelcontextprotocol/server-github
More: tool filtering, caching, env vars, multi-server
[mcp_servers.github] command = "npx" args = [ "-y", "callmux", "--tools", "create_issue,get_issue,list_issues,search_issues", "--env", "GITHUB_TOKEN=ghp_xxx", "--cache", "60", "--cache-allow", "get_*,list_*,search_*", "--", "npx", "-y", "@modelcontextprotocol/server-github" ]
Multi-server:
[mcp_servers.callmux] command = "npx" args = ["-y", "callmux", "--config", "/Users/you/.config/callmux/config.json"]
The Codex macOS app, CLI, and IDE extension all share ~/.codex/config.toml. Project-scoped overrides go in .codex/config.toml.
Claude Desktop (Mac / Windows)
Add to your claude_desktop_config.json:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"callmux": {
"command": "npx",
"args": ["-y", "callmux", "--", "npx", "-y", "@modelcontextprotocol/server-github"]
}
}
}More: PATH issues, multi-server
The Claude desktop app has a minimal PATH. If npx isn't found, use the full path (e.g., /usr/local/bin/npx). Find it with which npx. Or install globally and use "command": "callmux" directly.
Multi-server works the same way as Claude Code. Point at a config file or let auto-discovery find it.
Interactive Setup
The fastest way to go from zero to configured:
npx -y callmux setup
The wizard walks you through:
- Detects existing MCP servers from
.mcp.json,~/.claude.json, and Claude Desktop config, then offers to import them - Pick servers from a curated list (GitHub, Linear, Slack, Filesystem, etc.) or add custom (local command or remote URL)
- Auto-discovers tools by probing each server, then lets you pick which to expose
- Configures caching with sensible defaults
- Attaches to your client (Claude Code, Codex) automatically
Meta-Tools
These are exposed to your agent alongside the proxied tools:
callmux_parallel
Execute multiple independent tool calls concurrently.
{
"calls": [
{ "tool": "get_issue", "arguments": { "number": 1 } },
{ "tool": "get_issue", "arguments": { "number": 2 } },
{ "tool": "get_issue", "arguments": { "number": 3 } }
]
}callmux_batch
Same tool, many items. The bulk operation pattern.
{
"tool": "create_issue",
"items": [
{ "arguments": { "title": "Bug A", "labels": ["bug"] } },
{ "arguments": { "title": "Bug B", "labels": ["bug"] } }
]
}callmux_pipeline
Chain tools where each step feeds into the next.
{
"steps": [
{ "tool": "search_issues", "arguments": { "query": "is:open label:bug" } },
{ "tool": "analyze", "arguments": {}, "inputMapping": { "data": "$json" } }
]
}callmux_cache_clear
Invalidate cached results. Scope by tool, server, or clear everything.
{ "tool": "get_issue", "server": "github" }callmux_status
Introspect callmux from inside your agent. Shows connected servers, tools, and cache state.
{ "server": "github" }Multi-Server Mode
Wrap multiple MCP servers through a single callmux instance. Tools are automatically namespaced (github__create_issue, linear__list_issues) and the server field in meta-tool calls lets you target specific servers:
{
"calls": [
{ "server": "github", "tool": "get_issue", "arguments": { "number": 42 } },
{ "server": "linear", "tool": "get_issue", "arguments": { "id": "ENG-123" } }
]
}Remote Servers (HTTP/SSE)
callmux can connect to remote MCP servers over HTTP, not just local stdio processes. Use url instead of command:
{
"servers": {
"local-github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"]
},
"remote-api": {
"url": "https://mcp.example.com/mcp",
"headers": { "Authorization": "Bearer sk-..." }
}
}
}Transport is auto-detected: callmux tries Streamable HTTP first (the current MCP spec), then falls back to SSE for older servers. Force a specific transport with "transport": "sse" or "transport": "streamable-http".
Inline mode for a single remote server:
npx -y callmux --url https://mcp.example.com/mcp --header "Authorization:Bearer sk-..."Caching
Enable with cacheTtlSeconds or --cache <seconds>. Error results are never cached.
{
"cacheTtlSeconds": 60,
"cachePolicy": {
"allowTools": ["get_*", "list_*", "search_*"],
"denyTools": ["get_secret"]
}
}allowTools: only matching tools are cacheable (whitelist)denyTools: matching tools are never cached (blacklist)- Supports exact names and
*wildcards - Per-server policies combine with the global policy
callmux_cache_clearinvalidates manually
CLI Management
Manage servers without editing JSON:
callmux setup # interactive wizard callmux init # create config manually callmux server add github -- npx -y @modelcontextprotocol/server-github callmux server set github --add-tool search_issues callmux server test --all callmux doctor callmux client status callmux client attach claude --yes
When adding a server without --tools, callmux probes it automatically and lets you pick which tools to expose interactively.
Full CLI reference
| Command | Description |
|---|---|
callmux setup |
Interactive setup wizard |
callmux init |
Create empty config file |
callmux server add <name> [opts] -- <cmd> |
Add a downstream server |
callmux server set <name> [opts] |
Modify an existing server |
callmux server test <name>|--all |
Smoke-test connectivity |
callmux server list [--json] |
List configured servers |
callmux server remove <name> |
Remove a server |
callmux doctor [--json] |
Validate config + probe all servers |
callmux client status [claude|codex] |
Check client configuration state |
callmux client attach <client> [--yes] |
Write callmux into client config |
callmux client detach <client> [--yes] |
Remove callmux from client config |
callmux client print <client> |
Output ready-to-paste snippet |
Inline flags (single-server mode):
| Flag | Description |
|---|---|
--tools <list> |
Comma-separated tool whitelist |
--env KEY=VALUE |
Environment variable (repeatable) |
--cache <seconds> |
Cache TTL |
--cache-allow <list> |
Cacheable tool patterns |
--cache-deny <list> |
Non-cacheable tool patterns |
--concurrency <n> |
Max parallel calls (default: 20) |
--url <url> |
Connect to remote server (instead of -- command) |
--transport <type> |
Force streamable-http or sse |
--header Name:Value |
HTTP header (repeatable) |
Config File
Auto-discovery order:
$CALLMUX_CONFIGenvironment variable~/.config/callmux/config.json
Works on Linux, macOS, and Windows.
Full config schema
{
"servers": {
"<stdio-server>": {
"command": "...",
"args": ["..."],
"env": { "KEY": "value" },
"cwd": "/path",
"tools": ["tool_a", "tool_b"],
"cachePolicy": {
"allowTools": ["get_*"],
"denyTools": ["get_secret"]
}
},
"<http-server>": {
"url": "https://...",
"transport": "streamable-http | sse",
"headers": { "Authorization": "Bearer ..." },
"tools": ["tool_a"],
"cachePolicy": { "allowTools": ["*"] }
}
},
"cacheTtlSeconds": 60,
"cachePolicy": { "denyTools": ["create_*"] },
"maxConcurrency": 20
}Also accepts MCP-compatible format ({ "mcpServers": { ... } }).
Each server needs either command (local stdio) or url (remote HTTP/SSE). All other fields are optional. tools filters which downstream tools are exposed. Omit to expose everything.
Related
- tokenlean - CLI tools for AI agents, token-efficient code understanding. Same philosophy: make agents less wasteful.
License
MIT


























