@frontmcp/sdk 1.4.0 → 1.5.0-rc.1

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 (67) hide show
  1. package/auth/flows/oauth.authorize.flow.d.ts.map +1 -1
  2. package/auth/flows/oauth.token.flow.d.ts.map +1 -1
  3. package/auth/flows/session.verify.flow.d.ts.map +1 -1
  4. package/auth/instances/instance.local-primary-auth.d.ts.map +1 -1
  5. package/common/decorators/app.decorator.d.ts +13 -1
  6. package/common/decorators/app.decorator.d.ts.map +1 -1
  7. package/common/decorators/front-mcp.decorator.d.ts.map +1 -1
  8. package/common/metadata/front-mcp.metadata.d.ts +24 -0
  9. package/common/metadata/front-mcp.metadata.d.ts.map +1 -1
  10. package/common/schemas/http-output.schema.d.ts +17 -0
  11. package/common/schemas/http-output.schema.d.ts.map +1 -1
  12. package/common/tokens/server.tokens.d.ts +3 -0
  13. package/common/tokens/server.tokens.d.ts.map +1 -1
  14. package/common/types/options/skills-http/interfaces.d.ts +15 -1
  15. package/common/types/options/skills-http/interfaces.d.ts.map +1 -1
  16. package/common/types/options/skills-http/schema.d.ts +4 -0
  17. package/common/types/options/skills-http/schema.d.ts.map +1 -1
  18. package/common/utils/path.utils.d.ts +15 -0
  19. package/common/utils/path.utils.d.ts.map +1 -1
  20. package/esm/index.mjs +1190 -295
  21. package/esm-loader/esm-cache.d.ts +10 -0
  22. package/esm-loader/esm-cache.d.ts.map +1 -1
  23. package/esm-loader/esm-module-loader.d.ts.map +1 -1
  24. package/flows/flow.instance.d.ts +14 -0
  25. package/flows/flow.instance.d.ts.map +1 -1
  26. package/flows/flow.registry.d.ts +9 -1
  27. package/flows/flow.registry.d.ts.map +1 -1
  28. package/front-mcp/front-mcp.d.ts +14 -0
  29. package/front-mcp/front-mcp.d.ts.map +1 -1
  30. package/front-mcp/front-mcp.providers.d.ts +4 -0
  31. package/front-mcp/front-mcp.providers.d.ts.map +1 -1
  32. package/index.d.ts +9 -5
  33. package/index.d.ts.map +1 -1
  34. package/index.js +1423 -522
  35. package/logger/instances/instance.file-logger.d.ts.map +1 -1
  36. package/package.json +29 -29
  37. package/scope/flows/http.request.flow.d.ts +17 -1
  38. package/scope/flows/http.request.flow.d.ts.map +1 -1
  39. package/scope/optional-dependency.util.d.ts +25 -0
  40. package/scope/optional-dependency.util.d.ts.map +1 -1
  41. package/scope/scope.instance.d.ts +9 -1
  42. package/scope/scope.instance.d.ts.map +1 -1
  43. package/server/server.instance.d.ts.map +1 -1
  44. package/server/server.validation.d.ts.map +1 -1
  45. package/skill/index.d.ts +1 -0
  46. package/skill/index.d.ts.map +1 -1
  47. package/skill/providers/memory-skill.provider.d.ts +61 -1
  48. package/skill/providers/memory-skill.provider.d.ts.map +1 -1
  49. package/skill/skill-index-cache.interface.d.ts +33 -0
  50. package/skill/skill-index-cache.interface.d.ts.map +1 -0
  51. package/skill/skill-instructions.helper.d.ts +13 -0
  52. package/skill/skill-instructions.helper.d.ts.map +1 -1
  53. package/skill/skill-storage.interface.d.ts +13 -0
  54. package/skill/skill-storage.interface.d.ts.map +1 -1
  55. package/skill/skill.registry.d.ts +27 -0
  56. package/skill/skill.registry.d.ts.map +1 -1
  57. package/transport/build-scoped-server-options.d.ts +35 -0
  58. package/transport/build-scoped-server-options.d.ts.map +1 -0
  59. package/transport/in-memory-server.d.ts.map +1 -1
  60. package/transport/index.d.ts +17 -0
  61. package/transport/index.d.ts.map +1 -1
  62. package/transport/web-fetch-handler.d.ts +106 -0
  63. package/transport/web-fetch-handler.d.ts.map +1 -0
  64. package/transport/web-response.renderer.d.ts +13 -0
  65. package/transport/web-response.renderer.d.ts.map +1 -0
  66. package/transport/web-standard-mcp.d.ts +63 -0
  67. package/transport/web-standard-mcp.d.ts.map +1 -0
package/esm/index.mjs CHANGED
@@ -1,3 +1,5 @@
1
+ import { createRequire as __frontmcpCreateRequire } from 'module';
2
+ const require = __frontmcpCreateRequire(import.meta.url || 'file:///');
1
3
  var __defProp = Object.defineProperty;
2
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -9,11 +11,20 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
9
11
  if (typeof require !== "undefined") return require.apply(this, arguments);
10
12
  throw Error('Dynamic require of "' + x + '" is not supported');
11
13
  });
12
- var __esm = (fn, res) => function __init() {
13
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
14
+ var __esm = (fn, res, err) => function __init() {
15
+ if (err) throw err[0];
16
+ try {
17
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
18
+ } catch (e) {
19
+ throw err = [e], e;
20
+ }
14
21
  };
15
22
  var __commonJS = (cb, mod) => function __require2() {
16
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
23
+ try {
24
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
25
+ } catch (e) {
26
+ throw mod = 0, e;
27
+ }
17
28
  };
18
29
  var __export = (target, all) => {
19
30
  for (var name41 in all)
@@ -665,7 +676,10 @@ var init_server_tokens = __esm({
665
676
  intent: tokenFactory.meta("intent"),
666
677
  auth: tokenFactory.meta("auth"),
667
678
  sessionId: tokenFactory.meta("sessionId"),
668
- reinitialize: tokenFactory.meta("reinitialize")
679
+ reinitialize: tokenFactory.meta("reinitialize"),
680
+ webRequest: tokenFactory.meta("webRequest"),
681
+ webCtx: tokenFactory.meta("webCtx"),
682
+ webTransport: tokenFactory.meta("webTransport")
669
683
  };
670
684
  }
671
685
  });
@@ -1372,7 +1386,7 @@ import {
1372
1386
  JSONRPCResponseSchema
1373
1387
  } from "@frontmcp/protocol";
1374
1388
  import { randomUUID } from "@frontmcp/utils";
