One MCP to orchestrate them all.
VoidMCP is a standalone MCP server that gives your AI agent Code Mode - the ability to write and execute JavaScript that orchestrates multiple MCP tools in a single sandboxed execution. No round-trips, no token waste, no setup complexity.
Add MCPs at runtime. Search across tools. Let your agent write scripts that chain GitHub + Notion + Slack + anything with an MCP server.
Built by the team behind VoidLLM.
When your AI agent has access to 10 MCP servers with 50+ tools, two problems emerge:
- Token waste - every tool schema is sent to the LLM on every request
- Round-trip overhead - chaining 5 tool calls means 5 LLM inference cycles
VoidMCP solves both. It exposes a single execute_code tool. The LLM writes a JavaScript script that calls multiple tools in one execution. One inference, one sandbox, multiple tool calls.
// One script, three tool calls, zero round-trips
const issues = await tools.github.search_issues({ q: "is:open label:bug" });
for (const issue of issues.items.slice(0, 5)) {
await tools.notion.create_page({ title: issue.title, content: issue.html_url });
}
await tools.slack.post_message({ channel: "#bugs", text: `Synced ${issues.items.length} issues` });go install github.com/voidmind-io/voidmcp/cmd/voidmcp@latestOr install the latest release binary:
macOS / Linux:
curl -fsSL https://raw.githubusercontent.com/voidmind-io/voidmcp/main/install.sh | shWindows (PowerShell):
irm https://raw.githubusercontent.com/voidmind-io/voidmcp/main/install.ps1 | iexManual downloads are also available on Releases.
claude mcp add --transport stdio voidmcp -- voidmcp serve --stdioAdd to your claude_desktop_config.json:
{
"mcpServers": {
"voidmcp": {
"type": "stdio",
"command": "voidmcp",
"args": ["serve", "--stdio"]
}
}
}Same config format. Point to the full voidmcp binary path if it's not in your PATH.
Public servers (no auth) - the AI agent can add these directly:
"Add the weather MCP at https://weather.mcp.example.com"
Servers with authentication - use the CLI to keep tokens out of the LLM context:
voidmcp add github https://mcp.github.com --token ghp_your_token_here
voidmcp add notion https://mcp.notion.com --token ntn_your_token_here
voidmcp add myapi https://api.example.com/mcp --token secret --header X-Api-KeyLocal stdio servers (child processes) - also CLI-only:
voidmcp add filesystem "npx -y @modelcontextprotocol/server-filesystem /home/user/docs"
voidmcp add sqlite "uvx mcp-server-sqlite --db /tmp/test.db"You can also manage servers via CLI:
voidmcp list # show registered servers + tools
voidmcp remove filesystem # unregister a serverVoidMCP exposes 5 tools to the LLM:
| Tool | Description |
|---|---|
add_mcp |
Register an HTTP MCP server (discovers its tools automatically) |
remove_mcp |
Unregister a server |
list_mcps |
List all registered servers with their tools and status |
search |
Find tools by keyword across all registered servers |
execute_code |
Run JavaScript in a WASM sandbox with access to all registered tools |
The workflow is always: search first, then execute.
- The LLM calls
search("your goal")to discover relevant tools with full TypeScript signatures - The LLM calls
execute_codewith JavaScript that chains the discovered tools - VoidMCP injects tool bindings into a WASM-sandboxed QuickJS runtime
- The script runs with
awaitsupport, calling tools across multiple servers - VoidMCP returns the result, console logs, and a summary of all tool calls made
The sandbox has no access to the host filesystem, network, or environment. Tool calls go through a Go bridge that routes to the correct MCP transport.
The first time a tool is called, VoidMCP captures the response and infers its return type. On subsequent search calls, the TypeScript definitions show concrete return types instead of Promise<any>:
// Before first call:
function read_query(args: { query: string }): Promise<any>;
// After first call:
function read_query(args: { query: string }): Promise<Array<{ id: number; name: string; email: string }>>;Inferred schemas are stored in SQLite and refresh after 7 days (configurable via --schema-ttl).
For shared or remote deployments:
voidmcp serve --port 8090Binds to 127.0.0.1 by default. A bearer token is generated at startup and printed to stderr. Use --host 0.0.0.0 to expose on the network, --no-auth to disable the token.
All settings are available as CLI flags:
voidmcp serve [flags]
--stdio Use stdio transport (default: HTTP)
--port int HTTP port (default: 8090)
--host string Bind address (default: 127.0.0.1)
--no-auth Disable bearer token authentication
--db string Database path (default: ~/.voidmcp/voidmcp.db)
--pool-size int WASM runtime pool size (default: 4)
--memory int Per-execution memory limit in MB (default: 16)
--timeout duration Per-execution timeout (default: 30s)
--max-tool-calls int Maximum tool calls per execution (default: 50)
Registered servers and their tools persist in SQLite across restarts.
- WASM sandbox: JavaScript runs in QuickJS compiled to WebAssembly. No filesystem, network, or environment access. Runtimes are discarded after each execution.
- Localhost only: HTTP server binds to
127.0.0.1by default - Bearer auth: Random 256-bit token generated at startup for HTTP mode
- Credentials never touch the LLM: The
add_mcptool only accepts public URLs (no auth). Servers requiring tokens and local stdio servers can only be registered via CLI. This keeps API keys out of the LLM context and prevents prompt injection from triggering arbitrary command execution. - Encrypted credentials: Auth tokens stored with AES-256-GCM in SQLite. Encryption key at
~/.voidmcp/keywith 0600 permissions. - Restricted child env: stdio MCP servers receive only PATH, HOME, TMPDIR, LANG from the parent environment
~/.voidmcp/
voidmcp.db SQLite database (registered servers, cached tool schemas)
key AES-256-GCM encryption key (auto-generated, chmod 0600)
MIT
- VoidLLM - Privacy-first LLM proxy with built-in Code Mode for teams