@execbox/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +113 -0
- package/dist/executor-C0lf5vWT.d.ts +182 -0
- package/dist/executor-C0lf5vWT.d.ts.map +1 -0
- package/dist/executor-DcnjQGwA.d.cts +182 -0
- package/dist/executor-DcnjQGwA.d.cts.map +1 -0
- package/dist/index.cjs +242 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +105 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.ts +105 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +221 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/index.cjs +234 -0
- package/dist/mcp/index.cjs.map +1 -0
- package/dist/mcp/index.d.cts +77 -0
- package/dist/mcp/index.d.cts.map +1 -0
- package/dist/mcp/index.d.ts +77 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +230 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/resolveProvider-CUxAvFCK.js +338 -0
- package/dist/resolveProvider-CUxAvFCK.js.map +1 -0
- package/dist/resolveProvider-CixOjPKp.cjs +456 -0
- package/dist/resolveProvider-CixOjPKp.cjs.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { h as ResolvedToolProvider, t as Executor } from "../executor-C0lf5vWT.js";
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
4
|
+
import { Implementation } from "@modelcontextprotocol/sdk/types.js";
|
|
5
|
+
|
|
6
|
+
//#region src/mcp/createMcpToolProvider.d.ts
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Source used to discover MCP tools for wrapping.
|
|
10
|
+
*/
|
|
11
|
+
type McpToolSource = {
|
|
12
|
+
client: Client;
|
|
13
|
+
serverInfo?: Implementation;
|
|
14
|
+
} | {
|
|
15
|
+
server: McpServer;
|
|
16
|
+
serverInfo?: Implementation;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Returns the upstream server identity when the source can provide one.
|
|
20
|
+
*/
|
|
21
|
+
declare function getMcpToolSourceServerInfo(source: McpToolSource): Implementation | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Options for wrapping MCP tools into a code-execution provider.
|
|
24
|
+
*/
|
|
25
|
+
interface CreateMcpToolProviderOptions {
|
|
26
|
+
/** Namespace exposed to guest code for the wrapped tools. */
|
|
27
|
+
namespace?: string;
|
|
28
|
+
/** Implementation metadata exposed to local `{ server }` sources as the client identity. */
|
|
29
|
+
clientInfo?: Implementation;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Explicit handle for a wrapped MCP provider and any owned source connections.
|
|
33
|
+
*/
|
|
34
|
+
interface McpToolProviderHandle {
|
|
35
|
+
/** Resolved provider exposed to the executor or wrapper server. */
|
|
36
|
+
provider: ResolvedToolProvider;
|
|
37
|
+
/** Best-effort upstream server identity when available. */
|
|
38
|
+
serverInfo?: Implementation;
|
|
39
|
+
/** Releases any internal MCP client/server connection opened for the provider. */
|
|
40
|
+
close: () => Promise<void>;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Opens an MCP tool source as a resolved execution provider with explicit cleanup.
|
|
44
|
+
*/
|
|
45
|
+
declare function openMcpToolProvider(source: McpToolSource, options?: CreateMcpToolProviderOptions): Promise<McpToolProviderHandle>;
|
|
46
|
+
/**
|
|
47
|
+
* Wraps MCP tools from a client or server as a resolved execution provider.
|
|
48
|
+
*/
|
|
49
|
+
declare function createMcpToolProvider(source: McpToolSource, options?: CreateMcpToolProviderOptions): Promise<ResolvedToolProvider>;
|
|
50
|
+
//#endregion
|
|
51
|
+
//#region src/mcp/codeMcpServer.d.ts
|
|
52
|
+
/**
|
|
53
|
+
* Options for exposing wrapped MCP tool execution through an MCP server.
|
|
54
|
+
*/
|
|
55
|
+
interface CodeMcpServerOptions extends CreateMcpToolProviderOptions {
|
|
56
|
+
/** Executor used to run guest JavaScript against the wrapped provider. */
|
|
57
|
+
executor: Executor;
|
|
58
|
+
/** Implementation metadata exposed to downstream clients as the wrapper server identity. */
|
|
59
|
+
serverInfo?: Implementation;
|
|
60
|
+
/** Maximum number of text characters returned in text content blocks. */
|
|
61
|
+
maxTextChars?: number;
|
|
62
|
+
/** Wrapper tool layout to expose on the returned server. */
|
|
63
|
+
mode?: "both" | "single" | "split";
|
|
64
|
+
/** Optional custom names for the wrapper tools. */
|
|
65
|
+
names?: {
|
|
66
|
+
execute?: string;
|
|
67
|
+
search?: string;
|
|
68
|
+
single?: string;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Creates an MCP server that exposes code-execution tools for a wrapped MCP source.
|
|
73
|
+
*/
|
|
74
|
+
declare function codeMcpServer(source: McpToolSource, options: CodeMcpServerOptions): Promise<McpServer>;
|
|
75
|
+
//#endregion
|
|
76
|
+
export { type CodeMcpServerOptions, type CreateMcpToolProviderOptions, type McpToolProviderHandle, type McpToolSource, codeMcpServer, createMcpToolProvider, getMcpToolSourceServerInfo, openMcpToolProvider };
|
|
77
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/mcp/createMcpToolProvider.ts","../../src/mcp/codeMcpServer.ts"],"sourcesContent":[],"mappings":";;;;;;;;;AAYA;AACc,KADF,aAAA,GACE;EAAqB,MAAA,EAArB,MAAqB;EACrB,UAAA,CAAA,EADqB,cACrB;CAAwB,GAAA;EAAc,MAAA,EAAtC,SAAsC;EAUpC,UAAA,CAAA,EAVsB,cAUtB;AAiBhB,CAAA;AAUA;;;AAMe,iBAjCC,0BAAA,CAiCD,MAAA,EAhCL,aAgCK,CAAA,EA/BZ,cA+BY,GAAA,SAAA;;AA2Df;;AAEW,UA7EM,4BAAA,CA6EN;EACA;EAAR,SAAA,CAAA,EAAA,MAAA;EAAO;EAsDY,UAAA,CAAA,EAhIP,cAgI4B;;;;;AAGjC,UA7HO,qBAAA,CA6HP;;YA3HE;;ECtCK,UAAA,CAAA,EDwCF,cCxCuB;EAE1B;EAEG,KAAA,EAAA,GAAA,GDsCA,OCtCA,CAAA,IAAA,CAAA;;;AAiLf;;AAEW,iBDlFW,mBAAA,CCkFX,MAAA,EDjFD,aCiFC,EAAA,OAAA,CAAA,EDhFA,4BCgFA,CAAA,ED/ER,OC+EQ,CD/EA,qBC+EA,CAAA;;;;iBDzBW,qBAAA,SACZ,yBACC,+BACR,QAAQ;;;;;AApKX;AACc,UCEG,oBAAA,SAA6B,4BDFhC,CAAA;EAAqB;EACrB,QAAA,ECGF,QDHE;EAAwB;EAAc,UAAA,CAAA,ECKrC,cDLqC;EAUpC;EAiBC,YAAA,CAAA,EAAA,MAAA;EAUA;EAEL,IAAA,CAAA,EAAA,MAAA,GAAA,QAAA,GAAA,OAAA;EAEG;EAEA,KAAA,CAAA,EAAA;IAAO,OAAA,CAAA,EAAA,MAAA;IA2DA,MAAA,CAAA,EAAA,MAAA;IACZ,MAAA,CAAA,EAAA,MAAA;EACC,CAAA;;;;AAuDX;AACU,iBCsBY,aAAA,CDtBZ,MAAA,ECuBA,aDvBA,EAAA,OAAA,ECwBC,oBDxBD,CAAA,ECyBP,ODzBO,CCyBC,SDzBD,CAAA"}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { a as renderNamespaceDeclaration, i as renderDocComment, r as schemaToType, t as resolveProvider } from "../resolveProvider-CUxAvFCK.js";
|
|
2
|
+
import * as z from "zod";
|
|
3
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
5
|
+
import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
|
|
6
|
+
|
|
7
|
+
//#region src/mcp/mcpWrappedToolTypes.ts
|
|
8
|
+
const MCP_CALL_TOOL_RESULT_TYPE = [
|
|
9
|
+
"type McpCallToolResult = {",
|
|
10
|
+
" content: Array<{",
|
|
11
|
+
" type: string;",
|
|
12
|
+
" text?: string;",
|
|
13
|
+
" data?: string;",
|
|
14
|
+
" mimeType?: string;",
|
|
15
|
+
" resource?: unknown;",
|
|
16
|
+
" uri?: string;",
|
|
17
|
+
" name?: string;",
|
|
18
|
+
" description?: string;",
|
|
19
|
+
" }>;",
|
|
20
|
+
" structuredContent?: unknown;",
|
|
21
|
+
" isError?: boolean;",
|
|
22
|
+
" _meta?: Record<string, unknown>;",
|
|
23
|
+
"};"
|
|
24
|
+
].join("\n");
|
|
25
|
+
/**
|
|
26
|
+
* Generates the wrapped MCP tool namespace declarations exposed to guest code.
|
|
27
|
+
*/
|
|
28
|
+
function generateMcpWrappedToolTypes(provider) {
|
|
29
|
+
const declarations = [MCP_CALL_TOOL_RESULT_TYPE];
|
|
30
|
+
for (const [safeName, tool] of Object.entries(provider.tools)) {
|
|
31
|
+
const comment = renderDocComment([...tool.description ? [tool.description, ""] : [], "Wrapped MCP tool. Inspect structuredContent first, then fall back to content text items."]);
|
|
32
|
+
declarations.push([comment, `function ${safeName}(input: ${schemaToType(tool.inputSchema)}): Promise<McpCallToolResult>;`].filter(Boolean).join("\n"));
|
|
33
|
+
}
|
|
34
|
+
return renderNamespaceDeclaration(provider.name, declarations);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
//#endregion
|
|
38
|
+
//#region src/mcp/createMcpToolProvider.ts
|
|
39
|
+
const DEFAULT_MCP_TOOL_CLIENT_INFO = {
|
|
40
|
+
name: "mcp-tool-client",
|
|
41
|
+
version: "0.0.0"
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Returns the upstream server identity when the source can provide one.
|
|
45
|
+
*/
|
|
46
|
+
function getMcpToolSourceServerInfo(source) {
|
|
47
|
+
if (source.serverInfo) return source.serverInfo;
|
|
48
|
+
if ("client" in source) return source.client.getServerVersion();
|
|
49
|
+
}
|
|
50
|
+
async function closeAll(closers) {
|
|
51
|
+
const rejected = (await Promise.allSettled(closers.map((close) => close()))).find((result) => result.status === "rejected");
|
|
52
|
+
if (rejected) throw rejected.reason;
|
|
53
|
+
}
|
|
54
|
+
async function openMcpToolClient(source, clientInfo) {
|
|
55
|
+
if ("client" in source) return {
|
|
56
|
+
client: source.client,
|
|
57
|
+
close: async () => {}
|
|
58
|
+
};
|
|
59
|
+
if (source.server.isConnected()) throw new Error("{ server } sources must be unconnected local MCP servers");
|
|
60
|
+
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
|
|
61
|
+
const client = new Client(clientInfo);
|
|
62
|
+
let closePromise;
|
|
63
|
+
await Promise.all([source.server.connect(serverTransport), client.connect(clientTransport)]);
|
|
64
|
+
return {
|
|
65
|
+
client,
|
|
66
|
+
close: async () => {
|
|
67
|
+
closePromise ??= closeAll([() => client.close(), () => source.server.close()]);
|
|
68
|
+
return closePromise;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Opens an MCP tool source as a resolved execution provider with explicit cleanup.
|
|
74
|
+
*/
|
|
75
|
+
async function openMcpToolProvider(source, options = {}) {
|
|
76
|
+
const connection = await openMcpToolClient(source, options.clientInfo ?? DEFAULT_MCP_TOOL_CLIENT_INFO);
|
|
77
|
+
try {
|
|
78
|
+
const toolsResponse = await connection.client.listTools();
|
|
79
|
+
const provider = {
|
|
80
|
+
name: options.namespace ?? "mcp",
|
|
81
|
+
tools: {}
|
|
82
|
+
};
|
|
83
|
+
for (const tool of toolsResponse.tools) provider.tools[tool.name] = {
|
|
84
|
+
description: tool.description,
|
|
85
|
+
execute: async (input, context) => {
|
|
86
|
+
const argumentsObject = typeof input === "object" && input !== null ? input : void 0;
|
|
87
|
+
return connection.client.callTool({
|
|
88
|
+
arguments: argumentsObject,
|
|
89
|
+
name: tool.name
|
|
90
|
+
}, void 0, { signal: context.signal });
|
|
91
|
+
},
|
|
92
|
+
inputSchema: tool.inputSchema
|
|
93
|
+
};
|
|
94
|
+
const resolvedProvider = resolveProvider(provider);
|
|
95
|
+
return {
|
|
96
|
+
close: connection.close,
|
|
97
|
+
provider: {
|
|
98
|
+
...resolvedProvider,
|
|
99
|
+
types: generateMcpWrappedToolTypes(resolvedProvider)
|
|
100
|
+
},
|
|
101
|
+
serverInfo: getMcpToolSourceServerInfo(source)
|
|
102
|
+
};
|
|
103
|
+
} catch (error) {
|
|
104
|
+
await connection.close().catch(() => {});
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Wraps MCP tools from a client or server as a resolved execution provider.
|
|
110
|
+
*/
|
|
111
|
+
async function createMcpToolProvider(source, options = {}) {
|
|
112
|
+
return (await openMcpToolProvider(source, options)).provider;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
//#endregion
|
|
116
|
+
//#region src/mcp/codeMcpServer.ts
|
|
117
|
+
const DEFAULT_MAX_TEXT_CHARS = 24e3;
|
|
118
|
+
const DEFAULT_MCP_CODE_WRAPPER_SERVER_INFO = {
|
|
119
|
+
name: "mcp-code-wrapper",
|
|
120
|
+
version: "0.0.0"
|
|
121
|
+
};
|
|
122
|
+
function truncateText(text, maxTextChars) {
|
|
123
|
+
return text.length <= maxTextChars ? text : text.slice(0, maxTextChars);
|
|
124
|
+
}
|
|
125
|
+
function renderText(value, maxTextChars) {
|
|
126
|
+
return truncateText(JSON.stringify(value, null, 2), maxTextChars);
|
|
127
|
+
}
|
|
128
|
+
function searchTools(provider, query, limit) {
|
|
129
|
+
const normalizedQuery = query?.toLowerCase().trim();
|
|
130
|
+
const matches = Object.entries(provider.tools).map(([safeName, descriptor]) => ({
|
|
131
|
+
description: descriptor.description,
|
|
132
|
+
inputSchema: descriptor.inputSchema,
|
|
133
|
+
originalName: descriptor.originalName,
|
|
134
|
+
outputSchema: descriptor.outputSchema,
|
|
135
|
+
safeName
|
|
136
|
+
})).filter((tool) => {
|
|
137
|
+
if (!normalizedQuery) return true;
|
|
138
|
+
return [
|
|
139
|
+
tool.originalName,
|
|
140
|
+
tool.safeName,
|
|
141
|
+
tool.description ?? ""
|
|
142
|
+
].some((field) => field.toLowerCase().includes(normalizedQuery));
|
|
143
|
+
}).slice(0, limit);
|
|
144
|
+
return {
|
|
145
|
+
namespace: provider.name,
|
|
146
|
+
originalToSafeName: provider.originalToSafeName,
|
|
147
|
+
safeToOriginalName: provider.safeToOriginalName,
|
|
148
|
+
tools: matches,
|
|
149
|
+
types: provider.types
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
function registerExecuteTool(server, name, provider, executor, maxTextChars, description) {
|
|
153
|
+
server.registerTool.bind(server)(name, {
|
|
154
|
+
description,
|
|
155
|
+
inputSchema: { code: z.string() }
|
|
156
|
+
}, async (args) => {
|
|
157
|
+
const execution = await executor.execute(args.code, [provider]);
|
|
158
|
+
return {
|
|
159
|
+
content: [{
|
|
160
|
+
text: renderText(execution, maxTextChars),
|
|
161
|
+
type: "text"
|
|
162
|
+
}],
|
|
163
|
+
isError: !execution.ok,
|
|
164
|
+
structuredContent: execution
|
|
165
|
+
};
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
function registerSearchTool(server, name, provider, maxTextChars) {
|
|
169
|
+
server.registerTool.bind(server)(name, {
|
|
170
|
+
description: `Search wrapped MCP tools exposed under the ${provider.name} namespace.`,
|
|
171
|
+
inputSchema: {
|
|
172
|
+
limit: z.number().int().optional(),
|
|
173
|
+
query: z.string().optional()
|
|
174
|
+
}
|
|
175
|
+
}, async (args) => {
|
|
176
|
+
const structuredContent = searchTools(provider, args.query, args.limit ?? 20);
|
|
177
|
+
return {
|
|
178
|
+
content: [{
|
|
179
|
+
text: renderText(structuredContent, maxTextChars),
|
|
180
|
+
type: "text"
|
|
181
|
+
}],
|
|
182
|
+
structuredContent
|
|
183
|
+
};
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
function attachOwnedClose(server, closeOwnedResources) {
|
|
187
|
+
const originalClose = server.close.bind(server);
|
|
188
|
+
let closePromise;
|
|
189
|
+
server.close = async () => {
|
|
190
|
+
closePromise ??= (async () => {
|
|
191
|
+
const rejected = (await Promise.allSettled([originalClose(), closeOwnedResources()])).find((result) => result.status === "rejected");
|
|
192
|
+
if (rejected) throw rejected.reason;
|
|
193
|
+
})();
|
|
194
|
+
return closePromise;
|
|
195
|
+
};
|
|
196
|
+
return server;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Creates an MCP server that exposes code-execution tools for a wrapped MCP source.
|
|
200
|
+
*/
|
|
201
|
+
async function codeMcpServer(source, options) {
|
|
202
|
+
const maxTextChars = options.maxTextChars ?? DEFAULT_MAX_TEXT_CHARS;
|
|
203
|
+
const mode = options.mode ?? "both";
|
|
204
|
+
const names = {
|
|
205
|
+
execute: options.names?.execute ?? "mcp_execute_code",
|
|
206
|
+
search: options.names?.search ?? "mcp_search_tools",
|
|
207
|
+
single: options.names?.single ?? "mcp_code"
|
|
208
|
+
};
|
|
209
|
+
const handle = await openMcpToolProvider(source, {
|
|
210
|
+
clientInfo: options.clientInfo,
|
|
211
|
+
namespace: options.namespace ?? "mcp"
|
|
212
|
+
});
|
|
213
|
+
const provider = handle.provider;
|
|
214
|
+
const server = new McpServer(options.serverInfo ?? handle.serverInfo ?? DEFAULT_MCP_CODE_WRAPPER_SERVER_INFO);
|
|
215
|
+
try {
|
|
216
|
+
if (mode === "both" || mode === "split") {
|
|
217
|
+
registerSearchTool(server, names.search, provider, maxTextChars);
|
|
218
|
+
registerExecuteTool(server, names.execute, provider, options.executor, maxTextChars, `Execute JavaScript against the wrapped ${provider.name} MCP tool namespace.`);
|
|
219
|
+
}
|
|
220
|
+
if (mode === "both" || mode === "single") registerExecuteTool(server, names.single, provider, options.executor, maxTextChars, `Execute JavaScript against the wrapped ${provider.name} MCP tool namespace.\n\n${provider.types}`);
|
|
221
|
+
return attachOwnedClose(server, handle.close);
|
|
222
|
+
} catch (error) {
|
|
223
|
+
await handle.close().catch(() => {});
|
|
224
|
+
throw error;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
//#endregion
|
|
229
|
+
export { codeMcpServer, createMcpToolProvider, getMcpToolSourceServerInfo, openMcpToolProvider };
|
|
230
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["closePromise: Promise<void> | undefined","provider: ToolProvider","closePromise: Promise<void> | undefined"],"sources":["../../src/mcp/mcpWrappedToolTypes.ts","../../src/mcp/createMcpToolProvider.ts","../../src/mcp/codeMcpServer.ts"],"sourcesContent":["import type { ResolvedToolProvider } from \"../types\";\nimport { schemaToType } from \"../typegen/jsonSchema\";\nimport {\n renderDocComment,\n renderNamespaceDeclaration,\n} from \"../typegen/render\";\n\nconst MCP_CALL_TOOL_RESULT_TYPE = [\n \"type McpCallToolResult = {\",\n \" content: Array<{\",\n \" type: string;\",\n \" text?: string;\",\n \" data?: string;\",\n \" mimeType?: string;\",\n \" resource?: unknown;\",\n \" uri?: string;\",\n \" name?: string;\",\n \" description?: string;\",\n \" }>;\",\n \" structuredContent?: unknown;\",\n \" isError?: boolean;\",\n \" _meta?: Record<string, unknown>;\",\n \"};\",\n].join(\"\\n\");\n\n/**\n * Generates the wrapped MCP tool namespace declarations exposed to guest code.\n */\nexport function generateMcpWrappedToolTypes(\n provider: ResolvedToolProvider,\n): string {\n const declarations = [MCP_CALL_TOOL_RESULT_TYPE];\n\n for (const [safeName, tool] of Object.entries(provider.tools)) {\n const comment = renderDocComment([\n ...(tool.description ? [tool.description, \"\"] : []),\n \"Wrapped MCP tool. Inspect structuredContent first, then fall back to content text items.\",\n ]);\n\n declarations.push(\n [\n comment,\n `function ${safeName}(input: ${schemaToType(tool.inputSchema)}): Promise<McpCallToolResult>;`,\n ]\n .filter(Boolean)\n .join(\"\\n\"),\n );\n }\n\n return renderNamespaceDeclaration(provider.name, declarations);\n}\n","import { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { InMemoryTransport } from \"@modelcontextprotocol/sdk/inMemory.js\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { Implementation } from \"@modelcontextprotocol/sdk/types.js\";\n\nimport { resolveProvider } from \"../provider/resolveProvider\";\nimport type { ResolvedToolProvider, ToolProvider } from \"../types\";\nimport { generateMcpWrappedToolTypes } from \"./mcpWrappedToolTypes\";\n\n/**\n * Source used to discover MCP tools for wrapping.\n */\nexport type McpToolSource =\n | { client: Client; serverInfo?: Implementation }\n | { server: McpServer; serverInfo?: Implementation };\n\nconst DEFAULT_MCP_TOOL_CLIENT_INFO = {\n name: \"mcp-tool-client\",\n version: \"0.0.0\",\n} satisfies Implementation;\n\n/**\n * Returns the upstream server identity when the source can provide one.\n */\nexport function getMcpToolSourceServerInfo(\n source: McpToolSource,\n): Implementation | undefined {\n if (source.serverInfo) {\n return source.serverInfo;\n }\n\n if (\"client\" in source) {\n return source.client.getServerVersion();\n }\n\n return undefined;\n}\n\n/**\n * Options for wrapping MCP tools into a code-execution provider.\n */\nexport interface CreateMcpToolProviderOptions {\n /** Namespace exposed to guest code for the wrapped tools. */\n namespace?: string;\n /** Implementation metadata exposed to local `{ server }` sources as the client identity. */\n clientInfo?: Implementation;\n}\n\n/**\n * Explicit handle for a wrapped MCP provider and any owned source connections.\n */\nexport interface McpToolProviderHandle {\n /** Resolved provider exposed to the executor or wrapper server. */\n provider: ResolvedToolProvider;\n /** Best-effort upstream server identity when available. */\n serverInfo?: Implementation;\n /** Releases any internal MCP client/server connection opened for the provider. */\n close: () => Promise<void>;\n}\n\ninterface OpenMcpToolClientResult {\n client: Client;\n close: () => Promise<void>;\n}\n\nasync function closeAll(closers: Array<() => Promise<void>>): Promise<void> {\n const results = await Promise.allSettled(closers.map((close) => close()));\n const rejected = results.find(\n (result): result is PromiseRejectedResult => result.status === \"rejected\",\n );\n\n if (rejected) {\n throw rejected.reason;\n }\n}\n\nasync function openMcpToolClient(\n source: McpToolSource,\n clientInfo: Implementation,\n): Promise<OpenMcpToolClientResult> {\n if (\"client\" in source) {\n return {\n client: source.client,\n close: async () => {},\n };\n }\n\n if (source.server.isConnected()) {\n throw new Error(\"{ server } sources must be unconnected local MCP servers\");\n }\n\n const [clientTransport, serverTransport] =\n InMemoryTransport.createLinkedPair();\n const client = new Client(clientInfo);\n let closePromise: Promise<void> | undefined;\n\n await Promise.all([\n source.server.connect(serverTransport),\n client.connect(clientTransport),\n ]);\n\n return {\n client,\n close: async () => {\n closePromise ??= closeAll([\n () => client.close(),\n () => source.server.close(),\n ]);\n return closePromise;\n },\n };\n}\n\n/**\n * Opens an MCP tool source as a resolved execution provider with explicit cleanup.\n */\nexport async function openMcpToolProvider(\n source: McpToolSource,\n options: CreateMcpToolProviderOptions = {},\n): Promise<McpToolProviderHandle> {\n const connection = await openMcpToolClient(\n source,\n options.clientInfo ?? DEFAULT_MCP_TOOL_CLIENT_INFO,\n );\n\n try {\n const toolsResponse = await connection.client.listTools();\n const provider: ToolProvider = {\n name: options.namespace ?? \"mcp\",\n tools: {},\n };\n\n for (const tool of toolsResponse.tools) {\n provider.tools[tool.name] = {\n description: tool.description,\n execute: async (input, context) => {\n const argumentsObject =\n typeof input === \"object\" && input !== null\n ? (input as Record<string, unknown>)\n : undefined;\n\n return connection.client.callTool(\n {\n arguments: argumentsObject,\n name: tool.name,\n },\n undefined,\n { signal: context.signal },\n );\n },\n inputSchema: tool.inputSchema,\n };\n }\n\n const resolvedProvider = resolveProvider(provider);\n\n return {\n close: connection.close,\n provider: {\n ...resolvedProvider,\n types: generateMcpWrappedToolTypes(resolvedProvider),\n },\n serverInfo: getMcpToolSourceServerInfo(source),\n };\n } catch (error) {\n await connection.close().catch(() => {});\n throw error;\n }\n}\n\n/**\n * Wraps MCP tools from a client or server as a resolved execution provider.\n */\nexport async function createMcpToolProvider(\n source: McpToolSource,\n options: CreateMcpToolProviderOptions = {},\n): Promise<ResolvedToolProvider> {\n const handle = await openMcpToolProvider(source, options);\n return handle.provider;\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { Implementation } from \"@modelcontextprotocol/sdk/types.js\";\nimport * as z from \"zod\";\n\nimport type { Executor } from \"../executor/executor\";\nimport type { ResolvedToolProvider } from \"../types\";\nimport {\n openMcpToolProvider,\n type CreateMcpToolProviderOptions,\n type McpToolSource,\n} from \"./createMcpToolProvider\";\n\n/**\n * Options for exposing wrapped MCP tool execution through an MCP server.\n */\nexport interface CodeMcpServerOptions extends CreateMcpToolProviderOptions {\n /** Executor used to run guest JavaScript against the wrapped provider. */\n executor: Executor;\n /** Implementation metadata exposed to downstream clients as the wrapper server identity. */\n serverInfo?: Implementation;\n /** Maximum number of text characters returned in text content blocks. */\n maxTextChars?: number;\n /** Wrapper tool layout to expose on the returned server. */\n mode?: \"both\" | \"single\" | \"split\";\n /** Optional custom names for the wrapper tools. */\n names?: {\n execute?: string;\n search?: string;\n single?: string;\n };\n}\n\nconst DEFAULT_MAX_TEXT_CHARS = 24_000;\nconst DEFAULT_MCP_CODE_WRAPPER_SERVER_INFO = {\n name: \"mcp-code-wrapper\",\n version: \"0.0.0\",\n} satisfies Implementation;\n\nfunction truncateText(text: string, maxTextChars: number): string {\n return text.length <= maxTextChars ? text : text.slice(0, maxTextChars);\n}\n\nfunction renderText(value: unknown, maxTextChars: number): string {\n return truncateText(JSON.stringify(value, null, 2), maxTextChars);\n}\n\nfunction searchTools(\n provider: ResolvedToolProvider,\n query: string | undefined,\n limit: number,\n): Record<string, unknown> {\n const normalizedQuery = query?.toLowerCase().trim();\n const matches = Object.entries(provider.tools)\n .map(([safeName, descriptor]) => ({\n description: descriptor.description,\n inputSchema: descriptor.inputSchema,\n originalName: descriptor.originalName,\n outputSchema: descriptor.outputSchema,\n safeName,\n }))\n .filter((tool) => {\n if (!normalizedQuery) {\n return true;\n }\n\n return [tool.originalName, tool.safeName, tool.description ?? \"\"].some(\n (field) => field.toLowerCase().includes(normalizedQuery),\n );\n })\n .slice(0, limit);\n\n return {\n namespace: provider.name,\n originalToSafeName: provider.originalToSafeName,\n safeToOriginalName: provider.safeToOriginalName,\n tools: matches,\n types: provider.types,\n };\n}\n\nfunction registerExecuteTool(\n server: McpServer,\n name: string,\n provider: ResolvedToolProvider,\n executor: Executor,\n maxTextChars: number,\n description: string,\n): void {\n const registerTool = server.registerTool.bind(server) as (\n toolName: string,\n config: {\n description: string;\n inputSchema: Record<string, z.ZodTypeAny>;\n },\n handler: (args: { code: string }) => Promise<{\n content: Array<{ text: string; type: \"text\" }>;\n isError: boolean;\n structuredContent: Record<string, unknown>;\n }>,\n ) => void;\n\n registerTool(\n name,\n {\n description,\n inputSchema: {\n code: z.string(),\n },\n },\n async (args: { code: string }) => {\n const execution = await executor.execute(args.code, [provider]);\n\n return {\n content: [{ text: renderText(execution, maxTextChars), type: \"text\" }],\n isError: !execution.ok,\n structuredContent: execution as Record<string, unknown>,\n };\n },\n );\n}\n\nfunction registerSearchTool(\n server: McpServer,\n name: string,\n provider: ResolvedToolProvider,\n maxTextChars: number,\n): void {\n const registerTool = server.registerTool.bind(server) as (\n toolName: string,\n config: {\n description: string;\n inputSchema: Record<string, z.ZodTypeAny>;\n },\n handler: (args: { limit?: number; query?: string }) => Promise<{\n content: Array<{ text: string; type: \"text\" }>;\n structuredContent: Record<string, unknown>;\n }>,\n ) => void;\n\n registerTool(\n name,\n {\n description: `Search wrapped MCP tools exposed under the ${provider.name} namespace.`,\n inputSchema: {\n limit: z.number().int().optional(),\n query: z.string().optional(),\n },\n },\n async (args: { limit?: number; query?: string }) => {\n const structuredContent = searchTools(\n provider,\n args.query,\n args.limit ?? 20,\n );\n return {\n content: [\n { text: renderText(structuredContent, maxTextChars), type: \"text\" },\n ],\n structuredContent,\n };\n },\n );\n}\n\nfunction attachOwnedClose(\n server: McpServer,\n closeOwnedResources: () => Promise<void>,\n): McpServer {\n const originalClose = server.close.bind(server);\n let closePromise: Promise<void> | undefined;\n\n server.close = async () => {\n closePromise ??= (async () => {\n const results = await Promise.allSettled([\n originalClose(),\n closeOwnedResources(),\n ]);\n const rejected = results.find(\n (result): result is PromiseRejectedResult =>\n result.status === \"rejected\",\n );\n\n if (rejected) {\n throw rejected.reason;\n }\n })();\n\n return closePromise;\n };\n\n return server;\n}\n\n/**\n * Creates an MCP server that exposes code-execution tools for a wrapped MCP source.\n */\nexport async function codeMcpServer(\n source: McpToolSource,\n options: CodeMcpServerOptions,\n): Promise<McpServer> {\n const maxTextChars = options.maxTextChars ?? DEFAULT_MAX_TEXT_CHARS;\n const mode = options.mode ?? \"both\";\n const names = {\n execute: options.names?.execute ?? \"mcp_execute_code\",\n search: options.names?.search ?? \"mcp_search_tools\",\n single: options.names?.single ?? \"mcp_code\",\n };\n const handle = await openMcpToolProvider(source, {\n clientInfo: options.clientInfo,\n namespace: options.namespace ?? \"mcp\",\n });\n const provider = handle.provider;\n const server = new McpServer(\n options.serverInfo ??\n handle.serverInfo ??\n DEFAULT_MCP_CODE_WRAPPER_SERVER_INFO,\n );\n\n try {\n if (mode === \"both\" || mode === \"split\") {\n registerSearchTool(server, names.search, provider, maxTextChars);\n registerExecuteTool(\n server,\n names.execute,\n provider,\n options.executor,\n maxTextChars,\n `Execute JavaScript against the wrapped ${provider.name} MCP tool namespace.`,\n );\n }\n\n if (mode === \"both\" || mode === \"single\") {\n registerExecuteTool(\n server,\n names.single,\n provider,\n options.executor,\n maxTextChars,\n `Execute JavaScript against the wrapped ${provider.name} MCP tool namespace.\\n\\n${provider.types}`,\n );\n }\n\n return attachOwnedClose(server, handle.close);\n } catch (error) {\n await handle.close().catch(() => {});\n throw error;\n }\n}\n"],"mappings":"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"}
|