@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.
- package/auth/flows/oauth.authorize.flow.d.ts.map +1 -1
- package/auth/flows/oauth.token.flow.d.ts.map +1 -1
- package/auth/flows/session.verify.flow.d.ts.map +1 -1
- package/auth/instances/instance.local-primary-auth.d.ts.map +1 -1
- package/common/decorators/app.decorator.d.ts +13 -1
- package/common/decorators/app.decorator.d.ts.map +1 -1
- package/common/decorators/front-mcp.decorator.d.ts.map +1 -1
- package/common/metadata/front-mcp.metadata.d.ts +24 -0
- package/common/metadata/front-mcp.metadata.d.ts.map +1 -1
- package/common/schemas/http-output.schema.d.ts +17 -0
- package/common/schemas/http-output.schema.d.ts.map +1 -1
- package/common/tokens/server.tokens.d.ts +3 -0
- package/common/tokens/server.tokens.d.ts.map +1 -1
- package/common/types/options/skills-http/interfaces.d.ts +15 -1
- package/common/types/options/skills-http/interfaces.d.ts.map +1 -1
- package/common/types/options/skills-http/schema.d.ts +4 -0
- package/common/types/options/skills-http/schema.d.ts.map +1 -1
- package/common/utils/path.utils.d.ts +15 -0
- package/common/utils/path.utils.d.ts.map +1 -1
- package/esm/index.mjs +1187 -294
- package/esm-loader/esm-cache.d.ts +10 -0
- package/esm-loader/esm-cache.d.ts.map +1 -1
- package/esm-loader/esm-module-loader.d.ts.map +1 -1
- package/flows/flow.instance.d.ts +14 -0
- package/flows/flow.instance.d.ts.map +1 -1
- package/flows/flow.registry.d.ts +9 -1
- package/flows/flow.registry.d.ts.map +1 -1
- package/front-mcp/front-mcp.d.ts +14 -0
- package/front-mcp/front-mcp.d.ts.map +1 -1
- package/front-mcp/front-mcp.providers.d.ts +4 -0
- package/front-mcp/front-mcp.providers.d.ts.map +1 -1
- package/index.d.ts +9 -5
- package/index.d.ts.map +1 -1
- package/index.js +1421 -520
- package/logger/instances/instance.file-logger.d.ts.map +1 -1
- package/package.json +13 -13
- package/scope/flows/http.request.flow.d.ts +17 -1
- package/scope/flows/http.request.flow.d.ts.map +1 -1
- package/scope/optional-dependency.util.d.ts +25 -0
- package/scope/optional-dependency.util.d.ts.map +1 -1
- package/scope/scope.instance.d.ts +9 -1
- package/scope/scope.instance.d.ts.map +1 -1
- package/server/server.instance.d.ts.map +1 -1
- package/server/server.validation.d.ts.map +1 -1
- package/skill/index.d.ts +1 -0
- package/skill/index.d.ts.map +1 -1
- package/skill/providers/memory-skill.provider.d.ts +61 -1
- package/skill/providers/memory-skill.provider.d.ts.map +1 -1
- package/skill/skill-index-cache.interface.d.ts +33 -0
- package/skill/skill-index-cache.interface.d.ts.map +1 -0
- package/skill/skill-instructions.helper.d.ts +13 -0
- package/skill/skill-instructions.helper.d.ts.map +1 -1
- package/skill/skill-storage.interface.d.ts +13 -0
- package/skill/skill-storage.interface.d.ts.map +1 -1
- package/skill/skill.registry.d.ts +27 -0
- package/skill/skill.registry.d.ts.map +1 -1
- package/transport/build-scoped-server-options.d.ts +35 -0
- package/transport/build-scoped-server-options.d.ts.map +1 -0
- package/transport/in-memory-server.d.ts.map +1 -1
- package/transport/index.d.ts +17 -0
- package/transport/index.d.ts.map +1 -1
- package/transport/web-fetch-handler.d.ts +106 -0
- package/transport/web-fetch-handler.d.ts.map +1 -0
- package/transport/web-response.renderer.d.ts +13 -0
- package/transport/web-response.renderer.d.ts.map +1 -0
- package/transport/web-standard-mcp.d.ts +63 -0
- 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
|
-
|
|
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
|
-
|
|
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
|
|
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,
|
|
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,
|
|
6249
|
+
const iv = (0, import_utils103.randomBytes)(12);
|
|
6208
6250
|
const plaintextBytes = new TextEncoder().encode(plaintext);
|
|
6209
|
-
const { ciphertext, tag } = (0,
|
|
6210
|
-
return [(0,
|
|
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,
|
|
6218
|
-
const tag = (0,
|
|
6219
|
-
const ciphertext = (0,
|
|
6220
|
-
const plaintext = (0,
|
|
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
|
|
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
|
-
|
|
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
|
|
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 (!
|
|
10916
|
-
const found = walkForFile(srcRoot, cleanRelative,
|
|
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,
|
|
10987
|
+
function walkForFile(dir, targetRelative, fs, path3, maxDepth = 10) {
|
|
10922
10988
|
const candidate = path3.join(dir, targetRelative);
|
|
10923
|
-
if (
|
|
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 =
|
|
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,
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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 {
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
25274
|
-
|
|
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
|
-
|
|
25282
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
25311
|
-
|
|
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.
|
|
25327
|
-
|
|
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
|
|
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
|
|
31410
|
-
if (
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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 {
|
|
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
|
|
32137
|
-
|
|
32138
|
-
|
|
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
|
|
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 =
|
|
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:
|
|
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:
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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:
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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 = `${
|
|
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
|
|
38184
|
+
sha256Hex as sha256Hex7
|
|
37811
38185
|
} from "@frontmcp/utils";
|
|
37812
|
-
|
|
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 =
|
|
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 =
|
|
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
|
|
46243
|
-
const candidateBytes =
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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-${
|
|
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
|
|
56891
|
-
|
|
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
|
-
|
|
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
|
|
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:${
|
|
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
|
|
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,
|