@easynet/agent-tool 1.0.74 → 1.0.76

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +21 -10
  2. package/dist/api/adapters/LangChainToolsHub.d.ts +1 -1
  3. package/dist/api/createAgentTools.d.ts +55 -16
  4. package/dist/api/createAgentTools.d.ts.map +1 -1
  5. package/dist/api/expose/index.d.ts +2 -2
  6. package/dist/api/expose/index.d.ts.map +1 -1
  7. package/dist/api/expose/mcpServer.d.ts +3 -4
  8. package/dist/api/expose/mcpServer.d.ts.map +1 -1
  9. package/dist/api/expose/openapiHttp.d.ts +15 -31
  10. package/dist/api/expose/openapiHttp.d.ts.map +1 -1
  11. package/dist/api/main.cjs +20 -24
  12. package/dist/api/main.d.ts +16 -15
  13. package/dist/api/main.d.ts.map +1 -1
  14. package/dist/api/main.js +2 -2
  15. package/dist/api/runtimeFromConfig.d.ts +1 -1
  16. package/dist/api/runtimeFromConfig.d.ts.map +1 -1
  17. package/dist/{chunk-JYADGZQP.js → chunk-BMAYX22K.js} +298 -268
  18. package/dist/chunk-BMAYX22K.js.map +1 -0
  19. package/dist/{chunk-SE6IMOIE.cjs → chunk-CEVOKZFT.cjs} +301 -269
  20. package/dist/chunk-CEVOKZFT.cjs.map +1 -0
  21. package/dist/{chunk-KTQTDKWU.cjs → chunk-EZDDKTCF.cjs} +84 -89
  22. package/dist/chunk-EZDDKTCF.cjs.map +1 -0
  23. package/dist/{chunk-ECHW6AWF.js → chunk-LUKSY7VK.js} +73 -79
  24. package/dist/chunk-LUKSY7VK.js.map +1 -0
  25. package/dist/index.cjs +19 -23
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.d.ts +2 -2
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +3 -3
  30. package/dist/index.js.map +1 -1
  31. package/dist/tools/util/toolConfig.d.ts +13 -0
  32. package/dist/tools/util/toolConfig.d.ts.map +1 -1
  33. package/dist/utils/cli/index.cjs +12 -12
  34. package/dist/utils/cli/index.js +1 -1
  35. package/package.json +4 -1
  36. package/dist/chunk-ECHW6AWF.js.map +0 -1
  37. package/dist/chunk-JYADGZQP.js.map +0 -1
  38. package/dist/chunk-KTQTDKWU.cjs.map +0 -1
  39. package/dist/chunk-SE6IMOIE.cjs.map +0 -1
@@ -16,8 +16,27 @@ import pTimeout from 'p-timeout';
16
16
  import { createRequire } from 'module';
17
17
  import { pathToFileURL } from 'url';
18
18
  import { resolveLatestVersionFromRegistry, ensurePackageInCache, getPackageEntryPath, importFromCache } from '@easynet/agent-common/npm';
19
- import { createServer } from 'http';
19
+ import express from 'express';
20
20
 
21
+ function normalizeMcpConfig(raw) {
22
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
23
+ const source = raw;
24
+ const out = {};
25
+ if (typeof source.name === "string" && source.name.trim()) out.name = source.name.trim();
26
+ if (typeof source.version === "string" && source.version.trim()) out.version = source.version.trim();
27
+ return Object.keys(out).length > 0 ? out : void 0;
28
+ }
29
+ function normalizeOpenApiConfig(raw) {
30
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
31
+ const source = raw;
32
+ const out = {};
33
+ if (typeof source.host === "string" && source.host.trim()) out.host = source.host.trim();
34
+ if (typeof source.basePath === "string") out.basePath = source.basePath;
35
+ if (typeof source.title === "string" && source.title.trim()) out.title = source.title.trim();
36
+ if (typeof source.version === "string" && source.version.trim()) out.version = source.version.trim();
37
+ if (typeof source.port === "number" && Number.isFinite(source.port)) out.port = source.port;
38
+ return Object.keys(out).length > 0 ? out : void 0;
39
+ }
21
40
  function loadToolConfig(toolYamlPath) {
22
41
  const abs = resolve(toolYamlPath);
23
42
  const raw = readFileSync(abs, "utf8");
@@ -26,6 +45,8 @@ function loadToolConfig(toolYamlPath) {
26
45
  });
