内容
# toolnexus
[](https://github.com/muthuishere/toolnexus/actions/workflows/ci.yml)
**几行代码构建代理。** 引入任意LLM端点,指向 `mcp.json` 和 `skills/` 文件夹,即可获得一个可用的代理——系统、技能、工具调用循环,全部包含在内。一个小型、**供应商中立** 的库,支持 **JavaScript / TypeScript, Python, Go, 和 Java**。
灵感来自 [opencode](https://github.com/anomalyco/opencode):MCP服务器工具、代理技能、您自己的函数和远程HTTP端点在LLM眼中都是*相同的事物*——一个命名、描述、模式化的可调用函数。toolnexus统一了**四个工具源**,并通过一个 `Tool` 接口驱动**任何**模型。
```
来源 工具包 任意LLM
┌────────────────┐
│ MCP服务器 │──┐
│ (mcp.json) │ │ ┌─────────────────────────┐ ┌──────────────┐
├────────────────┤ │ │ 统一的Tool[]注册表 │─────▶│ OpenAI风格 │
│ 代理技能 │ ├─────▶│ • tools() / execute() │ ├──────────────┤
│ (SKILL.md) │ │ │ • skillsPrompt() │─────▶│ Anthropic │
├────────────────┤ │ │ • toOpenAI/Anthropic/ │ ├──────────────┤
│ 原生函数 │ │ │ Gemini() │─────▶│ Gemini │
│ (@tool) │ │ └────────────┬────────────┘ └──────────────┘
├────────────────┤ │ ▼
│ HTTP / OpenAPI │──┘ ┌─────────────────────────────────┐
│ (url+headers) │ │ 统一客户端(主机循环): │
└────────────────┘ │ baseURL + style + model → run() │
│ 注入技能 → 调用 → 执行 → … │
└─────────────────────────────────┘
```
## 从零开始构建代理,3步
无需框架,无需胶水。两个文件和一个调用——您的LLM现在具有**MCP工具和代理技能**,这是其他库无法直接提供的。
**1. 添加MCP配置文件** — `mcp.json`:
```jsonc
{ "mcpServers": {
"fs": { "command": ["npx","-y","@modelcontextprotocol/server-filesystem","/data"] },
"acme": { "type": "remote", "url": "https://api.acme.com/mcp",
"headers": { "Authorization": "Bearer ${ACME_TOKEN}" } }
} }
```
**2. 添加技能文件夹** — `skills/process-refund/SKILL.md`:
```markdown
---
name: process-refund
description: Use when a customer asks for a refund. Walks the policy + steps.
---
# 退款工作流
1. 验证订单 …
```
**3. 调用任意LLM** — MCP + 技能已经包含在内:
```ts
const tk = await createToolkit({ mcpConfig: "./mcp.json", skillsDir: "./skills" })
const agent = createClient({ baseUrl: "https://openrouter.ai/api/v1", style: "openai", model: "openai/gpt-4o-mini" })
const { text } = await agent.run("Refund order 1234 for the customer.", { toolkit: tk })
// 模型已经可以看到每个MCP服务器工具和一个`skill`工具,并且技能目录被注入到其系统中——它加载`process-refund`并调用fs/acme工具。
```
就是这样。如果您想使用自己的循环?使用 `tk.toOpenAI()` / `toAnthropic()` / `toGemini()` 获取模式,并使用 `tk.execute(name, args)` 运行调用。相同的三个步骤适用于Python、Go和Java。
## 为什么选择toolnexus(而不是框架)
巨头们各自覆盖了*部分*领域;没有一个涵盖了我们领域的全部:
| | MCP来自配置 | 代理技能(SKILL.md) | 原生/装饰工具 | HTTP/OpenAPI→工具 | 统一的任意LLM客户端 | 语言 |
|---|:--:|:--:|:--:|:--:|:--:|---|
| **Spring AI** | ✅ | ❌ | ✅ | ❌ | ✅ | 仅限Java |
| **LangChain** | ✅ | ❌ | ✅ | ~ | ✅ | Python,JavaScript(不支持Go) |
| **Google ADK** | ✅ | ✅ | ✅ | ✅ | ✅ | Python/Java/Go/JS — 以Gemini为中心 |
| **toolnexus** | ✅ | ✅ | ✅ | ✅ | ✅ | **JS + Python + Go + Java,供应商中立** |
toolnexus是一个**专注的库**,而不是平台:轻量级、供应商中立,在JS、Python和Go(包括一流的Go——LangChain和Spring AI无法达到)之间具有真正的对等性。 每种语言都建立在其最流行的MCP SDK之上——没有任何东西是从头开始重新实现的:
| 语言 | 目录 | MCP SDK |
|--------|-------------|--------------------------------------------------|
| JS/TS | [`js/`](js/) | `@modelcontextprotocol/sdk` (与opencode相同) |
| Python | [`python/`](python/) | `mcp` (modelcontextprotocol/python-sdk) |
| Go | [`golang/`](golang/) | `github.com/mark3labs/mcp-go` |
| Java | [`java/`](java/) | `io.modelcontextprotocol.sdk:mcp` (官方) |
语言无关行为在 **[SPEC.md](SPEC.md)** 中固定,因此所有三个保持字节兼容(特别是技能加载器输出)。
## 快速入门(JS)—— 一个完整的代理
```sh
cd js && npm install && npm run build
```
```ts
import { createToolkit, defineTool, httpTool, createClient } from "toolnexus"
const tk = await createToolkit({ mcpConfig: "./mcp.json", skillsDir: "./skills" })
// 添加您自己的工具 — 一个原生函数和一个REST端点
tk.register(
defineTool({ name: "add", description: "Add two numbers",
inputSchema: { type: "object", properties: { a: { type: "number" }, b: { type: "number" } }, required: ["a", "b"] },
run: ({ a, b }) => `${a + b}` }),
httpTool({ name: "get_post", description: "Fetch a post", method: "GET",
url: "https://jsonplaceholder.typicode.com/posts/{id}",
inputSchema: { type: "object", properties: { id: { type: "number" } }, required: ["id"] } }),
)
// 主机循环:普通URL + 样式 → 可用的代理
const agent = createClient({ baseUrl: "https://openrouter.ai/api/v1", style: "openai", model: "openai/gpt-4o-mini" })
const { text } = await agent.run("What is 21+21? Then fetch post 1's title.", { toolkit: tk })
console.log(text)
await tk.close()
```
更喜欢拥有自己的循环?使用模式适配器并自己调用 `tk.execute(name, args)`。
## Go CLI — 从终端创建即时代理
```sh
cd golang && go build -o toolnexus ./cmd/toolnexus
./toolnexus run --config ../examples/mcp.json --skills ../examples/skills \
--base-url https://openrouter.ai/api/v1 --style openai --model openai/gpt-4o-mini
# > 您:... (连续REPL代理循环)
./toolnexus tools --config ../examples/mcp.json --skills ../examples/skills # 列出已解析的工具
```
## 四个来源
1. **MCP服务器** — 一个 `mcp.json` (Claude-desktop超集;顶级 `mcpServers`/`servers`/`mcp`)。
本地stdio + 远程流式HTTP/SSE,带有用于身份验证的 `headers`。
2. **代理技能** — 一个 `<name>/SKILL.md` 文件夹(YAML前置信息);一个 `skill` 工具按需加载每个文件(渐进式披露)+ 系统提示目录。与Claude/opencode格式相同。
3. **原生工具** — 一个普通函数 → 一个工具(`defineTool` / `@tool` 装饰器;模式推断)。
4. **HTTP/REST工具** — 声明一个端点(`httpTool`);`${ENV}` 头部扩展;OpenAPI导入(尽力而为)。
所有四个都作为同一个统一的 `Tool` 出现在一个注册表中,适用于任何模型。
**À la carte.** 每个源都可以单独使用。您只想要一个MCP主机——解析 `mcp.json`,连接,获取工具,就像MCP-only库一样?只需使用 `loadMcp` / `load_mcp` / `LoadMcp` (无技能,无循环)。技能、原生/HTTP工具和主机循环都是可选的。
## 每种语言的文档
[`js/`](js/) · [`python/`](python/) · [`golang/`](golang/) · [`java/`](java/) — 快速入门和API。
嵌入到Go应用程序中?参见 [`golang/GUIDE.md`](golang/GUIDE.md)。
[`examples/`](examples/) 包含每个实现示例和测试中使用的共享 `mcp.json` + 示例技能。
## 状态
- ✅ MCP服务器(stdio + 流式HTTP / SSE)
- ✅ 代理技能(SKILL.md发现 + 渐进式披露 `skill` 工具)
- ✅ 原生/装饰工具 + HTTP/REST工具
- ✅ 统一的LLM客户端(OpenAI- 和 Anthropic-style端点)+ Go CLI
- ✅ OpenAI / Anthropic / Gemini模式适配器
- ✅ 通过 `examples/agent.*` 运行器与OpenRouter进行实时工具调用验证
- ⏳ OpenAPI批量导入 + MCP OAuth — 跟进(现在通过 `headers`传递 bearer token)
## 测试
每个端口都有一个独立的测试套件(无网络,无LLM — 本地HTTP服务器用于HTTP工具,共享 `examples/` 夹具用于技能),涵盖配置解析,`${ENV}` 头部扩展,字节精确的技能块,原生 + HTTP工具,提供商适配器和工具包路由。
```sh
cd js && npm test # node:test — 8 tests
cd python && .venv/bin/python -m pytest -q # pytest — 13 tests
cd golang && go test ./... # go test — 9 tests
cd java && ./gradlew test # JUnit 5 — 22 tests
```
端到端代理循环(MCP + 技能 + 原生 + HTTP通过主机循环)额外使用 `examples/agent.*` 运行器针对OpenRouter在每种语言上进行实时验证。
## 许可证
MIT