@easynet/agent-tool 1.0.74 → 1.0.75

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 +10 -5
  2. package/dist/api/adapters/LangChainToolsHub.d.ts +1 -1
  3. package/dist/api/createAgentTools.d.ts +8 -10
  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 +18 -22
  12. package/dist/api/main.d.ts +6 -7
  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-MBCFJBZY.js} +298 -268
  18. package/dist/chunk-MBCFJBZY.js.map +1 -0
  19. package/dist/{chunk-SE6IMOIE.cjs → chunk-PYTHEY6A.cjs} +301 -269
  20. package/dist/chunk-PYTHEY6A.cjs.map +1 -0
  21. package/dist/{chunk-KTQTDKWU.cjs → chunk-SR53PQTG.cjs} +97 -78
  22. package/dist/chunk-SR53PQTG.cjs.map +1 -0
  23. package/dist/{chunk-ECHW6AWF.js → chunk-XS26ZNYC.js} +84 -65
  24. package/dist/chunk-XS26ZNYC.js.map +1 -0
  25. package/dist/index.cjs +17 -21
  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
@@ -18,7 +18,7 @@ var pTimeout = require('p-timeout');
18
18
  var module$1 = require('module');
19
19
  var url = require('url');
20
20
  var npm = require('@easynet/agent-common/npm');
21
- var http = require('http');
21
+ var express = require('express');
22
22
 
23
23
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
24
24
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -26,7 +26,27 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
26
26
  var Ajv__default = /*#__PURE__*/_interopDefault(Ajv);
27
27
  var addFormats__default = /*#__PURE__*/_interopDefault(addFormats);
28
28
  var pTimeout__default = /*#__PURE__*/_interopDefault(pTimeout);
29
+ var express__default = /*#__PURE__*/_interopDefault(express);
29
30
 
31
+ function normalizeMcpConfig(raw) {
32
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
33
+ const source = raw;
34
+ const out = {};
35
+ if (typeof source.name === "string" && source.name.trim()) out.name = source.name.trim();
36
+ if (typeof source.version === "string" && source.version.trim()) out.version = source.version.trim();
37
+ return Object.keys(out).length > 0 ? out : void 0;
38
+ }
39
+ function normalizeOpenApiConfig(raw) {
40
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
41
+ const source = raw;
42
+ const out = {};
43
+ if (typeof source.host === "string" && source.host.trim()) out.host = source.host.trim();
44
+ if (typeof source.basePath === "string") out.basePath = source.basePath;
45
+ if (typeof source.title === "string" && source.title.trim()) out.title = source.title.trim();
46
+ if (typeof source.version === "string" && source.version.trim()) out.version = source.version.trim();
47
+ if (typeof source.port === "number" && Number.isFinite(source.port)) out.port = source.port;
48
+ return Object.keys(out).length > 0 ? out : void 0;
49
+ }
30
50
  function loadToolConfig(toolYamlPath) {
31
51
  const abs = path.resolve(toolYamlPath);
32
52
  const raw = fs.readFileSync(abs, "utf8");
@@ -35,6 +55,8 @@ function loadToolConfig(toolYamlPath) {
35
55
  });
36
56
  if (!parsed || typeof parsed !== "object") return {};
37
57
  const source = parsed.spec && typeof parsed.spec === "object" && !Array.isArray(parsed.spec) ? parsed.spec : parsed;
58
+ const mcpConfig = normalizeMcpConfig(source.expose?.mcp ?? source.mcp);
59
+ const openApiConfig = normalizeOpenApiConfig(source.expose?.openapi ?? source.openapi);
38
60
  const toolsBlock = source.tools;
39
61
  if (toolsBlock != null && typeof toolsBlock === "object" && !Array.isArray(toolsBlock)) {
40
62
  const toolDefaults = toolsBlock.defaults != null && typeof toolsBlock.defaults === "object" && !Array.isArray(toolsBlock.defaults) ? toolsBlock.defaults : void 0;
@@ -48,7 +70,9 @@ function loadToolConfig(toolYamlPath) {
48
70
  blockedHosts: Array.isArray(toolsBlock.blockedHosts) ? toolsBlock.blockedHosts : source.blockedHosts,
49
71
  blockedCidrs: Array.isArray(toolsBlock.blockedCidrs) ? toolsBlock.blockedCidrs : source.blockedCidrs,
50
72
  toolDefaults,
51
- packageToolDefaults: packageToolDefaults2
73
+ packageToolDefaults: packageToolDefaults2,
74
+ mcp: mcpConfig,
75
+ openapi: openApiConfig
52
76
  };
53
77
  }
