@skyramp/mcp 0.2.8 → 0.2.150-rc.ldw

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 (99) hide show
  1. package/build/commands/commandLibrary.d.ts +1 -0
  2. package/build/commands/commandLibrary.js +20 -14
  3. package/build/commands/commandLibrary.test.d.ts +1 -0
  4. package/build/commands/commandLibrary.test.js +59 -0
  5. package/build/commands/localDevTestChangesCommand.d.ts +15 -0
  6. package/build/commands/localDevTestChangesCommand.js +188 -0
  7. package/build/index.js +77 -13
  8. package/build/prompts/enhance-assertions/sharedAssertionRules.d.ts +1 -0
  9. package/build/prompts/enhance-assertions/sharedAssertionRules.js +17 -0
  10. package/build/prompts/initialize-workspace/initializeWorkspacePrompt.js +9 -8
  11. package/build/prompts/local-dev/local-dev-plan.d.ts +25 -0
  12. package/build/prompts/local-dev/local-dev-plan.js +419 -0
  13. package/build/prompts/local-dev/local-dev-prompts.d.ts +4 -0
  14. package/build/prompts/local-dev/local-dev-prompts.js +157 -0
  15. package/build/prompts/prompt-utils.d.ts +8 -0
  16. package/build/prompts/prompt-utils.js +33 -0
  17. package/build/prompts/sut-setup/modes/adaptWorkflowPrompt.js +3 -1
  18. package/build/prompts/sut-setup/modes/dockerComposePrompt.js +3 -1
  19. package/build/prompts/sut-setup/shared.d.ts +20 -0
  20. package/build/prompts/sut-setup/shared.js +69 -7
  21. package/build/prompts/test-recommendation/analysisOutputPrompt.js +21 -29
  22. package/build/prompts/test-recommendation/analysisOutputPrompt.test.js +0 -28
  23. package/build/prompts/test-recommendation/test-recommendation-prompt.js +41 -4
  24. package/build/prompts/test-recommendation/test-recommendation-prompt.test.js +16 -1
  25. package/build/prompts/testbot/testbot-prompts.d.ts +0 -5
  26. package/build/prompts/testbot/testbot-prompts.js +4 -34
  27. package/build/resources/testbotResource.js +2 -1
  28. package/build/services/AnalyticsService.d.ts +1 -1
  29. package/build/services/TestExecutionService.d.ts +2 -1
  30. package/build/services/TestExecutionService.js +15 -10
  31. package/build/services/TestExecutionService.test.js +75 -1
  32. package/build/services/TestGenerationService.d.ts +2 -2
  33. package/build/tool-phases.js +4 -0
  34. package/build/tools/code-refactor/enhanceAssertionsTool.js +47 -18
  35. package/build/tools/enrichTestWithMocksTool.d.ts +28 -0
  36. package/build/tools/enrichTestWithMocksTool.js +726 -0
  37. package/build/tools/enrichTestWithMocksTool.test.d.ts +1 -0
  38. package/build/tools/enrichTestWithMocksTool.test.js +266 -0
  39. package/build/tools/executeSkyrampTestTool.d.ts +4 -0
  40. package/build/tools/executeSkyrampTestTool.js +48 -24
  41. package/build/tools/executeSkyrampTestTool.test.d.ts +1 -0
  42. package/build/tools/executeSkyrampTestTool.test.js +16 -0
  43. package/build/tools/generate-tests/batchMockGenerationTool.d.ts +85 -0
  44. package/build/tools/generate-tests/batchMockGenerationTool.js +432 -0
  45. package/build/tools/generate-tests/generateContractRestTool.js +2 -2
  46. package/build/tools/generate-tests/generateMockRestTool.d.ts +129 -6
  47. package/build/tools/generate-tests/generateMockRestTool.js +234 -22
  48. package/build/tools/generate-tests/loadTestSchema.d.ts +1 -1
  49. package/build/tools/generateEnrichedIntegrationTestTool.d.ts +24 -0
  50. package/build/tools/generateEnrichedIntegrationTestTool.js +225 -0
  51. package/build/tools/generateEnrichedIntegrationTestTool.test.d.ts +1 -0
  52. package/build/tools/generateEnrichedIntegrationTestTool.test.js +44 -0
  53. package/build/tools/localDevWorkflowFixes.test.d.ts +1 -0
  54. package/build/tools/localDevWorkflowFixes.test.js +255 -0
  55. package/build/tools/one-click/oneClickTool.d.ts +10 -0
  56. package/build/tools/one-click/oneClickTool.js +177 -21
  57. package/build/tools/one-click/oneClickTool.test.d.ts +1 -0
  58. package/build/tools/one-click/oneClickTool.test.js +172 -0
  59. package/build/tools/preflightMockCheckTool.d.ts +2 -0
  60. package/build/tools/preflightMockCheckTool.js +96 -0
  61. package/build/tools/submitReportTool.d.ts +14 -14
  62. package/build/tools/test-management/analyzeChangesTool.d.ts +2 -1
  63. package/build/tools/test-management/analyzeChangesTool.js +59 -38
  64. package/build/tools/trace/startTraceCollectionTool.js +3 -3
  65. package/build/tools/workspace/initializeWorkspaceTool.js +2 -9
  66. package/build/tools/workspace/initializeWorkspaceTool.test.js +9 -4
  67. package/build/types/OneClickCommands.d.ts +1 -1
  68. package/build/types/RepositoryAnalysis.d.ts +117 -0
  69. package/build/types/RepositoryAnalysis.js +16 -2
  70. package/build/types/TestExecution.d.ts +1 -0
  71. package/build/types/TestTypes.d.ts +20 -8
  72. package/build/types/TestTypes.js +19 -5
  73. package/build/utils/analyze-openapi.js +18 -1
  74. package/build/utils/analyze-openapi.test.d.ts +1 -0
  75. package/build/utils/analyze-openapi.test.js +19 -0
  76. package/build/utils/branchDiff.d.ts +17 -1
  77. package/build/utils/branchDiff.js +96 -14
  78. package/build/utils/branchDiff.test.d.ts +1 -0
  79. package/build/utils/branchDiff.test.js +109 -0
  80. package/build/utils/docker.test.js +1 -1
  81. package/build/utils/featureFlags.d.ts +20 -1
  82. package/build/utils/featureFlags.js +26 -2
  83. package/build/utils/featureFlags.test.js +57 -2
  84. package/build/utils/grpcMockValidation.d.ts +1 -0
  85. package/build/utils/grpcMockValidation.js +49 -0
  86. package/build/utils/grpcMockValidation.test.d.ts +1 -0
  87. package/build/utils/grpcMockValidation.test.js +41 -0
  88. package/build/utils/httpMethodValidation.d.ts +4 -0
  89. package/build/utils/httpMethodValidation.js +13 -0
  90. package/build/utils/mockCompatibility.d.ts +49 -0
  91. package/build/utils/mockCompatibility.js +82 -0
  92. package/build/utils/mockCompatibility.test.d.ts +1 -0
  93. package/build/utils/mockCompatibility.test.js +79 -0
  94. package/build/utils/versions.d.ts +3 -3
  95. package/build/utils/versions.js +1 -1
  96. package/build/workspace/workspace.d.ts +49 -35
  97. package/build/workspace/workspace.js +10 -5
  98. package/build/workspace/workspace.test.js +65 -6
  99. package/package.json +2 -2
