@frontmcp/sdk 1.4.1 → 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 +1187 -294
  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 +1421 -520
  35. package/logger/instances/instance.file-logger.d.ts.map +1 -1
  36. package/package.json +13 -13
  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,5 +1,5 @@
1
1
  import { createRequire as __frontmcpCreateRequire } from 'module';
2
- const require = __frontmcpCreateRequire(import.meta.url);
2
+ const require = __frontmcpCreateRequire(import.meta.url || 'file:///');
3
3
  var __defProp = Object.defineProperty;
4
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -11,11 +11,20 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
11
11
  if (typeof require !== "undefined") return require.apply(this, arguments);
12
12
  throw Error('Dynamic require of "' + x + '" is not supported');
13
13
  });
14
- var __esm = (fn, res) => function __init() {
15
- 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
+ }
16
21
  };
17
22
  var __commonJS = (cb, mod) => function __require2() {
18
- 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
+ }
19
28
  };
20
29
  var __export = (target, all) => {
21
30
  for (var name41 in all)
@@ -667,7 +676,10 @@ var init_server_tokens = __esm({
667
676
  intent: tokenFactory.meta("intent"),
668
677
  auth: tokenFactory.meta("auth"),
669
678
  sessionId: tokenFactory.meta("sessionId"),
670
- reinitialize: tokenFactory.meta("reinitialize")
679
+ reinitialize: tokenFactory.meta("reinitialize"),
680
+ webRequest: tokenFactory.meta("webRequest"),
681
+ webCtx: tokenFactory.meta("webCtx"),
682
+ webTransport: tokenFactory.meta("webTransport")
671
683
  };
672
684
  }
673
685
  });
@@ -1374,7 +1386,7 @@ import {
1374
1386
  JSONRPCResponseSchema
1375
1387
  } from "@frontmcp/protocol";
1376
1388
  import { randomUUID } from "@frontmcp/utils";
