@wunderio/wdrmcp 0.1.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.
Files changed (43) hide show
  1. package/LICENSE +185 -0
  2. package/README.md +141 -0
  3. package/dist/config.d.ts +6 -0
  4. package/dist/config.d.ts.map +1 -0
  5. package/dist/config.js +59 -0
  6. package/dist/config.js.map +1 -0
  7. package/dist/docker.d.ts +34 -0
  8. package/dist/docker.d.ts.map +1 -0
  9. package/dist/docker.js +115 -0
  10. package/dist/docker.js.map +1 -0
  11. package/dist/executors/base.d.ts +2 -0
  12. package/dist/executors/base.d.ts.map +1 -0
  13. package/dist/executors/base.js +4 -0
  14. package/dist/executors/base.js.map +1 -0
  15. package/dist/executors/command.d.ts +37 -0
  16. package/dist/executors/command.d.ts.map +1 -0
  17. package/dist/executors/command.js +107 -0
  18. package/dist/executors/command.js.map +1 -0
  19. package/dist/executors/mcp-proxy.d.ts +58 -0
  20. package/dist/executors/mcp-proxy.d.ts.map +1 -0
  21. package/dist/executors/mcp-proxy.js +152 -0
  22. package/dist/executors/mcp-proxy.js.map +1 -0
  23. package/dist/index.d.ts +14 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +46 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/logger.d.ts +18 -0
  28. package/dist/logger.d.ts.map +1 -0
  29. package/dist/logger.js +70 -0
  30. package/dist/logger.js.map +1 -0
  31. package/dist/registry.d.ts +42 -0
  32. package/dist/registry.d.ts.map +1 -0
  33. package/dist/registry.js +240 -0
  34. package/dist/registry.js.map +1 -0
  35. package/dist/server.d.ts +12 -0
  36. package/dist/server.d.ts.map +1 -0
  37. package/dist/server.js +54 -0
  38. package/dist/server.js.map +1 -0
  39. package/dist/types.d.ts +98 -0
  40. package/dist/types.d.ts.map +1 -0
  41. package/dist/types.js +5 -0
  42. package/dist/types.js.map +1 -0
  43. package/package.json +51 -0