@@ -0,0 +1,432 @@
1
+ import { z } from "zod";
2
+ import { SkyrampClient } from "@skyramp/skyramp";
3
+ import { MockProtocol, RuntimeEnvironment, runtimeEnvironmentInputSchema } from "../../types/TestTypes.js";
4
+ export { MockProtocol } from "../../types/TestTypes.js";
5
+ import { AnalyticsService } from "../../services/AnalyticsService.js";
6
+ import { logger } from "../../utils/logger.js";
7
+ import { getEntryPoint } from "../../utils/telemetry.js";
8
+ import fs from "fs";
9
+ import { getRestMockMethodValidationError, normalizeRestMockMethod, } from "../../utils/httpMethodValidation.js";
10
+ import { getGrpcMockResponseValidationError } from "../../utils/grpcMockValidation.js";
11
+ import { validateMockCompatibility } from "../../utils/mockCompatibility.js";
12
+ export const BATCH_MOCK_PROTOCOL_EXAMPLES = `
13
+ <example protocol="rest">
14
+ Batch REST item. Required fields: protocol="rest", endpointURL, method unless apiSchema is provided.
15
+ {
16
+ "protocol": "rest",
17
+ "endpointURL": "http://identity-service:4000/api/internal/v1/users/validate",
18
+ "method": "POST",
19
+ "requestAware": true,
20
+ "responseData": "{\"valid\":true}"
21
+ }
22
+ </example>
23
+
24
+ <example protocol="grpc">
25
+ Batch gRPC item. Required fields: protocol="grpc", endpointURL as host:port, protoPath, grpcServiceName. method is the RPC name; empty means all service methods.
26
+ {
27
+ "protocol": "grpc",
28
+ "endpointURL": "profile-service:50051",
29
+ "protoPath": "/repo/proto/profiles.proto",
30
+ "grpcServiceName": "ProfileService",
31
+ "method": "GetProfile",
32
+ "responseData": "{\"id\":\"profile_123\"}"
33
+ }
34
+ </example>
35
+
36
+ <example protocol="grpc-status-error">
37
+ Batch gRPC status error item. Do not provide responseData with grpcStatusCode.
38
+ {
39
+ "protocol": "grpc",
40
+ "endpointURL": "profile-service:50051",
41
+ "protoPath": "/repo/proto/profiles.proto",
42
+ "grpcServiceName": "ProfileService",
43
+ "method": "GetProfile",
44
+ "grpcStatusCode": 5,
45
+ "grpcStatusMessage": "profile not found"
46
+ }
47
+ </example>
48
+
49
+ <example protocol="kafka-producer">
50
+ Batch Kafka producer validation item. Required fields: protocol="kafka", endpointURL as broker host:port, kafkaTopic, and requestData. Do not pass method or responseData.
51
+ {
52
+ "protocol": "kafka",
53
+ "endpointURL": "broker:9092",
54
+ "kafkaTopic": "orders",
55
+ "requestData": "{\"order_id\":\"ord_123\"}"
56
+ }
57
+ </example>
58
+
59
+ <example protocol="kafka-consumer">
60
+ Batch Kafka consumer message item. Required fields: protocol="kafka", endpointURL as broker host:port, kafkaTopic, and responseData. Do not pass method or requestData.
61
+ {
62
+ "protocol": "kafka",
63
+ "endpointURL": "broker:9092",
64
+ "kafkaTopic": "orders",
65
+ "responseData": "{\"accepted\":true}"
66
+ }
67
+ </example>`;
68
+ const mockSpecSchema = z.object({
69
+ protocol: z
70
+ .nativeEnum(MockProtocol)
71
+ .default(MockProtocol.Rest)
72
+ .describe("Protocol for this mock: 'rest', 'grpc', or 'kafka'. See <example> blocks in the tool description for required fields."),
73
+ endpointURL: z
74
+ .string()
75
+ .describe("For REST: the base URL or endpoint URL. " +
76
+ "For gRPC: the target service address as host:port. " +
77
+ "For Kafka: the broker address as host:port."),
78
+ method: z
79
+ .string()
80
+ .default("")
81
+ .describe("For REST: HTTP method, required unless apiSchema is provided. For gRPC: RPC method name, empty generates all service methods. For Kafka: MUST be empty; use kafkaTopic."),
82
+ responseData: z
83
+ .string()
84
+ .optional()
85
+ .describe("REST/gRPC response body data; Kafka consumer messages. Inline JSON/YAML or @/path/to/file."),
86
+ responseStatusCode: z
87
+ .string()
88
+ .default("")
89
+ .refine((val) => !val || /^\d{3}$/.test(val), {
90
+ message: "Must be a 3-digit HTTP status code (e.g., '200', '201') or empty string",
91
+ })
92
+ .describe("HTTP status code the mock should return (e.g., '200', '201')."),
93
+ grpcStatusCode: z
94
+ .number()
95
+ .int()
96
+ .min(1)
97
+ .max(16)
98
+ .optional()
99
+ .describe("For protocol='grpc' error mocks only. Non-OK gRPC status code number. Do not combine with responseData."),
100
+ grpcStatusMessage: z
101
+ .string()
102
+ .optional()
103
+ .describe("For protocol='grpc' error mocks only. gRPC status message to return with grpcStatusCode."),
104
+ requestData: z
105
+ .string()
106
+ .default("")
107
+ .describe("REST request body sample for request-aware mocks; Kafka producer validation payload/schema."),
108
+ requestAware: z
109
+ .boolean()
110
+ .default(false)
111
+ .describe("When true, generates a dynamic mock that varies by request."),
112
+ apiSchema: z
113
+ .string()
114
+ .default("")
115
+ .describe("Path or URL to OpenAPI/Swagger schema file."),
116
+ protoPath: z
117
+ .string()
118
+ .optional()
119
+ .describe("Required for protocol='grpc'. Path to the .proto file."),
120
+ grpcServiceName: z
121
+ .string()
122
+ .optional()
123
+ .describe("Required for protocol='grpc'. gRPC service name."),
124
+ protobufExtraFiles: z
125
+ .array(z.string())
126
+ .optional()
127
+ .describe("Optional extra .proto files for gRPC compilation."),
128
+ protobufExtraImportPath: z
129
+ .array(z.string())
130
+ .optional()
131
+ .describe("Optional extra import directories for protobuf compilation."),
132
+ kafkaTopic: z
133
+ .string()
134
+ .optional()
135
+ .describe("Required for protocol='kafka'. Kafka topic name."),
136
+ output: z
137
+ .string()
138
+ .optional()
139
+ .describe("Optional output file name for this mock. Use when multiple mocks share the same endpoint and method so generated files do not overwrite each other."),
140
+ outputDir: z
141
+ .string()
142
+ .optional()
143
+ .describe("Optional output directory for this mock. Defaults to the batch-level outputDir."),
144
+ });
145
+ function validateMockSpec(spec) {
146
+ const protocol = spec.protocol ?? MockProtocol.Rest;
147
+ if (protocol === MockProtocol.Rest) {
148
+ const methodError = getRestMockMethodValidationError(spec.method);
149
+ if (methodError)
150
+ return methodError;
151
+ if (!spec.apiSchema && !spec.method) {
152
+ return "REST mock method is required unless apiSchema is provided for schema-wide generation";
153
+ }
154
+ }
155
+ if (protocol === MockProtocol.Grpc) {
156
+ const missing = [];
157
+ if (!spec.protoPath)
158
+ missing.push("protoPath");
159
+ if (!spec.grpcServiceName)
160
+ missing.push("grpcServiceName");
161
+ if (missing.length > 0) {
162
+ return `gRPC mock requires: ${missing.join(", ")}`;
163
+ }
164
+ if (spec.grpcStatusCode !== undefined && spec.responseData?.trim()) {
165
+ return "gRPC status error mocks must use grpcStatusCode/grpcStatusMessage instead of responseData";
166
+ }
167
+ if (spec.grpcStatusMessage && spec.grpcStatusCode === undefined) {
168
+ return "grpcStatusMessage requires grpcStatusCode";
169
+ }
170
+ const grpcResponseError = getGrpcMockResponseValidationError(spec.responseData);
171
+ if (grpcResponseError)
172
+ return grpcResponseError;
173
+ }
174
+ if (protocol === MockProtocol.Kafka) {
175
+ if (!spec.kafkaTopic)
176
+ return "Kafka mock requires: kafkaTopic";
177
+ if (spec.method) {
178
+ return "Kafka mock method must be empty; use kafkaTopic for the topic name. Produce validation uses requestData and consumer messages use responseData";
179
+ }
180
+ const hasRequestData = Boolean(spec.requestData && spec.requestData.trim());
181
+ const hasResponseData = Boolean(spec.responseData && spec.responseData.trim());
182
+ if (hasRequestData === hasResponseData) {
183
+ return "Kafka mock requires exactly one of requestData (producer validation) or responseData (consumer messages)";
184
+ }
185
+ }
186
+ return null;
187
+ }
188
+ function buildGenerateOptions(spec, shared) {
189
+ const protocol = spec.protocol ?? MockProtocol.Rest;
190
+ const language = shared.language ?? "python";
191
+ const framework = shared.framework ??
192
+ (language === "typescript" || language === "javascript"
193
+ ? "playwright"
194
+ : "");
195
+ const outputDir = spec.outputDir ?? shared.outputDir;
196
+ const common = {
197
+ protocol,
198
+ language,
199
+ framework,
200
+ outputDir,
201
+ output: spec.output,
202
+ force: true,
203
+ overwrite: true,
204
+ runtime: shared.runtime,
205
+ dockerNetwork: shared.dockerNetwork,
206
+ entrypoint: getEntryPoint(),
207
+ };
208
+ const responseDataOption = spec.responseData !== undefined &&
209
+ !(protocol === MockProtocol.Grpc && spec.grpcStatusCode !== undefined)
210
+ ? { responseData: spec.responseData }
211
+ : {};
212
+ if (protocol === MockProtocol.Grpc) {
213
+ return {
214
+ ...common,
215
+ ...responseDataOption,
216
+ method: spec.method ?? "",
217
+ url: spec.endpointURL,
218
+ protoPath: spec.protoPath,
219
+ service: spec.grpcServiceName,
220
+ grpcStatusCode: spec.grpcStatusCode,
221
+ grpcStatusMessage: spec.grpcStatusMessage,
222
+ extraFiles: spec.protobufExtraFiles ?? [],
223
+ extraImports: spec.protobufExtraImportPath ?? [],
224
+ };
225
+ }
226
+ if (protocol === MockProtocol.Kafka) {
227
+ return {
228
+ ...common,
229
+ ...responseDataOption,
230
+ url: spec.endpointURL,
231
+ topic: spec.kafkaTopic,
232
+ requestData: spec.requestData?.trim() ? spec.requestData : undefined,
233
+ };
234
+ }
235
+ // REST
236
+ return {
237
+ ...common,
238
+ ...responseDataOption,
239
+ method: normalizeRestMockMethod(spec.method),
240
+ uri: spec.endpointURL,
241
+ apiSchema: spec.apiSchema ? [spec.apiSchema] : [],
242
+ requestData: spec.requestData ?? "",
243
+ responseStatusCode: spec.responseStatusCode ?? "",
244
+ requestAware: spec.requestAware ?? false,
245
+ mockPort: 0,
246
+ optionalFields: false,
247
+ };
248
+ }
249
+ export async function executeBatchMockGeneration(params) {
250
+ const { mocks, outputDir } = params;
251
+ fs.mkdirSync(outputDir, { recursive: true });
252
+ const client = new SkyrampClient();
253
+ const results = [];
254
+ for (let i = 0; i < mocks.length; i++) {
255
+ const spec = mocks[i];
256
+ const protocol = spec.protocol ?? MockProtocol.Rest;
257
+ const method = spec.method ?? "";
258
+ // Validate spec
259
+ const validationError = validateMockSpec(spec);
260
+ if (validationError) {
261
+ results.push({
262
+ index: i,
263
+ protocol,
264
+ endpointURL: spec.endpointURL,
265
+ method,
266
+ topic: spec.kafkaTopic,
267
+ success: false,
268
+ error: validationError,
269
+ });
270
+ continue;
271
+ }
272
+ const dockerLocalDev = params.runtime === "docker" || Boolean(params.dockerNetwork?.trim());
273
+ const compatibility = validateMockCompatibility([{ ...spec, protocol }], {
274
+ dockerLocalDev,
275
+ });
276
+ const blockingWarnings = compatibility.warnings.filter((warning) => warning.blocking);
277
+ if (blockingWarnings.length > 0) {
278
+ results.push({
279
+ index: i,
280
+ protocol,
281
+ endpointURL: spec.endpointURL,
282
+ method,
283
+ topic: spec.kafkaTopic,
284
+ success: false,
285
+ error: blockingWarnings
286
+ .map((warning) => `${warning.code}: ${warning.message} Suggestion: ${warning.suggestion}`)
287
+ .join("\n"),
288
+ });
289
+ continue;
290
+ }
291
+ const resolvedOutputDir = spec.outputDir ?? outputDir;
292
+ fs.mkdirSync(resolvedOutputDir, { recursive: true });
293
+ // Build options and generate
294
+ const options = buildGenerateOptions(spec, {
295
+ outputDir,
296
+ runtime: params.runtime,
297
+ dockerNetwork: params.dockerNetwork,
298
+ language: params.language,
299
+ framework: params.framework,
300
+ });
301
+ try {
302
+ let result;
303
+ if (protocol === MockProtocol.Grpc) {
304
+ result = await client.generateGrpcMock(options);
305
+ }
306
+ else if (protocol === MockProtocol.Kafka) {
307
+ result = await client.generateKafkaMock(options);
308
+ }
309
+ else {
310
+ result = await client.generateRestMock(options);
311
+ }
312
+ if (!result || !result.toLowerCase().includes("success")) {
313
+ results.push({
314
+ index: i,
315
+ protocol,
316
+ endpointURL: spec.endpointURL,
317
+ method,
318
+ topic: spec.kafkaTopic,
319
+ success: false,
320
+ error: `Mock generation failed: ${result || "no output from backend"}`,
321
+ });
322
+ continue;
323
+ }
324
+ results.push({
325
+ index: i,
326
+ protocol,
327
+ endpointURL: spec.endpointURL,
328
+ method,
329
+ topic: spec.kafkaTopic,
330
+ success: true,
331
+ outputDir: resolvedOutputDir,
332
+ output: spec.output,
333
+ detail: result,
334
+ });
335
+ }
336
+ catch (error) {
337
+ const errorMessage = error instanceof Error ? error.message : String(error);
338
+ logger.error("Batch mock generation failed for spec", {
339
+ index: i,
340
+ protocol,
341
+ endpointURL: spec.endpointURL,
342
+ error: errorMessage,
343
+ });
344
+ results.push({
345
+ index: i,
346
+ protocol,
347
+ endpointURL: spec.endpointURL,
348
+ method,
349
+ topic: spec.kafkaTopic,
350
+ success: false,
351
+ error: errorMessage,
352
+ });
353
+ }
354
+ }
355
+ const succeeded = results.filter((r) => r.success);
356
+ const failed = results.filter((r) => !r.success);
357
+ const summaryLines = [
358
+ `## Batch Mock Generation Summary`,
359
+ ``,
360
+ `- **Total:** ${mocks.length}`,
361
+ `- **Succeeded:** ${succeeded.length}`,
362
+ `- **Failed:** ${failed.length}`,
363
+ `- **Default Output Directory:** ${outputDir}`,
364
+ ``,
365
+ ];
366
+ if (succeeded.length > 0) {
367
+ summaryLines.push(`### Successful Mocks`);
368
+ for (const r of succeeded) {
369
+ summaryLines.push(`- [${r.index}] ${r.protocol.toUpperCase()} ${r.endpointURL} ${r.method || (r.protocol === MockProtocol.Kafka ? `topic:${r.topic ?? "?"}` : "(all methods)")}${r.output ? ` -> ${r.outputDir ?? outputDir}/${r.output}` : ""}`);
370
+ }
371
+ summaryLines.push(``);
372
+ }
373
+ if (failed.length > 0) {
374
+ summaryLines.push(`### Failed Mocks`);
375
+ for (const r of failed) {
376
+ summaryLines.push(`- [${r.index}] ${r.protocol.toUpperCase()} ${r.endpointURL} ${r.method || (r.protocol === MockProtocol.Kafka ? `topic:${r.topic ?? "?"}` : "(all methods)")}: ${r.error}`);
377
+ }
378
+ summaryLines.push(``);
379
+ }
380
+ return {
381
+ content: [{ type: "text", text: summaryLines.join("\n") }],
382
+ isError: failed.length > 0,
383
+ };
384
+ }
385
+ const TOOL_NAME = "skyramp_batch_mock_generation";
386
+ const batchMockSchema = {
387
+ mocks: z
388
+ .array(mockSpecSchema)
389
+ .min(1)
390
+ .describe("Array of mock specifications. Each element describes one mock to generate."),
391
+ outputDir: z
392
+ .string()
393
+ .describe("Directory where generated mock files will be written."),
394
+ runtime: runtimeEnvironmentInputSchema
395
+ .default(RuntimeEnvironment.LOCAL)
396
+ .describe("Runtime environment: 'local', 'docker', or 'k8s' (also accepts 'kubernetes')."),
397
+ dockerNetwork: z
398
+ .string()
399
+ .default("")
400
+ .describe("Docker network name for containerized testing."),
401
+ language: z
402
+ .string()
403
+ .default("python")
404
+ .describe("Programming language for generated mocks (python, typescript, javascript, java)."),
405
+ framework: z
406
+ .string()
407
+ .default("")
408
+ .describe("Testing framework (e.g., pytest, playwright)."),
409
+ };
410
+ export function registerBatchMockTool(server) {
411
+ server.registerTool(TOOL_NAME, {
412
+ description: `Generate multiple mock server implementations in a single call using Skyramp.
413
+
414
+ This tool accepts an array of mock specifications and generates all mocks in one operation,
415
+ avoiding the need for N separate tool calls when mocking multiple downstream services.
416
+
417
+ Each mock spec can target REST, gRPC, or Kafka protocols. Partial failures are handled
418
+ gracefully — if some mocks fail, the others still succeed and are reported.
419
+
420
+ Use this tool when you need to mock 2+ downstream services simultaneously (e.g., for a
421
+ local-dev workflow with multiple dependencies).
422
+
423
+ ${BATCH_MOCK_PROTOCOL_EXAMPLES}`,
424
+ inputSchema: batchMockSchema,
425
+ }, async (params) => {
426
+ const result = await executeBatchMockGeneration(params);
427
+ AnalyticsService.pushTestGenerationToolEvent(TOOL_NAME, result, params).catch(() => {
428
+ // Silently ignore analytics errors
429
+ });
430
+ return result;
431
+ });
432
+ }
@@ -357,8 +357,8 @@ const TOOL_NAME = "skyramp_contract_test_generation";
357
357
  const MODES_SECTION = CONSUMER_MODE_ENABLED
