You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+315-1Lines changed: 315 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -19,6 +19,7 @@ The Model Context Protocol (MCP) is an open standard that enables AI assistants
19
19
## Prerequisites
20
20
21
21
- Node.js 20.0.0 or higher
22
+
- Note: External tool plugins require Node.js >= 22 at runtime. On Node < 22, the server starts with built‑in tools only and logs a one‑time warning.
22
23
- NPM (or another Node package manager)
23
24
24
25
## Installation
@@ -83,6 +84,258 @@ Returned content format:
83
84
- For each entry in urlList, the server loads its content, prefixes it with a header like: `# Documentation from <resolved-path-or-url>` and joins multiple entries using a separator: `\n\n---\n\n`.
84
85
- If an entry fails to load, an inline error message is included for that entry.
85
86
87
+
### External tools (Plugins)
88
+
89
+
Add external tools at startup. External tools run out‑of‑process in a separate Tools Host (Node >= 22). Built‑in tools are always in‑process and register first.
90
+
91
+
- Node version gate
92
+
- Node < 22 → external tools are skipped with a single startup warning; built‑ins still register.
93
+
- Node >= 22 → external tools run out‑of‑process via the Tools Host.
94
+
95
+
- CLI
96
+
-`--tool <plugin>` Add one or more external tools. Repeat the flag or pass a comma‑separated list.
- Defaults: `strict` when any `--tool` is provided; otherwise `none`.
100
+
101
+
- Behavior
102
+
- External tools run in a single Tools Host child process.
103
+
- In `strict` isolation (default with externals): network and fs write are denied; fs reads are allow‑listed to your project and resolved plugin directories.
104
+
105
+
- Supported `--tool` inputs
106
+
- ESM packages (installed in node_modules)
107
+
- Local ESM files (paths are normalized to `file://` URLs internally)
108
+
109
+
- Not supported as `--tool` inputs
110
+
- Raw TypeScript sources (`.ts`) — the Tools Host does not install a TS loader
111
+
- Remote `http(s):` or `data:` URLs — these will fail to load and appear in startup warnings/errors
112
+
113
+
- Troubleshooting
114
+
- If external tools don't appear, verify you're running on Node >= 22 (see Node version gate above) and check startup `load:ack` warnings/errors.
115
+
- Startup `load:ack` warnings/errors from plugins are logged when stderr/protocol logging is enabled.
116
+
- If `tools/list` fails or `tools/call` rejects due to argument validation (e.g., messages about `safeParseAsync is not a function`), ensure your `inputSchema` is either a valid JSON Schema object or a Zod schema. Plain JSON Schema objects are automatically converted, but malformed schemas may cause issues. See the [Input Schema Format](#input-schema-format) section for details.
117
+
118
+
### Embedding the server (Programmatic API)
119
+
120
+
You can embed the MCP server inside another Node/TypeScript application and register tools programmatically.
121
+
122
+
Tools as plugins can be
123
+
- Inline creators, or an array/list of inline creators, provided through the convenience wrapper `createMcpTool`, i.e. `createMcpTool({ name: 'echoAMessage', ... })` or `createMcpTool([{ name: 'echoAMessage', ... }])`.
124
+
- Local file paths and local file URLs (Node >= 22 required), i.e. `a string representing a local file path or file URL starting with file://`
125
+
- Local NPM package names (Node >= 22 required), i.e. `a string representing a local NPM package name like @loremIpsum/my-plugin`
126
+
127
+
> Note: Consuming remote/external files, such as YML, and NPM packages is targeted for the near future.
128
+
129
+
Supported export shapes for external modules (Node >= 22 only):
130
+
131
+
- Default export: function returning a realized tool tuple. It is called once with ToolOptions and cached. Example shape: `export default function (opts) { return ['name', { description, inputSchema }, handler] }`
132
+
- Default export: function returning an array of creator functions. Example shape: `export default function (opts) { return [() => [...], () => [...]] }`
133
+
- Default export: array of creator functions. Example shape: `export default [ () => ['name', {...}, handler] ]`
134
+
- Fallback: a named export that is an array of creator functions (only used if default export is not present).
135
+
136
+
Not supported (Phase A+B):
137
+
138
+
- Directly exporting a bare tuple as the module default (wrap it in a function instead)
139
+
- Plugin objects like `{ createCreators, createTools }`
140
+
141
+
Performance and determinism note:
142
+
143
+
- If your default export is a function that returns a tuple, we invoke it once during load with a minimal ToolOptions object and cache the result. Use a creators‑factory (a function returning an array of creators) if you need per‑realization variability by options.
144
+
145
+
External module examples (Node >= 22):
146
+
147
+
Function returning a tuple (called once with options):
// In programmatic mode, unhandled errors throw unless allowProcessExit=true
244
+
console.error(err);
245
+
process.exit(1);
246
+
});
247
+
```
248
+
249
+
#### Development notes
250
+
- Built‑in tools are always registered first.
251
+
- Consuming the MCP server comes with a not-so-obvious limitation, avoiding `console.log` and `console.info`.
252
+
- In `stdio` server run mode `console.log` and `console.info` can create unnecessary noise between server and client, and potentially the Model. Instead, use `console.error`, `console.warn`, or `process.stderr.write`.
253
+
- In `http` server run mode `console.log` and `console.info` can be used, but it's still recommended you get in the habit of avoiding their use.
254
+
255
+
### Authoring external tools with `createMcpTool`
256
+
257
+
Export an ESM module using `createMcpTool`. The server adapts single or multiple tool definitions automatically.
- External tools must be ESM modules (packages or ESM files). The Tools Host imports your module via `import()`.
305
+
- The `handler` receives `args` per your `inputSchema`. A reserved `options?` parameter may be added in a future release; it is not currently passed.
306
+
307
+
### Input Schema Format
308
+
309
+
The `inputSchema` property accepts either **plain JSON Schema objects** or **Zod schemas**. Both formats are automatically converted to the format required by the MCP SDK.
310
+
311
+
**JSON Schema (recommended for simplicity):**
312
+
```
313
+
inputSchema: {
314
+
type: 'object',
315
+
properties: {
316
+
name: { type: 'string' },
317
+
age: { type: 'number' }
318
+
},
319
+
required: ['name']
320
+
}
321
+
```
322
+
323
+
**Zod Schema (for advanced validation):**
324
+
```
325
+
import { z } from 'zod';
326
+
327
+
inputSchema: {
328
+
name: z.string(),
329
+
age: z.number().optional()
330
+
}
331
+
```
332
+
333
+
**Important:** The MCP SDK expects Zod-compatible schemas internally. Plain JSON Schema objects are automatically converted to equivalent Zod schemas when tools are registered. This conversion handles common cases like:
- DOC_MCP_FETCH_TIMEOUT_MS: Milliseconds to wait before aborting an HTTP fetch (default: 15000)
336
-
- DOC_MCP_CLEAR_COOLDOWN_MS: Default cooldown value used in internal cache configuration. The current public API does not expose a `clearCache` tool.
589
+
590
+
## External tools (plugins)
591
+
592
+
You can load external MCP tool modules at runtime using a single CLI flag or via programmatic options. Modules must be ESM-importable (absolute/relative path or package).
593
+
594
+
CLI examples (single `--tool` flag):
595
+
596
+
```bash
597
+
# Single module
598
+
npm run start:dev -- --tool ./dist/my-tool.js
599
+
600
+
# Multiple modules (repeatable)
601
+
npm run start:dev -- --tool ./dist/t1.js --tool ./dist/t2.js
602
+
603
+
# Multiple modules (comma-separated)
604
+
npm run start:dev -- --tool ./dist/t1.js,./dist/t2.js
0 commit comments