We wrote one agent SDK and ported it, by hand, to seven languages — JS, Python, Go, Java, C#, Elixir, Clojure — until the same conformance suite passes byte-identical output in every one of them.
Point toolnexus at an mcp.json and a skills/ folder and you get a working agent: the
tool-calling loop, skills injection, six unified tool sources, and conversation memory — all
included. Vendor-neutral, byte-identical across JavaScript · Python · Go · Java · C# · Elixir ·
Clojure — the Clojure port is one .cljc tree that runs on both the JVM and cljgo, held
to the same full tier as the other six and published to Clojars like the rest.
Right-sized. Not a framework — no builders, advisors, runnables, or config to wade through. Not a toy that falls over the moment you need streaming or a retry. Exactly what a real agent needs — MCP, skills, native + HTTP + built-in tools, remote A2A agents, in-process sub-agents, the loop, hooks, streaming, retries, memory — and nothing it doesn't.
npm i toolnexus # JS / TypeScript
pip install toolnexus # Python
go get github.com/muthuishere/toolnexus/golang # Go
dotnet add package Toolnexus # C#
{:toolnexus, "~> 0.18"} # Elixir (mix.exs deps)
# Java (Maven): io.github.muthuishere:toolnexus:0.18.1
# Clojure (deps.edn): net.clojars.muthuishere/toolnexus {:mvn/version "0.18.1"} — JVM and cljgo
The insight (borrowed from opencode): MCP server
tools, agent skills, your own functions, remote HTTP endpoints, the built-in shell/file
tools, remote A2A agents, and in-process sub-agents are all the same thing to an LLM — a
named, described, schema'd callable. toolnexus unifies every tool source behind one Tool
interface and drives any model with them.
1. Point at an mcp.json — the standard Claude-desktop-style config:
{
"mcpServers": {
"fs": { "command": ["npx", "-y", "@modelcontextprotocol/server-filesystem", "/data"] },
"acme": { "type": "remote", "url": "https://api.acme.com/mcp",
"headers": { "Authorization": "Bearer ${ACME_TOKEN}" } }
}
}
2. Point at a skills/ folder — **/SKILL.md files with YAML frontmatter, loaded on demand
through one skill tool (progressive disclosure).
3. Run.
import { createToolkit, createClient } from "toolnexus"
const tk = await createToolkit({ mcp: "mcp.json", skills: ["skills"] })
const agent = createClient({ baseUrl: "https://openrouter.ai/api/v1", style: "openai", model: "openai/gpt-4o-mini" })
const { text } = await agent.run("Refund order 4021 using the policy.", { toolkit: tk })
The same three steps, in the same shape, in every port — see your language's API reference below.
| language | package | API reference |
|---|---|---|
| JavaScript / TypeScript | toolnexus (npm) | api/javascript |
| Python | toolnexus (PyPI) | api/python |
| Go | github.com/muthuishere/toolnexus/golang | api/go |
| Java | io.github.muthuishere:toolnexus | api/java |
| C# / .NET | Toolnexus (NuGet) | api/csharp |
| Elixir | toolnexus (Hex) | api/elixir |
| Clojure | net.clojars.muthuishere/toolnexus | api/clojure |
Each port's own README covers install and a quick start; everything beyond that is on the docs site.
| Start here | Quickstart · Concepts · Install |
| Tool sources | MCP · Skills · Native · HTTP · Built-ins · A2A |
| The loop | Streaming · Memory · Suspension · Resilience · Observability |
| Agents | Sub-agents & teams · Personas · Typed decisions (Classifier) |
| Cookbook | Zero to agent · MCP servers · Agent skills · Judge |
| Numbers | Performance · Comparison · Judge, live |
SPEC.md is the cross-language contract — §0 is the one-page conformance suite every
port must satisfy. A behaviour change lands in all seven ports or it is not done; the shared
fixtures in examples/ are what "identical" is measured against.
Changes go through OpenSpec before code. See CLAUDE.md for the
workflow, CHANGELOG.md for what shipped, and PUBLISHING.md
for how each port is released.
MIT — see LICENSE.
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |