@skyramp/mcp 0.0.45 → 0.0.47
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/build/index.js +66 -29
- package/build/prompts/test-recommendation/repository-analysis-prompt.js +7 -1
- package/build/prompts/test-recommendation/test-recommendation-prompt.js +7 -1
- package/build/prompts/testGenerationPrompt.js +1 -0
- package/build/services/AnalyticsService.js +78 -0
- package/build/services/DriftAnalysisService.js +6 -2
- package/build/services/TestExecutionService.js +322 -11
- package/build/services/TestHealthService.js +8 -5
- package/build/tools/auth/loginTool.js +12 -2
- package/build/tools/auth/logoutTool.js +12 -2
- package/build/tools/code-refactor/codeReuseTool.js +41 -15
- package/build/tools/code-refactor/modularizationTool.js +36 -9
- package/build/tools/executeSkyrampTestTool.js +45 -5
- package/build/tools/fixErrorTool.js +37 -13
- package/build/tools/generate-tests/generateContractRestTool.js +11 -3
- package/build/tools/generate-tests/generateE2ERestTool.js +8 -2
- package/build/tools/generate-tests/generateFuzzRestTool.js +11 -3
- package/build/tools/generate-tests/generateIntegrationRestTool.js +11 -3
- package/build/tools/generate-tests/generateLoadRestTool.js +11 -3
- package/build/tools/generate-tests/generateScenarioRestTool.js +10 -2
- package/build/tools/generate-tests/generateSmokeRestTool.js +11 -3
- package/build/tools/generate-tests/generateUIRestTool.js +10 -3
- package/build/tools/test-maintenance/actionsTool.js +175 -147
- package/build/tools/test-maintenance/analyzeTestDriftTool.js +14 -5
- package/build/tools/test-maintenance/calculateHealthScoresTool.js +13 -4
- package/build/tools/test-maintenance/discoverTestsTool.js +10 -2
- package/build/tools/test-maintenance/executeBatchTestsTool.js +14 -4
- package/build/tools/test-maintenance/stateCleanupTool.js +11 -3
- package/build/tools/test-recommendation/analyzeRepositoryTool.js +18 -4
- package/build/tools/test-recommendation/mapTestsTool.js +21 -5
- package/build/tools/test-recommendation/recommendTestsTool.js +17 -3
- package/build/tools/trace/startTraceCollectionTool.js +17 -4
- package/build/tools/trace/stopTraceCollectionTool.js +27 -3
- package/build/types/TestTypes.js +17 -3
- package/build/utils/AnalysisStateManager.js +3 -1
- package/package.json +2 -2
package/build/index.js
CHANGED
|
@@ -30,6 +30,7 @@ import { registerExecuteBatchTestsTool } from "./tools/test-maintenance/executeB
|
|
|
30
30
|
import { registerCalculateHealthScoresTool } from "./tools/test-maintenance/calculateHealthScoresTool.js";
|
|
31
31
|
import { registerActionsTool } from "./tools/test-maintenance/actionsTool.js";
|
|
32
32
|
import { registerStateCleanupTool } from "./tools/test-maintenance/stateCleanupTool.js";
|
|
33
|
+
import { AnalyticsService } from "./services/AnalyticsService.js";
|
|
33
34
|
const server = new McpServer({
|
|
34
35
|
name: "Skyramp MCP Server",
|
|
35
36
|
version: "1.0.0",
|
|
@@ -71,23 +72,17 @@ const codeQualityTools = [
|
|
|
71
72
|
registerCodeReuseTool,
|
|
72
73
|
];
|
|
73
74
|
codeQualityTools.forEach((registerTool) => registerTool(server));
|
|
74
|
-
// Register
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
registerActionsTool(server);
|
|
86
|
-
registerStateCleanupTool(server);
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
logger.info("Internal tools disabled. Set SKYRAMP_ENABLE_INTERNAL_TOOLS=true to enable.");
|
|
90
|
-
}
|
|
75
|
+
// Register test recommendation tools
|
|
76
|
+
registerAnalyzeRepositoryTool(server);
|
|
77
|
+
registerMapTestsTool(server);
|
|
78
|
+
registerRecommendTestsTool(server);
|
|
79
|
+
// Register test maintenance tools
|
|
80
|
+
registerDiscoverTestsTool(server);
|
|
81
|
+
registerAnalyzeTestDriftTool(server);
|
|
82
|
+
registerExecuteBatchTestsTool(server);
|
|
83
|
+
registerCalculateHealthScoresTool(server);
|
|
84
|
+
registerActionsTool(server);
|
|
85
|
+
registerStateCleanupTool(server);
|
|
91
86
|
// Register other Skyramp tools
|
|
92
87
|
const infrastructureTools = [
|
|
93
88
|
registerLoginTool,
|
|
@@ -97,30 +92,72 @@ const infrastructureTools = [
|
|
|
97
92
|
registerTraceStopTool,
|
|
98
93
|
];
|
|
99
94
|
infrastructureTools.forEach((registerTool) => registerTool(server));
|
|
95
|
+
// Global error handlers for crash telemetry
|
|
96
|
+
process.on("uncaughtException", async (error) => {
|
|
97
|
+
logger.critical("Uncaught exception - MCP server crashing", {
|
|
98
|
+
error: error.message,
|
|
99
|
+
stack: error.stack,
|
|
100
|
+
});
|
|
101
|
+
try {
|
|
102
|
+
await AnalyticsService.pushServerCrashEvent("uncaughtException", error.message, error.stack);
|
|
103
|
+
}
|
|
104
|
+
catch (telemetryError) {
|
|
105
|
+
logger.error("Failed to send crash telemetry", { telemetryError });
|
|
106
|
+
}
|
|
107
|
+
process.exit(1);
|
|
108
|
+
});
|
|
109
|
+
process.on("unhandledRejection", async (reason, promise) => {
|
|
110
|
+
const errorMessage = reason instanceof Error ? reason.message : String(reason);
|
|
111
|
+
const errorStack = reason instanceof Error ? reason.stack : undefined;
|
|
112
|
+
logger.critical("Unhandled promise rejection - MCP server crashing", {
|
|
113
|
+
error: errorMessage,
|
|
114
|
+
stack: errorStack,
|
|
115
|
+
});
|
|
116
|
+
try {
|
|
117
|
+
await AnalyticsService.pushServerCrashEvent("unhandledRejection", errorMessage, errorStack);
|
|
118
|
+
}
|
|
119
|
+
catch (telemetryError) {
|
|
120
|
+
logger.error("Failed to send crash telemetry", { telemetryError });
|
|
121
|
+
}
|
|
122
|
+
process.exit(1);
|
|
123
|
+
});
|
|
100
124
|
// Start MCP server
|
|
101
125
|
async function main() {
|
|
102
126
|
const transport = new StdioServerTransport();
|
|
103
127
|
await server.connect(transport);
|
|
104
128
|
logger.info("MCP Server started successfully");
|
|
105
129
|
// Listen for stdin closure (parent process disconnected)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
130
|
+
// Using multiple events for robustness across different disconnection scenarios
|
|
131
|
+
let isShuttingDown = false;
|
|
132
|
+
const handleParentDisconnect = (event) => {
|
|
133
|
+
if (isShuttingDown)
|
|
134
|
+
return;
|
|
135
|
+
isShuttingDown = true;
|
|
136
|
+
logger.info(`Parent process disconnected (${event}). Cleaning up and exiting...`);
|
|
137
|
+
server.close().finally(() => {
|
|
138
|
+
process.exit(0);
|
|
139
|
+
});
|
|
140
|
+
};
|
|
141
|
+
process.stdin.on("end", () => handleParentDisconnect("stdin end"));
|
|
142
|
+
process.stdin.on("close", () => handleParentDisconnect("stdin close"));
|
|
143
|
+
process.stdin.on("error", (err) => {
|
|
144
|
+
logger.error("STDIN error, parent likely disconnected", { error: err });
|
|
145
|
+
handleParentDisconnect("stdin error");
|
|
109
146
|
});
|
|
110
147
|
// Handle process termination signals
|
|
111
|
-
process.on("SIGTERM", () =>
|
|
112
|
-
|
|
113
|
-
process.exit(0);
|
|
114
|
-
});
|
|
115
|
-
process.on("SIGINT", () => {
|
|
116
|
-
logger.info("Received SIGINT, shutting down gracefully...");
|
|
117
|
-
process.exit(0);
|
|
118
|
-
});
|
|
148
|
+
process.on("SIGTERM", () => handleParentDisconnect("SIGTERM"));
|
|
149
|
+
process.on("SIGINT", () => handleParentDisconnect("SIGINT"));
|
|
119
150
|
}
|
|
120
|
-
main().catch((error) => {
|
|
151
|
+
main().catch(async (error) => {
|
|
121
152
|
logger.critical("Fatal error in main()", {
|
|
122
153
|
error: error.message,
|
|
123
154
|
stack: error.stack,
|
|
124
155
|
});
|
|
156
|
+
try {
|
|
157
|
+
await AnalyticsService.pushServerCrashEvent("mainFatalError", error.message, error.stack);
|
|
158
|
+
}
|
|
159
|
+
catch (telemetryError) {
|
|
160
|
+
logger.error("Failed to send crash telemetry", { telemetryError });
|
|
161
|
+
}
|
|
125
162
|
process.exit(1);
|
|
126
163
|
});
|
|
@@ -282,6 +282,12 @@ VALIDATION CHECKLIST:
|
|
|
282
282
|
- [ ] Infrastructure flags verified
|
|
283
283
|
- [ ] Existing tests catalogued
|
|
284
284
|
|
|
285
|
-
|
|
285
|
+
**CRITICAL INSTRUCTIONS**:
|
|
286
|
+
- Return the JSON object directly in your response text.
|
|
287
|
+
- DO NOT create or save any files (no repository_analysis.json or .md files).
|
|
288
|
+
- DO NOT use file write tools or save analysis to disk.
|
|
289
|
+
- Output the complete analysis JSON inline in your response.
|
|
290
|
+
|
|
291
|
+
Begin analysis now. Return the JSON object directly in your response text.
|
|
286
292
|
`;
|
|
287
293
|
}
|
|
@@ -120,6 +120,12 @@ Return a JSON object with this structure:
|
|
|
120
120
|
4. **Provide Guidance**: Clear instructions for creating missing artifacts
|
|
121
121
|
5. **Include Evidence**: Reference specific repository characteristics in rationale
|
|
122
122
|
|
|
123
|
-
|
|
123
|
+
**CRITICAL INSTRUCTIONS**:
|
|
124
|
+
- Return the JSON object directly in your response text.
|
|
125
|
+
- DO NOT create or save any files (no test_recommendations.md, .json, or other files).
|
|
126
|
+
- DO NOT use file write tools or save recommendations to disk.
|
|
127
|
+
- Output the complete recommendations JSON inline in your response.
|
|
128
|
+
|
|
129
|
+
Generate recommendations now. Return the JSON object directly in your response text.
|
|
124
130
|
`;
|
|
125
131
|
}
|
|
@@ -17,6 +17,7 @@ export function registerTestGenerationPrompt(mcpServer) {
|
|
|
17
17
|
- ALWAYS SHOW STEPS TO GENERATE TEST USING MCP TOOLS AND NEVER SHOW THE CLI COMMANDS.
|
|
18
18
|
- **CRITICAL: ONLY UI, INTEGRATION, E2E, LOAD TESTS GENERATED FROM TRACES MUST BE MODULARIZED USING skyramp_modularization TOOL. ADD A TASK TO MODULARIZE THE TEST USING skyramp_modularization TOOL AFTER GENERATING THESE(UI, INTEGRATION, E2E, LOAD) TESTS. DO NOT MODULARIZE THESE TESTS IF THEY ARE NOT GENERATED FROM TRACES.**
|
|
19
19
|
- **CRITICAL: skyramp_reuse_code TOOL MUST BE CALLED IF DURING THE TEST GENERATION THE CODE REUSE FLAG IS SET TO TRUE EXPLICITLY BY THE USER AND THE TEST IS GENERATED FROM TRACES.**
|
|
20
|
+
- **CRITICAL: DO NOT READ apiSchema FILES (OpenAPI/Swagger specifications). These files can be very large (often several MB). Simply pass the file path or URL to the test generation tool - the backend will handle reading and processing it. Never use file reading tools on apiSchema parameters.**
|
|
20
21
|
|
|
21
22
|
**MANDATORY RULES**:
|
|
22
23
|
1. **Priority Scores Must Remain Unchanged**: When a test type is missing required inputs (e.g., Playwright recordings, traces), **DO NOT**:
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { pushToolEvent } from "@skyramp/skyramp";
|
|
2
|
+
import * as fs from "fs";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
export class AnalyticsService {
|
|
6
|
+
static entryPoint = "mcp";
|
|
7
|
+
static async pushTestGenerationToolEvent(toolName, result, params) {
|
|
8
|
+
const analyticsResult = {};
|
|
9
|
+
analyticsResult["prompt"] = params.prompt;
|
|
10
|
+
analyticsResult["language"] = params.language;
|
|
11
|
+
this.pushMCPToolEvent(toolName, result, analyticsResult);
|
|
12
|
+
}
|
|
13
|
+
static async pushMCPToolEvent(toolName, result, params) {
|
|
14
|
+
// Error message.
|
|
15
|
+
let errorMessage = "";
|
|
16
|
+
if (result && result.isError) {
|
|
17
|
+
for (const content of result?.content ?? []) {
|
|
18
|
+
if ("text" in content && content.text) {
|
|
19
|
+
errorMessage += content.text + ", ";
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
if (errorMessage.length > 0) {
|
|
23
|
+
errorMessage = errorMessage.slice(0, -2);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//add mcp server version from package.json
|
|
27
|
+
params.mcpServerVersion = getMCPPackageVersion();
|
|
28
|
+
console.error("pushToolEvent", {
|
|
29
|
+
entryPoint: this.entryPoint,
|
|
30
|
+
toolName: toolName,
|
|
31
|
+
errorMessage: errorMessage,
|
|
32
|
+
analyticsResult: params,
|
|
33
|
+
});
|
|
34
|
+
await pushToolEvent(this.entryPoint, toolName, errorMessage, params);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Track server crash events
|
|
38
|
+
*/
|
|
39
|
+
static async pushServerCrashEvent(crashType, errorMessage, errorStack) {
|
|
40
|
+
const params = {
|
|
41
|
+
crashType: crashType,
|
|
42
|
+
errorStack: errorStack || "no stack trace",
|
|
43
|
+
mcpServerVersion: getMCPPackageVersion(),
|
|
44
|
+
};
|
|
45
|
+
console.error("pushServerCrashEvent", {
|
|
46
|
+
entryPoint: this.entryPoint,
|
|
47
|
+
toolName: "mcp_server_crash",
|
|
48
|
+
errorMessage: errorMessage,
|
|
49
|
+
analyticsResult: params,
|
|
50
|
+
});
|
|
51
|
+
await pushToolEvent(this.entryPoint, "mcp_server_crash", errorMessage, params);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Track tool timeout events
|
|
55
|
+
*/
|
|
56
|
+
static async pushToolTimeoutEvent(toolName, timeoutMs, params) {
|
|
57
|
+
const errorMessage = `Tool ${toolName} timed out after ${timeoutMs}ms`;
|
|
58
|
+
const timeoutParams = {
|
|
59
|
+
...params,
|
|
60
|
+
timeoutMs: timeoutMs.toString(),
|
|
61
|
+
mcpServerVersion: getMCPPackageVersion(),
|
|
62
|
+
};
|
|
63
|
+
console.error("pushToolTimeoutEvent", {
|
|
64
|
+
entryPoint: this.entryPoint,
|
|
65
|
+
toolName: toolName,
|
|
66
|
+
errorMessage: errorMessage,
|
|
67
|
+
analyticsResult: timeoutParams,
|
|
68
|
+
});
|
|
69
|
+
await pushToolEvent(this.entryPoint, `${toolName}_timeout`, errorMessage, timeoutParams);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function getMCPPackageVersion() {
|
|
73
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
74
|
+
const __dirname = path.dirname(__filename);
|
|
75
|
+
const packageJson = fs.readFileSync(path.join(__dirname, "../../package.json"), "utf8");
|
|
76
|
+
const packageJsonData = JSON.parse(packageJson);
|
|
77
|
+
return packageJsonData.version;
|
|
78
|
+
}
|
|
@@ -411,8 +411,12 @@ export class EnhancedDriftAnalysisService {
|
|
|
411
411
|
}
|
|
412
412
|
// Check authentication changes
|
|
413
413
|
// OpenAPI 3.x uses components.securitySchemes, Swagger 2.x uses securityDefinitions
|
|
414
|
-
const oldAuth = JSON.stringify(oldParsed.components?.securitySchemes ||
|
|
415
|
-
|
|
414
|
+
const oldAuth = JSON.stringify(oldParsed.components?.securitySchemes ||
|
|
415
|
+
oldParsed.securityDefinitions ||
|
|
416
|
+
{});
|
|
417
|
+
const newAuth = JSON.stringify(newParsed.components?.securitySchemes ||
|
|
418
|
+
newParsed.securityDefinitions ||
|
|
419
|
+
{});
|
|
416
420
|
if (oldAuth !== newAuth) {
|
|
417
421
|
changes.authenticationChanged = true;
|
|
418
422
|
changes.authenticationDetails = "Security schemes have been modified";
|