windows-exe-decompiler-mcp-server 0.1.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.
Files changed (190) hide show
  1. package/CODEX_INSTALLATION.md +69 -0
  2. package/COPILOT_INSTALLATION.md +77 -0
  3. package/LICENSE +21 -0
  4. package/README.md +314 -0
  5. package/bin/windows-exe-decompiler-mcp-server.js +3 -0
  6. package/dist/analysis-provenance.d.ts +184 -0
  7. package/dist/analysis-provenance.js +74 -0
  8. package/dist/analysis-task-runner.d.ts +31 -0
  9. package/dist/analysis-task-runner.js +160 -0
  10. package/dist/artifact-inventory.d.ts +23 -0
  11. package/dist/artifact-inventory.js +175 -0
  12. package/dist/cache-manager.d.ts +128 -0
  13. package/dist/cache-manager.js +454 -0
  14. package/dist/confidence-semantics.d.ts +66 -0
  15. package/dist/confidence-semantics.js +122 -0
  16. package/dist/config.d.ts +335 -0
  17. package/dist/config.js +193 -0
  18. package/dist/database.d.ts +227 -0
  19. package/dist/database.js +601 -0
  20. package/dist/decompiler-worker.d.ts +441 -0
  21. package/dist/decompiler-worker.js +1962 -0
  22. package/dist/dynamic-trace.d.ts +95 -0
  23. package/dist/dynamic-trace.js +629 -0
  24. package/dist/env-validator.d.ts +15 -0
  25. package/dist/env-validator.js +249 -0
  26. package/dist/error-handler.d.ts +28 -0
  27. package/dist/error-handler.example.d.ts +22 -0
  28. package/dist/error-handler.example.js +141 -0
  29. package/dist/error-handler.js +139 -0
  30. package/dist/ghidra-analysis-status.d.ts +49 -0
  31. package/dist/ghidra-analysis-status.js +178 -0
  32. package/dist/ghidra-config.d.ts +134 -0
  33. package/dist/ghidra-config.js +464 -0
  34. package/dist/index.d.ts +9 -0
  35. package/dist/index.js +200 -0
  36. package/dist/job-queue.d.ts +169 -0
  37. package/dist/job-queue.js +407 -0
  38. package/dist/logger.d.ts +106 -0
  39. package/dist/logger.js +176 -0
  40. package/dist/policy-guard.d.ts +115 -0
  41. package/dist/policy-guard.js +243 -0
  42. package/dist/process-output.d.ts +15 -0
  43. package/dist/process-output.js +90 -0
  44. package/dist/prompts/function-explanation-review.d.ts +5 -0
  45. package/dist/prompts/function-explanation-review.js +64 -0
  46. package/dist/prompts/semantic-name-review.d.ts +5 -0
  47. package/dist/prompts/semantic-name-review.js +63 -0
  48. package/dist/runtime-correlation.d.ts +34 -0
  49. package/dist/runtime-correlation.js +279 -0
  50. package/dist/runtime-paths.d.ts +3 -0
  51. package/dist/runtime-paths.js +11 -0
  52. package/dist/selection-diff.d.ts +667 -0
  53. package/dist/selection-diff.js +53 -0
  54. package/dist/semantic-name-suggestion-artifacts.d.ts +116 -0
  55. package/dist/semantic-name-suggestion-artifacts.js +314 -0
  56. package/dist/server.d.ts +129 -0
  57. package/dist/server.js +578 -0
  58. package/dist/tools/artifact-read.d.ts +235 -0
  59. package/dist/tools/artifact-read.js +317 -0
  60. package/dist/tools/artifacts-diff.d.ts +728 -0
  61. package/dist/tools/artifacts-diff.js +304 -0
  62. package/dist/tools/artifacts-list.d.ts +515 -0
  63. package/dist/tools/artifacts-list.js +389 -0
  64. package/dist/tools/attack-map.d.ts +290 -0
  65. package/dist/tools/attack-map.js +519 -0
  66. package/dist/tools/cache-observability.d.ts +4 -0
  67. package/dist/tools/cache-observability.js +36 -0
  68. package/dist/tools/code-function-cfg.d.ts +50 -0
  69. package/dist/tools/code-function-cfg.js +102 -0
  70. package/dist/tools/code-function-decompile.d.ts +55 -0
  71. package/dist/tools/code-function-decompile.js +103 -0
  72. package/dist/tools/code-function-disassemble.d.ts +43 -0
  73. package/dist/tools/code-function-disassemble.js +185 -0
  74. package/dist/tools/code-function-explain-apply.d.ts +255 -0
  75. package/dist/tools/code-function-explain-apply.js +225 -0
  76. package/dist/tools/code-function-explain-prepare.d.ts +535 -0
  77. package/dist/tools/code-function-explain-prepare.js +276 -0
  78. package/dist/tools/code-function-explain-review.d.ts +397 -0
  79. package/dist/tools/code-function-explain-review.js +589 -0
  80. package/dist/tools/code-function-rename-apply.d.ts +248 -0
  81. package/dist/tools/code-function-rename-apply.js +220 -0
  82. package/dist/tools/code-function-rename-prepare.d.ts +506 -0
  83. package/dist/tools/code-function-rename-prepare.js +279 -0
  84. package/dist/tools/code-function-rename-review.d.ts +574 -0
  85. package/dist/tools/code-function-rename-review.js +761 -0
  86. package/dist/tools/code-functions-list.d.ts +37 -0
  87. package/dist/tools/code-functions-list.js +91 -0
  88. package/dist/tools/code-functions-rank.d.ts +34 -0
  89. package/dist/tools/code-functions-rank.js +90 -0
  90. package/dist/tools/code-functions-reconstruct.d.ts +2725 -0
  91. package/dist/tools/code-functions-reconstruct.js +2807 -0
  92. package/dist/tools/code-functions-search.d.ts +39 -0
  93. package/dist/tools/code-functions-search.js +90 -0
  94. package/dist/tools/code-reconstruct-export.d.ts +1212 -0
  95. package/dist/tools/code-reconstruct-export.js +4002 -0
  96. package/dist/tools/code-reconstruct-plan.d.ts +274 -0
  97. package/dist/tools/code-reconstruct-plan.js +342 -0
  98. package/dist/tools/dotnet-metadata-extract.d.ts +541 -0
  99. package/dist/tools/dotnet-metadata-extract.js +355 -0
  100. package/dist/tools/dotnet-reconstruct-export.d.ts +567 -0
  101. package/dist/tools/dotnet-reconstruct-export.js +1151 -0
  102. package/dist/tools/dotnet-types-list.d.ts +325 -0
  103. package/dist/tools/dotnet-types-list.js +201 -0
  104. package/dist/tools/dynamic-dependencies.d.ts +115 -0
  105. package/dist/tools/dynamic-dependencies.js +213 -0
  106. package/dist/tools/dynamic-memory-import.d.ts +10 -0
  107. package/dist/tools/dynamic-memory-import.js +567 -0
  108. package/dist/tools/dynamic-trace-import.d.ts +10 -0
  109. package/dist/tools/dynamic-trace-import.js +235 -0
  110. package/dist/tools/entrypoint-fallback-disasm.d.ts +30 -0
  111. package/dist/tools/entrypoint-fallback-disasm.js +89 -0
  112. package/dist/tools/ghidra-analyze.d.ts +88 -0
  113. package/dist/tools/ghidra-analyze.js +208 -0
  114. package/dist/tools/ghidra-health.d.ts +37 -0
  115. package/dist/tools/ghidra-health.js +212 -0
  116. package/dist/tools/ioc-export.d.ts +209 -0
  117. package/dist/tools/ioc-export.js +542 -0
  118. package/dist/tools/packer-detect.d.ts +165 -0
  119. package/dist/tools/packer-detect.js +284 -0
  120. package/dist/tools/pe-exports-extract.d.ts +175 -0
  121. package/dist/tools/pe-exports-extract.js +253 -0
  122. package/dist/tools/pe-fingerprint.d.ts +234 -0
  123. package/dist/tools/pe-fingerprint.js +269 -0
  124. package/dist/tools/pe-imports-extract.d.ts +105 -0
  125. package/dist/tools/pe-imports-extract.js +245 -0
  126. package/dist/tools/report-generate.d.ts +157 -0
  127. package/dist/tools/report-generate.js +457 -0
  128. package/dist/tools/report-summarize.d.ts +2131 -0
  129. package/dist/tools/report-summarize.js +596 -0
  130. package/dist/tools/runtime-detect.d.ts +135 -0
  131. package/dist/tools/runtime-detect.js +247 -0
  132. package/dist/tools/sample-ingest.d.ts +94 -0
  133. package/dist/tools/sample-ingest.js +327 -0
  134. package/dist/tools/sample-profile-get.d.ts +183 -0
  135. package/dist/tools/sample-profile-get.js +121 -0
  136. package/dist/tools/sandbox-execute.d.ts +441 -0
  137. package/dist/tools/sandbox-execute.js +392 -0
  138. package/dist/tools/strings-extract.d.ts +375 -0
  139. package/dist/tools/strings-extract.js +314 -0
  140. package/dist/tools/strings-floss-decode.d.ts +143 -0
  141. package/dist/tools/strings-floss-decode.js +259 -0
  142. package/dist/tools/system-health.d.ts +434 -0
  143. package/dist/tools/system-health.js +446 -0
  144. package/dist/tools/task-cancel.d.ts +21 -0
  145. package/dist/tools/task-cancel.js +70 -0
  146. package/dist/tools/task-status.d.ts +27 -0
  147. package/dist/tools/task-status.js +106 -0
  148. package/dist/tools/task-sweep.d.ts +22 -0
  149. package/dist/tools/task-sweep.js +77 -0
  150. package/dist/tools/tool-help.d.ts +340 -0
  151. package/dist/tools/tool-help.js +261 -0
  152. package/dist/tools/yara-scan.d.ts +554 -0
  153. package/dist/tools/yara-scan.js +313 -0
  154. package/dist/types.d.ts +266 -0
  155. package/dist/types.js +41 -0
  156. package/dist/worker-pool.d.ts +204 -0
  157. package/dist/worker-pool.js +650 -0
  158. package/dist/workflows/deep-static.d.ts +104 -0
  159. package/dist/workflows/deep-static.js +276 -0
  160. package/dist/workflows/function-explanation-review.d.ts +655 -0
  161. package/dist/workflows/function-explanation-review.js +440 -0
  162. package/dist/workflows/reconstruct.d.ts +2053 -0
  163. package/dist/workflows/reconstruct.js +666 -0
  164. package/dist/workflows/semantic-name-review.d.ts +2418 -0
  165. package/dist/workflows/semantic-name-review.js +521 -0
  166. package/dist/workflows/triage.d.ts +659 -0
  167. package/dist/workflows/triage.js +1374 -0
  168. package/dist/workspace-manager.d.ts +150 -0
  169. package/dist/workspace-manager.js +411 -0
  170. package/ghidra_scripts/DecompileFunction.java +487 -0
  171. package/ghidra_scripts/DecompileFunction.py +150 -0
  172. package/ghidra_scripts/ExtractCFG.java +256 -0
  173. package/ghidra_scripts/ExtractCFG.py +233 -0
  174. package/ghidra_scripts/ExtractFunctions.java +442 -0
  175. package/ghidra_scripts/ExtractFunctions.py +101 -0
  176. package/ghidra_scripts/README.md +125 -0
  177. package/ghidra_scripts/SearchFunctionReferences.java +380 -0
  178. package/helpers/DotNetMetadataProbe/DotNetMetadataProbe.csproj +9 -0
  179. package/helpers/DotNetMetadataProbe/Program.cs +566 -0
  180. package/install-to-codex.ps1 +178 -0
  181. package/install-to-copilot.ps1 +303 -0
  182. package/package.json +101 -0
  183. package/requirements.txt +9 -0
  184. package/workers/requirements-dynamic.txt +11 -0
  185. package/workers/requirements.txt +8 -0
  186. package/workers/speakeasy_compat.py +175 -0
  187. package/workers/static_worker.py +5183 -0
  188. package/workers/yara_rules/default.yar +33 -0
  189. package/workers/yara_rules/malware_families.yar +93 -0
  190. package/workers/yara_rules/packers.yar +80 -0
