toolnexus 0.1.0 → 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.
Files changed (2) hide show
  1. package/README.md +81 -81
  2. package/package.json +4 -1
package/README.md CHANGED
@@ -1,8 +1,19 @@
1
- # toolnexus (JavaScript / TypeScript)
1
+ # toolnexus
2
2
 
3
- Dynamic MCP servers + agent skills as a uniform tool list for any LLM. Built on
4
- `@modelcontextprotocol/sdk` (the same MCP SDK opencode uses). See the root
5
- [SPEC.md](../SPEC.md) for the language-independent contract.
3
+ [![npm](https://img.shields.io/npm/v/toolnexus?logo=npm&label=npm)](https://www.npmjs.com/package/toolnexus)
4
+ [![license](https://img.shields.io/badge/license-MIT-green)](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
- ## Use
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
- const tk = await createToolkit({
19
- mcpConfig: "./mcp.json", // path or parsed object; key may be mcpServers/servers/mcp
20
- skillsDir: "./skills", // folder of <name>/SKILL.md (or an array of folders)
21
- // extraTools: [...] // your own custom tools, optional
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
- // 1. give the model the tool schema in its native format
25
- const tools = tk.toOpenAI() // or tk.toAnthropic() / tk.toGemini()
26
- const system = tk.skillsPrompt() // markdown catalog of skills for the system prompt
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
- // 2. when the model returns a tool call { name, arguments }:
29
- const res = await tk.execute(name, args) // -> { output, isError, metadata }
30
- // feed res.output back as the tool result, loop.
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
- console.log(tk.mcpStatus()) // { server: "connected" | "failed" | "disabled" }
33
- await tk.close()
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
- ## Run the examples
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
- ```sh
39
- npm install && npm run build
74
+ ## Bring your own loop
40
75
 
41
- # offline: connects to @modelcontextprotocol/server-everything via npx, lists tools, loads a skill
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
- # live: real OpenRouter tool-calling round trip (needs OPENROUTER_API_KEY)
45
- OPENROUTER_API_KEY=... node --experimental-strip-types examples/openrouter_test.ts
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
- | `tk.tools()` | all uniform `Tool`s (mcp + skill + extras) |
54
- | `tk.get(name)` | one tool by 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 at runtime |
108
+ | `tk.register(...tools)` | add native/http/custom tools |
60
109
  | `tk.close()` | disconnect MCP servers |
61
110
 
62
- You can also use the sources directly: `loadMcp(config)`, `loadSkills(dir)`.
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
- ## Examples
113
+ Full docs, the other four language ports, the shared behavior spec, and runnable examples:
114
+ **https://github.com/muthuishere/toolnexus**
113
115
 
114
- - `examples/basic.ts` — toolkit + adapters + skill load (offline).
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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toolnexus",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Dynamic MCP servers + agent skills as uniform tools for any LLM (opencode-style).",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -19,6 +19,9 @@
19
19
  },
20
20
  "keywords": ["mcp", "llm", "agent", "skills", "tools", "openai", "anthropic", "gemini"],
21
21
  "license": "MIT",
22
+ "repository": { "type": "git", "url": "git+https://github.com/muthuishere/toolnexus.git" },
23
+ "homepage": "https://github.com/muthuishere/toolnexus#readme",
24
+ "bugs": { "url": "https://github.com/muthuishere/toolnexus/issues" },
22
25
  "dependencies": {
23
26
  "@modelcontextprotocol/sdk": "^1.12.0"
24
27
  },