@mcpjam/inspector 0.3.9 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/BUILD_ID +1 -0
- package/.next/app-build-manifest.json +89 -0
- package/.next/app-path-routes-manifest.json +13 -0
- package/.next/build-manifest.json +33 -0
- package/.next/cache/.previewinfo +1 -0
- package/.next/cache/.rscinfo +1 -0
- package/.next/cache/.tsbuildinfo +1 -0
- package/.next/cache/eslint/.cache_11b5ofe +1 -0
- package/.next/cache/webpack/client-production/0.pack +0 -0
- package/.next/cache/webpack/client-production/index.pack +0 -0
- package/.next/cache/webpack/edge-server-production/0.pack +0 -0
- package/.next/cache/webpack/edge-server-production/index.pack +0 -0
- package/.next/cache/webpack/server-production/0.pack +0 -0
- package/.next/cache/webpack/server-production/index.pack +0 -0
- package/.next/diagnostics/build-diagnostics.json +6 -0
- package/.next/diagnostics/framework.json +1 -0
- package/.next/export-marker.json +6 -0
- package/.next/images-manifest.json +57 -0
- package/.next/next-minimal-server.js.nft.json +1 -0
- package/.next/next-server.js.nft.json +1 -0
- package/.next/package.json +1 -0
- package/.next/prerender-manifest.json +41 -0
- package/.next/react-loadable-manifest.json +1 -0
- package/.next/required-server-files.json +318 -0
- package/.next/routes-manifest.json +65 -0
- package/.next/server/app/_not-found/page.js +2 -0
- package/.next/server/app/_not-found/page.js.nft.json +1 -0
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -0
- package/.next/server/app/api/mcp/chat/route.js +45 -0
- package/.next/server/app/api/mcp/chat/route.js.nft.json +1 -0
- package/.next/server/app/api/mcp/chat/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/mcp/connect/route.js +1 -0
- package/.next/server/app/api/mcp/connect/route.js.nft.json +1 -0
- package/.next/server/app/api/mcp/connect/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/mcp/prompts/get/route.js +1 -0
- package/.next/server/app/api/mcp/prompts/get/route.js.nft.json +1 -0
- package/.next/server/app/api/mcp/prompts/get/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/mcp/prompts/list/route.js +1 -0
- package/.next/server/app/api/mcp/prompts/list/route.js.nft.json +1 -0
- package/.next/server/app/api/mcp/prompts/list/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/mcp/resources/list/route.js +1 -0
- package/.next/server/app/api/mcp/resources/list/route.js.nft.json +1 -0
- package/.next/server/app/api/mcp/resources/list/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/mcp/resources/read/route.js +1 -0
- package/.next/server/app/api/mcp/resources/read/route.js.nft.json +1 -0
- package/.next/server/app/api/mcp/resources/read/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/mcp/tools/route.js +21 -0
- package/.next/server/app/api/mcp/tools/route.js.nft.json +1 -0
- package/.next/server/app/api/mcp/tools/route_client-reference-manifest.js +1 -0
- package/.next/server/app/favicon.ico/route.js +1 -0
- package/.next/server/app/favicon.ico/route.js.nft.json +1 -0
- package/.next/server/app/favicon.ico.body +0 -0
- package/.next/server/app/favicon.ico.meta +1 -0
- package/.next/server/app/oauth/callback/page.js +2 -0
- package/.next/server/app/oauth/callback/page.js.nft.json +1 -0
- package/.next/server/app/oauth/callback/page_client-reference-manifest.js +1 -0
- package/.next/server/app/page.js +16 -0
- package/.next/server/app/page.js.nft.json +1 -0
- package/.next/server/app/page_client-reference-manifest.js +1 -0
- package/.next/server/app-paths-manifest.json +13 -0
- package/.next/server/chunks/175.js +8 -0
- package/.next/server/chunks/260.js +82 -0
- package/.next/server/chunks/546.js +1 -0
- package/.next/server/chunks/548.js +6 -0
- package/.next/server/chunks/55.js +1 -0
- package/.next/server/chunks/985.js +22 -0
- package/.next/server/functions-config-manifest.json +4 -0
- package/.next/server/interception-route-rewrite-manifest.js +1 -0
- package/.next/server/middleware-build-manifest.js +1 -0
- package/.next/server/middleware-manifest.json +6 -0
- package/.next/server/middleware-react-loadable-manifest.js +1 -0
- package/.next/server/next-font-manifest.js +1 -0
- package/.next/server/next-font-manifest.json +1 -0
- package/.next/server/pages/500.html +1 -0
- package/.next/server/pages/_app.js +1 -0
- package/.next/server/pages/_app.js.nft.json +1 -0
- package/.next/server/pages/_document.js +1 -0
- package/.next/server/pages/_document.js.nft.json +1 -0
- package/.next/server/pages/_error.js +19 -0
- package/.next/server/pages/_error.js.nft.json +1 -0
- package/.next/server/pages-manifest.json +5 -0
- package/.next/server/server-reference-manifest.js +1 -0
- package/.next/server/server-reference-manifest.json +1 -0
- package/.next/server/webpack-runtime.js +1 -0
- package/.next/static/chunks/14-ae3a01e72ea53777.js +1 -0
- package/.next/static/chunks/214-cc4c35d88f2695ed.js +1 -0
- package/.next/static/chunks/4bd1b696-cf72ae8a39fa05aa.js +1 -0
- package/.next/static/chunks/866-04c19dda4c52f2bf.js +1 -0
- package/.next/static/chunks/964-eda38e26c0391a47.js +1 -0
- package/.next/static/chunks/app/_not-found/page-d7e832b54474da82.js +1 -0
- package/.next/static/chunks/app/api/mcp/chat/route-0341498a8bf5f2da.js +1 -0
- package/.next/static/chunks/app/api/mcp/connect/route-0341498a8bf5f2da.js +1 -0
- package/.next/static/chunks/app/api/mcp/prompts/get/route-0341498a8bf5f2da.js +1 -0
- package/.next/static/chunks/app/api/mcp/prompts/list/route-0341498a8bf5f2da.js +1 -0
- package/.next/static/chunks/app/api/mcp/resources/list/route-0341498a8bf5f2da.js +1 -0
- package/.next/static/chunks/app/api/mcp/resources/read/route-0341498a8bf5f2da.js +1 -0
- package/.next/static/chunks/app/api/mcp/tools/route-0341498a8bf5f2da.js +1 -0
- package/.next/static/chunks/app/layout-fb6e1ad5933381f3.js +1 -0
- package/.next/static/chunks/app/oauth/callback/page-d8b3908ea67ba3e3.js +1 -0
- package/.next/static/chunks/app/page-81e35b2a61edb363.js +1 -0
- package/.next/static/chunks/framework-7c95b8e5103c9e90.js +1 -0
- package/.next/static/chunks/main-app-7d61da15faa6c1af.js +1 -0
- package/.next/static/chunks/main-bbdafee21a7bd1d6.js +1 -0
- package/.next/static/chunks/pages/_app-0a0020ddd67f79cf.js +1 -0
- package/.next/static/chunks/pages/_error-03529f2c21436739.js +1 -0
- package/.next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- package/.next/static/chunks/webpack-cdfccaf38062dd25.js +1 -0
- package/.next/static/css/1e852d83e9c1d0c6.css +1 -0
- package/.next/static/css/f30152c0704fba31.css +1 -0
- package/.next/static/css/fe751fdbe975e9ca.css +1 -0
- package/.next/static/media/569ce4b8f30dc480-s.p.woff2 +0 -0
- package/.next/static/media/747892c23ea88013-s.woff2 +0 -0
- package/.next/static/media/8d697b304b401681-s.woff2 +0 -0
- package/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
- package/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
- package/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
- package/.next/static/media/ollama_dark.9af45ac0.png +0 -0
- package/.next/static/media/ollama_logo.9f08a95b.svg +7 -0
- package/.next/static/media/openai_logo.3f83154a.png +0 -0
- package/.next/static/wgHmsxKAquUu9gOMW6Qd5/_buildManifest.js +1 -0
- package/.next/static/wgHmsxKAquUu9gOMW6Qd5/_ssgManifest.js +1 -0
- package/.next/trace +35 -0
- package/.next/types/app/api/mcp/chat/route.ts +347 -0
- package/.next/types/app/api/mcp/connect/route.ts +347 -0
- package/.next/types/app/api/mcp/prompts/get/route.ts +347 -0
- package/.next/types/app/api/mcp/prompts/list/route.ts +347 -0
- package/.next/types/app/api/mcp/resources/list/route.ts +347 -0
- package/.next/types/app/api/mcp/resources/read/route.ts +347 -0
- package/.next/types/app/api/mcp/tools/route.ts +347 -0
- package/.next/types/app/layout.ts +84 -0
- package/.next/types/app/oauth/callback/page.ts +84 -0
- package/.next/types/app/page.ts +84 -0
- package/.next/types/cache-life.d.ts +141 -0
- package/.next/types/package.json +1 -0
- package/README.md +76 -161
- package/bin/start.js +504 -0
- package/next.config.ts +7 -0
- package/package.json +71 -54
- package/public/claude_logo.png +0 -0
- package/public/demo_1.png +0 -0
- package/public/demo_2.png +0 -0
- package/public/demo_3.png +0 -0
- package/public/file.svg +1 -0
- package/public/globe.svg +1 -0
- package/public/mcp.svg +1 -0
- package/public/next.svg +1 -0
- package/public/ollama_dark.png +0 -0
- package/public/ollama_logo.svg +7 -0
- package/public/openai_logo.png +0 -0
- package/public/vercel.svg +1 -0
- package/public/window.svg +1 -0
- package/LICENSE +0 -200
- package/cli/build/cli.js +0 -251
- package/cli/build/client/connection.js +0 -33
- package/cli/build/client/index.js +0 -6
- package/cli/build/client/prompts.js +0 -23
- package/cli/build/client/resources.js +0 -30
- package/cli/build/client/tools.js +0 -64
- package/cli/build/client/types.js +0 -1
- package/cli/build/error-handler.js +0 -18
- package/cli/build/index.js +0 -166
- package/cli/build/transport.js +0 -47
- package/client/bin/client.js +0 -71
- package/client/bin/start.js +0 -143
- package/client/dist/assets/OAuthCallback-BSOXmPlE.js +0 -56
- package/client/dist/assets/OAuthDebugCallback-DyzqkofK.js +0 -44
- package/client/dist/assets/index-BT03cD-1.js +0 -63301
- package/client/dist/assets/index-Bwd_BFIj.css +0 -4164
- package/client/dist/index.html +0 -14
- package/client/dist/ollama_logo.png +0 -0
- package/client/dist/openai_logo.png +0 -0
- package/server/build/database/DatabaseManager.js +0 -108
- package/server/build/database/index.js +0 -8
- package/server/build/database/routes.js +0 -86
- package/server/build/database/types.js +0 -27
- package/server/build/database/utils.js +0 -86
- package/server/build/index.js +0 -331
- package/server/build/mcpProxy.js +0 -54
- package/server/build/shared/MCPProxyService.js +0 -221
- package/server/build/shared/TransportFactory.js +0 -130
- package/server/build/shared/index.js +0 -4
- package/server/build/shared/types.js +0 -1
- package/server/build/shared/utils.js +0 -27
- package/server/build/test-server.js +0 -145
- package/server/build/testing/HealthCheck.js +0 -42
- package/server/build/testing/TestExecutor.js +0 -240
- package/server/build/testing/TestRunner.js +0 -198
- package/server/build/testing/TestServer.js +0 -440
- package/server/build/testing/types.js +0 -1
- /package/{client/dist/claude_logo.png → .next/static/media/claude_logo.d33b25b0.png} +0 -0
- /package/{client/dist → public}/mcp_jam.svg +0 -0
- /package/{client/dist → public}/mcp_jam_dark.png +0 -0
- /package/{client/dist → public}/mcp_jam_light.png +0 -0
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
// server/src/testing/TestExecutor.ts
|
|
2
|
-
import { randomUUID } from "node:crypto";
|
|
3
|
-
export class TestExecutor {
|
|
4
|
-
mcpProxyService;
|
|
5
|
-
logger;
|
|
6
|
-
constructor(mcpProxyService, logger) {
|
|
7
|
-
this.mcpProxyService = mcpProxyService;
|
|
8
|
-
this.logger = logger;
|
|
9
|
-
}
|
|
10
|
-
async executeTest(testCase) {
|
|
11
|
-
const startTime = Date.now();
|
|
12
|
-
const resultId = randomUUID();
|
|
13
|
-
this.logger.info(`🧪 Starting test execution: ${testCase.name} (${testCase.id})`);
|
|
14
|
-
try {
|
|
15
|
-
// Validate test case
|
|
16
|
-
this.validateTestCase(testCase);
|
|
17
|
-
// Initialize connections to MCP servers
|
|
18
|
-
const connections = await this.initializeConnections(testCase);
|
|
19
|
-
// Execute the test
|
|
20
|
-
const toolCalls = await this.executeTestLogic(testCase, connections);
|
|
21
|
-
// Clean up connections
|
|
22
|
-
await this.cleanupConnections(connections);
|
|
23
|
-
const duration = Date.now() - startTime;
|
|
24
|
-
const result = {
|
|
25
|
-
id: resultId,
|
|
26
|
-
testCase: testCase,
|
|
27
|
-
toolCalls: toolCalls,
|
|
28
|
-
duration: duration,
|
|
29
|
-
success: true,
|
|
30
|
-
timestamp: new Date(),
|
|
31
|
-
metadata: {
|
|
32
|
-
executorVersion: "1.0.0",
|
|
33
|
-
executionMode: "single",
|
|
34
|
-
},
|
|
35
|
-
};
|
|
36
|
-
this.logger.info(`✅ Test execution completed: ${testCase.name} (${duration}ms)`);
|
|
37
|
-
return result;
|
|
38
|
-
}
|
|
39
|
-
catch (error) {
|
|
40
|
-
const duration = Date.now() - startTime;
|
|
41
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
42
|
-
this.logger.error(`❌ Test execution failed: ${testCase.name} - ${errorMessage}`);
|
|
43
|
-
const result = {
|
|
44
|
-
id: resultId,
|
|
45
|
-
testCase: testCase,
|
|
46
|
-
toolCalls: [],
|
|
47
|
-
duration: duration,
|
|
48
|
-
success: false,
|
|
49
|
-
error: errorMessage,
|
|
50
|
-
timestamp: new Date(),
|
|
51
|
-
metadata: {
|
|
52
|
-
executorVersion: "1.0.0",
|
|
53
|
-
executionMode: "single",
|
|
54
|
-
},
|
|
55
|
-
};
|
|
56
|
-
return result;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
validateTestCase(testCase) {
|
|
60
|
-
if (!testCase.id) {
|
|
61
|
-
throw new Error("Test case must have an ID");
|
|
62
|
-
}
|
|
63
|
-
if (!testCase.name) {
|
|
64
|
-
throw new Error("Test case must have a name");
|
|
65
|
-
}
|
|
66
|
-
if (!testCase.prompt) {
|
|
67
|
-
throw new Error("Test case must have a prompt");
|
|
68
|
-
}
|
|
69
|
-
if (!testCase.serverConfigs || testCase.serverConfigs.length === 0) {
|
|
70
|
-
throw new Error("Test case must have at least one server configuration");
|
|
71
|
-
}
|
|
72
|
-
// Validate timeout
|
|
73
|
-
if (testCase.timeout && testCase.timeout < 1000) {
|
|
74
|
-
throw new Error("Test case timeout must be at least 1000ms");
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
async initializeConnections(testCase) {
|
|
78
|
-
const connections = new Map();
|
|
79
|
-
for (const serverConfig of testCase.serverConfigs) {
|
|
80
|
-
try {
|
|
81
|
-
this.logger.info(`🔗 Initializing connection to server: ${serverConfig.name}`);
|
|
82
|
-
// Use MCPProxyService to create connection
|
|
83
|
-
let sessionId;
|
|
84
|
-
if (serverConfig.type === "stdio") {
|
|
85
|
-
// For STDIO, we need to create a mock response object for SSE
|
|
86
|
-
const mockResponse = {
|
|
87
|
-
writeHead: () => { },
|
|
88
|
-
write: () => { },
|
|
89
|
-
end: () => { },
|
|
90
|
-
on: () => { },
|
|
91
|
-
setHeader: () => { },
|
|
92
|
-
};
|
|
93
|
-
const connection = await this.mcpProxyService.createSSEConnection(serverConfig, mockResponse, {});
|
|
94
|
-
sessionId = connection.sessionId;
|
|
95
|
-
}
|
|
96
|
-
else if (serverConfig.type === "streamable-http") {
|
|
97
|
-
const connection = await this.mcpProxyService.createStreamableHTTPConnection(serverConfig, {});
|
|
98
|
-
sessionId = connection.sessionId;
|
|
99
|
-
}
|
|
100
|
-
else {
|
|
101
|
-
throw new Error(`Unsupported server type: ${serverConfig.type}`);
|
|
102
|
-
}
|
|
103
|
-
connections.set(serverConfig.id, sessionId);
|
|
104
|
-
this.logger.info(`✅ Connected to server: ${serverConfig.name} (${sessionId})`);
|
|
105
|
-
}
|
|
106
|
-
catch (error) {
|
|
107
|
-
this.logger.error(`❌ Failed to connect to server: ${serverConfig.name} - ${error}`);
|
|
108
|
-
throw new Error(`Failed to connect to server: ${serverConfig.name}`);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
return connections;
|
|
112
|
-
}
|
|
113
|
-
async executeTestLogic(testCase, connections) {
|
|
114
|
-
const toolCalls = [];
|
|
115
|
-
// Set timeout for the entire test execution
|
|
116
|
-
const timeout = testCase.timeout || 30000;
|
|
117
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
118
|
-
setTimeout(() => reject(new Error(`Test execution timed out after ${timeout}ms`)), timeout);
|
|
119
|
-
});
|
|
120
|
-
try {
|
|
121
|
-
// Execute the test logic with timeout
|
|
122
|
-
const result = await Promise.race([
|
|
123
|
-
this.runTestWithConnections(testCase, connections),
|
|
124
|
-
timeoutPromise,
|
|
125
|
-
]);
|
|
126
|
-
return result;
|
|
127
|
-
}
|
|
128
|
-
catch (error) {
|
|
129
|
-
if (error instanceof Error && error.message.includes("timed out")) {
|
|
130
|
-
this.logger.error(`⏱️ Test execution timed out: ${testCase.name}`);
|
|
131
|
-
}
|
|
132
|
-
throw error;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
async runTestWithConnections(testCase, connections) {
|
|
136
|
-
const toolCalls = [];
|
|
137
|
-
// For now, implement a simple test execution that simulates tool calls
|
|
138
|
-
// In a real implementation, this would involve:
|
|
139
|
-
// 1. Sending the prompt to an LLM
|
|
140
|
-
// 2. Processing tool calls returned by the LLM
|
|
141
|
-
// 3. Executing those tool calls against the connected MCP servers
|
|
142
|
-
// 4. Recording the results
|
|
143
|
-
this.logger.info(`🤖 Processing prompt: ${testCase.prompt.substring(0, 100)}...`);
|
|
144
|
-
// Simulate tool calls based on expected tools
|
|
145
|
-
if (testCase.expectedTools && testCase.expectedTools.length > 0) {
|
|
146
|
-
for (const expectedTool of testCase.expectedTools) {
|
|
147
|
-
for (const [serverId, _sessionId] of connections.entries()) {
|
|
148
|
-
const serverConfig = testCase.serverConfigs.find((s) => s.id === serverId);
|
|
149
|
-
if (!serverConfig)
|
|
150
|
-
continue;
|
|
151
|
-
const toolCallStartTime = Date.now();
|
|
152
|
-
try {
|
|
153
|
-
// Simulate tool call execution
|
|
154
|
-
await new Promise((resolve) => setTimeout(resolve, 100 + Math.random() * 400));
|
|
155
|
-
const toolCall = {
|
|
156
|
-
toolName: expectedTool,
|
|
157
|
-
serverId: serverId,
|
|
158
|
-
serverName: serverConfig.name,
|
|
159
|
-
parameters: {
|
|
160
|
-
prompt: testCase.prompt,
|
|
161
|
-
timestamp: new Date().toISOString(),
|
|
162
|
-
},
|
|
163
|
-
response: {
|
|
164
|
-
success: true,
|
|
165
|
-
data: `Mock response for ${expectedTool}`,
|
|
166
|
-
timestamp: new Date().toISOString(),
|
|
167
|
-
},
|
|
168
|
-
executionTimeMs: Date.now() - toolCallStartTime,
|
|
169
|
-
success: true,
|
|
170
|
-
timestamp: new Date(),
|
|
171
|
-
};
|
|
172
|
-
toolCalls.push(toolCall);
|
|
173
|
-
this.logger.info(`🔧 Tool call executed: ${expectedTool} on ${serverConfig.name}`);
|
|
174
|
-
}
|
|
175
|
-
catch (error) {
|
|
176
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
177
|
-
const toolCall = {
|
|
178
|
-
toolName: expectedTool,
|
|
179
|
-
serverId: serverId,
|
|
180
|
-
serverName: serverConfig.name,
|
|
181
|
-
parameters: {
|
|
182
|
-
prompt: testCase.prompt,
|
|
183
|
-
timestamp: new Date().toISOString(),
|
|
184
|
-
},
|
|
185
|
-
response: null,
|
|
186
|
-
executionTimeMs: Date.now() - toolCallStartTime,
|
|
187
|
-
success: false,
|
|
188
|
-
error: errorMessage,
|
|
189
|
-
timestamp: new Date(),
|
|
190
|
-
};
|
|
191
|
-
toolCalls.push(toolCall);
|
|
192
|
-
this.logger.error(`❌ Tool call failed: ${expectedTool} on ${serverConfig.name} - ${errorMessage}`);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
else {
|
|
198
|
-
// If no expected tools, simulate a basic interaction
|
|
199
|
-
const serverId = connections.keys().next().value;
|
|
200
|
-
if (serverId) {
|
|
201
|
-
const _sessionId = connections.get(serverId);
|
|
202
|
-
const serverConfig = testCase.serverConfigs.find((s) => s.id === serverId);
|
|
203
|
-
if (serverConfig) {
|
|
204
|
-
const toolCallStartTime = Date.now();
|
|
205
|
-
const toolCall = {
|
|
206
|
-
toolName: "default_interaction",
|
|
207
|
-
serverId: serverId,
|
|
208
|
-
serverName: serverConfig.name,
|
|
209
|
-
parameters: {
|
|
210
|
-
prompt: testCase.prompt,
|
|
211
|
-
timestamp: new Date().toISOString(),
|
|
212
|
-
},
|
|
213
|
-
response: {
|
|
214
|
-
success: true,
|
|
215
|
-
data: "Mock response for default interaction",
|
|
216
|
-
timestamp: new Date().toISOString(),
|
|
217
|
-
},
|
|
218
|
-
executionTimeMs: Date.now() - toolCallStartTime,
|
|
219
|
-
success: true,
|
|
220
|
-
timestamp: new Date(),
|
|
221
|
-
};
|
|
222
|
-
toolCalls.push(toolCall);
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
return toolCalls;
|
|
227
|
-
}
|
|
228
|
-
async cleanupConnections(connections) {
|
|
229
|
-
for (const [serverId, sessionId] of connections.entries()) {
|
|
230
|
-
try {
|
|
231
|
-
// Note: MCPProxyService doesn't have a direct cleanup method for individual sessions
|
|
232
|
-
// In a real implementation, you might want to add this functionality
|
|
233
|
-
this.logger.info(`🧹 Cleaning up connection: ${serverId} (${sessionId})`);
|
|
234
|
-
}
|
|
235
|
-
catch (error) {
|
|
236
|
-
this.logger.error(`❌ Failed to cleanup connection: ${serverId} - ${error}`);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
}
|
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
// server/src/testing/TestRunner.ts
|
|
2
|
-
import { EventEmitter } from "events";
|
|
3
|
-
import { randomUUID } from "node:crypto";
|
|
4
|
-
export class TestRunner extends EventEmitter {
|
|
5
|
-
mcpProxyService;
|
|
6
|
-
_database;
|
|
7
|
-
logger;
|
|
8
|
-
activeTests = new Map();
|
|
9
|
-
constructor(mcpProxyService, _database, logger) {
|
|
10
|
-
super();
|
|
11
|
-
this.mcpProxyService = mcpProxyService;
|
|
12
|
-
this._database = _database;
|
|
13
|
-
this.logger = logger;
|
|
14
|
-
}
|
|
15
|
-
async runTest(testCase) {
|
|
16
|
-
const testId = randomUUID();
|
|
17
|
-
const startTime = Date.now();
|
|
18
|
-
this.logger.info(`Starting test: ${testCase.name} (${testId})`);
|
|
19
|
-
try {
|
|
20
|
-
// Create test execution context
|
|
21
|
-
const execution = new TestExecution(testId, testCase, this.logger);
|
|
22
|
-
this.activeTests.set(testId, execution);
|
|
23
|
-
// Create MCP connections
|
|
24
|
-
const connections = await this.createConnections(testCase.serverConfigs);
|
|
25
|
-
execution.setConnections(connections);
|
|
26
|
-
// Execute test
|
|
27
|
-
const toolCalls = await this.executeTest(testCase, connections);
|
|
28
|
-
// Create result
|
|
29
|
-
const result = {
|
|
30
|
-
id: testId,
|
|
31
|
-
testCase,
|
|
32
|
-
toolCalls,
|
|
33
|
-
duration: Date.now() - startTime,
|
|
34
|
-
success: true,
|
|
35
|
-
timestamp: new Date(),
|
|
36
|
-
};
|
|
37
|
-
this.logger.info(`Test completed: ${testCase.name} (${testId})`);
|
|
38
|
-
this.emit("testComplete", result);
|
|
39
|
-
return result;
|
|
40
|
-
}
|
|
41
|
-
catch (error) {
|
|
42
|
-
this.logger.error(`Test failed: ${testCase.name} (${testId}):`, error);
|
|
43
|
-
const result = {
|
|
44
|
-
id: testId,
|
|
45
|
-
testCase,
|
|
46
|
-
toolCalls: [],
|
|
47
|
-
duration: Date.now() - startTime,
|
|
48
|
-
success: false,
|
|
49
|
-
error: error instanceof Error ? error.message : String(error),
|
|
50
|
-
timestamp: new Date(),
|
|
51
|
-
};
|
|
52
|
-
this.emit("testError", result, error);
|
|
53
|
-
return result;
|
|
54
|
-
}
|
|
55
|
-
finally {
|
|
56
|
-
this.activeTests.delete(testId);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
async runBatch(testCases) {
|
|
60
|
-
this.logger.info(`Starting batch test: ${testCases.length} tests`);
|
|
61
|
-
// Run tests in parallel with controlled concurrency
|
|
62
|
-
const maxConcurrency = 5;
|
|
63
|
-
const results = [];
|
|
64
|
-
for (let i = 0; i < testCases.length; i += maxConcurrency) {
|
|
65
|
-
const batch = testCases.slice(i, i + maxConcurrency);
|
|
66
|
-
const batchResults = await Promise.all(batch.map((testCase) => this.runTest(testCase)));
|
|
67
|
-
results.push(...batchResults);
|
|
68
|
-
}
|
|
69
|
-
this.logger.info(`Batch test completed: ${results.length} results`);
|
|
70
|
-
return results;
|
|
71
|
-
}
|
|
72
|
-
async getResults(_query) {
|
|
73
|
-
// Mock implementation - in real version would query database
|
|
74
|
-
return [];
|
|
75
|
-
}
|
|
76
|
-
async getResult(_id) {
|
|
77
|
-
// Mock implementation - in real version would query database
|
|
78
|
-
return null;
|
|
79
|
-
}
|
|
80
|
-
getActiveConnections() {
|
|
81
|
-
return this.mcpProxyService.getActiveConnections();
|
|
82
|
-
}
|
|
83
|
-
async closeConnection(id) {
|
|
84
|
-
// Note: MCPProxyService doesn't have closeConnection method
|
|
85
|
-
// Would need to be implemented
|
|
86
|
-
this.logger.info(`Closing connection: ${id}`);
|
|
87
|
-
}
|
|
88
|
-
async close() {
|
|
89
|
-
// Close all active tests
|
|
90
|
-
for (const [_testId, execution] of this.activeTests) {
|
|
91
|
-
await execution.cancel();
|
|
92
|
-
}
|
|
93
|
-
this.activeTests.clear();
|
|
94
|
-
// Close MCP connections
|
|
95
|
-
await this.mcpProxyService.closeAllConnections();
|
|
96
|
-
this.logger.info("Test runner closed");
|
|
97
|
-
}
|
|
98
|
-
async createConnections(serverConfigs) {
|
|
99
|
-
const connections = [];
|
|
100
|
-
for (const config of serverConfigs) {
|
|
101
|
-
try {
|
|
102
|
-
let sessionId;
|
|
103
|
-
if (config.type === "stdio") {
|
|
104
|
-
// For STDIO, create a mock response for SSE
|
|
105
|
-
const mockResponse = {
|
|
106
|
-
writeHead: () => { },
|
|
107
|
-
write: () => { },
|
|
108
|
-
end: () => { },
|
|
109
|
-
on: () => { },
|
|
110
|
-
setHeader: () => { },
|
|
111
|
-
};
|
|
112
|
-
const connection = await this.mcpProxyService.createSSEConnection(config, mockResponse, {});
|
|
113
|
-
sessionId = connection.sessionId;
|
|
114
|
-
}
|
|
115
|
-
else if (config.type === "streamable-http") {
|
|
116
|
-
const connection = await this.mcpProxyService.createStreamableHTTPConnection(config, {});
|
|
117
|
-
sessionId = connection.sessionId;
|
|
118
|
-
}
|
|
119
|
-
else {
|
|
120
|
-
throw new Error(`Unsupported server type: ${config.type}`);
|
|
121
|
-
}
|
|
122
|
-
connections.push(sessionId);
|
|
123
|
-
this.logger.info(`Created connection: ${config.name} (${sessionId})`);
|
|
124
|
-
}
|
|
125
|
-
catch (error) {
|
|
126
|
-
this.logger.error(`Failed to create connection for ${config.name}:`, error);
|
|
127
|
-
throw error;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
return connections;
|
|
131
|
-
}
|
|
132
|
-
async executeTest(testCase, connections) {
|
|
133
|
-
const toolCalls = [];
|
|
134
|
-
const _timeout = testCase.timeout || 30000;
|
|
135
|
-
// Simple mock execution for now
|
|
136
|
-
// In real implementation, would use LLM to process prompt and make tool calls
|
|
137
|
-
if (testCase.expectedTools && testCase.expectedTools.length > 0) {
|
|
138
|
-
for (const expectedTool of testCase.expectedTools) {
|
|
139
|
-
const toolCallStartTime = Date.now();
|
|
140
|
-
try {
|
|
141
|
-
// Mock tool call execution
|
|
142
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
143
|
-
const toolCall = {
|
|
144
|
-
toolName: expectedTool,
|
|
145
|
-
serverId: connections[0] || "unknown",
|
|
146
|
-
serverName: "Mock Server",
|
|
147
|
-
parameters: { test: true },
|
|
148
|
-
response: {
|
|
149
|
-
success: true,
|
|
150
|
-
data: `Mock response for ${expectedTool}`,
|
|
151
|
-
},
|
|
152
|
-
executionTimeMs: Date.now() - toolCallStartTime,
|
|
153
|
-
success: true,
|
|
154
|
-
timestamp: new Date(),
|
|
155
|
-
};
|
|
156
|
-
toolCalls.push(toolCall);
|
|
157
|
-
}
|
|
158
|
-
catch (error) {
|
|
159
|
-
const toolCall = {
|
|
160
|
-
toolName: expectedTool,
|
|
161
|
-
serverId: connections[0] || "unknown",
|
|
162
|
-
serverName: "Mock Server",
|
|
163
|
-
parameters: { test: true },
|
|
164
|
-
response: null,
|
|
165
|
-
executionTimeMs: Date.now() - toolCallStartTime,
|
|
166
|
-
success: false,
|
|
167
|
-
error: error instanceof Error ? error.message : String(error),
|
|
168
|
-
timestamp: new Date(),
|
|
169
|
-
};
|
|
170
|
-
toolCalls.push(toolCall);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
return toolCalls;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
class TestExecution {
|
|
178
|
-
id;
|
|
179
|
-
testCase;
|
|
180
|
-
logger;
|
|
181
|
-
_connections = [];
|
|
182
|
-
cancelled = false;
|
|
183
|
-
constructor(id, testCase, logger) {
|
|
184
|
-
this.id = id;
|
|
185
|
-
this.testCase = testCase;
|
|
186
|
-
this.logger = logger;
|
|
187
|
-
}
|
|
188
|
-
setConnections(connections) {
|
|
189
|
-
this._connections = connections;
|
|
190
|
-
}
|
|
191
|
-
async cancel() {
|
|
192
|
-
this.cancelled = true;
|
|
193
|
-
this.logger.info(`Test execution cancelled: ${this.id}`);
|
|
194
|
-
}
|
|
195
|
-
isCancelled() {
|
|
196
|
-
return this.cancelled;
|
|
197
|
-
}
|
|
198
|
-
}
|