27
46
  if (!parsed || typeof parsed !== "object") return {};
28
47
  const source = parsed.spec && typeof parsed.spec === "object" && !Array.isArray(parsed.spec) ? parsed.spec : parsed;
48
+ const mcpConfig = normalizeMcpConfig(source.expose?.mcp ?? source.mcp);
49
+ const openApiConfig = normalizeOpenApiConfig(source.expose?.openapi ?? source.openapi);
29
50
  const toolsBlock = source.tools;
30
51
  if (toolsBlock != null && typeof toolsBlock === "object" && !Array.isArray(toolsBlock)) {
31
52
  const toolDefaults = toolsBlock.defaults != null && typeof toolsBlock.defaults === "object" && !Array.isArray(toolsBlock.defaults) ? toolsBlock.defaults : void 0;
@@ -39,7 +60,9 @@ function loadToolConfig(toolYamlPath) {
39
60
  blockedHosts: Array.isArray(toolsBlock.blockedHosts) ? toolsBlock.blockedHosts : source.blockedHosts,
40
61
  blockedCidrs: Array.isArray(toolsBlock.blockedCidrs) ? toolsBlock.blockedCidrs : source.blockedCidrs,
41
62
  toolDefaults,
42
- packageToolDefaults: packageToolDefaults2
63
+ packageToolDefaults: packageToolDefaults2,
64
+ mcp: mcpConfig,
65
+ openapi: openApiConfig
43
66
  };
44
67
  }
45
68
  const packageToolDefaults = typeof source.packageToolDefaults === "object" && !Array.isArray(source.packageToolDefaults) ? source.packageToolDefaults : void 0;
@@ -52,7 +75,9 @@ function loadToolConfig(toolYamlPath) {
52
75
  blockedHosts: Array.isArray(source.blockedHosts) ? source.blockedHosts : void 0,
53
76
  blockedCidrs: Array.isArray(source.blockedCidrs) ? source.blockedCidrs : void 0,
54
77
  toolDefaults: typeof source.toolDefaults === "object" && !Array.isArray(source.toolDefaults) ? source.toolDefaults : void 0,
55
- packageToolDefaults
78
+ packageToolDefaults,
79
+ mcp: mcpConfig,
80
+ openapi: openApiConfig
56
81
  };
57
82
  }
