dynmcp 0.0.1
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/README.md +34 -0
- package/dist/index.cjs +396 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +374 -0
- package/dist/index.js.map +1 -0
- package/package.json +84 -0
package/README.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# dynmcp
|
|
2
|
+
|
|
3
|
+
A proxy MCP that exposes meta-tools so agents can discover and call upstream MCP tools on demand, without loading every tool schema into the context window.
|
|
4
|
+
|
|
5
|
+
## The Problem
|
|
6
|
+
|
|
7
|
+
Large MCPs routinely expose tens to hundreds of tools. When several are active at once, every tool schema is injected into the context window on every request regardless of relevance — degrading decision quality and consuming tokens unnecessarily. For any given task, only a small subset of tools is actually relevant.
|
|
8
|
+
|
|
9
|
+
## How It Works
|
|
10
|
+
|
|
11
|
+
`dynmcp` sits in front of an upstream MCP and exposes exactly two tools:
|
|
12
|
+
|
|
13
|
+
- **`discover_tool`** — its description contains a compact catalog of every upstream tool (name and one-line summary). Call it with a tool name to get that tool's full schema: description, parameters, types, and required fields.
|
|
14
|
+
- **`use_tool`** — executes a tool by name, proxying the call to the upstream MCP and returning its output unchanged.
|
|
15
|
+
|
|
16
|
+
The agent workflow: scan the catalog in `discover_tool`'s description to find relevant tools, call `discover_tool` to load the full schema of the one it needs, then call `use_tool` to execute it. Full schemas of tools the agent never needs never enter the context window.
|
|
17
|
+
|
|
18
|
+
`dynmcp` runs locally, communicating with both the agent host and the upstream MCP over stdio.
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
Requires Node.js >= 20.
|
|
23
|
+
|
|
24
|
+
Prefix any MCP invocation with `dynmcp --`:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# Before
|
|
28
|
+
npx -y chrome-devtools-mcp@latest
|
|
29
|
+
|
|
30
|
+
# With dynmcp
|
|
31
|
+
npx dynmcp@latest -- npx -y chrome-devtools-mcp@latest
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Everything after `--` is the command used to launch the upstream MCP.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (let key of __getOwnPropNames(from))
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
12
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
13
|
+
}
|
|
14
|
+
return to;
|
|
15
|
+
};
|
|
16
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
17
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
18
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
19
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
20
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
|
+
mod
|
|
23
|
+
));
|
|
24
|
+
|
|
25
|
+
// src/cli.ts
|
|
26
|
+
var import_node_process4 = __toESM(require("process"), 1);
|
|
27
|
+
var import_commander = require("commander");
|
|
28
|
+
|
|
29
|
+
// package.json
|
|
30
|
+
var package_default = {
|
|
31
|
+
name: "dynmcp",
|
|
32
|
+
version: "0.0.1",
|
|
33
|
+
description: "Dynamic MCP context management tool for AI MCP-enabled agents and clients.",
|
|
34
|
+
author: "Brandon Burrus <brandon@burrus.io>",
|
|
35
|
+
license: "MIT",
|
|
36
|
+
type: "module",
|
|
37
|
+
homepage: "https://github.com/brandonburrus/dynamic-discovery-mcp#readme",
|
|
38
|
+
keywords: [
|
|
39
|
+
"mcp",
|
|
40
|
+
"model-context-protocol",
|
|
41
|
+
"ai",
|
|
42
|
+
"agent",
|
|
43
|
+
"proxy",
|
|
44
|
+
"dynamic",
|
|
45
|
+
"discovery",
|
|
46
|
+
"tools",
|
|
47
|
+
"llm",
|
|
48
|
+
"cli"
|
|
49
|
+
],
|
|
50
|
+
engines: {
|
|
51
|
+
node: ">=20.0.0"
|
|
52
|
+
},
|
|
53
|
+
publishConfig: {
|
|
54
|
+
access: "public"
|
|
55
|
+
},
|
|
56
|
+
repository: {
|
|
57
|
+
type: "git",
|
|
58
|
+
url: "git+https://github.com/brandonburrus/dynamic-discovery-mcp.git"
|
|
59
|
+
},
|
|
60
|
+
bugs: {
|
|
61
|
+
url: "https://github.com/brandonburrus/dynamic-discovery-mcp/issues"
|
|
62
|
+
},
|
|
63
|
+
main: "./dist/index.cjs",
|
|
64
|
+
module: "./dist/index.js",
|
|
65
|
+
types: "./dist/index.d.ts",
|
|
66
|
+
bin: {
|
|
67
|
+
dynmcp: "./dist/index.js"
|
|
68
|
+
},
|
|
69
|
+
exports: {
|
|
70
|
+
".": {
|
|
71
|
+
types: "./dist/index.d.ts",
|
|
72
|
+
import: "./dist/index.js",
|
|
73
|
+
require: "./dist/index.cjs"
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
files: [
|
|
77
|
+
"dist"
|
|
78
|
+
],
|
|
79
|
+
scripts: {
|
|
80
|
+
build: "tsup",
|
|
81
|
+
dev: "tsx src/index.ts",
|
|
82
|
+
typecheck: "tsc --noEmit",
|
|
83
|
+
lint: "biome lint .",
|
|
84
|
+
format: "biome format --write .",
|
|
85
|
+
check: "biome check --write .",
|
|
86
|
+
test: "vitest run",
|
|
87
|
+
"test:watch": "vitest",
|
|
88
|
+
"test:coverage": "vitest run --coverage",
|
|
89
|
+
prepare: "husky"
|
|
90
|
+
},
|
|
91
|
+
dependencies: {
|
|
92
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
93
|
+
boxen: "^8.0.1",
|
|
94
|
+
chalk: "^5.6.2",
|
|
95
|
+
commander: "^14.0.3",
|
|
96
|
+
enquirer: "^2.4.1",
|
|
97
|
+
fastmcp: "^4.0.1",
|
|
98
|
+
figlet: "^1.11.0",
|
|
99
|
+
figures: "^6.1.0",
|
|
100
|
+
zod: "^4.4.3"
|
|
101
|
+
},
|
|
102
|
+
devDependencies: {
|
|
103
|
+
"@biomejs/biome": "^2.4.15",
|
|
104
|
+
"@commitlint/cli": "^21.0.1",
|
|
105
|
+
"@commitlint/config-conventional": "^21.0.1",
|
|
106
|
+
"@types/node": "^25.9.0",
|
|
107
|
+
husky: "^9.1.7",
|
|
108
|
+
tsup: "^8.5.1",
|
|
109
|
+
tsx: "^4.22.2",
|
|
110
|
+
typescript: "^6.0.3",
|
|
111
|
+
vitest: "^4.1.6"
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// src/cli.ts
|
|
116
|
+
var import_figlet = __toESM(require("figlet"), 1);
|
|
117
|
+
var import_chalk = __toESM(require("chalk"), 1);
|
|
118
|
+
|
|
119
|
+
// src/proxy/index.ts
|
|
120
|
+
var import_node_process3 = __toESM(require("process"), 1);
|
|
121
|
+
|
|
122
|
+
// src/proxy/tool-catalog.ts
|
|
123
|
+
var DISCOVER_TOOL_PREAMBLE = `Use this tool to look up the full schema of a tool before calling it with use_tool.
|
|
124
|
+
Call discover_tool with a tool name from the list below to get its complete description,
|
|
125
|
+
input parameters, and output schema. Always discover a tool before using it.`;
|
|
126
|
+
var ToolCatalog = class {
|
|
127
|
+
tools;
|
|
128
|
+
discoverToolDescription;
|
|
129
|
+
constructor(upstreamTools) {
|
|
130
|
+
const toolMap = /* @__PURE__ */ new Map();
|
|
131
|
+
for (const tool of upstreamTools) {
|
|
132
|
+
toolMap.set(tool.name, tool);
|
|
133
|
+
}
|
|
134
|
+
this.tools = toolMap;
|
|
135
|
+
this.discoverToolDescription = buildDiscoverToolDescription(upstreamTools);
|
|
136
|
+
}
|
|
137
|
+
getToolDetails(toolName) {
|
|
138
|
+
const tool = this.tools.get(toolName);
|
|
139
|
+
if (tool === void 0) {
|
|
140
|
+
const sortedNames = [...this.tools.keys()].sort().join(", ");
|
|
141
|
+
return `Unknown tool: "${toolName}". Available tools: ${sortedNames}`;
|
|
142
|
+
}
|
|
143
|
+
return buildToolDetailsString(tool);
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
function buildDiscoverToolDescription(tools) {
|
|
147
|
+
const sortedTools = [...tools].sort((a, b) => a.name.localeCompare(b.name));
|
|
148
|
+
const toolLines = sortedTools.map((tool) => `- ${tool.name}: ${tool.description}`).join("\n");
|
|
149
|
+
return `${DISCOVER_TOOL_PREAMBLE}
|
|
150
|
+
|
|
151
|
+
<tools>
|
|
152
|
+
${toolLines}
|
|
153
|
+
</tools>`;
|
|
154
|
+
}
|
|
155
|
+
function buildToolDetailsString(tool) {
|
|
156
|
+
const lines = [
|
|
157
|
+
`Tool: ${tool.name}`,
|
|
158
|
+
`Description: ${tool.description}`,
|
|
159
|
+
"",
|
|
160
|
+
"Input Schema:",
|
|
161
|
+
JSON.stringify(tool.inputSchema, null, 2)
|
|
162
|
+
];
|
|
163
|
+
if (tool.outputSchema !== void 0) {
|
|
164
|
+
lines.push("", "Output Schema:", JSON.stringify(tool.outputSchema, null, 2));
|
|
165
|
+
}
|
|
166
|
+
const annotationLines = buildAnnotationLines(tool);
|
|
167
|
+
if (annotationLines.length > 0) {
|
|
168
|
+
lines.push("", "Annotations:", ...annotationLines);
|
|
169
|
+
}
|
|
170
|
+
return lines.join("\n");
|
|
171
|
+
}
|
|
172
|
+
function buildAnnotationLines(tool) {
|
|
173
|
+
if (tool.annotations === void 0) {
|
|
174
|
+
return [];
|
|
175
|
+
}
|
|
176
|
+
const { annotations } = tool;
|
|
177
|
+
const lines = [];
|
|
178
|
+
if (annotations.title !== void 0) {
|
|
179
|
+
lines.push(`- title: ${annotations.title}`);
|
|
180
|
+
}
|
|
181
|
+
if (annotations.readOnlyHint !== void 0) {
|
|
182
|
+
lines.push(`- readOnlyHint: ${annotations.readOnlyHint}`);
|
|
183
|
+
}
|
|
184
|
+
if (annotations.destructiveHint !== void 0) {
|
|
185
|
+
lines.push(`- destructiveHint: ${annotations.destructiveHint}`);
|
|
186
|
+
}
|
|
187
|
+
if (annotations.idempotentHint !== void 0) {
|
|
188
|
+
lines.push(`- idempotentHint: ${annotations.idempotentHint}`);
|
|
189
|
+
}
|
|
190
|
+
if (annotations.openWorldHint !== void 0) {
|
|
191
|
+
lines.push(`- openWorldHint: ${annotations.openWorldHint}`);
|
|
192
|
+
}
|
|
193
|
+
return lines;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// src/proxy/server.ts
|
|
197
|
+
var import_node_process = __toESM(require("process"), 1);
|
|
198
|
+
var import_fastmcp = require("fastmcp");
|
|
199
|
+
var import_zod = require("zod");
|
|
200
|
+
var ProxyServer = class {
|
|
201
|
+
catalog;
|
|
202
|
+
upstreamClient;
|
|
203
|
+
constructor({ catalog, upstreamClient }) {
|
|
204
|
+
this.catalog = catalog;
|
|
205
|
+
this.upstreamClient = upstreamClient;
|
|
206
|
+
}
|
|
207
|
+
async start() {
|
|
208
|
+
const server = new import_fastmcp.FastMCP({
|
|
209
|
+
name: "dynamic-discovery-mcp",
|
|
210
|
+
version: package_default.version
|
|
211
|
+
});
|
|
212
|
+
server.addTool({
|
|
213
|
+
name: "discover_tool",
|
|
214
|
+
description: this.catalog.discoverToolDescription,
|
|
215
|
+
parameters: import_zod.z.object({ tool_name: import_zod.z.string() }),
|
|
216
|
+
execute: async ({ tool_name }) => {
|
|
217
|
+
return this.catalog.getToolDetails(tool_name);
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
server.addTool({
|
|
221
|
+
name: "use_tool",
|
|
222
|
+
description: "Use a tool that was previously discovered with the discover_tool tool.",
|
|
223
|
+
parameters: import_zod.z.object({
|
|
224
|
+
tool_name: import_zod.z.string(),
|
|
225
|
+
tool_input: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).default({})
|
|
226
|
+
}),
|
|
227
|
+
execute: async ({ tool_name, tool_input }) => {
|
|
228
|
+
if (!this.catalog.tools.has(tool_name)) {
|
|
229
|
+
return this.catalog.getToolDetails(tool_name);
|
|
230
|
+
}
|
|
231
|
+
const result = await this.upstreamClient.callTool(tool_name, tool_input);
|
|
232
|
+
return result;
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
import_node_process.default.stderr.write("Starting dynamic-discovery-mcp server over stdio\n");
|
|
236
|
+
await server.start({ transportType: "stdio" });
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
// src/proxy/upstream-client.ts
|
|
241
|
+
var import_node_process2 = __toESM(require("process"), 1);
|
|
242
|
+
var import_client = require("@modelcontextprotocol/sdk/client/index.js");
|
|
243
|
+
var import_stdio = require("@modelcontextprotocol/sdk/client/stdio.js");
|
|
244
|
+
var UpstreamClient = class {
|
|
245
|
+
command;
|
|
246
|
+
args;
|
|
247
|
+
onTransportError;
|
|
248
|
+
client = null;
|
|
249
|
+
transport = null;
|
|
250
|
+
constructor({ command, args, onTransportError }) {
|
|
251
|
+
this.command = command;
|
|
252
|
+
this.args = args;
|
|
253
|
+
this.onTransportError = onTransportError ?? ((error) => {
|
|
254
|
+
import_node_process2.default.stderr.write(`Upstream MCP transport error: ${error.message}
|
|
255
|
+
`);
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
async connect() {
|
|
259
|
+
this.transport = new import_stdio.StdioClientTransport({
|
|
260
|
+
command: this.command,
|
|
261
|
+
args: this.args
|
|
262
|
+
});
|
|
263
|
+
this.transport.onerror = this.onTransportError;
|
|
264
|
+
this.client = new import_client.Client({ name: "dynamic-discovery-mcp", version: "1.0.0" });
|
|
265
|
+
await this.client.connect(this.transport);
|
|
266
|
+
}
|
|
267
|
+
async listTools() {
|
|
268
|
+
if (this.client === null) {
|
|
269
|
+
throw new Error("Client is not connected. Call connect() first.");
|
|
270
|
+
}
|
|
271
|
+
const result = await this.client.listTools();
|
|
272
|
+
return result.tools.map((tool) => {
|
|
273
|
+
const upstreamTool = {
|
|
274
|
+
name: tool.name,
|
|
275
|
+
description: tool.description ?? "",
|
|
276
|
+
inputSchema: tool.inputSchema
|
|
277
|
+
};
|
|
278
|
+
if (tool.outputSchema !== void 0) {
|
|
279
|
+
upstreamTool.outputSchema = tool.outputSchema;
|
|
280
|
+
}
|
|
281
|
+
if (tool.annotations !== void 0) {
|
|
282
|
+
upstreamTool.annotations = {
|
|
283
|
+
title: tool.annotations.title,
|
|
284
|
+
readOnlyHint: tool.annotations.readOnlyHint,
|
|
285
|
+
destructiveHint: tool.annotations.destructiveHint,
|
|
286
|
+
idempotentHint: tool.annotations.idempotentHint,
|
|
287
|
+
openWorldHint: tool.annotations.openWorldHint
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
return upstreamTool;
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
async callTool(name, input) {
|
|
294
|
+
if (this.client === null) {
|
|
295
|
+
throw new Error("Client is not connected. Call connect() first.");
|
|
296
|
+
}
|
|
297
|
+
return this.client.callTool({
|
|
298
|
+
name,
|
|
299
|
+
arguments: input
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
async disconnect() {
|
|
303
|
+
if (this.client === null) {
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
await this.client.close();
|
|
307
|
+
this.client = null;
|
|
308
|
+
this.transport = null;
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
// src/proxy/index.ts
|
|
313
|
+
async function startProxy(command, args) {
|
|
314
|
+
let isShuttingDown = false;
|
|
315
|
+
const shutdown = (exitCode) => {
|
|
316
|
+
if (isShuttingDown) return;
|
|
317
|
+
isShuttingDown = true;
|
|
318
|
+
upstreamClient.disconnect().catch((error) => {
|
|
319
|
+
import_node_process3.default.stderr.write(
|
|
320
|
+
`dynmcp: error during disconnect: ${error instanceof Error ? error.message : String(error)}
|
|
321
|
+
`
|
|
322
|
+
);
|
|
323
|
+
}).finally(() => import_node_process3.default.exit(exitCode));
|
|
324
|
+
};
|
|
325
|
+
const upstreamClient = new UpstreamClient({
|
|
326
|
+
command,
|
|
327
|
+
args,
|
|
328
|
+
onTransportError: (error) => {
|
|
329
|
+
import_node_process3.default.stderr.write(`Upstream MCP transport error: ${error.message}
|
|
330
|
+
`);
|
|
331
|
+
shutdown(1);
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
try {
|
|
335
|
+
await upstreamClient.connect();
|
|
336
|
+
} catch (error) {
|
|
337
|
+
import_node_process3.default.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
|
|
338
|
+
`);
|
|
339
|
+
import_node_process3.default.exit(1);
|
|
340
|
+
}
|
|
341
|
+
let tools;
|
|
342
|
+
try {
|
|
343
|
+
tools = await upstreamClient.listTools();
|
|
344
|
+
} catch (error) {
|
|
345
|
+
import_node_process3.default.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
|
|
346
|
+
`);
|
|
347
|
+
import_node_process3.default.exit(1);
|
|
348
|
+
}
|
|
349
|
+
const catalog = new ToolCatalog(tools);
|
|
350
|
+
const proxyServer = new ProxyServer({ catalog, upstreamClient });
|
|
351
|
+
import_node_process3.default.on("SIGINT", () => shutdown(0));
|
|
352
|
+
import_node_process3.default.on("SIGTERM", () => shutdown(0));
|
|
353
|
+
import_node_process3.default.stdin.on("end", () => shutdown(0));
|
|
354
|
+
import_node_process3.default.stdin.on("close", () => shutdown(0));
|
|
355
|
+
await proxyServer.start();
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// src/cli.ts
|
|
359
|
+
var cliBanner = import_chalk.default.bold.magentaBright(
|
|
360
|
+
import_figlet.default.textSync("DYNAMIC MCP", {
|
|
361
|
+
font: "Sub-Zero",
|
|
362
|
+
horizontalLayout: "fitted",
|
|
363
|
+
verticalLayout: "fitted"
|
|
364
|
+
})
|
|
365
|
+
);
|
|
366
|
+
var cli = new import_commander.Command(package_default.name).description(package_default.description).version(package_default.version).addHelpText("beforeAll", cliBanner).addHelpText("after", "\nExample:\n dynmcp -- npx -y chrome-devtools-mcp@latest\n").allowExcessArguments(true).passThroughOptions(true).action(async () => {
|
|
367
|
+
const separatorIndex = import_node_process4.default.argv.indexOf("--");
|
|
368
|
+
if (separatorIndex === -1) {
|
|
369
|
+
import_node_process4.default.stderr.write(
|
|
370
|
+
"dynmcp: no upstream command provided.\nUsage: dynmcp -- <command> [args...]\nExample: dynmcp -- npx -y chrome-devtools-mcp@latest\n"
|
|
371
|
+
);
|
|
372
|
+
import_node_process4.default.exit(1);
|
|
373
|
+
}
|
|
374
|
+
const [command, ...args] = import_node_process4.default.argv.slice(separatorIndex + 1);
|
|
375
|
+
if (command === void 0) {
|
|
376
|
+
import_node_process4.default.stderr.write(
|
|
377
|
+
"dynmcp: no upstream command provided.\nUsage: dynmcp -- <command> [args...]\nExample: dynmcp -- npx -y chrome-devtools-mcp@latest\n"
|
|
378
|
+
);
|
|
379
|
+
import_node_process4.default.exit(1);
|
|
380
|
+
}
|
|
381
|
+
try {
|
|
382
|
+
await startProxy(command, args);
|
|
383
|
+
} catch (error) {
|
|
384
|
+
import_node_process4.default.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
|
|
385
|
+
`);
|
|
386
|
+
import_node_process4.default.exit(1);
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
// src/index.ts
|
|
391
|
+
var import_node_process5 = __toESM(require("process"), 1);
|
|
392
|
+
async function main() {
|
|
393
|
+
cli.parse(import_node_process5.default.argv);
|
|
394
|
+
}
|
|
395
|
+
main();
|
|
396
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../package.json","../src/proxy/index.ts","../src/proxy/tool-catalog.ts","../src/proxy/server.ts","../src/proxy/upstream-client.ts","../src/index.ts"],"sourcesContent":["import process from \"node:process\";\nimport { Command } from \"commander\";\nimport packageJson from \"../package.json\" with { type: \"json\" };\nimport figlet from \"figlet\";\nimport chalk from \"chalk\";\nimport { startProxy } from \"./proxy/index.js\";\n\nconst cliBanner = chalk.bold.magentaBright(\n figlet.textSync(\"DYNAMIC MCP\", {\n font: \"Sub-Zero\",\n horizontalLayout: \"fitted\",\n verticalLayout: \"fitted\",\n }),\n);\n\nexport const cli = new Command(packageJson.name)\n .description(packageJson.description)\n .version(packageJson.version)\n .addHelpText(\"beforeAll\", cliBanner)\n .addHelpText(\"after\", \"\\nExample:\\n dynmcp -- npx -y chrome-devtools-mcp@latest\\n\")\n .allowExcessArguments(true)\n .passThroughOptions(true)\n .action(async () => {\n const separatorIndex = process.argv.indexOf(\"--\");\n\n if (separatorIndex === -1) {\n process.stderr.write(\n \"dynmcp: no upstream command provided.\\n\" +\n \"Usage: dynmcp -- <command> [args...]\\n\" +\n \"Example: dynmcp -- npx -y chrome-devtools-mcp@latest\\n\",\n );\n process.exit(1);\n }\n\n const [command, ...args] = process.argv.slice(separatorIndex + 1);\n\n if (command === undefined) {\n process.stderr.write(\n \"dynmcp: no upstream command provided.\\n\" +\n \"Usage: dynmcp -- <command> [args...]\\n\" +\n \"Example: dynmcp -- npx -y chrome-devtools-mcp@latest\\n\",\n );\n process.exit(1);\n }\n\n try {\n await startProxy(command, args);\n } catch (error) {\n process.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}\\n`);\n process.exit(1);\n }\n });\n","{\n \"name\": \"dynmcp\",\n \"version\": \"0.0.1\",\n \"description\": \"Dynamic MCP context management tool for AI MCP-enabled agents and clients.\",\n \"author\": \"Brandon Burrus <brandon@burrus.io>\",\n \"license\": \"MIT\",\n \"type\": \"module\",\n \"homepage\": \"https://github.com/brandonburrus/dynamic-discovery-mcp#readme\",\n \"keywords\": [\n \"mcp\",\n \"model-context-protocol\",\n \"ai\",\n \"agent\",\n \"proxy\",\n \"dynamic\",\n \"discovery\",\n \"tools\",\n \"llm\",\n \"cli\"\n ],\n \"engines\": {\n \"node\": \">=20.0.0\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/brandonburrus/dynamic-discovery-mcp.git\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/brandonburrus/dynamic-discovery-mcp/issues\"\n },\n \"main\": \"./dist/index.cjs\",\n \"module\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"bin\": {\n \"dynmcp\": \"./dist/index.js\"\n },\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n }\n },\n \"files\": [\n \"dist\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsx src/index.ts\",\n \"typecheck\": \"tsc --noEmit\",\n \"lint\": \"biome lint .\",\n \"format\": \"biome format --write .\",\n \"check\": \"biome check --write .\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"test:coverage\": \"vitest run --coverage\",\n \"prepare\": \"husky\"\n },\n \"dependencies\": {\n \"@modelcontextprotocol/sdk\": \"^1.29.0\",\n \"boxen\": \"^8.0.1\",\n \"chalk\": \"^5.6.2\",\n \"commander\": \"^14.0.3\",\n \"enquirer\": \"^2.4.1\",\n \"fastmcp\": \"^4.0.1\",\n \"figlet\": \"^1.11.0\",\n \"figures\": \"^6.1.0\",\n \"zod\": \"^4.4.3\"\n },\n \"devDependencies\": {\n \"@biomejs/biome\": \"^2.4.15\",\n \"@commitlint/cli\": \"^21.0.1\",\n \"@commitlint/config-conventional\": \"^21.0.1\",\n \"@types/node\": \"^25.9.0\",\n \"husky\": \"^9.1.7\",\n \"tsup\": \"^8.5.1\",\n \"tsx\": \"^4.22.2\",\n \"typescript\": \"^6.0.3\",\n \"vitest\": \"^4.1.6\"\n }\n}\n","import process from \"node:process\";\nimport { ToolCatalog } from \"./tool-catalog.js\";\nimport { ProxyServer } from \"./server.js\";\nimport { UpstreamClient } from \"./upstream-client.js\";\n\nexport async function startProxy(command: string, args: string[]): Promise<void> {\n let isShuttingDown = false;\n\n const shutdown = (exitCode: number): void => {\n if (isShuttingDown) return;\n isShuttingDown = true;\n\n upstreamClient\n .disconnect()\n .catch((error: unknown) => {\n process.stderr.write(\n `dynmcp: error during disconnect: ${error instanceof Error ? error.message : String(error)}\\n`,\n );\n })\n .finally(() => process.exit(exitCode));\n };\n\n const upstreamClient = new UpstreamClient({\n command,\n args,\n onTransportError: (error: Error) => {\n process.stderr.write(`Upstream MCP transport error: ${error.message}\\n`);\n shutdown(1);\n },\n });\n\n try {\n await upstreamClient.connect();\n } catch (error) {\n process.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}\\n`);\n process.exit(1);\n }\n\n let tools: Awaited<ReturnType<UpstreamClient[\"listTools\"]>>;\n try {\n tools = await upstreamClient.listTools();\n } catch (error) {\n process.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}\\n`);\n process.exit(1);\n }\n\n const catalog = new ToolCatalog(tools);\n const proxyServer = new ProxyServer({ catalog, upstreamClient });\n\n process.on(\"SIGINT\", () => shutdown(0));\n process.on(\"SIGTERM\", () => shutdown(0));\n process.stdin.on(\"end\", () => shutdown(0));\n process.stdin.on(\"close\", () => shutdown(0));\n\n await proxyServer.start();\n}\n","import type { UpstreamTool } from \"./upstream-client.js\";\n\nconst DISCOVER_TOOL_PREAMBLE = `Use this tool to look up the full schema of a tool before calling it with use_tool.\nCall discover_tool with a tool name from the list below to get its complete description,\ninput parameters, and output schema. Always discover a tool before using it.`;\n\nexport class ToolCatalog {\n readonly tools: ReadonlyMap<string, UpstreamTool>;\n readonly discoverToolDescription: string;\n\n constructor(upstreamTools: UpstreamTool[]) {\n const toolMap = new Map<string, UpstreamTool>();\n for (const tool of upstreamTools) {\n toolMap.set(tool.name, tool);\n }\n this.tools = toolMap;\n this.discoverToolDescription = buildDiscoverToolDescription(upstreamTools);\n }\n\n getToolDetails(toolName: string): string {\n const tool = this.tools.get(toolName);\n\n if (tool === undefined) {\n const sortedNames = [...this.tools.keys()].sort().join(\", \");\n return `Unknown tool: \"${toolName}\". Available tools: ${sortedNames}`;\n }\n\n return buildToolDetailsString(tool);\n }\n}\n\nfunction buildDiscoverToolDescription(tools: UpstreamTool[]): string {\n const sortedTools = [...tools].sort((a, b) => a.name.localeCompare(b.name));\n const toolLines = sortedTools.map(tool => `- ${tool.name}: ${tool.description}`).join(\"\\n\");\n\n return `${DISCOVER_TOOL_PREAMBLE}\\n\\n<tools>\\n${toolLines}\\n</tools>`;\n}\n\nfunction buildToolDetailsString(tool: UpstreamTool): string {\n const lines: string[] = [\n `Tool: ${tool.name}`,\n `Description: ${tool.description}`,\n \"\",\n \"Input Schema:\",\n JSON.stringify(tool.inputSchema, null, 2),\n ];\n\n if (tool.outputSchema !== undefined) {\n lines.push(\"\", \"Output Schema:\", JSON.stringify(tool.outputSchema, null, 2));\n }\n\n const annotationLines = buildAnnotationLines(tool);\n if (annotationLines.length > 0) {\n lines.push(\"\", \"Annotations:\", ...annotationLines);\n }\n\n return lines.join(\"\\n\");\n}\n\nfunction buildAnnotationLines(tool: UpstreamTool): string[] {\n if (tool.annotations === undefined) {\n return [];\n }\n\n const { annotations } = tool;\n const lines: string[] = [];\n\n if (annotations.title !== undefined) {\n lines.push(`- title: ${annotations.title}`);\n }\n if (annotations.readOnlyHint !== undefined) {\n lines.push(`- readOnlyHint: ${annotations.readOnlyHint}`);\n }\n if (annotations.destructiveHint !== undefined) {\n lines.push(`- destructiveHint: ${annotations.destructiveHint}`);\n }\n if (annotations.idempotentHint !== undefined) {\n lines.push(`- idempotentHint: ${annotations.idempotentHint}`);\n }\n if (annotations.openWorldHint !== undefined) {\n lines.push(`- openWorldHint: ${annotations.openWorldHint}`);\n }\n\n return lines;\n}\n","import process from \"node:process\";\nimport { FastMCP } from \"fastmcp\";\nimport { z } from \"zod\";\nimport packageJson from \"../../package.json\" with { type: \"json\" };\nimport type { ToolCatalog } from \"./tool-catalog.js\";\nimport type { UpstreamClient } from \"./upstream-client.js\";\n\ntype ProxyServerConfig = {\n catalog: ToolCatalog;\n upstreamClient: UpstreamClient;\n};\n\nexport class ProxyServer {\n private readonly catalog: ToolCatalog;\n private readonly upstreamClient: UpstreamClient;\n\n constructor({ catalog, upstreamClient }: ProxyServerConfig) {\n this.catalog = catalog;\n this.upstreamClient = upstreamClient;\n }\n\n async start(): Promise<void> {\n const server = new FastMCP({\n name: \"dynamic-discovery-mcp\",\n version: packageJson.version as `${number}.${number}.${number}`,\n });\n\n server.addTool({\n name: \"discover_tool\",\n description: this.catalog.discoverToolDescription,\n parameters: z.object({ tool_name: z.string() }),\n execute: async ({ tool_name }) => {\n return this.catalog.getToolDetails(tool_name);\n },\n });\n\n server.addTool({\n name: \"use_tool\",\n description: \"Use a tool that was previously discovered with the discover_tool tool.\",\n parameters: z.object({\n tool_name: z.string(),\n tool_input: z.record(z.string(), z.unknown()).default({}),\n }),\n execute: async ({ tool_name, tool_input }) => {\n if (!this.catalog.tools.has(tool_name)) {\n return this.catalog.getToolDetails(tool_name);\n }\n\n const result = await this.upstreamClient.callTool(tool_name, tool_input);\n return result;\n },\n });\n\n process.stderr.write(\"Starting dynamic-discovery-mcp server over stdio\\n\");\n await server.start({ transportType: \"stdio\" });\n }\n}\n","import process from \"node:process\";\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { StdioClientTransport } from \"@modelcontextprotocol/sdk/client/stdio.js\";\nimport type { ContentResult } from \"fastmcp\";\n\nexport type ToolAnnotations = {\n title?: string;\n readOnlyHint?: boolean;\n destructiveHint?: boolean;\n idempotentHint?: boolean;\n openWorldHint?: boolean;\n};\n\nexport type UpstreamTool = {\n name: string;\n description: string;\n inputSchema: unknown;\n outputSchema?: unknown;\n annotations?: ToolAnnotations;\n};\n\ntype UpstreamClientConfig = {\n command: string;\n args: string[];\n onTransportError?: (error: Error) => void;\n};\n\nexport class UpstreamClient {\n private readonly command: string;\n private readonly args: string[];\n private readonly onTransportError: (error: Error) => void;\n private client: Client | null = null;\n private transport: StdioClientTransport | null = null;\n\n constructor({ command, args, onTransportError }: UpstreamClientConfig) {\n this.command = command;\n this.args = args;\n this.onTransportError =\n onTransportError ??\n ((error: Error) => {\n process.stderr.write(`Upstream MCP transport error: ${error.message}\\n`);\n });\n }\n\n async connect(): Promise<void> {\n this.transport = new StdioClientTransport({\n command: this.command,\n args: this.args,\n });\n\n this.transport.onerror = this.onTransportError;\n\n this.client = new Client({ name: \"dynamic-discovery-mcp\", version: \"1.0.0\" });\n await this.client.connect(this.transport);\n }\n\n async listTools(): Promise<UpstreamTool[]> {\n if (this.client === null) {\n throw new Error(\"Client is not connected. Call connect() first.\");\n }\n\n const result = await this.client.listTools();\n\n return result.tools.map(tool => {\n const upstreamTool: UpstreamTool = {\n name: tool.name,\n description: tool.description ?? \"\",\n inputSchema: tool.inputSchema,\n };\n\n if (tool.outputSchema !== undefined) {\n upstreamTool.outputSchema = tool.outputSchema;\n }\n\n if (tool.annotations !== undefined) {\n upstreamTool.annotations = {\n title: tool.annotations.title,\n readOnlyHint: tool.annotations.readOnlyHint,\n destructiveHint: tool.annotations.destructiveHint,\n idempotentHint: tool.annotations.idempotentHint,\n openWorldHint: tool.annotations.openWorldHint,\n };\n }\n\n return upstreamTool;\n });\n }\n\n async callTool(name: string, input: Record<string, unknown>): Promise<ContentResult> {\n if (this.client === null) {\n throw new Error(\"Client is not connected. Call connect() first.\");\n }\n\n return this.client.callTool({\n name,\n arguments: input,\n }) as Promise<ContentResult>;\n }\n\n async disconnect(): Promise<void> {\n if (this.client === null) {\n return;\n }\n\n await this.client.close();\n this.client = null;\n this.transport = null;\n }\n}\n","import { cli } from \"./cli.js\";\nimport process from \"node:process\";\n\nasync function main() {\n cli.parse(process.argv);\n}\n\nmain();\n"],"mappings":"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","names":["import_node_process","import_node_process","process","import_node_process","process","process","chalk","figlet","process","import_node_process","process"]}
|
package/dist/index.d.cts
ADDED
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/cli.ts
|
|
4
|
+
import process4 from "process";
|
|
5
|
+
import { Command } from "commander";
|
|
6
|
+
|
|
7
|
+
// package.json
|
|
8
|
+
var package_default = {
|
|
9
|
+
name: "dynmcp",
|
|
10
|
+
version: "0.0.1",
|
|
11
|
+
description: "Dynamic MCP context management tool for AI MCP-enabled agents and clients.",
|
|
12
|
+
author: "Brandon Burrus <brandon@burrus.io>",
|
|
13
|
+
license: "MIT",
|
|
14
|
+
type: "module",
|
|
15
|
+
homepage: "https://github.com/brandonburrus/dynamic-discovery-mcp#readme",
|
|
16
|
+
keywords: [
|
|
17
|
+
"mcp",
|
|
18
|
+
"model-context-protocol",
|
|
19
|
+
"ai",
|
|
20
|
+
"agent",
|
|
21
|
+
"proxy",
|
|
22
|
+
"dynamic",
|
|
23
|
+
"discovery",
|
|
24
|
+
"tools",
|
|
25
|
+
"llm",
|
|
26
|
+
"cli"
|
|
27
|
+
],
|
|
28
|
+
engines: {
|
|
29
|
+
node: ">=20.0.0"
|
|
30
|
+
},
|
|
31
|
+
publishConfig: {
|
|
32
|
+
access: "public"
|
|
33
|
+
},
|
|
34
|
+
repository: {
|
|
35
|
+
type: "git",
|
|
36
|
+
url: "git+https://github.com/brandonburrus/dynamic-discovery-mcp.git"
|
|
37
|
+
},
|
|
38
|
+
bugs: {
|
|
39
|
+
url: "https://github.com/brandonburrus/dynamic-discovery-mcp/issues"
|
|
40
|
+
},
|
|
41
|
+
main: "./dist/index.cjs",
|
|
42
|
+
module: "./dist/index.js",
|
|
43
|
+
types: "./dist/index.d.ts",
|
|
44
|
+
bin: {
|
|
45
|
+
dynmcp: "./dist/index.js"
|
|
46
|
+
},
|
|
47
|
+
exports: {
|
|
48
|
+
".": {
|
|
49
|
+
types: "./dist/index.d.ts",
|
|
50
|
+
import: "./dist/index.js",
|
|
51
|
+
require: "./dist/index.cjs"
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
files: [
|
|
55
|
+
"dist"
|
|
56
|
+
],
|
|
57
|
+
scripts: {
|
|
58
|
+
build: "tsup",
|
|
59
|
+
dev: "tsx src/index.ts",
|
|
60
|
+
typecheck: "tsc --noEmit",
|
|
61
|
+
lint: "biome lint .",
|
|
62
|
+
format: "biome format --write .",
|
|
63
|
+
check: "biome check --write .",
|
|
64
|
+
test: "vitest run",
|
|
65
|
+
"test:watch": "vitest",
|
|
66
|
+
"test:coverage": "vitest run --coverage",
|
|
67
|
+
prepare: "husky"
|
|
68
|
+
},
|
|
69
|
+
dependencies: {
|
|
70
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
71
|
+
boxen: "^8.0.1",
|
|
72
|
+
chalk: "^5.6.2",
|
|
73
|
+
commander: "^14.0.3",
|
|
74
|
+
enquirer: "^2.4.1",
|
|
75
|
+
fastmcp: "^4.0.1",
|
|
76
|
+
figlet: "^1.11.0",
|
|
77
|
+
figures: "^6.1.0",
|
|
78
|
+
zod: "^4.4.3"
|
|
79
|
+
},
|
|
80
|
+
devDependencies: {
|
|
81
|
+
"@biomejs/biome": "^2.4.15",
|
|
82
|
+
"@commitlint/cli": "^21.0.1",
|
|
83
|
+
"@commitlint/config-conventional": "^21.0.1",
|
|
84
|
+
"@types/node": "^25.9.0",
|
|
85
|
+
husky: "^9.1.7",
|
|
86
|
+
tsup: "^8.5.1",
|
|
87
|
+
tsx: "^4.22.2",
|
|
88
|
+
typescript: "^6.0.3",
|
|
89
|
+
vitest: "^4.1.6"
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// src/cli.ts
|
|
94
|
+
import figlet from "figlet";
|
|
95
|
+
import chalk from "chalk";
|
|
96
|
+
|
|
97
|
+
// src/proxy/index.ts
|
|
98
|
+
import process3 from "process";
|
|
99
|
+
|
|
100
|
+
// src/proxy/tool-catalog.ts
|
|
101
|
+
var DISCOVER_TOOL_PREAMBLE = `Use this tool to look up the full schema of a tool before calling it with use_tool.
|
|
102
|
+
Call discover_tool with a tool name from the list below to get its complete description,
|
|
103
|
+
input parameters, and output schema. Always discover a tool before using it.`;
|
|
104
|
+
var ToolCatalog = class {
|
|
105
|
+
tools;
|
|
106
|
+
discoverToolDescription;
|
|
107
|
+
constructor(upstreamTools) {
|
|
108
|
+
const toolMap = /* @__PURE__ */ new Map();
|
|
109
|
+
for (const tool of upstreamTools) {
|
|
110
|
+
toolMap.set(tool.name, tool);
|
|
111
|
+
}
|
|
112
|
+
this.tools = toolMap;
|
|
113
|
+
this.discoverToolDescription = buildDiscoverToolDescription(upstreamTools);
|
|
114
|
+
}
|
|
115
|
+
getToolDetails(toolName) {
|
|
116
|
+
const tool = this.tools.get(toolName);
|
|
117
|
+
if (tool === void 0) {
|
|
118
|
+
const sortedNames = [...this.tools.keys()].sort().join(", ");
|
|
119
|
+
return `Unknown tool: "${toolName}". Available tools: ${sortedNames}`;
|
|
120
|
+
}
|
|
121
|
+
return buildToolDetailsString(tool);
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
function buildDiscoverToolDescription(tools) {
|
|
125
|
+
const sortedTools = [...tools].sort((a, b) => a.name.localeCompare(b.name));
|
|
126
|
+
const toolLines = sortedTools.map((tool) => `- ${tool.name}: ${tool.description}`).join("\n");
|
|
127
|
+
return `${DISCOVER_TOOL_PREAMBLE}
|
|
128
|
+
|
|
129
|
+
<tools>
|
|
130
|
+
${toolLines}
|
|
131
|
+
</tools>`;
|
|
132
|
+
}
|
|
133
|
+
function buildToolDetailsString(tool) {
|
|
134
|
+
const lines = [
|
|
135
|
+
`Tool: ${tool.name}`,
|
|
136
|
+
`Description: ${tool.description}`,
|
|
137
|
+
"",
|
|
138
|
+
"Input Schema:",
|
|
139
|
+
JSON.stringify(tool.inputSchema, null, 2)
|
|
140
|
+
];
|
|
141
|
+
if (tool.outputSchema !== void 0) {
|
|
142
|
+
lines.push("", "Output Schema:", JSON.stringify(tool.outputSchema, null, 2));
|
|
143
|
+
}
|
|
144
|
+
const annotationLines = buildAnnotationLines(tool);
|
|
145
|
+
if (annotationLines.length > 0) {
|
|
146
|
+
lines.push("", "Annotations:", ...annotationLines);
|
|
147
|
+
}
|
|
148
|
+
return lines.join("\n");
|
|
149
|
+
}
|
|
150
|
+
function buildAnnotationLines(tool) {
|
|
151
|
+
if (tool.annotations === void 0) {
|
|
152
|
+
return [];
|
|
153
|
+
}
|
|
154
|
+
const { annotations } = tool;
|
|
155
|
+
const lines = [];
|
|
156
|
+
if (annotations.title !== void 0) {
|
|
157
|
+
lines.push(`- title: ${annotations.title}`);
|
|
158
|
+
}
|
|
159
|
+
if (annotations.readOnlyHint !== void 0) {
|
|
160
|
+
lines.push(`- readOnlyHint: ${annotations.readOnlyHint}`);
|
|
161
|
+
}
|
|
162
|
+
if (annotations.destructiveHint !== void 0) {
|
|
163
|
+
lines.push(`- destructiveHint: ${annotations.destructiveHint}`);
|
|
164
|
+
}
|
|
165
|
+
if (annotations.idempotentHint !== void 0) {
|
|
166
|
+
lines.push(`- idempotentHint: ${annotations.idempotentHint}`);
|
|
167
|
+
}
|
|
168
|
+
if (annotations.openWorldHint !== void 0) {
|
|
169
|
+
lines.push(`- openWorldHint: ${annotations.openWorldHint}`);
|
|
170
|
+
}
|
|
171
|
+
return lines;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// src/proxy/server.ts
|
|
175
|
+
import process from "process";
|
|
176
|
+
import { FastMCP } from "fastmcp";
|
|
177
|
+
import { z } from "zod";
|
|
178
|
+
var ProxyServer = class {
|
|
179
|
+
catalog;
|
|
180
|
+
upstreamClient;
|
|
181
|
+
constructor({ catalog, upstreamClient }) {
|
|
182
|
+
this.catalog = catalog;
|
|
183
|
+
this.upstreamClient = upstreamClient;
|
|
184
|
+
}
|
|
185
|
+
async start() {
|
|
186
|
+
const server = new FastMCP({
|
|
187
|
+
name: "dynamic-discovery-mcp",
|
|
188
|
+
version: package_default.version
|
|
189
|
+
});
|
|
190
|
+
server.addTool({
|
|
191
|
+
name: "discover_tool",
|
|
192
|
+
description: this.catalog.discoverToolDescription,
|
|
193
|
+
parameters: z.object({ tool_name: z.string() }),
|
|
194
|
+
execute: async ({ tool_name }) => {
|
|
195
|
+
return this.catalog.getToolDetails(tool_name);
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
server.addTool({
|
|
199
|
+
name: "use_tool",
|
|
200
|
+
description: "Use a tool that was previously discovered with the discover_tool tool.",
|
|
201
|
+
parameters: z.object({
|
|
202
|
+
tool_name: z.string(),
|
|
203
|
+
tool_input: z.record(z.string(), z.unknown()).default({})
|
|
204
|
+
}),
|
|
205
|
+
execute: async ({ tool_name, tool_input }) => {
|
|
206
|
+
if (!this.catalog.tools.has(tool_name)) {
|
|
207
|
+
return this.catalog.getToolDetails(tool_name);
|
|
208
|
+
}
|
|
209
|
+
const result = await this.upstreamClient.callTool(tool_name, tool_input);
|
|
210
|
+
return result;
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
process.stderr.write("Starting dynamic-discovery-mcp server over stdio\n");
|
|
214
|
+
await server.start({ transportType: "stdio" });
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
// src/proxy/upstream-client.ts
|
|
219
|
+
import process2 from "process";
|
|
220
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
221
|
+
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
222
|
+
var UpstreamClient = class {
|
|
223
|
+
command;
|
|
224
|
+
args;
|
|
225
|
+
onTransportError;
|
|
226
|
+
client = null;
|
|
227
|
+
transport = null;
|
|
228
|
+
constructor({ command, args, onTransportError }) {
|
|
229
|
+
this.command = command;
|
|
230
|
+
this.args = args;
|
|
231
|
+
this.onTransportError = onTransportError ?? ((error) => {
|
|
232
|
+
process2.stderr.write(`Upstream MCP transport error: ${error.message}
|
|
233
|
+
`);
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
async connect() {
|
|
237
|
+
this.transport = new StdioClientTransport({
|
|
238
|
+
command: this.command,
|
|
239
|
+
args: this.args
|
|
240
|
+
});
|
|
241
|
+
this.transport.onerror = this.onTransportError;
|
|
242
|
+
this.client = new Client({ name: "dynamic-discovery-mcp", version: "1.0.0" });
|
|
243
|
+
await this.client.connect(this.transport);
|
|
244
|
+
}
|
|
245
|
+
async listTools() {
|
|
246
|
+
if (this.client === null) {
|
|
247
|
+
throw new Error("Client is not connected. Call connect() first.");
|
|
248
|
+
}
|
|
249
|
+
const result = await this.client.listTools();
|
|
250
|
+
return result.tools.map((tool) => {
|
|
251
|
+
const upstreamTool = {
|
|
252
|
+
name: tool.name,
|
|
253
|
+
description: tool.description ?? "",
|
|
254
|
+
inputSchema: tool.inputSchema
|
|
255
|
+
};
|
|
256
|
+
if (tool.outputSchema !== void 0) {
|
|
257
|
+
upstreamTool.outputSchema = tool.outputSchema;
|
|
258
|
+
}
|
|
259
|
+
if (tool.annotations !== void 0) {
|
|
260
|
+
upstreamTool.annotations = {
|
|
261
|
+
title: tool.annotations.title,
|
|
262
|
+
readOnlyHint: tool.annotations.readOnlyHint,
|
|
263
|
+
destructiveHint: tool.annotations.destructiveHint,
|
|
264
|
+
idempotentHint: tool.annotations.idempotentHint,
|
|
265
|
+
openWorldHint: tool.annotations.openWorldHint
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
return upstreamTool;
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
async callTool(name, input) {
|
|
272
|
+
if (this.client === null) {
|
|
273
|
+
throw new Error("Client is not connected. Call connect() first.");
|
|
274
|
+
}
|
|
275
|
+
return this.client.callTool({
|
|
276
|
+
name,
|
|
277
|
+
arguments: input
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
async disconnect() {
|
|
281
|
+
if (this.client === null) {
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
await this.client.close();
|
|
285
|
+
this.client = null;
|
|
286
|
+
this.transport = null;
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
// src/proxy/index.ts
|
|
291
|
+
async function startProxy(command, args) {
|
|
292
|
+
let isShuttingDown = false;
|
|
293
|
+
const shutdown = (exitCode) => {
|
|
294
|
+
if (isShuttingDown) return;
|
|
295
|
+
isShuttingDown = true;
|
|
296
|
+
upstreamClient.disconnect().catch((error) => {
|
|
297
|
+
process3.stderr.write(
|
|
298
|
+
`dynmcp: error during disconnect: ${error instanceof Error ? error.message : String(error)}
|
|
299
|
+
`
|
|
300
|
+
);
|
|
301
|
+
}).finally(() => process3.exit(exitCode));
|
|
302
|
+
};
|
|
303
|
+
const upstreamClient = new UpstreamClient({
|
|
304
|
+
command,
|
|
305
|
+
args,
|
|
306
|
+
onTransportError: (error) => {
|
|
307
|
+
process3.stderr.write(`Upstream MCP transport error: ${error.message}
|
|
308
|
+
`);
|
|
309
|
+
shutdown(1);
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
try {
|
|
313
|
+
await upstreamClient.connect();
|
|
314
|
+
} catch (error) {
|
|
315
|
+
process3.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
|
|
316
|
+
`);
|
|
317
|
+
process3.exit(1);
|
|
318
|
+
}
|
|
319
|
+
let tools;
|
|
320
|
+
try {
|
|
321
|
+
tools = await upstreamClient.listTools();
|
|
322
|
+
} catch (error) {
|
|
323
|
+
process3.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
|
|
324
|
+
`);
|
|
325
|
+
process3.exit(1);
|
|
326
|
+
}
|
|
327
|
+
const catalog = new ToolCatalog(tools);
|
|
328
|
+
const proxyServer = new ProxyServer({ catalog, upstreamClient });
|
|
329
|
+
process3.on("SIGINT", () => shutdown(0));
|
|
330
|
+
process3.on("SIGTERM", () => shutdown(0));
|
|
331
|
+
process3.stdin.on("end", () => shutdown(0));
|
|
332
|
+
process3.stdin.on("close", () => shutdown(0));
|
|
333
|
+
await proxyServer.start();
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// src/cli.ts
|
|
337
|
+
var cliBanner = chalk.bold.magentaBright(
|
|
338
|
+
figlet.textSync("DYNAMIC MCP", {
|
|
339
|
+
font: "Sub-Zero",
|
|
340
|
+
horizontalLayout: "fitted",
|
|
341
|
+
verticalLayout: "fitted"
|
|
342
|
+
})
|
|
343
|
+
);
|
|
344
|
+
var cli = new Command(package_default.name).description(package_default.description).version(package_default.version).addHelpText("beforeAll", cliBanner).addHelpText("after", "\nExample:\n dynmcp -- npx -y chrome-devtools-mcp@latest\n").allowExcessArguments(true).passThroughOptions(true).action(async () => {
|
|
345
|
+
const separatorIndex = process4.argv.indexOf("--");
|
|
346
|
+
if (separatorIndex === -1) {
|
|
347
|
+
process4.stderr.write(
|
|
348
|
+
"dynmcp: no upstream command provided.\nUsage: dynmcp -- <command> [args...]\nExample: dynmcp -- npx -y chrome-devtools-mcp@latest\n"
|
|
349
|
+
);
|
|
350
|
+
process4.exit(1);
|
|
351
|
+
}
|
|
352
|
+
const [command, ...args] = process4.argv.slice(separatorIndex + 1);
|
|
353
|
+
if (command === void 0) {
|
|
354
|
+
process4.stderr.write(
|
|
355
|
+
"dynmcp: no upstream command provided.\nUsage: dynmcp -- <command> [args...]\nExample: dynmcp -- npx -y chrome-devtools-mcp@latest\n"
|
|
356
|
+
);
|
|
357
|
+
process4.exit(1);
|
|
358
|
+
}
|
|
359
|
+
try {
|
|
360
|
+
await startProxy(command, args);
|
|
361
|
+
} catch (error) {
|
|
362
|
+
process4.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}
|
|
363
|
+
`);
|
|
364
|
+
process4.exit(1);
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
// src/index.ts
|
|
369
|
+
import process5 from "process";
|
|
370
|
+
async function main() {
|
|
371
|
+
cli.parse(process5.argv);
|
|
372
|
+
}
|
|
373
|
+
main();
|
|
374
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../package.json","../src/proxy/index.ts","../src/proxy/tool-catalog.ts","../src/proxy/server.ts","../src/proxy/upstream-client.ts","../src/index.ts"],"sourcesContent":["import process from \"node:process\";\nimport { Command } from \"commander\";\nimport packageJson from \"../package.json\" with { type: \"json\" };\nimport figlet from \"figlet\";\nimport chalk from \"chalk\";\nimport { startProxy } from \"./proxy/index.js\";\n\nconst cliBanner = chalk.bold.magentaBright(\n figlet.textSync(\"DYNAMIC MCP\", {\n font: \"Sub-Zero\",\n horizontalLayout: \"fitted\",\n verticalLayout: \"fitted\",\n }),\n);\n\nexport const cli = new Command(packageJson.name)\n .description(packageJson.description)\n .version(packageJson.version)\n .addHelpText(\"beforeAll\", cliBanner)\n .addHelpText(\"after\", \"\\nExample:\\n dynmcp -- npx -y chrome-devtools-mcp@latest\\n\")\n .allowExcessArguments(true)\n .passThroughOptions(true)\n .action(async () => {\n const separatorIndex = process.argv.indexOf(\"--\");\n\n if (separatorIndex === -1) {\n process.stderr.write(\n \"dynmcp: no upstream command provided.\\n\" +\n \"Usage: dynmcp -- <command> [args...]\\n\" +\n \"Example: dynmcp -- npx -y chrome-devtools-mcp@latest\\n\",\n );\n process.exit(1);\n }\n\n const [command, ...args] = process.argv.slice(separatorIndex + 1);\n\n if (command === undefined) {\n process.stderr.write(\n \"dynmcp: no upstream command provided.\\n\" +\n \"Usage: dynmcp -- <command> [args...]\\n\" +\n \"Example: dynmcp -- npx -y chrome-devtools-mcp@latest\\n\",\n );\n process.exit(1);\n }\n\n try {\n await startProxy(command, args);\n } catch (error) {\n process.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}\\n`);\n process.exit(1);\n }\n });\n","{\n \"name\": \"dynmcp\",\n \"version\": \"0.0.1\",\n \"description\": \"Dynamic MCP context management tool for AI MCP-enabled agents and clients.\",\n \"author\": \"Brandon Burrus <brandon@burrus.io>\",\n \"license\": \"MIT\",\n \"type\": \"module\",\n \"homepage\": \"https://github.com/brandonburrus/dynamic-discovery-mcp#readme\",\n \"keywords\": [\n \"mcp\",\n \"model-context-protocol\",\n \"ai\",\n \"agent\",\n \"proxy\",\n \"dynamic\",\n \"discovery\",\n \"tools\",\n \"llm\",\n \"cli\"\n ],\n \"engines\": {\n \"node\": \">=20.0.0\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/brandonburrus/dynamic-discovery-mcp.git\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/brandonburrus/dynamic-discovery-mcp/issues\"\n },\n \"main\": \"./dist/index.cjs\",\n \"module\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"bin\": {\n \"dynmcp\": \"./dist/index.js\"\n },\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n }\n },\n \"files\": [\n \"dist\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsx src/index.ts\",\n \"typecheck\": \"tsc --noEmit\",\n \"lint\": \"biome lint .\",\n \"format\": \"biome format --write .\",\n \"check\": \"biome check --write .\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"test:coverage\": \"vitest run --coverage\",\n \"prepare\": \"husky\"\n },\n \"dependencies\": {\n \"@modelcontextprotocol/sdk\": \"^1.29.0\",\n \"boxen\": \"^8.0.1\",\n \"chalk\": \"^5.6.2\",\n \"commander\": \"^14.0.3\",\n \"enquirer\": \"^2.4.1\",\n \"fastmcp\": \"^4.0.1\",\n \"figlet\": \"^1.11.0\",\n \"figures\": \"^6.1.0\",\n \"zod\": \"^4.4.3\"\n },\n \"devDependencies\": {\n \"@biomejs/biome\": \"^2.4.15\",\n \"@commitlint/cli\": \"^21.0.1\",\n \"@commitlint/config-conventional\": \"^21.0.1\",\n \"@types/node\": \"^25.9.0\",\n \"husky\": \"^9.1.7\",\n \"tsup\": \"^8.5.1\",\n \"tsx\": \"^4.22.2\",\n \"typescript\": \"^6.0.3\",\n \"vitest\": \"^4.1.6\"\n }\n}\n","import process from \"node:process\";\nimport { ToolCatalog } from \"./tool-catalog.js\";\nimport { ProxyServer } from \"./server.js\";\nimport { UpstreamClient } from \"./upstream-client.js\";\n\nexport async function startProxy(command: string, args: string[]): Promise<void> {\n let isShuttingDown = false;\n\n const shutdown = (exitCode: number): void => {\n if (isShuttingDown) return;\n isShuttingDown = true;\n\n upstreamClient\n .disconnect()\n .catch((error: unknown) => {\n process.stderr.write(\n `dynmcp: error during disconnect: ${error instanceof Error ? error.message : String(error)}\\n`,\n );\n })\n .finally(() => process.exit(exitCode));\n };\n\n const upstreamClient = new UpstreamClient({\n command,\n args,\n onTransportError: (error: Error) => {\n process.stderr.write(`Upstream MCP transport error: ${error.message}\\n`);\n shutdown(1);\n },\n });\n\n try {\n await upstreamClient.connect();\n } catch (error) {\n process.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}\\n`);\n process.exit(1);\n }\n\n let tools: Awaited<ReturnType<UpstreamClient[\"listTools\"]>>;\n try {\n tools = await upstreamClient.listTools();\n } catch (error) {\n process.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}\\n`);\n process.exit(1);\n }\n\n const catalog = new ToolCatalog(tools);\n const proxyServer = new ProxyServer({ catalog, upstreamClient });\n\n process.on(\"SIGINT\", () => shutdown(0));\n process.on(\"SIGTERM\", () => shutdown(0));\n process.stdin.on(\"end\", () => shutdown(0));\n process.stdin.on(\"close\", () => shutdown(0));\n\n await proxyServer.start();\n}\n","import type { UpstreamTool } from \"./upstream-client.js\";\n\nconst DISCOVER_TOOL_PREAMBLE = `Use this tool to look up the full schema of a tool before calling it with use_tool.\nCall discover_tool with a tool name from the list below to get its complete description,\ninput parameters, and output schema. Always discover a tool before using it.`;\n\nexport class ToolCatalog {\n readonly tools: ReadonlyMap<string, UpstreamTool>;\n readonly discoverToolDescription: string;\n\n constructor(upstreamTools: UpstreamTool[]) {\n const toolMap = new Map<string, UpstreamTool>();\n for (const tool of upstreamTools) {\n toolMap.set(tool.name, tool);\n }\n this.tools = toolMap;\n this.discoverToolDescription = buildDiscoverToolDescription(upstreamTools);\n }\n\n getToolDetails(toolName: string): string {\n const tool = this.tools.get(toolName);\n\n if (tool === undefined) {\n const sortedNames = [...this.tools.keys()].sort().join(\", \");\n return `Unknown tool: \"${toolName}\". Available tools: ${sortedNames}`;\n }\n\n return buildToolDetailsString(tool);\n }\n}\n\nfunction buildDiscoverToolDescription(tools: UpstreamTool[]): string {\n const sortedTools = [...tools].sort((a, b) => a.name.localeCompare(b.name));\n const toolLines = sortedTools.map(tool => `- ${tool.name}: ${tool.description}`).join(\"\\n\");\n\n return `${DISCOVER_TOOL_PREAMBLE}\\n\\n<tools>\\n${toolLines}\\n</tools>`;\n}\n\nfunction buildToolDetailsString(tool: UpstreamTool): string {\n const lines: string[] = [\n `Tool: ${tool.name}`,\n `Description: ${tool.description}`,\n \"\",\n \"Input Schema:\",\n JSON.stringify(tool.inputSchema, null, 2),\n ];\n\n if (tool.outputSchema !== undefined) {\n lines.push(\"\", \"Output Schema:\", JSON.stringify(tool.outputSchema, null, 2));\n }\n\n const annotationLines = buildAnnotationLines(tool);\n if (annotationLines.length > 0) {\n lines.push(\"\", \"Annotations:\", ...annotationLines);\n }\n\n return lines.join(\"\\n\");\n}\n\nfunction buildAnnotationLines(tool: UpstreamTool): string[] {\n if (tool.annotations === undefined) {\n return [];\n }\n\n const { annotations } = tool;\n const lines: string[] = [];\n\n if (annotations.title !== undefined) {\n lines.push(`- title: ${annotations.title}`);\n }\n if (annotations.readOnlyHint !== undefined) {\n lines.push(`- readOnlyHint: ${annotations.readOnlyHint}`);\n }\n if (annotations.destructiveHint !== undefined) {\n lines.push(`- destructiveHint: ${annotations.destructiveHint}`);\n }\n if (annotations.idempotentHint !== undefined) {\n lines.push(`- idempotentHint: ${annotations.idempotentHint}`);\n }\n if (annotations.openWorldHint !== undefined) {\n lines.push(`- openWorldHint: ${annotations.openWorldHint}`);\n }\n\n return lines;\n}\n","import process from \"node:process\";\nimport { FastMCP } from \"fastmcp\";\nimport { z } from \"zod\";\nimport packageJson from \"../../package.json\" with { type: \"json\" };\nimport type { ToolCatalog } from \"./tool-catalog.js\";\nimport type { UpstreamClient } from \"./upstream-client.js\";\n\ntype ProxyServerConfig = {\n catalog: ToolCatalog;\n upstreamClient: UpstreamClient;\n};\n\nexport class ProxyServer {\n private readonly catalog: ToolCatalog;\n private readonly upstreamClient: UpstreamClient;\n\n constructor({ catalog, upstreamClient }: ProxyServerConfig) {\n this.catalog = catalog;\n this.upstreamClient = upstreamClient;\n }\n\n async start(): Promise<void> {\n const server = new FastMCP({\n name: \"dynamic-discovery-mcp\",\n version: packageJson.version as `${number}.${number}.${number}`,\n });\n\n server.addTool({\n name: \"discover_tool\",\n description: this.catalog.discoverToolDescription,\n parameters: z.object({ tool_name: z.string() }),\n execute: async ({ tool_name }) => {\n return this.catalog.getToolDetails(tool_name);\n },\n });\n\n server.addTool({\n name: \"use_tool\",\n description: \"Use a tool that was previously discovered with the discover_tool tool.\",\n parameters: z.object({\n tool_name: z.string(),\n tool_input: z.record(z.string(), z.unknown()).default({}),\n }),\n execute: async ({ tool_name, tool_input }) => {\n if (!this.catalog.tools.has(tool_name)) {\n return this.catalog.getToolDetails(tool_name);\n }\n\n const result = await this.upstreamClient.callTool(tool_name, tool_input);\n return result;\n },\n });\n\n process.stderr.write(\"Starting dynamic-discovery-mcp server over stdio\\n\");\n await server.start({ transportType: \"stdio\" });\n }\n}\n","import process from \"node:process\";\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { StdioClientTransport } from \"@modelcontextprotocol/sdk/client/stdio.js\";\nimport type { ContentResult } from \"fastmcp\";\n\nexport type ToolAnnotations = {\n title?: string;\n readOnlyHint?: boolean;\n destructiveHint?: boolean;\n idempotentHint?: boolean;\n openWorldHint?: boolean;\n};\n\nexport type UpstreamTool = {\n name: string;\n description: string;\n inputSchema: unknown;\n outputSchema?: unknown;\n annotations?: ToolAnnotations;\n};\n\ntype UpstreamClientConfig = {\n command: string;\n args: string[];\n onTransportError?: (error: Error) => void;\n};\n\nexport class UpstreamClient {\n private readonly command: string;\n private readonly args: string[];\n private readonly onTransportError: (error: Error) => void;\n private client: Client | null = null;\n private transport: StdioClientTransport | null = null;\n\n constructor({ command, args, onTransportError }: UpstreamClientConfig) {\n this.command = command;\n this.args = args;\n this.onTransportError =\n onTransportError ??\n ((error: Error) => {\n process.stderr.write(`Upstream MCP transport error: ${error.message}\\n`);\n });\n }\n\n async connect(): Promise<void> {\n this.transport = new StdioClientTransport({\n command: this.command,\n args: this.args,\n });\n\n this.transport.onerror = this.onTransportError;\n\n this.client = new Client({ name: \"dynamic-discovery-mcp\", version: \"1.0.0\" });\n await this.client.connect(this.transport);\n }\n\n async listTools(): Promise<UpstreamTool[]> {\n if (this.client === null) {\n throw new Error(\"Client is not connected. Call connect() first.\");\n }\n\n const result = await this.client.listTools();\n\n return result.tools.map(tool => {\n const upstreamTool: UpstreamTool = {\n name: tool.name,\n description: tool.description ?? \"\",\n inputSchema: tool.inputSchema,\n };\n\n if (tool.outputSchema !== undefined) {\n upstreamTool.outputSchema = tool.outputSchema;\n }\n\n if (tool.annotations !== undefined) {\n upstreamTool.annotations = {\n title: tool.annotations.title,\n readOnlyHint: tool.annotations.readOnlyHint,\n destructiveHint: tool.annotations.destructiveHint,\n idempotentHint: tool.annotations.idempotentHint,\n openWorldHint: tool.annotations.openWorldHint,\n };\n }\n\n return upstreamTool;\n });\n }\n\n async callTool(name: string, input: Record<string, unknown>): Promise<ContentResult> {\n if (this.client === null) {\n throw new Error(\"Client is not connected. Call connect() first.\");\n }\n\n return this.client.callTool({\n name,\n arguments: input,\n }) as Promise<ContentResult>;\n }\n\n async disconnect(): Promise<void> {\n if (this.client === null) {\n return;\n }\n\n await this.client.close();\n this.client = null;\n this.transport = null;\n }\n}\n","import { cli } from \"./cli.js\";\nimport process from \"node:process\";\n\nasync function main() {\n cli.parse(process.argv);\n}\n\nmain();\n"],"mappings":"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","names":["process","process","process","process","process","process"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dynmcp",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Dynamic MCP context management tool for AI MCP-enabled agents and clients.",
|
|
5
|
+
"author": "Brandon Burrus <brandon@burrus.io>",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"homepage": "https://github.com/brandonburrus/dynamic-discovery-mcp#readme",
|
|
9
|
+
"keywords": [
|
|
10
|
+
"mcp",
|
|
11
|
+
"model-context-protocol",
|
|
12
|
+
"ai",
|
|
13
|
+
"agent",
|
|
14
|
+
"proxy",
|
|
15
|
+
"dynamic",
|
|
16
|
+
"discovery",
|
|
17
|
+
"tools",
|
|
18
|
+
"llm",
|
|
19
|
+
"cli"
|
|
20
|
+
],
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=20.0.0"
|
|
23
|
+
},
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "git+https://github.com/brandonburrus/dynamic-discovery-mcp.git"
|
|
30
|
+
},
|
|
31
|
+
"bugs": {
|
|
32
|
+
"url": "https://github.com/brandonburrus/dynamic-discovery-mcp/issues"
|
|
33
|
+
},
|
|
34
|
+
"main": "./dist/index.cjs",
|
|
35
|
+
"module": "./dist/index.js",
|
|
36
|
+
"types": "./dist/index.d.ts",
|
|
37
|
+
"bin": {
|
|
38
|
+
"dynmcp": "./dist/index.js"
|
|
39
|
+
},
|
|
40
|
+
"exports": {
|
|
41
|
+
".": {
|
|
42
|
+
"types": "./dist/index.d.ts",
|
|
43
|
+
"import": "./dist/index.js",
|
|
44
|
+
"require": "./dist/index.cjs"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"files": [
|
|
48
|
+
"dist"
|
|
49
|
+
],
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "tsup",
|
|
52
|
+
"dev": "tsx src/index.ts",
|
|
53
|
+
"typecheck": "tsc --noEmit",
|
|
54
|
+
"lint": "biome lint .",
|
|
55
|
+
"format": "biome format --write .",
|
|
56
|
+
"check": "biome check --write .",
|
|
57
|
+
"test": "vitest run",
|
|
58
|
+
"test:watch": "vitest",
|
|
59
|
+
"test:coverage": "vitest run --coverage",
|
|
60
|
+
"prepare": "husky"
|
|
61
|
+
},
|
|
62
|
+
"dependencies": {
|
|
63
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
64
|
+
"boxen": "^8.0.1",
|
|
65
|
+
"chalk": "^5.6.2",
|
|
66
|
+
"commander": "^14.0.3",
|
|
67
|
+
"enquirer": "^2.4.1",
|
|
68
|
+
"fastmcp": "^4.0.1",
|
|
69
|
+
"figlet": "^1.11.0",
|
|
70
|
+
"figures": "^6.1.0",
|
|
71
|
+
"zod": "^4.4.3"
|
|
72
|
+
},
|
|
73
|
+
"devDependencies": {
|
|
74
|
+
"@biomejs/biome": "^2.4.15",
|
|
75
|
+
"@commitlint/cli": "^21.0.1",
|
|
76
|
+
"@commitlint/config-conventional": "^21.0.1",
|
|
77
|
+
"@types/node": "^25.9.0",
|
|
78
|
+
"husky": "^9.1.7",
|
|
79
|
+
"tsup": "^8.5.1",
|
|
80
|
+
"tsx": "^4.22.2",
|
|
81
|
+
"typescript": "^6.0.3",
|
|
82
|
+
"vitest": "^4.1.6"
|
|
83
|
+
}
|
|
84
|
+
}
|