54
78
  const packageToolDefaults = typeof source.packageToolDefaults === "object" && !Array.isArray(source.packageToolDefaults) ? source.packageToolDefaults : void 0;
@@ -61,7 +85,9 @@ function loadToolConfig(toolYamlPath) {
61
85
  blockedHosts: Array.isArray(source.blockedHosts) ? source.blockedHosts : void 0,
62
86
  blockedCidrs: Array.isArray(source.blockedCidrs) ? source.blockedCidrs : void 0,
63
87
  toolDefaults: typeof source.toolDefaults === "object" && !Array.isArray(source.toolDefaults) ? source.toolDefaults : void 0,
64
- packageToolDefaults
88
+ packageToolDefaults,
89
+ mcp: mcpConfig,
90
+ openapi: openApiConfig
65
91
  };
66
92
  }
67
93
  function resolveSandboxedPath(toolYamlPath, sandboxedPath) {
@@ -1727,7 +1753,7 @@ function buildInputSchemaHint(inputSchema) {
1727
1753
  if (names.length === 0) return null;
1728
1754
  return `This tool expects input property ${names.length === 1 ? `'${names[0]}'` : `one of [${names.map((n) => `'${n}'`).join(", ")}]`}. Use the exact property names from the tool schema.`;
1729
1755
  }
1730
- var requireFromPackage = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-SE6IMOIE.cjs', document.baseURI).href)));
1756
+ var requireFromPackage = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-PYTHEY6A.cjs', document.baseURI).href)));
1731
1757
  function getProjectRequire() {
1732
1758
  const cwd = process.cwd();
1733
1759
  if (fs.existsSync(path.join(cwd, "package.json"))) return module$1.createRequire(path.join(cwd, "package.json"));
@@ -1893,7 +1919,7 @@ function parseNpmDescriptor(entry) {
1893
1919
  }
1894
1920
 
1895
1921
  // src/api/runtimeFromConfig.ts
1896
- var requireFromPackage2 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-SE6IMOIE.cjs', document.baseURI).href)));
1922
+ var requireFromPackage2 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-PYTHEY6A.cjs', document.baseURI).href)));
1897
1923
  var DEFAULT_EXTENSION_PACKAGES = [];
1898
1924
  function resolveFileDescriptorPath(descriptor, configFilePath) {
1899
1925
  const parsed = parseToolPath(descriptor.trim());
@@ -2204,6 +2230,137 @@ async function createRuntimeFromConfig(options = {}) {
2204
2230
  return createRuntimeFromConfigSync(options);
2205
2231
  }
2206
2232
 
2233
+ // src/api/expose/mcpServer.ts
2234
+ var DEFAULT_CTX = {
2235
+ requestId: `mcp-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
2236
+ taskId: `task-${Date.now()}`,
2237
+ permissions: [
2238
+ "read:web",
2239
+ "read:fs",
2240
+ "write:fs",
2241
+ "read:db",
2242
+ "write:db",
2243
+ "network",
2244
+ "workflow",
2245
+ "danger:destructive"
2246
+ ]
2247
+ };
2248
+ function toMcpToolName(registryName) {
2249
+ return chunkQEJF3KDV_cjs.normalizeToolName(registryName);
2250
+ }
2251
+ async function createMcpServerWithTools(runtime, options) {
2252
+ const { McpServer } = await import('@modelcontextprotocol/sdk/server/mcp.js');
2253
+ const name = options.name ?? "agent-tool";
2254
+ const version = options.version ?? "1.0.0";
2255
+ const ctxFactory = options.execContextFactory ?? (() => ({ ...DEFAULT_CTX }));
2256
+ const server = new McpServer({ name, version });
2257
+ const registry = runtime.getRegistry();
2258
+ const specs = registry.snapshot();
2259
+ for (const spec of specs) {
2260
+ const mcpName = toMcpToolName(spec.name);
2261
+ server.registerTool(
2262
+ mcpName,
2263
+ {
2264
+ description: spec.description ?? `Tool: ${spec.name}`,
2265
+ inputSchema: spec.inputSchema,
2266
+ _meta: spec._meta
2267
+ },
2268
+ async (args) => {
2269
+ const ctx = ctxFactory();
2270
+ const result = await runtime.invoke(
2271
+ { tool: spec.name, args: args ?? {}, purpose: chunk33N4Y6IS_cjs.MCP_KIND },
2272
+ ctx
2273
+ );
2274
+ if (result.ok) {
2275
+ return { content: [{ type: "text", text: JSON.stringify(result.result) }] };
2276
+ }
2277
+ const err = result.error;
2278
+ return {
2279
+ content: [
2280
+ {
2281
+ type: "text",
2282
+ text: JSON.stringify({ error: err?.message ?? "Tool failed", kind: err?.kind })
2283
+ }
2284
+ ],
2285
+ isError: true
2286
+ };
2287
+ }
2288
+ );
2289
+ }
2290
+ return { server };
2291
+ }
2292
+ async function createMCPServer(runtimeOrConfig, options = {}) {
2293
+ const runtime = "invoke" in runtimeOrConfig && typeof runtimeOrConfig.invoke === "function" ? runtimeOrConfig : (await createRuntimeFromConfig(runtimeOrConfig)).runtime;
2294
+ const { StdioServerTransport } = await import('@modelcontextprotocol/sdk/server/stdio.js');
2295
+ const { server } = await createMcpServerWithTools(runtime, options);
2296
+ return {
2297
+ server,
2298
+ async connectStdio() {
2299
+ const transport = new StdioServerTransport();
2300
+ await server.connect(transport);
2301
+ }
2302
+ };
2303
+ }
2304
+ function createMCPStreamableHttpHandler(runtimeOrConfig, options = {}) {
2305
+ if ("invoke" in runtimeOrConfig && typeof runtimeOrConfig.invoke === "function") {
2306
+ const runtime = runtimeOrConfig;
2307
+ return async function streamableHttpHandler(req, res, parsedBody) {
2308
+ const { StreamableHTTPServerTransport } = await import('@modelcontextprotocol/sdk/server/streamableHttp.js');
2309
+ const { server } = await createMcpServerWithTools(runtime, options);
2310
+ const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: void 0 });
2311
+ await server.connect(transport);
2312
+ const onClose = () => {
2313
+ transport.close().catch(() => {
2314
+ });
2315
+ server.close().catch(() => {
2316
+ });
2317
+ res.removeListener("close", onClose);
2318
+ res.removeListener("finish", onClose);
2319
+ };
2320
+ res.once("close", onClose);
2321
+ res.once("finish", onClose);
2322
+ await transport.handleRequest(
2323
+ req,
2324
+ res,
2325
+ parsedBody
2326
+ );
2327
+ };
2328
+ }
2329
+ return (async () => {
2330
+ const { runtime } = await createRuntimeFromConfig(runtimeOrConfig);
2331
+ return createMCPStreamableHttpHandler(runtime, options);
2332
+ })();
2333
+ }
2334
+ async function createMCPServerStreamableHttp(runtimeOrConfig, options = {}) {
2335
+ const path = options.path ?? "/mcp";
2336
+ const host = options.host ?? "127.0.0.1";
2337
+ const port = options.port ?? 3e3;
2338
+ const { createMcpExpressApp } = await import('@modelcontextprotocol/sdk/server/express.js');
2339
+ const handler = "invoke" in runtimeOrConfig && typeof runtimeOrConfig.invoke === "function" ? createMCPStreamableHttpHandler(runtimeOrConfig, options) : await createMCPStreamableHttpHandler(runtimeOrConfig, options);
2340
+ const app = createMcpExpressApp({ host });
2341
+ app.post(path, handler);
2342
+ return {
2343
+ app,
2344
+ path,
2345
+ async listen(listenPort, listenHost) {
2346
+ const p = listenPort ?? port;
2347
+ const h = listenHost ?? host;
2348
+ return new Promise((resolve4, reject) => {
2349
+ const server = app.listen(p, h, () => {
2350
+ const addr = server.address();
2351
+ const actualPort = typeof addr === "object" && addr !== null && "port" in addr ? addr.port : p;
2352
+ resolve4({ url: `http://${h}:${actualPort}${path}`, port: actualPort });
2353
+ });
2354
+ });
2355
+ }
2356
+ };
2357
+ }
2358
+ async function runMCPServerOverStdio(runtime, options = {}) {
2359
+ const result = await createMCPServer(runtime, options);
2360
+ await result.connectStdio();
2361
+ return result;
2362
+ }
2363
+
2207
2364
  // src/api/expose/openapi.ts
