McpOrchestrator 0.2.3
{ "servers": { "McpOrchestrator": { "type": "stdio", "command": "dnx", "args": ["McpOrchestrator@0.2.3", "--yes"] } } }
.vscode/mcp.json settings file.
dotnet tool install --global McpOrchestrator --version 0.2.3
dotnet new tool-manifest
dotnet tool install --local McpOrchestrator --version 0.2.3
#tool dotnet:?package=McpOrchestrator&version=0.2.3
nuke :add-package McpOrchestrator --version 0.2.3
McpOrchestrator — a .NET-native MCP orchestrator
Every MCP server you connect costs context before the agent does anything — its tool manifests sit in the prompt on every turn. Connect enough of them and you're spending tens of thousands of tokens just describing tools the agent isn't using yet.
McpOrchestrator puts one server between your agent and all the others. It loads downstream tool manifests on demand instead of upfront, so the agent's always-on context stays flat no matter how many servers you add. It's a pure relay — the orchestrator never interprets the agent's input.
Measured impact
Running against a real workplace MCP setup, measured with the Copilot CLI's /usage:
| Tokens in context | |
|---|---|
| MCP connected directly (manifests loaded upfront) | 17,900 |
| Same MCP behind McpOrchestrator | 1,400 |
| Reduction | ~13x |
The savings scale with the number of servers: the more MCPs you connect, the more upfront manifest cost you avoid. Measure your own setup with the profile command below — no install, nothing changed.
How it works
One agent connects to this single server; it holds connections to many downstream MCP servers (JIRA, code generation, a filesystem server, …) and relays the agent's calls to the right one — so you use one agent + one MCP instead of switching agents per toolset. Downstream tools are discovered on demand via three meta-tools:
list_capabilities → discover_tools("Tokensaver") → route("Tokensaver", "outline_c_sharp_file", { … })
Where this fits
The value here is the smallest possible surface: a pure stdio relay that installs as a single .NET tool (or AOT binary, no runtime), with nothing to read but the routing path. Progressive discovery isn't unique to it — the closest .NET alternative, mcp-aggregator, does more (REST API alongside MCP, runtime server registration, credential management), so reach for that if you want a gateway. Reach for this if you want the leanest possible relay with nothing extra to run or reason about. It deliberately omits the enterprise layer — auth, multi-tenancy, rate limiting — that gateways like Kong or Envoy provide.
👉 Full documentation: McpOrchestrator/README.md — how it works, setup, adding new MCPs, configuration reference, testing, and troubleshooting.
Is this tool for you? Check in one command — no install
Before changing anything, see what the orchestrator would actually save for your servers. Point it at your existing MCP host config and it connects to each stdio server once, then prints the token savings — nothing is installed and not a single file is changed (needs the .NET SDK):
dotnet tool execute McpOrchestrator profile --host-config <your .mcp.json / Cursor / Claude Desktop config>
Remote (http/sse) servers can't be relayed and are skipped; everything else is measured in memory. If the numbers look good, set it up below — if not, you're done, with no cleanup. (Full details and a local-build variant: the profiling guide.)
Quick start
Three steps from an existing MCP setup to running through the orchestrator.
1. Install
The .NET tool (needs the .NET SDK — dotnet tool ships with the SDK, not the runtime) puts the mcp-orchestrator command on your PATH:
dotnet tool install --global McpOrchestrator
No .NET SDK? Download the self-contained Native-AOT binary from GitHub Releases, unzip it, and use the absolute path to the binary as the command (pass it to
initbelow with--command <path>). It needs no .NET at all.
2. Init
Point init at your existing MCP host config — .mcp.json (Claude Code, Visual Studio), .vscode/mcp.json (VS Code), or a Cursor / Claude Desktop config:
mcp-orchestrator init path/to/.mcp.json
It lifts every stdio server into a generated orchestrator.config.json (one capability each), backs up the original to .bak, then rewrites it to launch only the orchestrator — pointed at the new catalog via MCP_ORCHESTRATOR_CONFIG. Remote (http/sse) servers can't be relayed over stdio, so they're left in place untouched. (Add --dry-run to preview both files first.)
3. Add summary text
Open the generated orchestrator.config.json and replace each capability's TODO summary with a one-line description of when the agent should use it — that line is what the agent reads to route. Then restart your MCP host.
That's it. The agent now sees three meta-tools and the flow is list_capabilities → discover_tools("…") → route("…", "<tool>", { … }).
Starting from scratch with no MCP config yet? See Manual setup for the two files
initwould otherwise generate. Logs are mirrored to~/.mcpOrchestrator/orchestrator.log.
Manual setup
init automates this; do it by hand if you have no host config yet or want full control. Two config files are involved:
- Host config — your agent's existing MCP file:
.mcp.json(Claude Code and Visual Studio) or.vscode/mcp.json(VS Code). You add the orchestrator as a server here. - Orchestrator config — a new file you create (e.g.
orchestrator.config.json), pointed to by theMCP_ORCHESTRATOR_CONFIGenvironment variable. It lists the downstream MCP servers.
1. Add the orchestrator to your host config (.mcp.json / .vscode/mcp.json)
The agent only ever sees this one server:
{
"servers": {
"orchestrator": {
"type": "stdio",
// The command the tool put on your PATH — `mcp-orchestrator`, NOT the package
// id `McpOrchestrator`. (Or the absolute path to the AOT binary instead.)
"command": "mcp-orchestrator",
"args": [],
"env": {
// absolute path to the orchestrator config you create in step 2:
"MCP_ORCHESTRATOR_CONFIG": "<ABSOLUTE-PATH-TO>/orchestrator.config.json"
}
}
}
}
2. List your downstream servers in the orchestrator config (orchestrator.config.json)
This is the file you pointed MCP_ORCHESTRATOR_CONFIG at. Each entry is one capability the agent can route to; command/args/env are how that downstream MCP is launched. Use plain absolute paths here — you don't need any special syntax. Optionally, ${...} placeholders are substituted if you want them: ${CONFIG_DIR} (the folder this config lives in) and any ${ENV_VAR} (a process environment variable, e.g. for API keys):
{
"capabilities": [
{
"name": "files",
"summary": "Read and write files on the local machine.",
"enabled": true,
"transport": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "<ABSOLUTE-PATH-TO>/projects"],
"connectTimeoutSeconds": 30
},
{
"name": "Tokensaver",
"summary": "Reduce tokens spent when working with .NET (outline/minify/trace DI).",
"enabled": true,
"transport": "stdio",
"command": "dotnet",
"args": ["tool", "execute", "TokenSaver.Mcp", "--yes"],
"env": {
"TOKENSAVER_API_URL": "https://tokensavermcp.com",
"TOKENSAVER_UPDATE_INTERVAL_MINUTES": "0"
}
}
]
}
Restart the MCP host to pick it up.
The agent now sees the three meta-tools and the flow is list_capabilities → discover_tools("Tokensaver") → route("Tokensaver", "outline_c_sharp_file", { … }).
Notes.
summaryis what the agent routes on.instructionsis an optional usage hint surfaced to the agent — omit it unless a capability needs one.env/workingDirectoryare per-capability and optional. The config file supports//comments. There's also a${SOLUTION_DIR}placeholder, but you almost certainly don't need it — it resolves to this repo's solution root and exists only so the in-repo sample configs can find sibling demo servers. For your own setup, use absolute paths,${CONFIG_DIR}, or${ENV_VAR}instead. Logs are mirrored to~/.mcpOrchestrator/orchestrator.log. See the full documentation for every field, packaging, and troubleshooting.
Testing a local build?
pack-local.ps1packs the project as a pinned9.9.9-devversion intonupkg/local-feed; theninit --dev-feed nupkg/local-feedwires the host to launch the orchestrator from that feed, so it always runs your latest local code. Re-runpack-local.ps1and restart the host to pick up changes.
Projects
| Project | Role |
|---|---|
McpOrchestrator |
The orchestrator: MCP server to the agent, MCP client to downstream servers. The ~1.4 MB tool. |
McpOrchestrator.DemoMcp |
Sample downstream MCP (--persona jira / codegen / diag). |
McpOrchestrator.SmokeTest |
Console MCP client that drives the orchestrator end-to-end. |
McpOrchestrator.Tests |
xUnit suite: unit + integration + end-to-end. |
The three tools
list_capabilities → discover_tools → route (you pick the tool and fill the arguments). The orchestrator is a courier, not an interpreter: it forwards exactly what the agent sends — the agent does the thinking. See the full docs for details.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
This package has no dependencies.