358
358
  ? `**Modes:**
359
359
  - Default (no mode set): both \`providerMode\` and \`consumerMode\` default to false. This generates both provider and consumer contract tests — equivalent to setting both modes to true.
360
- - \`providerMode\`: set to true ONLY if the user explicitly requests a provider-side contract test. Optionally specify \`providerOutput\` for the output file path.
361
- - \`consumerMode\`: set to true ONLY if the user explicitly requests a consumer-side contract test. Optionally specify \`consumerOutput\` for the output file path.
360
+ - \`providerMode\`: set to true ONLY if the user explicitly requests a provider-side contract test. Optionally specify \`providerOutput\` for the output file path. Provider tests hit the real endpoint — no mocks.
361
+ - \`consumerMode\`: set to true ONLY if the user explicitly requests a consumer-side contract test. Optionally specify \`consumerOutput\` for the output file path. Consumer tests include mocks wired inline (\`client.apply_mock(mock)\` in the test function) — no separate \`skyramp_enrich_test_with_mocks\` call needed.
362
362
  - Both \`providerMode\` and \`consumerMode\` can be enabled simultaneously to generate both sides.`
363
363
  : `**Mode:**
364
364
  - Only provider-side contract tests are generated. Pass \`providerMode: true\` (or omit it — the tool always behaves as provider-only). Optionally specify \`providerOutput\` for the output file path.`;
