MCP servers
What is MCP?
Section titled “What is MCP?”The Model Context Protocol is an open standard for connecting AI models to external systems. An MCP server exposes a set of capabilities — tools (callable functions), resources (readable data), and prompts — over a well-defined JSON-RPC interface. The model (the client) discovers what a server offers and calls it, without hard-coding anything server-specific.
Servers speak one of two transports:
- Local (stdio) — the server runs as a child process on your machine and talks over stdin/stdout. Great for filesystem, git, databases, anything local.
- Remote (streamable-HTTP) — the server is a URL you connect to over HTTP. Great for hosted, shared, or third-party services.
MCP is vendor-neutral: the same server works with any client that speaks the protocol.
You’re the host — consume the world’s servers
Section titled “You’re the host — consume the world’s servers”People all over the world ship MCP servers — for GitHub, Postgres, Slack, filesystems, anything.
toolnexus is the host that connects your LLM to them. You don’t author MCP servers with
toolnexus; you use the ones that already exist. Point it at a single mcp.json and it dials
every server listed (local stdio and remote HTTP), discovers their tools, and hands your
model one uniform Tool interface — the connection, discovery, and schema translation handled for
you, no per-server glue.
const tk = await createToolkit({ mcpConfig: "./mcp.json" })tk = await create_toolkit(mcp_config="./mcp.json")tk, _ := toolnexus.CreateToolkit(ctx, toolnexus.Options{ MCPConfig: "./mcp.json" })Toolkit tk = Toolkit.create(new Toolkit.Options().mcpConfig("./mcp.json"));await using var tk = await Toolkit.CreateAsync(new Toolkit.Options { McpConfig = "./mcp.json" });Each server tool is namespaced as <server>_<tool> (sanitised), so a tool named echo on a
server named everything becomes everything_echo — no collisions across servers.
The mcp.json format
Section titled “The mcp.json format”Both transports live in one file. This is the shared fixture toolnexus tests every port against:
{ "mcpServers": { "everything": { "type": "local", "command": ["npx", "-y", "@modelcontextprotocol/server-everything"], "enabled": true, "timeout": 30000 }, "example-remote": { "type": "remote", "url": "https://example.com/mcp", "headers": { "Authorization": "Bearer ${MCP_TOKEN}" }, "enabled": false } }}| Field | Applies to | Meaning |
|---|---|---|
type |
both | "local" (stdio child process) or "remote" (streamable-HTTP) |
command |
local | argv array to spawn the server |
url |
remote | the server endpoint |
headers |
remote | sent on every request; ${ENV_VAR} is expanded from the environment |
enabled |
both | skip a server without deleting it |
timeout |
both | per-call timeout in milliseconds |
What toolnexus adds on top
Section titled “What toolnexus adds on top”MCP defines the protocol. toolnexus is what makes it usable inside an agent loop — and it does so identically in five languages:
- One registry, every source. MCP tools sit beside your functions, agent skills, HTTP tools,
built-ins, and A2A agents — all one
Toolinterface, all callable in the same loop. - Dynamic, config-driven loading. No per-server glue code. Add a server to
mcp.jsonand it appears; setenabled: falseand it’s gone. - Both transports, one API. Local stdio and remote streamable-HTTP are the same to you.
- The MCP elicitation bridge. When a server asks the client for input mid-call
(
elicitation/create), toolnexus maps it onto its own suspension layer — so a server can pause your agent to ask the user a question, and your singlewaitForhost answers it. Advertised to servers only when you provide awaitFor. - Byte-identical parity. The same
mcp.jsonyields the same tools and behavior in JavaScript, Python, Go, Java and C#.
Inbound: serve your toolkit as an MCP server
Section titled “Inbound: serve your toolkit as an MCP server”Because every source is unified behind one Tool interface, toolnexus can turn around and
re-serve the whole toolkit back out. toolkit.serve(addr, { mcp }) exposes everything you
assembled — MCP tools, skills, native + HTTP tools, built-ins, and A2A agents — as a single MCP
server any other host can consume:
await tk.serve("127.0.0.1:8080", { mcp: {} }) // mounts POST /mcp — your whole toolkit, as one MCP serverThis is a re-export of the aggregate, not a framework for hand-authoring servers — you never
write protocol handlers or transports. The same serve(...) can also expose your toolkit as an
A2A agent. So what you assembled as a host is instantly consumable by
other hosts, too.