@toolsdk.ai/registry 1.0.113 → 1.0.114
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/dist/api/package-handler.js +7 -6
- package/dist/api/package-so.d.ts +7 -7
- package/dist/api/package-so.js +45 -85
- package/dist/helper.d.ts +3 -1
- package/dist/helper.js +34 -0
- package/dist/sandbox/mcp-sandbox-client.d.ts +4 -25
- package/dist/sandbox/mcp-sandbox-client.js +92 -291
- package/dist/sandbox/mcp-sandbox-client.test.d.ts +1 -0
- package/dist/sandbox/mcp-sandbox-client.test.js +491 -0
- package/dist/types.d.ts +1 -0
- package/package.json +2 -1
- package/packages/search-data-extraction/ref-tools-mcp.json +7 -2
|
@@ -1,13 +1,12 @@
|
|
|
1
|
+
import { getSandboxProvider } from "../helper";
|
|
1
2
|
import { createErrorResponse, createResponse } from "../utils";
|
|
2
3
|
import { PackageSO } from "./package-so";
|
|
3
|
-
const shouldUseSandbox = () => {
|
|
4
|
-
return process.env.USE_MCP_SANDBOX === "true";
|
|
5
|
-
};
|
|
6
4
|
export const packageHandler = {
|
|
7
5
|
executeTool: async (c) => {
|
|
8
6
|
const requestBody = await c.req.json();
|
|
7
|
+
const provider = getSandboxProvider();
|
|
9
8
|
try {
|
|
10
|
-
const toolSO = new PackageSO(
|
|
9
|
+
const toolSO = new PackageSO(provider);
|
|
11
10
|
const result = await toolSO.executeTool(requestBody);
|
|
12
11
|
const response = createResponse(result);
|
|
13
12
|
return c.json(response, 200);
|
|
@@ -35,8 +34,9 @@ export const packageHandler = {
|
|
|
35
34
|
const errorResponse = createErrorResponse("Missing packageName query parameter", 400);
|
|
36
35
|
return c.json(errorResponse, 200);
|
|
37
36
|
}
|
|
37
|
+
const provider = getSandboxProvider();
|
|
38
38
|
try {
|
|
39
|
-
const toolSO = new PackageSO(
|
|
39
|
+
const toolSO = new PackageSO(provider);
|
|
40
40
|
const result = await toolSO.getPackageDetail(packageName);
|
|
41
41
|
const response = createResponse(result);
|
|
42
42
|
return c.json(response, 200);
|
|
@@ -55,8 +55,9 @@ export const packageHandler = {
|
|
|
55
55
|
const errorResponse = createErrorResponse("Missing packageName query parameter", 400);
|
|
56
56
|
return c.json(errorResponse, 200);
|
|
57
57
|
}
|
|
58
|
+
const provider = getSandboxProvider();
|
|
58
59
|
try {
|
|
59
|
-
const toolSO = new PackageSO(
|
|
60
|
+
const toolSO = new PackageSO(provider);
|
|
60
61
|
const result = await toolSO.listTools(packageName);
|
|
61
62
|
const response = createResponse(result);
|
|
62
63
|
return c.json(response, 200);
|
package/dist/api/package-so.d.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import type { Tool } from "@modelcontextprotocol/sdk/types.js";
|
|
2
2
|
import { MCPSandboxClient } from "../sandbox/mcp-sandbox-client.js";
|
|
3
|
-
import type { MCPServerPackageConfig, ToolExecute } from "../types";
|
|
3
|
+
import type { MCPSandboxProvider, MCPServerPackageConfig, ToolExecute } from "../types";
|
|
4
4
|
export declare class PackageSO {
|
|
5
|
-
private
|
|
6
|
-
private sandboxClient;
|
|
5
|
+
private sandboxProvider;
|
|
7
6
|
private static sandboxInstances;
|
|
8
7
|
private static MAX_SANDBOXES;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
static
|
|
12
|
-
static releaseSandbox(key?: string): Promise<void>;
|
|
8
|
+
constructor(provider?: MCPSandboxProvider);
|
|
9
|
+
static acquireSandbox(runtime?: "node" | "python" | "java" | "go", provider?: MCPSandboxProvider): Promise<MCPSandboxClient>;
|
|
10
|
+
static releaseSandbox(runtime?: "node" | "python" | "java" | "go", provider?: MCPSandboxProvider): Promise<void>;
|
|
13
11
|
static cleanupSandboxInstances(): Promise<void>;
|
|
12
|
+
private static getSandboxKey;
|
|
13
|
+
private isSandboxEnabled;
|
|
14
14
|
executeTool(request: ToolExecute): Promise<unknown>;
|
|
15
15
|
private executeToolInSandbox;
|
|
16
16
|
listTools(packageName: string): Promise<Tool[]>;
|
package/dist/api/package-so.js
CHANGED
|
@@ -5,66 +5,17 @@ import { MCPSandboxClient } from "../sandbox/mcp-sandbox-client.js";
|
|
|
5
5
|
import { getDirname } from "../utils";
|
|
6
6
|
const __dirname = getDirname(import.meta.url);
|
|
7
7
|
export class PackageSO {
|
|
8
|
-
constructor(
|
|
9
|
-
this.
|
|
10
|
-
this.
|
|
11
|
-
this.useSandbox = useSandbox;
|
|
12
|
-
if (useSandbox) {
|
|
13
|
-
const sandboxKey = "default";
|
|
14
|
-
const record = PackageSO.sandboxInstances.get(sandboxKey);
|
|
15
|
-
if (record) {
|
|
16
|
-
record.refCount++;
|
|
17
|
-
record.lastUsedAt = Date.now();
|
|
18
|
-
this.sandboxClient = record.client;
|
|
19
|
-
// Cancel all idle close timer
|
|
20
|
-
record.client.touch();
|
|
21
|
-
}
|
|
22
|
-
else {
|
|
23
|
-
// Create a new instance if none exists (subject to max limit)
|
|
24
|
-
this.sandboxClient = new MCPSandboxClient();
|
|
25
|
-
const newRecord = {
|
|
26
|
-
client: this.sandboxClient,
|
|
27
|
-
refCount: 1,
|
|
28
|
-
lastUsedAt: Date.now(),
|
|
29
|
-
idleCloseMs: PackageSO.IDLE_CLOSE_MS,
|
|
30
|
-
};
|
|
31
|
-
// Try to insert, evict LRU idle instance if MAX is reached
|
|
32
|
-
if (PackageSO.sandboxInstances.size >= PackageSO.MAX_SANDBOXES) {
|
|
33
|
-
// Find the oldest idle instance (refCount === 0)
|
|
34
|
-
let lruKey = null;
|
|
35
|
-
let lruTime = Infinity;
|
|
36
|
-
for (const [k, r] of PackageSO.sandboxInstances) {
|
|
37
|
-
if (r.refCount === 0 && r.lastUsedAt < lruTime) {
|
|
38
|
-
lruKey = k;
|
|
39
|
-
lruTime = r.lastUsedAt;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
if (lruKey) {
|
|
43
|
-
const evict = PackageSO.sandboxInstances.get(lruKey);
|
|
44
|
-
// Immediately close and delete
|
|
45
|
-
if (evict) {
|
|
46
|
-
evict.client.kill().catch((e) => {
|
|
47
|
-
console.error("[PackageSO] Error killing evicted sandbox:", e);
|
|
48
|
-
});
|
|
49
|
-
PackageSO.sandboxInstances.delete(lruKey);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
else {
|
|
53
|
-
// No recyclable instances -> throw error to prevent exceeding system limit
|
|
54
|
-
throw new Error("Cannot create new sandbox: max sandboxes reached and none are idle");
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
PackageSO.sandboxInstances.set(sandboxKey, newRecord);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
8
|
+
constructor(provider = "LOCAL") {
|
|
9
|
+
this.sandboxProvider = "LOCAL";
|
|
10
|
+
this.sandboxProvider = provider;
|
|
60
11
|
}
|
|
61
12
|
// Acquire / Release explicit APIs (for external or future use)
|
|
62
|
-
static async acquireSandbox(
|
|
63
|
-
const
|
|
13
|
+
static async acquireSandbox(runtime = "python", provider = "DAYTONA") {
|
|
14
|
+
const sandboxKey = PackageSO.getSandboxKey(runtime, provider);
|
|
15
|
+
const record = PackageSO.sandboxInstances.get(sandboxKey);
|
|
64
16
|
if (record) {
|
|
65
17
|
record.refCount++;
|
|
66
18
|
record.lastUsedAt = Date.now();
|
|
67
|
-
record.client.touch();
|
|
68
19
|
return record.client;
|
|
69
20
|
}
|
|
70
21
|
// Create new instance (note MAX_SANDBOXES check, consistent with constructor logic)
|
|
@@ -91,25 +42,32 @@ export class PackageSO {
|
|
|
91
42
|
throw new Error("Cannot create new sandbox: max sandboxes reached and none are idle");
|
|
92
43
|
}
|
|
93
44
|
}
|
|
94
|
-
const client = new MCPSandboxClient();
|
|
45
|
+
const client = new MCPSandboxClient(runtime, provider);
|
|
95
46
|
const newRecord = {
|
|
96
47
|
client,
|
|
97
48
|
refCount: 1,
|
|
98
49
|
lastUsedAt: Date.now(),
|
|
99
|
-
|
|
50
|
+
provider,
|
|
100
51
|
};
|
|
101
|
-
PackageSO.sandboxInstances.set(
|
|
52
|
+
PackageSO.sandboxInstances.set(sandboxKey, newRecord);
|
|
102
53
|
return client;
|
|
103
54
|
}
|
|
104
|
-
static async releaseSandbox(
|
|
105
|
-
const
|
|
55
|
+
static async releaseSandbox(runtime = "python", provider = "DAYTONA") {
|
|
56
|
+
const sandboxKey = PackageSO.getSandboxKey(runtime, provider);
|
|
57
|
+
const record = PackageSO.sandboxInstances.get(sandboxKey);
|
|
106
58
|
if (!record)
|
|
107
59
|
return;
|
|
108
60
|
record.refCount = Math.max(0, record.refCount - 1);
|
|
109
61
|
record.lastUsedAt = Date.now();
|
|
110
62
|
if (record.refCount === 0) {
|
|
111
|
-
|
|
112
|
-
|
|
63
|
+
try {
|
|
64
|
+
await record.client.kill();
|
|
65
|
+
PackageSO.sandboxInstances.delete(sandboxKey);
|
|
66
|
+
console.log(`[PackageSO] Sandbox ${sandboxKey} closed immediately after use`);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
console.error(`[PackageSO] Error closing sandbox ${sandboxKey}:`, error);
|
|
70
|
+
}
|
|
113
71
|
}
|
|
114
72
|
}
|
|
115
73
|
// Cleanup all static sandbox instances safely
|
|
@@ -128,9 +86,15 @@ export class PackageSO {
|
|
|
128
86
|
}
|
|
129
87
|
await Promise.all(killers);
|
|
130
88
|
}
|
|
89
|
+
static getSandboxKey(runtime, provider) {
|
|
90
|
+
return `sandbox-${provider}-${runtime}`;
|
|
91
|
+
}
|
|
92
|
+
isSandboxEnabled() {
|
|
93
|
+
return this.sandboxProvider === "DAYTONA" || this.sandboxProvider === "SANDOCK";
|
|
94
|
+
}
|
|
131
95
|
async executeTool(request) {
|
|
132
96
|
const mcpServerConfig = getPackageConfigByKey(request.packageName);
|
|
133
|
-
if (this.
|
|
97
|
+
if (this.isSandboxEnabled()) {
|
|
134
98
|
try {
|
|
135
99
|
const result = await this.executeToolInSandbox(request);
|
|
136
100
|
return result;
|
|
@@ -153,15 +117,13 @@ export class PackageSO {
|
|
|
153
117
|
}
|
|
154
118
|
}
|
|
155
119
|
async executeToolInSandbox(request) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
120
|
+
const mcpServerConfig = getPackageConfigByKey(request.packageName);
|
|
121
|
+
const runtime = mcpServerConfig.runtime || "python"; // Default to python if not specified
|
|
122
|
+
const sandboxClient = await PackageSO.acquireSandbox(runtime, this.sandboxProvider);
|
|
159
123
|
// Initialize if not already initialized (concurrency protection via MCPSandboxClient.initialize)
|
|
160
|
-
await
|
|
161
|
-
// Mark usage
|
|
162
|
-
this.sandboxClient.touch();
|
|
124
|
+
await sandboxClient.initialize();
|
|
163
125
|
try {
|
|
164
|
-
const result = await
|
|
126
|
+
const result = await sandboxClient.executeTool(request.packageName, request.toolKey, request.inputData || {}, request.envs);
|
|
165
127
|
console.log(`Tool ${request.toolKey} executed successfully in sandbox`);
|
|
166
128
|
return result;
|
|
167
129
|
}
|
|
@@ -169,9 +131,9 @@ export class PackageSO {
|
|
|
169
131
|
// If it's a sandbox not found error, try reinitializing and retrying once
|
|
170
132
|
if (error instanceof Error && error.message.includes("sandbox was not found")) {
|
|
171
133
|
console.log("[PackageSO] Retrying tool execution after sandbox failure");
|
|
172
|
-
await
|
|
134
|
+
await sandboxClient.initialize();
|
|
173
135
|
// Retry tool execution
|
|
174
|
-
const result = await
|
|
136
|
+
const result = await sandboxClient.executeTool(request.packageName, request.toolKey, request.inputData || {}, request.envs);
|
|
175
137
|
console.log(`Tool ${request.toolKey} executed successfully in sandbox (retry)`);
|
|
176
138
|
return result;
|
|
177
139
|
}
|
|
@@ -179,12 +141,12 @@ export class PackageSO {
|
|
|
179
141
|
}
|
|
180
142
|
finally {
|
|
181
143
|
// Release reference count
|
|
182
|
-
await PackageSO.releaseSandbox(
|
|
144
|
+
await PackageSO.releaseSandbox(runtime, this.sandboxProvider);
|
|
183
145
|
}
|
|
184
146
|
}
|
|
185
147
|
async listTools(packageName) {
|
|
186
148
|
const mcpServerConfig = getPackageConfigByKey(packageName);
|
|
187
|
-
if (this.
|
|
149
|
+
if (this.isSandboxEnabled()) {
|
|
188
150
|
try {
|
|
189
151
|
const tools = await this.listToolsInSandbox(packageName);
|
|
190
152
|
return tools;
|
|
@@ -210,14 +172,13 @@ export class PackageSO {
|
|
|
210
172
|
}
|
|
211
173
|
}
|
|
212
174
|
async listToolsInSandbox(packageName) {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
// Initialize only if sandbox is not initialized
|
|
217
|
-
await this.sandboxClient.initialize();
|
|
218
|
-
this.sandboxClient.touch();
|
|
175
|
+
const mcpServerConfig = getPackageConfigByKey(packageName);
|
|
176
|
+
const runtime = mcpServerConfig.runtime || "python";
|
|
177
|
+
const sandboxClient = await PackageSO.acquireSandbox(runtime, this.sandboxProvider);
|
|
219
178
|
try {
|
|
220
|
-
|
|
179
|
+
// Initialize only if sandbox is not initialized
|
|
180
|
+
await sandboxClient.initialize();
|
|
181
|
+
const tools = await sandboxClient.listTools(packageName);
|
|
221
182
|
console.log(`Tools list retrieved successfully for package ${packageName} in sandbox`);
|
|
222
183
|
return tools;
|
|
223
184
|
}
|
|
@@ -225,16 +186,16 @@ export class PackageSO {
|
|
|
225
186
|
// If it's a sandbox not found error, try reinitializing and retrying once
|
|
226
187
|
if (error instanceof Error && error.message.includes("sandbox was not found")) {
|
|
227
188
|
console.log("[PackageSO] Retrying tools listing after sandbox failure");
|
|
228
|
-
await
|
|
189
|
+
await sandboxClient.initialize();
|
|
229
190
|
// Retry listing tools
|
|
230
|
-
const tools = await
|
|
191
|
+
const tools = await sandboxClient.listTools(packageName);
|
|
231
192
|
console.log(`Tools list retrieved successfully for package ${packageName} in sandbox (retry)`);
|
|
232
193
|
return tools;
|
|
233
194
|
}
|
|
234
195
|
throw error;
|
|
235
196
|
}
|
|
236
197
|
finally {
|
|
237
|
-
await PackageSO.releaseSandbox(
|
|
198
|
+
await PackageSO.releaseSandbox(runtime, this.sandboxProvider);
|
|
238
199
|
}
|
|
239
200
|
}
|
|
240
201
|
async getPackageDetail(packageName) {
|
|
@@ -260,4 +221,3 @@ export class PackageSO {
|
|
|
260
221
|
}
|
|
261
222
|
PackageSO.sandboxInstances = new Map();
|
|
262
223
|
PackageSO.MAX_SANDBOXES = 10;
|
|
263
|
-
PackageSO.IDLE_CLOSE_MS = 5 * 60 * 1000;
|
package/dist/helper.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
2
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
3
|
-
import type { MCPServerPackageConfig } from "./types";
|
|
3
|
+
import type { MCPSandboxProvider, MCPServerPackageConfig } from "./types";
|
|
4
4
|
export declare const typedAllPackagesList: Record<string, {
|
|
5
5
|
path: string;
|
|
6
6
|
category?: string | undefined;
|
|
@@ -10,6 +10,7 @@ export declare const typedAllPackagesList: Record<string, {
|
|
|
10
10
|
name?: string | undefined;
|
|
11
11
|
}> | undefined;
|
|
12
12
|
}>;
|
|
13
|
+
export declare function getSandboxProvider(): MCPSandboxProvider;
|
|
13
14
|
export declare function getPackageConfigByKey(packageKey: string): MCPServerPackageConfig;
|
|
14
15
|
export declare function getPackageJSON(packageName: string): any;
|
|
15
16
|
export declare function getMcpClient(mcpServerConfig: MCPServerPackageConfig, env?: Record<string, string>): Promise<{
|
|
@@ -69,4 +70,5 @@ export declare function extractPackageName(dep: string): string;
|
|
|
69
70
|
* @returns Array of Python dependency names
|
|
70
71
|
*/
|
|
71
72
|
export declare function getPythonDependencies(): string[];
|
|
73
|
+
export declare function extractLastOuterJSON(str: string): string;
|
|
72
74
|
export {};
|
package/dist/helper.js
CHANGED
|
@@ -11,6 +11,14 @@ import { getDirname } from "../src/utils";
|
|
|
11
11
|
import { MCPServerPackageConfigSchema, PackagesListSchema } from "./schema";
|
|
12
12
|
const __dirname = getDirname(import.meta.url);
|
|
13
13
|
export const typedAllPackagesList = PackagesListSchema.parse(allPackagesList);
|
|
14
|
+
export function getSandboxProvider() {
|
|
15
|
+
const provider = (process.env.MCP_SANDBOX_PROVIDER || "LOCAL").toUpperCase();
|
|
16
|
+
if (provider === "LOCAL" || provider === "DAYTONA" || provider === "SANDOCK") {
|
|
17
|
+
return provider;
|
|
18
|
+
}
|
|
19
|
+
console.warn(`[helper] Unsupported MCP_SANDBOX_PROVIDER value '${provider}', falling back to LOCAL mode`);
|
|
20
|
+
return "LOCAL";
|
|
21
|
+
}
|
|
14
22
|
export function getPackageConfigByKey(packageKey) {
|
|
15
23
|
const value = typedAllPackagesList[packageKey];
|
|
16
24
|
if (!value) {
|
|
@@ -101,6 +109,7 @@ export function updatePackageJsonDependencies({ packageDeps, enableValidation =
|
|
|
101
109
|
const packageJsonFile = "./package.json";
|
|
102
110
|
const packageJSONStr = fs.readFileSync(packageJsonFile, "utf-8");
|
|
103
111
|
const newDeps = {
|
|
112
|
+
"@daytonaio/sdk": "0.109.0",
|
|
104
113
|
"@e2b/code-interpreter": "^2.0.0",
|
|
105
114
|
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
106
115
|
"@hono/node-server": "1.15.0",
|
|
@@ -276,3 +285,28 @@ export function getPythonDependencies() {
|
|
|
276
285
|
const deps = ((_a = data.project) === null || _a === void 0 ? void 0 : _a.dependencies) || [];
|
|
277
286
|
return deps.map(extractPackageName);
|
|
278
287
|
}
|
|
288
|
+
export function extractLastOuterJSON(str) {
|
|
289
|
+
let braceCount = 0;
|
|
290
|
+
let end = -1;
|
|
291
|
+
let start = -1;
|
|
292
|
+
for (let i = str.length - 1; i >= 0; i--) {
|
|
293
|
+
const ch = str[i];
|
|
294
|
+
if (ch === "}") {
|
|
295
|
+
if (end === -1)
|
|
296
|
+
end = i;
|
|
297
|
+
braceCount++;
|
|
298
|
+
}
|
|
299
|
+
else if (ch === "{") {
|
|
300
|
+
braceCount--;
|
|
301
|
+
if (braceCount === 0 && end !== -1) {
|
|
302
|
+
start = i;
|
|
303
|
+
break;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
if (start === -1 || end === -1) {
|
|
308
|
+
throw new Error("No valid JSON found in string");
|
|
309
|
+
}
|
|
310
|
+
const jsonStr = str.slice(start, end + 1);
|
|
311
|
+
return jsonStr;
|
|
312
|
+
}
|
|
@@ -1,37 +1,16 @@
|
|
|
1
1
|
import type { Tool } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
import type { MCPSandboxProvider } from "../types";
|
|
2
3
|
export declare class MCPSandboxClient {
|
|
3
4
|
private sandbox;
|
|
4
5
|
private initializing;
|
|
5
6
|
private readonly apiKey;
|
|
6
|
-
private
|
|
7
|
-
private
|
|
8
|
-
|
|
9
|
-
TOOL_EXECUTION_TIMEOUT: number;
|
|
10
|
-
private lastTouchTime;
|
|
11
|
-
private readonly THROTTLE_DELAY_MS;
|
|
12
|
-
createdAt: number | null;
|
|
13
|
-
lastUsedAt: number | null;
|
|
14
|
-
private ttlTimer;
|
|
15
|
-
private autoCloseOnIdleTimer;
|
|
16
|
-
private idleCloseMs;
|
|
17
|
-
constructor(apiKey?: string);
|
|
7
|
+
private readonly provider;
|
|
8
|
+
private runtime;
|
|
9
|
+
constructor(runtime?: "node" | "python" | "java" | "go", provider?: MCPSandboxProvider);
|
|
18
10
|
initialize(): Promise<void>;
|
|
19
|
-
private setupTTLTimer;
|
|
20
|
-
/**
|
|
21
|
-
* Update sandbox last used time
|
|
22
|
-
*/
|
|
23
|
-
touch(): void;
|
|
24
|
-
/**
|
|
25
|
-
* Actually perform the touch operation
|
|
26
|
-
*/
|
|
27
|
-
private performTouch;
|
|
28
|
-
scheduleIdleClose(idleMs: number): void;
|
|
29
11
|
kill(): Promise<void>;
|
|
30
|
-
clearPackageCache(packageKey: string): void;
|
|
31
|
-
clearAllCache(): void;
|
|
32
12
|
listTools(packageKey: string): Promise<Tool[]>;
|
|
33
13
|
executeTool(packageKey: string, toolName: string, argumentsObj: Record<string, unknown>, envs?: Record<string, string>): Promise<unknown>;
|
|
34
|
-
private runCodeWithTimeout;
|
|
35
14
|
private generateMCPTestCode;
|
|
36
15
|
private generateEnvVariables;
|
|
37
16
|
}
|