@@ -1,13 +1,23 @@
1
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- import { TestType } from "../../types/TestTypes.js";
2
+ import { MockProtocol } from "../../types/TestTypes.js";
3
+ export { MockProtocol } from "../../types/TestTypes.js";
3
4
  import { TestGenerationService } from "../../services/TestGenerationService.js";
4
5
  import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
6
+ export declare const MOCK_PROTOCOL_EXAMPLES = "\n<example protocol=\"rest\">\nGenerate a REST mock for one HTTP endpoint. Required fields: protocol=\"rest\", endpointURL, method. Use apiSchema with an empty method only when intentionally generating all schema methods.\n{\n \"protocol\": \"rest\",\n \"endpointURL\": \"http://payment-service:5001/orders/:order_id/payment_authorizations\",\n \"method\": \"PUT\",\n \"requestAware\": true,\n \"requestData\": \"{\"payment_method_id\":\"pm_123\"}\",\n \"responseData\": \"{\"accepted\":true}\",\n \"responseStatusCode\": \"200\"\n}\n</example>\n\n<example protocol=\"grpc\">\nGenerate a gRPC mock. Required fields: protocol=\"grpc\", endpointURL as host:port, protoPath, grpcServiceName. method is the RPC method name; omit or leave empty to generate all service methods. use responseData for successful protobuf-shaped responses, or grpcStatusCode/grpcStatusMessage for gRPC status errors.\n{\n \"protocol\": \"grpc\",\n \"endpointURL\": \"profile-service:50051\",\n \"protoPath\": \"/repo/proto/profiles.proto\",\n \"grpcServiceName\": \"ProfileService\",\n \"method\": \"GetProfile\",\n \"responseData\": \"{\"eligible\":true}\"\n}\n</example>\n\n<example protocol=\"grpc-status-error\">\nGenerate a gRPC status error mock. Do not provide responseData with grpcStatusCode.\n{\n \"protocol\": \"grpc\",\n \"endpointURL\": \"profile-service:50051\",\n \"protoPath\": \"/repo/proto/profiles.proto\",\n \"grpcServiceName\": \"ProfileService\",\n \"method\": \"GetProfile\",\n \"grpcStatusCode\": 5,\n \"grpcStatusMessage\": \"profile not found\"\n}\n</example>\n\n<example protocol=\"kafka-producer\">\nGenerate a Kafka producer validation mock. Required fields: protocol=\"kafka\", endpointURL as broker host:port, kafkaTopic, and requestData. Do not pass method or responseData.\n{\n \"protocol\": \"kafka\",\n \"endpointURL\": \"broker:9092\",\n \"kafkaTopic\": \"events\",\n \"requestData\": \"{\"name\":\"order.created\"}\"\n}\n</example>\n\n<example protocol=\"kafka-consumer\">\nGenerate a Kafka consumer message mock. Required fields: protocol=\"kafka\", endpointURL as broker host:port, kafkaTopic, and responseData. Do not pass method or requestData.\n{\n \"protocol\": \"kafka\",\n \"endpointURL\": \"broker:9092\",\n \"kafkaTopic\": \"events\",\n \"responseData\": \"{\"accepted\":true}\"\n}\n</example>";
5
7
  type MockParams = {
8
+ protocol?: MockProtocol;
6
9
  endpointURL?: string;
10
+ protoPath?: string;
11
+ grpcServiceName?: string;
12
+ protobufExtraFiles?: string[];
13
+ protobufExtraImportPath?: string[];
14
+ kafkaTopic?: string;
7
15
  method?: string;
8
16
  apiSchema?: string;
9
17
  responseData?: string;
10
18
  responseStatusCode?: string;
19
+ grpcStatusCode?: number;
20
+ grpcStatusMessage?: string;
11
21
  requestData?: string;
12
22
  formParams?: string;
13
23
  requestAware?: boolean;
@@ -29,13 +39,21 @@ type MockParams = {
29
39
  prompt?: string;
30
40
  };
31
41
  export declare class MockGenerationService extends TestGenerationService {
32
- protected getTestType(): TestType;
42
+ protected getTestType(): "mock";
33
43
  generateTest(params: MockParams & Record<string, any>): Promise<CallToolResult>;
34
44
  private buildReorganizationInstructions;
45
+ protected validateInputs(params: MockParams & Record<string, any>): CallToolResult;
35
46
  protected buildGenerationOptions(params: MockParams): {
36
- uri: string | undefined;
37
47
  method: string | undefined;
38
- apiSchema: string[];
48
+ url: string | undefined;
49
+ protoPath: string | undefined;
50
+ service: string | undefined;
51
+ grpcStatusCode: number | undefined;
52
+ grpcStatusMessage: string | undefined;
53
+ extraFiles: string[];
54
+ extraImports: string[];
55
+ responseData: string;
56
+ protocol: MockProtocol;
39
57
  language: string;
40
58
  framework: string;
41
59
  output: string | undefined;
@@ -48,17 +66,122 @@ export declare class MockGenerationService extends TestGenerationService {
48
66
  k8sNamespace: string | undefined;
49
67
  k8sConfig: string | undefined;
50
68
  k8sContext: string | undefined;
69
+ entrypoint: string;
70
+ } | {
71
+ method: string | undefined;
72
+ url: string | undefined;
73
+ protoPath: string | undefined;
74
+ service: string | undefined;
75
+ grpcStatusCode: number | undefined;
76
+ grpcStatusMessage: string | undefined;
77
+ extraFiles: string[];
78
+ extraImports: string[];
79
+ responseData?: undefined;
80
+ protocol: MockProtocol;
81
+ language: string;
82
+ framework: string;
83
+ output: string | undefined;
84
+ outputDir: string;
85
+ force: boolean;
86
+ deployDashboard: boolean | undefined;
87
+ runtime: string | undefined;
88
+ dockerNetwork: string | undefined;
89
+ dockerWorkerPort: string;
90
+ k8sNamespace: string | undefined;
91
+ k8sConfig: string | undefined;
92
+ k8sContext: string | undefined;
93
+ entrypoint: string;
94
+ } | {
95
+ url: string | undefined;
96
+ topic: string | undefined;
97
+ requestData: string | undefined;
98
+ responseData: string;
99
+ protocol: MockProtocol;
100
+ language: string;
101
+ framework: string;
102
+ output: string | undefined;
103
+ outputDir: string;
104
+ force: boolean;
105
+ deployDashboard: boolean | undefined;
106
+ runtime: string | undefined;
107
+ dockerNetwork: string | undefined;
108
+ dockerWorkerPort: string;
109
+ k8sNamespace: string | undefined;
110
+ k8sConfig: string | undefined;
111
+ k8sContext: string | undefined;
112
+ entrypoint: string;
113
+ } | {
114
+ url: string | undefined;
115
+ topic: string | undefined;
116
+ requestData: string | undefined;
117
+ responseData?: undefined;
118
+ protocol: MockProtocol;
119
+ language: string;
120
+ framework: string;
121
+ output: string | undefined;
122
+ outputDir: string;
123
+ force: boolean;
124
+ deployDashboard: boolean | undefined;
125
+ runtime: string | undefined;
126
+ dockerNetwork: string | undefined;
127
+ dockerWorkerPort: string;
128
+ k8sNamespace: string | undefined;
129
+ k8sConfig: string | undefined;
130
+ k8sContext: string | undefined;
131
+ entrypoint: string;
132
+ } | {
133
+ method: string;
134
+ uri: string | undefined;
135
+ apiSchema: string[];
51
136
  requestData: string | undefined;
52
- responseData: string | undefined;
53
137
  responseStatusCode: string | undefined;
54
138
  formParams: string | undefined;
55
139
  requestAware: boolean | undefined;
56
140
  traceFilePath: string | undefined;
141
+ mockPort: number;
142
+ optionalFields: boolean;
143
+ responseData: string;
144
+ protocol: MockProtocol;
145
+ language: string;
146
+ framework: string;
147
+ output: string | undefined;
148
+ outputDir: string;
149
+ force: boolean;
150
+ deployDashboard: boolean | undefined;
151
+ runtime: string | undefined;
152
+ dockerNetwork: string | undefined;
153
+ dockerWorkerPort: string;
154
+ k8sNamespace: string | undefined;
155
+ k8sConfig: string | undefined;
156
+ k8sContext: string | undefined;
57
157
  entrypoint: string;
158
+ } | {
159
+ method: string;
160
+ uri: string | undefined;
161
+ apiSchema: string[];
162
+ requestData: string | undefined;
163
+ responseStatusCode: string | undefined;
164
+ formParams: string | undefined;
165
+ requestAware: boolean | undefined;
166
+ traceFilePath: string | undefined;
58
167
  mockPort: number;
59
168
  optionalFields: boolean;
169
+ responseData?: undefined;
170
+ protocol: MockProtocol;
171
+ language: string;
172
+ framework: string;
173
+ output: string | undefined;
174
+ outputDir: string;
175
+ force: boolean;
176
+ deployDashboard: boolean | undefined;
177
+ runtime: string | undefined;
178
+ dockerNetwork: string | undefined;
179
+ dockerWorkerPort: string;
180
+ k8sNamespace: string | undefined;
181
+ k8sConfig: string | undefined;
182
+ k8sContext: string | undefined;
183
+ entrypoint: string;
60
184
  };
61
185
  protected executeGeneration(generateOptions: any): Promise<string>;
62
186
  }
63
187
  export declare function registerMockTool(server: McpServer): void;
64
- export {};