Skip to content

v0.4.0

Latest

Choose a tag to compare

@github-actions github-actions released this 14 Oct 00:03
· 1 commit to main since this release

v0.4.0

Bring your own server.

All 10 languages.

October 2026

Every language now does what Node.js does: federate remote MCP servers, pass your app's runtime into tools, and hand you a registry to mount in the HTTP server you already run. And none of them ships its own HTTP server anymore.

What's new

No built-in HTTP server

ZeroMCP doesn't own the HTTP layer. Every language ships stdio plus the framework-neutral pieces: a request handler and a registry that gives you routes, an OpenAPI document and an MCP handler as plain data. Mount them in Express, FastAPI, Axum, Javalin, ASP.NET, Sinatra, Slim — whatever you run. Auth, CORS and health checks are your server's job.

A config with an http transport now fails at startup with a message naming the replacement. Nothing falls back silently.

Remote MCP servers, everywhere

The remote config federates other MCP servers over HTTP. Their tools appear as <name>.<tool>; tools optionally limits which ones are exposed; a local tool with the same name wins. auth accepts a token or env:VAR. Works in the stdio server, the handler and the registry.

{
  "tools": "./tools",
  "remote": [
    { "name": "github", "url": "https://mcp.example.com/mcp", "auth": "env:GH_TOKEN", "tools": ["list_issues"] }
  ]
}

Runtime context

Pass something from your app — a DB pool, the current user — and local tools receive it as ctx.runtime on every call.

Hot reload

autoload_tools watches tool directories and sends notifications/tools/list_changed over stdio, in the languages that load tools from directories (Node.js, Python, Go, Ruby, PHP).

Breaking changes

  • The built-in HTTP server is removed in every language (serveHttp, serve_http, ServeHttp, startHttp, the http transport, HTTP auth, /docs, /health). Mount the handler or registry in your own server instead.
  • Registry constructors that now connect to remote servers are async where the language needs it (noted per language below).

Node.js

  • Removed the built-in HTTP listener (zeromcp serve http, { "type": "http" }). Mount createHandler (@antidrift/zeromcp/handler) or createRegistry (@antidrift/zeromcp/registry) in your own server.

Python

  • New create_registry (from zeromcp import create_registry): routes, OpenAPI and an MCP handler from a tools dict. Async; takes get_env, title, version, execute_timeout and remote.
  • remote config, with the tools allowlist, in serve(), create_handler() and create_registry().
  • create_handler(config, get_runtime=...) passes the value to tools as ctx.runtime.
  • autoload_tools hot reload.
  • Removed the built-in HTTP server. An http transport exits with an error naming create_registry / create_handler.

Go

  • remote config, with the tools allowlist; remote tools show up in HandleRequest and Registry().MCP.
  • (*Server).SetRuntime(func() any) → ctx.Runtime.
  • autoload_tools hot reload; tools, namespacing, resources and prompts config.
  • The module path is now github.com/antidrift-dev/zeromcp-go, matching the repo it ships from. The old path couldn't be installed; use go get github.com/antidrift-dev/zeromcp-go/pkg/zeromcp.
  • Fixed a deadlock between Registry() and a concurrent Tool().
  • Removed serveHTTP, TransportConfig.Port/.Auth and ResolveAuth. An http transport exits with an error naming Registry().

Rust

  • remote config, with the tools allowlist. Call Server::prepare().await before handle_request to connect remotes (serve does it for you).
  • create_registry is now async and takes RegistryOptions { remote }.
  • Server::set_runtime → ctx.runtime_as::<T>().
  • page_size and icon config.
  • Removed serve_http. An http transport panics with a message naming create_registry.
  • Minimum Rust version is now 1.85 (remote support uses reqwest).

Java

  • remote config or ZeroMcp.remote(...), with the tools allowlist; remote tools appear in registry().mcp().
  • ZeroMcp.runtime(Supplier) → ctx.runtime().
  • page_size and icon config.
  • Removed serveHttp and Config.port(). serve() throws on any transport other than stdio, naming registry().

Kotlin

  • remote config, with the tools allowlist. Call connectRemotes() before handleRequest (serve() and registry() do it for you). registry() is now a suspend function.
  • runtimeProvider → ctx.runtime.
  • icon and page_size config.
  • Removed serveHttp and the port config. Non-stdio transports fail at startup, naming registry() / handleRequest().
  • kotlinx-serialization and kotlinx-coroutines are now api dependencies, so you can compile against the registry's types.

Swift

  • remote config, with the tools allowlist. Call prepare() once before handleRequest (serve() does it for you).
  • createRegistry is now async and connects remotes.
  • getRuntime on the server and in the registry options → ctx.runtime.
  • page_size and icon config.
  • Removed serveHttp. An http transport exits with an error naming createRegistry.
  • The library now builds on Linux; every Swift conformance suite runs and passes.

C#

  • remote config, with the tools allowlist. Prepare() connects remotes (Serve() calls it).
  • New Registry.CreateAsync with RegistryOptions.Remote.
  • ZeroMcpServer.GetRuntime → ToolContext.Runtime.
  • page_size and icon config.
  • Removed ServeHttp. Serve() throws on an http transport.

Ruby

  • remote config, with the tools allowlist; ZeroMcp.create_registry(tools, remote: [...]).
  • get_runtime: on Server and create_registry → ctx.runtime.
  • autoload_tools hot reload; tool sources with prefix, and namespacing; icon as an http(s) URL.
  • Removed serve_http. The gem no longer needs WEBrick. An http transport exits with an error naming ZeroMcp.create_registry.

PHP

  • remote config, with the tools allowlist; Registry::create($tools, ['remote' => [...]]).
  • new Server($config, ['get_runtime' => ...]) → $ctx->runtime.
  • autoload_tools hot reload; tool sources with prefix, and namespacing.
  • Logging no longer crashes under php -S, FPM or Apache (it used STDERR, which only exists in the CLI).
  • Removed serveHttp() and the http command. An http transport fails at startup.