dynmcp 0.1.1 → 0.2.0
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 +59 -0
- package/dist/index.cjs +238 -54
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +241 -57
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/schema/mcp-config.json +10 -0
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../package.json","../src/proxy/index.ts","../src/config/schema.ts","../src/config/loader.ts","../src/config/json-schema.ts","../src/proxy/transport-factory.ts","../src/proxy/tool-catalog.ts","../src/proxy/upstream-client.ts","../src/proxy/orchestrator.ts","../src/proxy/server.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, startProxyFromConfig } 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(\n \"after\",\n \"\\nExamples:\\n\" +\n \" dynmcp -- npx -y chrome-devtools-mcp@latest\\n\" +\n \" dynmcp --config ./mcp.json\\n\",\n )\n .option(\"-c, --config <path>\", \"Path to config file (JSON or YAML)\")\n .allowExcessArguments(true)\n .passThroughOptions(true)\n .action(async (_options, cmd) => {\n const separatorIndex = process.argv.indexOf(\"--\");\n const configPath = cmd.opts().config as string | undefined;\n\n if (separatorIndex !== -1) {\n const [command, ...args] = process.argv.slice(separatorIndex + 1);\n\n if (command === undefined) {\n process.stderr.write(\n \"dynmcp: no upstream command provided after --.\\n\" +\n \"Usage: dynmcp -- <command> [args...]\\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 return;\n }\n\n try {\n await startProxyFromConfig(configPath);\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.1.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 \"schema\"\n ],\n \"scripts\": {\n \"generate:schema\": \"tsx scripts/generate-schema.ts\",\n \"prebuild\": \"tsx scripts/generate-schema.ts\",\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 \"yaml\": \"^2.9.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 { StdioClientTransport } from \"@modelcontextprotocol/sdk/client/stdio.js\";\nimport { loadConfig } from \"../config/index.js\";\nimport { createTransport } from \"./transport-factory.js\";\nimport { Orchestrator } from \"./orchestrator.js\";\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 transport = new StdioClientTransport({ command, args });\n\n const upstreamClient = new UpstreamClient({\n name: command,\n transport,\n onTransportError: (error: Error) => {\n process.stderr.write(`Upstream MCP transport error: ${error.message}\\n`);\n shutdown(1);\n },\n });\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 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 = ToolCatalog.fromFlat(tools);\n const proxyServer = new ProxyServer({\n catalog,\n callTool: (name, input) => upstreamClient.callTool(name, input),\n });\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 try {\n await proxyServer.start();\n } catch (error) {\n shutdown(1);\n throw error;\n }\n}\n\nexport async function startProxyFromConfig(configPath?: string): Promise<void> {\n let isShuttingDown = false;\n\n const config = loadConfig(configPath);\n\n const mcps = new Map<string, { transport: ReturnType<typeof createTransport> }>();\n for (const [name, entry] of Object.entries(config.mcp)) {\n mcps.set(name, { transport: createTransport(entry) });\n }\n\n const orchestrator = new Orchestrator({\n mcps,\n onTransportError: (mcpName: string, error: Error) => {\n process.stderr.write(`Upstream MCP \"${mcpName}\" transport error: ${error.message}\\n`);\n shutdown(1);\n },\n });\n\n const shutdown = (exitCode: number): void => {\n if (isShuttingDown) return;\n isShuttingDown = true;\n\n orchestrator\n .disconnectAll()\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 try {\n await orchestrator.connect();\n } catch (error) {\n process.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}\\n`);\n process.exit(1);\n }\n\n const proxyServer = new ProxyServer({\n catalog: orchestrator.catalog,\n callTool: (name, input) => orchestrator.callTool(name, input),\n });\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 try {\n await proxyServer.start();\n } catch (error) {\n shutdown(1);\n throw error;\n }\n}\n","import { z } from \"zod\";\n\nexport const MCP_NAME_PATTERN = /^[a-z0-9][a-z0-9-]*$/;\n\nconst mcpName = z.string().regex(MCP_NAME_PATTERN);\n\nconst stdioTransport = z\n .object({\n transport: z.literal(\"stdio\"),\n command: z.string(),\n args: z.array(z.string()).optional(),\n env: z.record(z.string(), z.string()).optional(),\n })\n .strict();\n\nconst httpUrl = z\n .string()\n .url()\n .refine(u => u.startsWith(\"http://\") || u.startsWith(\"https://\"), {\n message: \"URL must use http:// or https:// scheme\",\n });\n\nconst streamableHttpTransport = z\n .object({\n transport: z.literal(\"streamable-http\"),\n url: httpUrl,\n headers: z.record(z.string(), z.string()).optional(),\n })\n .strict();\n\nconst sseTransport = z\n .object({\n transport: z.literal(\"sse\"),\n url: httpUrl,\n headers: z.record(z.string(), z.string()).optional(),\n })\n .strict();\n\nconst transportConfig = z.discriminatedUnion(\"transport\", [\n stdioTransport,\n streamableHttpTransport,\n sseTransport,\n]);\n\nexport const mcpConfigSchema = z.object({\n mcp: z\n .record(mcpName, transportConfig)\n .refine(obj => Object.keys(obj).length > 0, { message: \"At least one MCP must be configured\" }),\n});\n\nexport type McpConfig = z.infer<typeof mcpConfigSchema>;\n","import { readFileSync } from \"node:fs\";\nimport { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { parse as parseYaml } from \"yaml\";\nimport { type McpConfig, mcpConfigSchema } from \"./schema.js\";\n\nconst AUTO_DISCOVER_NAMES = [\"mcp.json\", \".mcp.json\"] as const;\n\n/**\n * Resolves the config file path without loading or parsing it.\n *\n * @param explicitPath - If provided, resolves this path directly.\n * @returns The absolute path to the config file.\n * @throws If no config file is found at the explicit path or via auto-discovery.\n */\nexport function resolveConfigPath(explicitPath?: string): string {\n if (explicitPath) {\n const resolved = resolve(explicitPath);\n if (!existsSync(resolved)) {\n throw new Error(`Config file not found: ${resolved}`);\n }\n return resolved;\n }\n\n const cwd = process.cwd();\n for (const name of AUTO_DISCOVER_NAMES) {\n const candidate = resolve(cwd, name);\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n\n const searched = AUTO_DISCOVER_NAMES.map(n => resolve(cwd, n)).join(\", \");\n throw new Error(`No config file found. Searched: ${searched}`);\n}\n\n/**\n * Loads, parses, and validates the dynmcp config file.\n *\n * @param explicitPath - If provided, loads from this path. Otherwise auto-discovers.\n * @returns The validated config object.\n * @throws On missing file, parse errors, or schema validation failures.\n */\nexport function loadConfig(explicitPath?: string): McpConfig {\n const configPath = resolveConfigPath(explicitPath);\n const raw = readFileSync(configPath, \"utf-8\");\n\n let content: unknown;\n try {\n content = isYamlFile(configPath) ? parseYaml(raw) : JSON.parse(raw);\n } catch (parseError) {\n const message = parseError instanceof Error ? parseError.message : String(parseError);\n throw new Error(`Failed to parse config file (${configPath}): ${message}`);\n }\n\n const result = mcpConfigSchema.safeParse(content);\n if (!result.success) {\n const formatted = result.error.issues\n .map(issue => ` - ${issue.path.join(\".\")}: ${issue.message}`)\n .join(\"\\n\");\n throw new Error(`Invalid config file (${configPath}):\\n${formatted}`);\n }\n\n return result.data;\n}\n\nfunction isYamlFile(filePath: string): boolean {\n return filePath.endsWith(\".yml\") || filePath.endsWith(\".yaml\");\n}\n","import { z } from \"zod\";\nimport { mcpConfigSchema } from \"./schema.js\";\n\nexport const MCP_CONFIG_SCHEMA_ID = \"https://unpkg.com/dynmcp/schema/mcp-config.json\";\nexport const MCP_CONFIG_SCHEMA_DRAFT = \"http://json-schema.org/draft-07/schema#\";\n\n/**\n * Generates the JSON Schema for the dynmcp config file from the runtime Zod schema.\n *\n * The schema is targeted at JSON Schema draft-07 for the broadest editor support\n * (VS Code, JetBrains, and the JSON Schema Store all consume draft-07 reliably).\n *\n * @returns A JSON Schema document describing the dynmcp config file format.\n */\nexport function generateMcpConfigJsonSchema(): Record<string, unknown> {\n const generated = z.toJSONSchema(mcpConfigSchema, {\n target: \"draft-7\",\n }) as Record<string, unknown>;\n\n const properties = (generated.properties ?? {}) as Record<string, unknown>;\n const mcpProperty = (properties.mcp ?? {}) as Record<string, unknown>;\n\n return {\n $schema: MCP_CONFIG_SCHEMA_DRAFT,\n $id: MCP_CONFIG_SCHEMA_ID,\n title: \"dynmcp config\",\n description:\n \"Configuration file for dynmcp. Declares the set of upstream MCPs to proxy through dynamic-discovery-mcp.\",\n ...generated,\n properties: {\n ...properties,\n $schema: {\n type: \"string\",\n description: \"URL of the JSON Schema for editor validation.\",\n },\n mcp: {\n ...mcpProperty,\n minProperties: 1,\n description:\n \"Map of upstream MCPs to proxy, keyed by MCP name. Each name becomes the namespace prefix for that MCP's tools.\",\n },\n },\n };\n}\n","import { StdioClientTransport } from \"@modelcontextprotocol/sdk/client/stdio.js\";\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport { SSEClientTransport } from \"@modelcontextprotocol/sdk/client/sse.js\";\nimport type { Transport } from \"@modelcontextprotocol/sdk/shared/transport.js\";\n\ninterface StdioTransportConfig {\n transport: \"stdio\";\n command: string;\n args?: string[];\n env?: Record<string, string>;\n}\n\ninterface StreamableHttpTransportConfig {\n transport: \"streamable-http\";\n url: string;\n headers?: Record<string, string>;\n}\n\ninterface SseTransportConfig {\n transport: \"sse\";\n url: string;\n headers?: Record<string, string>;\n}\n\nexport type McpTransportConfig =\n | StdioTransportConfig\n | StreamableHttpTransportConfig\n | SseTransportConfig;\n\nexport function createTransport(config: McpTransportConfig): Transport {\n switch (config.transport) {\n case \"stdio\":\n return new StdioClientTransport({\n command: config.command,\n args: config.args,\n env: config.env,\n });\n\n case \"streamable-http\":\n return new StreamableHTTPClientTransport(\n new URL(config.url),\n config.headers ? { requestInit: { headers: config.headers } } : undefined,\n );\n\n case \"sse\":\n return new SSEClientTransport(\n new URL(config.url),\n config.headers ? { requestInit: { headers: config.headers } } : undefined,\n );\n\n default: {\n const _exhaustive: never = config;\n return _exhaustive;\n }\n }\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 private constructor(tools: Map<string, UpstreamTool>, description: string) {\n this.tools = tools;\n this.discoverToolDescription = description;\n }\n\n static fromFlat(upstreamTools: UpstreamTool[]): ToolCatalog {\n const toolMap = new Map<string, UpstreamTool>();\n for (const tool of upstreamTools) {\n toolMap.set(tool.name, tool);\n }\n const description = buildFlatDescription(upstreamTools);\n return new ToolCatalog(toolMap, description);\n }\n\n static fromGrouped(groups: Map<string, UpstreamTool[]>): ToolCatalog {\n const toolMap = new Map<string, UpstreamTool>();\n for (const [mcpName, tools] of groups) {\n for (const tool of tools) {\n toolMap.set(`${mcpName}/${tool.name}`, tool);\n }\n }\n const description = buildGroupedDescription(groups);\n return new ToolCatalog(toolMap, description);\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(toolName, tool);\n }\n}\n\nfunction buildFlatDescription(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 buildGroupedDescription(groups: Map<string, UpstreamTool[]>): string {\n const sortedMcpNames = [...groups.keys()].sort();\n const sections = sortedMcpNames.map(mcpName => {\n const tools = groups.get(mcpName)!;\n const sortedTools = [...tools].sort((a, b) => a.name.localeCompare(b.name));\n const toolLines = sortedTools\n .map(tool => `- ${mcpName}/${tool.name}: ${tool.description}`)\n .join(\"\\n\");\n return `${mcpName}:\\n${toolLines}`;\n });\n\n return `${DISCOVER_TOOL_PREAMBLE}\\n\\n<tools>\\n${sections.join(\"\\n\\n\")}\\n</tools>`;\n}\n\nfunction buildToolDetailsString(displayName: string, tool: UpstreamTool): string {\n const lines: string[] = [\n `Tool: ${displayName}`,\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 { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport type { Transport } from \"@modelcontextprotocol/sdk/shared/transport.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 name: string;\n transport: Transport;\n onTransportError?: (error: Error) => void;\n};\n\nexport class UpstreamClient {\n private readonly transport: Transport;\n private readonly onTransportError: (error: Error) => void;\n private client: Client | null = null;\n\n constructor({ name, transport, onTransportError }: UpstreamClientConfig) {\n this.transport = transport;\n this.onTransportError =\n onTransportError ??\n ((error: Error) => {\n process.stderr.write(`[${name}] Upstream MCP transport error: ${error.message}\\n`);\n });\n }\n\n async connect(): Promise<void> {\n this.transport.onerror = this.onTransportError;\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 const result = await this.client.callTool({ name, arguments: input });\n return result as 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 }\n}\n","import type { Transport } from \"@modelcontextprotocol/sdk/shared/transport.js\";\nimport type { ContentResult } from \"fastmcp\";\nimport { ToolCatalog } from \"./tool-catalog.js\";\nimport { UpstreamClient } from \"./upstream-client.js\";\n\nexport type OrchestratorConfig = {\n mcps: Map<string, { transport: Transport }>;\n onTransportError?: (mcpName: string, error: Error) => void;\n};\n\nexport class Orchestrator {\n private readonly config: OrchestratorConfig;\n private readonly clients: Map<string, UpstreamClient> = new Map();\n private toolCatalog: ToolCatalog | null = null;\n\n constructor(config: OrchestratorConfig) {\n this.config = config;\n }\n\n async connect(): Promise<void> {\n const groups = new Map<string, import(\"./upstream-client.js\").UpstreamTool[]>();\n\n try {\n for (const [mcpName, { transport }] of this.config.mcps) {\n const client = new UpstreamClient({\n name: mcpName,\n transport,\n onTransportError: (error: Error) => {\n this.config.onTransportError?.(mcpName, error);\n },\n });\n\n await client.connect();\n const tools = await client.listTools();\n\n this.clients.set(mcpName, client);\n groups.set(mcpName, tools);\n }\n } catch (error) {\n await this.disconnectAll();\n throw error;\n }\n\n this.toolCatalog = ToolCatalog.fromGrouped(groups);\n }\n\n get catalog(): ToolCatalog {\n if (this.toolCatalog === null) {\n throw new Error(\"Orchestrator is not connected. Call connect() first.\");\n }\n return this.toolCatalog;\n }\n\n async callTool(namespacedName: string, input: Record<string, unknown>): Promise<ContentResult> {\n const separatorIndex = namespacedName.indexOf(\"/\");\n if (separatorIndex === -1) {\n throw new Error(\n `Invalid namespaced tool name: \"${namespacedName}\". Expected format: \"mcpName/toolName\".`,\n );\n }\n\n const mcpName = namespacedName.slice(0, separatorIndex);\n const toolName = namespacedName.slice(separatorIndex + 1);\n\n const client = this.clients.get(mcpName);\n if (client === undefined) {\n const available = [...this.clients.keys()].sort().join(\", \");\n throw new Error(`Unknown MCP: \"${mcpName}\". Available MCPs: ${available}`);\n }\n\n return client.callTool(toolName, input);\n }\n\n async disconnectAll(): Promise<void> {\n const disconnections = [...this.clients.values()].map(client => client.disconnect());\n await Promise.all(disconnections);\n this.clients.clear();\n this.toolCatalog = null;\n }\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 { ContentResult } from \"fastmcp\";\nimport type { ToolCatalog } from \"./tool-catalog.js\";\n\ntype ToolCaller = (name: string, input: Record<string, unknown>) => Promise<ContentResult>;\n\ntype ProxyServerConfig = {\n catalog: ToolCatalog;\n callTool: ToolCaller;\n};\n\nexport class ProxyServer {\n private readonly catalog: ToolCatalog;\n private readonly callTool: ToolCaller;\n\n constructor({ catalog, callTool }: ProxyServerConfig) {\n this.catalog = catalog;\n this.callTool = callTool;\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.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 { 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","StdioClientTransport","z","mcpName","process","mcpName","process","z","z","process","StdioClientTransport","process","mcpName","process","process"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../package.json","../src/proxy/index.ts","../src/config/schema.ts","../src/config/loader.ts","../src/config/env-sources.ts","../src/config/interpolate.ts","../src/config/json-schema.ts","../src/proxy/transport-factory.ts","../src/proxy/tool-catalog.ts","../src/proxy/upstream-client.ts","../src/proxy/orchestrator.ts","../src/proxy/server.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, startProxyFromConfig } 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(\n \"after\",\n \"\\nExamples:\\n\" +\n \" dynmcp -- npx -y chrome-devtools-mcp@latest\\n\" +\n \" dynmcp --config ./mcp.json\\n\",\n )\n .option(\"-c, --config <path>\", \"Path to config file (JSON or YAML)\")\n .option(\n \"-e, --env <path>\",\n \"Path to a .env file for environment variable interpolation\",\n )\n .allowExcessArguments(true)\n .passThroughOptions(true)\n .action(async (_options, cmd) => {\n const separatorIndex = process.argv.indexOf(\"--\");\n const configPath = cmd.opts().config as string | undefined;\n const envFilePath = cmd.opts().env as string | undefined;\n\n if (separatorIndex !== -1) {\n const [command, ...args] = process.argv.slice(separatorIndex + 1);\n\n if (command === undefined) {\n process.stderr.write(\n \"dynmcp: no upstream command provided after --.\\n\" +\n \"Usage: dynmcp -- <command> [args...]\\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 return;\n }\n\n try {\n await startProxyFromConfig({ configPath, envFilePath });\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.2.0\",\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 \"schema\"\n ],\n \"scripts\": {\n \"generate:schema\": \"tsx scripts/generate-schema.ts\",\n \"prebuild\": \"tsx scripts/generate-schema.ts\",\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 \"dotenv\": \"^17.4.2\",\n \"enquirer\": \"^2.4.1\",\n \"fastmcp\": \"^4.0.1\",\n \"figlet\": \"^1.11.0\",\n \"figures\": \"^6.1.0\",\n \"yaml\": \"^2.9.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 { StdioClientTransport } from \"@modelcontextprotocol/sdk/client/stdio.js\";\nimport { loadConfig } from \"../config/index.js\";\nimport { createTransport } from \"./transport-factory.js\";\nimport { Orchestrator } from \"./orchestrator.js\";\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 transport = new StdioClientTransport({ command, args });\n\n const upstreamClient = new UpstreamClient({\n name: command,\n transport,\n onTransportError: (error: Error) => {\n process.stderr.write(`Upstream MCP transport error: ${error.message}\\n`);\n shutdown(1);\n },\n });\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 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 = ToolCatalog.fromFlat(tools);\n const proxyServer = new ProxyServer({\n catalog,\n callTool: (name, input) => upstreamClient.callTool(name, input),\n });\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 try {\n await proxyServer.start();\n } catch (error) {\n shutdown(1);\n throw error;\n }\n}\n\nexport interface StartProxyFromConfigOptions {\n configPath?: string;\n envFilePath?: string;\n}\n\nexport async function startProxyFromConfig(\n options: StartProxyFromConfigOptions = {},\n): Promise<void> {\n let isShuttingDown = false;\n\n const config = loadConfig(options);\n\n const mcps = new Map<string, { transport: ReturnType<typeof createTransport> }>();\n for (const [name, entry] of Object.entries(config.mcp)) {\n mcps.set(name, { transport: createTransport(entry) });\n }\n\n const orchestrator = new Orchestrator({\n mcps,\n onTransportError: (mcpName: string, error: Error) => {\n process.stderr.write(`Upstream MCP \"${mcpName}\" transport error: ${error.message}\\n`);\n shutdown(1);\n },\n });\n\n const shutdown = (exitCode: number): void => {\n if (isShuttingDown) return;\n isShuttingDown = true;\n\n orchestrator\n .disconnectAll()\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 try {\n await orchestrator.connect();\n } catch (error) {\n process.stderr.write(`dynmcp: ${error instanceof Error ? error.message : String(error)}\\n`);\n process.exit(1);\n }\n\n const proxyServer = new ProxyServer({\n catalog: orchestrator.catalog,\n callTool: (name, input) => orchestrator.callTool(name, input),\n });\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 try {\n await proxyServer.start();\n } catch (error) {\n shutdown(1);\n throw error;\n }\n}\n","import { z } from \"zod\";\n\nexport const MCP_NAME_PATTERN = /^[a-z0-9][a-z0-9-]*$/;\n\nconst mcpName = z.string().regex(MCP_NAME_PATTERN);\n\nexport const envModeSchema = z\n .enum([\"enable\", \"dotenv\", \"process\", \"disable\"])\n .describe(\n 'Controls environment variable interpolation in config values. \"enable\" (default) merges .env and process.env (.env wins). \"dotenv\" loads .env only. \"process\" uses process.env only. \"disable\" turns interpolation off.',\n );\n\nexport type EnvMode = z.infer<typeof envModeSchema>;\n\nconst stdioTransport = z\n .object({\n transport: z.literal(\"stdio\"),\n command: z.string(),\n args: z.array(z.string()).optional(),\n env: z.record(z.string(), z.string()).optional(),\n })\n .strict();\n\nconst httpUrl = z\n .string()\n .url()\n .refine(u => u.startsWith(\"http://\") || u.startsWith(\"https://\"), {\n message: \"URL must use http:// or https:// scheme\",\n });\n\nconst streamableHttpTransport = z\n .object({\n transport: z.literal(\"streamable-http\"),\n url: httpUrl,\n headers: z.record(z.string(), z.string()).optional(),\n })\n .strict();\n\nconst sseTransport = z\n .object({\n transport: z.literal(\"sse\"),\n url: httpUrl,\n headers: z.record(z.string(), z.string()).optional(),\n })\n .strict();\n\nconst transportConfig = z.discriminatedUnion(\"transport\", [\n stdioTransport,\n streamableHttpTransport,\n sseTransport,\n]);\n\nexport const mcpConfigSchema = z.object({\n env: envModeSchema.optional(),\n mcp: z\n .record(mcpName, transportConfig)\n .refine(obj => Object.keys(obj).length > 0, { message: \"At least one MCP must be configured\" }),\n});\n\nexport type McpConfig = z.infer<typeof mcpConfigSchema>;\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport process from \"node:process\";\nimport { parse as parseYaml } from \"yaml\";\nimport { loadEnv } from \"./env-sources.js\";\nimport { interpolateConfig } from \"./interpolate.js\";\nimport { type EnvMode, type McpConfig, mcpConfigSchema } from \"./schema.js\";\n\nconst AUTO_DISCOVER_NAMES = [\"mcp.json\", \".mcp.json\"] as const;\nconst DEFAULT_ENV_MODE: EnvMode = \"enable\";\nconst VALID_ENV_MODES: readonly EnvMode[] = [\"enable\", \"dotenv\", \"process\", \"disable\"];\n\nexport interface LoadConfigOptions {\n /** Path to the config file. If omitted, auto-discovers `mcp.json` then `.mcp.json` in cwd. */\n configPath?: string;\n /** Path to a custom `.env` file (from the `--env` / `-e` CLI flag). */\n envFilePath?: string;\n}\n\n/**\n * Resolves the config file path without loading or parsing it.\n *\n * @param explicitPath - If provided, resolves this path directly.\n * @returns The absolute path to the config file.\n * @throws If no config file is found at the explicit path or via auto-discovery.\n */\nexport function resolveConfigPath(explicitPath?: string): string {\n if (explicitPath) {\n const resolved = resolve(explicitPath);\n if (!existsSync(resolved)) {\n throw new Error(`Config file not found: ${resolved}`);\n }\n return resolved;\n }\n\n const cwd = process.cwd();\n for (const name of AUTO_DISCOVER_NAMES) {\n const candidate = resolve(cwd, name);\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n\n const searched = AUTO_DISCOVER_NAMES.map(n => resolve(cwd, n)).join(\", \");\n throw new Error(`No config file found. Searched: ${searched}`);\n}\n\n/**\n * Loads, parses, interpolates, and validates the dynmcp config file.\n *\n * Flow: resolve path → read file → parse JSON/YAML → read env mode →\n * load env sources → interpolate `${VAR}` references → Zod validate.\n *\n * @param options - Config path and optional custom `.env` file path.\n * @returns The validated config object with all interpolations resolved.\n * @throws On missing file, parse errors, missing env vars, or schema validation failures.\n */\nexport function loadConfig(options: LoadConfigOptions = {}): McpConfig {\n const { configPath, envFilePath } = options;\n\n const resolvedPath = resolveConfigPath(configPath);\n const raw = readFileSync(resolvedPath, \"utf-8\");\n\n let content: unknown;\n try {\n content = isYamlFile(resolvedPath) ? parseYaml(raw) : JSON.parse(raw);\n } catch (parseError) {\n const message = parseError instanceof Error ? parseError.message : String(parseError);\n throw new Error(`Failed to parse config file (${resolvedPath}): ${message}`);\n }\n\n const envMode = readEnvMode(content);\n const loadedEnv = loadEnv({ mode: envMode, envFilePath });\n\n const interpolated = loadedEnv.interpolationEnabled\n ? interpolateConfig(content, loadedEnv.variables)\n : content;\n\n const result = mcpConfigSchema.safeParse(interpolated);\n if (!result.success) {\n const formatted = result.error.issues\n .map(issue => ` - ${issue.path.join(\".\")}: ${issue.message}`)\n .join(\"\\n\");\n throw new Error(`Invalid config file (${resolvedPath}):\\n${formatted}`);\n }\n\n return result.data;\n}\n\n/**\n * Reads the top-level `env` field from raw parsed config content. This runs\n * before Zod validation so we can resolve env vars before validating types.\n *\n * If the field is missing, the default mode is returned. If it is present but\n * not a recognized value, the default is returned so that Zod can surface a\n * specific validation error later.\n */\nfunction readEnvMode(content: unknown): EnvMode {\n if (content === null || typeof content !== \"object\" || Array.isArray(content)) {\n return DEFAULT_ENV_MODE;\n }\n const value = (content as Record<string, unknown>).env;\n if (value === undefined) return DEFAULT_ENV_MODE;\n if (typeof value === \"string\" && (VALID_ENV_MODES as readonly string[]).includes(value)) {\n return value as EnvMode;\n }\n return DEFAULT_ENV_MODE;\n}\n\nfunction isYamlFile(filePath: string): boolean {\n return filePath.endsWith(\".yml\") || filePath.endsWith(\".yaml\");\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport process from \"node:process\";\nimport dotenv from \"dotenv\";\nimport type { EnvMode } from \"./schema.js\";\n\nconst DEFAULT_DOTENV_FILENAME = \".env\";\n\nexport interface LoadEnvOptions {\n /** Env interpolation mode (from config file top-level `env` field). */\n mode: EnvMode;\n /** Custom `.env` path from the `--env` / `-e` CLI flag. When provided, the file must exist. */\n envFilePath?: string;\n /** Override for cwd (testability). Defaults to `process.cwd()`. */\n cwd?: string;\n /** Override for process.env (testability). Defaults to `process.env`. */\n processEnv?: NodeJS.ProcessEnv;\n}\n\nexport interface LoadedEnv {\n /** Merged variable map ready for interpolation. */\n variables: Record<string, string>;\n /** Whether interpolation should run at all. False only when mode is \"disable\". */\n interpolationEnabled: boolean;\n}\n\n/**\n * Resolves the environment variable map used for config interpolation.\n *\n * Precedence rules:\n * - mode \"enable\": load .env + process.env, .env wins for duplicates.\n * - mode \"dotenv\": load .env only; process.env is ignored.\n * - mode \"process\": process.env only; no .env file is loaded.\n * - mode \"disable\": no sources; interpolation is turned off.\n *\n * The `--env` flag is incompatible with \"disable\" and \"process\" modes and is\n * rejected at startup as an incoherent combination.\n *\n * @throws If `--env` is combined with an incompatible mode.\n * @throws If an explicit `--env` path does not exist or cannot be parsed.\n */\nexport function loadEnv(options: LoadEnvOptions): LoadedEnv {\n const { mode, envFilePath, cwd = process.cwd(), processEnv = process.env } = options;\n\n if (envFilePath !== undefined && (mode === \"disable\" || mode === \"process\")) {\n throw new Error(\n `--env flag is incompatible with env mode \"${mode}\". --env requires env mode \"enable\" or \"dotenv\".`,\n );\n }\n\n if (mode === \"disable\") {\n return { variables: {}, interpolationEnabled: false };\n }\n\n const dotenvVars = mode === \"process\" ? {} : readDotenvFile(envFilePath, cwd);\n const processVars = mode === \"dotenv\" ? {} : filterDefined(processEnv);\n\n // For \"enable\" mode, .env wins (later spread overrides earlier).\n // For \"process\" and \"dotenv\" modes only one source is non-empty, so order is moot.\n const variables = { ...processVars, ...dotenvVars };\n\n return { variables, interpolationEnabled: true };\n}\n\nfunction readDotenvFile(envFilePath: string | undefined, cwd: string): Record<string, string> {\n const isExplicit = envFilePath !== undefined;\n const resolvedPath = isExplicit\n ? resolve(envFilePath as string)\n : resolve(cwd, DEFAULT_DOTENV_FILENAME);\n\n if (!existsSync(resolvedPath)) {\n if (isExplicit) {\n throw new Error(`.env file not found: ${resolvedPath}`);\n }\n // Soft-fail: a missing default .env is not an error.\n return {};\n }\n\n let raw: string;\n try {\n raw = readFileSync(resolvedPath, \"utf-8\");\n } catch (readError) {\n const message = readError instanceof Error ? readError.message : String(readError);\n throw new Error(`Failed to read .env file (${resolvedPath}): ${message}`);\n }\n\n try {\n return dotenv.parse(raw);\n } catch (parseError) {\n const message = parseError instanceof Error ? parseError.message : String(parseError);\n throw new Error(`Failed to parse .env file (${resolvedPath}): ${message}`);\n }\n}\n\nfunction filterDefined(env: NodeJS.ProcessEnv): Record<string, string> {\n const result: Record<string, string> = {};\n for (const [key, value] of Object.entries(env)) {\n if (value !== undefined) {\n result[key] = value;\n }\n }\n return result;\n}\n","/**\n * Environment variable interpolation for dynmcp config files.\n *\n * Runs after JSON/YAML parsing but before Zod validation, so the validated\n * config contains only fully-resolved string values.\n *\n * Supported syntax (per SPEC.md \"Environment Variable Interpolation\"):\n * - `${VAR}` substitute the value of VAR; missing → error\n * - `${VAR:-default}` substitute VAR, or `default` if VAR is unset or empty\n * - `$${...}` escape — resolves to the literal `${...}`\n *\n * Interpolation applies only to leaf string values reached through the `mcp`\n * subtree. The top-level `$schema` and `env` fields are passed through verbatim.\n */\n\nconst TOP_LEVEL_PASSTHROUGH_KEYS = new Set([\"$schema\", \"env\"]);\n\nexport class MissingEnvVarsError extends Error {\n constructor(public readonly missingVars: readonly string[]) {\n const list = missingVars.join(\", \");\n const plural = missingVars.length === 1 ? \"\" : \"s\";\n super(`Missing required environment variable${plural}: ${list}`);\n this.name = \"MissingEnvVarsError\";\n }\n}\n\n/**\n * Walks a parsed config object and substitutes `${VAR}` references in all leaf\n * string values. Top-level `$schema` and `env` keys are not interpolated.\n *\n * @param config - The parsed (but unvalidated) config object.\n * @param env - The resolved environment variable map (already merged per env mode).\n * @returns A structurally identical config with all string leaves interpolated.\n * @throws {MissingEnvVarsError} If any `${VAR}` reference has no default and no value in env.\n */\nexport function interpolateConfig(config: unknown, env: Record<string, string>): unknown {\n if (config === null || typeof config !== \"object\" || Array.isArray(config)) {\n return config;\n }\n\n const missing: string[] = [];\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(config as Record<string, unknown>)) {\n if (TOP_LEVEL_PASSTHROUGH_KEYS.has(key)) {\n result[key] = value;\n } else {\n result[key] = walkNode(value, env, missing);\n }\n }\n\n if (missing.length > 0) {\n const unique = Array.from(new Set(missing)).sort();\n throw new MissingEnvVarsError(unique);\n }\n\n return result;\n}\n\nfunction walkNode(node: unknown, env: Record<string, string>, missing: string[]): unknown {\n if (typeof node === \"string\") {\n return interpolateString(node, env, missing);\n }\n if (Array.isArray(node)) {\n return node.map(item => walkNode(item, env, missing));\n }\n if (node !== null && typeof node === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(node as Record<string, unknown>)) {\n result[key] = walkNode(value, env, missing);\n }\n return result;\n }\n return node;\n}\n\nfunction interpolateString(value: string, env: Record<string, string>, missing: string[]): string {\n let result = \"\";\n let i = 0;\n const len = value.length;\n\n while (i < len) {\n const ch = value[i];\n\n if (ch === \"$\" && value[i + 1] === \"$\" && value[i + 2] === \"{\") {\n // Escape: $${...} -> literal ${...} (strip one leading $)\n const close = value.indexOf(\"}\", i + 3);\n if (close === -1) {\n // Unclosed escape; treat the leading $ as literal and advance one char\n result += ch;\n i += 1;\n continue;\n }\n result += value.substring(i + 1, close + 1);\n i = close + 1;\n continue;\n }\n\n if (ch === \"$\" && value[i + 1] === \"{\") {\n const close = value.indexOf(\"}\", i + 2);\n if (close === -1) {\n // Unclosed expression; emit the rest of the string literally\n result += value.substring(i);\n break;\n }\n const expr = value.substring(i + 2, close);\n const { name, defaultValue } = parseExpr(expr);\n const resolved = env[name];\n const hasValue = resolved !== undefined && resolved !== \"\";\n\n if (hasValue) {\n result += resolved;\n } else if (defaultValue !== undefined) {\n result += defaultValue;\n } else if (resolved !== undefined) {\n // Defined but empty string and no default — treat as the empty string.\n // Per spec: ${VAR} without default fails only when VAR is *undefined*.\n result += \"\";\n } else {\n missing.push(name);\n }\n i = close + 1;\n continue;\n }\n\n result += ch;\n i += 1;\n }\n\n return result;\n}\n\nfunction parseExpr(expr: string): { name: string; defaultValue: string | undefined } {\n const sep = expr.indexOf(\":-\");\n if (sep === -1) {\n return { name: expr, defaultValue: undefined };\n }\n return {\n name: expr.substring(0, sep),\n defaultValue: expr.substring(sep + 2),\n };\n}\n","import { z } from \"zod\";\nimport { mcpConfigSchema } from \"./schema.js\";\n\nexport const MCP_CONFIG_SCHEMA_ID = \"https://unpkg.com/dynmcp/schema/mcp-config.json\";\nexport const MCP_CONFIG_SCHEMA_DRAFT = \"http://json-schema.org/draft-07/schema#\";\n\n/**\n * Generates the JSON Schema for the dynmcp config file from the runtime Zod schema.\n *\n * The schema is targeted at JSON Schema draft-07 for the broadest editor support\n * (VS Code, JetBrains, and the JSON Schema Store all consume draft-07 reliably).\n *\n * @returns A JSON Schema document describing the dynmcp config file format.\n */\nexport function generateMcpConfigJsonSchema(): Record<string, unknown> {\n const generated = z.toJSONSchema(mcpConfigSchema, {\n target: \"draft-7\",\n }) as Record<string, unknown>;\n\n const properties = (generated.properties ?? {}) as Record<string, unknown>;\n const mcpProperty = (properties.mcp ?? {}) as Record<string, unknown>;\n\n return {\n $schema: MCP_CONFIG_SCHEMA_DRAFT,\n $id: MCP_CONFIG_SCHEMA_ID,\n title: \"dynmcp config\",\n description:\n \"Configuration file for dynmcp. Declares the set of upstream MCPs to proxy through dynamic-discovery-mcp.\",\n ...generated,\n properties: {\n ...properties,\n $schema: {\n type: \"string\",\n description: \"URL of the JSON Schema for editor validation.\",\n },\n mcp: {\n ...mcpProperty,\n minProperties: 1,\n description:\n \"Map of upstream MCPs to proxy, keyed by MCP name. Each name becomes the namespace prefix for that MCP's tools.\",\n },\n },\n };\n}\n","import { StdioClientTransport } from \"@modelcontextprotocol/sdk/client/stdio.js\";\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport { SSEClientTransport } from \"@modelcontextprotocol/sdk/client/sse.js\";\nimport type { Transport } from \"@modelcontextprotocol/sdk/shared/transport.js\";\n\ninterface StdioTransportConfig {\n transport: \"stdio\";\n command: string;\n args?: string[];\n env?: Record<string, string>;\n}\n\ninterface StreamableHttpTransportConfig {\n transport: \"streamable-http\";\n url: string;\n headers?: Record<string, string>;\n}\n\ninterface SseTransportConfig {\n transport: \"sse\";\n url: string;\n headers?: Record<string, string>;\n}\n\nexport type McpTransportConfig =\n | StdioTransportConfig\n | StreamableHttpTransportConfig\n | SseTransportConfig;\n\nexport function createTransport(config: McpTransportConfig): Transport {\n switch (config.transport) {\n case \"stdio\":\n return new StdioClientTransport({\n command: config.command,\n args: config.args,\n env: config.env,\n });\n\n case \"streamable-http\":\n return new StreamableHTTPClientTransport(\n new URL(config.url),\n config.headers ? { requestInit: { headers: config.headers } } : undefined,\n );\n\n case \"sse\":\n return new SSEClientTransport(\n new URL(config.url),\n config.headers ? { requestInit: { headers: config.headers } } : undefined,\n );\n\n default: {\n const _exhaustive: never = config;\n return _exhaustive;\n }\n }\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 private constructor(tools: Map<string, UpstreamTool>, description: string) {\n this.tools = tools;\n this.discoverToolDescription = description;\n }\n\n static fromFlat(upstreamTools: UpstreamTool[]): ToolCatalog {\n const toolMap = new Map<string, UpstreamTool>();\n for (const tool of upstreamTools) {\n toolMap.set(tool.name, tool);\n }\n const description = buildFlatDescription(upstreamTools);\n return new ToolCatalog(toolMap, description);\n }\n\n static fromGrouped(groups: Map<string, UpstreamTool[]>): ToolCatalog {\n const toolMap = new Map<string, UpstreamTool>();\n for (const [mcpName, tools] of groups) {\n for (const tool of tools) {\n toolMap.set(`${mcpName}/${tool.name}`, tool);\n }\n }\n const description = buildGroupedDescription(groups);\n return new ToolCatalog(toolMap, description);\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(toolName, tool);\n }\n}\n\nfunction buildFlatDescription(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 buildGroupedDescription(groups: Map<string, UpstreamTool[]>): string {\n const sortedMcpNames = [...groups.keys()].sort();\n const sections = sortedMcpNames.map(mcpName => {\n const tools = groups.get(mcpName)!;\n const sortedTools = [...tools].sort((a, b) => a.name.localeCompare(b.name));\n const toolLines = sortedTools\n .map(tool => `- ${mcpName}/${tool.name}: ${tool.description}`)\n .join(\"\\n\");\n return `${mcpName}:\\n${toolLines}`;\n });\n\n return `${DISCOVER_TOOL_PREAMBLE}\\n\\n<tools>\\n${sections.join(\"\\n\\n\")}\\n</tools>`;\n}\n\nfunction buildToolDetailsString(displayName: string, tool: UpstreamTool): string {\n const lines: string[] = [\n `Tool: ${displayName}`,\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 { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport type { Transport } from \"@modelcontextprotocol/sdk/shared/transport.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 name: string;\n transport: Transport;\n onTransportError?: (error: Error) => void;\n};\n\nexport class UpstreamClient {\n private readonly transport: Transport;\n private readonly onTransportError: (error: Error) => void;\n private client: Client | null = null;\n\n constructor({ name, transport, onTransportError }: UpstreamClientConfig) {\n this.transport = transport;\n this.onTransportError =\n onTransportError ??\n ((error: Error) => {\n process.stderr.write(`[${name}] Upstream MCP transport error: ${error.message}\\n`);\n });\n }\n\n async connect(): Promise<void> {\n this.transport.onerror = this.onTransportError;\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 const result = await this.client.callTool({ name, arguments: input });\n return result as 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 }\n}\n","import type { Transport } from \"@modelcontextprotocol/sdk/shared/transport.js\";\nimport type { ContentResult } from \"fastmcp\";\nimport { ToolCatalog } from \"./tool-catalog.js\";\nimport { UpstreamClient } from \"./upstream-client.js\";\n\nexport type OrchestratorConfig = {\n mcps: Map<string, { transport: Transport }>;\n onTransportError?: (mcpName: string, error: Error) => void;\n};\n\nexport class Orchestrator {\n private readonly config: OrchestratorConfig;\n private readonly clients: Map<string, UpstreamClient> = new Map();\n private toolCatalog: ToolCatalog | null = null;\n\n constructor(config: OrchestratorConfig) {\n this.config = config;\n }\n\n async connect(): Promise<void> {\n const groups = new Map<string, import(\"./upstream-client.js\").UpstreamTool[]>();\n\n try {\n for (const [mcpName, { transport }] of this.config.mcps) {\n const client = new UpstreamClient({\n name: mcpName,\n transport,\n onTransportError: (error: Error) => {\n this.config.onTransportError?.(mcpName, error);\n },\n });\n\n await client.connect();\n const tools = await client.listTools();\n\n this.clients.set(mcpName, client);\n groups.set(mcpName, tools);\n }\n } catch (error) {\n await this.disconnectAll();\n throw error;\n }\n\n this.toolCatalog = ToolCatalog.fromGrouped(groups);\n }\n\n get catalog(): ToolCatalog {\n if (this.toolCatalog === null) {\n throw new Error(\"Orchestrator is not connected. Call connect() first.\");\n }\n return this.toolCatalog;\n }\n\n async callTool(namespacedName: string, input: Record<string, unknown>): Promise<ContentResult> {\n const separatorIndex = namespacedName.indexOf(\"/\");\n if (separatorIndex === -1) {\n throw new Error(\n `Invalid namespaced tool name: \"${namespacedName}\". Expected format: \"mcpName/toolName\".`,\n );\n }\n\n const mcpName = namespacedName.slice(0, separatorIndex);\n const toolName = namespacedName.slice(separatorIndex + 1);\n\n const client = this.clients.get(mcpName);\n if (client === undefined) {\n const available = [...this.clients.keys()].sort().join(\", \");\n throw new Error(`Unknown MCP: \"${mcpName}\". Available MCPs: ${available}`);\n }\n\n return client.callTool(toolName, input);\n }\n\n async disconnectAll(): Promise<void> {\n const disconnections = [...this.clients.values()].map(client => client.disconnect());\n await Promise.all(disconnections);\n this.clients.clear();\n this.toolCatalog = null;\n }\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 { ContentResult } from \"fastmcp\";\nimport type { ToolCatalog } from \"./tool-catalog.js\";\n\ntype ToolCaller = (name: string, input: Record<string, unknown>) => Promise<ContentResult>;\n\ntype ProxyServerConfig = {\n catalog: ToolCatalog;\n callTool: ToolCaller;\n};\n\nexport class ProxyServer {\n private readonly catalog: ToolCatalog;\n private readonly callTool: ToolCaller;\n\n constructor({ catalog, callTool }: ProxyServerConfig) {\n this.catalog = catalog;\n this.callTool = callTool;\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.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 { 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","StdioClientTransport","existsSync","readFileSync","resolve","process","resolve","existsSync","process","readFileSync","z","mcpName","process","mcpName","process","z","z","process","StdioClientTransport","process","mcpName","process","process"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dynmcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Dynamic MCP context management tool for AI MCP-enabled agents and clients.",
|
|
5
5
|
"author": "Brandon Burrus <brandon@burrus.io>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -67,6 +67,7 @@
|
|
|
67
67
|
"boxen": "^8.0.1",
|
|
68
68
|
"chalk": "^5.6.2",
|
|
69
69
|
"commander": "^14.0.3",
|
|
70
|
+
"dotenv": "^17.4.2",
|
|
70
71
|
"enquirer": "^2.4.1",
|
|
71
72
|
"fastmcp": "^4.0.1",
|
|
72
73
|
"figlet": "^1.11.0",
|
package/schema/mcp-config.json
CHANGED
|
@@ -5,6 +5,16 @@
|
|
|
5
5
|
"description": "Configuration file for dynmcp. Declares the set of upstream MCPs to proxy through dynamic-discovery-mcp.",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"properties": {
|
|
8
|
+
"env": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"enum": [
|
|
11
|
+
"enable",
|
|
12
|
+
"dotenv",
|
|
13
|
+
"process",
|
|
14
|
+
"disable"
|
|
15
|
+
],
|
|
16
|
+
"description": "Controls environment variable interpolation in config values. \"enable\" (default) merges .env and process.env (.env wins). \"dotenv\" loads .env only. \"process\" uses process.env only. \"disable\" turns interpolation off."
|
|
17
|
+
},
|
|
8
18
|
"mcp": {
|
|
9
19
|
"type": "object",
|
|
10
20
|
"propertyNames": {
|