package/dist/server.js ADDED
@@ -0,0 +1,578 @@
1
+ /**
2
+ * MCP Server implementation
3
+ * Implements the Model Context Protocol with JSON-RPC 2.0 message handling
4
+ */
5
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
6
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
7
+ import { CallToolRequestSchema, GetPromptRequestSchema, ListPromptsRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
8
+ import { z } from 'zod';
9
+ import pino from 'pino';
10
+ /**
11
+ * MCP Server class implementing the Model Context Protocol
12
+ */
13
+ export class MCPServer {
14
+ server;
15
+ logger;
16
+ tools;
17
+ handlers;
18
+ prompts;
19
+ promptHandlers;
20
+ constructor(config) {
21
+ // Create logger that writes to stderr to avoid interfering with MCP protocol on stdout
22
+ const destination = pino.destination({ dest: 2, sync: false }); // fd 2 = stderr
23
+ this.logger = pino({
24
+ level: config.logging.level,
25
+ }, destination);
26
+ this.tools = new Map();
27
+ this.handlers = new Map();
28
+ this.prompts = new Map();
29
+ this.promptHandlers = new Map();
30
+ // Initialize MCP SDK server
31
+ this.server = new Server({
32
+ name: 'windows-exe-decompiler-mcp-server',
33
+ version: '0.1.0',
34
+ }, {
35
+ capabilities: {
36
+ tools: {},
37
+ prompts: {},
38
+ },
39
+ });
40
+ this.setupHandlers();
41
+ this.logger.info('MCP Server initialized');
42
+ }
43
+ /**
44
+ * Setup MCP protocol handlers
45
+ */
46
+ setupHandlers() {
47
+ // Handle tools/list request
48
+ this.server.setRequestHandler(ListToolsRequestSchema, async () => {
49
+ this.logger.debug('Handling tools/list request');
50
+ return {
51
+ tools: await this.listTools(),
52
+ };
53
+ });
54
+ this.server.setRequestHandler(ListPromptsRequestSchema, async () => {
55
+ this.logger.debug('Handling prompts/list request');
56
+ return {
57
+ prompts: await this.listPrompts(),
58
+ };
59
+ });
60
+ this.server.setRequestHandler(GetPromptRequestSchema, async (request) => {
61
+ this.logger.debug({ prompt: request.params.name }, 'Handling prompts/get request');
62
+ return (await this.getPrompt(request.params.name, request.params.arguments || {}));
63
+ });
64
+ // Handle tools/call request
65
+ this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
66
+ this.logger.debug({ tool: request.params.name }, 'Handling tools/call request');
67
+ const result = await this.callTool(request.params.name, request.params.arguments || {});
68
+ return result;
69
+ });
70
+ }
71
+ /**
72
+ * Register a tool with its definition and handler
73
+ */
74
+ registerTool(definition, handler) {
75
+ this.logger.info({ tool: definition.name }, 'Registering tool');
76
+ this.tools.set(definition.name, definition);
77
+ this.handlers.set(definition.name, handler);
78
+ }
79
+ /**
80
+ * Register a prompt with its definition and handler
81
+ */
82
+ registerPrompt(definition, handler) {
83
+ this.logger.info({ prompt: definition.name }, 'Registering prompt');
84
+ this.prompts.set(definition.name, definition);
85
+ this.promptHandlers.set(definition.name, handler);
86
+ }
87
+ getToolDefinitions() {
88
+ return Array.from(this.tools.values());
89
+ }
90
+ getToolDefinition(name) {
91
+ return this.tools.get(name);
92
+ }
93
+ getPromptDefinitions() {
94
+ return Array.from(this.prompts.values());
95
+ }
96
+ getPromptDefinition(name) {
97
+ return this.prompts.get(name);
98
+ }
99
+ /**
100
+ * List all available tools (MCP protocol method)
101
+ */
102
+ async listTools() {
103
+ const tools = [];
104
+ for (const [name, definition] of this.tools.entries()) {
105
+ // Convert Zod schema to JSON Schema format for MCP protocol
106
+ const inputSchema = this.zodToJsonSchema(definition.inputSchema);
107
+ tools.push({
108
+ name,
109
+ description: definition.description,
110
+ inputSchema: inputSchema,
111
+ });
112
+ }
113
+ this.logger.debug({ count: tools.length }, 'Listed tools');
114
+ return tools;
115
+ }
116
+ /**
117
+ * List all available prompts (MCP protocol method)
118
+ */
119
+ async listPrompts() {
120
+ const prompts = [];
121
+ for (const [name, definition] of this.prompts.entries()) {
122
+ prompts.push({
123
+ name,
124
+ title: definition.title,
125
+ description: definition.description,
126
+ arguments: definition.arguments?.map((item) => ({
127
+ name: item.name,
128
+ description: item.description,
129
+ required: item.required,
130
+ })),
131
+ });
132
+ }
133
+ this.logger.debug({ count: prompts.length }, 'Listed prompts');
134
+ return prompts;
135
+ }
136
+ /**
137
+ * Convert Zod schema to JSON Schema format
138
+ * Basic implementation for common Zod types
139
+ */
140
+ zodToJsonSchema(schema) {
141
+ const converted = this.zodFieldToJsonSchema(schema);
142
+ if (converted && typeof converted === 'object') {
143
+ return converted;
144
+ }
145
+ return { type: 'object', properties: {} };
146
+ }
147
+ /**
148
+ * Determine whether a field is required in object schema.
149
+ * Optional/default/catch wrappers should not be marked as required.
150
+ */
151
+ isFieldRequired(schema) {
152
+ if (schema instanceof z.ZodOptional) {
153
+ return false;
154
+ }
155
+ if (schema instanceof z.ZodDefault) {
156
+ return false;
157
+ }
158
+ if (schema instanceof z.ZodCatch) {
159
+ return false;
160
+ }
161
+ if (schema instanceof z.ZodEffects) {
162
+ return this.isFieldRequired(schema._def.schema);
163
+ }
164
+ if (schema instanceof z.ZodNullable) {
165
+ return this.isFieldRequired(schema._def.innerType);
166
+ }
167
+ if (schema instanceof z.ZodBranded) {
168
+ return this.isFieldRequired(schema._def.type);
169
+ }
170
+ if (schema instanceof z.ZodReadonly) {
171
+ return this.isFieldRequired(schema._def.innerType);
172
+ }
173
+ return true;
174
+ }
175
+ /**
176
+ * Attach schema description when available.
177
+ */
178
+ withDescription(jsonSchema, schema) {
179
+ if (schema.description) {
180
+ return {
181
+ ...jsonSchema,
182
+ description: schema.description,
183
+ };
184
+ }
185
+ return jsonSchema;
186
+ }
187
+ /**
188
+ * Convert Zod field schema to JSON Schema property
189
+ */
190
+ zodFieldToJsonSchema(schema) {
191
+ // Handle optional
192
+ if (schema instanceof z.ZodOptional) {
193
+ return this.zodFieldToJsonSchema(schema._def.innerType);
194
+ }
195
+ // Handle nullable
196
+ if (schema instanceof z.ZodNullable) {
197
+ const innerSchema = this.zodFieldToJsonSchema(schema._def.innerType);
198
+ return this.withDescription({
199
+ anyOf: [innerSchema, { type: 'null' }],
200
+ }, schema);
201
+ }
202
+ // Handle defaults
203
+ if (schema instanceof z.ZodDefault) {
204
+ const innerSchema = this.zodFieldToJsonSchema(schema._def.innerType);
205
+ try {
206
+ return this.withDescription({
207
+ ...innerSchema,
208
+ default: schema._def.defaultValue(),
209
+ }, schema);
210
+ }
211
+ catch {
212
+ return this.withDescription(innerSchema, schema);
213
+ }
214
+ }
215
+ // Handle catch fallback values
216
+ if (schema instanceof z.ZodCatch) {
217
+ return this.zodFieldToJsonSchema(schema._def.innerType);
218
+ }
219
+ // Handle effects/transform wrappers
220
+ if (schema instanceof z.ZodEffects) {
221
+ return this.zodFieldToJsonSchema(schema._def.schema);
222
+ }
223
+ // Handle branded types
224
+ if (schema instanceof z.ZodBranded) {
225
+ return this.zodFieldToJsonSchema(schema._def.type);
226
+ }
227
+ // Handle readonly wrapper
228
+ if (schema instanceof z.ZodReadonly) {
229
+ return this.zodFieldToJsonSchema(schema._def.innerType);
230
+ }
231
+ // Handle string
232
+ if (schema instanceof z.ZodString) {
233
+ return this.withDescription({ type: 'string' }, schema);
234
+ }
235
+ // Handle number
236
+ if (schema instanceof z.ZodNumber) {
237
+ return this.withDescription({ type: 'number' }, schema);
238
+ }
239
+ // Handle boolean
240
+ if (schema instanceof z.ZodBoolean) {
241
+ return this.withDescription({ type: 'boolean' }, schema);
242
+ }
243
+ // Handle array
244
+ if (schema instanceof z.ZodArray) {
245
+ return this.withDescription({
246
+ type: 'array',
247
+ items: this.zodFieldToJsonSchema(schema._def.type),
248
+ }, schema);
249
+ }
250
+ // Handle enum
251
+ if (schema instanceof z.ZodEnum) {
252
+ return this.withDescription({
253
+ type: 'string',
254
+ enum: schema._def.values,
255
+ }, schema);
256
+ }
257
+ // Handle literal
258
+ if (schema instanceof z.ZodLiteral) {
259
+ const literalValue = schema._def.value;
260
+ const literalType = literalValue === null ? 'null' : typeof literalValue;
261
+ return this.withDescription({
262
+ type: literalType,
263
+ const: literalValue,
264
+ }, schema);
265
+ }
266
+ // Handle object
267
+ if (schema instanceof z.ZodObject) {
268
+ const shape = schema.shape;
269
+ const properties = {};
270
+ const required = [];
271
+ for (const [key, fieldSchema] of Object.entries(shape)) {
272
+ properties[key] = this.zodFieldToJsonSchema(fieldSchema);
273
+ if (this.isFieldRequired(fieldSchema)) {
274
+ required.push(key);
275
+ }
276
+ }
277
+ return this.withDescription({
278
+ type: 'object',
279
+ properties,
280
+ ...(required.length > 0 ? { required } : {}),
281
+ }, schema);
282
+ }
283
+ // Handle union
284
+ if (schema instanceof z.ZodUnion) {
285
+ const options = schema._def.options;
286
+ return this.withDescription({
287
+ anyOf: options.map((option) => this.zodFieldToJsonSchema(option)),
288
+ }, schema);
289
+ }
290
+ // Handle discriminated union
291
+ if (schema instanceof z.ZodDiscriminatedUnion) {
292
+ const options = Array.from(schema.options.values());
293
+ return this.withDescription({
294
+ anyOf: options.map((option) => this.zodFieldToJsonSchema(option)),
295
+ }, schema);
296
+ }
297
+ // Handle record
298
+ if (schema instanceof z.ZodRecord) {
299
+ return this.withDescription({
300
+ type: 'object',
301
+ additionalProperties: this.zodFieldToJsonSchema(schema._def.valueType),
302
+ }, schema);
303
+ }
304
+ // Handle tuple
305
+ if (schema instanceof z.ZodTuple) {
306
+ return this.withDescription({
307
+ type: 'array',
308
+ items: schema._def.items.map((item) => this.zodFieldToJsonSchema(item)),
309
+ }, schema);
310
+ }
311
+ // Default
312
+ return this.withDescription({ type: 'string' }, schema);
313
+ }
314
+ /**
315
+ * Call a tool by name with arguments (MCP protocol method)
316
+ */
317
+ async callTool(name, args) {
318
+ const startTime = Date.now();
319
+ this.logger.info({ tool: name, args }, 'Calling tool');
320
+ try {
321
+ // Check if tool exists
322
+ const definition = this.tools.get(name);
323
+ if (!definition) {
324
+ throw new Error(`Tool not found: ${name}`);
325
+ }
326
+ // Validate input arguments
327
+ const validatedArgs = this.validateArgs(definition.inputSchema, args);
328
+ // Get handler
329
+ const handler = this.handlers.get(name);
330
+ if (!handler) {
331
+ throw new Error(`Handler not found for tool: ${name}`);
332
+ }
333
+ // Execute handler
334
+ const result = await handler(validatedArgs);
335
+ const elapsed = Date.now() - startTime;
336
+ // Check if result is ToolResult or WorkerResult
337
+ if ('content' in result) {
338
+ // It's a ToolResult - use directly
339
+ this.logger.info({ tool: name, elapsed, isError: result.isError }, 'Tool execution completed');
340
+ return {
341
+ content: result.content, // MCP SDK Content type
342
+ isError: result.isError
343
+ };
344
+ }
345
+ else {
346
+ // It's a WorkerResult - convert to ToolResult
347
+ this.logger.info({ tool: name, elapsed, ok: result.ok }, 'Tool execution completed');
348
+ return this.workerResultToToolResult(result);
349
+ }
350
+ }
351
+ catch (error) {
352
+ const elapsed = Date.now() - startTime;
353
+ this.logger.error({ tool: name, elapsed, error }, 'Tool execution failed');
354
+ return {
355
+ content: [
356
+ {
357
+ type: 'text',
358
+ text: JSON.stringify({
359
+ ok: false,
360
+ errors: [error.message],
361
+ }),
362
+ },
363
+ ],
364
+ isError: true,
365
+ };
366
+ }
367
+ }
368
+ /**
369
+ * Resolve a prompt by name and arguments (MCP protocol method)
370
+ */
371
+ async getPrompt(name, args) {
372
+ const definition = this.prompts.get(name);
373
+ if (!definition) {
374
+ throw new Error(`Prompt not found: ${name}`);
375
+ }
376
+ const handler = this.promptHandlers.get(name);
377
+ if (!handler) {
378
+ throw new Error(`Handler not found for prompt: ${name}`);
379
+ }
380
+ const validatedArgs = this.validatePromptArgs(definition, args);
381
+ return handler(validatedArgs);
382
+ }
383
+ validatePromptArgs(definition, args) {
384
+ const validated = {};
385
+ const provided = args || {};
386
+ for (const [key, value] of Object.entries(provided)) {
387
+ if (value === undefined || value === null) {
388
+ continue;
389
+ }
390
+ validated[key] = String(value);
391
+ }
392
+ for (const item of definition.arguments || []) {
393
+ if (item.required && (!validated[item.name] || validated[item.name].trim().length === 0)) {
394
+ throw new Error(`Missing required prompt argument: ${item.name}`);
395
+ }
396
+ }
397
+ return validated;
398
+ }
399
+ /**
400
+ * Validate tool arguments against schema
401
+ * Provides clear error messages with field paths and validation details
402
+ */
403
+ validateArgs(schema, args) {
404
+ try {
405
+ return schema.parse(args);
406
+ }
407
+ catch (error) {
408
+ if (error instanceof z.ZodError) {
409
+ // Build detailed validation error message
410
+ const errorDetails = error.errors.map((e) => {
411
+ const path = e.path.length > 0 ? e.path.join('.') : 'root';
412
+ return ` - ${path}: ${e.message}`;
413
+ });
414
+ // Generate example based on schema
415
+ const example = this.generateSchemaExample(schema);
416
+ const exampleStr = example ? `\n\nExample:\n${JSON.stringify(example, null, 2)}` : '';
417
+ throw new Error(`Invalid arguments:\n${errorDetails.join('\n')}${exampleStr}`);
418
+ }
419
+ throw error;
420
+ }
421
+ }
422
+ /**
423
+ * Generate an example object from a Zod schema
424
+ * Helps users understand the expected input format
425
+ */
426
+ generateSchemaExample(schema) {
427
+ try {
428
+ // Handle ZodObject
429
+ if (schema instanceof z.ZodObject) {
430
+ const shape = schema.shape;
431
+ const example = {};
432
+ for (const [key, fieldSchema] of Object.entries(shape)) {
433
+ example[key] = this.generateFieldExample(fieldSchema);
434
+ }
435
+ return example;
436
+ }
437
+ return null;
438
+ }
439
+ catch {
440
+ return null;
441
+ }
442
+ }
443
+ /**
444
+ * Generate an example value for a specific field schema
445
+ */
446
+ generateFieldExample(schema) {
447
+ // Handle optional fields
448
+ if (schema instanceof z.ZodOptional) {
449
+ return this.generateFieldExample(schema._def.innerType);
450
+ }
451
+ // Handle nullable fields
452
+ if (schema instanceof z.ZodNullable) {
453
+ return this.generateFieldExample(schema._def.innerType);
454
+ }
455
+ // Handle default values
456
+ if (schema instanceof z.ZodDefault) {
457
+ return schema._def.defaultValue();
458
+ }
459
+ // Handle string
460
+ if (schema instanceof z.ZodString) {
461
+ return 'string';
462
+ }
463
+ // Handle number
464
+ if (schema instanceof z.ZodNumber) {
465
+ return 0;
466
+ }
467
+ // Handle boolean
468
+ if (schema instanceof z.ZodBoolean) {
469
+ return true;
470
+ }
471
+ // Handle array
472
+ if (schema instanceof z.ZodArray) {
473
+ const elementExample = this.generateFieldExample(schema._def.type);
474
+ return [elementExample];
475
+ }
476
+ // Handle object
477
+ if (schema instanceof z.ZodObject) {
478
+ const shape = schema.shape;
479
+ const example = {};
480
+ for (const [key, fieldSchema] of Object.entries(shape)) {
481
+ example[key] = this.generateFieldExample(fieldSchema);
482
+ }
483
+ return example;
484
+ }
485
+ // Handle enum
486
+ if (schema instanceof z.ZodEnum) {
487
+ const values = schema._def.values;
488
+ return values[0];
489
+ }
490
+ // Handle literal
491
+ if (schema instanceof z.ZodLiteral) {
492
+ return schema._def.value;
493
+ }
494
+ // Handle union
495
+ if (schema instanceof z.ZodUnion) {
496
+ const options = schema._def.options;
497
+ return this.generateFieldExample(options[0]);
498
+ }
499
+ // Default fallback
500
+ return 'value';
501
+ }
502
+ /**
503
+ * Convert worker result to MCP tool result
504
+ */
505
+ workerResultToToolResult(result) {
506
+ const content = [];
507
+ // Add text representation
508
+ content.push({
509
+ type: 'text',
510
+ text: JSON.stringify({
511
+ ok: result.ok,
512
+ data: result.data,
513
+ warnings: result.warnings,
514
+ errors: result.errors,
515
+ artifacts: result.artifacts,
516
+ metrics: result.metrics,
517
+ }, null, 2),
518
+ });
519
+ return {
520
+ content,
521
+ isError: !result.ok,
522
+ };
523
+ }
524
+ /**
525
+ * Start the MCP server with stdio transport
526
+ */
527
+ async start() {
528
+ this.logger.info('Starting MCP Server with stdio transport');
529
+ const transport = new StdioServerTransport();
530
+ await this.server.connect(transport);
531
+ this.logger.info('MCP Server started and listening on stdio');
532
+ }
533
+ /**
534
+ * Stop the MCP server
535
+ */
536
+ async stop() {
537
+ this.logger.info('Stopping MCP Server');
538
+ await this.server.close();
539
+ this.logger.info('MCP Server stopped');
540
+ }
541
+ /**
542
+ * Get server instance for testing
543
+ */
544
+ getServer() {
545
+ return this.server;
546
+ }
547
+ /**
548
+ * Get connected client capabilities after MCP initialization.
549
+ */
550
+ getClientCapabilities() {
551
+ return this.server.getClientCapabilities();
552
+ }
553
+ /**
554
+ * Get connected client implementation info after MCP initialization.
555
+ */
556
+ getClientVersion() {
557
+ return this.server.getClientVersion();
558
+ }
559
+ /**
560
+ * Whether the connected MCP client advertised sampling support.
561
+ */
562
+ supportsSampling() {
563
+ return Boolean(this.getClientCapabilities()?.sampling);
564
+ }
565
+ /**
566
+ * Request client-mediated MCP sampling from the connected client.
567
+ */
568
+ async createMessage(params) {
569
+ return this.server.createMessage(params);
570
+ }
571
+ /**
572
+ * Get logger instance
573
+ */
574
+ getLogger() {
575
+ return this.logger;
576
+ }
577
+ }
578
+ //# sourceMappingURL=server.js.map