@@ -0,0 +1,107 @@
1
+ /**
2
+ * CommandToolExecutor — executes shell commands in Docker containers
3
+ * with argument substitution ({placeholder} syntax).
4
+ *
5
+ * Refactored from the Python version with these improvements:
6
+ * - Static safety checks happen at construction time (not per-call)
7
+ * - Container validation and UID resolution are cached in docker.ts
8
+ * - Path normalization is an external preprocessor (not baked in)
9
+ * - No abstract base class; implements ToolExecutor interface directly
10
+ */
11
+ import { dockerExec, validateContainer, validateStaticSafety, resolveContainerUser, } from "../docker.js";
12
+ import { getLogger } from "../logger.js";
13
+ export class CommandToolExecutor {
14
+ commandTemplate;
15
+ container;
16
+ ddevProject;
17
+ user;
18
+ shell;
19
+ defaultArgs;
20
+ disallowedCommands;
21
+ validationRules;
22
+ constructor(options) {
23
+ this.commandTemplate = options.commandTemplate;
24
+ this.container = options.container;
25
+ this.ddevProject = options.ddevProject;
26
+ this.user = options.user ?? "www-data";
27
+ this.shell = options.shell ?? "/bin/bash";
28
+ this.defaultArgs = options.defaultArgs ?? {};
29
+ this.disallowedCommands = new Set(options.disallowedCommands ?? []);
30
+ this.validationRules = options.validationRules ?? [];
31
+ // Static safety: validate shell and flag at construction, not per-call.
32
+ validateStaticSafety([this.shell, "-c"]);
33
+ }
34
+ async execute(args) {
35
+ const log = getLogger();
36
+ // Resolve user (cached after first call).
37
+ const user = await resolveContainerUser(this.user, this.container);
38
+ // Merge with defaults.
39
+ const mergedArgs = { ...this.defaultArgs, ...args };
40
+ // Check disallowed commands.
41
+ if (typeof mergedArgs.command === "string" && this.disallowedCommands.has(mergedArgs.command)) {
42
+ log.warn(`Blocked disallowed command: ${mergedArgs.command}`);
43
+ return { content: `Error: Command '${mergedArgs.command}' is not allowed`, isError: true };
44
+ }
45
+ // Substitute arguments into template.
46
+ let cmdStr;
47
+ try {
48
+ cmdStr = this.commandTemplate.replace(/\{(\w+)\}/g, (_match, key) => {
49
+ if (key in mergedArgs)
50
+ return String(mergedArgs[key]);
51
+ throw new Error(`Missing required argument: ${key}`);
52
+ });
53
+ }
54
+ catch (e) {
55
+ return { content: `Error: ${e.message}`, isError: true };
56
+ }
57
+ // Validate rendered command against rules.
58
+ const ruleError = this.checkRules(cmdStr);
59
+ if (ruleError) {
60
+ return { content: `Validation error: ${ruleError}`, isError: true };
61
+ }
62
+ // Validate container ownership (cached after first call).
63
+ try {
64
+ await validateContainer(this.container, this.ddevProject);
65
+ }
66
+ catch (e) {
67
+ log.warn(`Container validation: ${e.message}`);
68
+ }
69
+ // Execute in Docker container.
70
+ try {
71
+ log.info(`EXEC: ${this.container} as ${user}: ${this.shell} -c ...`);
72
+ const output = await dockerExec({
73
+ container: this.container,
74
+ command: [cmdStr],
75
+ user,
76
+ shell: this.shell,
77
+ });
78
+ return { content: output.trim() };
79
+ }
80
+ catch (e) {
81
+ return { content: `Execution failed: ${e.message}`, isError: true };
82
+ }
83
+ }
84
+ validateArguments(args) {
85
+ // Check validation rules against stringified arguments.
86
+ const ruleError = this.checkRules(JSON.stringify(args));
87
+ if (ruleError)
88
+ throw new Error(ruleError);
89
+ // Verify required placeholders are provided.
90
+ const placeholders = new Set([...this.commandTemplate.matchAll(/\{(\w+)\}/g)].map((m) => m[1]));
91
+ const provided = new Set([...Object.keys(this.defaultArgs), ...Object.keys(args)]);
92
+ const missing = [...placeholders].filter((p) => !provided.has(p));
93
+ if (missing.length > 0) {
94
+ throw new Error(`Missing required arguments: ${missing.join(", ")}`);
95
+ }
96
+ }
97
+ /** Check validation rules against a value. Returns error message or null. */
98
+ checkRules(value) {
99
+ for (const rule of this.validationRules) {
100
+ if (rule.pattern && new RegExp(rule.pattern).test(value)) {
101
+ return rule.message ?? `Validation failed for pattern: ${rule.pattern}`;
102
+ }
103
+ }
104
+ return null;
105
+ }
106
+ }
107
+ //# sourceMappingURL=command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command.js","sourceRoot":"","sources":["../../src/executors/command.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * MCP proxy executors — proxy tool calls to external MCP servers via HTTP.
3
+ *
4
+ * McpProxyExecutor: handles HTTP transport, auth, and remote tool discovery.
5
+ * BoundRemoteToolExecutor: a thin wrapper that binds a specific remote tool
6
+ * name, so the registry doesn't need special-case logic for proxied tools.
7
+ */
8
+ import type { ToolExecutionResult, ToolExecutor } from "../types.js";
9
+ /** Remote tool definition as returned by tools/list. */
10
+ export interface RemoteToolDefinition {
11
+ name: string;
12
+ description?: string;
13
+ inputSchema?: Record<string, unknown>;
14
+ }
15
+ export interface McpProxyOptions {
16
+ serverUrl: string;
17
+ forwardArgs?: boolean;
18
+ timeout?: number;
19
+ authUsername?: string;
20
+ authPassword?: string;
21
+ authToken?: string;
22
+ authTokenBasic?: boolean;
23
+ verifySsl?: boolean;
24
+ }
25
+ export declare class McpProxyExecutor implements ToolExecutor {
26
+ private readonly serverUrl;
27
+ private readonly forwardArgs;
28
+ private readonly timeout;
29
+ private readonly headers;
30
+ constructor(options: McpProxyOptions);
31
+ /** Fetch available tools from the remote MCP server via tools/list. */
32
+ fetchRemoteTools(): Promise<RemoteToolDefinition[]>;
33
+ /** Execute a direct (non-proxied) tool call. */
34
+ execute(args: Record<string, unknown>): Promise<ToolExecutionResult>;
35
+ /**
36
+ * Call a specific tool on the remote MCP server by name.
37
+ * Used by BoundRemoteToolExecutor.
38
+ */
39
+ callTool(args: Record<string, unknown>, toolName?: string): Promise<ToolExecutionResult>;
40
+ validateArguments(_args: Record<string, unknown>): void;
41
+ /** Send a JSON-RPC request to the remote server. */
42
+ private rpc;
43
+ /** Parse a JSON-RPC response into a ToolExecutionResult. */
44
+ private parseResponse;
45
+ }
46
+ /**
47
+ * A thin wrapper that binds a specific remote tool name to a McpProxyExecutor.
48
+ * This eliminates the need for the registry to track "originalName" separately.
49
+ * Each remote tool gets its own BoundRemoteToolExecutor instance.
50
+ */
51
+ export declare class BoundRemoteToolExecutor implements ToolExecutor {
52
+ private readonly proxy;
53
+ private readonly remoteToolName;
54
+ constructor(proxy: McpProxyExecutor, remoteToolName: string);
55
+ execute(args: Record<string, unknown>): Promise<ToolExecutionResult>;
56
+ validateArguments(_args: Record<string, unknown>): void;
57
+ }
58
+ //# sourceMappingURL=mcp-proxy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-proxy.d.ts","sourceRoot":"","sources":["../../src/executors/mcp-proxy.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAErE,wDAAwD;AACxD,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,qBAAa,gBAAiB,YAAW,YAAY;IACnD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAU;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyB;gBAErC,OAAO,EAAE,eAAe;IAqBpC,uEAAuE;IACjE,gBAAgB,IAAI,OAAO,CAAC,oBAAoB,EAAE,CAAC;IA2BzD,gDAAgD;IAC1C,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAI1E;;;OAGG;IACG,QAAQ,CACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,mBAAmB,CAAC;IA0B/B,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAIvD,oDAAoD;YACtC,GAAG;IAoBjB,4DAA4D;IAC5D,OAAO,CAAC,aAAa;CAoBtB;AAED;;;;GAIG;AACH,qBAAa,uBAAwB,YAAW,YAAY;IAExD,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,cAAc;gBADd,KAAK,EAAE,gBAAgB,EACvB,cAAc,EAAE,MAAM;IAGnC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAI1E,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;CAGxD"}
@@ -0,0 +1,152 @@
1
+ /**
2
+ * MCP proxy executors — proxy tool calls to external MCP servers via HTTP.
3
+ *
4
+ * McpProxyExecutor: handles HTTP transport, auth, and remote tool discovery.
5
+ * BoundRemoteToolExecutor: a thin wrapper that binds a specific remote tool
6
+ * name, so the registry doesn't need special-case logic for proxied tools.
7
+ */
8
+ import { getLogger } from "../logger.js";
9
+ export class McpProxyExecutor {
10
+ serverUrl;
11
+ forwardArgs;
12
+ timeout;
13
+ headers;
14
+ constructor(options) {
15
+ this.serverUrl = options.serverUrl;
16
+ this.forwardArgs = options.forwardArgs ?? true;
17
+ this.timeout = (options.timeout ?? 10) * 1000;
18
+ this.headers = { "Content-Type": "application/json" };
19
+ if (options.authToken) {
20
+ if (options.authTokenBasic) {
21
+ const encoded = Buffer.from(options.authToken).toString("base64");
22
+ this.headers["Authorization"] = `Basic ${encoded}`;
23
+ }
24
+ else {
25
+ this.headers["Authorization"] = `Bearer ${options.authToken}`;
26
+ }
27
+ }
28
+ else if (options.authUsername && options.authPassword) {
29
+ const encoded = Buffer.from(`${options.authUsername}:${options.authPassword}`).toString("base64");
30
+ this.headers["Authorization"] = `Basic ${encoded}`;
31
+ }
32
+ }
33
+ /** Fetch available tools from the remote MCP server via tools/list. */
34
+ async fetchRemoteTools() {
35
+ const log = getLogger();
36
+ log.info(`Fetching remote tools from ${this.serverUrl}`);
37
+ try {
38
+ const result = await this.rpc("tools/list", {});
39
+ let tools;
40
+ if (Array.isArray(result)) {
41
+ tools = result;
42
+ }
43
+ else if (typeof result === "object" && result !== null) {
44
+ const r = result;
45
+ const raw = r.tools ?? r.result?.tools ?? [];
46
+ tools = (Array.isArray(raw) ? raw : []);
47
+ }
48
+ else {
49
+ log.warn(`Unexpected response format from ${this.serverUrl}`);
50
+ return [];
51
+ }
52
+ log.info(`Fetched ${tools.length} tools from ${this.serverUrl}`);
53
+ return tools;
54
+ }
55
+ catch (e) {
56
+ log.error(`Failed to fetch tools from ${this.serverUrl}: ${e}`);
57
+ return [];
58
+ }
59
+ }
60
+ /** Execute a direct (non-proxied) tool call. */
61
+ async execute(args) {
62
+ return this.callTool(args);
63
+ }
64
+ /**
65
+ * Call a specific tool on the remote MCP server by name.
66
+ * Used by BoundRemoteToolExecutor.
67
+ */
68
+ async callTool(args, toolName) {
69
+ try {
70
+ let payload;
71
+ if (toolName) {
72
+ payload = { method: "tools/call", params: { name: toolName, arguments: args } };
73
+ }
74
+ else if (typeof args.method === "string") {
75
+ payload = { method: args.method, params: args.params ?? {} };
76
+ }
77
+ else {
78
+ payload = this.forwardArgs ? args : {};
79
+ }
80
+ const result = await this.rpc(payload.method, payload.params);
81
+ return this.parseResponse(result);
82
+ }
83
+ catch (e) {
84
+ if (e.name === "AbortError") {
85
+ return { content: `Request timeout after ${this.timeout / 1000}s`, isError: true };
86
+ }
87
+ getLogger().error(`MCP proxy error: ${e}`);
88
+ return { content: `Error: ${e.message}`, isError: true };
89
+ }
90
+ }
91
+ validateArguments(_args) {
92
+ // Remote servers handle their own validation.
93
+ }
94
+ /** Send a JSON-RPC request to the remote server. */
95
+ async rpc(method, params) {
96
+ const controller = new AbortController();
97
+ const timer = setTimeout(() => controller.abort(), this.timeout);
98
+ try {
99
+ const response = await fetch(this.serverUrl, {
100
+ method: "POST",
101
+ headers: this.headers,
102
+ body: JSON.stringify({ jsonrpc: "2.0", method, params, id: 1 }),
103
+ signal: controller.signal,
104
+ });
105
+ if (!response.ok) {
106
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
107
+ }
108
+ return response.json();
109
+ }
110
+ finally {
111
+ clearTimeout(timer);
112
+ }
113
+ }
114
+ /** Parse a JSON-RPC response into a ToolExecutionResult. */
115
+ parseResponse(result) {
116
+ if (typeof result !== "object" || result === null || Array.isArray(result)) {
117
+ return { content: typeof result === "string" ? result : JSON.stringify(result) };
118
+ }
119
+ const r = result;
120
+ if ("result" in r)
121
+ return { content: String(r.result) };
122
+ const content = r.content;
123
+ if (Array.isArray(content) && content.length > 0) {
124
+ return { content: content[0].text ?? JSON.stringify(result) };
125
+ }
126
+ if ("error" in r) {
127
+ const err = r.error;
128
+ return { content: `RPC Error: ${err.message ?? String(err)}`, isError: true };
129
+ }
130
+ return { content: JSON.stringify(result) };
131
+ }
132
+ }
133
+ /**
134
+ * A thin wrapper that binds a specific remote tool name to a McpProxyExecutor.
135
+ * This eliminates the need for the registry to track "originalName" separately.
136
+ * Each remote tool gets its own BoundRemoteToolExecutor instance.
137
+ */
138
+ export class BoundRemoteToolExecutor {
139
+ proxy;
140
+ remoteToolName;
141
+ constructor(proxy, remoteToolName) {
142
+ this.proxy = proxy;
143
+ this.remoteToolName = remoteToolName;
144
+ }
145
+ async execute(args) {
146
+ return this.proxy.callTool(args, this.remoteToolName);
147
+ }
148
+ validateArguments(_args) {
149
+ // Remote server handles validation.
150
+ }
151
+ }
152
+ //# sourceMappingURL=mcp-proxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-proxy.js","sourceRoot":"","sources":["../../src/executors/mcp-proxy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * WDRMCP — CLI entry point.
4
+ *
5
+ * A generic MCP server that dynamically loads tool definitions from YAML
6
+ * configuration files and executes them in Docker containers or proxies
7
+ * them to remote MCP servers.
8
+ *
9
+ * Usage:
10
+ * wdrmcp --tools-config /path/to/tools-config
11
+ * npx @wunderio/wdrmcp --tools-config /path/to/tools-config
12
+ */
13
+ export {};
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;GAUG"}
package/dist/index.js ADDED
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * WDRMCP — CLI entry point.
4
+ *
5
+ * A generic MCP server that dynamically loads tool definitions from YAML
6
+ * configuration files and executes them in Docker containers or proxies
7
+ * them to remote MCP servers.
8
+ *
9
+ * Usage:
10
+ * wdrmcp --tools-config /path/to/tools-config
11
+ * npx @wunderio/wdrmcp --tools-config /path/to/tools-config
12
+ */
13
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
14
+ import { parseArgs } from "./config.js";
15
+ import { initLogger, getLogger } from "./logger.js";
16
+ import { ToolRegistry } from "./registry.js";
17
+ import { createMcpServer } from "./server.js";
18
+ async function main() {
19
+ // Parse CLI arguments.
20
+ const config = parseArgs(process.argv);
21
+ // Initialize logger (stderr only — stdout is reserved for JSON-RPC).
22
+ initLogger(config.logLevel, config.logFile);
23
+ const log = getLogger();
24
+ try {
25
+ log.info("Starting WDRMCP (YAML Configuration MCP Server)");
26
+ log.info(`Tools config path: ${config.toolsConfigPath}`);
27
+ log.info(`DDEV project: ${config.ddevProject}`);
28
+ // Load tools from YAML configuration files.
29
+ const registry = new ToolRegistry(config.toolsConfigPath, config);
30
+ const toolCount = await registry.loadTools();
31
+ if (toolCount === 0) {
32
+ log.warn("No tools loaded! Check the tools-config directory.");
33
+ }
34
+ // Create and start the MCP server.
35
+ const server = createMcpServer(registry);
36
+ const transport = new StdioServerTransport();
37
+ await server.connect(transport);
38
+ log.info("WDRMCP server running on stdio");
39
+ }
40
+ catch (e) {
41
+ log.error(`Fatal error: ${e}`);
42
+ process.exit(1);
43
+ }
44
+ }
45
+ main();
46
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,KAAK,UAAU,IAAI;IACjB,uBAAuB;IACvB,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvC,qEAAqE;IACrE,UAAU,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAC5C,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;IAExB,IAAI,CAAC;QACH,GAAG,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;QAC5D,GAAG,CAAC,IAAI,CAAC,sBAAsB,MAAM,CAAC,eAAe,EAAE,CAAC,CAAC;QACzD,GAAG,CAAC,IAAI,CAAC,iBAAiB,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;QAEhD,4CAA4C;QAC5C,MAAM,QAAQ,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;QAClE,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,SAAS,EAAE,CAAC;QAE7C,IAAI,SAAS,KAAK,CAAC,EAAE,CAAC;YACpB,GAAG,CAAC,IAAI,CAAC,oDAAoD,CAAC,CAAC;QACjE,CAAC;QAED,mCAAmC;QACnC,MAAM,MAAM,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;QACzC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;QAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAEhC,GAAG,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;IAC7C,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;QAC/B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Logger that writes exclusively to stderr (stdout is reserved for JSON-RPC).
3
+ * Optionally writes to a log file.
4
+ */
5
+ export type LogLevel = "debug" | "info" | "warn" | "error";
6
+ export declare class Logger {
7
+ private level;
8
+ private logFile?;
9
+ constructor(level?: LogLevel, logFile?: string);
10
+ private log;
11
+ debug(message: string, ...args: unknown[]): void;
12
+ info(message: string, ...args: unknown[]): void;
13
+ warn(message: string, ...args: unknown[]): void;
14
+ error(message: string, ...args: unknown[]): void;
15
+ }
16
+ export declare function initLogger(level?: LogLevel, logFile?: string): Logger;
17
+ export declare function getLogger(): Logger;
18
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAS3D,qBAAa,MAAM;IACjB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,OAAO,CAAC,CAAS;gBAEb,KAAK,GAAE,QAAiB,EAAE,OAAO,CAAC,EAAE,MAAM;IActD,OAAO,CAAC,GAAG;IAuBX,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAIhD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAI/C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAI/C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;CAGjD;AAKD,wBAAgB,UAAU,CAAC,KAAK,GAAE,QAAiB,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAG7E;AAED,wBAAgB,SAAS,IAAI,MAAM,CAElC"}
package/dist/logger.js ADDED
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Logger that writes exclusively to stderr (stdout is reserved for JSON-RPC).
3
+ * Optionally writes to a log file.
4
+ */
5
+ import { appendFileSync, writeFileSync } from "node:fs";
6
+ const LOG_LEVELS = {
7
+ debug: 0,
8
+ info: 1,
9
+ warn: 2,
10
+ error: 3,
11
+ };
12
+ export class Logger {
13
+ level;
14
+ logFile;
15
+ constructor(level = "info", logFile) {
16
+ this.level = LOG_LEVELS[level];
17
+ this.logFile = logFile;
18
+ // Truncate log file on start.
19
+ if (this.logFile) {
20
+ try {
21
+ writeFileSync(this.logFile, "");
22
+ }
23
+ catch {
24
+ // Ignore if we can't create the log file.
25
+ }
26
+ }
27
+ }
28
+ log(level, message, ...args) {
29
+ if (LOG_LEVELS[level] < this.level)
30
+ return;
31
+ const timestamp = new Date().toISOString();
32
+ const formatted = `${timestamp} - wdrmcp - ${level.toUpperCase()} - ${message}`;
33
+ // Always write to stderr (never stdout).
34
+ console.error(formatted, ...args);
35
+ // Optionally write to file.
36
+ if (this.logFile) {
37
+ try {
38
+ const fileMsg = args.length > 0
39
+ ? `${formatted} ${args.map((a) => (typeof a === "string" ? a : JSON.stringify(a))).join(" ")}\n`
40
+ : `${formatted}\n`;
41
+ appendFileSync(this.logFile, fileMsg);
42
+ }
43
+ catch {
44
+ // Ignore file write errors.
45
+ }
46
+ }
47
+ }
48
+ debug(message, ...args) {
49
+ this.log("debug", message, ...args);
50
+ }
51
+ info(message, ...args) {
52
+ this.log("info", message, ...args);
53
+ }
54
+ warn(message, ...args) {
55
+ this.log("warn", message, ...args);
56
+ }
57
+ error(message, ...args) {
58
+ this.log("error", message, ...args);
59
+ }
60
+ }
61
+ /** Singleton logger instance — call `initLogger()` to configure. */
62
+ let logger = new Logger();
63
+ export function initLogger(level = "info", logFile) {
64
+ logger = new Logger(level, logFile);
65
+ return logger;
66
+ }
67
+ export function getLogger() {
68
+ return logger;
69
+ }
70
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * ToolRegistry — loads tool definitions from YAML config files
3
+ * and creates the appropriate executors.
4
+ *
5
+ * Refactored improvements:
6
+ * - BoundRemoteToolExecutor eliminates the originalName workaround
7
+ * - Path normalization is an arg preprocessor, not baked into executors
8
+ * - All tools go through a uniform execute path (no special-casing)
9
+ */
10
+ import type { BridgeConfig, ToolExecutionResult, RegisteredTool } from "./types.js";
11
+ export declare class ToolRegistry {
12
+ private readonly toolsConfigDir;
13
+ private readonly config;
14
+ private readonly tools;
15
+ private readonly argPreprocessor;
16
+ constructor(toolsConfigDir: string, config: BridgeConfig);
17
+ /**
18
+ * Load all tools from YAML config files. Returns tool count.
19
+ */
20
+ loadTools(): Promise<number>;
21
+ private loadSingleTool;
22
+ /**
23
+ * Fetch remote tools and register each with a BoundRemoteToolExecutor.
24
+ * No "originalName" tracking needed — the binding is in the executor itself.
25
+ */
26
+ private loadRemoteMcpTools;
27
+ private interpolateContainerName;
28
+ private createExecutor;
29
+ getToolNames(): string[];
30
+ getTool(name: string): RegisteredTool | undefined;
31
+ getAllTools(): Map<string, RegisteredTool>;
32
+ /**
33
+ * Execute a tool. Applies arg preprocessing (path normalization)
34
+ * then delegates to the executor. No special-casing needed.
35
+ */
36
+ executeTool(name: string, args: Record<string, unknown>): Promise<ToolExecutionResult>;
37
+ /**
38
+ * Recursively normalize devcontainer paths to container paths in argument values.
39
+ */
40
+ private normalizePaths;
41
+ }
42
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AASH,OAAO,KAAK,EACV,YAAY,EAIZ,mBAAmB,EACnB,cAAc,EAIf,MAAM,YAAY,CAAC;AAEpB,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IACtC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA0C;IAChE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkB;gBAEtC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY;IAWxD;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC;YAgCpB,cAAc;IAoB5B;;;OAGG;YACW,kBAAkB;IAmDhC,OAAO,CAAC,wBAAwB;IAMhC,OAAO,CAAC,cAAc;IAgDtB,YAAY,IAAI,MAAM,EAAE;IACxB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IACjD,WAAW,IAAI,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC;IAE1C;;;OAGG;IACG,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAwB5F;;OAEG;IACH,OAAO,CAAC,cAAc;CAsBvB"}