58
83
  function resolveSandboxedPath(toolYamlPath, sandboxedPath) {
@@ -2195,6 +2220,137 @@ async function createRuntimeFromConfig(options = {}) {
2195
2220
  return createRuntimeFromConfigSync(options);
2196
2221
  }
2197
2222
 
2223
+ // src/api/expose/mcpServer.ts
2224
+ var DEFAULT_CTX = {
2225
+ requestId: `mcp-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
2226
+ taskId: `task-${Date.now()}`,
2227
+ permissions: [
2228
+ "read:web",
2229
+ "read:fs",
2230
+ "write:fs",
2231
+ "read:db",
2232
+ "write:db",
2233
+ "network",
2234
+ "workflow",
2235
+ "danger:destructive"
2236
+ ]
2237
+ };
2238
+ function toMcpToolName(registryName) {
2239
+ return normalizeToolName(registryName);
2240
+ }
2241
+ async function createMcpServerWithTools(runtime, options) {
2242
+ const { McpServer } = await import('@modelcontextprotocol/sdk/server/mcp.js');
2243
+ const name = options.name ?? "agent-tool";
2244
+ const version = options.version ?? "1.0.0";
2245
+ const ctxFactory = options.execContextFactory ?? (() => ({ ...DEFAULT_CTX }));
2246
+ const server = new McpServer({ name, version });
2247
+ const registry = runtime.getRegistry();
2248
+ const specs = registry.snapshot();
2249
+ for (const spec of specs) {
2250
+ const mcpName = toMcpToolName(spec.name);
2251
+ server.registerTool(
2252
+ mcpName,
2253
+ {
2254
+ description: spec.description ?? `Tool: ${spec.name}`,
2255
+ inputSchema: spec.inputSchema,
2256
+ _meta: spec._meta
2257
+ },
2258
+ async (args) => {
2259
+ const ctx = ctxFactory();
2260
+ const result = await runtime.invoke(
2261
+ { tool: spec.name, args: args ?? {}, purpose: MCP_KIND },
2262
+ ctx
2263
+ );
2264
+ if (result.ok) {
2265
+ return { content: [{ type: "text", text: JSON.stringify(result.result) }] };
2266
+ }
2267
+ const err = result.error;
2268
+ return {
2269
+ content: [
2270
+ {
2271
+ type: "text",
2272
+ text: JSON.stringify({ error: err?.message ?? "Tool failed", kind: err?.kind })
2273
+ }
2274
+ ],
2275
+ isError: true
2276
+ };
2277
+ }
2278
+ );
2279
+ }
2280
+ return { server };
2281
+ }
2282
+ async function createMCPServer(runtimeOrConfig, options = {}) {
2283
+ const runtime = "invoke" in runtimeOrConfig && typeof runtimeOrConfig.invoke === "function" ? runtimeOrConfig : (await createRuntimeFromConfig(runtimeOrConfig)).runtime;
2284
+ const { StdioServerTransport } = await import('@modelcontextprotocol/sdk/server/stdio.js');
2285
+ const { server } = await createMcpServerWithTools(runtime, options);
2286
+ return {
2287
+ server,
2288
+ async connectStdio() {
2289
+ const transport = new StdioServerTransport();
2290
+ await server.connect(transport);
2291
+ }
2292
+ };
2293
+ }
2294
+ function createMCPStreamableHttpHandler(runtimeOrConfig, options = {}) {
2295
+ if ("invoke" in runtimeOrConfig && typeof runtimeOrConfig.invoke === "function") {
2296
+ const runtime = runtimeOrConfig;
2297
+ return async function streamableHttpHandler(req, res, parsedBody) {
2298
+ const { StreamableHTTPServerTransport } = await import('@modelcontextprotocol/sdk/server/streamableHttp.js');
2299
+ const { server } = await createMcpServerWithTools(runtime, options);
2300
+ const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: void 0 });
2301
+ await server.connect(transport);
2302
+ const onClose = () => {
2303
+ transport.close().catch(() => {
2304
+ });
2305
+ server.close().catch(() => {
2306
+ });
2307
+ res.removeListener("close", onClose);
2308
+ res.removeListener("finish", onClose);
2309
+ };
2310
+ res.once("close", onClose);
2311
+ res.once("finish", onClose);
2312
+ await transport.handleRequest(
2313
+ req,
2314
+ res,
2315
+ parsedBody
2316
+ );
2317
+ };
2318
+ }
2319
+ return (async () => {
2320
+ const { runtime } = await createRuntimeFromConfig(runtimeOrConfig);
2321
+ return createMCPStreamableHttpHandler(runtime, options);
2322
+ })();
2323
+ }
2324
+ async function createMCPServerStreamableHttp(runtimeOrConfig, options = {}) {
2325
+ const path = options.path ?? "/mcp";
2326
+ const host = options.host ?? "127.0.0.1";
2327
+ const port = options.port ?? 3e3;
2328
+ const { createMcpExpressApp } = await import('@modelcontextprotocol/sdk/server/express.js');
2329
+ const handler = "invoke" in runtimeOrConfig && typeof runtimeOrConfig.invoke === "function" ? createMCPStreamableHttpHandler(runtimeOrConfig, options) : await createMCPStreamableHttpHandler(runtimeOrConfig, options);
2330
+ const app = createMcpExpressApp({ host });
2331
+ app.post(path, handler);
2332
+ return {
2333
+ app,
2334
+ path,
2335
+ async listen(listenPort, listenHost) {
2336
+ const p = listenPort ?? port;
2337
+ const h = listenHost ?? host;
2338
+ return new Promise((resolve4, reject) => {
2339
+ const server = app.listen(p, h, () => {
2340
+ const addr = server.address();
2341
+ const actualPort = typeof addr === "object" && addr !== null && "port" in addr ? addr.port : p;
2342
+ resolve4({ url: `http://${h}:${actualPort}${path}`, port: actualPort });
2343
+ });
2344
+ });
2345
+ }
2346
+ };
2347
+ }
2348
+ async function runMCPServerOverStdio(runtime, options = {}) {
2349
+ const result = await createMCPServer(runtime, options);
2350
+ await result.connectStdio();
2351
+ return result;
2352
+ }
2353
+
2198
2354
  // src/api/expose/openapi.ts
