Agents keep gaining access to more MCP tools — dozens, then hundreds. Exposing them all at once to Claude Code, Cursor, or OpenCode creates four concrete problems:
| Problem | Consequence |
|---|---|
| Discovery | an agent can't reason over 500 tool descriptions |
| Context | every exposed tool bloats the agent's context with irrelevant schemas |
| Security | a tool shouldn't automatically receive unlimited permissions |
| Maintenance | wiring each tool into each agent is duplicated, scattered work |
MCP Nexus answers with a capability surface: rather than dumping every tool, it exposes the few that fit the current request. One umbrella MCP endpoint in front of hundreds of tools — the agent only ever sees the right capability at the right time.
It's free and open source (Apache-2.0), written in TypeScript, and runs on the Model Context Protocol. v1.0.0 is out.
What it does
-
One endpoint, hundreds of tools — agents connect once over stdio or Streamable HTTP to the full
nexus.*surface:register_tool,remove_tool,inspect_tool,list_tools,route,discover,invoke,approvals,resolve_approval. -
Dynamic capability discovery —
nexus.discoverreturns the minimal tool surface that fits the request instead of 500 schemas. - Explainable routing — every decision carries a provider, confidence, matched capabilities, and alternatives.
- LLM-optional — heuristic → semantic → LLM fallback. It routes perfectly with no GPU, no API key, no internet.
- Policy-aware execution — per-tool permission scopes plus allow / deny / approval rules.
-
Audit-ready — JSONL activity log with
executionIdcorrelated end-to-end from gateway invoke to dashboard activity.
Architecture
AI AGENT
Claude / Cursor / Codex
│
▼
┌─────────────────┐
│ MCP SERVER │ stdio · Streamable HTTP
└────────┬────────┘
│
▼
┌─────────────────┐
│ DISCOVERY │
└────────┬────────┘
│
┌─────────┴─────────┐
▼ ▼
TOOL REGISTRY ROUTER intent overlay
│
┌───────────┼───────────┐
▼ ▼ ▼
Heuristic Semantic LLM*
│ │ │
└───────────┼───────────┘
▼
POLICY ENGINE
│
▼
TOOL RUNNER
│
local · stdio · docker · http
│
▼
MCP TOOL
* LLM is optional — the zero-dependency router stack runs fully offline.
Quick start
Requires Node.js ≥ 22 (Node 24 recommended for native TypeScript).
git clone https://github.com/dsk-dev-ai/mcp-nexus.git
cd mcp-nexus
npm install
# stdio (local client)
npm start
# …or Streamable HTTP (remote clients)
npm start -- start:http # http://127.0.0.1:3001/mcp
Connect the endpoint from any MCP client. From a second terminal, manage the registry:
npm start -- add tools/repoarch.json
npm start -- add tools/ctx.json
npm start -- add tools/dependency-audit.json
npm start -- list # browse
npm start -- inspect repoarch # full manifest
npm start -- search "check vulnerable dependencies" # dry-run routing
npm start -- doctor # environment check
npm start -- benchmark # CI gate
Now connect any MCP client and ask:
"Analyze my repository architecture and check dependencies for vulnerabilities."
The agent calls nexus.route / nexus.invoke; Nexus discovers, selects, policy-checks, and executes the right tool — over both transports.
How routing works
The router chain is provider fallback, left to right:
heuristic → semantic → llm
| Provider | What it does |
|---|---|
| heuristic | deterministic keyword / capability scoring with an embedded stemmer |
| semantic | zero-dependency character-bigram / IDF fuzzy router; recovers typos like "archtecture" and "vulnerbilities" |
| llm | Gemini (REST) or OpenRouter (OpenAI-compatible); reports unavailable without a key so the chain never depends on it |
A deterministic intent overlay fires at the route head in both heuristic and semantic layers, so domain vocabulary — git history, dependency/lockfile risk, secret scanning, repo structure — always wins over generic context fallbacks.
Every decision is explainable:
$ npm start -- search "check vulnerable dependencies"
Request: "check vulnerable dependencies"
Selected: dependency-audit
Provider: heuristic
Confidence: 100%
Matched capabilities: dependency-audit
Alternatives: repoarch (49%), ctx (0%)
Why: Matched capabilities: dependency-audit for "dependency-audit".
Policy-aware execution
Manifests carry permission scopes; global rules add allow / deny / approval:
// .nexus/policy.json
{
"default": "allow",
"rules": [
{ "tool": "git", "blocklists": ["git.push"], "approvals": ["git.commit"] }
]
}
Approval-gated tools queue for an operator and resolve over the gateway (nexus.approvals, nexus.resolve_approval) or through the web dashboard.
Deterministic benchmark, not vibes
A fully-offline reference suite — 6 tools / 32 tasks across exact / semantic / ambiguous / unknown intents — reproducible on any machine:
| Provider | Accuracy | exact | semantic | ambiguous | unknown |
|---|---|---|---|---|---|
| Heuristic | 100.0% | 15/15 | 4/4 | 5/5 | 8/8 |
| Semantic | 87.5% | 15/15 | 4/4 | 2/5 | 7/8 |
| Hybrid | 93.8% | 15/15 | 4/4 | 4/5 | 7/8 |
| Large (50 tools) | 100.0% | 20/20 | — | — | — |
Hard failures: none. mcp-nexus benchmark exits 0 only when every exact + semantic reference task routes correctly — and that is the CI gate.
Try it
- GitHub: dsk-dev-ai/mcp-nexus
- Project site: dsk-dev-ai.github.io/mcp-nexus
- Docs: API, architecture, routing, registry, benchmarks, dashboard, security, clients, SDK, performance, integrations
- Sponsor: github.com/sponsors/dsk-dev-ai
Top comments (3)
The explainable routing is the part I’d operationalize first. I’d version-test the capability registry like an API contract: replay a fixture set of ambiguous requests, record the selected tool, alternatives, and policy decision, then fail CI when a new manifest changes routing unexpectedly. For approval-gated actions, putting the exact arguments plus a short diff in the queue helps the reviewer judge intent, not just the tool name.
Thanks Noah! This is a great suggestion. I especially like treating the capability registry as an API contract with routing regression tests. I’ll look at incorporating this into the next iteration of MCP Nexus, along with clearer approval details for gated actions.
nice, glad it helped. one small thing if you do the approval details: store what the tool call actually looked like at the moment it got approved (args and all), not just an approved=true flag. saves a lot of head scratching later when someone asks why the agent did X