toolnexus 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +81 -81
- package/package.json +1 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Muthukumaran Navaneethakrishnan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
|
-
# toolnexus
|
|
1
|
+
# toolnexus
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/toolnexus)
|
|
4
|
+
[](https://github.com/muthuishere/toolnexus/blob/main/LICENSE)
|
|
5
|
+
|
|
6
|
+
**Build an agent in a few lines.** Point at an `mcp.json` and a `skills/` folder, call `run()`,
|
|
7
|
+
and you have a working agent — MCP servers, agent skills, your own functions, and HTTP endpoints
|
|
8
|
+
unified as one tool set, driving any LLM.
|
|
9
|
+
|
|
10
|
+
> **Right-sized.** Not a framework (no builders, advisors, runnables, config), not a toy that
|
|
11
|
+
> falls over the moment you need streaming or a retry. Everything a real agent needs — the loop,
|
|
12
|
+
> hooks, streaming, retries, memory — and nothing it doesn't.
|
|
13
|
+
|
|
14
|
+
The JS/TypeScript port of [toolnexus](https://github.com/muthuishere/toolnexus) — the same
|
|
15
|
+
library, byte-identical, also in **Python, Go, Java, and C#**. Built on
|
|
16
|
+
`@modelcontextprotocol/sdk` (the MCP SDK opencode uses).
|
|
6
17
|
|
|
7
18
|
## Install
|
|
8
19
|
|
|
@@ -10,107 +21,96 @@ Dynamic MCP servers + agent skills as a uniform tool list for any LLM. Built on
|
|
|
10
21
|
npm install toolnexus
|
|
11
22
|
```
|
|
12
23
|
|
|
13
|
-
##
|
|
24
|
+
## An agent in 3 steps
|
|
14
25
|
|
|
15
26
|
```ts
|
|
16
|
-
import { createToolkit } from "toolnexus"
|
|
27
|
+
import { createToolkit, createClient } from "toolnexus"
|
|
17
28
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
29
|
+
// 1. tools from an mcp.json + a skills/ folder
|
|
30
|
+
const tk = await createToolkit({ mcpConfig: "./mcp.json", skillsDir: "./skills" })
|
|
31
|
+
|
|
32
|
+
// 2. point at any OpenAI- or Anthropic-style endpoint
|
|
33
|
+
const agent = createClient({
|
|
34
|
+
baseUrl: "https://openrouter.ai/api/v1",
|
|
35
|
+
style: "openai", // or "anthropic"
|
|
36
|
+
model: "openai/gpt-4o-mini",
|
|
22
37
|
})
|
|
23
38
|
|
|
24
|
-
//
|
|
25
|
-
const
|
|
26
|
-
|
|
39
|
+
// 3. run — skills are injected into the system prompt, tools are called for you, looped to an answer
|
|
40
|
+
const { text } = await agent.run("Refund order 1234 for the customer.", { toolkit: tk })
|
|
41
|
+
console.log(text)
|
|
42
|
+
await tk.close()
|
|
43
|
+
```
|
|
27
44
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
45
|
+
`createClient` reads the key from `OPENROUTER_API_KEY` / `OPENAI_API_KEY` / `ANTHROPIC_API_KEY`
|
|
46
|
+
by default. The loop runs call → execute tools → feed back → repeat (up to `maxTurns`, default 10),
|
|
47
|
+
with hooks, streaming (`agent.stream(...)`), retries/backoff, and conversation memory available.
|
|
31
48
|
|
|
32
|
-
|
|
33
|
-
|
|
49
|
+
## Add your own tools
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
import { defineTool, httpTool } from "toolnexus"
|
|
53
|
+
|
|
54
|
+
tk.register(
|
|
55
|
+
// a plain function → a tool
|
|
56
|
+
defineTool({
|
|
57
|
+
name: "add", description: "Add two numbers",
|
|
58
|
+
inputSchema: { type: "object", properties: { a: { type: "number" }, b: { type: "number" } }, required: ["a", "b"] },
|
|
59
|
+
run: ({ a, b }) => `${(a as number) + (b as number)}`,
|
|
60
|
+
}),
|
|
61
|
+
// a REST endpoint → a tool
|
|
62
|
+
httpTool({
|
|
63
|
+
name: "create_ticket", description: "Create a ticket", method: "POST",
|
|
64
|
+
url: "https://api.example.com/tickets",
|
|
65
|
+
headers: { Authorization: "Bearer ${API_TOKEN}" }, // ${ENV} expands from process.env, never logged
|
|
66
|
+
inputSchema: { type: "object", properties: { title: { type: "string" } }, required: ["title"] },
|
|
67
|
+
}),
|
|
68
|
+
)
|
|
34
69
|
```
|
|
35
70
|
|
|
36
|
-
|
|
71
|
+
URL `{placeholders}` are filled from args; `query` args go to the querystring; the rest become
|
|
72
|
+
the JSON body. Non-2xx → `{ isError: true, output: "HTTP <status>: <body>" }`.
|
|
37
73
|
|
|
38
|
-
|
|
39
|
-
npm install && npm run build
|
|
74
|
+
## Bring your own loop
|
|
40
75
|
|
|
41
|
-
|
|
42
|
-
node --experimental-strip-types examples/basic.ts
|
|
76
|
+
Don't want the host loop? Use the schema adapters and execute calls yourself:
|
|
43
77
|
|
|
44
|
-
|
|
45
|
-
|
|
78
|
+
```ts
|
|
79
|
+
const tools = tk.toOpenAI() // or tk.toAnthropic() / tk.toGemini()
|
|
80
|
+
const system = tk.skillsPrompt() // markdown skills catalog for your system prompt
|
|
81
|
+
// when the model returns a tool call { name, arguments }:
|
|
82
|
+
const res = await tk.execute(name, args) // -> { output, isError, metadata }
|
|
46
83
|
```
|
|
47
84
|
|
|
85
|
+
## The four sources
|
|
86
|
+
|
|
87
|
+
| Source | How |
|
|
88
|
+
|--------|-----|
|
|
89
|
+
| **MCP servers** | an `mcp.json` (`mcpServers`/`servers`/`mcp`); local stdio + remote streamable-HTTP, `headers` for auth |
|
|
90
|
+
| **Agent skills** | a folder of `<name>/SKILL.md`; a `skill` tool loads each on demand + a system-prompt catalog |
|
|
91
|
+
| **Native tools** | `defineTool({...})` — a function becomes a tool |
|
|
92
|
+
| **HTTP / REST** | `httpTool({...})` — an endpoint becomes a tool, `${ENV}` headers |
|
|
93
|
+
|
|
94
|
+
All four appear as one uniform `Tool` in `tk.tools()`. Each is à la carte — use just `loadMcp(config)`
|
|
95
|
+
or `loadSkills(dir)` if that's all you need.
|
|
96
|
+
|
|
48
97
|
## API
|
|
49
98
|
|
|
50
99
|
| Member | Description |
|
|
51
100
|
|--------|-------------|
|
|
52
101
|
| `createToolkit(opts)` | async factory → `Toolkit` |
|
|
53
|
-
| `
|
|
54
|
-
| `tk.get(name)` |
|
|
102
|
+
| `createClient(opts)` | the unified host loop (`run` / `stream`) |
|
|
103
|
+
| `tk.tools()` / `tk.get(name)` | the uniform tools |
|
|
55
104
|
| `tk.execute(name, args, ctx?)` | run a tool → `ToolResult` |
|
|
56
105
|
| `tk.skillsPrompt()` | system-prompt skill catalog |
|
|
57
106
|
| `tk.mcpStatus()` | per-server connection status |
|
|
58
107
|
| `tk.toOpenAI()` / `toAnthropic()` / `toGemini()` | provider tool schemas |
|
|
59
|
-
| `tk.register(...tools)` | add native/http/custom tools
|
|
108
|
+
| `tk.register(...tools)` | add native/http/custom tools |
|
|
60
109
|
| `tk.close()` | disconnect MCP servers |
|
|
61
110
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
## Native tools (a function → a tool)
|
|
65
|
-
|
|
66
|
-
```ts
|
|
67
|
-
import { defineTool } from "toolnexus"
|
|
68
|
-
|
|
69
|
-
const add = defineTool({
|
|
70
|
-
name: "add", description: "Add two numbers",
|
|
71
|
-
inputSchema: { type: "object", properties: { a: { type: "number" }, b: { type: "number" } }, required: ["a", "b"] },
|
|
72
|
-
run: ({ a, b }) => `${(a as number) + (b as number)}`, // string or ToolResult
|
|
73
|
-
})
|
|
74
|
-
tk.register(add)
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
## HTTP / REST tools (an endpoint → a tool)
|
|
78
|
-
|
|
79
|
-
```ts
|
|
80
|
-
import { httpTool } from "toolnexus"
|
|
81
|
-
|
|
82
|
-
tk.register(httpTool({
|
|
83
|
-
name: "create_ticket", description: "Create a ticket", method: "POST",
|
|
84
|
-
url: "https://api.example.com/tickets",
|
|
85
|
-
headers: { Authorization: "Bearer ${API_TOKEN}" }, // ${ENV} expands from process.env, never logged
|
|
86
|
-
inputSchema: { type: "object", properties: { title: { type: "string" } }, required: ["title"] },
|
|
87
|
-
}))
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
URL `{placeholders}` are filled from args; `query` args go to the querystring; the rest
|
|
91
|
-
become the JSON body. Non-2xx → `{ isError: true, output: "HTTP <status>: <body>" }`.
|
|
92
|
-
|
|
93
|
-
## Unified client (the host loop)
|
|
94
|
-
|
|
95
|
-
```ts
|
|
96
|
-
import { createClient } from "toolnexus"
|
|
97
|
-
|
|
98
|
-
const agent = createClient({
|
|
99
|
-
baseUrl: "https://openrouter.ai/api/v1", // any OpenAI- or Anthropic-style endpoint
|
|
100
|
-
style: "openai", // or "anthropic"
|
|
101
|
-
model: "openai/gpt-4o-mini",
|
|
102
|
-
// apiKey defaults to OPENROUTER_API_KEY / OPENAI_API_KEY / ANTHROPIC_API_KEY
|
|
103
|
-
systemPrompt: "You are a helpful agent.",
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
const { text, toolCalls } = await agent.run("do the thing", { toolkit: tk })
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
It injects `tk.skillsPrompt()` into the system message and runs the full
|
|
110
|
-
call → execute tools → feed back → repeat loop (up to `maxTurns`, default 10).
|
|
111
|
+
## More
|
|
111
112
|
|
|
112
|
-
|
|
113
|
+
Full docs, the other four language ports, the shared behavior spec, and runnable examples:
|
|
114
|
+
**https://github.com/muthuishere/toolnexus**
|
|
113
115
|
|
|
114
|
-
|
|
115
|
-
- `examples/agent.ts` — native + http tools driven by the unified client (live with `OPENROUTER_API_KEY`).
|
|
116
|
-
- `examples/openrouter_test.ts` — minimal live tool-calling round trip.
|
|
116
|
+
MIT licensed.
|