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