2199
2355
  function toolNameToSlug(name) {
2200
2356
  return name.replace(/\./g, "~");
@@ -2332,7 +2488,7 @@ function createPerToolPathSpec(spec, key) {
2332
2488
  }
2333
2489
 
2334
2490
  // src/api/expose/openapiHttp.ts
2335
- var DEFAULT_CTX = {
2491
+ var DEFAULT_CTX2 = {
2336
2492
  requestId: `http-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
2337
2493
  taskId: `task-${Date.now()}`,
2338
2494
  permissions: [
@@ -2346,8 +2502,17 @@ var DEFAULT_CTX = {
2346
2502
  "danger:destructive"
2347
2503
  ]
2348
2504
  };
2505
+ var BodyParseError = class extends Error {
2506
+ hint;
2507
+ constructor(message, hint) {
2508
+ super(message);
2509
+ this.name = "BodyParseError";
2510
+ this.hint = hint;
2511
+ }
2512
+ };
2349
2513
  function safeParseToolArgs(raw) {
2350
2514
  const text = String(raw ?? "").trim();
2515
+ if (!text) return { ok: true, value: {} };
2351
2516
  const firstBrace = text.indexOf("{");
2352
2517
  if (firstBrace === -1) {
2353
2518
  return {
@@ -2357,9 +2522,7 @@ function safeParseToolArgs(raw) {
2357
2522
  }
2358
2523
  let jsonText = text.slice(firstBrace);
2359
2524
  const lastBrace = jsonText.lastIndexOf("}");
2360
- if (lastBrace !== -1) {
2361
- jsonText = jsonText.slice(0, lastBrace + 1);
2362
- }
2525
+ if (lastBrace !== -1) jsonText = jsonText.slice(0, lastBrace + 1);
2363
2526
  try {
2364
2527
  return { ok: true, value: JSON.parse(jsonText) };
2365
2528
  } catch {
@@ -2369,37 +2532,8 @@ function safeParseToolArgs(raw) {
2369
2532
  };
2370
2533
  }
2371
2534
  }
2372
- var BodyParseError = class extends Error {
2373
- hint;
2374
- constructor(message, hint) {
2375
- super(message);
2376
- this.name = "BodyParseError";
2377
- this.hint = hint;
2378
- }
2379
- };
2380
- function parseBody(req) {
2381
- return new Promise((resolve4, reject) => {
2382
- const chunks = [];
2383
- req.on("data", (chunk) => chunks.push(chunk));
2384
- req.on("end", () => {
2385
- const raw = Buffer.concat(chunks).toString("utf-8");
2386
- if (!raw.trim()) {
2387
- resolve4({});
2388
- return;
2389
- }
2390
- const parsed = safeParseToolArgs(raw);
2391
- if (parsed.ok) {
2392
- resolve4(parsed.value);
2393
- return;
2394
- }
2395
- reject(new BodyParseError("Invalid JSON body", parsed.hint));
2396
- });
2397
- req.on("error", reject);
2398
- });
2399
- }
2400
2535
  function sendJson(res, status, data) {
2401
- res.writeHead(status, { "Content-Type": "application/json" });
2402
- res.end(JSON.stringify(data));
2536
+ res.status(status).json(data);
2403
2537
  }
2404
2538
  function swaggerUiHtml(specUrl) {
2405
2539
  const specUrlEscaped = specUrl.replace(/"/g, """);
@@ -2432,99 +2566,13 @@ function swaggerUiHtml(specUrl) {
2432
2566
  </body>
2433
2567
  </html>`;
2434
2568
  }
2435
- function createOpenAPIHttpServer(runtime, options = {}) {
2436
- const basePath = (options.basePath ?? "").replace(/\/$/, "");
2437
- const ctxFactory = options.execContextFactory ?? (() => ({ ...DEFAULT_CTX }));
2438
- const server = createServer(
2439
- (req, res) => handleOpenApiHttpRequest({ runtime, req, res, basePath, ctxFactory })
2440
- );
2441
- return server;
2442
- }
2443
- async function handleOpenApiHttpRequest(input) {
2444
- const norm = normalizePath(input.req.url, input.basePath);
2445
- try {
2446
- if (await maybeHandleDocsRoute(input, norm)) return;
2447
- if (await maybeHandleToolsRoute(input, norm)) return;
2448
- if (await maybeHandleInvokeRoute(input, norm)) return;
2449
- sendJson(input.res, 404, { error: "Not found", path: norm });
2450
- } catch (err) {
2451
- const message = err instanceof Error ? err.message : String(err);
2452
- sendJson(input.res, 500, { error: message, kind: "INTERNAL_ERROR" });
2453
- }
2454
- }
2455
- function normalizePath(url, basePath) {
2456
- const path = (url ?? "/").split("?")[0] ?? "/";
2457
- return basePath ? path === basePath ? "" : path.replace(basePath, "") || "/" : path;
2458
- }
2459
- async function maybeHandleDocsRoute(input, norm) {
2460
- if (input.req.method === "GET" && (norm === "/" || norm === "/swagger")) {
2461
- const specPath = input.basePath ? `${input.basePath}/openapi.json` : "/openapi.json";
2462
- input.res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
2463
- input.res.end(swaggerUiHtml(specPath));
2464
- return true;
2465
- }
2466
- if (input.req.method === "GET" && (norm === "/openapi.json" || norm === "/spec")) {
2467
- sendJson(
2468
- input.res,
2469
- 200,
2470
- toolsToOpenAPISpec(input.runtime.getRegistry(), {
2471
- title: "Tool API",
2472
- version: "1.0.0",
2473
- basePath: input.basePath || void 0
2474
- })
2475
- );
2476
- return true;
2477
- }
2478
- return false;
2479
- }
2480
- async function maybeHandleToolsRoute(input, norm) {
2481
- if (input.req.method !== "GET" || norm !== "/tools") return false;
2482
- const { enrichSpecWithCanonicalSchema: enrichSpecWithCanonicalSchema2 } = await import('./canonicalCoreSchemas-PHGTNPN5.js');
2483
- const tools = input.runtime.getRegistry().snapshot().map(enrichSpecWithCanonicalSchema2).map((s) => ({
2484
- name: s.name,
2485
- description: s.description,
2486
- kind: s.kind,
2487
- inputSchema: s.inputSchema
2488
- }));
2489
- sendJson(input.res, 200, { tools });
2490
- return true;
2491
- }
2492
- async function maybeHandleInvokeRoute(input, norm) {
2493
- if (input.req.method !== "POST") return false;
2494
- if (norm === "/invoke") {
2495
- const body = await parseBodyOrSendError(input.req, input.res);
2496
- if (!body) return true;
2497
- const tool = body.tool;
2498
- if (typeof tool !== "string" || !tool.trim()) {
2499
- sendJson(input.res, 400, { error: "Missing or invalid 'tool' in body", kind: "BAD_REQUEST" });
2500
- return true;
2501
- }
2502
- await invokeAndSend(input.runtime, input.ctxFactory(input.req), input.res, tool.trim(), body.args ?? {});
2503
- return true;
2504
- }
2505
- if (norm.startsWith("/invoke/") && norm.length > "/invoke/".length) {
2506
- const args = await parseArgsOrSendError(input.req, input.res);
2507
- if (args === void 0) return true;
2508
- await invokeAndSend(input.runtime, input.ctxFactory(input.req), input.res, slugToToolName(norm.slice(8)), args);
2509
- return true;
2510
- }
2511
- return false;
2512
- }
2513
- async function parseBodyOrSendError(req, res) {
2514
- try {
2515
- return await parseBody(req);
2516
- } catch (err) {
2517
- sendBadJsonBody(res, err);
2518
- return null;
2519
- }
2520
- }
2521
- async function parseArgsOrSendError(req, res) {
2522
- try {
2523
- return await parseBody(req) ?? {};
2524
- } catch (err) {
2525
- sendBadJsonBody(res, err);
2526
- return void 0;
2527
- }
2569
+ function parseBodyFromExpress(raw) {
2570
+ if (raw == null) return {};
2571
+ if (typeof raw === "object") return raw;
2572
+ const text = Buffer.isBuffer(raw) ? raw.toString("utf-8") : String(raw);
2573
+ const parsed = safeParseToolArgs(text);
2574
+ if (parsed.ok) return parsed.value;
2575
+ throw new BodyParseError("Invalid JSON body", parsed.hint);
2528
2576
  }
2529
2577
  function sendBadJsonBody(res, err) {
2530
2578
  const hint = err instanceof BodyParseError ? err.hint : void 0;
@@ -2547,16 +2595,117 @@ async function invokeAndSend(runtime, ctx, res, tool, args) {
2547
2595
  details: result.error?.details
2548
2596
  });
2549
2597
  }
2550
- function listenOpenAPIHttpServer(server, options = {}) {
2598
+ function createOpenAPIHttpServer(runtime, options = {}) {
2599
+ const app = express();
2600
+ const router = express.Router();
2601
+ const basePath = (options.basePath ?? "").replace(/\/$/, "");
2602
+ const ctxFactory = options.execContextFactory ?? (() => ({ ...DEFAULT_CTX2 }));
2603
+ app.use(express.text({ type: "*/*" }));
2604
+ router.get("/", (_req, res) => {
2605
+ const specPath = basePath ? `${basePath}/openapi.json` : "/openapi.json";
2606
+ res.type("text/html; charset=utf-8").send(swaggerUiHtml(specPath));
2607
+ });
2608
+ router.get("/swagger", (_req, res) => {
2609
+ const specPath = basePath ? `${basePath}/openapi.json` : "/openapi.json";
2610
+ res.type("text/html; charset=utf-8").send(swaggerUiHtml(specPath));
2611
+ });
2612
+ router.get("/openapi.json", (_req, res) => {
2613
+ sendJson(
2614
+ res,
2615
+ 200,
2616
+ toolsToOpenAPISpec(runtime.getRegistry(), {
2617
+ title: "Tool API",
2618
+ version: "1.0.0",
2619
+ basePath: basePath || void 0
2620
+ })
2621
+ );
2622
+ });
2623
+ router.get("/spec", (_req, res) => {
2624
+ sendJson(
2625
+ res,
2626
+ 200,
2627
+ toolsToOpenAPISpec(runtime.getRegistry(), {
2628
+ title: "Tool API",
2629
+ version: "1.0.0",
2630
+ basePath: basePath || void 0
2631
+ })
2632
+ );
2633
+ });
2634
+ router.get("/tools", async (_req, res, next) => {
2635
+ try {
2636
+ const { enrichSpecWithCanonicalSchema: enrichSpecWithCanonicalSchema2 } = await import('./canonicalCoreSchemas-PHGTNPN5.js');
2637
+ const tools = runtime.getRegistry().snapshot().map(enrichSpecWithCanonicalSchema2).map((s) => ({
2638
+ name: s.name,
2639
+ description: s.description,
2640
+ kind: s.kind,
2641
+ inputSchema: s.inputSchema
2642
+ }));
2643
+ sendJson(res, 200, { tools });
2644
+ } catch (error) {
2645
+ next(error);
2646
+ }
2647
+ });
2648
+ router.post("/invoke", async (req, res) => {
2649
+ let body = null;
2650
+ try {
2651
+ body = parseBodyFromExpress(req.body);
2652
+ } catch (err) {
2653
+ sendBadJsonBody(res, err);
2654
+ return;
2655
+ }
2656
+ const tool = body.tool;
2657
+ if (typeof tool !== "string" || !tool.trim()) {
2658
+ sendJson(res, 400, { error: "Missing or invalid 'tool' in body", kind: "BAD_REQUEST" });
2659
+ return;
2660
+ }
2661
+ await invokeAndSend(runtime, ctxFactory(req), res, tool.trim(), body.args ?? {});
2662
+ });
2663
+ router.post("/invoke/:slug", async (req, res) => {
2664
+ let args;
2665
+ try {
2666
+ args = parseBodyFromExpress(req.body);
2667
+ } catch (err) {
2668
+ sendBadJsonBody(res, err);
2669
+ return;
2670
+ }
2671
+ await invokeAndSend(runtime, ctxFactory(req), res, slugToToolName(req.params?.slug ?? ""), args);
2672
+ });
2673
+ if (basePath) {
2674
+ app.use(basePath, router);
2675
+ } else {
2676
+ app.use(router);
2677
+ }
2678
+ app.use((req, res) => {
2679
+ sendJson(res, 404, { error: "Not found", path: req.url ?? "/" });
2680
+ });
2681
+ app.use((err, _req, res, _next) => {
2682
+ const message = err instanceof Error ? err.message : String(err);
2683
+ sendJson(res, 500, { error: message, kind: "INTERNAL_ERROR" });
2684
+ });
2685
+ const originalListen = app.listen.bind(app);
2686
+ const defaultPort = options.port;
2687
+ const defaultHost = options.host;
2688
+ app.listen = ((...args) => {
2689
+ if (args.length === 0) {
2690
+ return originalListen(defaultPort ?? 0, defaultHost ?? "localhost");
2691
+ }
2692
+ if (args.length === 1 && typeof args[0] === "function") {
2693
+ return originalListen(defaultPort ?? 0, defaultHost ?? "localhost", args[0]);
2694
+ }
2695
+ return originalListen(...args);
2696
+ });
2697
+ return app;
2698
+ }
2699
+ function listenOpenAPIHttpServer(app, options = {}) {
2551
2700
  return new Promise((resolve4, reject) => {
2552
2701
  const port = options.port ?? 0;
2553
2702
  const host = options.host ?? "localhost";
2554
- server.listen(port, host, () => {
2555
- const addr = server.address();
2703
+ const httpServer = app.listen(port, host, () => {
2704
+ const addr = httpServer.address();
2556
2705
  const actualPort = typeof addr === "object" && addr?.port != null ? addr.port : port;
2557
- resolve4({ port: actualPort, host });
2706
+ resolve4({ port: actualPort, host, httpServer });
2558
2707
  });
2559
- server.on("error", reject);
2708
+ httpServer.on("error", reject);
2560
2709
  });
2561
2710
  }
2562
2711
  async function createHttpService(runtimeOrConfig, options = {}) {
@@ -2567,144 +2716,25 @@ async function createHttpService(runtimeOrConfig, options = {}) {
2567
2716
  version: options.version ?? "1.0.0",
2568
2717
  basePath: options.basePath
2569
2718
  });
2719
+ let activeHttpServer = null;
2570
2720
  return {
2571
2721
  server,
2572
2722
  openApiSpec,
2573
- listen: (listenOpts) => listenOpenAPIHttpServer(server, listenOpts)
2574
- };
2575
- }
2576
-
2577
- // src/api/expose/mcpServer.ts
2578
- var DEFAULT_CTX2 = {
2579
- requestId: `mcp-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
2580
- taskId: `task-${Date.now()}`,
2581
- permissions: [
2582
- "read:web",
2583
- "read:fs",
2584
- "write:fs",
2585
- "read:db",
2586
- "write:db",
2587
- "network",
2588
- "workflow",
2589
- "danger:destructive"
2590
- ]
2591
- };
2592
- function toMcpToolName(registryName) {
2593
- return normalizeToolName(registryName);
2594
- }
2595
- async function createMcpServerWithTools(runtime, options) {
2596
- const { McpServer } = await import('@modelcontextprotocol/sdk/server/mcp.js');
2597
- const name = options.name ?? "agent-tool";
2598
- const version = options.version ?? "1.0.0";
2599
- const ctxFactory = options.execContextFactory ?? (() => ({ ...DEFAULT_CTX2 }));
2600
- const server = new McpServer({ name, version });
2601
- const registry = runtime.getRegistry();
2602
- const specs = registry.snapshot();
2603
- for (const spec of specs) {
2604
- const mcpName = toMcpToolName(spec.name);
2605
- server.registerTool(
2606
- mcpName,
2607
- {
2608
- description: spec.description ?? `Tool: ${spec.name}`,
2609
- inputSchema: spec.inputSchema,
2610
- _meta: spec._meta
2611
- },
2612
- async (args) => {
2613
- const ctx = ctxFactory();
2614
- const result = await runtime.invoke(
2615
- { tool: spec.name, args: args ?? {}, purpose: MCP_KIND },
2616
- ctx
2617
- );
2618
- if (result.ok) {
2619
- return { content: [{ type: "text", text: JSON.stringify(result.result) }] };
2620
- }
2621
- const err = result.error;
2622
- return {
2623
- content: [
2624
- {
2625
- type: "text",
2626
- text: JSON.stringify({ error: err?.message ?? "Tool failed", kind: err?.kind })
2627
- }
2628
- ],
2629
- isError: true
2630
- };
2631
- }
2632
- );
2633
- }
2634
- return { server };
2635
- }
2636
- async function createMCPServer(runtimeOrConfig, options = {}) {
2637
- const runtime = "invoke" in runtimeOrConfig && typeof runtimeOrConfig.invoke === "function" ? runtimeOrConfig : (await createRuntimeFromConfig(runtimeOrConfig)).runtime;
2638
- const { StdioServerTransport } = await import('@modelcontextprotocol/sdk/server/stdio.js');
2639
- const { server } = await createMcpServerWithTools(runtime, options);
2640
- return {
2641
- server,
2642
- async connectStdio() {
2643
- const transport = new StdioServerTransport();
2644
- await server.connect(transport);
2645
- }
2646
- };
2647
- }
2648
- function createMCPStreamableHttpHandler(runtimeOrConfig, options = {}) {
2649
- if ("invoke" in runtimeOrConfig && typeof runtimeOrConfig.invoke === "function") {
2650
- const runtime = runtimeOrConfig;
2651
- return async function streamableHttpHandler(req, res, parsedBody) {
2652
- const { StreamableHTTPServerTransport } = await import('@modelcontextprotocol/sdk/server/streamableHttp.js');
2653
- const { server } = await createMcpServerWithTools(runtime, options);
2654
- const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: void 0 });
2655
- await server.connect(transport);
2656
- const onClose = () => {
2657
- transport.close().catch(() => {
2658
- });
2659
- server.close().catch(() => {
2660
- });
2661
- res.removeListener("close", onClose);
2662
- res.removeListener("finish", onClose);
2663
- };
2664
- res.once("close", onClose);
2665
- res.once("finish", onClose);
2666
- await transport.handleRequest(
2667
- req,
2668
- res,
2669
- parsedBody
2670
- );
2671
- };
2672
- }
2673
- return (async () => {
2674
- const { runtime } = await createRuntimeFromConfig(runtimeOrConfig);
2675
- return createMCPStreamableHttpHandler(runtime, options);
2676
- })();
2677
- }
2678
- async function createMCPServerStreamableHttp(runtimeOrConfig, options = {}) {
2679
- const path = options.path ?? "/mcp";
2680
- const host = options.host ?? "127.0.0.1";
2681
- const port = options.port ?? 3e3;
2682
- const { createMcpExpressApp } = await import('@modelcontextprotocol/sdk/server/express.js');
2683
- const handler = "invoke" in runtimeOrConfig && typeof runtimeOrConfig.invoke === "function" ? createMCPStreamableHttpHandler(runtimeOrConfig, options) : await createMCPStreamableHttpHandler(runtimeOrConfig, options);
2684
- const app = createMcpExpressApp({ host });
2685
- app.post(path, handler);
2686
- return {
2687
- app,
2688
- path,
2689
- async listen(listenPort, listenHost) {
2690
- const p = listenPort ?? port;
2691
- const h = listenHost ?? host;
2692
- return new Promise((resolve4, reject) => {
2693
- const server = app.listen(p, h, () => {
2694
- const addr = server.address();
2695
- const actualPort = typeof addr === "object" && addr !== null && "port" in addr ? addr.port : p;
2696
- resolve4({ url: `http://${h}:${actualPort}${path}`, port: actualPort });
2697
- });
2723
+ listen: async (listenOpts) => {
2724
+ const { port, host, httpServer } = await listenOpenAPIHttpServer(server, listenOpts);
2725
+ activeHttpServer = httpServer;
2726
+ return { port, host };
2727
+ },
2728
+ close: async () => {
2729
+ if (!activeHttpServer) return;
2730
+ await new Promise((resolve4, reject) => {
2731
+ activeHttpServer.close((err) => err ? reject(err) : resolve4());
2698
2732
  });
2733
+ activeHttpServer = null;
2699
2734
  }
2700
2735
  };
2701
2736
  }
2702
- async function runMCPServerOverStdio(runtime, options = {}) {
2703
- const result = await createMCPServer(runtime, options);
2704
- await result.connectStdio();
2705
- return result;
2706
- }
2707
2737
 
2708
- export { PTCRuntime, createHttpService, createMCPServer, createMCPServerStreamableHttp, createMCPStreamableHttpHandler, createRuntimeFromConfig, createRuntimeFromConfigSync, expandToolDescriptorsToRegistryNames, fileDescriptorToPackagePrefix, findAndLoadToolConfig, getDisplayScope, isBarePackageDescriptor, loadToolConfig, npmDescriptorToPackagePrefixWithVersion, resolveSandboxedPath, resolveToolDescriptor, runMCPServerOverStdio };
2709
- //# sourceMappingURL=chunk-JYADGZQP.js.map
2710
- //# sourceMappingURL=chunk-JYADGZQP.js.map
2738
+ export { PTCRuntime, createHttpService, createMCPServer, createMCPServerStreamableHttp, createMCPStreamableHttpHandler, createOpenAPIHttpServer, createRuntimeFromConfig, createRuntimeFromConfigSync, expandToolDescriptorsToRegistryNames, fileDescriptorToPackagePrefix, findAndLoadToolConfig, getDisplayScope, isBarePackageDescriptor, loadToolConfig, npmDescriptorToPackagePrefixWithVersion, resolveSandboxedPath, resolveToolDescriptor, runMCPServerOverStdio };
2739
+ //# sourceMappingURL=chunk-BMAYX22K.js.map
2740
+ //# sourceMappingURL=chunk-BMAYX22K.js.map