1377
- 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;
1378
1390
  var init_http_output_schema = __esm({
1379
1391
  "libs/sdk/src/common/schemas/http-output.schema.ts"() {
1380
1392
  "use strict";
@@ -1426,6 +1438,13 @@ var init_http_output_schema = __esm({
1426
1438
  kind: z2.literal("next")
1427
1439
  }).passthrough();
1428
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
+ });
1429
1448
  HttpTextSchema = z2.object({
1430
1449
  kind: z2.literal("text"),
1431
1450
  status: HttpStatus.refine((s) => statusAllowsBody(s) && !REDIRECTS.includes(s), {
@@ -1518,7 +1537,8 @@ var init_http_output_schema = __esm({
1518
1537
  HttpProblemSchema,
1519
1538
  HttpEmptySchema,
1520
1539
  HttpNextSchema,
1521
- HttpConsumedSchema
1540
+ HttpConsumedSchema,
1541
+ HttpWebResponseSchema
1522
1542
  ]);
1523
1543
  httpRespond = {
1524
1544
  json: (body, extra = {}) => {
@@ -1618,6 +1638,9 @@ var init_http_output_schema = __esm({
1618
1638
  consumed() {
1619
1639
  return { kind: "consumed" };
1620
1640
  },
1641
+ webResponse(response) {
1642
+ return { kind: "web-response", response };
1643
+ },
1621
1644
  empty(status = 204, headers) {
1622
1645
  return { kind: "empty", status, headers };
1623
1646
  },
@@ -2174,6 +2197,18 @@ var init_sqlite = __esm({
2174
2197
  });
2175
2198
 
2176
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
+ });
2177
2212
  import { z as z12 } from "@frontmcp/lazy-zod";
2178
2213
  import { isServerless } from "@frontmcp/utils";
2179
2214
  function expandProtocolConfig(protocol) {
@@ -2493,7 +2528,8 @@ var init_schema10 = __esm({
2493
2528
  sep2640InInstructions: z15.boolean().optional().default(false),
2494
2529
  cache: skillsConfigCacheOptionsSchema.optional(),
2495
2530
  audit: skillsConfigAuditOptionsSchema.optional(),
2496
- 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()
2497
2533
  });
2498
2534
  }
2499
2535
  });
@@ -4714,6 +4750,12 @@ var init_elicitation_error = __esm({
4714
4750
  this.toolInput = toolInput;
4715
4751
  this.ttl = ttl;
4716
4752
  }
4753
+ elicitId;
4754
+ elicitMessage;
4755
+ schema;
4756
+ toolName;
4757
+ toolInput;
4758
+ ttl;
4717
4759
  getPublicMessage() {
4718
4760
  return this.elicitMessage;
4719
4761
  }
@@ -6194,30 +6236,30 @@ var require_dist = __commonJS({
6194
6236
  sqliteStorageOptionsSchema: () => sqliteStorageOptionsSchema
6195
6237
  });
6196
6238
  module.exports = __toCommonJS2(index_exports);
6197
- var import_utils101 = __require("@frontmcp/utils");
6239
+ var import_utils103 = __require("@frontmcp/utils");
6198
6240
  var HKDF_SALT = new TextEncoder().encode("frontmcp-sqlite-storage-v1");
6199
6241
  var HKDF_INFO = new TextEncoder().encode("aes-256-gcm-value-encryption");
6200
6242
  var KEY_LENGTH = 32;
6201
6243
  function deriveEncryptionKey(secret) {
6202
6244
  const ikm = new TextEncoder().encode(secret);
6203
- 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);
6204
6246
  }
6205
6247
  var SEPARATOR = ":";
6206
6248
  function encryptValue(key, plaintext) {
6207
- const iv = (0, import_utils101.randomBytes)(12);
6249
+ const iv = (0, import_utils103.randomBytes)(12);
6208
6250
  const plaintextBytes = new TextEncoder().encode(plaintext);
6209
- const { ciphertext, tag } = (0, import_utils101.encryptAesGcm)(key, plaintextBytes, iv);
6210
- 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);
6211
6253
  }
6212
6254
  function decryptValue(key, encrypted) {
6213
6255
  const parts = encrypted.split(SEPARATOR);
6214
6256
  if (parts.length !== 3) {
6215
6257
  throw new Error("Invalid encrypted value format");
6216
6258
  }
6217
- const iv = (0, import_utils101.base64urlDecode)(parts[0]);
6218
- const tag = (0, import_utils101.base64urlDecode)(parts[1]);
6219
- const ciphertext = (0, import_utils101.base64urlDecode)(parts[2]);
6220
- 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);
6221
6263
  return new TextDecoder().decode(plaintext);
6222
6264
  }
6223
6265
  var import_utils210 = __require("@frontmcp/utils");
@@ -7338,6 +7380,8 @@ var init_task_notifier = __esm({
7338
7380
  this.notifications = notifications;
7339
7381
  this.logger = logger;
7340
7382
  }
7383
+ notifications;
7384
+ logger;
7341
7385
  sendStatus(record) {
7342
7386
  const params = {
7343
7387
  ...toWireShape(record)
@@ -7493,6 +7537,7 @@ var init_in_process_task_runner = __esm({
7493
7537
  constructor(deps) {
7494
7538
  this.deps = deps;
7495
7539
  }
7540
+ deps;
7496
7541
  kind = "in-process";
7497
7542
  async run(record, context) {
7498
7543
  await this.deps.store.update(record.taskId, record.sessionId, {
@@ -7547,6 +7592,7 @@ var init_cli_task_runner = __esm({
7547
7592
  constructor(deps) {
7548
7593
  this.deps = deps;
7549
7594
  }
7595
+ deps;
7550
7596
  kind = "cli";
7551
7597
  async run(record, _context) {
7552
7598
  const { exe, args } = this.resolveCommand();
@@ -7901,6 +7947,9 @@ var init_tasks_result_flow = __esm({
7901
7947
  this.taskId = taskId;
7902
7948
  this.name = "JsonRpcReplayError";
7903
7949
  }
7950
+ code;
7951
+ data;
7952
+ taskId;
7904
7953
  toJsonRpcError() {
7905
7954
  const out = {
7906
7955
  code: this.code,
@@ -8124,6 +8173,72 @@ var init_task = __esm({
8124
8173
  }
8125
8174
  });
8126
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
+
8127
8242
  // libs/sdk/src/transport/mcp-handlers/mcp-error.utils.ts
8128
8243
  import { McpError as McpError2 } from "@frontmcp/protocol";
8129
8244
  function toSdkMcpError(err) {
@@ -8393,6 +8508,8 @@ var init_notification_service = __esm({
8393
8508
  this.options = options;
8394
8509
  this.logger = scope.logger.child("NotificationService");
8395
8510
  }
8511
+ scope;
8512
+ options;
8396
8513
  logger;
8397
8514
  servers = /* @__PURE__ */ new Map();
8398
8515
  unsubscribers = [];
@@ -10808,58 +10925,7 @@ async function createInMemoryServer(scope, options) {
10808
10925
  const sessionId = options?.sessionId ?? `in-memory:${randomUUID4()}`;
10809
10926
  const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
10810
10927
  let currentAuthInfo = options?.authInfo ?? {};
10811
- const hasRemoteApps = scope.apps?.getApps().some((app) => app.isRemote) ?? false;
10812
- const hasPrompts = scope.prompts.hasAny() || hasRemoteApps;
10813
- const hasResources = scope.resources.hasAny() || hasRemoteApps;
10814
- const completionsCapability = hasPrompts || hasResources ? { completions: {} } : {};
10815
- const remoteCapabilities = hasRemoteApps ? {
10816
- tools: { listChanged: true },
10817
- resources: { subscribe: true, listChanged: true },
10818
- prompts: { listChanged: true }
10819
- } : {};
10820
- const skillsCapabilities = scope.skills?.getCapabilities() ?? {};
10821
- const toolsCapabilities = scope.tools.getCapabilities();
10822
- const resourcesCapabilities = scope.resources.getCapabilities();
10823
- const promptsCapabilities = scope.prompts.getCapabilities();
10824
- const agentsCapabilities = scope.agents.getCapabilities();
10825
- const taskCapabilities = computeTaskCapabilities(scope);
10826
- const fragments = [
10827
- remoteCapabilities,
10828
- toolsCapabilities,
10829
- resourcesCapabilities,
10830
- promptsCapabilities,
10831
- agentsCapabilities,
10832
- skillsCapabilities,
10833
- completionsCapability,
10834
- taskCapabilities
10835
- ];
10836
- const experimental = {};
10837
- const extensions = {};
10838
- for (const cap2 of fragments) {
10839
- if (cap2["experimental"] && typeof cap2["experimental"] === "object") {
10840
- Object.assign(experimental, cap2["experimental"]);
10841
- }
10842
- if (cap2["extensions"] && typeof cap2["extensions"] === "object") {
10843
- Object.assign(extensions, cap2["extensions"]);
10844
- }
10845
- }
10846
- const baseCapabilities = {
10847
- ...remoteCapabilities,
10848
- ...toolsCapabilities,
10849
- ...resourcesCapabilities,
10850
- ...promptsCapabilities,
10851
- ...agentsCapabilities,
10852
- ...completionsCapability,
10853
- ...taskCapabilities,
10854
- logging: {}
10855
- };
10856
- if (Object.keys(experimental).length > 0) baseCapabilities["experimental"] = experimental;
10857
- if (Object.keys(extensions).length > 0) baseCapabilities["extensions"] = extensions;
10858
- const serverOptions = {
10859
- instructions: "",
10860
- capabilities: baseCapabilities,
10861
- serverInfo: scope.metadata.info
10862
- };
10928
+ const serverOptions = buildScopedServerOptions(scope);
10863
10929
  const mcpServer = new McpServer2(scope.metadata.info, serverOptions);
10864
10930
  const handlers = createMcpHandlers2({ scope, serverOptions });
10865
10931
  for (const handler of handlers) {
@@ -10892,7 +10958,7 @@ async function createInMemoryServer(scope, options) {
10892
10958
  var init_in_memory_server = __esm({
10893
10959
  "libs/sdk/src/transport/in-memory-server.ts"() {
10894
10960
  "use strict";
10895
- init_task();
10961
+ init_build_scoped_server_options();
10896
10962
  }
10897
10963
  });
10898
10964
 
@@ -10906,29 +10972,29 @@ import {
10906
10972
  } from "@frontmcp/protocol";
10907
10973
  import { fileExists as fileExists2, pathResolve, randomUUID as randomUUID5 } from "@frontmcp/utils";
10908
10974
  function findFileFromRoot(root, relativePath) {
10909
- const fs2 = __require("fs");
10975
+ const fs = __require("fs");
10910
10976
  const path3 = __require("path");
10911
10977
  const cleanRelative = relativePath.replace(/^\.\//, "");
10912
10978
  const searchDirs = ["src", "."];
10913
10979
  for (const srcDir of searchDirs) {
10914
10980
  const srcRoot = path3.join(root, srcDir);
10915
- if (!fs2.existsSync(srcRoot)) continue;
10916
- const found = walkForFile(srcRoot, cleanRelative, fs2, path3);
10981
+ if (!fs.existsSync(srcRoot)) continue;
10982
+ const found = walkForFile(srcRoot, cleanRelative, fs, path3);
10917
10983
  if (found) return found;
10918
10984
  }
10919
10985
  return void 0;
10920
10986
  }
10921
- function walkForFile(dir, targetRelative, fs2, path3, maxDepth = 10) {
10987
+ function walkForFile(dir, targetRelative, fs, path3, maxDepth = 10) {
10922
10988
  const candidate = path3.join(dir, targetRelative);
10923
- if (fs2.existsSync(candidate)) {
10989
+ if (fs.existsSync(candidate)) {
10924
10990
  return { absolute: candidate, baseDir: dir };
10925
10991
  }
10926
10992
  if (maxDepth <= 0) return void 0;
10927
10993
  try {
10928
- const entries = fs2.readdirSync(dir, { withFileTypes: true });
10994
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
10929
10995
  for (const entry of entries) {
10930
10996
  if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules" && entry.name !== "dist") {
10931
- 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);
10932
10998
  if (result) return result;
10933
10999
  }
10934
11000
  }
@@ -12108,13 +12174,15 @@ var init_health2 = __esm({
12108
12174
  });
12109
12175
 
12110
12176
  // libs/sdk/src/logger/instances/instance.file-logger.ts
12111
- import * as fs from "fs";
12112
12177
  import * as os from "os";
12113
12178
  import * as path2 from "path";
12179
+ function getFs() {
12180
+ return _fs ??= __require("fs");
12181
+ }
12114
12182
  function stripAnsi(str) {
12115
12183
  return str.split(ESC).map((s) => s.replace(/\[[0-9;]*m/, "")).join("");
12116
12184
  }
12117
- var LOG_LEVEL_LABELS, ESC, DEFAULT_LOGS_MAX, FileLogTransportInstance;
12185
+ var _fs, LOG_LEVEL_LABELS, ESC, DEFAULT_LOGS_MAX, FileLogTransportInstance;
12118
12186
  var init_instance_file_logger = __esm({
12119
12187
  "libs/sdk/src/logger/instances/instance.file-logger.ts"() {
12120
12188
  "use strict";
@@ -12145,10 +12213,10 @@ var init_instance_file_logger = __esm({
12145
12213
  return;
12146
12214
  }
12147
12215
  try {
12148
- fs.mkdirSync(this.logDir, { recursive: true });
12216
+ getFs().mkdirSync(this.logDir, { recursive: true });
12149
12217
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "_");
12150
12218
  const filePath = path2.join(this.logDir, `${this.appName}-${ts}.log`);
12151
- this.fd = fs.openSync(filePath, "a");
12219
+ this.fd = getFs().openSync(filePath, "a");
12152
12220
  this.rotate(isNaN(logsMax) ? DEFAULT_LOGS_MAX : logsMax);
12153
12221
  } catch {
12154
12222
  this.fd = void 0;
@@ -12158,7 +12226,7 @@ var init_instance_file_logger = __esm({
12158
12226
  close() {
12159
12227
  if (this.fd !== void 0) {
12160
12228
  try {
12161
- fs.closeSync(this.fd);
12229
+ getFs().closeSync(this.fd);
12162
12230
  } catch {
12163
12231
  }
12164
12232
  this.fd = void 0;
@@ -12173,7 +12241,7 @@ var init_instance_file_logger = __esm({
12173
12241
  const line = `[${ts}] ${level}${prefix} ${message}
12174
12242
  `;
12175
12243
  try {
12176
- fs.writeSync(this.fd, line);
12244
+ getFs().writeSync(this.fd, line);
12177
12245
  } catch {
12178
12246
  }
12179
12247
  }
@@ -12181,12 +12249,12 @@ var init_instance_file_logger = __esm({
12181
12249
  rotate(maxFiles) {
12182
12250
  try {
12183
12251
  const prefix = `${this.appName}-`;
12184
- 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();
12185
12253
  const excess = files.length - maxFiles;
12186
12254
  if (excess <= 0) return;
12187
12255
  for (let i = 0; i < excess; i++) {
12188
12256
  try {
12189
- fs.unlinkSync(path2.join(this.logDir, files[i]));
12257
+ getFs().unlinkSync(path2.join(this.logDir, files[i]));
12190
12258
  } catch {
12191
12259
  }
12192
12260
  }
@@ -12344,6 +12412,8 @@ var init_instance_logger = __esm({
12344
12412
  this.transports = transports;
12345
12413
  this.consoleTransport = consoleTransport;
12346
12414
  }
12415
+ config;
12416
+ getTransports;
12347
12417
  level;
12348
12418
  prefix;
12349
12419
  transports;
@@ -15236,6 +15306,7 @@ var init_tool_instance = __esm({
15236
15306
  super(args);
15237
15307
  this.record = record;
15238
15308
  }
15309
+ record;
15239
15310
  execute(input) {
15240
15311
  return this.record.provide(input, this);
15241
15312
  }
@@ -15342,6 +15413,10 @@ var init_base_adapter = __esm({
15342
15413
  this.raw = raw;
15343
15414
  this.name = "LlmAdapterError";
15344
15415
  }
15416
+ provider;
15417
+ code;
15418
+ statusCode;
15419
+ raw;
15345
15420
  };
15346
15421
  }
15347
15422
  });
@@ -16292,6 +16367,7 @@ var init_providers = __esm({
16292
16367
  constructor(options) {
16293
16368
  this.options = options;
16294
16369
  }
16370
+ options;
16295
16371
  adapter = null;
16296
16372
  getAdapter() {
16297
16373
  if (this.adapter) {
@@ -16575,6 +16651,8 @@ var init_flow_context_providers = __esm({
16575
16651
  this.baseProviders = baseProviders;
16576
16652
  this.contextDeps = contextDeps;
16577
16653
  }
16654
+ baseProviders;
16655
+ contextDeps;
16578
16656
  get(token) {
16579
16657
  if (this.contextDeps.has(token)) {
16580
16658
  return this.contextDeps.get(token);
@@ -17325,6 +17403,7 @@ var init_prompt_instance = __esm({
17325
17403
  super(args);
17326
17404
  this.record = record;
17327
17405
  }
17406
+ record;
17328
17407
  execute(args) {
17329
17408
  return this.record.provide(args, this);
17330
17409
  }
@@ -19492,6 +19571,7 @@ var init_resource_instance = __esm({
19492
19571
  super(args);
19493
19572
  this.record = record;
19494
19573
  }
19574
+ record;
19495
19575
  execute(uri, params) {
19496
19576
  return this.record.provide(uri, params, this);
19497
19577
  }
@@ -23133,6 +23213,8 @@ var init_flow_interface = __esm({
23133
23213
  this.type = type;
23134
23214
  this.output = output;
23135
23215
  }
23216
+ type;
23217
+ output;
23136
23218
  static respond(output) {
23137
23219
  throw new _FlowControl("respond", output);
23138
23220
  }
@@ -23161,6 +23243,11 @@ var init_flow_interface = __esm({
23161
23243
  this.input = metadata.inputSchema?.parse?.(rawInput);
23162
23244
  this.scopeLogger = scope.logger;
23163
23245
  }
23246
+ metadata;
23247
+ rawInput;
23248
+ scope;
23249
+ appendContextHooks;
23250
+ deps;
23164
23251
  input;
23165
23252
  state = FlowState.create({});
23166
23253
  scopeLogger;
@@ -23814,6 +23901,18 @@ async function writeHttpResponse(res, value) {
23814
23901
  res.status(out.status).end();
23815
23902
  return;
23816
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
+ }
23817
23916
  }
23818
23917
  }
23819
23918
  var init_server_validation = __esm({
@@ -24030,6 +24129,34 @@ var init_flow_instance = __esm({
24030
24129
  const results = await Promise.all(canActivate.map((m) => m(request, this.scope)));
24031
24130
  return results.every((r) => r);
24032
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
+ }
24033
24160
  /**
24034
24161
  * Get FrontMcpContextStorage from providers (with fallback).
24035
24162
  * Returns undefined if not available (backward compatibility).
@@ -24431,6 +24558,21 @@ var init_flow_registry = __esm({
24431
24558
  )
24432
24559
  );
24433
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
+ }
24434
24576
  /**
24435
24577
  * Get FrontMcpContextStorage from providers (with fallback).
24436
24578
  * Returns undefined if not available (backward compatibility).
@@ -25019,12 +25161,51 @@ var init_skill_validation_error = __esm({
25019
25161
  }
25020
25162
  });
25021
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
+
25022
25198
  // libs/sdk/src/skill/providers/memory-skill.provider.ts
25023
- 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
+ }
25024
25204
  var STOP_WORDS, MemorySkillProvider;
25025
25205
  var init_memory_skill_provider = __esm({
25026
25206
  "libs/sdk/src/skill/providers/memory-skill.provider.ts"() {
25027
25207
  "use strict";
25208
+ init_optional_dependency_util();
25028
25209
  STOP_WORDS = /* @__PURE__ */ new Set([
25029
25210
  // Articles & Determiners
25030
25211
  "the",
@@ -25100,19 +25281,118 @@ var init_memory_skill_provider = __esm({
25100
25281
  MemorySkillProvider = class {
25101
25282
  type = "memory";
25102
25283
  vectorDB;
25284
+ vectorDBReady;
25103
25285
  skills = /* @__PURE__ */ new Map();
25104
25286
  defaultTopK;
25105
25287
  defaultMinScore;
25106
25288
  toolValidator;
25107
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;
25108
25301
  constructor(options = {}) {
25109
25302
  this.defaultTopK = options.defaultTopK ?? 10;
25110
25303
  this.defaultMinScore = options.defaultMinScore ?? 0.1;
25111
25304
  this.toolValidator = options.toolValidator;
25112
- 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 = {
25113
25318
  defaultTopK: this.defaultTopK,
25114
25319
  defaultSimilarityThreshold: this.defaultMinScore
25115
- });
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;
25116
25396
  }
25117
25397
  /**
25118
25398
  * Set the tool validator after construction.
@@ -25122,9 +25402,13 @@ var init_memory_skill_provider = __esm({
25122
25402
  this.toolValidator = validator;
25123
25403
  }
25124
25404
  async initialize() {
25405
+ await this.vectorDBReady;
25125
25406
  this.initialized = true;
25126
25407
  }
25127
25408
  async search(query, options = {}) {
25409
+ if (query.trim().length === 0) {
25410
+ return [];
25411
+ }
25128
25412
  const {
25129
25413
  topK = this.defaultTopK,
25130
25414
  tags,
@@ -25155,10 +25439,16 @@ var init_memory_skill_provider = __esm({
25155
25439
  }
25156
25440
  return true;
25157
25441
  };
25158
- let results = await this.vectorDB.search(query, {
25442
+ const db = await this.db();
25443
+ await this.ensureIndexed();
25444
+ let results = await db.search(query, {
25159
25445
  topK,
25160
25446
  threshold: minScore,
25161
- 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 } : {}
25162
25452
  });
25163
25453
  if (results.length === 0 && query.trim().length > 0 && this.skills.size > 0) {
25164
25454
  results = this.fallbackTextSearch(query, topK, filter);
@@ -25266,29 +25556,35 @@ var init_memory_skill_provider = __esm({
25266
25556
  }
25267
25557
  async add(skill) {
25268
25558
  this.skills.set(skill.id, skill);
25269
- this.indexSkill(skill);
25559
+ await this.indexSkill(skill);
25270
25560
  }
25271
25561
  async update(skillId, skill) {
25272
25562
  const normalizedSkill = skill.id !== skillId ? { ...skill, id: skillId } : skill;
25273
- if (this.vectorDB.hasDocument(skillId)) {
25274
- this.vectorDB.removeDocument(skillId);
25563
+ const db = await this.db();
25564
+ if (db.hasDocument(skillId)) {
25565
+ db.removeDocument(skillId);
25275
25566
  }
25276
25567
  this.skills.set(skillId, normalizedSkill);
25277
- this.indexSkill(normalizedSkill);
25568
+ await this.indexSkill(normalizedSkill);
25278
25569
  }
25279
25570
  async remove(skillId) {
25280
25571
  this.skills.delete(skillId);
25281
- if (this.vectorDB.hasDocument(skillId)) {
25282
- this.vectorDB.removeDocument(skillId);
25572
+ const db = await this.db();
25573
+ if (db.hasDocument(skillId)) {
25574
+ db.removeDocument(skillId);
25283
25575
  }
25576
+ this.indexReady = false;
25284
25577
  }
25285
25578
  async clear() {
25286
25579
  this.skills.clear();
25287
- this.vectorDB.clear();
25580
+ const db = await this.db().catch(() => void 0);
25581
+ db?.clear();
25582
+ this.indexReady = false;
25288
25583
  }
25289
25584
  async dispose() {
25290
25585
  this.skills.clear();
25291
- this.vectorDB.clear();
25586
+ const db = await this.db().catch(() => void 0);
25587
+ db?.clear();
25292
25588
  this.initialized = false;
25293
25589
  }
25294
25590
  /**
@@ -25307,13 +25603,14 @@ var init_memory_skill_provider = __esm({
25307
25603
  }
25308
25604
  };
25309
25605
  });
25310
- this.vectorDB.addDocuments(documents);
25311
- this.vectorDB.reindex();
25606
+ const db = await this.db();
25607
+ db.addDocuments(documents);
25608
+ this.indexReady = false;
25312
25609
  }
25313
25610
  /**
25314
25611
  * Index a single skill in the vector database.
25315
25612
  */
25316
- indexSkill(skill) {
25613
+ async indexSkill(skill) {
25317
25614
  const document = {
25318
25615
  id: skill.id,
25319
25616
  text: this.buildSearchableText(skill),
@@ -25323,8 +25620,9 @@ var init_memory_skill_provider = __esm({
25323
25620
  skill
25324
25621
  }
25325
25622
  };
25326
- this.vectorDB.addDocuments([document]);
25327
- this.vectorDB.reindex();
25623
+ const db = await this.db();
25624
+ db.addDocuments([document]);
25625
+ this.indexReady = false;
25328
25626
  }
25329
25627
  /**
25330
25628
  * Build searchable text for TF-IDF indexing.
@@ -26061,7 +26359,9 @@ var init_skill_registry = __esm({
26061
26359
  this.options = options ?? {};
26062
26360
  this.storageProvider = new MemorySkillProvider({
26063
26361
  defaultTopK: 10,
26064
- defaultMinScore: 0.1
26362
+ defaultMinScore: 0.1,
26363
+ ...this.options.scoring ? { scoring: this.options.scoring } : {},
26364
+ ...this.options.indexCache ? { indexCache: this.options.indexCache } : {}
26065
26365
  });
26066
26366
  this.buildGraph();
26067
26367
  this.ready = this.initialize();
@@ -26271,6 +26571,31 @@ var init_skill_registry = __esm({
26271
26571
  * provider update lagged or failed) would mask the newer dynamic content.
26272
26572
  * Provider-only rows pass through unchanged; overlay-only rows are appended.
26273
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
+ }
26274
26599
  async search(query, options) {
26275
26600
  const baseResults = await this.storageProvider.search(query, options);
26276
26601
  if (this.dynamicContents.size === 0) return baseResults;
@@ -27320,6 +27645,7 @@ var init_agent_scope = __esm({
27320
27645
  };
27321
27646
  this.ready = this.initialize();
27322
27647
  }
27648
+ metadata;
27323
27649
  id;
27324
27650
  entryPath;
27325
27651
  routeBase;
@@ -27489,6 +27815,7 @@ var init_agent_scope = __esm({
27489
27815
  this.fullPath = agentScope.fullPath;
27490
27816
  this.logger = agentScope.logger;
27491
27817
  }
27818
+ agentScope;
27492
27819
  id;
27493
27820
  entryPath;
27494
27821
  routeBase;
@@ -28220,6 +28547,7 @@ var init_agent_instance = __esm({
28220
28547
  super(args);
28221
28548
  this.record = record;
28222
28549
  }
28550
+ record;
28223
28551
  async execute(input) {
28224
28552
  return this.record.provide(input, this);
28225
28553
  }
@@ -31369,7 +31697,7 @@ var init_semver_utils = __esm({
31369
31697
  });
31370
31698
 
31371
31699
  // libs/sdk/src/esm-loader/esm-cache.ts
31372
- import { sha256Hex as sha256Hex3, isValidMcpUri as isValidMcpUri6 } from "@frontmcp/utils";
31700
+ import { sha256Hex as sha256Hex4, isValidMcpUri as isValidMcpUri6 } from "@frontmcp/utils";
31373
31701
  function isBrowserEnv() {
31374
31702
  return typeof window !== "undefined" || typeof globalThis !== "undefined" && typeof globalThis.document !== "undefined";
31375
31703
  }
@@ -31406,8 +31734,8 @@ function getDefaultCacheDir() {
31406
31734
  const path3 = __require("node:path");
31407
31735
  try {
31408
31736
  const nodeModulesDir = path3.join(process.cwd(), "node_modules");
31409
- const fs2 = __require("node:fs");
31410
- if (fs2.existsSync(nodeModulesDir)) {
31737
+ const fs = __require("node:fs");
31738
+ if (fs.existsSync(nodeModulesDir)) {
31411
31739
  return path3.join(nodeModulesDir, ".cache", "frontmcp-esm");
31412
31740
  }
31413
31741
  } catch {
@@ -31422,19 +31750,30 @@ function getDefaultCacheDir() {
31422
31750
  return "";
31423
31751
  }
31424
31752
  }
31425
- var DEFAULT_CACHE_DIR, DEFAULT_MAX_AGE_MS, EsmCacheManager;
31753
+ var DEFAULT_CACHE_DIR, DEFAULT_MAX_AGE_MS, DEFAULT_MAX_ENTRIES, EsmCacheManager;
31426
31754
  var init_esm_cache = __esm({
31427
31755
  "libs/sdk/src/esm-loader/esm-cache.ts"() {
31428
31756
  "use strict";
31429
31757
  DEFAULT_CACHE_DIR = getDefaultCacheDir();
31430
31758
  DEFAULT_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
31759
+ DEFAULT_MAX_ENTRIES = 100;
31431
31760
  EsmCacheManager = class {
31432
31761
  cacheDir;
31433
31762
  maxAgeMs;
31763
+ maxEntries;
31434
31764
  memoryStore = /* @__PURE__ */ new Map();
31435
31765
  constructor(options) {
31436
31766
  this.cacheDir = options?.cacheDir ?? DEFAULT_CACHE_DIR;
31437
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
+ }
31438
31777
  }
31439
31778
  /**
31440
31779
  * Get a cached ESM bundle entry if it exists and is not expired.
@@ -31468,6 +31807,7 @@ var init_esm_cache = __esm({
31468
31807
  return void 0;
31469
31808
  }
31470
31809
  this.memoryStore.set(memKey, meta);
31810
+ this.evictIfNeeded();
31471
31811
  return meta;
31472
31812
  } catch {
31473
31813
  return void 0;
@@ -31514,6 +31854,7 @@ var init_esm_cache = __esm({
31514
31854
  bundleContent
31515
31855
  };
31516
31856
  this.memoryStore.set(memKey, entry);
31857
+ this.evictIfNeeded();
31517
31858
  return entry;
31518
31859
  }
31519
31860
  /**
@@ -31607,7 +31948,7 @@ var init_esm_cache = __esm({
31607
31948
  */
31608
31949
  getEntryDir(packageName, version) {
31609
31950
  const path3 = __require("node:path");
31610
- const hash = sha256Hex3(`${packageName}@${version}`);
31951
+ const hash = sha256Hex4(`${packageName}@${version}`);
31611
31952
  return path3.join(this.cacheDir, hash);
31612
31953
  }
31613
31954
  };
@@ -31959,6 +32300,13 @@ var init_version_resolver = __esm({
31959
32300
  });
31960
32301
 
31961
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
+ }
31962
32310
  var EsmModuleLoader;
31963
32311
  var init_esm_module_loader = __esm({
31964
32312
  "libs/sdk/src/esm-loader/esm-module-loader.ts"() {
@@ -32090,9 +32438,7 @@ var init_esm_module_loader = __esm({
32090
32438
  */
32091
32439
  async importFromPath(filePath) {
32092
32440
  const { pathToFileURL } = await import("node:url");
32093
- const fileUrl = pathToFileURL(filePath).href;
32094
- const bustUrl = `${fileUrl}?t=${Date.now()}`;
32095
- return import(bustUrl);
32441
+ return importComputed(pathToFileURL(filePath).href);
32096
32442
  }
32097
32443
  /**
32098
32444
  * Import a bundle from its source text.
@@ -32121,27 +32467,22 @@ var init_esm_module_loader = __esm({
32121
32467
  const blob = new Blob([bundleContent], { type: "text/javascript" });
32122
32468
  const url = URL.createObjectURL(blob);
32123
32469
  try {
32124
- return await import(
32125
- /* webpackIgnore: true */
32126
- url
32127
- );
32470
+ return await importComputed(url);
32128
32471
  } finally {
32129
32472
  URL.revokeObjectURL(url);
32130
32473
  }
32131
32474
  }
32132
- const { mkdtemp, writeFile, rm } = await import("@frontmcp/utils");
32475
+ const { ensureDir, fileExists: fileExists9, sha256Hex: sha256Hex9, writeFile } = await import("@frontmcp/utils");
32133
32476
  const nodePath = await import("node:path");
32134
32477
  const nodeOs = await import("node:os");
32135
32478
  const { pathToFileURL } = await import("node:url");
32136
- const tempDir = await mkdtemp(nodePath.join(nodeOs.tmpdir(), "frontmcp-esm-"));
32137
- const tempPath = nodePath.join(tempDir, "bundle.mjs");
32138
- 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)) {
32139
32483
  await writeFile(tempPath, bundleContent);
32140
- return await import(pathToFileURL(tempPath).href + `?t=${Date.now()}`);
32141
- } finally {
32142
- await rm(tempDir, { recursive: true, force: true }).catch(() => {
32143
- });
32144
32484
  }
32485
+ return importComputed(pathToFileURL(tempPath).href);
32145
32486
  }
32146
32487
  };
32147
32488
  }
@@ -32920,7 +33261,7 @@ var init_auth_ui_contract = __esm({
32920
33261
  });
32921
33262
 
32922
33263
  // libs/sdk/src/auth/auth-ui/auth-ui.registry.ts
32923
- 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";
32924
33265
  function timingSafeEqualStr(a, b) {
32925
33266
  if (a.length !== b.length) return false;
32926
33267
  let diff = 0;
@@ -33049,7 +33390,7 @@ var init_auth_ui_registry = __esm({
33049
33390
  mintCsrf(pendingAuthId) {
33050
33391
  const existing = this.pending.get(pendingAuthId);
33051
33392
  if (existing) return existing.csrf;
33052
- const csrf = sha256Hex4(randomBytes3(32)).slice(0, 43);
33393
+ const csrf = sha256Hex5(randomBytes3(32)).slice(0, 43);
33053
33394
  this.pending.set(pendingAuthId, { csrf, addedItems: {}, createdAt: Date.now() });
33054
33395
  this.pruneExpired();
33055
33396
  return csrf;
@@ -33102,7 +33443,7 @@ var init_auth_ui_registry = __esm({
33102
33443
  ensurePending(pendingAuthId) {
33103
33444
  let state = this.pending.get(pendingAuthId);
33104
33445
  if (!state) {
33105
- 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() };
33106
33447
  this.pending.set(pendingAuthId, state);
33107
33448
  this.pruneExpired();
33108
33449
  }
@@ -33959,6 +34300,15 @@ var init_oauth_authorize_flow = __esm({
33959
34300
  return;
33960
34301
  }
33961
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
+ }
33962
34312
  }
33963
34313
  async checkIfAuthorized() {
33964
34314
  }
@@ -34223,7 +34573,7 @@ var init_oauth_authorize_flow = __esm({
34223
34573
  }
34224
34574
  const state = buildState({
34225
34575
  pendingAuthId,
34226
- submitUrl: `${this.scope.fullPath}/oauth/callback`,
34576
+ submitUrl: "/oauth/callback",
34227
34577
  extraUrl: authUiExtraPath(this.scope.fullPath),
34228
34578
  csrfToken,
34229
34579
  addedItems: authUi.getAddedItems(pendingAuthId)
@@ -34369,7 +34719,7 @@ var init_oauth_authorize_flow = __esm({
34369
34719
  */
34370
34720
  renderLoginPage(params) {
34371
34721
  const { pendingAuthId, clientId, clientName, scope, logoUri } = params;
34372
- const callbackPath = `${this.scope.fullPath}/oauth/callback`;
34722
+ const callbackPath = "/oauth/callback";
34373
34723
  const auth = this.scope.metadata.auth;
34374
34724
  const login = auth && auth.mode === "local" ? auth.login : void 0;
34375
34725
  const ctx = {
@@ -34388,7 +34738,7 @@ var init_oauth_authorize_flow = __esm({
34388
34738
  */
34389
34739
  renderIncrementalAuthPage(params) {
34390
34740
  const { pendingAuthId, appId, appName, appDescription, toolId } = params;
34391
- const callbackPath = `${this.scope.fullPath}/oauth/callback`;
34741
+ const callbackPath = "/oauth/callback";
34392
34742
  const app = {
34393
34743
  appId,
34394
34744
  appName,
@@ -34406,7 +34756,7 @@ var init_oauth_authorize_flow = __esm({
34406
34756
  */
34407
34757
  renderFederatedLoginPage(params) {
34408
34758
  const { pendingAuthId, detection, clientId } = params;
34409
- const callbackPath = `${this.scope.fullPath}/oauth/callback`;
34759
+ const callbackPath = "/oauth/callback";
34410
34760
  const providers = [...detection.providers.values()].map((provider) => ({
34411
34761
  providerId: provider.id,
34412
34762
  providerName: provider.id,
@@ -34510,7 +34860,7 @@ import {
34510
34860
  startNextProvider as startNextProvider2
34511
34861
  } from "@frontmcp/auth";
34512
34862
  import { z as z65 } from "@frontmcp/lazy-zod";
34513
- 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";
34514
34864
  function timingSafeEqualStr3(a, b) {
34515
34865
  if (a.length !== b.length) return false;
34516
34866
  let diff = 0;
@@ -35236,7 +35586,7 @@ var init_oauth_callback_flow = __esm({
35236
35586
  * preserved on the form so the user does not have to re-enter everything.
35237
35587
  */
35238
35588
  renderLoginRetryPage(pendingAuth, login, fields, failure) {
35239
- const callbackPath = `${this.scope.fullPath}/oauth/callback`;
35589
+ const callbackPath = "/oauth/callback";
35240
35590
  const ctx = {
35241
35591
  clientId: pendingAuth.clientId,
35242
35592
  clientName: pendingAuth.clientId,
@@ -35302,7 +35652,7 @@ var init_oauth_callback_flow = __esm({
35302
35652
  const state = buildConsentState(
35303
35653
  {
35304
35654
  pendingAuthId: pendingAuth.id,
35305
- submitUrl: `${this.scope.fullPath}/oauth/callback`,
35655
+ submitUrl: "/oauth/callback",
35306
35656
  extraUrl: authUiExtraPath(this.scope.fullPath),
35307
35657
  csrfToken,
35308
35658
  addedItems: authUi.getAddedItems(pendingAuth.id)
@@ -35329,7 +35679,7 @@ var init_oauth_callback_flow = __esm({
35329
35679
  * (used for an empty `requireSelection` submit).
35330
35680
  */
35331
35681
  renderConsentScreen(pendingAuth, consentConfig, identity, error, preSelectedTools) {
35332
- const callbackPath = `${this.scope.fullPath}/oauth/callback`;
35682
+ const callbackPath = "/oauth/callback";
35333
35683
  const { toolCards } = projectConsentTools(this.scope, consentConfig?.excludedTools);
35334
35684
  const hiddenFields = [];
35335
35685
  if (identity.email) hiddenFields.push({ name: "email", value: identity.email });
@@ -35368,7 +35718,7 @@ var init_oauth_callback_flow = __esm({
35368
35718
  * In production, this would be the user's ID from the database
35369
35719
  */
35370
35720
  generateUserSub(email) {
35371
- const hash = sha256Hex5(email.toLowerCase());
35721
+ const hash = sha256Hex6(email.toLowerCase());
35372
35722
  return `${hash.slice(0, 8)}-${hash.slice(8, 12)}-${hash.slice(12, 16)}-${hash.slice(16, 20)}-${hash.slice(20, 32)}`;
35373
35723
  }
35374
35724
  /**
@@ -36770,7 +37120,8 @@ var init_oauth_token_flow = __esm({
36770
37120
  async handleAuthorizationCodeGrant() {
36771
37121
  const { body, isDefaultAuthProvider } = this.state.required;
36772
37122
  if (body?.grant_type !== "authorization_code") return;
36773
- if (isDefaultAuthProvider && body.code === "anonymous") {
37123
+ const authOptions = this.scope.auth?.options;
37124
+ if (isDefaultAuthProvider && body.code === "anonymous" && !!authOptions && allowsPublicAccess(authOptions)) {
36774
37125
  const localAuth2 = this.scope.auth;
36775
37126
  const accessToken = await localAuth2.signAnonymousJwt();
36776
37127
  this.state.set("tokenResponse", {
@@ -36808,6 +37159,16 @@ var init_oauth_token_flow = __esm({
36808
37159
  const { body, isDefaultAuthProvider } = this.state.required;
36809
37160
  if (body?.grant_type !== "refresh_token") return;
36810
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
+ }
36811
37172
  const localAuth2 = this.scope.auth;
36812
37173
  const accessToken = await localAuth2.signAnonymousJwt();
36813
37174
  this.state.set("tokenResponse", {
@@ -36843,6 +37204,19 @@ var init_oauth_token_flow = __esm({
36843
37204
  }
36844
37205
  async handleAnonymousGrant() {
36845
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
+ }
36846
37220
  if (body?.grant_type === "anonymous" && body.resource) {
36847
37221
  const { request } = this.rawInput;
36848
37222
  const canonicalResource = computeResource(request, this.scope.entryPath, this.scope.routeBase);
@@ -37162,7 +37536,7 @@ var init_session_verify_flow = __esm({
37162
37536
  const token = extractBearerToken2(authorizationHeader);
37163
37537
  const userAgent = request.headers?.["user-agent"] ?? void 0;
37164
37538
  const prmMetadataPath = `/.well-known/oauth-protected-resource${entryPath}${routeBase}`;
37165
- const prmUrl = `${baseUrl}${prmMetadataPath}`;
37539
+ const prmUrl = `${getRequestBaseUrl(request)}${prmMetadataPath}`;
37166
37540
  const prmMetadataHeader = buildUnauthorizedHeader(prmUrl);
37167
37541
  this.logger.verbose("parseInput", {
37168
37542
  hasAuthHeader: !!authorizationHeader,
@@ -37807,9 +38181,15 @@ import {
37807
38181
  MemoryStorageAdapter,
37808
38182
  randomBytes as randomBytes5,
37809
38183
  randomUUID as randomUUID21,
37810
- sha256Hex as sha256Hex6
38184
+ sha256Hex as sha256Hex7
37811
38185
  } from "@frontmcp/utils";
37812
- 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;
37813
38193
  var init_instance_local_primary_auth = __esm({
37814
38194
  "libs/sdk/src/auth/instances/instance.local-primary-auth.ts"() {
37815
38195
  "use strict";
@@ -37833,7 +38213,6 @@ var init_instance_local_primary_auth = __esm({
37833
38213
  init_well_known_prm_flow();
37834
38214
  init_secure_store();
37835
38215
  init_secure_store_context_extension();
37836
- DEFAULT_NO_AUTH_SECRET = randomBytes5(32);
37837
38216
  RESERVED_JWT_CLAIMS = /* @__PURE__ */ new Set([
37838
38217
  "sub",
37839
38218
  "iss",
@@ -37865,7 +38244,7 @@ var init_instance_local_primary_auth = __esm({
37865
38244
  this.secret = new TextEncoder().encode(jwtSecret);
37866
38245
  } else {
37867
38246
  this.logger.warn("JWT_SECRET is not set, using default secret");
37868
- this.secret = DEFAULT_NO_AUTH_SECRET;
38247
+ this.secret = getDefaultNoAuthSecret();
37869
38248
  }
37870
38249
  this.tokenStorage = this.readTokenStorage(options);
37871
38250
  this.authorizationStoreImpl = new InMemoryAuthorizationStore();
@@ -37882,6 +38261,8 @@ var init_instance_local_primary_auth = __esm({
37882
38261
  }
37883
38262
  this.ready = this.initialize();
37884
38263
  }
38264
+ scope;
38265
+ providers;
37885
38266
  host;
37886
38267
  port;
37887
38268
  issuer;
@@ -38325,7 +38706,7 @@ var init_instance_local_primary_auth = __esm({
38325
38706
  const pendingAuthId = `pending:${codeRecord.pendingAuthId}`;
38326
38707
  const parts = accessToken.split(".");
38327
38708
  const signature = parts[2] || accessToken;
38328
- const newAuthId = sha256Hex6(signature).substring(0, 16);
38709
+ const newAuthId = sha256Hex7(signature).substring(0, 16);
38329
38710
  await this.orchestratedTokenStore.migrateTokens(pendingAuthId, newAuthId);
38330
38711
  this.logger.info(`Migrated tokens from ${pendingAuthId} to ${newAuthId}`);
38331
38712
  } catch (err) {
@@ -38775,6 +39156,8 @@ var init_instance_remote_primary_auth = __esm({
38775
39156
  this.providers = providers;
38776
39157
  this.ready = this.initialize();
38777
39158
  }
39159
+ scope;
39160
+ providers;
38778
39161
  ready;
38779
39162
  jwks = new JwksService4();
38780
39163
  fetch(input, init) {
@@ -39029,6 +39412,7 @@ var init_channel_notification_service = __esm({
39029
39412
  this.logger = logger.child("ChannelNotificationService");
39030
39413
  this.defaultMeta = defaultMeta ?? {};
39031
39414
  }
39415
+ notificationService;
39032
39416
  logger;
39033
39417
  defaultMeta;
39034
39418
  /**
@@ -41921,6 +42305,8 @@ var init_heartbeat_service = __esm({
41921
42305
  this.intervalMs = config?.heartbeatIntervalMs ?? DEFAULT_HA_CONFIG.heartbeatIntervalMs;
41922
42306
  this.ttlMs = config?.heartbeatTtlMs ?? DEFAULT_HA_CONFIG.heartbeatTtlMs;
41923
42307
  }
42308
+ redis;
42309
+ nodeId;
41924
42310
  timer;
41925
42311
  startedAt;
41926
42312
  keyPrefix;
@@ -42000,6 +42386,9 @@ var init_notification_relay = __esm({
42000
42386
  this.keyPrefix = config?.redisKeyPrefix ?? DEFAULT_HA_CONFIG.redisKeyPrefix;
42001
42387
  this.channel = `${this.keyPrefix}notify:${nodeId}`;
42002
42388
  }
42389
+ subscriber;
42390
+ publisher;
42391
+ nodeId;
42003
42392
  handler;
42004
42393
  channel;
42005
42394
  keyPrefix;
@@ -42109,6 +42498,8 @@ var init_ha_manager = __esm({
42109
42498
  this.relay = new NotificationRelay(options.pubsubSubscriber, options.pubsubPublisher, nodeId, this.config);
42110
42499
  }
42111
42500
  }
42501
+ redis;
42502
+ nodeId;
42112
42503
  heartbeat;
42113
42504
  relay;
42114
42505
  config;
@@ -43610,6 +44001,7 @@ var init_job_instance = __esm({
43610
44001
  super(args);
43611
44002
  this.record = record;
43612
44003
  }
44004
+ record;
43613
44005
  execute(input) {
43614
44006
  return this.record.provide(input, this);
43615
44007
  }
@@ -44777,6 +45169,9 @@ var init_custom_routes_helper = __esm({
44777
45169
  this.reserved = reserved;
44778
45170
  this.name = "ReservedRouteCollisionError";
44779
45171
  }
45172
+ method;
45173
+ path;
45174
+ reserved;
44780
45175
  };
44781
45176
  }
44782
45177
  });
@@ -46239,11 +46634,11 @@ var init_skill_http_auth = __esm({
46239
46634
  * This prevents timing attacks that could reveal information about valid API keys.
46240
46635
  */
46241
46636
  timingSafeIncludes(keys, candidate) {
46242
- const encoder = new TextEncoder();
46243
- const candidateBytes = encoder.encode(candidate);
46637
+ const encoder2 = new TextEncoder();
46638
+ const candidateBytes = encoder2.encode(candidate);
46244
46639
  let found = false;
46245
46640
  for (const key of keys) {
46246
- const keyBytes = encoder.encode(key);
46641
+ const keyBytes = encoder2.encode(key);
46247
46642
  if (keyBytes.length === candidateBytes.length) {
46248
46643
  try {
46249
46644
  if (timingSafeEqual(keyBytes, candidateBytes)) {
@@ -48177,6 +48572,7 @@ var init_agent_execution_loop = __esm({
48177
48572
  this.maxIterations = maxIterations;
48178
48573
  this.name = "AgentMaxIterationsError";
48179
48574
  }
48575
+ maxIterations;
48180
48576
  };
48181
48577
  }
48182
48578
  });
@@ -49168,7 +49564,23 @@ function normalizeScopeBase(scopeBase) {
49168
49564
  const t = trimSlashes(scopeBase ?? "");
49169
49565
  return t ? `/${t}` : "";
49170
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
+ }
49171
49579
  function getRequestBaseUrl(req, entryPath) {
49580
+ const pin = readPublicUrlPin();
49581
+ if (pin) {
49582
+ return `${pin}${entryPath ?? ""}`;
49583
+ }
49172
49584
  const proto = req.headers["x-forwarded-proto"] || req.protocol || "http";
49173
49585
  const host = req.headers["x-forwarded-host"] || req.headers["host"];
49174
49586
  return `${proto}://${host}${entryPath ?? ""}`;
@@ -50073,6 +50485,8 @@ return 0
50073
50485
  this.haKeyPrefix = options?.haKeyPrefix ?? "mcp:ha:";
50074
50486
  this.logger = options?.logger;
50075
50487
  }
50488
+ redis;
50489
+ machineId;
50076
50490
  keyPrefix;
50077
50491
  ttlSeconds;
50078
50492
  haKeyPrefix;
@@ -51829,6 +52243,8 @@ var init_base_sse_transport = __esm({
51829
52243
  this._sessionId = options?.sessionId ?? randomUUID25();
51830
52244
  this._options = options || { enableDnsRebindingProtection: false };
51831
52245
  }
52246
+ _endpoint;
52247
+ res;
51832
52248
  _sseResponse;
51833
52249
  _sessionId;
51834
52250
  _options;
@@ -52073,6 +52489,12 @@ function sanitizeDescription(raw) {
52073
52489
  if (!raw) return "";
52074
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();
52075
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
+ }
52076
52498
  function buildSkillsCatalogSummary(skillRegistry) {
52077
52499
  if (!skillRegistry) return "";
52078
52500
  const skills = skillRegistry.getSkills({ visibility: "mcp" });
@@ -52084,7 +52506,7 @@ function buildSkillsCatalogSummary(skillRegistry) {
52084
52506
  const effectiveCap = MAX_SKILL_CATALOG_CHARS - TRUNCATION_FOOTER_RESERVE;
52085
52507
  for (const skill of skills) {
52086
52508
  const meta = skill.metadata;
52087
- const name41 = meta.name;
52509
+ const name41 = sanitizeName(meta.name);
52088
52510
  const description = sanitizeDescription(meta.description);
52089
52511
  const line = description ? `- **${name41}**: ${description}` : `- **${name41}**`;
52090
52512
  if (charCount + line.length + 1 > effectiveCap) {
@@ -52129,13 +52551,14 @@ function buildChannelInstructions(channels) {
52129
52551
  function joinSections(sections) {
52130
52552
  return sections.map((s) => (s ?? "").trim()).filter((s) => s.length > 0).join("\n\n---\n\n");
52131
52553
  }
52132
- 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;
52133
52555
  var init_skill_instructions_helper = __esm({
52134
52556
  "libs/sdk/src/skill/skill-instructions.helper.ts"() {
52135
52557
  "use strict";
52136
52558
  DEFAULT_POLICY = "append";
52137
52559
  MAX_SKILL_CATALOG_CHARS = 16e3;
52138
52560
  TRUNCATION_FOOTER_RESERVE = 160;
52561
+ MAX_SKILL_NAME_CHARS = 80;
52139
52562
  CATALOG_HEADER = "Available skills (read the `skills://catalog` resource to browse, or `skills://{name}/SKILL.md` for full content):";
52140
52563
  }
52141
52564
  });
@@ -52188,6 +52611,9 @@ var init_transport_local_adapter = __esm({
52188
52611
  this.transport = this.createTransport(key.sessionId, res);
52189
52612
  this.ready = this.connectServer();
52190
52613
  }
52614
+ scope;
52615
+ key;
52616
+ onDispose;
52191
52617
  logger;
52192
52618
  transport;
52193
52619
  /**
@@ -53108,6 +53534,7 @@ var init_transport_local = __esm({
53108
53534
  throw new UnsupportedTransportTypeError(this.type);
53109
53535
  }
53110
53536
  }
53537
+ onDispose;
53111
53538
  type;
53112
53539
  tokenHash;
53113
53540
  sessionId;
@@ -53177,6 +53604,8 @@ var init_transport_remote = __esm({
53177
53604
  this.tokenHash = key.tokenHash;
53178
53605
  this.sessionId = key.sessionId;
53179
53606
  }
53607
+ key;
53608
+ bus;
53180
53609
  type;
53181
53610
  tokenHash;
53182
53611
  sessionId;
@@ -53206,7 +53635,7 @@ var init_transport_remote = __esm({
53206
53635
  });
53207
53636
 
53208
53637
  // libs/sdk/src/transport/transport.registry.ts
53209
- import { getMachineId as getMachineId5, sha256Hex as sha256Hex7 } from "@frontmcp/utils";
53638
+ import { getMachineId as getMachineId5, sha256Hex as sha256Hex8 } from "@frontmcp/utils";
53210
53639
  var TransportService;
53211
53640
  var init_transport_registry = __esm({
53212
53641
  "libs/sdk/src/transport/transport.registry.ts"() {
@@ -53736,7 +54165,7 @@ var init_transport_registry = __esm({
53736
54165
  }
53737
54166
  /* --------------------------------- internals -------------------------------- */
53738
54167
  sha256(value) {
53739
- return sha256Hex7(value);
54168
+ return sha256Hex8(value);
53740
54169
  }
53741
54170
  /**
53742
54171
  * Create a history key from components.
@@ -53842,6 +54271,74 @@ var init_transport_registry = __esm({
53842
54271
  }
53843
54272
  });
53844
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
+
53845
54342
  // libs/sdk/src/scope/flows/http.request.flow.ts
53846
54343
  import {
53847
54344
  deriveAuthorizationId,
@@ -53850,7 +54347,7 @@ import {
53850
54347
  OrchestratedAuthorization
53851
54348
  } from "@frontmcp/auth";
53852
54349
  import { z as z103 } from "@frontmcp/lazy-zod";
53853
- import { randomUUID as randomUUID26 } from "@frontmcp/utils";
54350
+ import { randomUUID as randomUUID27 } from "@frontmcp/utils";
53854
54351
  var plan39, httpRequestStateSchema, name40, Stage40, HttpRequestFlow;
53855
54352
  var init_http_request_flow = __esm({
53856
54353
  "libs/sdk/src/scope/flows/http.request.flow.ts"() {
@@ -53870,6 +54367,11 @@ var init_http_request_flow = __esm({
53870
54367
  "router"
53871
54368
  ],
53872
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",
53873
54375
  "handleLegacySse",
53874
54376
  "handleSse",
53875
54377
  "handleStreamableHttp",
@@ -53912,7 +54414,7 @@ var init_http_request_flow = __esm({
53912
54414
  const { request } = this.rawInput;
53913
54415
  this.requestStartTime = Date.now();
53914
54416
  const ctx = this.tryGetContext();
53915
- this.requestId = ctx?.requestId ?? `req-${randomUUID26()}`;
54417
+ this.requestId = ctx?.requestId ?? `req-${randomUUID27()}`;
53916
54418
  const headers = request.headers ?? {};
53917
54419
  const body = request.body;
53918
54420
  const userAgent = headers["user-agent"];
@@ -54071,6 +54573,10 @@ var init_http_request_flow = __esm({
54071
54573
  accept: request.headers?.["accept"]
54072
54574
  });
54073
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
+ }
54074
54580
  this.logger.debug(`[${this.requestId}] decision result`, {
54075
54581
  intent: decision.intent,
54076
54582
  reasons: decision.reasons,
@@ -54197,6 +54703,47 @@ var init_http_request_flow = __esm({
54197
54703
  throw error;
54198
54704
  }
54199
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
+ }
54200
54747
  async handleLegacySse() {
54201
54748
  try {
54202
54749
  const response = await this.scope.runFlow("handle:legacy-sse", this.rawInput);
@@ -54366,6 +54913,9 @@ var init_http_request_flow = __esm({
54366
54913
  __decorateClass([
54367
54914
  Stage40("router")
54368
54915
  ], HttpRequestFlow.prototype, "router", 1);
54916
+ __decorateClass([
54917
+ Stage40("handleWebFetch")
54918
+ ], HttpRequestFlow.prototype, "handleWebFetch", 1);
54369
54919
  __decorateClass([
54370
54920
  Stage40("handleLegacySse", {
54371
54921
  filter: ({
@@ -54438,28 +54988,11 @@ var init_http_request_flow = __esm({
54438
54988
  }
54439
54989
  });
54440
54990
 
54441
- // libs/sdk/src/scope/optional-dependency.util.ts
54442
- function probeOptionalDependency(moduleName, loadError, resolve) {
54443
- let resolvedPath;
54444
- try {
54445
- resolvedPath = resolve(moduleName);
54446
- } catch {
54447
- resolvedPath = void 0;
54448
- }
54449
- const error = loadError instanceof Error ? loadError.message : String(loadError);
54450
- return resolvedPath ? { status: "load-failed", resolvedPath, error } : { status: "not-installed", error };
54451
- }
54452
- var init_optional_dependency_util = __esm({
54453
- "libs/sdk/src/scope/optional-dependency.util.ts"() {
54454
- "use strict";
54455
- }
54456
- });
54457
-
54458
54991
  // libs/sdk/src/scope/scope.instance.ts
54459
54992
  import "reflect-metadata";
54460
54993
  import { createGuardManager } from "@frontmcp/guard";
54461
54994
  import { getEnvFlag, getMachineId as getMachineId6, getRuntimeContext as getRuntimeContext15, isEdgeRuntime } from "@frontmcp/utils";
54462
- var Scope;
54995
+ var SCOPE_NON_DISPATCHABLE_FLOWS, Scope;
54463
54996
  var init_scope_instance = __esm({
54464
54997
  "libs/sdk/src/scope/scope.instance.ts"() {
54465
54998
  "use strict";
@@ -54505,6 +55038,7 @@ var init_scope_instance = __esm({
54505
55038
  init_transport_registry();
54506
55039
  init_http_request_flow();
54507
55040
  init_optional_dependency_util();
55041
+ SCOPE_NON_DISPATCHABLE_FLOWS = /* @__PURE__ */ new Set(["http:request"]);
54508
55042
  Scope = class _Scope extends ScopeEntry {
54509
55043
  id;
54510
55044
  globalProviders;
@@ -54898,7 +55432,9 @@ var init_scope_instance = __esm({
54898
55432
  this.scopeResources = new ResourceRegistry(this.scopeProviders, [], scopeRef);
54899
55433
  this.scopePrompts = new PromptRegistry(this.scopeProviders, [], scopeRef);
54900
55434
  this.scopeAgents = new AgentRegistry(this.scopeProviders, [], scopeRef);
54901
- 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
+ });
54902
55438
  await Promise.all([
54903
55439
  this.scopeTools.ready,
54904
55440
  this.scopeResources.ready,
@@ -55659,6 +56195,16 @@ var init_scope_instance = __esm({
55659
56195
  runFlow(name41, input, deps) {
55660
56196
  return this.scopeFlows.runFlow(name41, input, deps);
55661
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
+ }
55662
56208
  async runFlowForOutput(name41, input, deps) {
55663
56209
  const result = await this.scopeFlows.runFlow(name41, input, deps);
55664
56210
  if (result) {
@@ -55743,6 +56289,7 @@ var init_provider_registry = __esm({
55743
56289
  this.topoSort();
55744
56290
  this.ready = this.initialize();
55745
56291
  }
56292
+ parentProviders;
55746
56293
  /** used to track which registry provided which token */
55747
56294
  providedBy;
55748
56295
  /** topo order (deps first) */
@@ -56695,6 +57242,292 @@ var init_scope_registry = __esm({
56695
57242
  }
56696
57243
  });
56697
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
+
56698
57531
  // libs/sdk/src/server/noop-server.ts
56699
57532
  var NoopFrontMcpServer;
56700
57533
  var init_noop_server = __esm({
@@ -56720,6 +57553,122 @@ var init_noop_server = __esm({
56720
57553
  }
56721
57554
  });
56722
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
+
56723
57672
  // libs/sdk/src/server/middleware/host-validation.middleware.ts
56724
57673
  function createHostValidationMiddleware(options) {
56725
57674
  if (!options.enabled) {
@@ -56887,8 +57836,8 @@ var init_express_host_adapter = __esm({
56887
57836
  server.on("error", reject);
56888
57837
  server.listen(portOrSocketPath, () => {
56889
57838
  try {
56890
- const fs2 = __require("node:fs");
56891
- fs2.chmodSync(portOrSocketPath, 432);
57839
+ const fs = __require("node:fs");
57840
+ fs.chmodSync(portOrSocketPath, 432);
56892
57841
  } catch {
56893
57842
  }
56894
57843
  console.log(`MCP HTTP (Express) on unix://${portOrSocketPath}`);
@@ -56919,6 +57868,11 @@ var init_express_host_adapter = __esm({
56919
57868
  });
56920
57869
 
56921
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
+ });
56922
57876
  var init_node_express_host = __esm({
56923
57877
  "libs/sdk/src/server/adapters/polyfills/node-express-host.ts"() {
56924
57878
  "use strict";
@@ -56926,129 +57880,12 @@ var init_node_express_host = __esm({
56926
57880
  }
56927
57881
  });
56928
57882
 
56929
- // libs/sdk/src/server/security/security-audit.ts
56930
- function auditSecurityDefaults(config, isProduction5) {
56931
- const findings = [];
56932
- if (!isProduction5 && config.deploymentMode !== "distributed") {
56933
- return findings;
56934
- }
56935
- const strict = config.security?.strict === true;
56936
- if (config.cors === void 0 && !strict) {
56937
- findings.push({
56938
- level: "warn",
56939
- code: "CORS_PERMISSIVE_DEFAULT",
56940
- message: "CORS is using the permissive default (origin: true), which allows all origins.",
56941
- recommendation: "Set explicit cors.origin to restrict allowed origins in production."
56942
- });
56943
- } else if (config.cors !== false && config.cors?.origin === true && !strict) {
56944
- findings.push({
56945
- level: "warn",
56946
- code: "CORS_ORIGIN_TRUE",
56947
- message: "CORS origin=true allows all origins to make cross-origin requests.",
56948
- recommendation: "Set cors.origin to specific allowed origins."
56949
- });
56950
- } else if (config.cors === false) {
56951
- findings.push({
56952
- level: "info",
56953
- code: "CORS_DISABLED",
56954
- message: "CORS is disabled. Cross-origin requests will be blocked by browsers."
56955
- });
56956
- } else {
56957
- findings.push({
56958
- level: "info",
56959
- code: "CORS_CONFIGURED",
56960
- message: "CORS is explicitly configured."
56961
- });
56962
- }
56963
- const bindAddress = config.resolvedBindAddress ?? "0.0.0.0";
56964
- if (bindAddress === "0.0.0.0" || bindAddress === "::") {
56965
- if (config.deploymentMode !== "distributed") {
56966
- findings.push({
56967
- level: "warn",
56968
- code: "BIND_ALL_INTERFACES",
56969
- message: `Server bound to ${bindAddress} \u2014 accessible from all network interfaces.`,
56970
- 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)."
56971
- });
56972
- } else {
56973
- findings.push({
56974
- level: "info",
56975
- code: "BIND_ALL_INTERFACES_DISTRIBUTED",
56976
- message: `Server bound to ${bindAddress} (expected for distributed deployment).`
56977
- });
56978
- }
56979
- } else {
56980
- findings.push({
56981
- level: "info",
56982
- code: "BIND_RESTRICTED",
56983
- message: `Server bound to ${bindAddress}.`
56984
- });
56985
- }
56986
- const dnsProtectionEnabled = config.security?.dnsRebindingProtection?.enabled ?? strict;
56987
- if (!dnsProtectionEnabled) {
56988
- findings.push({
56989
- level: "warn",
56990
- code: "DNS_REBINDING_UNPROTECTED",
56991
- message: "DNS rebinding protection is disabled.",
56992
- recommendation: "Enable security.dnsRebindingProtection with allowedHosts to prevent DNS rebinding attacks."
56993
- });
56994
- } else {
56995
- findings.push({
56996
- level: "info",
56997
- code: "DNS_REBINDING_PROTECTED",
56998
- message: "DNS rebinding protection is enabled."
56999
- });
57000
- }
57001
- if (config.security?.strict) {
57002
- findings.push({
57003
- level: "info",
57004
- code: "STRICT_MODE_ENABLED",
57005
- message: "Strict security mode is enabled: loopback binding, restrictive CORS, DNS rebinding protection."
57006
- });
57007
- } else {
57008
- findings.push({
57009
- level: "info",
57010
- code: "STRICT_MODE_HINT",
57011
- message: "To enable strict security defaults, set security.strict = true in HttpOptions."
57012
- });
57013
- }
57014
- return findings;
57015
- }
57016
- function logSecurityFindings(findings, logger) {
57017
- if (findings.length === 0) return;
57018
- for (const finding of findings) {
57019
- const prefix = `[Security] ${finding.code}:`;
57020
- const message = finding.recommendation ? `${prefix} ${finding.message} ${finding.recommendation}` : `${prefix} ${finding.message}`;
57021
- if (finding.level === "warn") {
57022
- logger.warn(message);
57023
- } else {
57024
- logger.info(message);
57025
- }
57026
- }
57027
- }
57028
- function resolveBindAddress(security, deploymentMode) {
57029
- if (security?.bindAddress) {
57030
- if (security.bindAddress === "loopback") return "127.0.0.1";
57031
- if (security.bindAddress === "all") return "0.0.0.0";
57032
- return security.bindAddress;
57033
- }
57034
- if (security?.strict) {
57035
- return deploymentMode === "distributed" ? "0.0.0.0" : "127.0.0.1";
57036
- }
57037
- return "0.0.0.0";
57038
- }
57039
- var init_security_audit = __esm({
57040
- "libs/sdk/src/server/security/security-audit.ts"() {
57041
- "use strict";
57042
- }
57043
- });
57044
-
57045
57883
  // libs/sdk/src/server/server.instance.ts
57046
57884
  import { getRuntimeContext as getRuntimeContext16 } from "@frontmcp/utils";
57047
57885
  var DEFAULT_CORS, FrontMcpServerInstance;
57048
57886
  var init_server_instance = __esm({
57049
57887
  "libs/sdk/src/server/server.instance.ts"() {
57050
57888
  "use strict";
57051
- init_node_express_host();
57052
57889
  init_common();
57053
57890
  init_health2();
57054
57891
  init_metrics2();
@@ -57076,7 +57913,8 @@ var init_server_instance = __esm({
57076
57913
  this.host = this.config.hostFactory;
57077
57914
  } else {
57078
57915
  const corsConfig = this.config.cors === false ? void 0 : this.config.cors ?? DEFAULT_CORS;
57079
- this.host = new ExpressHostAdapter({
57916
+ const { ExpressHostAdapter: ExpressHostAdapter2 } = (init_node_express_host(), __toCommonJS(node_express_host_exports));
57917
+ this.host = new ExpressHostAdapter2({
57080
57918
  ...corsConfig ? { cors: corsConfig } : {},
57081
57919
  ...this.config.security ? { security: this.config.security } : {},
57082
57920
  ...this.config.bodyLimit !== void 0 ? { bodyLimit: this.config.bodyLimit } : {},
@@ -57217,7 +58055,7 @@ var front_mcp_exports = {};
57217
58055
  __export(front_mcp_exports, {
57218
58056
  FrontMcpInstance: () => FrontMcpInstance
57219
58057
  });
57220
- 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";
57221
58059
  function resolveConfigInput(optionsOrClass) {
57222
58060
  if (typeof optionsOrClass === "function") {
57223
58061
  const stored = getDecoratorConfig(optionsOrClass);
@@ -57243,6 +58081,7 @@ var init_front_mcp = __esm({
57243
58081
  init_scope_registry();
57244
58082
  init_skill_instructions_helper();
57245
58083
  init_task();
58084
+ init_web_fetch_handler();
57246
58085
  init_front_mcp_providers();
57247
58086
  stdioServing = false;
57248
58087
  FrontMcpInstance = class _FrontMcpInstance2 {
@@ -57387,6 +58226,44 @@ var init_front_mcp = __esm({
57387
58226
  frontMcp.log?.info("FrontMCP handler created (serverless mode)");
57388
58227
  return server.getHandler();
57389
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
+ }
57390
58267
  /**
57391
58268
  * Creates and initializes a FrontMCP instance without starting any server.
57392
58269
  * Returns the instance for graph extraction and introspection purposes.
@@ -57669,7 +58546,7 @@ var init_front_mcp = __esm({
57669
58546
  };
57670
58547
  const mcpServer = new McpServer2(scope.metadata.info, serverOptions);
57671
58548
  startupCleanups.push(() => mcpServer.close());
57672
- const sessionId = `stdio:${randomUUID27()}`;
58549
+ const sessionId = `stdio:${randomUUID28()}`;
57673
58550
  const handlers = createMcpHandlers2({ scope, serverOptions, composeInstructions });
57674
58551
  for (const handler of handlers) {
57675
58552
  const originalHandler = handler.handler;
@@ -57997,7 +58874,8 @@ function FrontMcp(providedMetadata) {
57997
58874
  } else if (isServerless2) {
57998
58875
  const ServerlessInstance = getFrontMcpInstance();
57999
58876
  const { setServerlessHandler: setServerlessHandler2, setServerlessHandlerPromise: setServerlessHandlerPromise2, setServerlessHandlerError: setServerlessHandlerError2 } = getServerlessHandlerFns();
58000
- const handlerPromise = ServerlessInstance.createHandler(metadata);
58877
+ const isWorker = getEnvFlag2("FRONTMCP_WORKER");
58878
+ const handlerPromise = isWorker ? ServerlessInstance.createFetchHandler(metadata) : ServerlessInstance.createHandler(metadata);
58001
58879
  setServerlessHandlerPromise2(handlerPromise);
58002
58880
  handlerPromise.then(setServerlessHandler2).catch((err) => {
58003
58881
  const e = err instanceof Error ? err : new InternalMcpError(String(err), "SERVERLESS_INIT_FAILED");
@@ -58139,6 +59017,12 @@ function remoteApp(url, options) {
58139
59017
  filter: options?.filter
58140
59018
  };
58141
59019
  }
59020
+ function frontMcpApp(metadata) {
59021
+ const FunctionalApp = class {
59022
+ };
59023
+ FrontMcpApp(metadata)(FunctionalApp);
59024
+ return FunctionalApp;
59025
+ }
58142
59026
  var APP_DECORATOR_BASENAMES, App;
58143
59027
  var init_app_decorator = __esm({
58144
59028
  "libs/sdk/src/common/decorators/app.decorator.ts"() {
@@ -60127,6 +61011,8 @@ init_direct();
60127
61011
 
60128
61012
  // libs/sdk/src/transport/index.ts
60129
61013
  init_in_memory_server();
61014
+ init_web_fetch_handler();
61015
+ init_web_standard_mcp();
60130
61016
 
60131
61017
  // libs/sdk/src/index.ts
60132
61018
  init_ext_apps2();
@@ -60356,6 +61242,7 @@ export {
60356
61242
  HttpStatus,
60357
61243
  HttpStreamSchema,
60358
61244
  HttpTextSchema,
61245
+ HttpWebResponseSchema,
60359
61246
  ImageOutputSchema,
60360
61247
  InMemoryOrchestratedTokenStore2 as InMemoryOrchestratedTokenStore,
60361
61248
  InMemoryStoreRequiredError,
@@ -60625,6 +61512,7 @@ export {
60625
61512
  annotatedFrontMcpSkillsSchema,
60626
61513
  annotatedFrontMcpToolsSchema,
60627
61514
  annotatedFrontMcpWorkflowsSchema,
61515
+ frontMcpApp as app,
60628
61516
  appAuthOptionsSchema,
60629
61517
  appFilterConfigSchema,
60630
61518
  applyPrimitiveFilter,
@@ -60639,6 +61527,7 @@ export {
60639
61527
  buildEsmResourceRecord,
60640
61528
  buildEsmShUrl,
60641
61529
  buildEsmToolRecord,
61530
+ buildPersistentWebStandardMcp,
60642
61531
  buildRemotePromptRecord,
60643
61532
  buildRemoteResourceRecord,
60644
61533
  buildRemoteResourceTemplateRecord,
@@ -60691,6 +61580,7 @@ export {
60691
61580
  createSkillInstance,
60692
61581
  createSkillStorageProvider,
60693
61582
  createTaskStore,
61583
+ createWebFetchHandler,
60694
61584
  decideIntent,
60695
61585
  decisionSchema,
60696
61586
  decryptElicitationData,
@@ -60734,6 +61624,7 @@ export {
60734
61624
  frontMcpAdapterMetadataSchema,
60735
61625
  frontMcpAgent,
60736
61626
  frontMcpAgentMetadataSchema,
61627
+ frontMcpApp,
60737
61628
  frontMcpAuthProviderMetadataSchema,
60738
61629
  frontMcpBaseSchema,
60739
61630
  frontMcpChannelMetadataSchema,
@@ -60893,7 +61784,9 @@ export {
60893
61784
  frontMcpResource as resource,
60894
61785
  frontMcpResourceTemplate as resourceTemplate,
60895
61786
  resourceUriMatches,
61787
+ runHttpRequestFlowWeb,
60896
61788
  runTaskInBackground,
61789
+ runWebStandardMcp,
60897
61790
  satisfiesRange,
60898
61791
  scanSkillResources,
60899
61792
  secureStoreConfigSchema,