1375
- var JSON_RPC, REDIRECTS, NO_BODY_STATUSES, zNumUnion, HttpStatus, HttpRedirectStatus, HttpEmptyStatus, HttpHeaders, HttpCookieSchema, HttpCookies, HttpMeta, statusAllowsBody, HttpRedirectSchema, HttpJsonSchema, HttpNextSchema, HttpConsumedSchema, HttpTextSchema, HttpHtmlSchema, HttpBinarySchema, HttpImageSchema, isHttpReadableLike, HttpStreamSchema, HttpSseSchema, HttpJsonRpcSchema, HttpProblemSchema, HttpEmptySchema, httpOutputSchema, httpRespond;
1389
+ var JSON_RPC, REDIRECTS, NO_BODY_STATUSES, zNumUnion, HttpStatus, HttpRedirectStatus, HttpEmptyStatus, HttpHeaders, HttpCookieSchema, HttpCookies, HttpMeta, statusAllowsBody, HttpRedirectSchema, HttpJsonSchema, HttpNextSchema, HttpConsumedSchema, HttpWebResponseSchema, HttpTextSchema, HttpHtmlSchema, HttpBinarySchema, HttpImageSchema, isHttpReadableLike, HttpStreamSchema, HttpSseSchema, HttpJsonRpcSchema, HttpProblemSchema, HttpEmptySchema, httpOutputSchema, httpRespond;
1376
1390
  var init_http_output_schema = __esm({
1377
1391
  "libs/sdk/src/common/schemas/http-output.schema.ts"() {
1378
1392
  "use strict";
@@ -1424,6 +1438,13 @@ var init_http_output_schema = __esm({
1424
1438
  kind: z2.literal("next")
1425
1439
  }).passthrough();
1426
1440
  HttpConsumedSchema = z2.object({ kind: z2.literal("consumed") });
1441
+ HttpWebResponseSchema = z2.object({
1442
+ kind: z2.literal("web-response"),
1443
+ response: z2.custom(
1444
+ (v) => typeof Response !== "undefined" && v instanceof Response,
1445
+ "must be a Web Response"
1446
+ )
1447
+ });
1427
1448
  HttpTextSchema = z2.object({
1428
1449
  kind: z2.literal("text"),
1429
1450
  status: HttpStatus.refine((s) => statusAllowsBody(s) && !REDIRECTS.includes(s), {
@@ -1516,7 +1537,8 @@ var init_http_output_schema = __esm({
1516
1537
  HttpProblemSchema,
1517
1538
  HttpEmptySchema,
1518
1539
  HttpNextSchema,
1519
- HttpConsumedSchema
1540
+ HttpConsumedSchema,
1541
+ HttpWebResponseSchema
1520
1542
  ]);
1521
1543
  httpRespond = {
1522
1544
  json: (body, extra = {}) => {
@@ -1616,6 +1638,9 @@ var init_http_output_schema = __esm({
1616
1638
  consumed() {
1617
1639
  return { kind: "consumed" };
1618
1640
  },
1641
+ webResponse(response) {
1642
+ return { kind: "web-response", response };
1643
+ },
1619
1644
  empty(status = 204, headers) {
1620
1645
  return { kind: "empty", status, headers };
1621
1646
  },
@@ -2172,6 +2197,18 @@ var init_sqlite = __esm({
2172
2197
  });
2173
2198
 
2174
2199
  // libs/sdk/src/common/types/options/transport/schema.ts
2200
+ var schema_exports = {};
2201
+ __export(schema_exports, {
2202
+ PROTOCOL_PRESETS: () => PROTOCOL_PRESETS,
2203
+ eventStoreConfigSchema: () => eventStoreConfigSchema,
2204
+ expandProtocolConfig: () => expandProtocolConfig,
2205
+ expandTransportConfig: () => expandTransportConfig,
2206
+ isDistributedMode: () => isDistributedMode,
2207
+ persistenceConfigSchema: () => persistenceConfigSchema,
2208
+ shouldCacheProviders: () => shouldCacheProviders,
2209
+ toLegacyProtocolFlags: () => toLegacyProtocolFlags,
2210
+ transportOptionsSchema: () => transportOptionsSchema
2211
+ });
2175
2212
  import { z as z12 } from "@frontmcp/lazy-zod";
2176
2213
  import { isServerless } from "@frontmcp/utils";
2177
2214
  function expandProtocolConfig(protocol) {
@@ -2491,7 +2528,8 @@ var init_schema10 = __esm({
2491
2528
  sep2640InInstructions: z15.boolean().optional().default(false),
2492
2529
  cache: skillsConfigCacheOptionsSchema.optional(),
2493
2530
  audit: skillsConfigAuditOptionsSchema.optional(),
2494
- injectInstructions: z15.enum(["off", "append", "prepend", "replace"]).optional().default("append")
2531
+ injectInstructions: z15.enum(["off", "append", "prepend", "replace"]).optional().default("append"),
2532
+ scoring: z15.enum(["cosine", "bm25"]).optional()
2495
2533
  });
2496
2534
  }
2497
2535
  });
@@ -4712,6 +4750,12 @@ var init_elicitation_error = __esm({
4712
4750
  this.toolInput = toolInput;
4713
4751
  this.ttl = ttl;
4714
4752
  }
4753
+ elicitId;
4754
+ elicitMessage;
4755
+ schema;
4756
+ toolName;
4757
+ toolInput;
4758
+ ttl;
4715
4759
  getPublicMessage() {
4716
4760
  return this.elicitMessage;
4717
4761
  }
@@ -6192,30 +6236,30 @@ var require_dist = __commonJS({
6192
6236
  sqliteStorageOptionsSchema: () => sqliteStorageOptionsSchema
6193
6237
  });
6194
6238
  module.exports = __toCommonJS2(index_exports);
6195
- var import_utils101 = __require("@frontmcp/utils");
6239
+ var import_utils103 = __require("@frontmcp/utils");
6196
6240
  var HKDF_SALT = new TextEncoder().encode("frontmcp-sqlite-storage-v1");
6197
6241
  var HKDF_INFO = new TextEncoder().encode("aes-256-gcm-value-encryption");
6198
6242
  var KEY_LENGTH = 32;
6199
6243
  function deriveEncryptionKey(secret) {
6200
6244
  const ikm = new TextEncoder().encode(secret);
6201
- return (0, import_utils101.hkdfSha256)(ikm, HKDF_SALT, HKDF_INFO, KEY_LENGTH);
6245
+ return (0, import_utils103.hkdfSha256)(ikm, HKDF_SALT, HKDF_INFO, KEY_LENGTH);
6202
6246
  }
6203
6247
  var SEPARATOR = ":";
6204
6248
  function encryptValue(key, plaintext) {
6205
- const iv = (0, import_utils101.randomBytes)(12);
6249
+ const iv = (0, import_utils103.randomBytes)(12);
6206
6250
  const plaintextBytes = new TextEncoder().encode(plaintext);
6207
- const { ciphertext, tag } = (0, import_utils101.encryptAesGcm)(key, plaintextBytes, iv);
6208
- return [(0, import_utils101.base64urlEncode)(iv), (0, import_utils101.base64urlEncode)(tag), (0, import_utils101.base64urlEncode)(ciphertext)].join(SEPARATOR);
6251
+ const { ciphertext, tag } = (0, import_utils103.encryptAesGcm)(key, plaintextBytes, iv);
6252
+ return [(0, import_utils103.base64urlEncode)(iv), (0, import_utils103.base64urlEncode)(tag), (0, import_utils103.base64urlEncode)(ciphertext)].join(SEPARATOR);
6209
6253
  }
6210
6254
  function decryptValue(key, encrypted) {
6211
6255
  const parts = encrypted.split(SEPARATOR);
6212
6256
  if (parts.length !== 3) {
6213
6257
  throw new Error("Invalid encrypted value format");
6214
6258
  }
6215
- const iv = (0, import_utils101.base64urlDecode)(parts[0]);
6216
- const tag = (0, import_utils101.base64urlDecode)(parts[1]);
6217
- const ciphertext = (0, import_utils101.base64urlDecode)(parts[2]);
6218
- const plaintext = (0, import_utils101.decryptAesGcm)(key, ciphertext, iv, tag);
6259
+ const iv = (0, import_utils103.base64urlDecode)(parts[0]);
6260
+ const tag = (0, import_utils103.base64urlDecode)(parts[1]);
6261
+ const ciphertext = (0, import_utils103.base64urlDecode)(parts[2]);
6262
+ const plaintext = (0, import_utils103.decryptAesGcm)(key, ciphertext, iv, tag);
6219
6263
  return new TextDecoder().decode(plaintext);
6220
6264
  }
6221
6265
  var import_utils210 = __require("@frontmcp/utils");
@@ -7336,6 +7380,8 @@ var init_task_notifier = __esm({
7336
7380
  this.notifications = notifications;
7337
7381
  this.logger = logger;
7338
7382
  }
7383
+ notifications;
7384
+ logger;
7339
7385
  sendStatus(record) {
7340
7386
  const params = {
7341
7387
  ...toWireShape(record)
@@ -7491,6 +7537,7 @@ var init_in_process_task_runner = __esm({
7491
7537
  constructor(deps) {
7492
7538
  this.deps = deps;
7493
7539
  }
7540
+ deps;
7494
7541
  kind = "in-process";
7495
7542
  async run(record, context) {
7496
7543
  await this.deps.store.update(record.taskId, record.sessionId, {
@@ -7545,6 +7592,7 @@ var init_cli_task_runner = __esm({
7545
7592
  constructor(deps) {
7546
7593
  this.deps = deps;
7547
7594
  }
7595
+ deps;
7548
7596
  kind = "cli";
7549
7597
  async run(record, _context) {
7550
7598
  const { exe, args } = this.resolveCommand();
@@ -7899,6 +7947,9 @@ var init_tasks_result_flow = __esm({
7899
7947
  this.taskId = taskId;
7900
7948
  this.name = "JsonRpcReplayError";
7901
7949
  }
7950
+ code;
7951
+ data;
7952
+ taskId;
7902
7953
  toJsonRpcError() {
7903
7954
  const out = {
7904
7955
  code: this.code,
@@ -8122,6 +8173,72 @@ var init_task = __esm({
8122
8173
  }
8123
8174
  });
8124
8175
 
8176
+ // libs/sdk/src/transport/build-scoped-server-options.ts
8177
+ var build_scoped_server_options_exports = {};
8178
+ __export(build_scoped_server_options_exports, {
8179
+ buildScopedServerOptions: () => buildScopedServerOptions
8180
+ });
8181
+ function buildScopedServerOptions(scope, instructions = "") {
8182
+ const hasRemoteApps = scope.apps?.getApps().some((app) => app.isRemote) ?? false;
8183
+ const hasPrompts = scope.prompts.hasAny() || hasRemoteApps;
8184
+ const hasResources = scope.resources.hasAny() || hasRemoteApps;
8185
+ const completionsCapability = hasPrompts || hasResources ? { completions: {} } : {};
8186
+ const remoteCapabilities = hasRemoteApps ? {
8187
+ tools: { listChanged: true },
8188
+ resources: { subscribe: true, listChanged: true },
8189
+ prompts: { listChanged: true }
8190
+ } : {};
8191
+ const skillsCapabilities = scope.skills?.getCapabilities() ?? {};
8192
+ const toolsCapabilities = scope.tools.getCapabilities();
8193
+ const resourcesCapabilities = scope.resources.getCapabilities();
8194
+ const promptsCapabilities = scope.prompts.getCapabilities();
8195
+ const agentsCapabilities = scope.agents.getCapabilities();
8196
+ const taskCapabilities = computeTaskCapabilities(scope);
8197
+ const fragments = [
8198
+ remoteCapabilities,
8199
+ toolsCapabilities,
8200
+ resourcesCapabilities,
8201
+ promptsCapabilities,
8202
+ agentsCapabilities,
8203
+ skillsCapabilities,
8204
+ completionsCapability,
8205
+ taskCapabilities
8206
+ ];
8207
+ const experimental = {};
8208
+ const extensions = {};
8209
+ for (const cap2 of fragments) {
8210
+ if (cap2["experimental"] && typeof cap2["experimental"] === "object") {
8211
+ Object.assign(experimental, cap2["experimental"]);
8212
+ }
8213
+ if (cap2["extensions"] && typeof cap2["extensions"] === "object") {
8214
+ Object.assign(extensions, cap2["extensions"]);
8215
+ }
8216
+ }
8217
+ const baseCapabilities = {
8218
+ ...remoteCapabilities,
8219
+ ...toolsCapabilities,
8220
+ ...resourcesCapabilities,
8221
+ ...promptsCapabilities,
8222
+ ...agentsCapabilities,
8223
+ ...completionsCapability,
8224
+ ...taskCapabilities,
8225
+ logging: {}
8226
+ };
8227
+ if (Object.keys(experimental).length > 0) baseCapabilities["experimental"] = experimental;
8228
+ if (Object.keys(extensions).length > 0) baseCapabilities["extensions"] = extensions;
8229
+ return {
8230
+ instructions,
8231
+ capabilities: baseCapabilities,
8232
+ serverInfo: scope.metadata.info
8233
+ };
8234
+ }
8235
+ var init_build_scoped_server_options = __esm({
8236
+ "libs/sdk/src/transport/build-scoped-server-options.ts"() {
8237
+ "use strict";
8238
+ init_task();
8239
+ }
8240
+ });
8241
+
8125
8242
  // libs/sdk/src/transport/mcp-handlers/mcp-error.utils.ts
8126
8243
  import { McpError as McpError2 } from "@frontmcp/protocol";
8127
8244
  function toSdkMcpError(err) {
@@ -8391,6 +8508,8 @@ var init_notification_service = __esm({
8391
8508
  this.options = options;
8392
8509
  this.logger = scope.logger.child("NotificationService");
8393
8510
  }
8511
+ scope;
8512
+ options;
8394
8513
  logger;
8395
8514
  servers = /* @__PURE__ */ new Map();
8396
8515
  unsubscribers = [];
@@ -10806,58 +10925,7 @@ async function createInMemoryServer(scope, options) {
10806
10925
  const sessionId = options?.sessionId ?? `in-memory:${randomUUID4()}`;
10807
10926
  const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
10808
10927
  let currentAuthInfo = options?.authInfo ?? {};
10809
- const hasRemoteApps = scope.apps?.getApps().some((app) => app.isRemote) ?? false;
10810
- const hasPrompts = scope.prompts.hasAny() || hasRemoteApps;
10811
- const hasResources = scope.resources.hasAny() || hasRemoteApps;
10812
- const completionsCapability = hasPrompts || hasResources ? { completions: {} } : {};
10813
- const remoteCapabilities = hasRemoteApps ? {
10814
- tools: { listChanged: true },
10815
- resources: { subscribe: true, listChanged: true },
10816
- prompts: { listChanged: true }
10817
- } : {};
10818
- const skillsCapabilities = scope.skills?.getCapabilities() ?? {};
10819
- const toolsCapabilities = scope.tools.getCapabilities();
10820
- const resourcesCapabilities = scope.resources.getCapabilities();
10821
- const promptsCapabilities = scope.prompts.getCapabilities();
10822
- const agentsCapabilities = scope.agents.getCapabilities();
10823
- const taskCapabilities = computeTaskCapabilities(scope);
10824
- const fragments = [
10825
- remoteCapabilities,
10826
- toolsCapabilities,
10827
- resourcesCapabilities,
10828
- promptsCapabilities,
10829
- agentsCapabilities,
10830
- skillsCapabilities,
10831
- completionsCapability,
10832
- taskCapabilities
10833
- ];
10834
- const experimental = {};
10835
- const extensions = {};
10836
- for (const cap2 of fragments) {
10837
- if (cap2["experimental"] && typeof cap2["experimental"] === "object") {
10838
- Object.assign(experimental, cap2["experimental"]);
10839
- }
10840
- if (cap2["extensions"] && typeof cap2["extensions"] === "object") {
10841
- Object.assign(extensions, cap2["extensions"]);
10842
- }
10843
- }
10844
- const baseCapabilities = {
10845
- ...remoteCapabilities,
10846
- ...toolsCapabilities,
10847
- ...resourcesCapabilities,
10848
- ...promptsCapabilities,
10849
- ...agentsCapabilities,
10850
- ...completionsCapability,
10851
- ...taskCapabilities,
10852
- logging: {}
10853
- };
10854
- if (Object.keys(experimental).length > 0) baseCapabilities["experimental"] = experimental;
10855
- if (Object.keys(extensions).length > 0) baseCapabilities["extensions"] = extensions;
10856
- const serverOptions = {
10857
- instructions: "",
10858
- capabilities: baseCapabilities,
10859
- serverInfo: scope.metadata.info
10860
- };
10928
+ const serverOptions = buildScopedServerOptions(scope);
10861
10929
  const mcpServer = new McpServer2(scope.metadata.info, serverOptions);
10862
10930
  const handlers = createMcpHandlers2({ scope, serverOptions });
10863
10931
  for (const handler of handlers) {
@@ -10890,7 +10958,7 @@ async function createInMemoryServer(scope, options) {
10890
10958
  var init_in_memory_server = __esm({
10891
10959
  "libs/sdk/src/transport/in-memory-server.ts"() {
10892
10960
  "use strict";
10893
- init_task();
10961
+ init_build_scoped_server_options();
10894
10962
  }
10895
10963
  });
10896
10964
 
@@ -10904,29 +10972,29 @@ import {
10904
10972
  } from "@frontmcp/protocol";
10905
10973
  import { fileExists as fileExists2, pathResolve, randomUUID as randomUUID5 } from "@frontmcp/utils";
10906
10974
  function findFileFromRoot(root, relativePath) {
10907
- const fs2 = __require("fs");
10975
+ const fs = __require("fs");
10908
10976
  const path3 = __require("path");
10909
10977
  const cleanRelative = relativePath.replace(/^\.\//, "");
10910
10978
  const searchDirs = ["src", "."];
10911
10979
  for (const srcDir of searchDirs) {
10912
10980
  const srcRoot = path3.join(root, srcDir);
10913
- if (!fs2.existsSync(srcRoot)) continue;
10914
- const found = walkForFile(srcRoot, cleanRelative, fs2, path3);
10981
+ if (!fs.existsSync(srcRoot)) continue;
10982
+ const found = walkForFile(srcRoot, cleanRelative, fs, path3);
10915
10983
  if (found) return found;
10916
10984
  }
10917
10985
  return void 0;
10918
10986
  }
10919
- function walkForFile(dir, targetRelative, fs2, path3, maxDepth = 10) {
10987
+ function walkForFile(dir, targetRelative, fs, path3, maxDepth = 10) {
10920
10988
  const candidate = path3.join(dir, targetRelative);
10921
- if (fs2.existsSync(candidate)) {
10989
+ if (fs.existsSync(candidate)) {
10922
10990
  return { absolute: candidate, baseDir: dir };
10923
10991
  }
10924
10992
  if (maxDepth <= 0) return void 0;
10925
10993
  try {
10926
- const entries = fs2.readdirSync(dir, { withFileTypes: true });
10994
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
10927
10995
  for (const entry of entries) {
10928
10996
  if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules" && entry.name !== "dist") {
10929
- const result = walkForFile(path3.join(dir, entry.name), targetRelative, fs2, path3, maxDepth - 1);
10997
+ const result = walkForFile(path3.join(dir, entry.name), targetRelative, fs, path3, maxDepth - 1);
10930
10998
  if (result) return result;
10931
10999
  }
10932
11000
  }
@@ -12106,13 +12174,15 @@ var init_health2 = __esm({
12106
12174
  });
12107
12175
 
12108
12176
  // libs/sdk/src/logger/instances/instance.file-logger.ts
12109
- import * as fs from "fs";
12110
12177
  import * as os from "os";
12111
12178
  import * as path2 from "path";
12179
+ function getFs() {
12180
+ return _fs ??= __require("fs");
12181
+ }
12112
12182
  function stripAnsi(str) {
12113
12183
  return str.split(ESC).map((s) => s.replace(/\[[0-9;]*m/, "")).join("");
12114
12184
  }
12115
- var LOG_LEVEL_LABELS, ESC, DEFAULT_LOGS_MAX, FileLogTransportInstance;
12185
+ var _fs, LOG_LEVEL_LABELS, ESC, DEFAULT_LOGS_MAX, FileLogTransportInstance;
12116
12186
  var init_instance_file_logger = __esm({
12117
12187
  "libs/sdk/src/logger/instances/instance.file-logger.ts"() {
12118
12188
  "use strict";
@@ -12143,10 +12213,10 @@ var init_instance_file_logger = __esm({
12143
12213
  return;
12144
12214
  }
12145
12215
  try {
12146
- fs.mkdirSync(this.logDir, { recursive: true });
12216
+ getFs().mkdirSync(this.logDir, { recursive: true });
12147
12217
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "_");
12148
12218
  const filePath = path2.join(this.logDir, `${this.appName}-${ts}.log`);
12149
- this.fd = fs.openSync(filePath, "a");
12219
+ this.fd = getFs().openSync(filePath, "a");
12150
12220
  this.rotate(isNaN(logsMax) ? DEFAULT_LOGS_MAX : logsMax);
12151
12221
  } catch {
12152
12222
  this.fd = void 0;
@@ -12156,7 +12226,7 @@ var init_instance_file_logger = __esm({
12156
12226
  close() {
12157
12227
  if (this.fd !== void 0) {
12158
12228
  try {
12159
- fs.closeSync(this.fd);
12229
+ getFs().closeSync(this.fd);
12160
12230
  } catch {
12161
12231
  }
12162
12232
  this.fd = void 0;
@@ -12171,7 +12241,7 @@ var init_instance_file_logger = __esm({
12171
12241
  const line = `[${ts}] ${level}${prefix} ${message}
12172
12242
  `;
12173
12243
  try {
12174
- fs.writeSync(this.fd, line);
12244
+ getFs().writeSync(this.fd, line);
12175
12245
  } catch {
12176
12246
  }
12177
12247
  }
@@ -12179,12 +12249,12 @@ var init_instance_file_logger = __esm({
12179
12249
  rotate(maxFiles) {
12180
12250
  try {
12181
12251
  const prefix = `${this.appName}-`;
12182
- const files = fs.readdirSync(this.logDir).filter((f) => f.startsWith(prefix) && f.endsWith(".log")).sort();
12252
+ const files = getFs().readdirSync(this.logDir).filter((f) => f.startsWith(prefix) && f.endsWith(".log")).sort();
12183
12253
  const excess = files.length - maxFiles;
12184
12254
  if (excess <= 0) return;
12185
12255
  for (let i = 0; i < excess; i++) {
12186
12256
  try {
12187
- fs.unlinkSync(path2.join(this.logDir, files[i]));
12257
+ getFs().unlinkSync(path2.join(this.logDir, files[i]));
12188
12258
  } catch {
12189
12259
  }
12190
12260
  }
@@ -12342,6 +12412,8 @@ var init_instance_logger = __esm({
12342
12412
  this.transports = transports;
12343
12413
  this.consoleTransport = consoleTransport;
12344
12414
  }
12415
+ config;
12416
+ getTransports;
12345
12417
  level;
12346
12418
  prefix;
12347
12419
  transports;
@@ -15234,6 +15306,7 @@ var init_tool_instance = __esm({
15234
15306
  super(args);
15235
15307
  this.record = record;
15236
15308
  }
15309
+ record;
15237
15310
  execute(input) {
15238
15311
  return this.record.provide(input, this);
15239
15312
  }
@@ -15340,6 +15413,10 @@ var init_base_adapter = __esm({
15340
15413
  this.raw = raw;
15341
15414
  this.name = "LlmAdapterError";
15342
15415
  }
15416
+ provider;
15417
+ code;
15418
+ statusCode;
15419
+ raw;
15343
15420
  };
15344
15421
  }
15345
15422
  });
@@ -16290,6 +16367,7 @@ var init_providers = __esm({
16290
16367
  constructor(options) {
16291
16368
  this.options = options;
16292
16369
  }
16370
+ options;
16293
16371
  adapter = null;
16294
16372
  getAdapter() {
16295
16373
  if (this.adapter) {
@@ -16573,6 +16651,8 @@ var init_flow_context_providers = __esm({
16573
16651
  this.baseProviders = baseProviders;
16574
16652
  this.contextDeps = contextDeps;
16575
16653
  }
16654
+ baseProviders;
16655
+ contextDeps;
16576
16656
  get(token) {
16577
16657
  if (this.contextDeps.has(token)) {
16578
16658
  return this.contextDeps.get(token);
@@ -17323,6 +17403,7 @@ var init_prompt_instance = __esm({
17323
17403
  super(args);
17324
17404
  this.record = record;
17325
17405
  }
17406
+ record;
17326
17407
  execute(args) {
17327
17408
  return this.record.provide(args, this);
17328
17409
  }
@@ -19490,6 +19571,7 @@ var init_resource_instance = __esm({
19490
19571
  super(args);
19491
19572
  this.record = record;
19492
19573
  }
19574
+ record;
19493
19575
  execute(uri, params) {
19494
19576
  return this.record.provide(uri, params, this);
19495
19577
  }
@@ -23131,6 +23213,8 @@ var init_flow_interface = __esm({
23131
23213
  this.type = type;
23132
23214
  this.output = output;
23133
23215
  }
23216
+ type;
23217
+ output;
23134
23218
  static respond(output) {
23135
23219
  throw new _FlowControl("respond", output);
23136
23220
  }
@@ -23159,6 +23243,11 @@ var init_flow_interface = __esm({
23159
23243
  this.input = metadata.inputSchema?.parse?.(rawInput);
23160
23244
  this.scopeLogger = scope.logger;
23161
23245
  }
23246
+ metadata;
23247
+ rawInput;
23248
+ scope;
23249
+ appendContextHooks;
23250
+ deps;
23162
23251
  input;
23163
23252
  state = FlowState.create({});
23164
23253
  scopeLogger;
@@ -23812,6 +23901,18 @@ async function writeHttpResponse(res, value) {
23812
23901
  res.status(out.status).end();
23813
23902
  return;
23814
23903
  }
23904
+ case "web-response": {
23905
+ const r = out.response;
23906
+ r.headers.forEach((v, k) => res.setHeader(k, v));
23907
+ res.status(r.status);
23908
+ if (r.body) {
23909
+ for await (const chunk of r.body) {
23910
+ res.write(chunk);
23911
+ }
23912
+ }
23913
+ res.end();
23914
+ return;
23915
+ }
23815
23916
  }
23816
23917
  }
23817
23918
  var init_server_validation = __esm({
@@ -24028,6 +24129,34 @@ var init_flow_instance = __esm({
24028
24129
  const results = await Promise.all(canActivate.map((m) => m(request, this.scope)));
24029
24130
  return results.every((r) => r);
24030
24131
  }
24132
+ /**
24133
+ * Express-equivalent HTTP match for runtimes that have NO middleware server
24134
+ * (the Cloudflare Worker / web-fetch handler, where `registerMiddleware` is a
24135
+ * no-op so flows never mount as routes). It mirrors how Express dispatches:
24136
+ * method + `middleware.path` (mounted as a prefix) + `canActivate`.
24137
+ *
24138
+ * Only flows with a SPECIFIC matcher qualify — a `middleware.path` (e.g.
24139
+ * `/oauth/token`) and/or a `canActivate` (static class method or
24140
+ * `middleware.canActivate`, e.g. the well-known PRM path set). A bare
24141
+ * `{ method }` middleware is too broad to safely claim an arbitrary request,
24142
+ * so it returns false. Used by the web-fetch handler to serve auth/well-known/
24143
+ * oauth endpoints through the real flow pipeline.
24144
+ */
24145
+ async matchHttp(request) {
24146
+ const mw = this.metadata.middleware;
24147
+ if (!mw) return false;
24148
+ const path3 = typeof mw.path === "string" ? mw.path : "";
24149
+ const hasStaticCanActivate = typeof this.FlowClass.canActivate === "function";
24150
+ const hasMwCanActivate = (mw.canActivate?.length ?? 0) > 0;
24151
+ if (!path3 && !hasStaticCanActivate && !hasMwCanActivate) return false;
24152
+ if (this.method && request.method !== this.method) return false;
24153
+ if (path3) {
24154
+ const reqPath = request.path;
24155
+ const prefix = path3.endsWith("/") ? path3 : `${path3}/`;
24156
+ if (reqPath !== path3 && !reqPath.startsWith(prefix)) return false;
24157
+ }
24158
+ return this.canActivate(request);
24159
+ }
24031
24160
  /**
24032
24161
  * Get FrontMcpContextStorage from providers (with fallback).
24033
24162
  * Returns undefined if not available (backward compatibility).
@@ -24429,6 +24558,21 @@ var init_flow_registry = __esm({
24429
24558
  )
24430
24559
  );
24431
24560
  }
24561
+ /**
24562
+ * Find the name of the first registered flow whose HTTP matcher claims this
24563
+ * request (method + `middleware.path` prefix + `canActivate`). For runtimes
24564
+ * with no middleware server (the web-fetch/Worker handler), this replaces
24565
+ * Express's route dispatch so auth/well-known/oauth flows still run. Returns
24566
+ * `undefined` when no flow matches.
24567
+ */
24568
+ async findHttpFlowName(request, exclude = /* @__PURE__ */ new Set()) {
24569
+ for (const instance of this.instances.values()) {
24570
+ const name41 = instance.name;
24571
+ if (exclude.has(name41)) continue;
24572
+ if (await instance.matchHttp(request)) return name41;
24573
+ }
24574
+ return void 0;
24575
+ }
24432
24576
  /**
24433
24577
  * Get FrontMcpContextStorage from providers (with fallback).
24434
24578
  * Returns undefined if not available (backward compatibility).
@@ -25017,12 +25161,51 @@ var init_skill_validation_error = __esm({
25017
25161
  }
25018
25162
  });
25019
25163
 
25164
+ // libs/sdk/src/scope/optional-dependency.util.ts
25165
+ function probeOptionalDependency(moduleName, loadError, resolve) {
25166
+ let resolvedPath;
25167
+ try {
25168
+ resolvedPath = resolve(moduleName);
25169
+ } catch {
25170
+ resolvedPath = void 0;
25171
+ }
25172
+ const error = loadError instanceof Error ? loadError.message : String(loadError);
25173
+ return resolvedPath ? { status: "load-failed", resolvedPath, error } : { status: "not-installed", error };
25174
+ }
25175
+ async function importOptionalPeer(moduleName, importer, resolve, feature) {
25176
+ try {
25177
+ return await importer();
25178
+ } catch (cause) {
25179
+ const probe = probeOptionalDependency(moduleName, cause, resolve);
25180
+ if (probe.status === "not-installed") {
25181
+ throw new Error(
25182
+ `@frontmcp/sdk ${feature} needs the optional peer dependency '${moduleName}'. Install it in your project (e.g. \`npm i ${moduleName}\`).`,
25183
+ { cause }
25184
+ );
25185
+ }
25186
+ throw new Error(
25187
+ `@frontmcp/sdk ${feature} found '${moduleName}' at ${probe.resolvedPath} but it failed to load \u2014 reinstalling will not help. This is usually an export-condition, transpile, or transitive-peer mismatch. Original error: ${probe.error}`,
25188
+ { cause }
25189
+ );
25190
+ }
25191
+ }
25192
+ var init_optional_dependency_util = __esm({
25193
+ "libs/sdk/src/scope/optional-dependency.util.ts"() {
25194
+ "use strict";
25195
+ }
25196
+ });
25197
+
25020
25198
  // libs/sdk/src/skill/providers/memory-skill.provider.ts
25021
- import { TFIDFVectoria } from "vectoriadb";
25199
+ import { sha256Hex as sha256Hex3 } from "@frontmcp/utils";
25200
+ function isSnapshotCapable(db) {
25201
+ const d = db;
25202
+ return typeof d.toSnapshot === "function" && typeof d.loadSnapshot === "function";
25203
+ }
25022
25204
  var STOP_WORDS, MemorySkillProvider;
25023
25205
  var init_memory_skill_provider = __esm({
25024
25206
  "libs/sdk/src/skill/providers/memory-skill.provider.ts"() {
25025
25207
  "use strict";
25208
+ init_optional_dependency_util();
25026
25209
  STOP_WORDS = /* @__PURE__ */ new Set([
25027
25210
  // Articles & Determiners
25028
25211
  "the",
@@ -25098,19 +25281,118 @@ var init_memory_skill_provider = __esm({
25098
25281
  MemorySkillProvider = class {
25099
25282
  type = "memory";
25100
25283
  vectorDB;
25284
+ vectorDBReady;
25101
25285
  skills = /* @__PURE__ */ new Map();
25102
25286
  defaultTopK;
25103
25287
  defaultMinScore;
25104
25288
  toolValidator;
25105
25289
  initialized = false;
25290
+ /** Ranking mode passed to the vector DB (cosine | bm25). */
25291
+ scoring;
25292
+ /** Optional snapshot cache for fast cold-start (e.g. KV-backed on the edge). */
25293
+ indexCache;
25294
+ /**
25295
+ * Whether the vector index reflects the current document set. Adds/removes
25296
+ * mark it stale; the FIRST search after a mutation builds (or restores) it
25297
+ * exactly once. This defers the expensive IDF/embedding pass off the
25298
+ * registration hot-path — registering N skills no longer triggers N reindexes.
25299
+ */
25300
+ indexReady = false;
25106
25301
  constructor(options = {}) {
25107
25302
  this.defaultTopK = options.defaultTopK ?? 10;
25108
25303
  this.defaultMinScore = options.defaultMinScore ?? 0.1;
25109
25304
  this.toolValidator = options.toolValidator;
25110
- this.vectorDB = new TFIDFVectoria({
25305
+ this.scoring = options.scoring ?? "cosine";
25306
+ this.indexCache = options.indexCache;
25307
+ this.vectorDBReady = this.initVectorDB();
25308
+ this.vectorDBReady.catch(() => void 0);
25309
+ }
25310
+ async initVectorDB() {
25311
+ const mod = await importOptionalPeer(
25312
+ "vectoriadb",
25313
+ () => import("vectoriadb"),
25314
+ __require.resolve,
25315
+ "skill storage"
25316
+ );
25317
+ const dbConfig = {
25111
25318
  defaultTopK: this.defaultTopK,
25112
25319
  defaultSimilarityThreshold: this.defaultMinScore
25113
- });
25320
+ };
25321
+ if (this.scoring !== "cosine") dbConfig.scoring = this.scoring;
25322
+ this.vectorDB = new mod.TFIDFVectoria(dbConfig);
25323
+ }
25324
+ /**
25325
+ * Attach (or replace) the snapshot cache after construction — useful when the
25326
+ * cache binding only exists at request time (e.g. a Cloudflare KV namespace on
25327
+ * `env`). Marks the index stale so the next search consults the new cache.
25328
+ */
25329
+ setIndexCache(cache2) {
25330
+ this.indexCache = cache2;
25331
+ this.indexReady = false;
25332
+ }
25333
+ /**
25334
+ * Ensure the vector index reflects the current document set, building it AT
25335
+ * MOST once per mutation batch. When a snapshot cache is configured and the
25336
+ * vector DB supports snapshots, a content-hash hit restores the index without
25337
+ * recomputing IDF/embeddings (the cold-start fast path); a miss rebuilds and
25338
+ * persists the snapshot for next time. Cache failures degrade to a local
25339
+ * rebuild — they never block search.
25340
+ */
25341
+ async ensureIndexed() {
25342
+ if (this.indexReady) return;
25343
+ const db = await this.db();
25344
+ if (this.indexCache && isSnapshotCapable(db)) {
25345
+ const key = await this.computeIndexKey();
25346
+ try {
25347
+ const snapshot = await this.indexCache.get(key);
25348
+ if (snapshot !== void 0 && snapshot !== null) {
25349
+ db.loadSnapshot(snapshot);
25350
+ this.indexReady = true;
25351
+ return;
25352
+ }
25353
+ } catch {
25354
+ }
25355
+ this.reindexNow(db);
25356
+ this.indexReady = true;
25357
+ try {
25358
+ await this.indexCache.set(key, db.toSnapshot());
25359
+ } catch {
25360
+ }
25361
+ return;
25362
+ }
25363
+ this.reindexNow(db);
25364
+ this.indexReady = true;
25365
+ }
25366
+ /**
25367
+ * Eagerly build (or restore from cache) the search index now, rather than on
25368
+ * the first search. A host calls this after registration completes to move the
25369
+ * one-time index build off the first request's critical path (e.g. the edge
25370
+ * does this right after attaching the KV cache).
25371
+ */
25372
+ async warm() {
25373
+ await this.ensureIndexed();
25374
+ }
25375
+ /** Force the vector DB to (re)compute its index now. */
25376
+ reindexNow(db) {
25377
+ db.reindex();
25378
+ }
25379
+ /**
25380
+ * Stable content hash of the indexed skill set + scoring mode. Changing any
25381
+ * skill's searchable text, the set of skills, or the scoring mode changes the
25382
+ * key, so a stale snapshot is never restored.
25383
+ */
25384
+ async computeIndexKey() {
25385
+ const parts = Array.from(this.skills.values()).map((s) => `${s.id}\0${this.buildSearchableText(s)}`).sort();
25386
+ const canonical = `frontmcp-skill-index:v1|${this.scoring}|${this.skills.size}|${parts.join("")}`;
25387
+ return sha256Hex3(canonical);
25388
+ }
25389
+ /** Await the lazy vectoriadb load (throws the clear install hint if absent). */
25390
+ async db() {
25391
+ await this.vectorDBReady;
25392
+ if (!this.vectorDB) {
25393
+ throw new Error("Vector DB not initialized; await this.vectorDBReady before use.");
25394
+ }
25395
+ return this.vectorDB;
25114
25396
  }
25115
25397
  /**
25116
25398
  * Set the tool validator after construction.
@@ -25120,9 +25402,13 @@ var init_memory_skill_provider = __esm({
25120
25402
  this.toolValidator = validator;
25121
25403
  }
25122
25404
  async initialize() {
25405
+ await this.vectorDBReady;
25123
25406
  this.initialized = true;
25124
25407
  }
25125
25408
  async search(query, options = {}) {
25409
+ if (query.trim().length === 0) {
25410
+ return [];
25411
+ }
25126
25412
  const {
25127
25413
  topK = this.defaultTopK,
25128
25414
  tags,
@@ -25153,10 +25439,16 @@ var init_memory_skill_provider = __esm({
25153
25439
  }
25154
25440
  return true;
25155
25441
  };
25156
- let results = await this.vectorDB.search(query, {
25442
+ const db = await this.db();
25443
+ await this.ensureIndexed();
25444
+ let results = await db.search(query, {
25157
25445
  topK,
25158
25446
  threshold: minScore,
25159
- filter
25447
+ filter,
25448
+ // `negativeQuery` (anti-query demotion) is honored by newer vectoriadb
25449
+ // versions; older ones ignore the extra field.
25450
+ ...options.negativeQuery !== void 0 ? { negativeQuery: options.negativeQuery } : {},
25451
+ ...options.negativeWeight !== void 0 ? { negativeWeight: options.negativeWeight } : {}
25160
25452
  });
25161
25453
  if (results.length === 0 && query.trim().length > 0 && this.skills.size > 0) {
25162
25454
  results = this.fallbackTextSearch(query, topK, filter);
@@ -25264,29 +25556,35 @@ var init_memory_skill_provider = __esm({
25264
25556
  }
25265
25557
  async add(skill) {
25266
25558
  this.skills.set(skill.id, skill);
25267
- this.indexSkill(skill);
25559
+ await this.indexSkill(skill);
25268
25560
  }
25269
25561
  async update(skillId, skill) {
25270
25562
  const normalizedSkill = skill.id !== skillId ? { ...skill, id: skillId } : skill;
25271
- if (this.vectorDB.hasDocument(skillId)) {
25272
- this.vectorDB.removeDocument(skillId);
25563
+ const db = await this.db();
25564
+ if (db.hasDocument(skillId)) {
25565
+ db.removeDocument(skillId);
25273
25566
  }
25274
25567
  this.skills.set(skillId, normalizedSkill);
25275
- this.indexSkill(normalizedSkill);
25568
+ await this.indexSkill(normalizedSkill);
25276
25569
  }
25277
25570
  async remove(skillId) {
25278
25571
  this.skills.delete(skillId);
25279
- if (this.vectorDB.hasDocument(skillId)) {
25280
- this.vectorDB.removeDocument(skillId);
25572
+ const db = await this.db();
25573
+ if (db.hasDocument(skillId)) {
25574
+ db.removeDocument(skillId);
25281
25575
  }
25576
+ this.indexReady = false;
25282
25577
  }
25283
25578
  async clear() {
25284
25579
  this.skills.clear();
25285
- this.vectorDB.clear();
25580
+ const db = await this.db().catch(() => void 0);
25581
+ db?.clear();
25582
+ this.indexReady = false;
25286
25583
  }
25287
25584
  async dispose() {
25288
25585
  this.skills.clear();
25289
- this.vectorDB.clear();
25586
+ const db = await this.db().catch(() => void 0);
25587
+ db?.clear();
25290
25588
  this.initialized = false;
25291
25589
  }
25292
25590
  /**
@@ -25305,13 +25603,14 @@ var init_memory_skill_provider = __esm({
25305
25603
  }
25306
25604
  };
25307
25605
  });
25308
- this.vectorDB.addDocuments(documents);
25309
- this.vectorDB.reindex();
25606
+ const db = await this.db();
25607
+ db.addDocuments(documents);
25608
+ this.indexReady = false;
25310
25609
  }
25311
25610
  /**
25312
25611
  * Index a single skill in the vector database.
25313
25612
  */
25314
- indexSkill(skill) {
25613
+ async indexSkill(skill) {
25315
25614
  const document = {
25316
25615
  id: skill.id,
25317
25616
  text: this.buildSearchableText(skill),
@@ -25321,8 +25620,9 @@ var init_memory_skill_provider = __esm({
25321
25620
  skill
25322
25621
  }
25323
25622
  };
25324
- this.vectorDB.addDocuments([document]);
25325
- this.vectorDB.reindex();
25623
+ const db = await this.db();
25624
+ db.addDocuments([document]);
25625
+ this.indexReady = false;
25326
25626
  }
25327
25627
  /**
25328
25628
  * Build searchable text for TF-IDF indexing.
@@ -26059,7 +26359,9 @@ var init_skill_registry = __esm({
26059
26359
  this.options = options ?? {};
26060
26360
  this.storageProvider = new MemorySkillProvider({
26061
26361
  defaultTopK: 10,
26062
- defaultMinScore: 0.1
26362
+ defaultMinScore: 0.1,
26363
+ ...this.options.scoring ? { scoring: this.options.scoring } : {},
26364
+ ...this.options.indexCache ? { indexCache: this.options.indexCache } : {}
26063
26365
  });
26064
26366
  this.buildGraph();
26065
26367
  this.ready = this.initialize();
@@ -26269,6 +26571,31 @@ var init_skill_registry = __esm({
26269
26571
  * provider update lagged or failed) would mask the newer dynamic content.
26270
26572
  * Provider-only rows pass through unchanged; overlay-only rows are appended.
26271
26573
  */
26574
+ /**
26575
+ * Attach (or replace) the snapshot cache used to persist/restore the search
26576
+ * index — for runtimes where the cache binding only exists at request time
26577
+ * (e.g. a Cloudflare KV namespace on `env`). No-op if the storage provider
26578
+ * doesn't support index caching. Pair with {@link warmIndex} to build/restore
26579
+ * the index off the first request's critical path.
26580
+ */
26581
+ setIndexCache(cache2) {
26582
+ const provider = this.storageProvider;
26583
+ if (typeof provider.setIndexCache === "function") {
26584
+ provider.setIndexCache(cache2);
26585
+ }
26586
+ }
26587
+ /**
26588
+ * Eagerly build (or restore from the cache) the search index now. Called by a
26589
+ * host after registration so the one-time index build (or a KV restore) is
26590
+ * paid here rather than inside the first `search`. No-op if unsupported.
26591
+ */
26592
+ async warmIndex() {
26593
+ await this.ready;
26594
+ const provider = this.storageProvider;
26595
+ if (typeof provider.warm === "function") {
26596
+ await provider.warm();
26597
+ }
26598
+ }
26272
26599
  async search(query, options) {
26273
26600
  const baseResults = await this.storageProvider.search(query, options);
26274
26601
  if (this.dynamicContents.size === 0) return baseResults;
@@ -27318,6 +27645,7 @@ var init_agent_scope = __esm({
27318
27645
  };
27319
27646
  this.ready = this.initialize();
27320
27647
  }
27648
+ metadata;
27321
27649
  id;
27322
27650
  entryPath;
27323
27651
  routeBase;
@@ -27487,6 +27815,7 @@ var init_agent_scope = __esm({
27487
27815
  this.fullPath = agentScope.fullPath;
27488
27816
  this.logger = agentScope.logger;
27489
27817
  }
27818
+ agentScope;
27490
27819
  id;
27491
27820
  entryPath;
27492
27821
  routeBase;
@@ -28218,6 +28547,7 @@ var init_agent_instance = __esm({
28218
28547
  super(args);
28219
28548
  this.record = record;
28220
28549
  }
28550
+ record;
28221
28551
  async execute(input) {
28222
28552
  return this.record.provide(input, this);
28223
28553
  }
@@ -31367,7 +31697,7 @@ var init_semver_utils = __esm({
31367
31697
  });
31368
31698
 
31369
31699
  // libs/sdk/src/esm-loader/esm-cache.ts
31370
- import { sha256Hex as sha256Hex3, isValidMcpUri as isValidMcpUri6 } from "@frontmcp/utils";
31700
+ import { sha256Hex as sha256Hex4, isValidMcpUri as isValidMcpUri6 } from "@frontmcp/utils";
31371
31701
  function isBrowserEnv() {
31372
31702
  return typeof window !== "undefined" || typeof globalThis !== "undefined" && typeof globalThis.document !== "undefined";
31373
31703
  }
@@ -31404,8 +31734,8 @@ function getDefaultCacheDir() {
31404
31734
  const path3 = __require("node:path");
31405
31735
  try {
31406
31736
  const nodeModulesDir = path3.join(process.cwd(), "node_modules");
31407
- const fs2 = __require("node:fs");
31408
- if (fs2.existsSync(nodeModulesDir)) {
31737
+ const fs = __require("node:fs");
31738
+ if (fs.existsSync(nodeModulesDir)) {
31409
31739
  return path3.join(nodeModulesDir, ".cache", "frontmcp-esm");
31410
31740
  }
31411
31741
  } catch {
@@ -31420,19 +31750,30 @@ function getDefaultCacheDir() {
31420
31750
  return "";
31421
31751
  }
31422
31752
  }
31423
- var DEFAULT_CACHE_DIR, DEFAULT_MAX_AGE_MS, EsmCacheManager;
31753
+ var DEFAULT_CACHE_DIR, DEFAULT_MAX_AGE_MS, DEFAULT_MAX_ENTRIES, EsmCacheManager;
31424
31754
  var init_esm_cache = __esm({
31425
31755
  "libs/sdk/src/esm-loader/esm-cache.ts"() {
31426
31756
  "use strict";
31427
31757
  DEFAULT_CACHE_DIR = getDefaultCacheDir();
31428
31758
  DEFAULT_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
31759
+ DEFAULT_MAX_ENTRIES = 100;
31429
31760
  EsmCacheManager = class {
31430
31761
  cacheDir;
31431
31762
  maxAgeMs;
31763
+ maxEntries;
31432
31764
  memoryStore = /* @__PURE__ */ new Map();
31433
31765
  constructor(options) {
31434
31766
  this.cacheDir = options?.cacheDir ?? DEFAULT_CACHE_DIR;
31435
31767
  this.maxAgeMs = options?.maxAgeMs ?? DEFAULT_MAX_AGE_MS;
31768
+ this.maxEntries = options?.maxEntries ?? DEFAULT_MAX_ENTRIES;
31769
+ }
31770
+ /** Evict oldest in-memory entries (FIFO via Map insertion order) past the cap. */
31771
+ evictIfNeeded() {
31772
+ while (this.memoryStore.size > this.maxEntries) {
31773
+ const oldest = this.memoryStore.keys().next().value;
31774
+ if (oldest === void 0) break;
31775
+ this.memoryStore.delete(oldest);
31776
+ }
31436
31777
  }
31437
31778
  /**
31438
31779
  * Get a cached ESM bundle entry if it exists and is not expired.
@@ -31466,6 +31807,7 @@ var init_esm_cache = __esm({
31466
31807
  return void 0;
31467
31808
  }
31468
31809
  this.memoryStore.set(memKey, meta);
31810
+ this.evictIfNeeded();
31469
31811
  return meta;
31470
31812
  } catch {
31471
31813
  return void 0;
@@ -31512,6 +31854,7 @@ var init_esm_cache = __esm({
31512
31854
  bundleContent
31513
31855
  };
31514
31856
  this.memoryStore.set(memKey, entry);
31857
+ this.evictIfNeeded();
31515
31858
  return entry;
31516
31859
  }
31517
31860
  /**
@@ -31605,7 +31948,7 @@ var init_esm_cache = __esm({
31605
31948
  */
31606
31949
  getEntryDir(packageName, version) {
31607
31950
  const path3 = __require("node:path");
31608
- const hash = sha256Hex3(`${packageName}@${version}`);
31951
+ const hash = sha256Hex4(`${packageName}@${version}`);
31609
31952
  return path3.join(this.cacheDir, hash);
31610
31953
  }
31611
31954
  };
@@ -31957,6 +32300,13 @@ var init_version_resolver = __esm({
31957
32300
  });
31958
32301
 
31959
32302
  // libs/sdk/src/esm-loader/esm-module-loader.ts
32303
+ function importComputed(specifier) {
32304
+ return import(
32305
+ /* webpackIgnore: true */
32306
+ /* @vite-ignore */
32307
+ specifier
32308
+ );
32309
+ }
31960
32310
  var EsmModuleLoader;
31961
32311
  var init_esm_module_loader = __esm({
31962
32312
  "libs/sdk/src/esm-loader/esm-module-loader.ts"() {
@@ -32088,9 +32438,7 @@ var init_esm_module_loader = __esm({
32088
32438
  */
32089
32439
  async importFromPath(filePath) {
32090
32440
  const { pathToFileURL } = await import("node:url");
32091
- const fileUrl = pathToFileURL(filePath).href;
32092
- const bustUrl = `${fileUrl}?t=${Date.now()}`;
32093
- return import(bustUrl);
32441
+ return importComputed(pathToFileURL(filePath).href);
32094
32442
  }
32095
32443
  /**
32096
32444
  * Import a bundle from its source text.
@@ -32119,27 +32467,22 @@ var init_esm_module_loader = __esm({
32119
32467
  const blob = new Blob([bundleContent], { type: "text/javascript" });
32120
32468
  const url = URL.createObjectURL(blob);
32121
32469
  try {
32122
- return await import(
32123
- /* webpackIgnore: true */
32124
- url
32125
- );
32470
+ return await importComputed(url);
32126
32471
  } finally {
32127
32472
  URL.revokeObjectURL(url);
32128
32473
  }
32129
32474
  }
32130
- const { mkdtemp, writeFile, rm } = await import("@frontmcp/utils");
32475
+ const { ensureDir, fileExists: fileExists9, sha256Hex: sha256Hex9, writeFile } = await import("@frontmcp/utils");
32131
32476
  const nodePath = await import("node:path");
32132
32477
  const nodeOs = await import("node:os");
32133
32478
  const { pathToFileURL } = await import("node:url");
32134
- const tempDir = await mkdtemp(nodePath.join(nodeOs.tmpdir(), "frontmcp-esm-"));
32135
- const tempPath = nodePath.join(tempDir, "bundle.mjs");
32136
- try {
32479
+ const dir = nodePath.join(nodeOs.tmpdir(), "frontmcp-esm-modules");
32480
+ await ensureDir(dir);
32481
+ const tempPath = nodePath.join(dir, `${sha256Hex9(bundleContent)}.mjs`);
32482
+ if (!await fileExists9(tempPath)) {
32137
32483
  await writeFile(tempPath, bundleContent);
32138
- return await import(pathToFileURL(tempPath).href + `?t=${Date.now()}`);
32139
- } finally {
32140
- await rm(tempDir, { recursive: true, force: true }).catch(() => {
32141
- });
32142
32484
  }
32485
+ return importComputed(pathToFileURL(tempPath).href);
32143
32486
  }
32144
32487
  };
32145
32488
  }
@@ -32918,7 +33261,7 @@ var init_auth_ui_contract = __esm({
32918
33261
  });
32919
33262
 
32920
33263
  // libs/sdk/src/auth/auth-ui/auth-ui.registry.ts
32921
- import { isAbsolute as isAbsolute2, pathResolve as pathResolve5, randomBytes as randomBytes3, sha256Hex as sha256Hex4 } from "@frontmcp/utils";
33264
+ import { isAbsolute as isAbsolute2, pathResolve as pathResolve5, randomBytes as randomBytes3, sha256Hex as sha256Hex5 } from "@frontmcp/utils";
32922
33265
  function timingSafeEqualStr(a, b) {
32923
33266
  if (a.length !== b.length) return false;
32924
33267
  let diff = 0;
@@ -33047,7 +33390,7 @@ var init_auth_ui_registry = __esm({
33047
33390
  mintCsrf(pendingAuthId) {
33048
33391
  const existing = this.pending.get(pendingAuthId);
33049
33392
  if (existing) return existing.csrf;
33050
- const csrf = sha256Hex4(randomBytes3(32)).slice(0, 43);
33393
+ const csrf = sha256Hex5(randomBytes3(32)).slice(0, 43);
33051
33394
  this.pending.set(pendingAuthId, { csrf, addedItems: {}, createdAt: Date.now() });
33052
33395
  this.pruneExpired();
33053
33396
  return csrf;
@@ -33100,7 +33443,7 @@ var init_auth_ui_registry = __esm({
33100
33443
  ensurePending(pendingAuthId) {
33101
33444
  let state = this.pending.get(pendingAuthId);
33102
33445
  if (!state) {
33103
- state = { csrf: sha256Hex4(randomBytes3(32)).slice(0, 43), addedItems: {}, createdAt: Date.now() };
33446
+ state = { csrf: sha256Hex5(randomBytes3(32)).slice(0, 43), addedItems: {}, createdAt: Date.now() };
33104
33447
  this.pending.set(pendingAuthId, state);
33105
33448
  this.pruneExpired();
33106
33449
  }
@@ -33957,6 +34300,15 @@ var init_oauth_authorize_flow = __esm({
33957
34300
  return;
33958
34301
  }
33959
34302
  }
34303
+ if (!isCimdClientId2) {
34304
+ const registry = this.scope.auth.dcrClientRegistry;
34305
+ const registered = registry?.get?.(client_id);
34306
+ if (registered && !registered.redirect_uris.includes(redirect_uri)) {
34307
+ this.logger.warn(`OAuth authorize: redirect_uri "${redirect_uri}" not registered for client "${client_id}"`);
34308
+ this.respondWithError(["redirect_uri is not registered for this client"], void 0, rawState);
34309
+ return;
34310
+ }
34311
+ }
33960
34312
  }
33961
34313
  async checkIfAuthorized() {
33962
34314
  }
@@ -34221,7 +34573,7 @@ var init_oauth_authorize_flow = __esm({
34221
34573
  }
34222
34574
  const state = buildState({
34223
34575
  pendingAuthId,
34224
- submitUrl: `${this.scope.fullPath}/oauth/callback`,
34576
+ submitUrl: "/oauth/callback",
34225
34577
  extraUrl: authUiExtraPath(this.scope.fullPath),
34226
34578
  csrfToken,
34227
34579
  addedItems: authUi.getAddedItems(pendingAuthId)
@@ -34367,7 +34719,7 @@ var init_oauth_authorize_flow = __esm({
34367
34719
  */
34368
34720
  renderLoginPage(params) {
34369
34721
  const { pendingAuthId, clientId, clientName, scope, logoUri } = params;
34370
- const callbackPath = `${this.scope.fullPath}/oauth/callback`;
34722
+ const callbackPath = "/oauth/callback";
34371
34723
  const auth = this.scope.metadata.auth;
34372
34724
  const login = auth && auth.mode === "local" ? auth.login : void 0;
34373
34725
  const ctx = {
@@ -34386,7 +34738,7 @@ var init_oauth_authorize_flow = __esm({
34386
34738
  */
34387
34739
  renderIncrementalAuthPage(params) {
34388
34740
  const { pendingAuthId, appId, appName, appDescription, toolId } = params;
34389
- const callbackPath = `${this.scope.fullPath}/oauth/callback`;
34741
+ const callbackPath = "/oauth/callback";
34390
34742
  const app = {
34391
34743
  appId,
34392
34744
  appName,
@@ -34404,7 +34756,7 @@ var init_oauth_authorize_flow = __esm({
34404
34756
  */
34405
34757
  renderFederatedLoginPage(params) {
34406
34758
  const { pendingAuthId, detection, clientId } = params;
34407
- const callbackPath = `${this.scope.fullPath}/oauth/callback`;
34759
+ const callbackPath = "/oauth/callback";
34408
34760
  const providers = [...detection.providers.values()].map((provider) => ({
34409
34761
  providerId: provider.id,
34410
34762
  providerName: provider.id,
@@ -34508,7 +34860,7 @@ import {
34508
34860
  startNextProvider as startNextProvider2
34509
34861
  } from "@frontmcp/auth";
34510
34862
  import { z as z65 } from "@frontmcp/lazy-zod";
34511
- import { generateCodeVerifier as generateCodeVerifier2, randomUUID as randomUUID16, sha256Base64url as sha256Base64url2, sha256Hex as sha256Hex5 } from "@frontmcp/utils";
34863
+ import { generateCodeVerifier as generateCodeVerifier2, randomUUID as randomUUID16, sha256Base64url as sha256Base64url2, sha256Hex as sha256Hex6 } from "@frontmcp/utils";
34512
34864
  function timingSafeEqualStr3(a, b) {
34513
34865
  if (a.length !== b.length) return false;
34514
34866
  let diff = 0;
@@ -35234,7 +35586,7 @@ var init_oauth_callback_flow = __esm({
35234
35586
  * preserved on the form so the user does not have to re-enter everything.
35235
35587
  */
35236
35588
  renderLoginRetryPage(pendingAuth, login, fields, failure) {
35237
- const callbackPath = `${this.scope.fullPath}/oauth/callback`;
35589
+ const callbackPath = "/oauth/callback";
35238
35590
  const ctx = {
35239
35591
  clientId: pendingAuth.clientId,
35240
35592
  clientName: pendingAuth.clientId,
@@ -35300,7 +35652,7 @@ var init_oauth_callback_flow = __esm({
35300
35652
  const state = buildConsentState(
35301
35653
  {
35302
35654
  pendingAuthId: pendingAuth.id,
35303
- submitUrl: `${this.scope.fullPath}/oauth/callback`,
35655
+ submitUrl: "/oauth/callback",
35304
35656
  extraUrl: authUiExtraPath(this.scope.fullPath),
35305
35657
  csrfToken,
35306
35658
  addedItems: authUi.getAddedItems(pendingAuth.id)
@@ -35327,7 +35679,7 @@ var init_oauth_callback_flow = __esm({
35327
35679
  * (used for an empty `requireSelection` submit).
35328
35680
  */
35329
35681
  renderConsentScreen(pendingAuth, consentConfig, identity, error, preSelectedTools) {
35330
- const callbackPath = `${this.scope.fullPath}/oauth/callback`;
35682
+ const callbackPath = "/oauth/callback";
35331
35683
  const { toolCards } = projectConsentTools(this.scope, consentConfig?.excludedTools);
35332
35684
  const hiddenFields = [];
35333
35685
  if (identity.email) hiddenFields.push({ name: "email", value: identity.email });
@@ -35366,7 +35718,7 @@ var init_oauth_callback_flow = __esm({
35366
35718
  * In production, this would be the user's ID from the database
35367
35719
  */
35368
35720
  generateUserSub(email) {
35369
- const hash = sha256Hex5(email.toLowerCase());
35721
+ const hash = sha256Hex6(email.toLowerCase());
35370
35722
  return `${hash.slice(0, 8)}-${hash.slice(8, 12)}-${hash.slice(12, 16)}-${hash.slice(16, 20)}-${hash.slice(20, 32)}`;
35371
35723
  }
35372
35724
  /**
@@ -36768,7 +37120,8 @@ var init_oauth_token_flow = __esm({
36768
37120
  async handleAuthorizationCodeGrant() {
36769
37121
  const { body, isDefaultAuthProvider } = this.state.required;
36770
37122
  if (body?.grant_type !== "authorization_code") return;
36771
- if (isDefaultAuthProvider && body.code === "anonymous") {
37123
+ const authOptions = this.scope.auth?.options;
37124
+ if (isDefaultAuthProvider && body.code === "anonymous" && !!authOptions && allowsPublicAccess(authOptions)) {
36772
37125
  const localAuth2 = this.scope.auth;
36773
37126
  const accessToken = await localAuth2.signAnonymousJwt();
36774
37127
  this.state.set("tokenResponse", {
@@ -36806,6 +37159,16 @@ var init_oauth_token_flow = __esm({
36806
37159
  const { body, isDefaultAuthProvider } = this.state.required;
36807
37160
  if (body?.grant_type !== "refresh_token") return;
36808
37161
  if (isDefaultAuthProvider) {
37162
+ const authOptions = this.scope.auth?.options;
37163
+ if (!authOptions || !allowsPublicAccess(authOptions)) {
37164
+ this.respond(
37165
+ httpRespond.json(
37166
+ { error: "invalid_grant", error_description: "Refresh requires re-authentication on this server" },
37167
+ { status: 400 }
37168
+ )
37169
+ );
37170
+ return;
37171
+ }
36809
37172
  const localAuth2 = this.scope.auth;
36810
37173
  const accessToken = await localAuth2.signAnonymousJwt();
36811
37174
  this.state.set("tokenResponse", {
@@ -36841,6 +37204,19 @@ var init_oauth_token_flow = __esm({
36841
37204
  }
36842
37205
  async handleAnonymousGrant() {
36843
37206
  const { body } = this.state.required;
37207
+ const authOptions = this.scope.auth?.options;
37208
+ if (!authOptions || !allowsPublicAccess(authOptions)) {
37209
+ this.respond(
37210
+ httpRespond.json(
37211
+ {
37212
+ error: "unsupported_grant_type",
37213
+ error_description: "Anonymous access is not enabled on this server"
37214
+ },
37215
+ { status: 400 }
37216
+ )
37217
+ );
37218
+ return;
37219
+ }
36844
37220
  if (body?.grant_type === "anonymous" && body.resource) {
36845
37221
  const { request } = this.rawInput;
36846
37222
  const canonicalResource = computeResource(request, this.scope.entryPath, this.scope.routeBase);
@@ -37160,7 +37536,7 @@ var init_session_verify_flow = __esm({
37160
37536
  const token = extractBearerToken2(authorizationHeader);
37161
37537
  const userAgent = request.headers?.["user-agent"] ?? void 0;
37162
37538
  const prmMetadataPath = `/.well-known/oauth-protected-resource${entryPath}${routeBase}`;
37163
- const prmUrl = `${baseUrl}${prmMetadataPath}`;
37539
+ const prmUrl = `${getRequestBaseUrl(request)}${prmMetadataPath}`;
37164
37540
  const prmMetadataHeader = buildUnauthorizedHeader(prmUrl);
37165
37541
  this.logger.verbose("parseInput", {
37166
37542
  hasAuthHeader: !!authorizationHeader,
@@ -37805,9 +38181,15 @@ import {
37805
38181
  MemoryStorageAdapter,
37806
38182
  randomBytes as randomBytes5,
37807
38183
  randomUUID as randomUUID21,
37808
- sha256Hex as sha256Hex6
38184
+ sha256Hex as sha256Hex7
37809
38185
  } from "@frontmcp/utils";
37810
- var DEFAULT_NO_AUTH_SECRET, RESERVED_JWT_CLAIMS, LocalPrimaryAuth;
38186
+ function getDefaultNoAuthSecret() {
38187
+ if (!defaultNoAuthSecret) {
38188
+ defaultNoAuthSecret = randomBytes5(32);
38189
+ }
38190
+ return defaultNoAuthSecret;
38191
+ }
38192
+ var defaultNoAuthSecret, RESERVED_JWT_CLAIMS, LocalPrimaryAuth;
37811
38193
  var init_instance_local_primary_auth = __esm({
37812
38194
  "libs/sdk/src/auth/instances/instance.local-primary-auth.ts"() {
37813
38195
  "use strict";
@@ -37831,7 +38213,6 @@ var init_instance_local_primary_auth = __esm({
37831
38213
  init_well_known_prm_flow();
37832
38214
  init_secure_store();
37833
38215
  init_secure_store_context_extension();
37834
- DEFAULT_NO_AUTH_SECRET = randomBytes5(32);
37835
38216
  RESERVED_JWT_CLAIMS = /* @__PURE__ */ new Set([
37836
38217
  "sub",
37837
38218
  "iss",
@@ -37863,7 +38244,7 @@ var init_instance_local_primary_auth = __esm({
37863
38244
  this.secret = new TextEncoder().encode(jwtSecret);
37864
38245
  } else {
37865
38246
  this.logger.warn("JWT_SECRET is not set, using default secret");
37866
- this.secret = DEFAULT_NO_AUTH_SECRET;
38247
+ this.secret = getDefaultNoAuthSecret();
37867
38248
  }
37868
38249
  this.tokenStorage = this.readTokenStorage(options);
37869
38250
  this.authorizationStoreImpl = new InMemoryAuthorizationStore();
@@ -37880,6 +38261,8 @@ var init_instance_local_primary_auth = __esm({
37880
38261
  }
37881
38262
  this.ready = this.initialize();
37882
38263
  }
38264
+ scope;
38265
+ providers;
37883
38266
  host;
37884
38267
  port;
37885
38268
  issuer;
@@ -38323,7 +38706,7 @@ var init_instance_local_primary_auth = __esm({
38323
38706
  const pendingAuthId = `pending:${codeRecord.pendingAuthId}`;
38324
38707
  const parts = accessToken.split(".");
38325
38708
  const signature = parts[2] || accessToken;
38326
- const newAuthId = sha256Hex6(signature).substring(0, 16);
38709
+ const newAuthId = sha256Hex7(signature).substring(0, 16);
38327
38710
  await this.orchestratedTokenStore.migrateTokens(pendingAuthId, newAuthId);
38328
38711
  this.logger.info(`Migrated tokens from ${pendingAuthId} to ${newAuthId}`);
38329
38712
  } catch (err) {
@@ -38773,6 +39156,8 @@ var init_instance_remote_primary_auth = __esm({
38773
39156
  this.providers = providers;
38774
39157
  this.ready = this.initialize();
38775
39158
  }
39159
+ scope;
39160
+ providers;
38776
39161
  ready;
38777
39162
  jwks = new JwksService4();
38778
39163
  fetch(input, init) {
@@ -39027,6 +39412,7 @@ var init_channel_notification_service = __esm({
39027
39412
  this.logger = logger.child("ChannelNotificationService");
39028
39413
  this.defaultMeta = defaultMeta ?? {};
39029
39414
  }
39415
+ notificationService;
39030
39416
  logger;
39031
39417
  defaultMeta;
39032
39418
  /**
@@ -41919,6 +42305,8 @@ var init_heartbeat_service = __esm({
41919
42305
  this.intervalMs = config?.heartbeatIntervalMs ?? DEFAULT_HA_CONFIG.heartbeatIntervalMs;
41920
42306
  this.ttlMs = config?.heartbeatTtlMs ?? DEFAULT_HA_CONFIG.heartbeatTtlMs;
41921
42307
  }
42308
+ redis;
42309
+ nodeId;
41922
42310
  timer;
41923
42311
  startedAt;
41924
42312
  keyPrefix;
@@ -41998,6 +42386,9 @@ var init_notification_relay = __esm({
41998
42386
  this.keyPrefix = config?.redisKeyPrefix ?? DEFAULT_HA_CONFIG.redisKeyPrefix;
41999
42387
  this.channel = `${this.keyPrefix}notify:${nodeId}`;
42000
42388
  }
42389
+ subscriber;
42390
+ publisher;
42391
+ nodeId;
42001
42392
  handler;
42002
42393
  channel;
42003
42394
  keyPrefix;
@@ -42107,6 +42498,8 @@ var init_ha_manager = __esm({
42107
42498
  this.relay = new NotificationRelay(options.pubsubSubscriber, options.pubsubPublisher, nodeId, this.config);
42108
42499
  }
42109
42500
  }
42501
+ redis;
42502
+ nodeId;
42110
42503
  heartbeat;
42111
42504
  relay;
42112
42505
  config;
@@ -43608,6 +44001,7 @@ var init_job_instance = __esm({
43608
44001
  super(args);
43609
44002
  this.record = record;
43610
44003
  }
44004
+ record;
43611
44005
  execute(input) {
43612
44006
  return this.record.provide(input, this);
43613
44007
  }
@@ -44775,6 +45169,9 @@ var init_custom_routes_helper = __esm({
44775
45169
  this.reserved = reserved;
44776
45170
  this.name = "ReservedRouteCollisionError";
44777
45171
  }
45172
+ method;
45173
+ path;
45174
+ reserved;
44778
45175
  };
44779
45176
  }
44780
45177
  });
@@ -46237,11 +46634,11 @@ var init_skill_http_auth = __esm({
46237
46634
  * This prevents timing attacks that could reveal information about valid API keys.
46238
46635
  */
46239
46636
  timingSafeIncludes(keys, candidate) {
46240
- const encoder = new TextEncoder();
46241
- const candidateBytes = encoder.encode(candidate);
46637
+ const encoder2 = new TextEncoder();
46638
+ const candidateBytes = encoder2.encode(candidate);
46242
46639
  let found = false;
46243
46640
  for (const key of keys) {
46244
- const keyBytes = encoder.encode(key);
46641
+ const keyBytes = encoder2.encode(key);
46245
46642
  if (keyBytes.length === candidateBytes.length) {
46246
46643
  try {
46247
46644
  if (timingSafeEqual(keyBytes, candidateBytes)) {
@@ -48175,6 +48572,7 @@ var init_agent_execution_loop = __esm({
48175
48572
  this.maxIterations = maxIterations;
48176
48573
  this.name = "AgentMaxIterationsError";
48177
48574
  }
48575
+ maxIterations;
48178
48576
  };
48179
48577
  }
48180
48578
  });
@@ -49166,7 +49564,23 @@ function normalizeScopeBase(scopeBase) {
49166
49564
  const t = trimSlashes(scopeBase ?? "");
49167
49565
  return t ? `/${t}` : "";
49168
49566
  }
49567
+ function readPublicUrlPin() {
49568
+ try {
49569
+ if (typeof process !== "undefined" && process.env) {
49570
+ const v = process.env["FRONTMCP_PUBLIC_URL"];
49571
+ if (typeof v === "string" && v.trim()) {
49572
+ return v.trim().replace(/\/+$/, "");
49573
+ }
49574
+ }
49575
+ } catch {
49576
+ }
49577
+ return void 0;
49578
+ }
49169
49579
  function getRequestBaseUrl(req, entryPath) {
49580
+ const pin = readPublicUrlPin();
49581
+ if (pin) {
49582
+ return `${pin}${entryPath ?? ""}`;
49583
+ }
49170
49584
  const proto = req.headers["x-forwarded-proto"] || req.protocol || "http";
49171
49585
  const host = req.headers["x-forwarded-host"] || req.headers["host"];
49172
49586
  return `${proto}://${host}${entryPath ?? ""}`;
@@ -50071,6 +50485,8 @@ return 0
50071
50485
  this.haKeyPrefix = options?.haKeyPrefix ?? "mcp:ha:";
50072
50486
  this.logger = options?.logger;
50073
50487
  }
50488
+ redis;
50489
+ machineId;
50074
50490
  keyPrefix;
50075
50491
  ttlSeconds;
50076
50492
  haKeyPrefix;
@@ -51827,6 +52243,8 @@ var init_base_sse_transport = __esm({
51827
52243
  this._sessionId = options?.sessionId ?? randomUUID25();
51828
52244
  this._options = options || { enableDnsRebindingProtection: false };
51829
52245
  }
52246
+ _endpoint;
52247
+ res;
51830
52248
  _sseResponse;
51831
52249
  _sessionId;
51832
52250
  _options;
@@ -52071,6 +52489,12 @@ function sanitizeDescription(raw) {
52071
52489
  if (!raw) return "";
52072
52490
  return raw.replace(/\r?\n/g, " ").replace(/\s+/g, " ").replace(/^\s*-{3,}\s*$/g, "").replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\*/g, "\\*").replace(/_/g, "\\_").replace(/\[/g, "\\[").trim();
52073
52491
  }
52492
+ function sanitizeName(raw) {
52493
+ if (!raw) return "(unnamed)";
52494
+ const s = raw.replace(/\s+/g, " ").trim();
52495
+ if (!s) return "(unnamed)";
52496
+ return s.length > MAX_SKILL_NAME_CHARS ? `${s.slice(0, MAX_SKILL_NAME_CHARS)}\u2026` : s;
52497
+ }
52074
52498
  function buildSkillsCatalogSummary(skillRegistry) {
52075
52499
  if (!skillRegistry) return "";
52076
52500
  const skills = skillRegistry.getSkills({ visibility: "mcp" });
@@ -52082,7 +52506,7 @@ function buildSkillsCatalogSummary(skillRegistry) {
52082
52506
  const effectiveCap = MAX_SKILL_CATALOG_CHARS - TRUNCATION_FOOTER_RESERVE;
52083
52507
  for (const skill of skills) {
52084
52508
  const meta = skill.metadata;
52085
- const name41 = meta.name;
52509
+ const name41 = sanitizeName(meta.name);
52086
52510
  const description = sanitizeDescription(meta.description);
52087
52511
  const line = description ? `- **${name41}**: ${description}` : `- **${name41}**`;
52088
52512
  if (charCount + line.length + 1 > effectiveCap) {
@@ -52127,13 +52551,14 @@ function buildChannelInstructions(channels) {
52127
52551
  function joinSections(sections) {
52128
52552
  return sections.map((s) => (s ?? "").trim()).filter((s) => s.length > 0).join("\n\n---\n\n");
52129
52553
  }
52130
- var DEFAULT_POLICY, MAX_SKILL_CATALOG_CHARS, TRUNCATION_FOOTER_RESERVE, CATALOG_HEADER;
52554
+ var DEFAULT_POLICY, MAX_SKILL_CATALOG_CHARS, TRUNCATION_FOOTER_RESERVE, MAX_SKILL_NAME_CHARS, CATALOG_HEADER;
52131
52555
  var init_skill_instructions_helper = __esm({
52132
52556
  "libs/sdk/src/skill/skill-instructions.helper.ts"() {
52133
52557
  "use strict";
52134
52558
  DEFAULT_POLICY = "append";
52135
52559
  MAX_SKILL_CATALOG_CHARS = 16e3;
52136
52560
  TRUNCATION_FOOTER_RESERVE = 160;
52561
+ MAX_SKILL_NAME_CHARS = 80;
52137
52562
  CATALOG_HEADER = "Available skills (read the `skills://catalog` resource to browse, or `skills://{name}/SKILL.md` for full content):";
52138
52563
  }
52139
52564
  });
@@ -52186,6 +52611,9 @@ var init_transport_local_adapter = __esm({
52186
52611
  this.transport = this.createTransport(key.sessionId, res);
52187
52612
  this.ready = this.connectServer();
52188
52613
  }
52614
+ scope;
52615
+ key;
52616
+ onDispose;
52189
52617
  logger;
52190
52618
  transport;
52191
52619
  /**
@@ -53106,6 +53534,7 @@ var init_transport_local = __esm({
53106
53534
  throw new UnsupportedTransportTypeError(this.type);
53107
53535
  }
53108
53536
  }
53537
+ onDispose;
53109
53538
  type;
53110
53539
  tokenHash;
53111
53540
  sessionId;
@@ -53175,6 +53604,8 @@ var init_transport_remote = __esm({
53175
53604
  this.tokenHash = key.tokenHash;
53176
53605
  this.sessionId = key.sessionId;
53177
53606
  }
53607
+ key;
53608
+ bus;
53178
53609
  type;
53179
53610
  tokenHash;
53180
53611
  sessionId;
@@ -53204,7 +53635,7 @@ var init_transport_remote = __esm({
53204
53635
  });
53205
53636
 
53206
53637
  // libs/sdk/src/transport/transport.registry.ts
53207
- import { getMachineId as getMachineId5, sha256Hex as sha256Hex7 } from "@frontmcp/utils";
53638
+ import { getMachineId as getMachineId5, sha256Hex as sha256Hex8 } from "@frontmcp/utils";
53208
53639
  var TransportService;
53209
53640
  var init_transport_registry = __esm({
53210
53641
  "libs/sdk/src/transport/transport.registry.ts"() {
@@ -53734,7 +54165,7 @@ var init_transport_registry = __esm({
53734
54165
  }
53735
54166
  /* --------------------------------- internals -------------------------------- */
53736
54167
  sha256(value) {
53737
- return sha256Hex7(value);
54168
+ return sha256Hex8(value);
53738
54169
  }
53739
54170
  /**
53740
54171
  * Create a history key from components.
@@ -53840,6 +54271,74 @@ var init_transport_registry = __esm({
53840
54271
  }
53841
54272
  });
53842
54273
 
54274
+ // libs/sdk/src/transport/web-standard-mcp.ts
54275
+ var web_standard_mcp_exports = {};
54276
+ __export(web_standard_mcp_exports, {
54277
+ buildPersistentWebStandardMcp: () => buildPersistentWebStandardMcp,
54278
+ runWebStandardMcp: () => runWebStandardMcp
54279
+ });
54280
+ import { randomUUID as randomUUID26 } from "@frontmcp/utils";
54281
+ async function wireServer(scope, serverOptions, sessionId, sessionIdGenerator, enableJsonResponse) {
54282
+ const { McpServer: McpServer2, WebStandardStreamableHTTPServerTransport: WebStandardStreamableHTTPServerTransport2 } = await import("@frontmcp/protocol");
54283
+ const { createMcpHandlers: createMcpHandlers2 } = await Promise.resolve().then(() => (init_mcp_handlers(), mcp_handlers_exports));
54284
+ const mcpServer = new McpServer2(scope.metadata.info, serverOptions);
54285
+ for (const handler of createMcpHandlers2({ scope, serverOptions })) {
54286
+ const originalHandler = handler.handler;
54287
+ const wrappedHandler = async (req, ctx) => {
54288
+ const existingAuthInfo = ctx?.["authInfo"] ?? {};
54289
+ const enrichedCtx = { ...ctx, authInfo: { ...existingAuthInfo, sessionId } };
54290
+ return originalHandler(req, enrichedCtx);
54291
+ };
54292
+ mcpServer.setRequestHandler(handler.requestSchema, wrappedHandler);
54293
+ }
54294
+ const transport = new WebStandardStreamableHTTPServerTransport2({ sessionIdGenerator, enableJsonResponse });
54295
+ await mcpServer.connect(transport);
54296
+ return { mcpServer, transport };
54297
+ }
54298
+ async function buildPersistentWebStandardMcp(scope, options) {
54299
+ const serverOptions = buildScopedServerOptions(scope);
54300
+ return wireServer(scope, serverOptions, options.sessionId, () => options.sessionId, false);
54301
+ }
54302
+ async function runWebStandardMcp(scope, request, options) {
54303
+ if (options.persistent) {
54304
+ return options.persistent.transport.handleRequest(request, { authInfo: options.authInfo });
54305
+ }
54306
+ const sessionId = `web:${randomUUID26()}`;
54307
+ const accept = request.headers.get("accept") ?? "";
54308
+ const wantsStream = request.method === "GET" || options.sse && accept.includes("text/event-stream");
54309
+ const { mcpServer, transport } = await wireServer(
54310
+ scope,
54311
+ options.serverOptions,
54312
+ sessionId,
54313
+ void 0,
54314
+ !wantsStream
54315
+ );
54316
+ const response = await transport.handleRequest(request, {
54317
+ authInfo: options.authInfo
54318
+ });
54319
+ if (response.headers.get("content-type")?.includes("text/event-stream")) {
54320
+ const closed = new Promise((resolve) => {
54321
+ const prev = transport.onclose;
54322
+ transport.onclose = () => {
54323
+ prev?.();
54324
+ resolve();
54325
+ };
54326
+ });
54327
+ const teardown = closed.then(() => mcpServer.close().catch(() => void 0));
54328
+ if (options.ctx?.waitUntil) options.ctx.waitUntil(teardown);
54329
+ else void teardown;
54330
+ } else {
54331
+ void mcpServer.close().catch(() => void 0);
54332
+ }
54333
+ return response;
54334
+ }
54335
+ var init_web_standard_mcp = __esm({
54336
+ "libs/sdk/src/transport/web-standard-mcp.ts"() {
54337
+ "use strict";
54338
+ init_build_scoped_server_options();
54339
+ }
54340
+ });
54341
+
53843
54342
  // libs/sdk/src/scope/flows/http.request.flow.ts
53844
54343
  import {
53845
54344
  deriveAuthorizationId,
@@ -53848,7 +54347,7 @@ import {
53848
54347
  OrchestratedAuthorization
53849
54348
  } from "@frontmcp/auth";
53850
54349
  import { z as z103 } from "@frontmcp/lazy-zod";
53851
- import { randomUUID as randomUUID26 } from "@frontmcp/utils";
54350
+ import { randomUUID as randomUUID27 } from "@frontmcp/utils";
53852
54351
  var plan39, httpRequestStateSchema, name40, Stage40, HttpRequestFlow;
53853
54352
  var init_http_request_flow = __esm({
53854
54353
  "libs/sdk/src/scope/flows/http.request.flow.ts"() {
@@ -53868,6 +54367,11 @@ var init_http_request_flow = __esm({
53868
54367
  "router"
53869
54368
  ],
53870
54369
  execute: [
54370
+ // Web-fetch (V8-isolate / Cloudflare Worker) MCP handling. Runs FIRST and,
54371
+ // in web mode only, responds with a Web `Response` (short-circuiting the
54372
+ // Node handle stages below). On the Node/Express path it's a no-op and falls
54373
+ // through to the runtime-coupled stages.
54374
+ "handleWebFetch",
53871
54375
  "handleLegacySse",
53872
54376
  "handleSse",
53873
54377
  "handleStreamableHttp",
@@ -53910,7 +54414,7 @@ var init_http_request_flow = __esm({
53910
54414
  const { request } = this.rawInput;
53911
54415
  this.requestStartTime = Date.now();
53912
54416
  const ctx = this.tryGetContext();
53913
- this.requestId = ctx?.requestId ?? `req-${randomUUID26()}`;
54417
+ this.requestId = ctx?.requestId ?? `req-${randomUUID27()}`;
53914
54418
  const headers = request.headers ?? {};
53915
54419
  const body = request.body;
53916
54420
  const userAgent = headers["user-agent"];
@@ -54069,6 +54573,10 @@ var init_http_request_flow = __esm({
54069
54573
  accept: request.headers?.["accept"]
54070
54574
  });
54071
54575
  const decision = decideIntent(request, { ...legacyFlags, tolerateMissingAccept: true });
54576
+ const isWebMode = !!request[ServerRequestTokens.webRequest];
54577
+ if (isWebMode && decision.intent === "unknown") {
54578
+ decision.intent = "stateless-http";
54579
+ }
54072
54580
  this.logger.debug(`[${this.requestId}] decision result`, {
54073
54581
  intent: decision.intent,
54074
54582
  reasons: decision.reasons,
@@ -54195,6 +54703,47 @@ var init_http_request_flow = __esm({
54195
54703
  throw error;
54196
54704
  }
54197
54705
  }
54706
+ async handleWebFetch() {
54707
+ const { request } = this.rawInput;
54708
+ const req = request;
54709
+ const webRequest = req[ServerRequestTokens.webRequest];
54710
+ if (!webRequest) return;
54711
+ try {
54712
+ const webCtx = req[ServerRequestTokens.webCtx];
54713
+ const { runWebStandardMcp: runWebStandardMcp2 } = await Promise.resolve().then(() => (init_web_standard_mcp(), web_standard_mcp_exports));
54714
+ const { buildScopedServerOptions: buildScopedServerOptions2 } = await Promise.resolve().then(() => (init_build_scoped_server_options(), build_scoped_server_options_exports));
54715
+ const { expandProtocolConfig: expandProtocolConfig2 } = await Promise.resolve().then(() => (init_schema7(), schema_exports));
54716
+ const scope = this.scope;
54717
+ const proto = expandProtocolConfig2(scope.metadata.transport?.protocol);
54718
+ const sse = proto.streamable && !proto.json;
54719
+ const authorization = req[ServerRequestTokens.auth];
54720
+ const authInfo = authorization ? {
54721
+ token: authorization.token,
54722
+ clientId: authorization.user?.sub,
54723
+ scopes: [],
54724
+ expiresAt: authorization.user?.exp ? authorization.user.exp * 1e3 : void 0,
54725
+ extra: {
54726
+ user: authorization.user,
54727
+ sessionId: authorization.session?.id,
54728
+ sessionPayload: authorization.session?.payload
54729
+ }
54730
+ } : void 0;
54731
+ const persistent = req[ServerRequestTokens.webTransport];
54732
+ const response = await runWebStandardMcp2(scope, webRequest, {
54733
+ serverOptions: buildScopedServerOptions2(scope),
54734
+ authInfo,
54735
+ sse,
54736
+ ctx: webCtx,
54737
+ persistent
54738
+ });
54739
+ this.respond(httpRespond.webResponse(response));
54740
+ } catch (error) {
54741
+ if (!(error instanceof FlowControl)) {
54742
+ this.logError(error, "handleWebFetch");
54743
+ }
54744
+ throw error;
54745
+ }
54746
+ }
54198
54747
  async handleLegacySse() {
54199
54748
  try {
54200
54749
  const response = await this.scope.runFlow("handle:legacy-sse", this.rawInput);
@@ -54364,6 +54913,9 @@ var init_http_request_flow = __esm({
54364
54913
  __decorateClass([
54365
54914
  Stage40("router")
54366
54915
  ], HttpRequestFlow.prototype, "router", 1);
54916
+ __decorateClass([
54917
+ Stage40("handleWebFetch")
54918
+ ], HttpRequestFlow.prototype, "handleWebFetch", 1);
54367
54919
  __decorateClass([
54368
54920
  Stage40("handleLegacySse", {
54369
54921
  filter: ({
@@ -54436,28 +54988,11 @@ var init_http_request_flow = __esm({
54436
54988
  }
54437
54989
  });
54438
54990
 
54439
- // libs/sdk/src/scope/optional-dependency.util.ts
54440
- function probeOptionalDependency(moduleName, loadError, resolve) {
54441
- let resolvedPath;
54442
- try {
54443
- resolvedPath = resolve(moduleName);
54444
- } catch {
54445
- resolvedPath = void 0;
54446
- }
54447
- const error = loadError instanceof Error ? loadError.message : String(loadError);
54448
- return resolvedPath ? { status: "load-failed", resolvedPath, error } : { status: "not-installed", error };
54449
- }
54450
- var init_optional_dependency_util = __esm({
54451
- "libs/sdk/src/scope/optional-dependency.util.ts"() {
54452
- "use strict";
54453
- }
54454
- });
54455
-
54456
54991
  // libs/sdk/src/scope/scope.instance.ts
54457
54992
  import "reflect-metadata";
54458
54993
  import { createGuardManager } from "@frontmcp/guard";
54459
54994
  import { getEnvFlag, getMachineId as getMachineId6, getRuntimeContext as getRuntimeContext15, isEdgeRuntime } from "@frontmcp/utils";
54460
- var Scope;
54995
+ var SCOPE_NON_DISPATCHABLE_FLOWS, Scope;
54461
54996
  var init_scope_instance = __esm({
54462
54997
  "libs/sdk/src/scope/scope.instance.ts"() {
54463
54998
  "use strict";
@@ -54503,6 +55038,7 @@ var init_scope_instance = __esm({
54503
55038
  init_transport_registry();
54504
55039
  init_http_request_flow();
54505
55040
  init_optional_dependency_util();
55041
+ SCOPE_NON_DISPATCHABLE_FLOWS = /* @__PURE__ */ new Set(["http:request"]);
54506
55042
  Scope = class _Scope extends ScopeEntry {
54507
55043
  id;
54508
55044
  globalProviders;
@@ -54896,7 +55432,9 @@ var init_scope_instance = __esm({
54896
55432
  this.scopeResources = new ResourceRegistry(this.scopeProviders, [], scopeRef);
54897
55433
  this.scopePrompts = new PromptRegistry(this.scopeProviders, [], scopeRef);
54898
55434
  this.scopeAgents = new AgentRegistry(this.scopeProviders, [], scopeRef);
54899
- this.scopeSkills = new SkillRegistry(this.scopeProviders, this.metadata.skills ?? [], scopeRef);
55435
+ this.scopeSkills = new SkillRegistry(this.scopeProviders, this.metadata.skills ?? [], scopeRef, {
55436
+ ...this.metadata.skillsConfig?.scoring ? { scoring: this.metadata.skillsConfig.scoring } : {}
55437
+ });
54900
55438
  await Promise.all([
54901
55439
  this.scopeTools.ready,
54902
55440
  this.scopeResources.ready,
@@ -55657,6 +56195,16 @@ var init_scope_instance = __esm({
55657
56195
  runFlow(name41, input, deps) {
55658
56196
  return this.scopeFlows.runFlow(name41, input, deps);
55659
56197
  }
56198
+ /**
56199
+ * Find the registered flow that handles this HTTP request (by method +
56200
+ * `middleware.path` + `canActivate`), excluding `http:request` (which the
56201
+ * web-fetch handler runs directly for the MCP entry path). Lets the
56202
+ * Worker/web-fetch adapter dispatch auth/well-known/oauth flows the same way
56203
+ * the Express host routes them — without a middleware server.
56204
+ */
56205
+ async findHttpFlowName(request) {
56206
+ return this.scopeFlows.findHttpFlowName(request, SCOPE_NON_DISPATCHABLE_FLOWS);
56207
+ }
55660
56208
  async runFlowForOutput(name41, input, deps) {
55661
56209
  const result = await this.scopeFlows.runFlow(name41, input, deps);
55662
56210
  if (result) {
@@ -55741,6 +56289,7 @@ var init_provider_registry = __esm({
55741
56289
  this.topoSort();
55742
56290
  this.ready = this.initialize();
55743
56291
  }
56292
+ parentProviders;
55744
56293
  /** used to track which registry provided which token */
55745
56294
  providedBy;
55746
56295
  /** topo order (deps first) */
@@ -56693,6 +57242,292 @@ var init_scope_registry = __esm({
56693
57242
  }
56694
57243
  });
56695
57244
 
57245
+ // libs/sdk/src/transport/web-response.renderer.ts
57246
+ function toByteStream(streamLike) {
57247
+ const iter = streamLike[Symbol.asyncIterator];
57248
+ if (typeof iter !== "function") {
57249
+ return new ReadableStream({ start: (c) => c.close() });
57250
+ }
57251
+ const it = iter.call(streamLike);
57252
+ return new ReadableStream({
57253
+ async pull(controller) {
57254
+ const { value, done } = await it.next();
57255
+ if (done) {
57256
+ controller.close();
57257
+ return;
57258
+ }
57259
+ controller.enqueue(typeof value === "string" ? encoder.encode(value) : value);
57260
+ },
57261
+ async cancel() {
57262
+ await it.return?.(void 0);
57263
+ }
57264
+ });
57265
+ }
57266
+ function bytesFrom(body, encoding) {
57267
+ if (typeof body !== "string") return body;
57268
+ if (encoding === "base64") return Uint8Array.from(atob(body), (c) => c.charCodeAt(0));
57269
+ if (encoding === "hex") {
57270
+ if (body.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(body)) {
57271
+ throw new TypeError("Invalid hex-encoded body");
57272
+ }
57273
+ const out = new Uint8Array(body.length / 2);
57274
+ for (let i = 0; i < out.length; i++) out[i] = parseInt(body.slice(i * 2, i * 2 + 2), 16);
57275
+ return out;
57276
+ }
57277
+ return encoder.encode(body);
57278
+ }
57279
+ function buildHeaders(out, contentType2) {
57280
+ const headers = new Headers();
57281
+ if (contentType2) headers.set("Content-Type", contentType2);
57282
+ const extra = out["headers"];
57283
+ if (extra) for (const [k, v] of Object.entries(extra)) headers.set(k, v);
57284
+ const cookies = out["cookies"];
57285
+ if (Array.isArray(cookies)) for (const c of cookies) headers.append("Set-Cookie", c);
57286
+ return headers;
57287
+ }
57288
+ function renderHttpOutputToWebResponse(output) {
57289
+ const out = output;
57290
+ switch (out.kind) {
57291
+ // Already a Web Response (the MCP execute stage on a worker) — return verbatim.
57292
+ case "web-response":
57293
+ return out.response;
57294
+ // "no response" — let the adapter fall through (404 / next middleware).
57295
+ case "next":
57296
+ case "consumed":
57297
+ return void 0;
57298
+ case "redirect": {
57299
+ const headers = buildHeaders(out);
57300
+ headers.set("Location", out.location);
57301
+ return new Response(null, { status: out.status, headers });
57302
+ }
57303
+ case "json":
57304
+ case "jsonrpc":
57305
+ case "problem":
57306
+ return new Response(JSON.stringify(out.body), { status: out.status, headers: buildHeaders(out, out.contentType) });
57307
+ case "text":
57308
+ case "html":
57309
+ return new Response(out.body, { status: out.status, headers: buildHeaders(out, out.contentType) });
57310
+ case "binary":
57311
+ case "image": {
57312
+ const headers = buildHeaders(out, out.contentType);
57313
+ headers.set(
57314
+ "Content-Disposition",
57315
+ out.filename ? `${out.disposition}; filename="${out.filename}"` : out.disposition
57316
+ );
57317
+ return new Response(bytesFrom(out.body, out.encoding), { status: out.status, headers });
57318
+ }
57319
+ case "stream":
57320
+ case "sse": {
57321
+ const headers = buildHeaders(out, out.contentType);
57322
+ if (out.kind === "sse" && !headers.has("Cache-Control")) headers.set("Cache-Control", "no-cache");
57323
+ return new Response(toByteStream(out.stream), { status: out.status, headers });
57324
+ }
57325
+ case "empty":
57326
+ return new Response(null, { status: out.status, headers: buildHeaders(out) });
57327
+ default:
57328
+ return void 0;
57329
+ }
57330
+ }
57331
+ var encoder;
57332
+ var init_web_response_renderer = __esm({
57333
+ "libs/sdk/src/transport/web-response.renderer.ts"() {
57334
+ "use strict";
57335
+ encoder = new TextEncoder();
57336
+ }
57337
+ });
57338
+
57339
+ // libs/sdk/src/transport/web-fetch-handler.ts
57340
+ function mapHttpCors(httpCors, scope) {
57341
+ if (!httpCors) return void 0;
57342
+ const { origin, credentials, maxAge } = httpCors;
57343
+ if (typeof origin === "function") {
57344
+ scope.logger.warn(
57345
+ "[web-fetch] http.cors.origin is a function, which the worker adapter cannot replay \u2014 CORS left disabled. Use a static origin (true / string / string[])."
57346
+ );
57347
+ return void 0;
57348
+ }
57349
+ return { origin, credentials, maxAge };
57350
+ }
57351
+ function createWebFetchHandler(scope, options = {}) {
57352
+ const httpConfig = scope.metadata.http;
57353
+ const healthPaths = new Set(options.healthPaths ?? ["/healthz", "/readyz"]);
57354
+ const normalizePath = (p) => {
57355
+ const withSlash = p.startsWith("/") ? p : `/${p}`;
57356
+ let end = withSlash.length;
57357
+ while (end > 1 && withSlash.charCodeAt(end - 1) === 47) end--;
57358
+ return withSlash.slice(0, end);
57359
+ };
57360
+ const rawEntry = options.entryPath ?? (normalizeEntryPrefix(httpConfig?.entryPath) || "/");
57361
+ const entryPaths = new Set((Array.isArray(rawEntry) ? rawEntry : [rawEntry]).map(normalizePath));
57362
+ const cors2 = options.cors ?? mapHttpCors(httpConfig?.cors, scope);
57363
+ const corsEnabled = cors2?.origin !== void 0 && cors2.origin !== false;
57364
+ const corsHeadersFor = (request) => {
57365
+ if (!corsEnabled) return {};
57366
+ const reqOrigin = request.headers.get("origin") ?? "";
57367
+ let allowOrigin;
57368
+ if (cors2.origin === true) allowOrigin = reqOrigin || "*";
57369
+ else if (cors2.origin === "*" || cors2.origin === reqOrigin) allowOrigin = cors2.origin;
57370
+ else if (typeof cors2.origin === "string") allowOrigin = cors2.origin;
57371
+ else if (Array.isArray(cors2.origin)) allowOrigin = cors2.origin.includes(reqOrigin) ? reqOrigin : void 0;
57372
+ if (!allowOrigin) return {};
57373
+ const h2 = {
57374
+ "Access-Control-Allow-Origin": allowOrigin,
57375
+ "Access-Control-Allow-Methods": (cors2.methods ?? ["GET", "POST", "OPTIONS", "DELETE"]).join(", "),
57376
+ "Access-Control-Allow-Headers": (cors2.headers ?? [
57377
+ request.headers.get("access-control-request-headers") || "content-type, authorization, mcp-session-id, mcp-protocol-version, last-event-id"
57378
+ ]).join(", "),
57379
+ "Access-Control-Expose-Headers": (cors2.exposeHeaders ?? ["Mcp-Session-Id", "WWW-Authenticate"]).join(", ")
57380
+ };
57381
+ if (cors2.credentials) h2["Access-Control-Allow-Credentials"] = "true";
57382
+ if (cors2.maxAge !== void 0) h2["Access-Control-Max-Age"] = String(cors2.maxAge);
57383
+ if (allowOrigin !== "*") h2["Vary"] = "Origin";
57384
+ return h2;
57385
+ };
57386
+ const withCors = (response, request) => {
57387
+ if (!corsEnabled) return response;
57388
+ const headers = new Headers(response.headers);
57389
+ for (const [k, v] of Object.entries(corsHeadersFor(request))) headers.set(k, v);
57390
+ return new Response(response.body, { status: response.status, statusText: response.statusText, headers });
57391
+ };
57392
+ return async function handle(request, ctx, env) {
57393
+ const url = new URL(request.url);
57394
+ if (corsEnabled && request.method === "OPTIONS") {
57395
+ return new Response(null, { status: 204, headers: corsHeadersFor(request) });
57396
+ }
57397
+ if (healthPaths.has(url.pathname)) {
57398
+ return withCors(
57399
+ Response.json(
57400
+ { status: "ok", server: scope.metadata.info, transport: "web-fetch" },
57401
+ { headers: { "Cache-Control": "no-store" } }
57402
+ ),
57403
+ request
57404
+ );
57405
+ }
57406
+ if (!entryPaths.has(normalizePath(url.pathname))) {
57407
+ const authResponse = await runMatchingHttpFlowWeb(scope, request);
57408
+ if (authResponse) return withCors(authResponse, request);
57409
+ return withCors(Response.json({ error: "Not Found", entryPaths: [...entryPaths] }, { status: 404 }), request);
57410
+ }
57411
+ if (options.sessionRouter) {
57412
+ const routed = await options.sessionRouter(request, env, ctx);
57413
+ if (routed) return withCors(routed, request);
57414
+ }
57415
+ const rendered = await runHttpRequestFlowWeb(scope, request, { ctx });
57416
+ return withCors(rendered ?? Response.json({ error: "Not Found" }, { status: 404 }), request);
57417
+ };
57418
+ }
57419
+ async function runHttpRequestFlowWeb(scope, request, opts = {}) {
57420
+ const url = new URL(request.url);
57421
+ const serverRequest = await toServerRequest(request, url, opts.ctx, opts.persistent);
57422
+ let output;
57423
+ try {
57424
+ output = await scope.runFlow("http:request", {
57425
+ request: serverRequest,
57426
+ response: {}
57427
+ });
57428
+ } catch (error) {
57429
+ output = flowErrorToHttpOutput(error);
57430
+ }
57431
+ return output ? renderHttpOutputToWebResponse(output) : void 0;
57432
+ }
57433
+ async function runMatchingHttpFlowWeb(scope, request) {
57434
+ const url = new URL(request.url);
57435
+ const serverRequest = await toServerRequest(request, url);
57436
+ const flowName = await scope.findHttpFlowName(serverRequest);
57437
+ if (!flowName) return void 0;
57438
+ let output;
57439
+ try {
57440
+ output = await scope.runFlow(flowName, {
57441
+ request: serverRequest,
57442
+ response: {}
57443
+ });
57444
+ } catch (error) {
57445
+ output = flowErrorToHttpOutput(error);
57446
+ }
57447
+ return output ? renderHttpOutputToWebResponse(output) : void 0;
57448
+ }
57449
+ async function toServerRequest(request, url, ctx, persistent) {
57450
+ const headers = {};
57451
+ request.headers.forEach((v, k) => {
57452
+ headers[k] = v;
57453
+ });
57454
+ const query = {};
57455
+ url.searchParams.forEach((v, k) => {
57456
+ const existing = query[k];
57457
+ if (existing === void 0) query[k] = v;
57458
+ else if (Array.isArray(existing)) existing.push(v);
57459
+ else query[k] = [existing, v];
57460
+ });
57461
+ const method = request.method.toUpperCase();
57462
+ const hasBody = method !== "GET" && method !== "HEAD";
57463
+ let rawBody = "";
57464
+ if (hasBody) {
57465
+ try {
57466
+ rawBody = await request.text();
57467
+ } catch {
57468
+ rawBody = "";
57469
+ }
57470
+ }
57471
+ let body;
57472
+ if (rawBody) {
57473
+ try {
57474
+ body = JSON.parse(rawBody);
57475
+ } catch {
57476
+ body = rawBody;
57477
+ }
57478
+ }
57479
+ const init = { method: request.method, headers: request.headers };
57480
+ if (rawBody) init.body = rawBody;
57481
+ const webRequest = new Request(url.toString(), init);
57482
+ const serverRequest = {
57483
+ method,
57484
+ path: url.pathname,
57485
+ url: url.pathname + url.search,
57486
+ headers,
57487
+ query,
57488
+ body
57489
+ };
57490
+ const tokenized = serverRequest;
57491
+ tokenized[ServerRequestTokens.webRequest] = webRequest;
57492
+ tokenized[ServerRequestTokens.webCtx] = ctx;
57493
+ if (persistent) tokenized[ServerRequestTokens.webTransport] = persistent;
57494
+ return serverRequest;
57495
+ }
57496
+ function flowErrorToHttpOutput(error) {
57497
+ if (error instanceof FlowControl) {
57498
+ switch (error.type) {
57499
+ case "respond":
57500
+ return error.output;
57501
+ case "next":
57502
+ case "handled":
57503
+ return void 0;
57504
+ default:
57505
+ return { kind: "text", status: 500, body: "Internal Server Error", contentType: "text/plain; charset=utf-8" };
57506
+ }
57507
+ }
57508
+ if (error instanceof PublicMcpError) {
57509
+ const challenge = error.wwwAuthenticate;
57510
+ return {
57511
+ kind: "json",
57512
+ status: error.statusCode,
57513
+ contentType: "application/json; charset=utf-8",
57514
+ body: { error: error.getPublicMessage() },
57515
+ ...typeof challenge === "string" && challenge.length > 0 ? { headers: { "WWW-Authenticate": challenge } } : {}
57516
+ };
57517
+ }
57518
+ return { kind: "text", status: 500, body: "Internal Server Error", contentType: "text/plain; charset=utf-8" };
57519
+ }
57520
+ var init_web_fetch_handler = __esm({
57521
+ "libs/sdk/src/transport/web-fetch-handler.ts"() {
57522
+ "use strict";
57523
+ init_common();
57524
+ init_server_tokens();
57525
+ init_path_utils();
57526
+ init_errors();
57527
+ init_web_response_renderer();
57528
+ }
57529
+ });
57530
+
56696
57531
  // libs/sdk/src/server/noop-server.ts
56697
57532
  var NoopFrontMcpServer;
56698
57533
  var init_noop_server = __esm({
@@ -56718,6 +57553,122 @@ var init_noop_server = __esm({
56718
57553
  }
56719
57554
  });
56720
57555
 
57556
+ // libs/sdk/src/server/security/security-audit.ts
57557
+ function auditSecurityDefaults(config, isProduction5) {
57558
+ const findings = [];
57559
+ if (!isProduction5 && config.deploymentMode !== "distributed") {
57560
+ return findings;
57561
+ }
57562
+ const strict = config.security?.strict === true;
57563
+ if (config.cors === void 0 && !strict) {
57564
+ findings.push({
57565
+ level: "warn",
57566
+ code: "CORS_PERMISSIVE_DEFAULT",
57567
+ message: "CORS is using the permissive default (origin: true), which allows all origins.",
57568
+ recommendation: "Set explicit cors.origin to restrict allowed origins in production."
57569
+ });
57570
+ } else if (config.cors !== false && config.cors?.origin === true && !strict) {
57571
+ findings.push({
57572
+ level: "warn",
57573
+ code: "CORS_ORIGIN_TRUE",
57574
+ message: "CORS origin=true allows all origins to make cross-origin requests.",
57575
+ recommendation: "Set cors.origin to specific allowed origins."
57576
+ });
57577
+ } else if (config.cors === false) {
57578
+ findings.push({
57579
+ level: "info",
57580
+ code: "CORS_DISABLED",
57581
+ message: "CORS is disabled. Cross-origin requests will be blocked by browsers."
57582
+ });
57583
+ } else {
57584
+ findings.push({
57585
+ level: "info",
57586
+ code: "CORS_CONFIGURED",
57587
+ message: "CORS is explicitly configured."
57588
+ });
57589
+ }
57590
+ const bindAddress = config.resolvedBindAddress ?? "0.0.0.0";
57591
+ if (bindAddress === "0.0.0.0" || bindAddress === "::") {
57592
+ if (config.deploymentMode !== "distributed") {
57593
+ findings.push({
57594
+ level: "warn",
57595
+ code: "BIND_ALL_INTERFACES",
57596
+ message: `Server bound to ${bindAddress} \u2014 accessible from all network interfaces.`,
57597
+ recommendation: "Set security.bindAddress to 'loopback' or '127.0.0.1' for local-only access, or configure a reverse proxy. Distributed deployments require 'all' (0.0.0.0)."
57598
+ });
57599
+ } else {
57600
+ findings.push({
57601
+ level: "info",
57602
+ code: "BIND_ALL_INTERFACES_DISTRIBUTED",
57603
+ message: `Server bound to ${bindAddress} (expected for distributed deployment).`
57604
+ });
57605
+ }
57606
+ } else {
57607
+ findings.push({
57608
+ level: "info",
57609
+ code: "BIND_RESTRICTED",
57610
+ message: `Server bound to ${bindAddress}.`
57611
+ });
57612
+ }
57613
+ const dnsProtectionEnabled = config.security?.dnsRebindingProtection?.enabled ?? strict;
57614
+ if (!dnsProtectionEnabled) {
57615
+ findings.push({
57616
+ level: "warn",
57617
+ code: "DNS_REBINDING_UNPROTECTED",
57618
+ message: "DNS rebinding protection is disabled.",
57619
+ recommendation: "Enable security.dnsRebindingProtection with allowedHosts to prevent DNS rebinding attacks."
57620
+ });
57621
+ } else {
57622
+ findings.push({
57623
+ level: "info",
57624
+ code: "DNS_REBINDING_PROTECTED",
57625
+ message: "DNS rebinding protection is enabled."
57626
+ });
57627
+ }
57628
+ if (config.security?.strict) {
57629
+ findings.push({
57630
+ level: "info",
57631
+ code: "STRICT_MODE_ENABLED",
57632
+ message: "Strict security mode is enabled: loopback binding, restrictive CORS, DNS rebinding protection."
57633
+ });
57634
+ } else {
57635
+ findings.push({
57636
+ level: "info",
57637
+ code: "STRICT_MODE_HINT",
57638
+ message: "To enable strict security defaults, set security.strict = true in HttpOptions."
57639
+ });
57640
+ }
57641
+ return findings;
57642
+ }
57643
+ function logSecurityFindings(findings, logger) {
57644
+ if (findings.length === 0) return;
57645
+ for (const finding of findings) {
57646
+ const prefix = `[Security] ${finding.code}:`;
57647
+ const message = finding.recommendation ? `${prefix} ${finding.message} ${finding.recommendation}` : `${prefix} ${finding.message}`;
57648
+ if (finding.level === "warn") {
57649
+ logger.warn(message);
57650
+ } else {
57651
+ logger.info(message);
57652
+ }
57653
+ }
57654
+ }
57655
+ function resolveBindAddress(security, deploymentMode) {
57656
+ if (security?.bindAddress) {
57657
+ if (security.bindAddress === "loopback") return "127.0.0.1";
57658
+ if (security.bindAddress === "all") return "0.0.0.0";
57659
+ return security.bindAddress;
57660
+ }
57661
+ if (security?.strict) {
57662
+ return deploymentMode === "distributed" ? "0.0.0.0" : "127.0.0.1";
57663
+ }
57664
+ return "0.0.0.0";
57665
+ }
57666
+ var init_security_audit = __esm({
57667
+ "libs/sdk/src/server/security/security-audit.ts"() {
57668
+ "use strict";
57669
+ }
57670
+ });
57671
+
56721
57672
  // libs/sdk/src/server/middleware/host-validation.middleware.ts
56722
57673
  function createHostValidationMiddleware(options) {
56723
57674
  if (!options.enabled) {
@@ -56885,8 +57836,8 @@ var init_express_host_adapter = __esm({
56885
57836
  server.on("error", reject);
56886
57837
  server.listen(portOrSocketPath, () => {
56887
57838
  try {
56888
- const fs2 = __require("node:fs");
56889
- fs2.chmodSync(portOrSocketPath, 432);
57839
+ const fs = __require("node:fs");
57840
+ fs.chmodSync(portOrSocketPath, 432);
56890
57841
  } catch {
56891
57842
  }
56892
57843
  console.log(`MCP HTTP (Express) on unix://${portOrSocketPath}`);
@@ -56917,6 +57868,11 @@ var init_express_host_adapter = __esm({
56917
57868
  });
56918
57869
 
56919
57870
  // libs/sdk/src/server/adapters/polyfills/node-express-host.ts
57871
+ var node_express_host_exports = {};
57872
+ __export(node_express_host_exports, {
57873
+ DEFAULT_EXPRESS_BODY_LIMIT: () => DEFAULT_EXPRESS_BODY_LIMIT,
57874
+ ExpressHostAdapter: () => ExpressHostAdapter
57875
+ });
56920
57876
  var init_node_express_host = __esm({
56921
57877
  "libs/sdk/src/server/adapters/polyfills/node-express-host.ts"() {
56922
57878
  "use strict";
@@ -56924,129 +57880,12 @@ var init_node_express_host = __esm({
56924
57880
  }
56925
57881
  });
56926
57882
 
56927
- // libs/sdk/src/server/security/security-audit.ts
56928
- function auditSecurityDefaults(config, isProduction5) {
56929
- const findings = [];
56930
- if (!isProduction5 && config.deploymentMode !== "distributed") {
56931
- return findings;
56932
- }
56933
- const strict = config.security?.strict === true;
56934
- if (config.cors === void 0 && !strict) {
56935
- findings.push({
56936
- level: "warn",
56937
- code: "CORS_PERMISSIVE_DEFAULT",
56938
- message: "CORS is using the permissive default (origin: true), which allows all origins.",
56939
- recommendation: "Set explicit cors.origin to restrict allowed origins in production."
56940
- });
56941
- } else if (config.cors !== false && config.cors?.origin === true && !strict) {
56942
- findings.push({
56943
- level: "warn",
56944
- code: "CORS_ORIGIN_TRUE",
56945
- message: "CORS origin=true allows all origins to make cross-origin requests.",
56946
- recommendation: "Set cors.origin to specific allowed origins."
56947
- });
56948
- } else if (config.cors === false) {
56949
- findings.push({
56950
- level: "info",
56951
- code: "CORS_DISABLED",
56952
- message: "CORS is disabled. Cross-origin requests will be blocked by browsers."
56953
- });
56954
- } else {
56955
- findings.push({
56956
- level: "info",
56957
- code: "CORS_CONFIGURED",
56958
- message: "CORS is explicitly configured."
56959
- });
56960
- }
56961
- const bindAddress = config.resolvedBindAddress ?? "0.0.0.0";
56962
- if (bindAddress === "0.0.0.0" || bindAddress === "::") {
56963
- if (config.deploymentMode !== "distributed") {
56964
- findings.push({
56965
- level: "warn",
56966
- code: "BIND_ALL_INTERFACES",
56967
- message: `Server bound to ${bindAddress} \u2014 accessible from all network interfaces.`,
56968
- recommendation: "Set security.bindAddress to 'loopback' or '127.0.0.1' for local-only access, or configure a reverse proxy. Distributed deployments require 'all' (0.0.0.0)."
56969
- });
56970
- } else {
56971
- findings.push({
56972
- level: "info",
56973
- code: "BIND_ALL_INTERFACES_DISTRIBUTED",
56974
- message: `Server bound to ${bindAddress} (expected for distributed deployment).`
56975
- });
56976
- }
56977
- } else {
56978
- findings.push({
56979
- level: "info",
56980
- code: "BIND_RESTRICTED",
56981
- message: `Server bound to ${bindAddress}.`
56982
- });
56983
- }
56984
- const dnsProtectionEnabled = config.security?.dnsRebindingProtection?.enabled ?? strict;
56985
- if (!dnsProtectionEnabled) {
56986
- findings.push({
56987
- level: "warn",
56988
- code: "DNS_REBINDING_UNPROTECTED",
56989
- message: "DNS rebinding protection is disabled.",
56990
- recommendation: "Enable security.dnsRebindingProtection with allowedHosts to prevent DNS rebinding attacks."
56991
- });
56992
- } else {
56993
- findings.push({
56994
- level: "info",
56995
- code: "DNS_REBINDING_PROTECTED",
56996
- message: "DNS rebinding protection is enabled."
56997
- });
56998
- }
56999
- if (config.security?.strict) {
57000
- findings.push({
57001
- level: "info",
57002
- code: "STRICT_MODE_ENABLED",
57003
- message: "Strict security mode is enabled: loopback binding, restrictive CORS, DNS rebinding protection."
57004
- });
57005
- } else {
57006
- findings.push({
57007
- level: "info",
57008
- code: "STRICT_MODE_HINT",
57009
- message: "To enable strict security defaults, set security.strict = true in HttpOptions."
57010
- });
57011
- }
57012
- return findings;
57013
- }
57014
- function logSecurityFindings(findings, logger) {
57015
- if (findings.length === 0) return;
57016
- for (const finding of findings) {
57017
- const prefix = `[Security] ${finding.code}:`;
57018
- const message = finding.recommendation ? `${prefix} ${finding.message} ${finding.recommendation}` : `${prefix} ${finding.message}`;
57019
- if (finding.level === "warn") {
57020
- logger.warn(message);
57021
- } else {
57022
- logger.info(message);
57023
- }
57024
- }
57025
- }
57026
- function resolveBindAddress(security, deploymentMode) {
57027
- if (security?.bindAddress) {
57028
- if (security.bindAddress === "loopback") return "127.0.0.1";
57029
- if (security.bindAddress === "all") return "0.0.0.0";
57030
- return security.bindAddress;
57031
- }
57032
- if (security?.strict) {
57033
- return deploymentMode === "distributed" ? "0.0.0.0" : "127.0.0.1";
57034
- }
57035
- return "0.0.0.0";
57036
- }
57037
- var init_security_audit = __esm({
57038
- "libs/sdk/src/server/security/security-audit.ts"() {
57039
- "use strict";
57040
- }
57041
- });
57042
-
57043
57883
  // libs/sdk/src/server/server.instance.ts
57044
57884
  import { getRuntimeContext as getRuntimeContext16 } from "@frontmcp/utils";
57045
57885
  var DEFAULT_CORS, FrontMcpServerInstance;
57046
57886
  var init_server_instance = __esm({
57047
57887
  "libs/sdk/src/server/server.instance.ts"() {
57048
57888
  "use strict";
57049
- init_node_express_host();
57050
57889
  init_common();
57051
57890
  init_health2();
57052
57891
  init_metrics2();
@@ -57074,7 +57913,8 @@ var init_server_instance = __esm({
57074
57913
  this.host = this.config.hostFactory;
57075
57914
  } else {
57076
57915
  const corsConfig = this.config.cors === false ? void 0 : this.config.cors ?? DEFAULT_CORS;
57077
- this.host = new ExpressHostAdapter({
57916
+ const { ExpressHostAdapter: ExpressHostAdapter2 } = (init_node_express_host(), __toCommonJS(node_express_host_exports));
57917
+ this.host = new ExpressHostAdapter2({
57078
57918
  ...corsConfig ? { cors: corsConfig } : {},
57079
57919
  ...this.config.security ? { security: this.config.security } : {},
57080
57920
  ...this.config.bodyLimit !== void 0 ? { bodyLimit: this.config.bodyLimit } : {},
@@ -57215,7 +58055,7 @@ var front_mcp_exports = {};
57215
58055
  __export(front_mcp_exports, {
57216
58056
  FrontMcpInstance: () => FrontMcpInstance
57217
58057
  });
57218
- import { fileExists as fileExists7, randomUUID as randomUUID27, unlink as unlink2 } from "@frontmcp/utils";
58058
+ import { fileExists as fileExists7, randomUUID as randomUUID28, unlink as unlink2 } from "@frontmcp/utils";
57219
58059
  function resolveConfigInput(optionsOrClass) {
57220
58060
  if (typeof optionsOrClass === "function") {
57221
58061
  const stored = getDecoratorConfig(optionsOrClass);
@@ -57241,6 +58081,7 @@ var init_front_mcp = __esm({
57241
58081
  init_scope_registry();
57242
58082
  init_skill_instructions_helper();
57243
58083
  init_task();
58084
+ init_web_fetch_handler();
57244
58085
  init_front_mcp_providers();
57245
58086
  stdioServing = false;
57246
58087
  FrontMcpInstance = class _FrontMcpInstance2 {
@@ -57385,6 +58226,44 @@ var init_front_mcp = __esm({
57385
58226
  frontMcp.log?.info("FrontMCP handler created (serverless mode)");
57386
58227
  return server.getHandler();
57387
58228
  }
58229
+ /**
58230
+ * Creates and initializes a FrontMCP instance and returns a Web-standard
58231
+ * `fetch` handler — `(request: Request) => Promise<Response>` — backed by the
58232
+ * MCP WebStandard transport. Unlike {@link createHandler} this needs no
58233
+ * Express / Node `req`/`res` and runs on V8-isolate targets (Cloudflare
58234
+ * Workers, Deno Deploy, Bun).
58235
+ *
58236
+ * @example
58237
+ * // worker entry
58238
+ * const handler = await FrontMcpInstance.createFetchHandler(config);
58239
+ * export default { fetch: (request) => handler(request) };
58240
+ */
58241
+ static async createFetchHandler(options) {
58242
+ let inner;
58243
+ let building;
58244
+ const build = async () => {
58245
+ const frontMcp = new _FrontMcpInstance2(options);
58246
+ await frontMcp.ready;
58247
+ const scope = frontMcp.getScopes()[0];
58248
+ if (!scope) {
58249
+ throw new ServerNotFoundError();
58250
+ }
58251
+ frontMcp.log?.info("FrontMCP fetch handler created (web-standard transport)");
58252
+ return createWebFetchHandler(scope);
58253
+ };
58254
+ return async (request) => {
58255
+ if (!inner) {
58256
+ if (!building) {
58257
+ building = build().catch((err) => {
58258
+ building = void 0;
58259
+ throw err;
58260
+ });
58261
+ }
58262
+ inner = await building;
58263
+ }
58264
+ return inner(request);
58265
+ };
58266
+ }
57388
58267
  /**
57389
58268
  * Creates and initializes a FrontMCP instance without starting any server.
57390
58269
  * Returns the instance for graph extraction and introspection purposes.
@@ -57608,7 +58487,7 @@ var init_front_mcp = __esm({
57608
58487
  serve: false
57609
58488
  });
57610
58489
  if (parsedConfig.logging) {
57611
- parsedConfig.logging.enableConsole = false;
58490
+ parsedConfig.logging.enableConsole = true;
57612
58491
  const transports = parsedConfig.logging.transports ?? [];
57613
58492
  if (!transports.includes(FileLogTransportInstance)) {
57614
58493
  transports.push(FileLogTransportInstance);
@@ -57616,7 +58495,7 @@ var init_front_mcp = __esm({
57616
58495
  parsedConfig.logging.transports = transports;
57617
58496
  } else {
57618
58497
  parsedConfig["logging"] = {
57619
- enableConsole: false,
58498
+ enableConsole: true,
57620
58499
  transports: [FileLogTransportInstance]
57621
58500
  };
57622
58501
  }
@@ -57667,7 +58546,7 @@ var init_front_mcp = __esm({
57667
58546
  };
57668
58547
  const mcpServer = new McpServer2(scope.metadata.info, serverOptions);
57669
58548
  startupCleanups.push(() => mcpServer.close());
57670
- const sessionId = `stdio:${randomUUID27()}`;
58549
+ const sessionId = `stdio:${randomUUID28()}`;
57671
58550
  const handlers = createMcpHandlers2({ scope, serverOptions, composeInstructions });
57672
58551
  for (const handler of handlers) {
57673
58552
  const originalHandler = handler.handler;
@@ -57995,7 +58874,8 @@ function FrontMcp(providedMetadata) {
57995
58874
  } else if (isServerless2) {
57996
58875
  const ServerlessInstance = getFrontMcpInstance();
57997
58876
  const { setServerlessHandler: setServerlessHandler2, setServerlessHandlerPromise: setServerlessHandlerPromise2, setServerlessHandlerError: setServerlessHandlerError2 } = getServerlessHandlerFns();
57998
- const handlerPromise = ServerlessInstance.createHandler(metadata);
58877
+ const isWorker = getEnvFlag2("FRONTMCP_WORKER");
58878
+ const handlerPromise = isWorker ? ServerlessInstance.createFetchHandler(metadata) : ServerlessInstance.createHandler(metadata);
57999
58879
  setServerlessHandlerPromise2(handlerPromise);
58000
58880
  handlerPromise.then(setServerlessHandler2).catch((err) => {
58001
58881
  const e = err instanceof Error ? err : new InternalMcpError(String(err), "SERVERLESS_INIT_FAILED");
@@ -58137,6 +59017,12 @@ function remoteApp(url, options) {
58137
59017
  filter: options?.filter
58138
59018
  };
58139
59019
  }
59020
+ function frontMcpApp(metadata) {
59021
+ const FunctionalApp = class {
59022
+ };
59023
+ FrontMcpApp(metadata)(FunctionalApp);
59024
+ return FunctionalApp;
59025
+ }
58140
59026
  var APP_DECORATOR_BASENAMES, App;
58141
59027
  var init_app_decorator = __esm({
58142
59028
  "libs/sdk/src/common/decorators/app.decorator.ts"() {
@@ -60125,6 +61011,8 @@ init_direct();
60125
61011
 
60126
61012
  // libs/sdk/src/transport/index.ts
60127
61013
  init_in_memory_server();
61014
+ init_web_fetch_handler();
61015
+ init_web_standard_mcp();
60128
61016
 
60129
61017
  // libs/sdk/src/index.ts
60130
61018
  init_ext_apps2();
@@ -60354,6 +61242,7 @@ export {
60354
61242
  HttpStatus,
60355
61243
  HttpStreamSchema,
60356
61244
  HttpTextSchema,
61245
+ HttpWebResponseSchema,
60357
61246
  ImageOutputSchema,
60358
61247
  InMemoryOrchestratedTokenStore2 as InMemoryOrchestratedTokenStore,
60359
61248
  InMemoryStoreRequiredError,
@@ -60623,6 +61512,7 @@ export {
60623
61512
  annotatedFrontMcpSkillsSchema,
60624
61513
  annotatedFrontMcpToolsSchema,
60625
61514
  annotatedFrontMcpWorkflowsSchema,
61515
+ frontMcpApp as app,
60626
61516
  appAuthOptionsSchema,
60627
61517
  appFilterConfigSchema,
60628
61518
  applyPrimitiveFilter,
@@ -60637,6 +61527,7 @@ export {
60637
61527
  buildEsmResourceRecord,
60638
61528
  buildEsmShUrl,
60639
61529
  buildEsmToolRecord,
61530
+ buildPersistentWebStandardMcp,
60640
61531
  buildRemotePromptRecord,
60641
61532
  buildRemoteResourceRecord,
60642
61533
  buildRemoteResourceTemplateRecord,
@@ -60689,6 +61580,7 @@ export {
60689
61580
  createSkillInstance,
60690
61581
  createSkillStorageProvider,
60691
61582
  createTaskStore,
61583
+ createWebFetchHandler,
60692
61584
  decideIntent,
60693
61585
  decisionSchema,
60694
61586
  decryptElicitationData,
@@ -60732,6 +61624,7 @@ export {
60732
61624
  frontMcpAdapterMetadataSchema,
60733
61625
  frontMcpAgent,
60734
61626
  frontMcpAgentMetadataSchema,
61627
+ frontMcpApp,
60735
61628
  frontMcpAuthProviderMetadataSchema,
60736
61629
  frontMcpBaseSchema,
60737
61630
  frontMcpChannelMetadataSchema,
@@ -60891,7 +61784,9 @@ export {
60891
61784
  frontMcpResource as resource,
60892
61785
  frontMcpResourceTemplate as resourceTemplate,
60893
61786
  resourceUriMatches,
61787
+ runHttpRequestFlowWeb,
60894
61788
  runTaskInBackground,
61789
+ runWebStandardMcp,
60895
61790
  satisfiesRange,
60896
61791
  scanSkillResources,
60897
61792
  secureStoreConfigSchema,