2208
2365
  function toolNameToSlug(name) {
2209
2366
  return name.replace(/\./g, "~");
@@ -2341,7 +2498,7 @@ function createPerToolPathSpec(spec, key) {
2341
2498
  }
2342
2499
 
2343
2500
  // src/api/expose/openapiHttp.ts
2344
- var DEFAULT_CTX = {
2501
+ var DEFAULT_CTX2 = {
2345
2502
  requestId: `http-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
2346
2503
  taskId: `task-${Date.now()}`,
2347
2504
  permissions: [
@@ -2355,8 +2512,17 @@ var DEFAULT_CTX = {
2355
2512
  "danger:destructive"
2356
2513
  ]
2357
2514
  };
2515
+ var BodyParseError = class extends Error {
2516
+ hint;
2517
+ constructor(message, hint) {
2518
+ super(message);
2519
+ this.name = "BodyParseError";
2520
+ this.hint = hint;
2521
+ }
2522
+ };
2358
2523
  function safeParseToolArgs(raw) {
2359
2524
  const text = String(raw ?? "").trim();
2525
+ if (!text) return { ok: true, value: {} };
2360
2526
  const firstBrace = text.indexOf("{");
2361
2527
  if (firstBrace === -1) {
2362
2528
  return {
@@ -2366,9 +2532,7 @@ function safeParseToolArgs(raw) {
2366
2532
  }
2367
2533
  let jsonText = text.slice(firstBrace);
2368
2534
  const lastBrace = jsonText.lastIndexOf("}");
2369
- if (lastBrace !== -1) {
2370
- jsonText = jsonText.slice(0, lastBrace + 1);
2371
- }
2535
+ if (lastBrace !== -1) jsonText = jsonText.slice(0, lastBrace + 1);
2372
2536
  try {
2373
2537
  return { ok: true, value: JSON.parse(jsonText) };
2374
2538
  } catch {
@@ -2378,37 +2542,8 @@ function safeParseToolArgs(raw) {
2378
2542
  };
2379
2543
  }
2380
2544
  }
2381
- var BodyParseError = class extends Error {
2382
- hint;
2383
- constructor(message, hint) {
2384
- super(message);
2385
- this.name = "BodyParseError";
2386
- this.hint = hint;
2387
- }
2388
- };
2389
- function parseBody(req) {
2390
- return new Promise((resolve4, reject) => {
2391
- const chunks = [];
2392
- req.on("data", (chunk) => chunks.push(chunk));
2393
- req.on("end", () => {
2394
- const raw = Buffer.concat(chunks).toString("utf-8");
2395
- if (!raw.trim()) {
2396
- resolve4({});
2397
- return;
2398
- }
2399
- const parsed = safeParseToolArgs(raw);
2400
- if (parsed.ok) {
2401
- resolve4(parsed.value);
2402
- return;
2403
- }
2404
- reject(new BodyParseError("Invalid JSON body", parsed.hint));
2405
- });
2406
- req.on("error", reject);
2407
- });
2408
- }
2409
2545
  function sendJson(res, status, data) {
2410
- res.writeHead(status, { "Content-Type": "application/json" });
2411
- res.end(JSON.stringify(data));
2546
+ res.status(status).json(data);
2412
2547
  }
2413
2548
  function swaggerUiHtml(specUrl) {
2414
2549
  const specUrlEscaped = specUrl.replace(/"/g, """);
@@ -2441,99 +2576,13 @@ function swaggerUiHtml(specUrl) {
2441
2576
  </body>
2442
2577
  </html>`;
2443
2578
  }
2444
- function createOpenAPIHttpServer(runtime, options = {}) {
2445
- const basePath = (options.basePath ?? "").replace(/\/$/, "");
2446
- const ctxFactory = options.execContextFactory ?? (() => ({ ...DEFAULT_CTX }));
2447
- const server = http.createServer(
2448
- (req, res) => handleOpenApiHttpRequest({ runtime, req, res, basePath, ctxFactory })
2449
- );
2450
- return server;
2451
- }
2452
- async function handleOpenApiHttpRequest(input) {
2453
- const norm = normalizePath(input.req.url, input.basePath);
2454
- try {
2455
- if (await maybeHandleDocsRoute(input, norm)) return;
2456
- if (await maybeHandleToolsRoute(input, norm)) return;
2457
- if (await maybeHandleInvokeRoute(input, norm)) return;
2458
- sendJson(input.res, 404, { error: "Not found", path: norm });
2459
- } catch (err) {
2460
- const message = err instanceof Error ? err.message : String(err);
2461
- sendJson(input.res, 500, { error: message, kind: "INTERNAL_ERROR" });
2462
- }
2463
- }
2464
- function normalizePath(url, basePath) {
2465
- const path = (url ?? "/").split("?")[0] ?? "/";
2466
- return basePath ? path === basePath ? "" : path.replace(basePath, "") || "/" : path;
2467
- }
2468
- async function maybeHandleDocsRoute(input, norm) {
2469
- if (input.req.method === "GET" && (norm === "/" || norm === "/swagger")) {
2470
- const specPath = input.basePath ? `${input.basePath}/openapi.json` : "/openapi.json";
2471
- input.res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
2472
- input.res.end(swaggerUiHtml(specPath));
2473
- return true;
2474
- }
2475
- if (input.req.method === "GET" && (norm === "/openapi.json" || norm === "/spec")) {
2476
- sendJson(
2477
- input.res,
2478
- 200,
2479
- toolsToOpenAPISpec(input.runtime.getRegistry(), {
2480
- title: "Tool API",
2481
- version: "1.0.0",
2482
- basePath: input.basePath || void 0
2483
- })
2484
- );
2485
- return true;
2486
- }
2487
- return false;
2488
- }
2489
- async function maybeHandleToolsRoute(input, norm) {
2490
- if (input.req.method !== "GET" || norm !== "/tools") return false;
2491
- const { enrichSpecWithCanonicalSchema: enrichSpecWithCanonicalSchema2 } = await import('./canonicalCoreSchemas-TY7NCWCC.cjs');
2492
- const tools = input.runtime.getRegistry().snapshot().map(enrichSpecWithCanonicalSchema2).map((s) => ({
2493
- name: s.name,
2494
- description: s.description,
2495
- kind: s.kind,
2496
- inputSchema: s.inputSchema
2497
- }));
2498
- sendJson(input.res, 200, { tools });
2499
- return true;
2500
- }
2501
- async function maybeHandleInvokeRoute(input, norm) {
2502
- if (input.req.method !== "POST") return false;
2503
- if (norm === "/invoke") {
2504
- const body = await parseBodyOrSendError(input.req, input.res);
2505
- if (!body) return true;
2506
- const tool = body.tool;
2507
- if (typeof tool !== "string" || !tool.trim()) {
2508
- sendJson(input.res, 400, { error: "Missing or invalid 'tool' in body", kind: "BAD_REQUEST" });
2509
- return true;
2510
- }
2511
- await invokeAndSend(input.runtime, input.ctxFactory(input.req), input.res, tool.trim(), body.args ?? {});
2512
- return true;
2513
- }
2514
- if (norm.startsWith("/invoke/") && norm.length > "/invoke/".length) {
2515
- const args = await parseArgsOrSendError(input.req, input.res);
2516
- if (args === void 0) return true;
2517
- await invokeAndSend(input.runtime, input.ctxFactory(input.req), input.res, slugToToolName(norm.slice(8)), args);
2518
- return true;
2519
- }
2520
- return false;
2521
- }
2522
- async function parseBodyOrSendError(req, res) {
2523
- try {
2524
- return await parseBody(req);
2525
- } catch (err) {
2526
- sendBadJsonBody(res, err);
2527
- return null;
2528
- }
2529
- }
2530
- async function parseArgsOrSendError(req, res) {
2531
- try {
2532
- return await parseBody(req) ?? {};
2533
- } catch (err) {
2534
- sendBadJsonBody(res, err);
2535
- return void 0;
2536
- }
2579
+ function parseBodyFromExpress(raw) {
2580
+ if (raw == null) return {};
2581
+ if (typeof raw === "object") return raw;
2582
+ const text = Buffer.isBuffer(raw) ? raw.toString("utf-8") : String(raw);
2583
+ const parsed = safeParseToolArgs(text);
2584
+ if (parsed.ok) return parsed.value;
2585
+ throw new BodyParseError("Invalid JSON body", parsed.hint);
2537
2586
  }
2538
2587
  function sendBadJsonBody(res, err) {
2539
2588
  const hint = err instanceof BodyParseError ? err.hint : void 0;
@@ -2556,16 +2605,117 @@ async function invokeAndSend(runtime, ctx, res, tool, args) {
2556
2605
  details: result.error?.details
2557
2606
  });
2558
2607
  }
2559
- function listenOpenAPIHttpServer(server, options = {}) {
2608
+ function createOpenAPIHttpServer(runtime, options = {}) {
2609
+ const app = express__default.default();
2610
+ const router = express__default.default.Router();
2611
+ const basePath = (options.basePath ?? "").replace(/\/$/, "");
2612
+ const ctxFactory = options.execContextFactory ?? (() => ({ ...DEFAULT_CTX2 }));
2613
+ app.use(express__default.default.text({ type: "*/*" }));
2614
+ router.get("/", (_req, res) => {
2615
+ const specPath = basePath ? `${basePath}/openapi.json` : "/openapi.json";
2616
+ res.type("text/html; charset=utf-8").send(swaggerUiHtml(specPath));
2617
+ });
2618
+ router.get("/swagger", (_req, res) => {
2619
+ const specPath = basePath ? `${basePath}/openapi.json` : "/openapi.json";
2620
+ res.type("text/html; charset=utf-8").send(swaggerUiHtml(specPath));
2621
+ });
2622
+ router.get("/openapi.json", (_req, res) => {
2623
+ sendJson(
2624
+ res,
2625
+ 200,
2626
+ toolsToOpenAPISpec(runtime.getRegistry(), {
2627
+ title: "Tool API",
2628
+ version: "1.0.0",
2629
+ basePath: basePath || void 0
2630
+ })
2631
+ );
2632
+ });
2633
+ router.get("/spec", (_req, res) => {
2634
+ sendJson(
2635
+ res,
2636
+ 200,
2637
+ toolsToOpenAPISpec(runtime.getRegistry(), {
2638
+ title: "Tool API",
2639
+ version: "1.0.0",
2640
+ basePath: basePath || void 0
2641
+ })
2642
+ );
2643
+ });
2644
+ router.get("/tools", async (_req, res, next) => {
2645
+ try {
2646
+ const { enrichSpecWithCanonicalSchema: enrichSpecWithCanonicalSchema2 } = await import('./canonicalCoreSchemas-TY7NCWCC.cjs');
2647
+ const tools = runtime.getRegistry().snapshot().map(enrichSpecWithCanonicalSchema2).map((s) => ({
2648
+ name: s.name,
2649
+ description: s.description,
2650
+ kind: s.kind,
2651
+ inputSchema: s.inputSchema
2652
+ }));
2653
+ sendJson(res, 200, { tools });
2654
+ } catch (error) {
2655
+ next(error);
2656
+ }
2657
+ });
2658
+ router.post("/invoke", async (req, res) => {
2659
+ let body = null;
2660
+ try {
2661
+ body = parseBodyFromExpress(req.body);
2662
+ } catch (err) {
2663
+ sendBadJsonBody(res, err);
2664
+ return;
2665
+ }
2666
+ const tool = body.tool;
2667
+ if (typeof tool !== "string" || !tool.trim()) {
2668
+ sendJson(res, 400, { error: "Missing or invalid 'tool' in body", kind: "BAD_REQUEST" });
2669
+ return;
2670
+ }
2671
+ await invokeAndSend(runtime, ctxFactory(req), res, tool.trim(), body.args ?? {});
2672
+ });
2673
+ router.post("/invoke/:slug", async (req, res) => {
2674
+ let args;
2675
+ try {
2676
+ args = parseBodyFromExpress(req.body);
2677
+ } catch (err) {
2678
+ sendBadJsonBody(res, err);
2679
+ return;
2680
+ }
2681
+ await invokeAndSend(runtime, ctxFactory(req), res, slugToToolName(req.params?.slug ?? ""), args);
2682
+ });
2683
+ if (basePath) {
2684
+ app.use(basePath, router);
2685
+ } else {
2686
+ app.use(router);
2687
+ }
2688
+ app.use((req, res) => {
2689
+ sendJson(res, 404, { error: "Not found", path: req.url ?? "/" });
2690
+ });
2691
+ app.use((err, _req, res, _next) => {
2692
+ const message = err instanceof Error ? err.message : String(err);
2693
+ sendJson(res, 500, { error: message, kind: "INTERNAL_ERROR" });
2694
+ });
2695
+ const originalListen = app.listen.bind(app);
2696
+ const defaultPort = options.port;
2697
+ const defaultHost = options.host;
2698
+ app.listen = ((...args) => {
2699
+ if (args.length === 0) {
2700
+ return originalListen(defaultPort ?? 0, defaultHost ?? "localhost");
2701
+ }
2702
+ if (args.length === 1 && typeof args[0] === "function") {
2703
+ return originalListen(defaultPort ?? 0, defaultHost ?? "localhost", args[0]);
2704
+ }
2705
+ return originalListen(...args);
2706
+ });
2707
+ return app;
2708
+ }
2709
+ function listenOpenAPIHttpServer(app, options = {}) {
2560
2710
  return new Promise((resolve4, reject) => {
2561
2711
  const port = options.port ?? 0;
2562
2712
  const host = options.host ?? "localhost";
2563
- server.listen(port, host, () => {
2564
- const addr = server.address();
2713
+ const httpServer = app.listen(port, host, () => {
2714
+ const addr = httpServer.address();
2565
2715
  const actualPort = typeof addr === "object" && addr?.port != null ? addr.port : port;
2566
- resolve4({ port: actualPort, host });
2716
+ resolve4({ port: actualPort, host, httpServer });
2567
2717
  });
2568
- server.on("error", reject);
2718
+ httpServer.on("error", reject);
2569
2719
  });
2570
2720
  }
2571
2721
  async function createHttpService(runtimeOrConfig, options = {}) {
@@ -2576,149 +2726,31 @@ async function createHttpService(runtimeOrConfig, options = {}) {
2576
2726
  version: options.version ?? "1.0.0",
2577
2727
  basePath: options.basePath
2578
2728
  });
2729
+ let activeHttpServer = null;
2579
2730
  return {
2580
2731
  server,
2581
2732
  openApiSpec,
2582
- listen: (listenOpts) => listenOpenAPIHttpServer(server, listenOpts)
2583
- };
2584
- }
2585
-
2586
- // src/api/expose/mcpServer.ts
2587
- var DEFAULT_CTX2 = {
2588
- requestId: `mcp-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
2589
- taskId: `task-${Date.now()}`,
2590
- permissions: [
2591
- "read:web",
2592
- "read:fs",
2593
- "write:fs",
2594
- "read:db",
2595
- "write:db",
2596
- "network",
2597
- "workflow",
2598
- "danger:destructive"
2599
- ]
2600
- };
2601
- function toMcpToolName(registryName) {
2602
- return chunkQEJF3KDV_cjs.normalizeToolName(registryName);
2603
- }
2604
- async function createMcpServerWithTools(runtime, options) {
2605
- const { McpServer } = await import('@modelcontextprotocol/sdk/server/mcp.js');
2606
- const name = options.name ?? "agent-tool";
2607
- const version = options.version ?? "1.0.0";
2608
- const ctxFactory = options.execContextFactory ?? (() => ({ ...DEFAULT_CTX2 }));
2609
- const server = new McpServer({ name, version });
2610
- const registry = runtime.getRegistry();
2611
- const specs = registry.snapshot();
2612
- for (const spec of specs) {
2613
- const mcpName = toMcpToolName(spec.name);
2614
- server.registerTool(
2615
- mcpName,
2616
- {
2617
- description: spec.description ?? `Tool: ${spec.name}`,
2618
- inputSchema: spec.inputSchema,
2619
- _meta: spec._meta
2620
- },
2621
- async (args) => {
2622
- const ctx = ctxFactory();
2623
- const result = await runtime.invoke(
2624
- { tool: spec.name, args: args ?? {}, purpose: chunk33N4Y6IS_cjs.MCP_KIND },
2625
- ctx
2626
- );
2627
- if (result.ok) {
2628
- return { content: [{ type: "text", text: JSON.stringify(result.result) }] };
2629
- }
2630
- const err = result.error;
2631
- return {
2632
- content: [
2633
- {
2634
- type: "text",
2635
- text: JSON.stringify({ error: err?.message ?? "Tool failed", kind: err?.kind })
2636
- }
2637
- ],
2638
- isError: true
2639
- };
2640
- }
2641
- );
2642
- }
2643
- return { server };
2644
- }
2645
- async function createMCPServer(runtimeOrConfig, options = {}) {
2646
- const runtime = "invoke" in runtimeOrConfig && typeof runtimeOrConfig.invoke === "function" ? runtimeOrConfig : (await createRuntimeFromConfig(runtimeOrConfig)).runtime;
2647
- const { StdioServerTransport } = await import('@modelcontextprotocol/sdk/server/stdio.js');
2648
- const { server } = await createMcpServerWithTools(runtime, options);
2649
- return {
2650
- server,
2651
- async connectStdio() {
2652
- const transport = new StdioServerTransport();
2653
- await server.connect(transport);
2654
- }
2655
- };
2656
- }
2657
- function createMCPStreamableHttpHandler(runtimeOrConfig, options = {}) {
2658
- if ("invoke" in runtimeOrConfig && typeof runtimeOrConfig.invoke === "function") {
2659
- const runtime = runtimeOrConfig;
2660
- return async function streamableHttpHandler(req, res, parsedBody) {
2661
- const { StreamableHTTPServerTransport } = await import('@modelcontextprotocol/sdk/server/streamableHttp.js');
2662
- const { server } = await createMcpServerWithTools(runtime, options);
2663
- const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: void 0 });
2664
- await server.connect(transport);
2665
- const onClose = () => {
2666
- transport.close().catch(() => {
2667
- });
2668
- server.close().catch(() => {
2669
- });
2670
- res.removeListener("close", onClose);
2671
- res.removeListener("finish", onClose);
2672
- };
2673
- res.once("close", onClose);
2674
- res.once("finish", onClose);
2675
- await transport.handleRequest(
2676
- req,
2677
- res,
2678
- parsedBody
2679
- );
2680
- };
2681
- }
2682
- return (async () => {
2683
- const { runtime } = await createRuntimeFromConfig(runtimeOrConfig);
2684
- return createMCPStreamableHttpHandler(runtime, options);
2685
- })();
2686
- }
2687
- async function createMCPServerStreamableHttp(runtimeOrConfig, options = {}) {
2688
- const path = options.path ?? "/mcp";
2689
- const host = options.host ?? "127.0.0.1";
2690
- const port = options.port ?? 3e3;
2691
- const { createMcpExpressApp } = await import('@modelcontextprotocol/sdk/server/express.js');
2692
- const handler = "invoke" in runtimeOrConfig && typeof runtimeOrConfig.invoke === "function" ? createMCPStreamableHttpHandler(runtimeOrConfig, options) : await createMCPStreamableHttpHandler(runtimeOrConfig, options);
2693
- const app = createMcpExpressApp({ host });
2694
- app.post(path, handler);
2695
- return {
2696
- app,
2697
- path,
2698
- async listen(listenPort, listenHost) {
2699
- const p = listenPort ?? port;
2700
- const h = listenHost ?? host;
2701
- return new Promise((resolve4, reject) => {
2702
- const server = app.listen(p, h, () => {
2703
- const addr = server.address();
2704
- const actualPort = typeof addr === "object" && addr !== null && "port" in addr ? addr.port : p;
2705
- resolve4({ url: `http://${h}:${actualPort}${path}`, port: actualPort });
2706
- });
2733
+ listen: async (listenOpts) => {
2734
+ const { port, host, httpServer } = await listenOpenAPIHttpServer(server, listenOpts);
2735
+ activeHttpServer = httpServer;
2736
+ return { port, host };
2737
+ },
2738
+ close: async () => {
2739
+ if (!activeHttpServer) return;
2740
+ await new Promise((resolve4, reject) => {
2741
+ activeHttpServer.close((err) => err ? reject(err) : resolve4());
2707
2742
  });
2743
+ activeHttpServer = null;
2708
2744
  }
2709
2745
  };
2710
2746
  }
2711
- async function runMCPServerOverStdio(runtime, options = {}) {
2712
- const result = await createMCPServer(runtime, options);
2713
- await result.connectStdio();
2714
- return result;
2715
- }
2716
2747
 
2717
2748
  exports.PTCRuntime = PTCRuntime;
2718
2749
  exports.createHttpService = createHttpService;
2719
2750
  exports.createMCPServer = createMCPServer;
2720
2751
  exports.createMCPServerStreamableHttp = createMCPServerStreamableHttp;
2721
2752
  exports.createMCPStreamableHttpHandler = createMCPStreamableHttpHandler;
2753
+ exports.createOpenAPIHttpServer = createOpenAPIHttpServer;
2722
2754
  exports.createRuntimeFromConfig = createRuntimeFromConfig;
2723
2755
  exports.createRuntimeFromConfigSync = createRuntimeFromConfigSync;
2724
2756
  exports.expandToolDescriptorsToRegistryNames = expandToolDescriptorsToRegistryNames;
@@ -2731,5 +2763,5 @@ exports.npmDescriptorToPackagePrefixWithVersion = npmDescriptorToPackagePrefixWi
2731
2763
  exports.resolveSandboxedPath = resolveSandboxedPath;
2732
2764
  exports.resolveToolDescriptor = resolveToolDescriptor;
2733
2765
  exports.runMCPServerOverStdio = runMCPServerOverStdio;
2734
- //# sourceMappingURL=chunk-SE6IMOIE.cjs.map
2735
- //# sourceMappingURL=chunk-SE6IMOIE.cjs.map
2766
+ //# sourceMappingURL=chunk-PYTHEY6A.cjs.map
2767
+ //# sourceMappingURL=chunk-PYTHEY6A.cjs.map