@frontmcp/sdk 1.8.5 → 1.8.7
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/agent/flows/call-agent.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/dynamic/dynamic.adapter.d.ts +1 -1
- package/common/dynamic/dynamic.adapter.d.ts.map +1 -1
- package/common/dynamic/dynamic.plugin.d.ts +18 -3
- package/common/dynamic/dynamic.plugin.d.ts.map +1 -1
- package/common/dynamic/dynamic.utils.d.ts +10 -1
- package/common/dynamic/dynamic.utils.d.ts.map +1 -1
- package/common/interfaces/execution-context.interface.d.ts +14 -0
- package/common/interfaces/execution-context.interface.d.ts.map +1 -1
- package/common/metadata/front-mcp.metadata.d.ts +127 -19
- package/common/metadata/front-mcp.metadata.d.ts.map +1 -1
- package/common/types/options/http/index.d.ts +1 -1
- package/common/types/options/http/index.d.ts.map +1 -1
- package/common/types/options/http/interfaces.d.ts +36 -1
- package/common/types/options/http/interfaces.d.ts.map +1 -1
- package/common/types/options/http/schema.d.ts +12 -0
- package/common/types/options/http/schema.d.ts.map +1 -1
- package/common/types/options/transport/schema.d.ts +2 -2
- package/common/utils/list-all-pages.utils.d.ts +17 -0
- package/common/utils/list-all-pages.utils.d.ts.map +1 -0
- package/context/frontmcp-context-storage.d.ts.map +1 -1
- package/context/frontmcp-context.d.ts +11 -0
- package/context/frontmcp-context.d.ts.map +1 -1
- package/elicitation/store/elicitation-store.factory.d.ts.map +1 -1
- package/errors/misconfiguration.d.ts +30 -0
- package/errors/misconfiguration.d.ts.map +1 -0
- package/esm/index.mjs +1181 -325
- package/flows/flow.instance.d.ts.map +1 -1
- package/front-mcp/front-mcp.d.ts.map +1 -1
- package/ha/ha-headers.d.ts +16 -0
- package/ha/ha-headers.d.ts.map +1 -0
- package/health/health.probes.d.ts +1 -1
- package/health/health.probes.d.ts.map +1 -1
- package/index.js +1259 -407
- package/job/store/job-definition-store.factory.d.ts.map +1 -1
- package/job/store/job-state-store.factory.d.ts.map +1 -1
- package/notification/notification.service.d.ts +4 -1
- package/notification/notification.service.d.ts.map +1 -1
- package/package.json +10 -10
- package/plugin/plugin.registry.d.ts.map +1 -1
- package/remote-mcp/mcp-client.service.d.ts.map +1 -1
- package/remote-mcp/mcp-stateless-client.adapter.d.ts +25 -6
- package/remote-mcp/mcp-stateless-client.adapter.d.ts.map +1 -1
- package/remote-mcp/resilience/health-check.d.ts.map +1 -1
- package/scope/scope.instance.d.ts +8 -0
- package/scope/scope.instance.d.ts.map +1 -1
- package/server/adapters/express.host.adapter.d.ts +6 -1
- package/server/adapters/express.host.adapter.d.ts.map +1 -1
- package/server/middleware/csp.middleware.d.ts +12 -1
- package/server/middleware/csp.middleware.d.ts.map +1 -1
- package/server/security/security-audit.d.ts.map +1 -1
- package/server/server.instance.d.ts.map +1 -1
- package/skill/cache/skill-http-cache.factory.d.ts +0 -5
- package/skill/cache/skill-http-cache.factory.d.ts.map +1 -1
- package/task/store/index.d.ts +1 -1
- package/task/store/index.d.ts.map +1 -1
- package/task/store/task-store.factory.d.ts +6 -0
- package/task/store/task-store.factory.d.ts.map +1 -1
- package/tool/flows/call-tool.flow.d.ts +1 -0
- package/tool/flows/call-tool.flow.d.ts.map +1 -1
- package/tool/ui/ui-option-warnings.d.ts +3 -0
- package/tool/ui/ui-option-warnings.d.ts.map +1 -0
- package/tool/ui/ui-resource.handler.d.ts.map +1 -1
- package/tool/ui/ui-shared.d.ts +14 -0
- package/tool/ui/ui-shared.d.ts.map +1 -1
- package/transport/event-stores/redis.event-store.d.ts.map +1 -1
- package/transport/flows/handle.mcp-20260728.flow.d.ts.map +1 -1
- package/transport/flows/handle.sse.flow.d.ts +25 -0
- package/transport/flows/handle.sse.flow.d.ts.map +1 -1
- package/transport/flows/handle.stateless-http.flow.d.ts +2 -1
- package/transport/flows/handle.stateless-http.flow.d.ts.map +1 -1
- package/transport/flows/handle.streamable-http.flow.d.ts +12 -1
- package/transport/flows/handle.streamable-http.flow.d.ts.map +1 -1
- package/transport/ipc-server.transport.d.ts +26 -0
- package/transport/ipc-server.transport.d.ts.map +1 -0
- package/transport/mcp-20260728/client/mcp-stateless.client.d.ts +9 -2
- package/transport/mcp-20260728/client/mcp-stateless.client.d.ts.map +1 -1
- package/transport/mcp-20260728/dispatcher.d.ts.map +1 -1
- package/transport/mcp-20260728/request-state.d.ts +28 -0
- package/transport/mcp-20260728/request-state.d.ts.map +1 -1
- package/transport/transport.registry.d.ts +34 -0
- package/transport/transport.registry.d.ts.map +1 -1
- package/transport/web-fetch-handler.d.ts.map +1 -1
package/index.js
CHANGED
|
@@ -1859,7 +1859,7 @@ var init_session = __esm({
|
|
|
1859
1859
|
});
|
|
1860
1860
|
|
|
1861
1861
|
// libs/sdk/src/common/types/options/http/schema.ts
|
|
1862
|
-
var import_lazy_zod8, HTTP_METHODS, httpRouteSchema, bodyParserLimitSchema, corsOptionsSchema, httpOptionsSchema;
|
|
1862
|
+
var import_lazy_zod8, HTTP_METHODS, httpRouteSchema, bodyParserLimitSchema, corsOptionsSchema, securityHeaderValueSchema, securityHeadersSchema, httpOptionsSchema;
|
|
1863
1863
|
var init_schema3 = __esm({
|
|
1864
1864
|
"libs/sdk/src/common/types/options/http/schema.ts"() {
|
|
1865
1865
|
"use strict";
|
|
@@ -1897,6 +1897,19 @@ var init_schema3 = __esm({
|
|
|
1897
1897
|
credentials: import_lazy_zod8.z.boolean().optional(),
|
|
1898
1898
|
maxAge: import_lazy_zod8.z.number().optional()
|
|
1899
1899
|
});
|
|
1900
|
+
securityHeaderValueSchema = import_lazy_zod8.z.union([import_lazy_zod8.z.string(), import_lazy_zod8.z.literal(false)]);
|
|
1901
|
+
securityHeadersSchema = import_lazy_zod8.z.object({
|
|
1902
|
+
hsts: securityHeaderValueSchema.optional(),
|
|
1903
|
+
contentTypeOptions: securityHeaderValueSchema.optional(),
|
|
1904
|
+
frameOptions: securityHeaderValueSchema.optional(),
|
|
1905
|
+
custom: import_lazy_zod8.z.record(import_lazy_zod8.z.string(), import_lazy_zod8.z.string()).optional(),
|
|
1906
|
+
csp: import_lazy_zod8.z.object({
|
|
1907
|
+
enabled: import_lazy_zod8.z.boolean().optional(),
|
|
1908
|
+
directives: import_lazy_zod8.z.record(import_lazy_zod8.z.string(), import_lazy_zod8.z.union([import_lazy_zod8.z.string(), import_lazy_zod8.z.array(import_lazy_zod8.z.string())])).optional(),
|
|
1909
|
+
reportUri: import_lazy_zod8.z.string().optional(),
|
|
1910
|
+
reportOnly: import_lazy_zod8.z.boolean().optional()
|
|
1911
|
+
}).optional()
|
|
1912
|
+
});
|
|
1900
1913
|
httpOptionsSchema = import_lazy_zod8.z.object({
|
|
1901
1914
|
port: import_lazy_zod8.z.number().optional().default(Number(process.env["PORT"]) || 3e3),
|
|
1902
1915
|
// `FRONTMCP_HTTP_ENTRY_PATH` lets `frontmcp dev` propagate the configured
|
|
@@ -1955,7 +1968,9 @@ var init_schema3 = __esm({
|
|
|
1955
1968
|
* app as the MCP endpoint; public by default, `auth: true` opts into the MCP
|
|
1956
1969
|
* `session:verify` flow. Reserved-path collisions are rejected at startup.
|
|
1957
1970
|
*/
|
|
1958
|
-
routes: import_lazy_zod8.z.array(httpRouteSchema).optional()
|
|
1971
|
+
routes: import_lazy_zod8.z.array(httpRouteSchema).optional(),
|
|
1972
|
+
/** Response security headers; see `SecurityHeadersOptions`. */
|
|
1973
|
+
securityHeaders: securityHeadersSchema.optional()
|
|
1959
1974
|
});
|
|
1960
1975
|
}
|
|
1961
1976
|
});
|
|
@@ -2357,7 +2372,7 @@ var init_schema7 = __esm({
|
|
|
2357
2372
|
persistenceConfigSchema = import_lazy_zod12.z.object({
|
|
2358
2373
|
redis: redisOptionsSchema.optional(),
|
|
2359
2374
|
sqlite: sqliteOptionsSchema.optional(),
|
|
2360
|
-
defaultTtlMs: import_lazy_zod12.z.number().int().positive().
|
|
2375
|
+
defaultTtlMs: import_lazy_zod12.z.number().int().positive().optional()
|
|
2361
2376
|
}).refine((cfg) => !(cfg.redis && cfg.sqlite), {
|
|
2362
2377
|
message: "Invalid persistence config: choose either redis or sqlite, not both",
|
|
2363
2378
|
path: ["sqlite"]
|
|
@@ -5972,6 +5987,33 @@ var init_errors = __esm({
|
|
|
5972
5987
|
}
|
|
5973
5988
|
});
|
|
5974
5989
|
|
|
5990
|
+
// libs/sdk/src/common/utils/list-all-pages.utils.ts
|
|
5991
|
+
async function listAllPages(method, fetchPage, fail = (message) => new InternalMcpError(message, "LIST_PAGINATION_STALLED")) {
|
|
5992
|
+
const items = [];
|
|
5993
|
+
const seenCursors = /* @__PURE__ */ new Set();
|
|
5994
|
+
let cursor;
|
|
5995
|
+
for (let page = 0; page < MAX_LIST_PAGES; page++) {
|
|
5996
|
+
const result = await fetchPage(cursor);
|
|
5997
|
+
items.push(...result.items ?? []);
|
|
5998
|
+
const next = result.nextCursor;
|
|
5999
|
+
if (!next) return items;
|
|
6000
|
+
if (seenCursors.has(next)) {
|
|
6001
|
+
throw fail(`${method} returned the cursor "${next}" twice`);
|
|
6002
|
+
}
|
|
6003
|
+
seenCursors.add(next);
|
|
6004
|
+
cursor = next;
|
|
6005
|
+
}
|
|
6006
|
+
throw fail(`${method} did not finish within ${MAX_LIST_PAGES} pages`);
|
|
6007
|
+
}
|
|
6008
|
+
var MAX_LIST_PAGES;
|
|
6009
|
+
var init_list_all_pages_utils = __esm({
|
|
6010
|
+
"libs/sdk/src/common/utils/list-all-pages.utils.ts"() {
|
|
6011
|
+
"use strict";
|
|
6012
|
+
init_mcp_error();
|
|
6013
|
+
MAX_LIST_PAGES = 1e3;
|
|
6014
|
+
}
|
|
6015
|
+
});
|
|
6016
|
+
|
|
5975
6017
|
// libs/sdk/src/transport/mcp-handlers/skills-mcp.types.ts
|
|
5976
6018
|
var import_lazy_zod40, SkillsSearchRequestSchema, SkillsSearchResultSchema, SkillsLoadRequestSchema, SkillsLoadResultSchema, SkillsListRequestSchema, SkillsListResultSchema;
|
|
5977
6019
|
var init_skills_mcp_types = __esm({
|
|
@@ -6415,6 +6457,7 @@ var require_dist = __commonJS({
|
|
|
6415
6457
|
var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
|
|
6416
6458
|
var index_exports2 = {};
|
|
6417
6459
|
__export2(index_exports2, {
|
|
6460
|
+
SqliteDecryptionError: () => SqliteDecryptionError,
|
|
6418
6461
|
SqliteElicitationStore: () => SqliteElicitationStore,
|
|
6419
6462
|
SqliteEventStore: () => SqliteEventStore,
|
|
6420
6463
|
SqliteKvStore: () => SqliteKvStore,
|
|
@@ -6426,34 +6469,47 @@ var require_dist = __commonJS({
|
|
|
6426
6469
|
encryptValue: () => encryptValue,
|
|
6427
6470
|
loadBetterSqlite3: () => loadBetterSqlite3,
|
|
6428
6471
|
openDatabase: () => openDatabase,
|
|
6429
|
-
sqliteStorageOptionsSchema: () => sqliteStorageOptionsSchema
|
|
6472
|
+
sqliteStorageOptionsSchema: () => sqliteStorageOptionsSchema,
|
|
6473
|
+
withBusyRetry: () => withBusyRetry
|
|
6430
6474
|
});
|
|
6431
6475
|
module2.exports = __toCommonJS2(index_exports2);
|
|
6432
|
-
var
|
|
6476
|
+
var import_utils119 = require("@frontmcp/utils");
|
|
6477
|
+
var SqliteDecryptionError = class extends Error {
|
|
6478
|
+
code = "SQLITE_DECRYPTION_FAILED";
|
|
6479
|
+
constructor() {
|
|
6480
|
+
super(
|
|
6481
|
+
"SqliteKvStore: failed to decrypt a stored value. The encryption secret differs from the one the database was written with (or the value is corrupted). Restore the original secret, or delete the database file to start empty."
|
|
6482
|
+
);
|
|
6483
|
+
this.name = "SqliteDecryptionError";
|
|
6484
|
+
}
|
|
6485
|
+
};
|
|
6433
6486
|
var HKDF_SALT = new TextEncoder().encode("frontmcp-sqlite-storage-v1");
|
|
6434
6487
|
var HKDF_INFO = new TextEncoder().encode("aes-256-gcm-value-encryption");
|
|
6435
6488
|
var KEY_LENGTH = 32;
|
|
6436
6489
|
function deriveEncryptionKey(secret) {
|
|
6437
6490
|
const ikm = new TextEncoder().encode(secret);
|
|
6438
|
-
return (0,
|
|
6491
|
+
return (0, import_utils119.hkdfSha256)(ikm, HKDF_SALT, HKDF_INFO, KEY_LENGTH);
|
|
6439
6492
|
}
|
|
6440
6493
|
var SEPARATOR = ":";
|
|
6441
6494
|
function encryptValue(key, plaintext) {
|
|
6442
|
-
const iv = (0,
|
|
6495
|
+
const iv = (0, import_utils119.randomBytes)(12);
|
|
6443
6496
|
const plaintextBytes = new TextEncoder().encode(plaintext);
|
|
6444
|
-
const { ciphertext, tag } = (0,
|
|
6445
|
-
return [(0,
|
|
6497
|
+
const { ciphertext, tag } = (0, import_utils119.encryptAesGcm)(key, plaintextBytes, iv);
|
|
6498
|
+
return [(0, import_utils119.base64urlEncode)(iv), (0, import_utils119.base64urlEncode)(tag), (0, import_utils119.base64urlEncode)(ciphertext)].join(SEPARATOR);
|
|
6446
6499
|
}
|
|
6447
6500
|
function decryptValue(key, encrypted) {
|
|
6448
6501
|
const parts = encrypted.split(SEPARATOR);
|
|
6449
6502
|
if (parts.length !== 3) {
|
|
6450
6503
|
throw new Error("Invalid encrypted value format");
|
|
6451
6504
|
}
|
|
6452
|
-
const iv = (0,
|
|
6453
|
-
const tag = (0,
|
|
6454
|
-
const ciphertext = (0,
|
|
6455
|
-
|
|
6456
|
-
|
|
6505
|
+
const iv = (0, import_utils119.base64urlDecode)(parts[0]);
|
|
6506
|
+
const tag = (0, import_utils119.base64urlDecode)(parts[1]);
|
|
6507
|
+
const ciphertext = (0, import_utils119.base64urlDecode)(parts[2]);
|
|
6508
|
+
try {
|
|
6509
|
+
return new TextDecoder().decode((0, import_utils119.decryptAesGcm)(key, ciphertext, iv, tag));
|
|
6510
|
+
} catch {
|
|
6511
|
+
throw new SqliteDecryptionError();
|
|
6512
|
+
}
|
|
6457
6513
|
}
|
|
6458
6514
|
var import_utils210 = require("@frontmcp/utils");
|
|
6459
6515
|
var cached = null;
|
|
@@ -6466,7 +6522,27 @@ var require_dist = __commonJS({
|
|
|
6466
6522
|
return mod;
|
|
6467
6523
|
}
|
|
6468
6524
|
var MEMORY_PATH = ":memory:";
|
|
6469
|
-
|
|
6525
|
+
var DEFAULT_BUSY_TIMEOUT_MS = 5e3;
|
|
6526
|
+
function isBusyError(err) {
|
|
6527
|
+
const code = err?.code;
|
|
6528
|
+
return code === "SQLITE_BUSY" || code === "SQLITE_BUSY_RECOVERY" || code === "SQLITE_BUSY_SNAPSHOT";
|
|
6529
|
+
}
|
|
6530
|
+
function sleepSync(ms) {
|
|
6531
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
6532
|
+
}
|
|
6533
|
+
function withBusyRetry(operation, options = {}) {
|
|
6534
|
+
const attempts = options.attempts ?? 5;
|
|
6535
|
+
const delayMs = options.delayMs ?? 50;
|
|
6536
|
+
for (let attempt = 1; ; attempt++) {
|
|
6537
|
+
try {
|
|
6538
|
+
return operation();
|
|
6539
|
+
} catch (err) {
|
|
6540
|
+
if (!isBusyError(err) || attempt >= attempts) throw err;
|
|
6541
|
+
sleepSync(delayMs * attempt);
|
|
6542
|
+
}
|
|
6543
|
+
}
|
|
6544
|
+
}
|
|
6545
|
+
function openDatabase(path3, storeName, options = {}) {
|
|
6470
6546
|
const BetterSqlite3 = loadBetterSqlite3();
|
|
6471
6547
|
if (path3 !== MEMORY_PATH && path3 !== "") {
|
|
6472
6548
|
const dir = (0, import_utils210.dirname)(path3);
|
|
@@ -6475,16 +6551,28 @@ var require_dist = __commonJS({
|
|
|
6475
6551
|
(0, import_utils210.ensureDirSync)(dir);
|
|
6476
6552
|
} catch (err) {
|
|
6477
6553
|
const message = err instanceof Error ? err.message : String(err);
|
|
6478
|
-
throw new Error(`${storeName}: failed to create directory "${dir}" for database "${path3}": ${message}
|
|
6554
|
+
throw new Error(`${storeName}: failed to create directory "${dir}" for database "${path3}": ${message}`, {
|
|
6555
|
+
cause: err
|
|
6556
|
+
});
|
|
6479
6557
|
}
|
|
6480
6558
|
}
|
|
6481
6559
|
}
|
|
6560
|
+
let db;
|
|
6561
|
+
try {
|
|
6562
|
+
db = new BetterSqlite3(path3);
|
|
6563
|
+
} catch (err) {
|
|
6564
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
6565
|
+
throw new Error(`${storeName}: failed to open database at "${path3}": ${message}`, { cause: err });
|
|
6566
|
+
}
|
|
6482
6567
|
try {
|
|
6483
|
-
|
|
6568
|
+
db.pragma(`busy_timeout = ${Math.max(0, Math.floor(options.busyTimeoutMs ?? DEFAULT_BUSY_TIMEOUT_MS))}`);
|
|
6569
|
+
if (options.walMode) withBusyRetry(() => db.pragma("journal_mode = WAL"));
|
|
6484
6570
|
} catch (err) {
|
|
6571
|
+
db.close();
|
|
6485
6572
|
const message = err instanceof Error ? err.message : String(err);
|
|
6486
|
-
throw new Error(`${storeName}: failed to
|
|
6573
|
+
throw new Error(`${storeName}: failed to configure database at "${path3}": ${message}`, { cause: err });
|
|
6487
6574
|
}
|
|
6575
|
+
return db;
|
|
6488
6576
|
}
|
|
6489
6577
|
var SqliteKvStore = class {
|
|
6490
6578
|
db;
|
|
@@ -6492,14 +6580,14 @@ var require_dist = __commonJS({
|
|
|
6492
6580
|
cleanupTimer = null;
|
|
6493
6581
|
stmts = null;
|
|
6494
6582
|
constructor(options) {
|
|
6495
|
-
this.db = openDatabase(options.path, "SqliteKvStore"
|
|
6496
|
-
|
|
6497
|
-
|
|
6498
|
-
}
|
|
6583
|
+
this.db = openDatabase(options.path, "SqliteKvStore", {
|
|
6584
|
+
busyTimeoutMs: options.busyTimeoutMs,
|
|
6585
|
+
walMode: options.walMode !== false
|
|
6586
|
+
});
|
|
6499
6587
|
if (options.encryption?.secret) {
|
|
6500
6588
|
this.encryptionKey = deriveEncryptionKey(options.encryption.secret);
|
|
6501
6589
|
}
|
|
6502
|
-
this.initSchema();
|
|
6590
|
+
withBusyRetry(() => this.initSchema());
|
|
6503
6591
|
this.prepareStatements();
|
|
6504
6592
|
const cleanupInterval = options.ttlCleanupIntervalMs ?? 6e4;
|
|
6505
6593
|
if (cleanupInterval > 0) {
|
|
@@ -6958,17 +7046,17 @@ var require_dist = __commonJS({
|
|
|
6958
7046
|
encryptionKey = null;
|
|
6959
7047
|
stmts = null;
|
|
6960
7048
|
constructor(options) {
|
|
6961
|
-
this.db = openDatabase(options.path, "SqliteTaskStore"
|
|
6962
|
-
|
|
6963
|
-
|
|
6964
|
-
}
|
|
7049
|
+
this.db = openDatabase(options.path, "SqliteTaskStore", {
|
|
7050
|
+
busyTimeoutMs: options.busyTimeoutMs,
|
|
7051
|
+
walMode: options.walMode !== false
|
|
7052
|
+
});
|
|
6965
7053
|
this.logger = options.logger;
|
|
6966
7054
|
this.liveness = options.livenessProbe ?? defaultLivenessProbe;
|
|
6967
7055
|
if (options.encryption?.secret) {
|
|
6968
7056
|
this.encryptionKey = deriveEncryptionKey(options.encryption.secret);
|
|
6969
7057
|
}
|
|
6970
7058
|
this.emitter.setMaxListeners(200);
|
|
6971
|
-
this.initSchema();
|
|
7059
|
+
withBusyRetry(() => this.initSchema());
|
|
6972
7060
|
this.prepareStatements();
|
|
6973
7061
|
const cleanupInterval = options.ttlCleanupIntervalMs ?? 6e4;
|
|
6974
7062
|
if (cleanupInterval > 0) {
|
|
@@ -7205,13 +7293,13 @@ var require_dist = __commonJS({
|
|
|
7205
7293
|
cleanupTimer = null;
|
|
7206
7294
|
stmts = null;
|
|
7207
7295
|
constructor(options) {
|
|
7208
|
-
this.db = openDatabase(options.path, "SqliteEventStore"
|
|
7209
|
-
|
|
7210
|
-
|
|
7211
|
-
}
|
|
7296
|
+
this.db = openDatabase(options.path, "SqliteEventStore", {
|
|
7297
|
+
busyTimeoutMs: options.busyTimeoutMs,
|
|
7298
|
+
walMode: options.walMode !== false
|
|
7299
|
+
});
|
|
7212
7300
|
this.maxEvents = options.maxEvents ?? 1e4;
|
|
7213
7301
|
this.ttlMs = options.ttlMs ?? 3e5;
|
|
7214
|
-
this.initSchema();
|
|
7302
|
+
withBusyRetry(() => this.initSchema());
|
|
7215
7303
|
this.prepareStatements();
|
|
7216
7304
|
const cleanupInterval = options.ttlCleanupIntervalMs ?? 6e4;
|
|
7217
7305
|
if (cleanupInterval > 0) {
|
|
@@ -7346,7 +7434,8 @@ var require_dist = __commonJS({
|
|
|
7346
7434
|
secret: import_lazy_zod113.z.string().min(1)
|
|
7347
7435
|
}).optional(),
|
|
7348
7436
|
ttlCleanupIntervalMs: import_lazy_zod113.z.number().int().nonnegative().optional().default(6e4),
|
|
7349
|
-
walMode: import_lazy_zod113.z.boolean().optional().default(true)
|
|
7437
|
+
walMode: import_lazy_zod113.z.boolean().optional().default(true),
|
|
7438
|
+
busyTimeoutMs: import_lazy_zod113.z.number().int().nonnegative().optional().default(5e3)
|
|
7350
7439
|
});
|
|
7351
7440
|
}
|
|
7352
7441
|
});
|
|
@@ -7364,6 +7453,14 @@ function detectStorageType(storage, configuredType) {
|
|
|
7364
7453
|
if ((0, import_utils15.getEnv)("REDIS_URL") || (0, import_utils15.getEnv)("REDIS_HOST")) return "redis";
|
|
7365
7454
|
return "memory";
|
|
7366
7455
|
}
|
|
7456
|
+
function isExplicitStorage(storage) {
|
|
7457
|
+
return Boolean(storage?.type && storage.type !== "auto");
|
|
7458
|
+
}
|
|
7459
|
+
function resolvesToVercelKvTaskBackend(redis, storage) {
|
|
7460
|
+
if (isExplicitStorage(storage)) return storage.type === "vercel-kv";
|
|
7461
|
+
if (redis) return "provider" in redis && redis.provider === "vercel-kv";
|
|
7462
|
+
return Boolean((0, import_utils15.getEnv)("KV_REST_API_URL"));
|
|
7463
|
+
}
|
|
7367
7464
|
async function createTaskStore(options = {}) {
|
|
7368
7465
|
const { storage: storageConfig, redis, keyPrefix = "mcp:task:", logger, isEdgeRuntime: isEdgeRuntime3 = false, sqlite } = options;
|
|
7369
7466
|
if (isEdgeRuntime3 && sqlite) {
|
|
@@ -7388,7 +7485,7 @@ async function createTaskStore(options = {}) {
|
|
|
7388
7485
|
return { store: store2, type: "sqlite" };
|
|
7389
7486
|
}
|
|
7390
7487
|
let finalStorageConfig = storageConfig;
|
|
7391
|
-
if (redis && !storageConfig) {
|
|
7488
|
+
if (redis && !isExplicitStorage(storageConfig)) {
|
|
7392
7489
|
if ("provider" in redis && redis.provider === "vercel-kv") {
|
|
7393
7490
|
throw new TaskStoreNotSupportedError(
|
|
7394
7491
|
"Vercel KV is not supported for task stores. Task result blocking and cancel signalling require pub/sub. Use Redis or Upstash instead."
|
|
@@ -7416,7 +7513,8 @@ async function createTaskStore(options = {}) {
|
|
|
7416
7513
|
};
|
|
7417
7514
|
}
|
|
7418
7515
|
}
|
|
7419
|
-
|
|
7516
|
+
const explicitBackend = isExplicitStorage(storageConfig) || Boolean(redis);
|
|
7517
|
+
if (finalStorageConfig?.type === "vercel-kv" || !explicitBackend && (0, import_utils15.getEnv)("KV_REST_API_URL")) {
|
|
7420
7518
|
throw new TaskStoreNotSupportedError(
|
|
7421
7519
|
"Vercel KV is not supported for task stores (pub/sub required). Use Redis or Upstash."
|
|
7422
7520
|
);
|
|
@@ -8657,11 +8755,8 @@ var init_get_prompt_request_handler = __esm({
|
|
|
8657
8755
|
|
|
8658
8756
|
// libs/sdk/src/notification/notification.service.ts
|
|
8659
8757
|
function hasMcpAppsExtension(capabilities) {
|
|
8660
|
-
|
|
8661
|
-
|
|
8662
|
-
}
|
|
8663
|
-
const uiExtension = capabilities.experimental[MCP_APPS_EXTENSION_KEY];
|
|
8664
|
-
return uiExtension !== void 0 && uiExtension !== null;
|
|
8758
|
+
const declared = capabilities?.experimental?.[MCP_APPS_EXTENSION_KEY] ?? capabilities?.extensions?.[MCP_APPS_EXTENSION_KEY];
|
|
8759
|
+
return declared !== void 0 && declared !== null;
|
|
8665
8760
|
}
|
|
8666
8761
|
function detectPlatformFromCapabilities(capabilities) {
|
|
8667
8762
|
if (hasMcpAppsExtension(capabilities)) {
|
|
@@ -11263,6 +11358,8 @@ var init_ui_shared = __esm({
|
|
|
11263
11358
|
widgets = /* @__PURE__ */ new Map();
|
|
11264
11359
|
manifests = /* @__PURE__ */ new Map();
|
|
11265
11360
|
resourceMeta = /* @__PURE__ */ new Map();
|
|
11361
|
+
uiTools = /* @__PURE__ */ new Set();
|
|
11362
|
+
customUris = /* @__PURE__ */ new Map();
|
|
11266
11363
|
resolver;
|
|
11267
11364
|
options;
|
|
11268
11365
|
constructor(resolver, options = {}) {
|
|
@@ -11277,6 +11374,28 @@ var init_ui_shared = __esm({
|
|
|
11277
11374
|
logger: this.options.logger
|
|
11278
11375
|
};
|
|
11279
11376
|
}
|
|
11377
|
+
/**
|
|
11378
|
+
* Record that `toolName` has a UI, and the custom `ui.resourceUri` it advertises (if any).
|
|
11379
|
+
* `tools/list` advertises that URI verbatim, so `resources/read` must resolve it back to the
|
|
11380
|
+
* tool; and only registered tools may be served a placeholder widget.
|
|
11381
|
+
*/
|
|
11382
|
+
registerTool(toolName, resourceUri) {
|
|
11383
|
+
this.uiTools.add(toolName);
|
|
11384
|
+
if (resourceUri) this.customUris.set(resourceUri, toolName);
|
|
11385
|
+
}
|
|
11386
|
+
/** The tool that advertised `uri` as its custom `ui.resourceUri`. */
|
|
11387
|
+
resolveCustomUri(uri) {
|
|
11388
|
+
return this.customUris.get(uri);
|
|
11389
|
+
}
|
|
11390
|
+
/**
|
|
11391
|
+
* Whether `name` (or its app-qualified form `app:name`) is a tool with a UI.
|
|
11392
|
+
*/
|
|
11393
|
+
hasTool(name44) {
|
|
11394
|
+
const known = (n) => this.uiTools.has(n) || this.widgets.has(n) || this.resourceMeta.has(n);
|
|
11395
|
+
if (known(name44)) return true;
|
|
11396
|
+
const sep = name44.indexOf(":");
|
|
11397
|
+
return sep > 0 && known(name44.slice(sep + 1));
|
|
11398
|
+
}
|
|
11280
11399
|
getStaticWidget(name44) {
|
|
11281
11400
|
return this.widgets.get(name44);
|
|
11282
11401
|
}
|
|
@@ -11305,8 +11424,9 @@ var init_ui_shared = __esm({
|
|
|
11305
11424
|
const output = options["output"] ?? {};
|
|
11306
11425
|
const uiConfig = options["uiConfig"];
|
|
11307
11426
|
const resourceMode = uiConfig?.["resourceMode"] ?? options["resourceMode"];
|
|
11308
|
-
if (!toolName
|
|
11427
|
+
if (!toolName) return;
|
|
11309
11428
|
this.updateResourceMetaFromConfig(toolName, uiConfig);
|
|
11429
|
+
if (!template) return;
|
|
11310
11430
|
const result = (0, import_adapters.renderToolTemplate)({
|
|
11311
11431
|
toolName,
|
|
11312
11432
|
input,
|
|
@@ -11315,6 +11435,7 @@ var init_ui_shared = __esm({
|
|
|
11315
11435
|
resolver: this.resolver,
|
|
11316
11436
|
resourceMode,
|
|
11317
11437
|
sizing: extractSizing(uiConfig),
|
|
11438
|
+
csp: uiConfig?.["csp"],
|
|
11318
11439
|
...this.stringResultOptions(uiConfig)
|
|
11319
11440
|
});
|
|
11320
11441
|
this.widgets.set(toolName, result.html);
|
|
@@ -11393,6 +11514,7 @@ var init_ui_shared = __esm({
|
|
|
11393
11514
|
resolver: this.resolver,
|
|
11394
11515
|
resourceMode,
|
|
11395
11516
|
sizing: extractSizing(uiConfig),
|
|
11517
|
+
csp: uiConfig?.["csp"],
|
|
11396
11518
|
...this.stringResultOptions(uiConfig)
|
|
11397
11519
|
});
|
|
11398
11520
|
return { meta: result.meta };
|
|
@@ -11445,26 +11567,14 @@ function handleUIResourceRead(uri, registry, platformType) {
|
|
|
11445
11567
|
return { handled: false };
|
|
11446
11568
|
}
|
|
11447
11569
|
const mimeType = getUIResourceMimeType(platformType);
|
|
11448
|
-
const
|
|
11570
|
+
const customTool = registry.resolveCustomUri(uri);
|
|
11571
|
+
const widgetParsed = customTool ? { toolName: customTool } : parseWidgetUri(uri);
|
|
11449
11572
|
if (widgetParsed) {
|
|
11450
|
-
|
|
11451
|
-
|
|
11452
|
-
if (cachedWidget) {
|
|
11453
|
-
return {
|
|
11454
|
-
handled: true,
|
|
11455
|
-
result: {
|
|
11456
|
-
contents: [
|
|
11457
|
-
{
|
|
11458
|
-
uri,
|
|
11459
|
-
mimeType,
|
|
11460
|
-
text: cachedWidget,
|
|
11461
|
-
...resourceMeta ? { _meta: resourceMeta } : {}
|
|
11462
|
-
}
|
|
11463
|
-
]
|
|
11464
|
-
}
|
|
11465
|
-
};
|
|
11573
|
+
if (!registry.hasTool(widgetParsed.toolName)) {
|
|
11574
|
+
return { handled: true, error: `No UI widget is registered for ${uri}` };
|
|
11466
11575
|
}
|
|
11467
|
-
const
|
|
11576
|
+
const resourceMeta = buildResourceMetaForWidget(registry, widgetParsed.toolName);
|
|
11577
|
+
const html = registry.getStaticWidget(widgetParsed.toolName) ?? generatePlaceholderWidget(widgetParsed.toolName);
|
|
11468
11578
|
return {
|
|
11469
11579
|
handled: true,
|
|
11470
11580
|
result: {
|
|
@@ -12043,6 +12153,7 @@ var init_direct_client = __esm({
|
|
|
12043
12153
|
"use strict";
|
|
12044
12154
|
import_protocol30 = require("@frontmcp/protocol");
|
|
12045
12155
|
import_utils29 = require("@frontmcp/utils");
|
|
12156
|
+
init_list_all_pages_utils();
|
|
12046
12157
|
init_errors();
|
|
12047
12158
|
init_skills_mcp_types();
|
|
12048
12159
|
init_llm_platform();
|
|
@@ -12189,8 +12300,11 @@ var init_direct_client = __esm({
|
|
|
12189
12300
|
// Tool Operations (platform-formatted)
|
|
12190
12301
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
12191
12302
|
async listTools() {
|
|
12192
|
-
const
|
|
12193
|
-
|
|
12303
|
+
const tools = await listAllPages("tools/list", async (cursor) => {
|
|
12304
|
+
const result = await this.mcpClient.listTools(cursor ? { cursor } : void 0);
|
|
12305
|
+
return { items: result.tools, nextCursor: result.nextCursor };
|
|
12306
|
+
});
|
|
12307
|
+
return formatToolsForPlatform(tools, this.platform);
|
|
12194
12308
|
}
|
|
12195
12309
|
async callTool(name44, args) {
|
|
12196
12310
|
const result = await this.mcpClient.callTool({
|
|
@@ -12203,19 +12317,34 @@ var init_direct_client = __esm({
|
|
|
12203
12317
|
// Resource Operations (raw format)
|
|
12204
12318
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
12205
12319
|
async listResources() {
|
|
12206
|
-
|
|
12320
|
+
const resources = await listAllPages("resources/list", async (cursor) => {
|
|
12321
|
+
const result = await this.mcpClient.listResources(cursor ? { cursor } : void 0);
|
|
12322
|
+
return { items: result.resources, nextCursor: result.nextCursor };
|
|
12323
|
+
});
|
|
12324
|
+
return { resources };
|
|
12207
12325
|
}
|
|
12208
12326
|
async readResource(uri) {
|
|
12209
12327
|
return this.mcpClient.readResource({ uri });
|
|
12210
12328
|
}
|
|
12211
12329
|
async listResourceTemplates() {
|
|
12212
|
-
|
|
12330
|
+
const resourceTemplates = await listAllPages(
|
|
12331
|
+
"resources/templates/list",
|
|
12332
|
+
async (cursor) => {
|
|
12333
|
+
const result = await this.mcpClient.listResourceTemplates(cursor ? { cursor } : void 0);
|
|
12334
|
+
return { items: result.resourceTemplates, nextCursor: result.nextCursor };
|
|
12335
|
+
}
|
|
12336
|
+
);
|
|
12337
|
+
return { resourceTemplates };
|
|
12213
12338
|
}
|
|
12214
12339
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
12215
12340
|
// Prompt Operations (raw format)
|
|
12216
12341
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
12217
12342
|
async listPrompts() {
|
|
12218
|
-
|
|
12343
|
+
const prompts = await listAllPages("prompts/list", async (cursor) => {
|
|
12344
|
+
const result = await this.mcpClient.listPrompts(cursor ? { cursor } : void 0);
|
|
12345
|
+
return { items: result.prompts, nextCursor: result.nextCursor };
|
|
12346
|
+
});
|
|
12347
|
+
return { prompts };
|
|
12219
12348
|
}
|
|
12220
12349
|
async getPrompt(name44, args) {
|
|
12221
12350
|
return this.mcpClient.getPrompt({
|
|
@@ -12943,8 +13072,8 @@ function createRemoteAppProbe(appId, provider) {
|
|
|
12943
13072
|
name: `remote:${appId}`,
|
|
12944
13073
|
async check() {
|
|
12945
13074
|
const result = provider.getHealthStatus(appId);
|
|
12946
|
-
if (!result) {
|
|
12947
|
-
return { status: "
|
|
13075
|
+
if (!result || result.status === "unknown" && result.consecutiveFailures === 0) {
|
|
13076
|
+
return { status: "degraded", details: { state: "unknown" } };
|
|
12948
13077
|
}
|
|
12949
13078
|
return {
|
|
12950
13079
|
status: result.status === "healthy" ? "healthy" : result.status === "degraded" ? "degraded" : "unhealthy",
|
|
@@ -14060,6 +14189,12 @@ var init_frontmcp_context = __esm({
|
|
|
14060
14189
|
// =====================
|
|
14061
14190
|
/** Request metadata (headers, user-agent, etc.) */
|
|
14062
14191
|
metadata;
|
|
14192
|
+
/**
|
|
14193
|
+
* The hosting platform's bindings object for this request: a Cloudflare Worker's `env`
|
|
14194
|
+
* (KV namespaces, D1 databases, R2 buckets, Durable Objects, `[vars]`, secrets).
|
|
14195
|
+
* `undefined` on Node, where bindings do not exist.
|
|
14196
|
+
*/
|
|
14197
|
+
platformEnv;
|
|
14063
14198
|
// =====================
|
|
14064
14199
|
// Auth (mutable, progressively populated)
|
|
14065
14200
|
// =====================
|
|
@@ -14095,6 +14230,7 @@ var init_frontmcp_context = __esm({
|
|
|
14095
14230
|
this.traceContext = args.traceContext ?? generateTraceContext();
|
|
14096
14231
|
this.timestamp = args.timestamp ?? Date.now();
|
|
14097
14232
|
this._authInfo = args.authInfo ?? {};
|
|
14233
|
+
this.platformEnv = args.platformEnv;
|
|
14098
14234
|
this.config = {
|
|
14099
14235
|
forwardCallerTokenTo: toOrigins(args.config?.forwardCallerTokenTo),
|
|
14100
14236
|
forwardCustomHeadersTo: toOrigins(args.config?.forwardCustomHeadersTo),
|
|
@@ -14797,6 +14933,7 @@ var init_frontmcp_context_storage = __esm({
|
|
|
14797
14933
|
import_utils39 = require("@frontmcp/utils");
|
|
14798
14934
|
init_decorators();
|
|
14799
14935
|
init_metadata();
|
|
14936
|
+
init_tokens();
|
|
14800
14937
|
init_mcp_error();
|
|
14801
14938
|
init_frontmcp_context();
|
|
14802
14939
|
init_metadata_utils();
|
|
@@ -14864,7 +15001,12 @@ var init_frontmcp_context_storage = __esm({
|
|
|
14864
15001
|
const headers = request.headers ?? {};
|
|
14865
15002
|
const headerSessionId = typeof headers["mcp-session-id"] === "string" ? headers["mcp-session-id"].trim() : "";
|
|
14866
15003
|
const sessionId = headerSessionId.length > 0 ? headerSessionId : `anon:${(0, import_utils39.randomUUID)()}`;
|
|
14867
|
-
|
|
15004
|
+
const platformEnv = request[ServerRequestTokens.webEnv];
|
|
15005
|
+
return this.runFromHeaders(
|
|
15006
|
+
headers,
|
|
15007
|
+
{ sessionId, scopeId, peerAddress: request.socket?.remoteAddress, platformEnv },
|
|
15008
|
+
fn
|
|
15009
|
+
);
|
|
14868
15010
|
}
|
|
14869
15011
|
withServerConfig(args) {
|
|
14870
15012
|
return { ...args, config: { ...this.contextConfig, ...args.config } };
|
|
@@ -21917,6 +22059,14 @@ var init_tool_credentials_gate = __esm({
|
|
|
21917
22059
|
});
|
|
21918
22060
|
|
|
21919
22061
|
// libs/sdk/src/tool/flows/call-tool.flow.ts
|
|
22062
|
+
function declaredOutput(tool, output) {
|
|
22063
|
+
if (!tool?.outputSchema || typeof output !== "object" || output === null || Array.isArray(output)) return output;
|
|
22064
|
+
if (Array.isArray(output["content"])) return output;
|
|
22065
|
+
const parsed = tool.safeParseOutput(output);
|
|
22066
|
+
if (!parsed.success) return output;
|
|
22067
|
+
const structured = parsed.data.structuredContent;
|
|
22068
|
+
return typeof structured === "object" && structured !== null && !Array.isArray(structured) ? structured : output;
|
|
22069
|
+
}
|
|
21920
22070
|
function toolNameCandidates(name44) {
|
|
21921
22071
|
if (!/[-_]/.test(name44)) return [name44];
|
|
21922
22072
|
return [name44, name44.includes("_") ? name44.replace(/_/g, "-") : name44.replace(/-/g, "_")];
|
|
@@ -21992,6 +22142,9 @@ var init_call_tool_flow = __esm({
|
|
|
21992
22142
|
uiResult: import_lazy_zod57.z.any().optional(),
|
|
21993
22143
|
// UI metadata from rendering (merged into _meta)
|
|
21994
22144
|
uiMeta: import_lazy_zod57.z.record(import_lazy_zod57.z.string(), import_lazy_zod57.z.unknown()).optional(),
|
|
22145
|
+
// Metadata hooks add to the result (e.g. the cache plugin's `cache: 'hit'`), merged into the
|
|
22146
|
+
// result's _meta; never merged into rawOutput, which is the tool's data
|
|
22147
|
+
resultMeta: import_lazy_zod57.z.record(import_lazy_zod57.z.string(), import_lazy_zod57.z.unknown()).optional(),
|
|
21995
22148
|
// Progress token from request's _meta (for progress notifications)
|
|
21996
22149
|
progressToken: import_lazy_zod57.z.union([import_lazy_zod57.z.string(), import_lazy_zod57.z.number()]).optional(),
|
|
21997
22150
|
// JSON-RPC request ID (for elicitation routing)
|
|
@@ -22647,7 +22800,7 @@ ${JSON.stringify(error.schema, null, 2)}
|
|
|
22647
22800
|
this.logger.verbose("execute:done (elicitation fire-and-forget fallback)");
|
|
22648
22801
|
return;
|
|
22649
22802
|
}
|
|
22650
|
-
if (isClientFacingError(error)) throw error;
|
|
22803
|
+
if (isClientFacingError(error) || error instanceof InvalidOutputError) throw error;
|
|
22651
22804
|
throw new ToolExecutionError(
|
|
22652
22805
|
this.state.tool?.metadata.name || "unknown",
|
|
22653
22806
|
error instanceof Error ? error : void 0
|
|
@@ -22690,7 +22843,8 @@ ${JSON.stringify(error.schema, null, 2)}
|
|
|
22690
22843
|
}
|
|
22691
22844
|
async applyUI() {
|
|
22692
22845
|
this.logger.verbose("applyUI:start");
|
|
22693
|
-
const { tool, rawOutput, input } = this.state;
|
|
22846
|
+
const { tool, rawOutput: executeOutput, input } = this.state;
|
|
22847
|
+
const rawOutput = declaredOutput(tool, executeOutput);
|
|
22694
22848
|
const ctx = this.input.ctx;
|
|
22695
22849
|
if (ctx?._skipUI) {
|
|
22696
22850
|
this.logger.verbose("applyUI:skip (agent context - structured data only)");
|
|
@@ -22819,7 +22973,7 @@ ${JSON.stringify(error.schema, null, 2)}
|
|
|
22819
22973
|
}
|
|
22820
22974
|
async finalize() {
|
|
22821
22975
|
this.logger.verbose("finalize:start");
|
|
22822
|
-
const { tool, rawOutput, uiResult, uiMeta } = this.state;
|
|
22976
|
+
const { tool, rawOutput, uiResult, uiMeta, resultMeta } = this.state;
|
|
22823
22977
|
if (!tool) {
|
|
22824
22978
|
this.logger.verbose("finalize: skipping (no tool in state)");
|
|
22825
22979
|
return;
|
|
@@ -22862,6 +23016,9 @@ ${JSON.stringify(error.schema, null, 2)}
|
|
|
22862
23016
|
if (rawMeta) {
|
|
22863
23017
|
result._meta = { ...result._meta, ...rawMeta };
|
|
22864
23018
|
}
|
|
23019
|
+
if (resultMeta) {
|
|
23020
|
+
result._meta = { ...result._meta, ...resultMeta };
|
|
23021
|
+
}
|
|
22865
23022
|
if (uiResult) {
|
|
22866
23023
|
result.content = uiResult.content;
|
|
22867
23024
|
if (uiResult.structuredContent !== void 0 && uiResult.structuredContent !== null) {
|
|
@@ -24313,6 +24470,38 @@ var init_context = __esm({
|
|
|
24313
24470
|
}
|
|
24314
24471
|
});
|
|
24315
24472
|
|
|
24473
|
+
// libs/sdk/src/errors/misconfiguration.ts
|
|
24474
|
+
function findMisconfiguration(error) {
|
|
24475
|
+
let current = error;
|
|
24476
|
+
for (let depth = 0; current instanceof Error && depth < 5; depth++) {
|
|
24477
|
+
const code = current.code;
|
|
24478
|
+
if (typeof code === "string" && Object.prototype.hasOwnProperty.call(MISCONFIGURATION_REMEDIES, code)) {
|
|
24479
|
+
return { code, remedy: MISCONFIGURATION_REMEDIES[code] };
|
|
24480
|
+
}
|
|
24481
|
+
if (current.name === "ZodError") return { code: "CONFIG_INVALID", remedy: CONFIG_INVALID_REMEDY };
|
|
24482
|
+
current = current.cause;
|
|
24483
|
+
}
|
|
24484
|
+
return void 0;
|
|
24485
|
+
}
|
|
24486
|
+
function misconfigurationBody(m) {
|
|
24487
|
+
return { error: "server_misconfigured", code: m.code, message: m.remedy };
|
|
24488
|
+
}
|
|
24489
|
+
var MISCONFIGURATION_REMEDIES, CONFIG_INVALID_REMEDY;
|
|
24490
|
+
var init_misconfiguration = __esm({
|
|
24491
|
+
"libs/sdk/src/errors/misconfiguration.ts"() {
|
|
24492
|
+
"use strict";
|
|
24493
|
+
MISCONFIGURATION_REMEDIES = {
|
|
24494
|
+
SESSION_SECRET_REQUIRED: "Set MCP_SESSION_SECRET in the deployment environment (e.g. `wrangler secret put MCP_SESSION_SECRET` on Cloudflare, or the platform environment settings on Node, Vercel and Lambda). Session IDs are encrypted with it, and production refuses the development machine-id fallback.",
|
|
24495
|
+
JWT_SECRET_INVALID: "JWT_SECRET is present but too weak: HS256 requires at least 32 bytes (RFC 7518). Replace it with `openssl rand -hex 32`.",
|
|
24496
|
+
JWT_SECRET_REQUIRED: "Set JWT_SECRET in the deployment environment (e.g. `wrangler secret put JWT_SECRET`). Tokens are signed with it; production refuses the random per-process fallback because tokens would not survive a restart or verify across instances.",
|
|
24497
|
+
// The startup checks: a server whose entries ask for protection nothing gives them does not start.
|
|
24498
|
+
UNENFORCED_METADATA: "An entry declares a field only a plugin enforces (approval, featureFlag, ...) and no installed plugin that enforces it reaches the entry, so the server refuses to start. Install the plugin or remove the field; the server log names the entries.",
|
|
24499
|
+
AUTH_CONFIGURATION_ERROR: "The auth or authorities configuration is invalid (for example, entries declare authorities and the server has no authorities option, or a rule checks nothing), so the server refuses to start. The server log names the entries."
|
|
24500
|
+
};
|
|
24501
|
+
CONFIG_INVALID_REMEDY = "The FrontMCP configuration failed validation, so the server refuses to start. The server log names the invalid fields.";
|
|
24502
|
+
}
|
|
24503
|
+
});
|
|
24504
|
+
|
|
24316
24505
|
// libs/sdk/src/server/server.validation.ts
|
|
24317
24506
|
function applyHeaders(res, headers) {
|
|
24318
24507
|
if (!headers) return;
|
|
@@ -24625,6 +24814,7 @@ var init_flow_instance = __esm({
|
|
|
24625
24814
|
init_common();
|
|
24626
24815
|
init_context();
|
|
24627
24816
|
init_errors();
|
|
24817
|
+
init_misconfiguration();
|
|
24628
24818
|
init_server_validation();
|
|
24629
24819
|
init_flow_http_path();
|
|
24630
24820
|
init_flow_stages();
|
|
@@ -24684,6 +24874,15 @@ var init_flow_instance = __esm({
|
|
|
24684
24874
|
return writeHttpResponse(response, e.output);
|
|
24685
24875
|
}
|
|
24686
24876
|
}
|
|
24877
|
+
const misconfiguration = findMisconfiguration(e);
|
|
24878
|
+
if (misconfiguration) {
|
|
24879
|
+
this.logger.error("Server misconfigured", { flow: this.name, code: misconfiguration.code });
|
|
24880
|
+
return writeHttpResponse(response, {
|
|
24881
|
+
kind: "json",
|
|
24882
|
+
status: 500,
|
|
24883
|
+
body: misconfigurationBody(misconfiguration)
|
|
24884
|
+
});
|
|
24885
|
+
}
|
|
24687
24886
|
if (e instanceof PublicMcpError) {
|
|
24688
24887
|
const challenge = e.wwwAuthenticate;
|
|
24689
24888
|
this.logger.warn("Public error in flow", {
|
|
@@ -25396,14 +25595,90 @@ function collectDynamicProviders(klass, options) {
|
|
|
25396
25595
|
}
|
|
25397
25596
|
return out;
|
|
25398
25597
|
}
|
|
25598
|
+
function collectDynamicTools(klass, options) {
|
|
25599
|
+
const chain = [];
|
|
25600
|
+
for (let k = klass; k && k !== Function.prototype; k = Object.getPrototypeOf(k)) {
|
|
25601
|
+
chain.push(k);
|
|
25602
|
+
}
|
|
25603
|
+
const out = [];
|
|
25604
|
+
for (let i = chain.length - 1; i >= 0; i--) {
|
|
25605
|
+
const k = chain[i];
|
|
25606
|
+
if (Object.prototype.hasOwnProperty.call(k, "dynamicTools") && typeof k.dynamicTools === "function") {
|
|
25607
|
+
out.push(...k.dynamicTools(options) ?? []);
|
|
25608
|
+
}
|
|
25609
|
+
}
|
|
25610
|
+
return out;
|
|
25611
|
+
}
|
|
25612
|
+
function pluginMetadataFromOptions(options, dynamicTools) {
|
|
25613
|
+
const out = { ...options };
|
|
25614
|
+
for (const key of LIST_METADATA_KEYS) {
|
|
25615
|
+
if (key in out && !Array.isArray(out[key])) delete out[key];
|
|
25616
|
+
}
|
|
25617
|
+
const tools = [...out["tools"] ?? [], ...dynamicTools];
|
|
25618
|
+
if (tools.length > 0) out["tools"] = tools;
|
|
25619
|
+
return out;
|
|
25620
|
+
}
|
|
25399
25621
|
function dedupePluginProviders(providers) {
|
|
25400
25622
|
const map = /* @__PURE__ */ new Map();
|
|
25401
25623
|
for (const p of providers) map.set(p["provide"] ?? p, p);
|
|
25402
25624
|
return [...map.values()];
|
|
25403
25625
|
}
|
|
25626
|
+
var LIST_METADATA_KEYS;
|
|
25404
25627
|
var init_dynamic_utils = __esm({
|
|
25405
25628
|
"libs/sdk/src/common/dynamic/dynamic.utils.ts"() {
|
|
25406
25629
|
"use strict";
|
|
25630
|
+
LIST_METADATA_KEYS = ["exports", "plugins", "adapters", "tools", "resources", "prompts", "skills"];
|
|
25631
|
+
}
|
|
25632
|
+
});
|
|
25633
|
+
|
|
25634
|
+
// libs/sdk/src/common/dynamic/dynamic.plugin.ts
|
|
25635
|
+
function isDynamicPluginClass(value) {
|
|
25636
|
+
return typeof value === "function" && value.prototype instanceof DynamicPlugin;
|
|
25637
|
+
}
|
|
25638
|
+
function initOptionsOf(instance) {
|
|
25639
|
+
return initOptionsByInstance.has(instance) ? { options: initOptionsByInstance.get(instance) } : void 0;
|
|
25640
|
+
}
|
|
25641
|
+
var initOptionsByInstance, DynamicPlugin;
|
|
25642
|
+
var init_dynamic_plugin = __esm({
|
|
25643
|
+
"libs/sdk/src/common/dynamic/dynamic.plugin.ts"() {
|
|
25644
|
+
"use strict";
|
|
25645
|
+
init_transport_errors();
|
|
25646
|
+
init_dynamic_utils();
|
|
25647
|
+
initOptionsByInstance = /* @__PURE__ */ new WeakMap();
|
|
25648
|
+
DynamicPlugin = class {
|
|
25649
|
+
get(token) {
|
|
25650
|
+
throw new MethodNotImplementedError("DynamicPlugin", "get");
|
|
25651
|
+
}
|
|
25652
|
+
/**
|
|
25653
|
+
* Static init() method to create a plugin provider.
|
|
25654
|
+
* @param options - Input options (with optional fields for defaults). Omitted, the plugin is
|
|
25655
|
+
* built with `{}`, as `ApprovalPlugin.init()` is documented.
|
|
25656
|
+
*/
|
|
25657
|
+
static init(options = {}) {
|
|
25658
|
+
const extraProviders = options.providers;
|
|
25659
|
+
const typedOptions = options;
|
|
25660
|
+
if ("useFactory" in options) {
|
|
25661
|
+
return {
|
|
25662
|
+
...pluginMetadataFromOptions(typedOptions, []),
|
|
25663
|
+
provide: this,
|
|
25664
|
+
inject: options.inject,
|
|
25665
|
+
useFactory: options.useFactory,
|
|
25666
|
+
providers: dedupePluginProviders(extraProviders ?? [])
|
|
25667
|
+
};
|
|
25668
|
+
}
|
|
25669
|
+
const dyn = collectDynamicProviders(this, typedOptions);
|
|
25670
|
+
const mergedProviders = dedupePluginProviders([...dyn ?? [], ...extraProviders ?? []]);
|
|
25671
|
+
const dynamicTools = collectDynamicTools(this, typedOptions);
|
|
25672
|
+
const instance = new this(options);
|
|
25673
|
+
initOptionsByInstance.set(instance, options);
|
|
25674
|
+
return {
|
|
25675
|
+
...pluginMetadataFromOptions(typedOptions, dynamicTools),
|
|
25676
|
+
provide: this,
|
|
25677
|
+
useValue: instance,
|
|
25678
|
+
providers: mergedProviders
|
|
25679
|
+
};
|
|
25680
|
+
}
|
|
25681
|
+
};
|
|
25407
25682
|
}
|
|
25408
25683
|
});
|
|
25409
25684
|
|
|
@@ -25659,9 +25934,18 @@ var init_execution_context_interface = __esm({
|
|
|
25659
25934
|
if (this._authContext) return this._authContext;
|
|
25660
25935
|
const rawAuth = require("@frontmcp/auth");
|
|
25661
25936
|
const auth = rawAuth.default ?? rawAuth;
|
|
25662
|
-
this._authContext = auth.buildAuthContext(this.
|
|
25937
|
+
this._authContext = auth.buildAuthContext(this.resolveAuthSource(), this.scope.metadata.authorities?.claimsMapping);
|
|
25663
25938
|
return this._authContext;
|
|
25664
25939
|
}
|
|
25940
|
+
resolveAuthSource() {
|
|
25941
|
+
const fromContext = this.tryGetContext()?.authInfo;
|
|
25942
|
+
if (!fromContext) return this._authInfo;
|
|
25943
|
+
const merged = { ...this._authInfo };
|
|
25944
|
+
for (const [key, value] of Object.entries(fromContext)) {
|
|
25945
|
+
if (value !== void 0) merged[key] = value;
|
|
25946
|
+
}
|
|
25947
|
+
return merged;
|
|
25948
|
+
}
|
|
25665
25949
|
/**
|
|
25666
25950
|
* Try to get the context, returning undefined if not available.
|
|
25667
25951
|
*
|
|
@@ -25847,6 +26131,23 @@ var init_execution_context_interface = __esm({
|
|
|
25847
26131
|
get config() {
|
|
25848
26132
|
return this.providers.get(ConfigService);
|
|
25849
26133
|
}
|
|
26134
|
+
// ---- Platform bindings ----
|
|
26135
|
+
/**
|
|
26136
|
+
* The hosting platform's bindings for the current request — on a Cloudflare Worker, the `env`
|
|
26137
|
+
* object holding KV namespaces, D1 databases, R2 buckets, Durable Object namespaces, `[vars]`
|
|
26138
|
+
* and secrets. `undefined` on Node/Express, where no such object exists.
|
|
26139
|
+
*
|
|
26140
|
+
* Only string bindings are mirrored into `process.env`; use this for the rest.
|
|
26141
|
+
*
|
|
26142
|
+
* @example
|
|
26143
|
+
* ```typescript
|
|
26144
|
+
* const kv = this.workerEnv?.['MY_KV'] as KVNamespace | undefined;
|
|
26145
|
+
* ```
|
|
26146
|
+
*/
|
|
26147
|
+
get workerEnv() {
|
|
26148
|
+
const env = this.tryGetContext()?.platformEnv;
|
|
26149
|
+
return env !== null && typeof env === "object" ? env : void 0;
|
|
26150
|
+
}
|
|
25850
26151
|
// ---- Runtime context helpers ----
|
|
25851
26152
|
/**
|
|
25852
26153
|
* Get the current runtime context (platform, runtime, deployment, env).
|
|
@@ -28895,7 +29196,7 @@ var init_plugin_utils = __esm({
|
|
|
28895
29196
|
});
|
|
28896
29197
|
|
|
28897
29198
|
// libs/sdk/src/plugin/plugin.registry.ts
|
|
28898
|
-
var import_reflect_metadata12, import_di24, PluginRegistry;
|
|
29199
|
+
var import_reflect_metadata12, import_di24, installedPluginValues, PluginRegistry;
|
|
28899
29200
|
var init_plugin_registry = __esm({
|
|
28900
29201
|
"libs/sdk/src/plugin/plugin.registry.ts"() {
|
|
28901
29202
|
"use strict";
|
|
@@ -28903,6 +29204,7 @@ var init_plugin_registry = __esm({
|
|
|
28903
29204
|
import_di24 = require("@frontmcp/di");
|
|
28904
29205
|
init_adapter_registry();
|
|
28905
29206
|
init_common();
|
|
29207
|
+
init_dynamic_plugin();
|
|
28906
29208
|
init_dynamic_utils();
|
|
28907
29209
|
init_context_extension();
|
|
28908
29210
|
init_errors();
|
|
@@ -28915,6 +29217,7 @@ var init_plugin_registry = __esm({
|
|
|
28915
29217
|
init_skill_registry();
|
|
28916
29218
|
init_tool_registry();
|
|
28917
29219
|
init_plugin_utils();
|
|
29220
|
+
installedPluginValues = /* @__PURE__ */ new WeakSet();
|
|
28918
29221
|
PluginRegistry = class _PluginRegistry extends RegistryAbstract {
|
|
28919
29222
|
/** providers by token */
|
|
28920
29223
|
pProviders = /* @__PURE__ */ new Map();
|
|
@@ -29103,8 +29406,15 @@ var init_plugin_registry = __esm({
|
|
|
29103
29406
|
pluginInstance: new rec.provide(...depsInstances),
|
|
29104
29407
|
dynamicProviders: rec.providers
|
|
29105
29408
|
};
|
|
29106
|
-
case "VALUE" /* VALUE */:
|
|
29107
|
-
|
|
29409
|
+
case "VALUE" /* VALUE */: {
|
|
29410
|
+
const value = rec.useValue;
|
|
29411
|
+
const init = installedPluginValues.has(value) ? initOptionsOf(value) : void 0;
|
|
29412
|
+
installedPluginValues.add(value);
|
|
29413
|
+
if (init && isDynamicPluginClass(rec.provide)) {
|
|
29414
|
+
return { pluginInstance: new rec.provide(init.options), dynamicProviders: rec.providers };
|
|
29415
|
+
}
|
|
29416
|
+
return { pluginInstance: value, dynamicProviders: rec.providers };
|
|
29417
|
+
}
|
|
29108
29418
|
case "FACTORY" /* FACTORY */: {
|
|
29109
29419
|
const args = [];
|
|
29110
29420
|
for (const d of rec.inject()) args.push(await this.providers.resolveBootstrapDep(d));
|
|
@@ -30644,6 +30954,9 @@ var init_completion_events = __esm({
|
|
|
30644
30954
|
});
|
|
30645
30955
|
|
|
30646
30956
|
// libs/sdk/src/agent/flows/call-agent.flow.ts
|
|
30957
|
+
function invalidOutputFrom(outputError) {
|
|
30958
|
+
return outputError instanceof InvalidOutputError ? outputError : new InvalidOutputError();
|
|
30959
|
+
}
|
|
30647
30960
|
var import_auth26, import_guard6, import_lazy_zod60, import_protocol41, inputSchema15, outputSchema14, stateSchema14, plan14, name14, Stage14, CallAgentFlow;
|
|
30648
30961
|
var init_call_agent_flow = __esm({
|
|
30649
30962
|
"libs/sdk/src/agent/flows/call-agent.flow.ts"() {
|
|
@@ -31030,7 +31343,7 @@ var init_call_agent_flow = __esm({
|
|
|
31030
31343
|
const { agent, agentContext, executionStartedAt, executionError, outputError, authInfo } = this.state;
|
|
31031
31344
|
if (!agent || executionStartedAt === void 0) return;
|
|
31032
31345
|
if (executionError instanceof ElicitationFallbackRequired || executionError instanceof FlowControl) return;
|
|
31033
|
-
const failure = executionError ?? (outputError !== void 0 ?
|
|
31346
|
+
const failure = executionError ?? (outputError !== void 0 ? invalidOutputFrom(outputError) : void 0);
|
|
31034
31347
|
const failed = failure !== void 0;
|
|
31035
31348
|
const requestId = this.tryGetContext()?.requestId;
|
|
31036
31349
|
const sessionId = typeof authInfo?.sessionId === "string" && authInfo.sessionId ? authInfo.sessionId : void 0;
|
|
@@ -31060,7 +31373,7 @@ var init_call_agent_flow = __esm({
|
|
|
31060
31373
|
agent: agent.metadata.name,
|
|
31061
31374
|
errors: outputError
|
|
31062
31375
|
});
|
|
31063
|
-
throw
|
|
31376
|
+
throw invalidOutputFrom(outputError);
|
|
31064
31377
|
}
|
|
31065
31378
|
const result = parsedOutput;
|
|
31066
31379
|
if (executionMeta) {
|
|
@@ -31641,12 +31954,36 @@ var init_request_validation = __esm({
|
|
|
31641
31954
|
});
|
|
31642
31955
|
|
|
31643
31956
|
// libs/sdk/src/transport/mcp-20260728/request-state.ts
|
|
31644
|
-
function
|
|
31957
|
+
function configuredSecret(name44) {
|
|
31958
|
+
const value = (0, import_utils65.getEnv)(name44);
|
|
31959
|
+
return value && value.trim().length > 0 ? value : void 0;
|
|
31960
|
+
}
|
|
31961
|
+
function resolveKey() {
|
|
31645
31962
|
if (cachedKey) return cachedKey;
|
|
31646
|
-
const
|
|
31647
|
-
|
|
31963
|
+
const vault = configuredSecret("VAULT_SECRET");
|
|
31964
|
+
const jwt = vault ? void 0 : configuredSecret("JWT_SECRET");
|
|
31965
|
+
if (vault) cachedKey = { key: encoder.encode(vault), source: "VAULT_SECRET" };
|
|
31966
|
+
else if (jwt) cachedKey = { key: encoder.encode(jwt), source: "JWT_SECRET" };
|
|
31967
|
+
else cachedKey = { key: (0, import_utils65.randomBytes)(32), source: "per-process" };
|
|
31648
31968
|
return cachedKey;
|
|
31649
31969
|
}
|
|
31970
|
+
function getRequestStateKey() {
|
|
31971
|
+
return resolveKey().key;
|
|
31972
|
+
}
|
|
31973
|
+
function getRequestStateKeySource() {
|
|
31974
|
+
return resolveKey().source;
|
|
31975
|
+
}
|
|
31976
|
+
function warnIfRequestStateKeyNotShared(options) {
|
|
31977
|
+
if (warnedKeyNotShared || !(0, import_utils65.isProduction)()) return;
|
|
31978
|
+
const { metadata } = options;
|
|
31979
|
+
const persistence = metadata.transport?.persistence;
|
|
31980
|
+
const sharesState = Boolean(metadata.redis) || typeof persistence === "object" && persistence !== null;
|
|
31981
|
+
if (!sharesState || getRequestStateKeySource() !== "per-process") return;
|
|
31982
|
+
warnedKeyNotShared = true;
|
|
31983
|
+
options.logger.warn(
|
|
31984
|
+
"requestState is signed with a per-process key (neither VAULT_SECRET nor JWT_SECRET is set). Multi-round tools (elicit/sample) restart when a round lands on another instance; set VAULT_SECRET (or JWT_SECRET) to the same value on every instance."
|
|
31985
|
+
);
|
|
31986
|
+
}
|
|
31650
31987
|
function computeRequestBinding(method, params) {
|
|
31651
31988
|
const salient = {};
|
|
31652
31989
|
for (const key of ["name", "uri", "arguments"]) {
|
|
@@ -31696,13 +32033,14 @@ function decodeRequestState(state, expected) {
|
|
|
31696
32033
|
if (payload.b !== expected.binding) return { ok: false, reason: "request-mismatch" };
|
|
31697
32034
|
return { ok: true, responses: payload.r };
|
|
31698
32035
|
}
|
|
31699
|
-
var import_utils65, DEFAULT_REQUEST_STATE_TTL_MS, MAX_REQUEST_STATE_BYTES, cachedKey, encoder, decoder;
|
|
32036
|
+
var import_utils65, DEFAULT_REQUEST_STATE_TTL_MS, MAX_REQUEST_STATE_BYTES, cachedKey, warnedKeyNotShared, encoder, decoder;
|
|
31700
32037
|
var init_request_state = __esm({
|
|
31701
32038
|
"libs/sdk/src/transport/mcp-20260728/request-state.ts"() {
|
|
31702
32039
|
"use strict";
|
|
31703
32040
|
import_utils65 = require("@frontmcp/utils");
|
|
31704
32041
|
DEFAULT_REQUEST_STATE_TTL_MS = 10 * 60 * 1e3;
|
|
31705
32042
|
MAX_REQUEST_STATE_BYTES = 256 * 1024;
|
|
32043
|
+
warnedKeyNotShared = false;
|
|
31706
32044
|
encoder = new TextEncoder();
|
|
31707
32045
|
decoder = new TextDecoder();
|
|
31708
32046
|
}
|
|
@@ -32423,7 +32761,8 @@ async function dispatch20260728(options) {
|
|
|
32423
32761
|
};
|
|
32424
32762
|
const carried = decodeRequestState(params["requestState"], binding);
|
|
32425
32763
|
if (!carried.ok && carried.reason !== "absent") {
|
|
32426
|
-
|
|
32764
|
+
const hint = carried.reason === "bad-signature" && getRequestStateKeySource() === "per-process" ? "requestState is signed with a per-process key; set VAULT_SECRET (or JWT_SECRET) to the same value on every instance so a round can land on any of them" : void 0;
|
|
32765
|
+
scope.logger.warn("mcp-20260728: rejected requestState", { method, reason: carried.reason, ...hint && { hint } });
|
|
32427
32766
|
}
|
|
32428
32767
|
const exchange = new MrtrExchange({
|
|
32429
32768
|
inputResponses: params["inputResponses"],
|
|
@@ -32580,6 +32919,7 @@ var init_mcp_stateless_client = __esm({
|
|
|
32580
32919
|
"libs/sdk/src/transport/mcp-20260728/client/mcp-stateless.client.ts"() {
|
|
32581
32920
|
"use strict";
|
|
32582
32921
|
import_protocol47 = require("@frontmcp/protocol");
|
|
32922
|
+
init_list_all_pages_utils();
|
|
32583
32923
|
init_header_codec();
|
|
32584
32924
|
init_protocol_20260728_constants();
|
|
32585
32925
|
init_tasks_extension();
|
|
@@ -32620,10 +32960,22 @@ var init_mcp_stateless_client = __esm({
|
|
|
32620
32960
|
* The spec requires this: one malformed tool definition must not prevent the
|
|
32621
32961
|
* other tools from being used, so the offender is excluded and logged rather
|
|
32622
32962
|
* than failing the call.
|
|
32963
|
+
*
|
|
32964
|
+
* Every page is fetched (`nextCursor` is followed to the end), since the
|
|
32965
|
+
* schemas cached here are what later `tools/call` headers are derived from.
|
|
32623
32966
|
*/
|
|
32624
32967
|
async listTools() {
|
|
32625
|
-
const
|
|
32626
|
-
|
|
32968
|
+
const tools = await listAllPages(
|
|
32969
|
+
"tools/list",
|
|
32970
|
+
async (cursor) => {
|
|
32971
|
+
const result = await this.request("tools/list", cursor ? { cursor } : {});
|
|
32972
|
+
return {
|
|
32973
|
+
items: Array.isArray(result["tools"]) ? result["tools"] : [],
|
|
32974
|
+
nextCursor: typeof result["nextCursor"] === "string" ? result["nextCursor"] : void 0
|
|
32975
|
+
};
|
|
32976
|
+
},
|
|
32977
|
+
(message) => new McpStatelessError(-32603, message)
|
|
32978
|
+
);
|
|
32627
32979
|
const usable = [];
|
|
32628
32980
|
for (const tool of tools) {
|
|
32629
32981
|
const validation = validateHeaderParams(tool["inputSchema"]);
|
|
@@ -32642,11 +32994,17 @@ var init_mcp_stateless_client = __esm({
|
|
|
32642
32994
|
async readResource(uri) {
|
|
32643
32995
|
return this.request("resources/read", { uri });
|
|
32644
32996
|
}
|
|
32645
|
-
|
|
32646
|
-
|
|
32997
|
+
/** One page of `resources/list`; pass the previous page's `nextCursor` for the next. */
|
|
32998
|
+
async listResources(cursor) {
|
|
32999
|
+
return this.request("resources/list", cursor ? { cursor } : {});
|
|
32647
33000
|
}
|
|
32648
|
-
|
|
32649
|
-
|
|
33001
|
+
/** One page of `resources/templates/list`; pass the previous page's `nextCursor` for the next. */
|
|
33002
|
+
async listResourceTemplates(cursor) {
|
|
33003
|
+
return this.request("resources/templates/list", cursor ? { cursor } : {});
|
|
33004
|
+
}
|
|
33005
|
+
/** One page of `prompts/list`; pass the previous page's `nextCursor` for the next. */
|
|
33006
|
+
async listPrompts(cursor) {
|
|
33007
|
+
return this.request("prompts/list", cursor ? { cursor } : {});
|
|
32650
33008
|
}
|
|
32651
33009
|
async getPrompt(name44, args = {}) {
|
|
32652
33010
|
return this.request("prompts/get", { name: name44, arguments: args });
|
|
@@ -32932,6 +33290,10 @@ var init_mcp_20260728 = __esm({
|
|
|
32932
33290
|
});
|
|
32933
33291
|
|
|
32934
33292
|
// libs/sdk/src/remote-mcp/mcp-stateless-client.adapter.ts
|
|
33293
|
+
function nextCursorOf(result) {
|
|
33294
|
+
const next = result["nextCursor"];
|
|
33295
|
+
return typeof next === "string" && next.length > 0 ? { nextCursor: next } : {};
|
|
33296
|
+
}
|
|
32935
33297
|
async function negotiateRemoteProtocol(url, configured, headers, fetchImpl = fetch) {
|
|
32936
33298
|
if (configured === "2026-07-28") return "2026-07-28";
|
|
32937
33299
|
if (configured !== "auto") return "legacy";
|
|
@@ -32974,16 +33336,29 @@ var init_mcp_stateless_client_adapter = __esm({
|
|
|
32974
33336
|
async callTool(params) {
|
|
32975
33337
|
return this.client.callTool(params.name, params.arguments ?? {});
|
|
32976
33338
|
}
|
|
32977
|
-
async listResources() {
|
|
32978
|
-
const result = await this.client.listResources();
|
|
32979
|
-
return {
|
|
33339
|
+
async listResources(params) {
|
|
33340
|
+
const result = await this.client.listResources(params?.cursor);
|
|
33341
|
+
return {
|
|
33342
|
+
resources: Array.isArray(result["resources"]) ? result["resources"] : [],
|
|
33343
|
+
...nextCursorOf(result)
|
|
33344
|
+
};
|
|
33345
|
+
}
|
|
33346
|
+
async listResourceTemplates(params) {
|
|
33347
|
+
const result = await this.client.listResourceTemplates(params?.cursor);
|
|
33348
|
+
return {
|
|
33349
|
+
resourceTemplates: Array.isArray(result["resourceTemplates"]) ? result["resourceTemplates"] : [],
|
|
33350
|
+
...nextCursorOf(result)
|
|
33351
|
+
};
|
|
32980
33352
|
}
|
|
32981
33353
|
async readResource(params) {
|
|
32982
33354
|
return this.client.readResource(params.uri);
|
|
32983
33355
|
}
|
|
32984
|
-
async listPrompts() {
|
|
32985
|
-
const result = await this.client.listPrompts();
|
|
32986
|
-
return {
|
|
33356
|
+
async listPrompts(params) {
|
|
33357
|
+
const result = await this.client.listPrompts(params?.cursor);
|
|
33358
|
+
return {
|
|
33359
|
+
prompts: Array.isArray(result["prompts"]) ? result["prompts"] : [],
|
|
33360
|
+
...nextCursorOf(result)
|
|
33361
|
+
};
|
|
32987
33362
|
}
|
|
32988
33363
|
async getPrompt(params) {
|
|
32989
33364
|
return this.client.getPrompt(params.name, params.arguments ?? {});
|
|
@@ -33342,7 +33717,7 @@ var init_health_check = __esm({
|
|
|
33342
33717
|
this.consecutiveSuccesses++;
|
|
33343
33718
|
this.consecutiveFailures = 0;
|
|
33344
33719
|
const previousStatus = this.status;
|
|
33345
|
-
if (this.consecutiveSuccesses >= this.options.healthyThreshold) {
|
|
33720
|
+
if (previousStatus === "unknown" || this.consecutiveSuccesses >= this.options.healthyThreshold) {
|
|
33346
33721
|
this.status = latencyMs > this.options.degradedLatencyMs ? "degraded" : "healthy";
|
|
33347
33722
|
}
|
|
33348
33723
|
this.lastResult = {
|
|
@@ -33506,6 +33881,7 @@ var init_mcp_client_service = __esm({
|
|
|
33506
33881
|
"libs/sdk/src/remote-mcp/mcp-client.service.ts"() {
|
|
33507
33882
|
"use strict";
|
|
33508
33883
|
import_protocol48 = require("@frontmcp/protocol");
|
|
33884
|
+
init_list_all_pages_utils();
|
|
33509
33885
|
init_mcp_error();
|
|
33510
33886
|
init_remote_errors();
|
|
33511
33887
|
init_transport_errors();
|
|
@@ -34109,10 +34485,15 @@ var init_mcp_client_service = __esm({
|
|
|
34109
34485
|
const httpOptions = request.transportOptions;
|
|
34110
34486
|
return httpOptions?.fallbackToSSE ?? true;
|
|
34111
34487
|
}
|
|
34488
|
+
// Each list follows `nextCursor` to the end: a FrontMCP remote pages its lists
|
|
34489
|
+
// (40 per page by default), and proxying only the first page silently dropped
|
|
34490
|
+
// everything after it.
|
|
34112
34491
|
async listToolsInternal(connection) {
|
|
34113
34492
|
try {
|
|
34114
|
-
|
|
34115
|
-
|
|
34493
|
+
return await listAllPages("tools/list", async (cursor) => {
|
|
34494
|
+
const result = await connection.client.listTools(cursor ? { cursor } : void 0);
|
|
34495
|
+
return { items: result.tools, nextCursor: result.nextCursor };
|
|
34496
|
+
});
|
|
34116
34497
|
} catch (error) {
|
|
34117
34498
|
this.logger.warn(`Failed to list tools: ${error.message}`);
|
|
34118
34499
|
return [];
|
|
@@ -34120,8 +34501,10 @@ var init_mcp_client_service = __esm({
|
|
|
34120
34501
|
}
|
|
34121
34502
|
async listResourcesInternal(connection) {
|
|
34122
34503
|
try {
|
|
34123
|
-
|
|
34124
|
-
|
|
34504
|
+
return await listAllPages("resources/list", async (cursor) => {
|
|
34505
|
+
const result = await connection.client.listResources(cursor ? { cursor } : void 0);
|
|
34506
|
+
return { items: result.resources, nextCursor: result.nextCursor };
|
|
34507
|
+
});
|
|
34125
34508
|
} catch (error) {
|
|
34126
34509
|
this.logger.warn(`Failed to list resources: ${error.message}`);
|
|
34127
34510
|
return [];
|
|
@@ -34129,8 +34512,10 @@ var init_mcp_client_service = __esm({
|
|
|
34129
34512
|
}
|
|
34130
34513
|
async listResourceTemplatesInternal(connection) {
|
|
34131
34514
|
try {
|
|
34132
|
-
|
|
34133
|
-
|
|
34515
|
+
return await listAllPages("resources/templates/list", async (cursor) => {
|
|
34516
|
+
const result = await connection.client.listResourceTemplates(cursor ? { cursor } : void 0);
|
|
34517
|
+
return { items: result.resourceTemplates, nextCursor: result.nextCursor };
|
|
34518
|
+
});
|
|
34134
34519
|
} catch (error) {
|
|
34135
34520
|
this.logger.warn(`Failed to list resource templates: ${error.message}`);
|
|
34136
34521
|
return [];
|
|
@@ -34138,8 +34523,10 @@ var init_mcp_client_service = __esm({
|
|
|
34138
34523
|
}
|
|
34139
34524
|
async listPromptsInternal(connection) {
|
|
34140
34525
|
try {
|
|
34141
|
-
|
|
34142
|
-
|
|
34526
|
+
return await listAllPages("prompts/list", async (cursor) => {
|
|
34527
|
+
const result = await connection.client.listPrompts(cursor ? { cursor } : void 0);
|
|
34528
|
+
return { items: result.prompts, nextCursor: result.nextCursor };
|
|
34529
|
+
});
|
|
34143
34530
|
} catch (error) {
|
|
34144
34531
|
this.logger.warn(`Failed to list prompts: ${error.message}`);
|
|
34145
34532
|
return [];
|
|
@@ -41592,8 +41979,11 @@ var init_session_verify_flow = __esm({
|
|
|
41592
41979
|
const machineId = (0, import_utils78.getMachineId)();
|
|
41593
41980
|
const authSignature = subject ? `${authMode}:${subject}` : authMode;
|
|
41594
41981
|
if (sessionIdHeader) {
|
|
41595
|
-
const
|
|
41596
|
-
|
|
41982
|
+
const body = this.rawInput.request.body;
|
|
41983
|
+
const isInitialize2 = typeof body === "object" && body !== null && "method" in body && body.method === "initialize";
|
|
41984
|
+
const decrypted = decryptPublicSession(sessionIdHeader, authSignature);
|
|
41985
|
+
const existingPayload = decrypted && isInitialize2 && decrypted.nodeId !== machineId ? void 0 : decrypted;
|
|
41986
|
+
if (existingPayload) {
|
|
41597
41987
|
const anonId = existingPayload.uuid ?? `${existingPayload.iat * 1e3}`;
|
|
41598
41988
|
const user2 = (0, import_auth39.anonymousCallerClaims)(options, anonId);
|
|
41599
41989
|
this.respond({
|
|
@@ -42549,9 +42939,11 @@ var init_instance_local_primary_auth = __esm({
|
|
|
42549
42939
|
} else if ((0, import_utils80.isProduction)() && (0, import_auth12.isOrchestratedMode)(options)) {
|
|
42550
42940
|
throw new import_auth14.JwtSecretRequiredError(options.mode);
|
|
42551
42941
|
} else {
|
|
42552
|
-
|
|
42553
|
-
|
|
42554
|
-
|
|
42942
|
+
if (!(0, import_auth12.isPublicMode)(options)) {
|
|
42943
|
+
this.logger.warn(
|
|
42944
|
+
"JWT_SECRET is not set; signing with a random per-process secret. Tokens will not survive a restart and will not verify across instances. Set JWT_SECRET for any deployment that mints tokens."
|
|
42945
|
+
);
|
|
42946
|
+
}
|
|
42555
42947
|
this.secret = getDefaultNoAuthSecret();
|
|
42556
42948
|
}
|
|
42557
42949
|
this.tokenStorage = this.readTokenStorage(options);
|
|
@@ -46520,7 +46912,14 @@ var init_encrypted_elicitation_store = __esm({
|
|
|
46520
46912
|
});
|
|
46521
46913
|
|
|
46522
46914
|
// libs/sdk/src/elicitation/store/elicitation-store.factory.ts
|
|
46523
|
-
function detectStorageType2(storage) {
|
|
46915
|
+
function detectStorageType2(storage, configuredType) {
|
|
46916
|
+
if (configuredType === "redis" || configuredType === "upstash" || configuredType === "memory") {
|
|
46917
|
+
return configuredType;
|
|
46918
|
+
}
|
|
46919
|
+
const backend = storage.type ?? storage.backendName;
|
|
46920
|
+
if (backend === "redis" || backend === "upstash" || backend === "memory") {
|
|
46921
|
+
return backend;
|
|
46922
|
+
}
|
|
46524
46923
|
if ((0, import_utils84.getEnv)("UPSTASH_REDIS_REST_URL")) {
|
|
46525
46924
|
return "upstash";
|
|
46526
46925
|
}
|
|
@@ -46610,7 +47009,8 @@ async function createElicitationStore(options = {}) {
|
|
|
46610
47009
|
});
|
|
46611
47010
|
}
|
|
46612
47011
|
}
|
|
46613
|
-
|
|
47012
|
+
const explicitBackend = Boolean(storageConfig || redis);
|
|
47013
|
+
if (finalStorageConfig?.type === "vercel-kv" || !explicitBackend && (0, import_utils84.getEnv)("KV_REST_API_URL")) {
|
|
46614
47014
|
throw new ElicitationNotSupportedError(
|
|
46615
47015
|
"Vercel KV is not supported for elicitation stores. Elicitation requires pub/sub for cross-node result routing, which Vercel KV does not support. Use Redis or Upstash instead."
|
|
46616
47016
|
);
|
|
@@ -46631,7 +47031,7 @@ async function createElicitationStore(options = {}) {
|
|
|
46631
47031
|
);
|
|
46632
47032
|
}
|
|
46633
47033
|
let store = new StorageElicitationStore(storage, logger);
|
|
46634
|
-
const type = detectStorageType2(storage);
|
|
47034
|
+
const type = detectStorageType2(storage, finalStorageConfig?.type);
|
|
46635
47035
|
const encryptionEnabled = encryption?.enabled ?? "auto";
|
|
46636
47036
|
const encryptionSecret = encryption?.secret;
|
|
46637
47037
|
const hasSecret = encryptionSecret || isElicitationEncryptionAvailable();
|
|
@@ -49458,6 +49858,7 @@ function createJobDefinitionStore(options, logger) {
|
|
|
49458
49858
|
host: options.redis.host ?? "localhost",
|
|
49459
49859
|
port: options.redis.port ?? 6379
|
|
49460
49860
|
});
|
|
49861
|
+
(0, import_utils88.attachRedisErrorListener)(client, { label: "JobDefinitionStore", logger: effectiveLogger });
|
|
49461
49862
|
return {
|
|
49462
49863
|
// Factory-created client lifetime is bound to the store, so the store
|
|
49463
49864
|
// must close it on dispose() — pass ownsClient: true.
|
|
@@ -49473,10 +49874,11 @@ function createJobDefinitionStore(options, logger) {
|
|
|
49473
49874
|
type: "memory"
|
|
49474
49875
|
};
|
|
49475
49876
|
}
|
|
49476
|
-
var noopFn, noopLogger2;
|
|
49877
|
+
var import_utils88, noopFn, noopLogger2;
|
|
49477
49878
|
var init_job_definition_store_factory = __esm({
|
|
49478
49879
|
"libs/sdk/src/job/store/job-definition-store.factory.ts"() {
|
|
49479
49880
|
"use strict";
|
|
49881
|
+
import_utils88 = require("@frontmcp/utils");
|
|
49480
49882
|
init_memory_job_definition_store();
|
|
49481
49883
|
noopFn = () => {
|
|
49482
49884
|
};
|
|
@@ -49669,6 +50071,7 @@ function createJobStateStore(options, logger) {
|
|
|
49669
50071
|
host: options.redis.host ?? "localhost",
|
|
49670
50072
|
port: options.redis.port ?? 6379
|
|
49671
50073
|
});
|
|
50074
|
+
(0, import_utils89.attachRedisErrorListener)(client, { label: "JobStateStore", logger });
|
|
49672
50075
|
return {
|
|
49673
50076
|
store: new RedisJobStateStore2(client, logger, keyPrefix, ttlSeconds),
|
|
49674
50077
|
type: "redis"
|
|
@@ -49682,9 +50085,11 @@ function createJobStateStore(options, logger) {
|
|
|
49682
50085
|
type: "memory"
|
|
49683
50086
|
};
|
|
49684
50087
|
}
|
|
50088
|
+
var import_utils89;
|
|
49685
50089
|
var init_job_state_store_factory = __esm({
|
|
49686
50090
|
"libs/sdk/src/job/store/job-state-store.factory.ts"() {
|
|
49687
50091
|
"use strict";
|
|
50092
|
+
import_utils89 = require("@frontmcp/utils");
|
|
49688
50093
|
init_memory_job_state_store();
|
|
49689
50094
|
}
|
|
49690
50095
|
});
|
|
@@ -50555,15 +50960,15 @@ var init_skill_session_types = __esm({
|
|
|
50555
50960
|
});
|
|
50556
50961
|
|
|
50557
50962
|
// libs/sdk/src/skill/session/skill-session.manager.ts
|
|
50558
|
-
var
|
|
50963
|
+
var import_utils90, SkillSessionManager;
|
|
50559
50964
|
var init_skill_session_manager = __esm({
|
|
50560
50965
|
"libs/sdk/src/skill/session/skill-session.manager.ts"() {
|
|
50561
50966
|
"use strict";
|
|
50562
|
-
|
|
50967
|
+
import_utils90 = require("@frontmcp/utils");
|
|
50563
50968
|
init_errors();
|
|
50564
50969
|
init_skill_session_types();
|
|
50565
|
-
SkillSessionManager = class extends
|
|
50566
|
-
storage = new
|
|
50970
|
+
SkillSessionManager = class extends import_utils90.EventEmitter {
|
|
50971
|
+
storage = new import_utils90.AsyncLocalStorage();
|
|
50567
50972
|
options;
|
|
50568
50973
|
logger;
|
|
50569
50974
|
store;
|
|
@@ -51762,11 +52167,11 @@ function createSkillHttpAuthValidator(skillsConfig, logger) {
|
|
|
51762
52167
|
logger
|
|
51763
52168
|
});
|
|
51764
52169
|
}
|
|
51765
|
-
var
|
|
52170
|
+
var import_utils91, SkillHttpAuthValidator;
|
|
51766
52171
|
var init_skill_http_auth = __esm({
|
|
51767
52172
|
"libs/sdk/src/skill/auth/skill-http-auth.ts"() {
|
|
51768
52173
|
"use strict";
|
|
51769
|
-
|
|
52174
|
+
import_utils91 = require("@frontmcp/utils");
|
|
51770
52175
|
init_common();
|
|
51771
52176
|
SkillHttpAuthValidator = class {
|
|
51772
52177
|
skillsConfig;
|
|
@@ -51848,7 +52253,7 @@ var init_skill_http_auth = __esm({
|
|
|
51848
52253
|
const keyBytes = encoder5.encode(key);
|
|
51849
52254
|
if (keyBytes.length === candidateBytes.length) {
|
|
51850
52255
|
try {
|
|
51851
|
-
if ((0,
|
|
52256
|
+
if ((0, import_utils91.timingSafeEqual)(keyBytes, candidateBytes)) {
|
|
51852
52257
|
found = true;
|
|
51853
52258
|
}
|
|
51854
52259
|
} catch {
|
|
@@ -52129,6 +52534,7 @@ async function createRedisCache(redis, keyPrefix, ttlMs, logger) {
|
|
|
52129
52534
|
enableReadyCheck: false,
|
|
52130
52535
|
maxRetriesPerRequest: 3
|
|
52131
52536
|
});
|
|
52537
|
+
(0, import_utils92.attachRedisErrorListener)(client, { label: "SkillHttpCache" });
|
|
52132
52538
|
await client.connect();
|
|
52133
52539
|
return new RedisSkillHttpCache({
|
|
52134
52540
|
getClient: async () => client,
|
|
@@ -52136,9 +52542,11 @@ async function createRedisCache(redis, keyPrefix, ttlMs, logger) {
|
|
|
52136
52542
|
ttlMs
|
|
52137
52543
|
});
|
|
52138
52544
|
}
|
|
52545
|
+
var import_utils92;
|
|
52139
52546
|
var init_skill_http_cache_factory = __esm({
|
|
52140
52547
|
"libs/sdk/src/skill/cache/skill-http-cache.factory.ts"() {
|
|
52141
52548
|
"use strict";
|
|
52549
|
+
import_utils92 = require("@frontmcp/utils");
|
|
52142
52550
|
init_skill_http_cache();
|
|
52143
52551
|
}
|
|
52144
52552
|
});
|
|
@@ -55309,15 +55717,15 @@ async function readSkillFileByPath(instance, filePath) {
|
|
|
55309
55717
|
let candidatePath;
|
|
55310
55718
|
for (const [subdir, configured] of candidateDirs) {
|
|
55311
55719
|
if (segments[0] !== subdir) continue;
|
|
55312
|
-
const dir = configured ? (0,
|
|
55313
|
-
candidatePath = (0,
|
|
55720
|
+
const dir = configured ? (0, import_utils94.isAbsolute)(configured) ? configured : (0, import_utils94.pathResolve)(baseDir, configured) : (0, import_utils94.joinPath)(baseDir, subdir);
|
|
55721
|
+
candidatePath = (0, import_utils94.pathResolve)(dir, ...segments.slice(1));
|
|
55314
55722
|
if (!isInside(candidatePath, dir)) {
|
|
55315
55723
|
throw new PublicMcpError(`Invalid file path "${filePath}".`, "INVALID_PARAMS", 400);
|
|
55316
55724
|
}
|
|
55317
55725
|
break;
|
|
55318
55726
|
}
|
|
55319
55727
|
if (!candidatePath) {
|
|
55320
|
-
candidatePath = (0,
|
|
55728
|
+
candidatePath = (0, import_utils94.pathResolve)(baseDir, ...segments);
|
|
55321
55729
|
if (!isInside(candidatePath, baseDir)) {
|
|
55322
55730
|
throw new PublicMcpError(`Invalid file path "${filePath}".`, "INVALID_PARAMS", 400);
|
|
55323
55731
|
}
|
|
@@ -55325,7 +55733,7 @@ async function readSkillFileByPath(instance, filePath) {
|
|
|
55325
55733
|
const mimeType = guessMimeType(filePath);
|
|
55326
55734
|
let buffer;
|
|
55327
55735
|
try {
|
|
55328
|
-
buffer = await (0,
|
|
55736
|
+
buffer = await (0, import_utils94.readFileBuffer)(candidatePath);
|
|
55329
55737
|
} catch (err) {
|
|
55330
55738
|
if (isFileMissingError(err)) {
|
|
55331
55739
|
throw new ResourceNotFoundError(`skill://${instance.getSkillPath()}/${filePath}`);
|
|
@@ -55368,7 +55776,7 @@ async function tryResolvedSubFile(instance, kind, tail) {
|
|
|
55368
55776
|
const resolvedPath = resolveEntryPath2(instance, kind, absolutePath, filename);
|
|
55369
55777
|
if (!resolvedPath) continue;
|
|
55370
55778
|
try {
|
|
55371
|
-
const buf = await (0,
|
|
55779
|
+
const buf = await (0, import_utils94.readFileBuffer)(resolvedPath);
|
|
55372
55780
|
const text = (Buffer.isBuffer(buf) ? buf : Buffer.from(buf)).toString("utf-8");
|
|
55373
55781
|
return parseSkillMdFrontmatter(text).body;
|
|
55374
55782
|
} catch (err) {
|
|
@@ -55381,18 +55789,18 @@ async function tryResolvedSubFile(instance, kind, tail) {
|
|
|
55381
55789
|
return void 0;
|
|
55382
55790
|
}
|
|
55383
55791
|
function resolveEntryPath2(instance, kind, absolutePath, filename) {
|
|
55384
|
-
if (absolutePath && (0,
|
|
55792
|
+
if (absolutePath && (0, import_utils94.isAbsolute)(absolutePath)) return absolutePath;
|
|
55385
55793
|
if (!filename) return void 0;
|
|
55386
55794
|
const baseDir = instance.getBaseDir();
|
|
55387
55795
|
const configured = instance.getResources()?.[kind];
|
|
55388
55796
|
let dir;
|
|
55389
|
-
if (configured && (0,
|
|
55797
|
+
if (configured && (0, import_utils94.isAbsolute)(configured)) {
|
|
55390
55798
|
dir = configured;
|
|
55391
55799
|
} else if (baseDir) {
|
|
55392
|
-
dir = configured ? (0,
|
|
55800
|
+
dir = configured ? (0, import_utils94.pathResolve)(baseDir, configured) : (0, import_utils94.joinPath)(baseDir, kind);
|
|
55393
55801
|
}
|
|
55394
55802
|
if (!dir) return void 0;
|
|
55395
|
-
const resolved = (0,
|
|
55803
|
+
const resolved = (0, import_utils94.pathResolve)(dir, filename);
|
|
55396
55804
|
if (!isInside(resolved, dir)) return void 0;
|
|
55397
55805
|
return resolved;
|
|
55398
55806
|
}
|
|
@@ -55424,11 +55832,11 @@ function isInside(child, parent) {
|
|
|
55424
55832
|
const parentPrefix = normParent.endsWith("/") ? normParent : `${normParent}/`;
|
|
55425
55833
|
return normChild === normParent || normChild.startsWith(parentPrefix);
|
|
55426
55834
|
}
|
|
55427
|
-
var
|
|
55835
|
+
var import_utils94;
|
|
55428
55836
|
var init_sep_2640_resource_helpers = __esm({
|
|
55429
55837
|
"libs/sdk/src/skill/sep-2640/sep-2640.resource-helpers.ts"() {
|
|
55430
55838
|
"use strict";
|
|
55431
|
-
|
|
55839
|
+
import_utils94 = require("@frontmcp/utils");
|
|
55432
55840
|
init_errors();
|
|
55433
55841
|
init_skill_filter_helper();
|
|
55434
55842
|
init_skill_md_parser();
|
|
@@ -55655,17 +56063,17 @@ async function resolveLastModifiedForSkill(skill) {
|
|
|
55655
56063
|
return void 0;
|
|
55656
56064
|
}
|
|
55657
56065
|
try {
|
|
55658
|
-
const s = await (0,
|
|
56066
|
+
const s = await (0, import_utils95.stat)(record.filePath);
|
|
55659
56067
|
return s.mtime instanceof Date ? s.mtime.toISOString() : void 0;
|
|
55660
56068
|
} catch {
|
|
55661
56069
|
return void 0;
|
|
55662
56070
|
}
|
|
55663
56071
|
}
|
|
55664
|
-
var
|
|
56072
|
+
var import_utils95;
|
|
55665
56073
|
var init_sep_2640_last_modified = __esm({
|
|
55666
56074
|
"libs/sdk/src/skill/sep-2640/sep-2640.last-modified.ts"() {
|
|
55667
56075
|
"use strict";
|
|
55668
|
-
|
|
56076
|
+
import_utils95 = require("@frontmcp/utils");
|
|
55669
56077
|
}
|
|
55670
56078
|
});
|
|
55671
56079
|
|
|
@@ -55855,7 +56263,7 @@ function createDefaultSigner(mod, logger) {
|
|
|
55855
56263
|
"[skill-audit] refusing to use the default HS256 signer in production. Configure skillsConfig.audit.signer with a host-managed key (e.g. RS256 pointing at the same key registry your bundle signing uses)."
|
|
55856
56264
|
);
|
|
55857
56265
|
}
|
|
55858
|
-
const bytes = (0,
|
|
56266
|
+
const bytes = (0, import_utils96.randomBytes)(32);
|
|
55859
56267
|
logger.warn(
|
|
55860
56268
|
"[skill-audit] no audit signer configured \u2014 using process-local HS256 with a CSPRNG-generated secret. Records signed by this instance cannot be verified after restart. Configure skillsConfig.audit.signer for production."
|
|
55861
56269
|
);
|
|
@@ -55867,12 +56275,12 @@ function createDefaultStore(mod, logger) {
|
|
|
55867
56275
|
);
|
|
55868
56276
|
return new mod.MemoryAuditStore();
|
|
55869
56277
|
}
|
|
55870
|
-
var import_di39,
|
|
56278
|
+
var import_di39, import_utils96, injectedFactory;
|
|
55871
56279
|
var init_skill_audit_helper = __esm({
|
|
55872
56280
|
"libs/sdk/src/skill/skill-audit.helper.ts"() {
|
|
55873
56281
|
"use strict";
|
|
55874
56282
|
import_di39 = require("@frontmcp/di");
|
|
55875
|
-
|
|
56283
|
+
import_utils96 = require("@frontmcp/utils");
|
|
55876
56284
|
}
|
|
55877
56285
|
});
|
|
55878
56286
|
|
|
@@ -55944,6 +56352,51 @@ var init_skill_scope_helper = __esm({
|
|
|
55944
56352
|
}
|
|
55945
56353
|
});
|
|
55946
56354
|
|
|
56355
|
+
// libs/sdk/src/tool/ui/ui-option-warnings.ts
|
|
56356
|
+
function describeIgnoredUiOptions(toolName, ui) {
|
|
56357
|
+
if (!ui) return [];
|
|
56358
|
+
const messages = [];
|
|
56359
|
+
const ignored = IGNORED_UI_OPTIONS.filter((key) => ui[key] !== void 0);
|
|
56360
|
+
if (ignored.length > 0) {
|
|
56361
|
+
messages.push(
|
|
56362
|
+
`Tool "${toolName}": \`ui.${ignored.join("`, `ui.")}\` ${ignored.length === 1 ? "is" : "are"} accepted but not used yet, so ${ignored.length === 1 ? "it has" : "they have"} no effect.`
|
|
56363
|
+
);
|
|
56364
|
+
}
|
|
56365
|
+
const mode = ui["servingMode"];
|
|
56366
|
+
if (UNSUPPORTED_SERVING_MODES.includes(mode)) {
|
|
56367
|
+
messages.push(
|
|
56368
|
+
`Tool "${toolName}": \`ui.servingMode: '${String(mode)}'\` is not implemented; the widget is served inline, as with \`servingMode: 'inline'\`.`
|
|
56369
|
+
);
|
|
56370
|
+
}
|
|
56371
|
+
if (mode === "hybrid") {
|
|
56372
|
+
messages.push(
|
|
56373
|
+
`Tool "${toolName}": \`ui.servingMode: 'hybrid'\` sends only a reference in \`_meta['ui/component']\` ({ type, hash, toolName }), not the component code; the widget is rendered from its \`ui://\` resource.`
|
|
56374
|
+
);
|
|
56375
|
+
}
|
|
56376
|
+
return messages;
|
|
56377
|
+
}
|
|
56378
|
+
var IGNORED_UI_OPTIONS, UNSUPPORTED_SERVING_MODES;
|
|
56379
|
+
var init_ui_option_warnings = __esm({
|
|
56380
|
+
"libs/sdk/src/tool/ui/ui-option-warnings.ts"() {
|
|
56381
|
+
"use strict";
|
|
56382
|
+
IGNORED_UI_OPTIONS = [
|
|
56383
|
+
"widgetDescription",
|
|
56384
|
+
"widgetAccessible",
|
|
56385
|
+
"displayMode",
|
|
56386
|
+
"prefersBorder",
|
|
56387
|
+
"sandboxDomain",
|
|
56388
|
+
"contentSecurity",
|
|
56389
|
+
"hydrate",
|
|
56390
|
+
"runtimeOptions",
|
|
56391
|
+
"mdxComponents",
|
|
56392
|
+
"bundlingMode",
|
|
56393
|
+
"uiType",
|
|
56394
|
+
"htmlResponsePrefix"
|
|
56395
|
+
];
|
|
56396
|
+
UNSUPPORTED_SERVING_MODES = ["direct-url", "custom-url"];
|
|
56397
|
+
}
|
|
56398
|
+
});
|
|
56399
|
+
|
|
55947
56400
|
// libs/sdk/src/transport/bus/redis-transport-bus.ts
|
|
55948
56401
|
var DEFAULT_BUS_PREFIX, DEFAULT_BUS_TTL_SECONDS, REVOKE_LUA, RedisTransportBus;
|
|
55949
56402
|
var init_redis_transport_bus = __esm({
|
|
@@ -56073,10 +56526,11 @@ var redis_event_store_exports = {};
|
|
|
56073
56526
|
__export(redis_event_store_exports, {
|
|
56074
56527
|
RedisEventStore: () => RedisEventStore
|
|
56075
56528
|
});
|
|
56076
|
-
var RedisEventStore;
|
|
56529
|
+
var import_utils97, RedisEventStore;
|
|
56077
56530
|
var init_redis_event_store = __esm({
|
|
56078
56531
|
"libs/sdk/src/transport/event-stores/redis.event-store.ts"() {
|
|
56079
56532
|
"use strict";
|
|
56533
|
+
import_utils97 = require("@frontmcp/utils");
|
|
56080
56534
|
init_sdk_errors();
|
|
56081
56535
|
RedisEventStore = class {
|
|
56082
56536
|
client;
|
|
@@ -56120,6 +56574,9 @@ var init_redis_event_store = __esm({
|
|
|
56120
56574
|
enableReadyCheck: false,
|
|
56121
56575
|
maxRetriesPerRequest: 3
|
|
56122
56576
|
});
|
|
56577
|
+
(0, import_utils97.attachRedisErrorListener)(this.client, {
|
|
56578
|
+
label: "RedisEventStore"
|
|
56579
|
+
});
|
|
56123
56580
|
await this.client.connect();
|
|
56124
56581
|
}
|
|
56125
56582
|
return this.client;
|
|
@@ -56512,11 +56969,11 @@ function createSqliteSessionStore(options, logger) {
|
|
|
56512
56969
|
logger?.info("[SessionStoreFactory] Creating SQLite session store", { path: options.path });
|
|
56513
56970
|
return new SqliteSessionStore(options);
|
|
56514
56971
|
}
|
|
56515
|
-
var
|
|
56972
|
+
var import_utils98;
|
|
56516
56973
|
var init_session_store_factory = __esm({
|
|
56517
56974
|
"libs/sdk/src/auth/session/session-store.factory.ts"() {
|
|
56518
56975
|
"use strict";
|
|
56519
|
-
|
|
56976
|
+
import_utils98 = require("@frontmcp/utils");
|
|
56520
56977
|
init_common();
|
|
56521
56978
|
}
|
|
56522
56979
|
});
|
|
@@ -56591,14 +57048,14 @@ function toClientInfo(value) {
|
|
|
56591
57048
|
const { name: name44, version } = value;
|
|
56592
57049
|
return typeof name44 === "string" && typeof version === "string" ? { name: name44, version } : void 0;
|
|
56593
57050
|
}
|
|
56594
|
-
var import_auth55, import_lazy_zod102, import_protocol52,
|
|
57051
|
+
var import_auth55, import_lazy_zod102, import_protocol52, import_utils99, plan37, subscriptionParamsSchema, requestIdSchema, stateSchema37, name38, Stage38, encoder3, TRACE_META_KEYS, HandleMcp20260728Flow;
|
|
56595
57052
|
var init_handle_mcp_20260728_flow = __esm({
|
|
56596
57053
|
"libs/sdk/src/transport/flows/handle.mcp-20260728.flow.ts"() {
|
|
56597
57054
|
"use strict";
|
|
56598
57055
|
import_auth55 = require("@frontmcp/auth");
|
|
56599
57056
|
import_lazy_zod102 = require("@frontmcp/lazy-zod");
|
|
56600
57057
|
import_protocol52 = require("@frontmcp/protocol");
|
|
56601
|
-
|
|
57058
|
+
import_utils99 = require("@frontmcp/utils");
|
|
56602
57059
|
init_common();
|
|
56603
57060
|
init_context();
|
|
56604
57061
|
init_notification();
|
|
@@ -56696,7 +57153,7 @@ var init_handle_mcp_20260728_flow = __esm({
|
|
|
56696
57153
|
if (!context) return (fn) => fn();
|
|
56697
57154
|
const storage = this.scope.providers.get(FrontMcpContextStorage);
|
|
56698
57155
|
return async (fn) => {
|
|
56699
|
-
await (0,
|
|
57156
|
+
await (0, import_utils99.runRequestExclusive)(() => storage.runWithContext(context, fn));
|
|
56700
57157
|
};
|
|
56701
57158
|
}
|
|
56702
57159
|
findToolSchema(scope, toolName) {
|
|
@@ -56773,7 +57230,7 @@ var init_handle_mcp_20260728_flow = __esm({
|
|
|
56773
57230
|
const sink = new RequestNotificationSink(logLevel, progressToken);
|
|
56774
57231
|
const clientInfo = toClientInfo(meta[import_protocol52.MCP_20260728_META.clientInfo]);
|
|
56775
57232
|
if (clientInfo) {
|
|
56776
|
-
const platformType = detectAIPlatform(clientInfo, this.scope.metadata.transport?.platformDetection);
|
|
57233
|
+
const platformType = detectPlatformFromCapabilities(clientCapabilities) ?? detectAIPlatform(clientInfo, this.scope.metadata.transport?.platformDetection);
|
|
56777
57234
|
this.tryGetContext()?.setClientInfo(clientInfo, platformType);
|
|
56778
57235
|
}
|
|
56779
57236
|
const dispatchOptions = {
|
|
@@ -56871,6 +57328,29 @@ var init_handle_mcp_20260728_flow = __esm({
|
|
|
56871
57328
|
}
|
|
56872
57329
|
});
|
|
56873
57330
|
|
|
57331
|
+
// libs/sdk/src/ha/ha-headers.ts
|
|
57332
|
+
function applyMachineIdHeader(response) {
|
|
57333
|
+
if ((0, import_utils100.getRuntimeContext)().deployment !== "distributed") return false;
|
|
57334
|
+
response.setHeader(DEFAULT_FRONTMCP_MACHINE_ID_HEADER, (0, import_utils100.getMachineId)());
|
|
57335
|
+
return true;
|
|
57336
|
+
}
|
|
57337
|
+
function applyNodeAffinity(response, request) {
|
|
57338
|
+
if (!applyMachineIdHeader(response)) return;
|
|
57339
|
+
const cookie = (0, import_utils100.buildSetCookie)({ name: DEFAULT_FRONTMCP_NODE_COOKIE, value: (0, import_utils100.getMachineId)() }, request);
|
|
57340
|
+
if (!cookie) return;
|
|
57341
|
+
const existing = response.getHeader("Set-Cookie");
|
|
57342
|
+
const existingArr = Array.isArray(existing) ? existing : existing ? [String(existing)] : [];
|
|
57343
|
+
response.setHeader("Set-Cookie", [...existingArr, cookie]);
|
|
57344
|
+
}
|
|
57345
|
+
var import_utils100;
|
|
57346
|
+
var init_ha_headers = __esm({
|
|
57347
|
+
"libs/sdk/src/ha/ha-headers.ts"() {
|
|
57348
|
+
"use strict";
|
|
57349
|
+
import_utils100 = require("@frontmcp/utils");
|
|
57350
|
+
init_ha_constants();
|
|
57351
|
+
}
|
|
57352
|
+
});
|
|
57353
|
+
|
|
56874
57354
|
// libs/sdk/src/skill/skill-mode.utils.ts
|
|
56875
57355
|
function detectSkillsOnlyMode(query) {
|
|
56876
57356
|
if (!query) return false;
|
|
@@ -56899,16 +57379,40 @@ function getQuerySessionId2(urlPath) {
|
|
|
56899
57379
|
return void 0;
|
|
56900
57380
|
}
|
|
56901
57381
|
}
|
|
56902
|
-
|
|
57382
|
+
function resolveLegacySseSession(params) {
|
|
57383
|
+
const { rawHeader, requestUrl, authorizationSession, createSession } = params;
|
|
57384
|
+
const rawMcpSessionHeader = typeof rawHeader === "string" ? rawHeader : void 0;
|
|
57385
|
+
const mcpSessionHeader = validateMcpSessionHeader(rawMcpSessionHeader);
|
|
57386
|
+
const querySessionId = getQuerySessionId2(requestUrl);
|
|
57387
|
+
const validatedQuerySessionId = querySessionId ? validateMcpSessionHeader(querySessionId) : void 0;
|
|
57388
|
+
if (rawHeader !== void 0 && !mcpSessionHeader) {
|
|
57389
|
+
return { responded404: true, createdNew: false };
|
|
57390
|
+
}
|
|
57391
|
+
if (querySessionId !== void 0 && !validatedQuerySessionId) {
|
|
57392
|
+
return { responded404: true, createdNew: false };
|
|
57393
|
+
}
|
|
57394
|
+
const effectiveSessionId = mcpSessionHeader ?? validatedQuerySessionId;
|
|
57395
|
+
if (effectiveSessionId) {
|
|
57396
|
+
if (authorizationSession?.id === effectiveSessionId) {
|
|
57397
|
+
return { session: authorizationSession, createdNew: false, responded404: false };
|
|
57398
|
+
}
|
|
57399
|
+
return { responded404: true, createdNew: false };
|
|
57400
|
+
}
|
|
57401
|
+
if (authorizationSession) {
|
|
57402
|
+
return { session: authorizationSession, createdNew: false, responded404: false };
|
|
57403
|
+
}
|
|
57404
|
+
return { session: createSession(), createdNew: true, responded404: false };
|
|
57405
|
+
}
|
|
57406
|
+
var import_lazy_zod103, import_utils101, plan38, stateSessionSchema, stateSchema38, name39, Stage39, HandleSseFlow;
|
|
56903
57407
|
var init_handle_sse_flow = __esm({
|
|
56904
57408
|
"libs/sdk/src/transport/flows/handle.sse.flow.ts"() {
|
|
56905
57409
|
"use strict";
|
|
56906
57410
|
import_lazy_zod103 = require("@frontmcp/lazy-zod");
|
|
56907
|
-
|
|
57411
|
+
import_utils101 = require("@frontmcp/utils");
|
|
56908
57412
|
init_session_id_utils();
|
|
56909
57413
|
init_common();
|
|
56910
57414
|
init_errors();
|
|
56911
|
-
|
|
57415
|
+
init_ha_headers();
|
|
56912
57416
|
init_skill_mode_utils();
|
|
56913
57417
|
plan38 = {
|
|
56914
57418
|
pre: ["parseInput", "router"],
|
|
@@ -56940,39 +57444,26 @@ var init_handle_sse_flow = __esm({
|
|
|
56940
57444
|
const { request } = this.rawInput;
|
|
56941
57445
|
const authorization = request[ServerRequestTokens.auth];
|
|
56942
57446
|
const { token } = authorization;
|
|
56943
|
-
const raw = request.headers?.["mcp-session-id"];
|
|
56944
|
-
const rawMcpSessionHeader = typeof raw === "string" ? raw : void 0;
|
|
56945
|
-
const mcpSessionHeader = validateMcpSessionHeader(rawMcpSessionHeader);
|
|
56946
57447
|
const anyReq = request;
|
|
56947
|
-
const
|
|
56948
|
-
|
|
56949
|
-
|
|
56950
|
-
|
|
56951
|
-
|
|
56952
|
-
|
|
56953
|
-
|
|
57448
|
+
const resolution = resolveLegacySseSession({
|
|
57449
|
+
rawHeader: request.headers?.["mcp-session-id"],
|
|
57450
|
+
requestUrl: anyReq.url ?? anyReq.path,
|
|
57451
|
+
authorizationSession: authorization.session,
|
|
57452
|
+
createSession: () => {
|
|
57453
|
+
const query = request.query;
|
|
57454
|
+
const skillsOnlyMode = detectSkillsOnlyMode(query);
|
|
57455
|
+
return createSessionId("legacy-sse", token, {
|
|
57456
|
+
userAgent: request.headers?.["user-agent"],
|
|
57457
|
+
platformDetectionConfig: this.scope.metadata.transport?.platformDetection,
|
|
57458
|
+
skillsOnlyMode
|
|
57459
|
+
});
|
|
57460
|
+
}
|
|
57461
|
+
});
|
|
57462
|
+
if (resolution.responded404 || !resolution.session) {
|
|
56954
57463
|
this.respond(httpRespond.sessionNotFound("invalid session id"));
|
|
56955
57464
|
return;
|
|
56956
57465
|
}
|
|
56957
|
-
const
|
|
56958
|
-
let session;
|
|
56959
|
-
if (effectiveSessionId) {
|
|
56960
|
-
if (authorization.session?.id === effectiveSessionId) {
|
|
56961
|
-
session = authorization.session;
|
|
56962
|
-
} else {
|
|
56963
|
-
session = { id: effectiveSessionId };
|
|
56964
|
-
}
|
|
56965
|
-
} else if (authorization.session) {
|
|
56966
|
-
session = authorization.session;
|
|
56967
|
-
} else {
|
|
56968
|
-
const query = request.query;
|
|
56969
|
-
const skillsOnlyMode = detectSkillsOnlyMode(query);
|
|
56970
|
-
session = createSessionId("legacy-sse", token, {
|
|
56971
|
-
userAgent: request.headers?.["user-agent"],
|
|
56972
|
-
platformDetectionConfig: this.scope.metadata.transport?.platformDetection,
|
|
56973
|
-
skillsOnlyMode
|
|
56974
|
-
});
|
|
56975
|
-
}
|
|
57466
|
+
const session = resolution.session;
|
|
56976
57467
|
this.state.set(stateSchema38.parse({ token, session }));
|
|
56977
57468
|
}
|
|
56978
57469
|
async router() {
|
|
@@ -56995,16 +57486,7 @@ var init_handle_sse_flow = __esm({
|
|
|
56995
57486
|
const { request, response } = this.rawInput;
|
|
56996
57487
|
const { token, session } = this.state.required;
|
|
56997
57488
|
const transport = await transportService.createTransporter("sse", token, session.id, response);
|
|
56998
|
-
|
|
56999
|
-
const nodeId = (0, import_utils96.getMachineId)();
|
|
57000
|
-
response.setHeader(DEFAULT_FRONTMCP_MACHINE_ID_HEADER, nodeId);
|
|
57001
|
-
const cookie = (0, import_utils96.buildSetCookie)({ name: DEFAULT_FRONTMCP_NODE_COOKIE, value: nodeId }, request);
|
|
57002
|
-
if (cookie) {
|
|
57003
|
-
const existing = response.getHeader("Set-Cookie");
|
|
57004
|
-
const existingArr = Array.isArray(existing) ? existing : existing ? [String(existing)] : [];
|
|
57005
|
-
response.setHeader("Set-Cookie", [...existingArr, cookie]);
|
|
57006
|
-
}
|
|
57007
|
-
}
|
|
57489
|
+
applyNodeAffinity(response, request);
|
|
57008
57490
|
await transport.initialize(request, response);
|
|
57009
57491
|
this.handled();
|
|
57010
57492
|
}
|
|
@@ -57020,12 +57502,12 @@ var init_handle_sse_flow = __esm({
|
|
|
57020
57502
|
const { request, response } = this.rawInput;
|
|
57021
57503
|
const { token, session } = this.state.required;
|
|
57022
57504
|
const transport = await transportService.getTransporter("sse", token, session.id);
|
|
57023
|
-
if (!transport && (0,
|
|
57505
|
+
if (!transport && (0, import_utils101.getRuntimeContext)().deployment === "distributed") {
|
|
57024
57506
|
const storedSession = await transportService.getStoredSession("sse", token, session.id);
|
|
57025
57507
|
if (storedSession) {
|
|
57026
57508
|
const haManager = this.scope.haManager;
|
|
57027
57509
|
const relay = haManager?.getRelay();
|
|
57028
|
-
if (relay && storedSession.session.nodeId && storedSession.session.nodeId !== (0,
|
|
57510
|
+
if (relay && storedSession.session.nodeId && storedSession.session.nodeId !== (0, import_utils101.getMachineId)()) {
|
|
57029
57511
|
const isAlive2 = await haManager.isNodeAlive(storedSession.session.nodeId);
|
|
57030
57512
|
if (isAlive2) {
|
|
57031
57513
|
try {
|
|
@@ -57120,9 +57602,10 @@ var init_handle_stateless_http_flow = __esm({
|
|
|
57120
57602
|
import_protocol53 = require("@frontmcp/protocol");
|
|
57121
57603
|
init_common();
|
|
57122
57604
|
init_errors();
|
|
57605
|
+
init_ha_headers();
|
|
57123
57606
|
init_transport_types();
|
|
57124
57607
|
plan39 = {
|
|
57125
|
-
pre: ["parseInput", "router"],
|
|
57608
|
+
pre: ["applyNodeHeaders", "parseInput", "router"],
|
|
57126
57609
|
execute: ["handleRequest"],
|
|
57127
57610
|
post: [],
|
|
57128
57611
|
finalize: ["cleanup"]
|
|
@@ -57136,6 +57619,9 @@ var init_handle_stateless_http_flow = __esm({
|
|
|
57136
57619
|
({ Stage: Stage40 } = FlowHooksOf(name40));
|
|
57137
57620
|
HandleStatelessHttpFlow = class extends FlowBase {
|
|
57138
57621
|
name = name40;
|
|
57622
|
+
async applyNodeHeaders() {
|
|
57623
|
+
applyMachineIdHeader(this.rawInput.response);
|
|
57624
|
+
}
|
|
57139
57625
|
async parseInput() {
|
|
57140
57626
|
const { request } = this.rawInput;
|
|
57141
57627
|
const logger = this.scope.logger.child("HandleStatelessHttpFlow");
|
|
@@ -57197,6 +57683,9 @@ var init_handle_stateless_http_flow = __esm({
|
|
|
57197
57683
|
this.handled();
|
|
57198
57684
|
}
|
|
57199
57685
|
};
|
|
57686
|
+
__decorateClass([
|
|
57687
|
+
Stage40("applyNodeHeaders")
|
|
57688
|
+
], HandleStatelessHttpFlow.prototype, "applyNodeHeaders", 1);
|
|
57200
57689
|
__decorateClass([
|
|
57201
57690
|
Stage40("parseInput")
|
|
57202
57691
|
], HandleStatelessHttpFlow.prototype, "parseInput", 1);
|
|
@@ -57251,11 +57740,11 @@ var init_ext_apps_types = __esm({
|
|
|
57251
57740
|
function createExtAppsMessageHandler(options) {
|
|
57252
57741
|
return new ExtAppsMessageHandler(options);
|
|
57253
57742
|
}
|
|
57254
|
-
var
|
|
57743
|
+
var import_utils102, ExtAppsMessageHandler, ExtAppsError, ExtAppsMethodNotFoundError, ExtAppsInvalidParamsError, ExtAppsNotSupportedError, ExtAppsToolNotFoundError;
|
|
57255
57744
|
var init_ext_apps_handler = __esm({
|
|
57256
57745
|
"libs/sdk/src/ext-apps/ext-apps.handler.ts"() {
|
|
57257
57746
|
"use strict";
|
|
57258
|
-
|
|
57747
|
+
import_utils102 = require("@frontmcp/utils");
|
|
57259
57748
|
init_ext_apps_types();
|
|
57260
57749
|
ExtAppsMessageHandler = class {
|
|
57261
57750
|
context;
|
|
@@ -57299,7 +57788,7 @@ var init_ext_apps_handler = __esm({
|
|
|
57299
57788
|
code: errorCode,
|
|
57300
57789
|
message: errorMessage,
|
|
57301
57790
|
// Only include stack traces in development to avoid leaking internals in production
|
|
57302
|
-
data: (0,
|
|
57791
|
+
data: (0, import_utils102.isDevelopment)() && error instanceof Error ? { stack: error.stack } : void 0
|
|
57303
57792
|
}
|
|
57304
57793
|
};
|
|
57305
57794
|
}
|
|
@@ -57585,7 +58074,7 @@ function resolveStreamableHttpSession(params) {
|
|
|
57585
58074
|
if (authorizationSession?.id === mcpSessionHeader) {
|
|
57586
58075
|
return { session: authorizationSession, createdNew: false, responded404: false };
|
|
57587
58076
|
}
|
|
57588
|
-
return {
|
|
58077
|
+
return { responded404: true, createdNew: false };
|
|
57589
58078
|
}
|
|
57590
58079
|
if (authorizationSession) {
|
|
57591
58080
|
return { session: authorizationSession, createdNew: false, responded404: false };
|
|
@@ -57661,22 +58150,21 @@ async function lookupStreamableHttpTransport(params) {
|
|
|
57661
58150
|
}
|
|
57662
58151
|
return { kind: "session-not-initialized", recreationError };
|
|
57663
58152
|
}
|
|
57664
|
-
var import_lazy_zod105, import_protocol54,
|
|
58153
|
+
var import_lazy_zod105, import_protocol54, plan40, stateSessionSchema2, stateSchema40, name41, Stage41, HandleStreamableHttpFlow;
|
|
57665
58154
|
var init_handle_streamable_http_flow = __esm({
|
|
57666
58155
|
"libs/sdk/src/transport/flows/handle.streamable-http.flow.ts"() {
|
|
57667
58156
|
"use strict";
|
|
57668
58157
|
import_lazy_zod105 = require("@frontmcp/lazy-zod");
|
|
57669
58158
|
import_protocol54 = require("@frontmcp/protocol");
|
|
57670
|
-
import_utils98 = require("@frontmcp/utils");
|
|
57671
58159
|
init_session_id_utils();
|
|
57672
58160
|
init_common();
|
|
57673
58161
|
init_errors();
|
|
57674
58162
|
init_ext_apps2();
|
|
57675
|
-
|
|
58163
|
+
init_ha_headers();
|
|
57676
58164
|
init_skill_mode_utils();
|
|
57677
58165
|
init_mcp_surface();
|
|
57678
58166
|
plan40 = {
|
|
57679
|
-
pre: ["parseInput", "router"],
|
|
58167
|
+
pre: ["applyNodeHeaders", "parseInput", "router"],
|
|
57680
58168
|
execute: ["onInitialize", "onMessage", "onElicitResult", "onSseListener", "onExtApps"],
|
|
57681
58169
|
post: [],
|
|
57682
58170
|
finalize: ["cleanup"]
|
|
@@ -57702,6 +58190,9 @@ var init_handle_streamable_http_flow = __esm({
|
|
|
57702
58190
|
({ Stage: Stage41 } = FlowHooksOf(name41));
|
|
57703
58191
|
HandleStreamableHttpFlow = class extends FlowBase {
|
|
57704
58192
|
name = name41;
|
|
58193
|
+
async applyNodeHeaders() {
|
|
58194
|
+
applyMachineIdHeader(this.rawInput.response);
|
|
58195
|
+
}
|
|
57705
58196
|
async parseInput() {
|
|
57706
58197
|
const { request } = this.rawInput;
|
|
57707
58198
|
const authorization = request[ServerRequestTokens.auth];
|
|
@@ -57733,7 +58224,7 @@ var init_handle_streamable_http_flow = __esm({
|
|
|
57733
58224
|
});
|
|
57734
58225
|
}
|
|
57735
58226
|
if (sessionResolution.responded404 || !sessionResolution.session) {
|
|
57736
|
-
logger.warn("parseInput:
|
|
58227
|
+
logger.warn("parseInput: mcp-session-id is not a session this server verified");
|
|
57737
58228
|
this.respond(httpRespond.sessionNotFound("invalid session id"));
|
|
57738
58229
|
return;
|
|
57739
58230
|
}
|
|
@@ -57800,16 +58291,7 @@ var init_handle_streamable_http_flow = __esm({
|
|
|
57800
58291
|
return;
|
|
57801
58292
|
}
|
|
57802
58293
|
}
|
|
57803
|
-
|
|
57804
|
-
const nodeId = (0, import_utils98.getMachineId)();
|
|
57805
|
-
response.setHeader(DEFAULT_FRONTMCP_MACHINE_ID_HEADER, nodeId);
|
|
57806
|
-
const cookie = (0, import_utils98.buildSetCookie)({ name: DEFAULT_FRONTMCP_NODE_COOKIE, value: nodeId }, request);
|
|
57807
|
-
if (cookie) {
|
|
57808
|
-
const existing = response.getHeader("Set-Cookie");
|
|
57809
|
-
const existingArr = Array.isArray(existing) ? existing : existing ? [String(existing)] : [];
|
|
57810
|
-
response.setHeader("Set-Cookie", [...existingArr, cookie]);
|
|
57811
|
-
}
|
|
57812
|
-
}
|
|
58294
|
+
applyNodeAffinity(response, request);
|
|
57813
58295
|
logger.info("onInitialize: transport created, calling initialize");
|
|
57814
58296
|
await transport.initialize(request, response);
|
|
57815
58297
|
logger.info("onInitialize: completed successfully");
|
|
@@ -57992,6 +58474,17 @@ var init_handle_streamable_http_flow = __esm({
|
|
|
57992
58474
|
const logger = this.scopeLogger.child("handle:streamable-http:onExtApps");
|
|
57993
58475
|
const { request, response } = this.rawInput;
|
|
57994
58476
|
const { token, session } = this.state.required;
|
|
58477
|
+
if (this.scope.metadata.extApps?.enabled === false) {
|
|
58478
|
+
const rpc = request.body;
|
|
58479
|
+
logger.verbose("onExtApps: ext-apps disabled by config", { method: rpc?.method });
|
|
58480
|
+
response.status(200).json({
|
|
58481
|
+
jsonrpc: "2.0",
|
|
58482
|
+
id: rpc?.id ?? null,
|
|
58483
|
+
error: { code: -32601, message: `Method not found: ${rpc?.method}` }
|
|
58484
|
+
});
|
|
58485
|
+
this.handled();
|
|
58486
|
+
return;
|
|
58487
|
+
}
|
|
57995
58488
|
logger.info("onExtApps: starting", {
|
|
57996
58489
|
sessionId: session.id?.slice(0, 20),
|
|
57997
58490
|
method: request.body?.method
|
|
@@ -58043,8 +58536,20 @@ var init_handle_streamable_http_flow = __esm({
|
|
|
58043
58536
|
const hostCapabilities = {
|
|
58044
58537
|
serverToolProxy: configuredCapabilities?.serverToolProxy ?? true,
|
|
58045
58538
|
logging: configuredCapabilities?.logging ?? true,
|
|
58046
|
-
...configuredCapabilities
|
|
58539
|
+
...configuredCapabilities,
|
|
58540
|
+
// Only advertise what this host can serve: the context below provides callTool and nothing else
|
|
58541
|
+
openLink: false,
|
|
58542
|
+
modelContextUpdate: false,
|
|
58543
|
+
widgetTools: false
|
|
58047
58544
|
};
|
|
58545
|
+
const unsupported = ["openLink", "modelContextUpdate", "widgetTools"].filter(
|
|
58546
|
+
(key) => configuredCapabilities?.[key] === true
|
|
58547
|
+
);
|
|
58548
|
+
if (unsupported.length > 0) {
|
|
58549
|
+
logger.warn(
|
|
58550
|
+
`onExtApps: extApps.hostCapabilities ${unsupported.join(", ")} are not supported yet and are not advertised`
|
|
58551
|
+
);
|
|
58552
|
+
}
|
|
58048
58553
|
const handler = createExtAppsMessageHandler({
|
|
58049
58554
|
context: {
|
|
58050
58555
|
sessionId: session.id,
|
|
@@ -58078,6 +58583,9 @@ var init_handle_streamable_http_flow = __esm({
|
|
|
58078
58583
|
this.handled();
|
|
58079
58584
|
}
|
|
58080
58585
|
};
|
|
58586
|
+
__decorateClass([
|
|
58587
|
+
Stage41("applyNodeHeaders")
|
|
58588
|
+
], HandleStreamableHttpFlow.prototype, "applyNodeHeaders", 1);
|
|
58081
58589
|
__decorateClass([
|
|
58082
58590
|
Stage41("parseInput")
|
|
58083
58591
|
], HandleStreamableHttpFlow.prototype, "parseInput", 1);
|
|
@@ -58122,21 +58630,21 @@ var init_handle_streamable_http_flow = __esm({
|
|
|
58122
58630
|
});
|
|
58123
58631
|
|
|
58124
58632
|
// libs/sdk/src/transport/transport.error.ts
|
|
58125
|
-
var
|
|
58633
|
+
var import_utils103, JSON_RPC2, rpcError, rpcRequest;
|
|
58126
58634
|
var init_transport_error = __esm({
|
|
58127
58635
|
"libs/sdk/src/transport/transport.error.ts"() {
|
|
58128
58636
|
"use strict";
|
|
58129
|
-
|
|
58637
|
+
import_utils103 = require("@frontmcp/utils");
|
|
58130
58638
|
JSON_RPC2 = "2.0";
|
|
58131
58639
|
rpcError = (message, requestId) => ({
|
|
58132
58640
|
jsonrpc: JSON_RPC2,
|
|
58133
58641
|
error: { code: -32e3, message },
|
|
58134
|
-
id: requestId ?? (0,
|
|
58642
|
+
id: requestId ?? (0, import_utils103.randomUUID)()
|
|
58135
58643
|
// change it to request id + random
|
|
58136
58644
|
});
|
|
58137
58645
|
rpcRequest = (requestId, method, params) => ({
|
|
58138
58646
|
jsonrpc: JSON_RPC2,
|
|
58139
|
-
id: requestId ?? (0,
|
|
58647
|
+
id: requestId ?? (0, import_utils103.randomUUID)(),
|
|
58140
58648
|
method,
|
|
58141
58649
|
...params !== void 0 && { params }
|
|
58142
58650
|
});
|
|
@@ -58199,14 +58707,14 @@ var init_host_validation = __esm({
|
|
|
58199
58707
|
});
|
|
58200
58708
|
|
|
58201
58709
|
// libs/sdk/src/transport/adapters/base-sse-transport.ts
|
|
58202
|
-
var import_content_type, import_raw_body, import_protocol55,
|
|
58710
|
+
var import_content_type, import_raw_body, import_protocol55, import_utils104, MAXIMUM_MESSAGE_SIZE, SSEServerTransport;
|
|
58203
58711
|
var init_base_sse_transport = __esm({
|
|
58204
58712
|
"libs/sdk/src/transport/adapters/base-sse-transport.ts"() {
|
|
58205
58713
|
"use strict";
|
|
58206
58714
|
import_content_type = __toESM(require("content-type"));
|
|
58207
58715
|
import_raw_body = __toESM(require("raw-body"));
|
|
58208
58716
|
import_protocol55 = require("@frontmcp/protocol");
|
|
58209
|
-
|
|
58717
|
+
import_utils104 = require("@frontmcp/utils");
|
|
58210
58718
|
init_transport_errors();
|
|
58211
58719
|
init_host_validation();
|
|
58212
58720
|
MAXIMUM_MESSAGE_SIZE = "4mb";
|
|
@@ -58217,7 +58725,7 @@ var init_base_sse_transport = __esm({
|
|
|
58217
58725
|
constructor(_endpoint, res, options) {
|
|
58218
58726
|
this._endpoint = _endpoint;
|
|
58219
58727
|
this.res = res;
|
|
58220
|
-
this._sessionId = options?.sessionId ?? (0,
|
|
58728
|
+
this._sessionId = options?.sessionId ?? (0, import_utils104.randomUUID)();
|
|
58221
58729
|
this._options = options || { enableDnsRebindingProtection: false };
|
|
58222
58730
|
}
|
|
58223
58731
|
_endpoint;
|
|
@@ -59663,11 +60171,11 @@ var init_transport_remote = __esm({
|
|
|
59663
60171
|
});
|
|
59664
60172
|
|
|
59665
60173
|
// libs/sdk/src/transport/transport.registry.ts
|
|
59666
|
-
var
|
|
60174
|
+
var import_utils105, SESSION_STORE_RETRY_BASE_MS, SESSION_STORE_RETRY_MAX_MS, TransportService;
|
|
59667
60175
|
var init_transport_registry = __esm({
|
|
59668
60176
|
"libs/sdk/src/transport/transport.registry.ts"() {
|
|
59669
60177
|
"use strict";
|
|
59670
|
-
|
|
60178
|
+
import_utils105 = require("@frontmcp/utils");
|
|
59671
60179
|
init_session_store_factory();
|
|
59672
60180
|
init_transport_errors();
|
|
59673
60181
|
init_handle_mcp_20260728_flow();
|
|
@@ -59677,6 +60185,8 @@ var init_transport_registry = __esm({
|
|
|
59677
60185
|
init_transport_local();
|
|
59678
60186
|
init_transport_remote();
|
|
59679
60187
|
init_transport_types();
|
|
60188
|
+
SESSION_STORE_RETRY_BASE_MS = 1e3;
|
|
60189
|
+
SESSION_STORE_RETRY_MAX_MS = 3e4;
|
|
59680
60190
|
TransportService = class {
|
|
59681
60191
|
ready;
|
|
59682
60192
|
byType = /* @__PURE__ */ new Map();
|
|
@@ -59733,8 +60243,28 @@ var init_transport_registry = __esm({
|
|
|
59733
60243
|
* Returns undefined if persistence is disabled or not configured.
|
|
59734
60244
|
*/
|
|
59735
60245
|
getDefaultTtlMs() {
|
|
60246
|
+
if (this.resolvedTtlMs !== void 0) return this.resolvedTtlMs;
|
|
59736
60247
|
return typeof this.persistenceConfig === "object" ? this.persistenceConfig?.defaultTtlMs : void 0;
|
|
59737
60248
|
}
|
|
60249
|
+
/**
|
|
60250
|
+
* TTL resolved from `persistence.defaultTtlMs`, then `persistence.redis.defaultTtlMs`, then 1 hour.
|
|
60251
|
+
* Set only when a persistence backend is configured.
|
|
60252
|
+
*/
|
|
60253
|
+
resolvedTtlMs;
|
|
60254
|
+
/** Store config kept after a successful create so a failed ping can be retried. */
|
|
60255
|
+
storeRetryConfig;
|
|
60256
|
+
storeRetryTimer;
|
|
60257
|
+
storeRetryAttempt = 0;
|
|
60258
|
+
destroyed = false;
|
|
60259
|
+
/** Last time a request refreshed the stored session's TTL, by session id. */
|
|
60260
|
+
lastTtlRefreshAt = /* @__PURE__ */ new Map();
|
|
60261
|
+
/**
|
|
60262
|
+
* Redis key prefix under which session records are stored.
|
|
60263
|
+
* The session store appends `session:` to the transport key prefix.
|
|
60264
|
+
*/
|
|
60265
|
+
getSessionKeyPrefix() {
|
|
60266
|
+
return `${this.transportKeyPrefix}session:`;
|
|
60267
|
+
}
|
|
59738
60268
|
constructor(scope, persistenceConfig, bus) {
|
|
59739
60269
|
this.scope = scope;
|
|
59740
60270
|
this.persistenceConfig = persistenceConfig;
|
|
@@ -59745,10 +60275,11 @@ var init_transport_registry = __esm({
|
|
|
59745
60275
|
this.backendKind = "sqlite";
|
|
59746
60276
|
const sqliteConfig = persistenceConfig.sqlite;
|
|
59747
60277
|
this.transportKeyPrefix = "mcp:transport:";
|
|
60278
|
+
this.resolvedTtlMs = persistenceConfig.defaultTtlMs ?? 36e5;
|
|
59748
60279
|
this.pendingStoreConfig = {
|
|
59749
60280
|
sqlite: sqliteConfig,
|
|
59750
60281
|
keyPrefix: this.transportKeyPrefix,
|
|
59751
|
-
defaultTtlMs:
|
|
60282
|
+
defaultTtlMs: this.resolvedTtlMs
|
|
59752
60283
|
};
|
|
59753
60284
|
this.scope.logger.info("[TransportService] sqlite session store will be initialized for transport persistence");
|
|
59754
60285
|
} else if (persistenceConfig !== false && persistenceConfig?.redis) {
|
|
@@ -59757,43 +60288,23 @@ var init_transport_registry = __esm({
|
|
|
59757
60288
|
const providerType = "provider" in redisConfig ? redisConfig.provider : "redis";
|
|
59758
60289
|
this.backendKind = providerType === "vercel-kv" ? "vercel-kv" : "redis";
|
|
59759
60290
|
this.transportKeyPrefix = redisConfig.keyPrefix ?? "mcp:transport:";
|
|
60291
|
+
this.resolvedTtlMs = persistenceConfig.defaultTtlMs ?? redisConfig.defaultTtlMs ?? 36e5;
|
|
59760
60292
|
this.pendingStoreConfig = {
|
|
59761
60293
|
...redisConfig,
|
|
59762
60294
|
keyPrefix: this.transportKeyPrefix,
|
|
59763
|
-
defaultTtlMs:
|
|
59764
|
-
// 1 hour default
|
|
60295
|
+
defaultTtlMs: this.resolvedTtlMs
|
|
59765
60296
|
};
|
|
59766
60297
|
this.scope.logger.info(
|
|
59767
60298
|
`[TransportService] ${providerType} session store will be initialized for transport persistence`
|
|
59768
60299
|
);
|
|
59769
60300
|
}
|
|
60301
|
+
this.storeRetryConfig = this.pendingStoreConfig;
|
|
59770
60302
|
this.ready = this.initialize();
|
|
59771
60303
|
}
|
|
59772
60304
|
async initialize() {
|
|
59773
60305
|
if (this.pendingStoreConfig) {
|
|
59774
|
-
|
|
59775
|
-
|
|
59776
|
-
this.sessionStore = store;
|
|
59777
|
-
this.pendingStoreConfig = void 0;
|
|
59778
|
-
} catch (error) {
|
|
59779
|
-
const err = error;
|
|
59780
|
-
this.scope.logger.error("[TransportService] Failed to create session store - session persistence disabled", {
|
|
59781
|
-
error: err.message,
|
|
59782
|
-
cause: err.cause?.message
|
|
59783
|
-
});
|
|
59784
|
-
}
|
|
59785
|
-
}
|
|
59786
|
-
if (this.sessionStore) {
|
|
59787
|
-
const isConnected = this.sessionStore.ping ? await this.sessionStore.ping() : true;
|
|
59788
|
-
if (!isConnected) {
|
|
59789
|
-
const providerType = this.backendKind ?? "redis";
|
|
59790
|
-
this.scope.logger.error(
|
|
59791
|
-
`[TransportService] Failed to connect to ${providerType} - session persistence disabled`
|
|
59792
|
-
);
|
|
59793
|
-
await this.teardownSessionStore().catch(() => void 0);
|
|
59794
|
-
} else {
|
|
59795
|
-
this.scope.logger.info("[TransportService] Session store connection validated successfully");
|
|
59796
|
-
}
|
|
60306
|
+
const connected = await this.connectSessionStore();
|
|
60307
|
+
if (!connected && this.backendKind !== "sqlite") this.scheduleSessionStoreRetry();
|
|
59797
60308
|
}
|
|
59798
60309
|
await this.scope.registryFlows(
|
|
59799
60310
|
HandleStreamableHttpFlow,
|
|
@@ -59802,7 +60313,70 @@ var init_transport_registry = __esm({
|
|
|
59802
60313
|
HandleMcp20260728Flow
|
|
59803
60314
|
);
|
|
59804
60315
|
}
|
|
60316
|
+
/**
|
|
60317
|
+
* Create the session store and validate the connection.
|
|
60318
|
+
* Returns true when the store is usable; on failure the store is left undefined.
|
|
60319
|
+
*/
|
|
60320
|
+
async connectSessionStore() {
|
|
60321
|
+
const storeConfig = this.pendingStoreConfig ?? this.storeRetryConfig;
|
|
60322
|
+
if (!storeConfig) return false;
|
|
60323
|
+
try {
|
|
60324
|
+
const store = await createSessionStore(storeConfig, this.scope.logger.child("SessionStore"));
|
|
60325
|
+
this.sessionStore = store;
|
|
60326
|
+
this.pendingStoreConfig = void 0;
|
|
60327
|
+
} catch (error) {
|
|
60328
|
+
const err = error;
|
|
60329
|
+
this.scope.logger.error("[TransportService] Failed to create session store - session persistence disabled", {
|
|
60330
|
+
error: err.message,
|
|
60331
|
+
cause: err.cause?.message
|
|
60332
|
+
});
|
|
60333
|
+
return false;
|
|
60334
|
+
}
|
|
60335
|
+
const isConnected = this.sessionStore?.ping ? await this.sessionStore.ping() : true;
|
|
60336
|
+
if (!isConnected) {
|
|
60337
|
+
const providerType = this.backendKind ?? "redis";
|
|
60338
|
+
this.scope.logger.error(`[TransportService] Failed to connect to ${providerType} - session persistence disabled`);
|
|
60339
|
+
await this.teardownSessionStore().catch(() => void 0);
|
|
60340
|
+
return false;
|
|
60341
|
+
}
|
|
60342
|
+
this.scope.logger.info("[TransportService] Session store connection validated successfully");
|
|
60343
|
+
return true;
|
|
60344
|
+
}
|
|
60345
|
+
/**
|
|
60346
|
+
* Retry the session store with exponential backoff (1s doubling to 30s) so a Redis that
|
|
60347
|
+
* was down at startup is picked up when it comes back, and `/readyz` turns healthy.
|
|
60348
|
+
*/
|
|
60349
|
+
scheduleSessionStoreRetry() {
|
|
60350
|
+
if (this.destroyed || this.storeRetryTimer) return;
|
|
60351
|
+
const delay = Math.min(SESSION_STORE_RETRY_MAX_MS, SESSION_STORE_RETRY_BASE_MS * 2 ** this.storeRetryAttempt);
|
|
60352
|
+
this.storeRetryAttempt++;
|
|
60353
|
+
this.storeRetryTimer = setTimeout(() => {
|
|
60354
|
+
this.storeRetryTimer = void 0;
|
|
60355
|
+
void this.retrySessionStore();
|
|
60356
|
+
}, delay);
|
|
60357
|
+
this.storeRetryTimer.unref?.();
|
|
60358
|
+
}
|
|
60359
|
+
async retrySessionStore() {
|
|
60360
|
+
if (this.destroyed || this.sessionStore) return;
|
|
60361
|
+
const connected = await this.connectSessionStore().catch(() => false);
|
|
60362
|
+
if (this.destroyed) {
|
|
60363
|
+
await this.teardownSessionStore().catch(() => void 0);
|
|
60364
|
+
return;
|
|
60365
|
+
}
|
|
60366
|
+
if (connected) {
|
|
60367
|
+
this.storeRetryAttempt = 0;
|
|
60368
|
+
this.scope.logger.info("[TransportService] Session store recovered after startup failure");
|
|
60369
|
+
return;
|
|
60370
|
+
}
|
|
60371
|
+
this.scheduleSessionStoreRetry();
|
|
60372
|
+
}
|
|
59805
60373
|
async destroy() {
|
|
60374
|
+
this.destroyed = true;
|
|
60375
|
+
if (this.storeRetryTimer) {
|
|
60376
|
+
clearTimeout(this.storeRetryTimer);
|
|
60377
|
+
this.storeRetryTimer = void 0;
|
|
60378
|
+
}
|
|
60379
|
+
this.lastTtlRefreshAt.clear();
|
|
59806
60380
|
await this.teardownSessionStore();
|
|
59807
60381
|
}
|
|
59808
60382
|
/**
|
|
@@ -59863,10 +60437,33 @@ var init_transport_registry = __esm({
|
|
|
59863
60437
|
getBackendKind() {
|
|
59864
60438
|
return this.backendKind;
|
|
59865
60439
|
}
|
|
60440
|
+
/**
|
|
60441
|
+
* Slide the stored session's TTL while this instance is serving it. Redis and Vercel KV
|
|
60442
|
+
* session stores extend the TTL on read, so a plain `get` is enough. Throttled per session
|
|
60443
|
+
* to a quarter of the TTL, fire-and-forget.
|
|
60444
|
+
*/
|
|
60445
|
+
refreshStoredSessionTtl(sessionId) {
|
|
60446
|
+
const store = this.sessionStore;
|
|
60447
|
+
const ttlMs = this.getDefaultTtlMs();
|
|
60448
|
+
if (!store || !ttlMs || this.backendKind !== "redis" && this.backendKind !== "vercel-kv") return;
|
|
60449
|
+
const now = Date.now();
|
|
60450
|
+
const last = this.lastTtlRefreshAt.get(sessionId);
|
|
60451
|
+
if (last !== void 0 && now - last < Math.max(1e3, Math.floor(ttlMs / 4))) return;
|
|
60452
|
+
this.lastTtlRefreshAt.set(sessionId, now);
|
|
60453
|
+
store.get(sessionId).catch((err) => {
|
|
60454
|
+
this.scope.logger.warn("[TransportService] Failed to refresh session TTL", {
|
|
60455
|
+
sessionId: sessionId.slice(0, 20),
|
|
60456
|
+
error: err instanceof Error ? err.message : String(err)
|
|
60457
|
+
});
|
|
60458
|
+
});
|
|
60459
|
+
}
|
|
59866
60460
|
async getTransporter(type, token, sessionId) {
|
|
59867
60461
|
const key = this.keyOf(type, token, sessionId);
|
|
59868
60462
|
const local = this.lookupLocal(key);
|
|
59869
|
-
if (local)
|
|
60463
|
+
if (local) {
|
|
60464
|
+
this.refreshStoredSessionTtl(sessionId);
|
|
60465
|
+
return local;
|
|
60466
|
+
}
|
|
59870
60467
|
if (this.distributed && this.bus) {
|
|
59871
60468
|
const location = await this.bus.lookup(key);
|
|
59872
60469
|
if (location) {
|
|
@@ -59959,9 +60556,9 @@ var init_transport_registry = __esm({
|
|
|
59959
60556
|
protocol: storedSession.session.protocol,
|
|
59960
60557
|
createdAt: storedSession.createdAt
|
|
59961
60558
|
});
|
|
59962
|
-
const currentNodeId = (0,
|
|
60559
|
+
const currentNodeId = (0, import_utils105.getMachineId)();
|
|
59963
60560
|
if (this.scope.haManager && storedSession.session.nodeId && storedSession.session.nodeId !== currentNodeId) {
|
|
59964
|
-
const sessionKey = `${this.
|
|
60561
|
+
const sessionKey = `${this.getSessionKeyPrefix()}${sessionId}`;
|
|
59965
60562
|
const result = await this.scope.haManager.attemptTakeover(sessionKey, storedSession.session.nodeId);
|
|
59966
60563
|
if (!result.claimed) {
|
|
59967
60564
|
this.scope.logger.debug("[HA] Session already claimed by another pod", { sessionId: sessionId.slice(0, 20) });
|
|
@@ -60054,7 +60651,7 @@ var init_transport_registry = __esm({
|
|
|
60054
60651
|
authorizationId: key.tokenHash,
|
|
60055
60652
|
protocol: type === "sse" ? "sse" : "streamable-http",
|
|
60056
60653
|
createdAt: Date.now(),
|
|
60057
|
-
nodeId: (0,
|
|
60654
|
+
nodeId: (0, import_utils105.getMachineId)()
|
|
60058
60655
|
},
|
|
60059
60656
|
authorizationId: key.tokenHash,
|
|
60060
60657
|
createdAt: Date.now(),
|
|
@@ -60200,7 +60797,7 @@ var init_transport_registry = __esm({
|
|
|
60200
60797
|
}
|
|
60201
60798
|
/* --------------------------------- internals -------------------------------- */
|
|
60202
60799
|
sha256(value) {
|
|
60203
|
-
return (0,
|
|
60800
|
+
return (0, import_utils105.sha256Hex)(value);
|
|
60204
60801
|
}
|
|
60205
60802
|
/**
|
|
60206
60803
|
* Create a history key from components.
|
|
@@ -60294,6 +60891,7 @@ var init_transport_registry = __esm({
|
|
|
60294
60891
|
}
|
|
60295
60892
|
}
|
|
60296
60893
|
evictLocal(key) {
|
|
60894
|
+
this.lastTtlRefreshAt.delete(key.sessionId);
|
|
60297
60895
|
const typeBucket = this.byType.get(key.type);
|
|
60298
60896
|
if (!typeBucket) return;
|
|
60299
60897
|
const tokenBucket = typeBucket.get(key.tokenHash);
|
|
@@ -60384,9 +60982,9 @@ function persistentSessionCallerKey(authorization) {
|
|
|
60384
60982
|
const sub = authorization?.user?.sub;
|
|
60385
60983
|
if (!(0, import_auth56.isAnonymousSubject)(sub)) {
|
|
60386
60984
|
const iss = authorization?.user?.iss;
|
|
60387
|
-
return `sub:${(0,
|
|
60985
|
+
return `sub:${(0, import_utils106.sha256Hex)(JSON.stringify([typeof iss === "string" ? iss : "", sub]))}`;
|
|
60388
60986
|
}
|
|
60389
|
-
if (authorization?.token) return `token:${(0,
|
|
60987
|
+
if (authorization?.token) return `token:${(0, import_utils106.sha256Hex)(authorization.token)}`;
|
|
60390
60988
|
return null;
|
|
60391
60989
|
}
|
|
60392
60990
|
function claimPersistentSession(session, callerKey, store) {
|
|
@@ -60399,12 +60997,12 @@ function claimPersistentSession(session, callerKey, store) {
|
|
|
60399
60997
|
}
|
|
60400
60998
|
return owners.get(session) === callerKey ? "owner" : "refused";
|
|
60401
60999
|
}
|
|
60402
|
-
var import_auth56,
|
|
61000
|
+
var import_auth56, import_utils106, owners;
|
|
60403
61001
|
var init_persistent_session_owner = __esm({
|
|
60404
61002
|
"libs/sdk/src/transport/persistent-session-owner.ts"() {
|
|
60405
61003
|
"use strict";
|
|
60406
61004
|
import_auth56 = require("@frontmcp/auth");
|
|
60407
|
-
|
|
61005
|
+
import_utils106 = require("@frontmcp/utils");
|
|
60408
61006
|
owners = /* @__PURE__ */ new WeakMap();
|
|
60409
61007
|
}
|
|
60410
61008
|
});
|
|
@@ -60441,7 +61039,7 @@ async function runWebStandardMcp(scope, request, options) {
|
|
|
60441
61039
|
if (options.persistent) {
|
|
60442
61040
|
return options.persistent.transport.handleRequest(request, { authInfo: options.authInfo });
|
|
60443
61041
|
}
|
|
60444
|
-
const sessionId = `web:${(0,
|
|
61042
|
+
const sessionId = `web:${(0, import_utils107.randomUUID)()}`;
|
|
60445
61043
|
const accept = request.headers.get("accept") ?? "";
|
|
60446
61044
|
const wantsStream = request.method === "GET" || options.sse && accept.includes("text/event-stream");
|
|
60447
61045
|
const { mcpServer, transport } = await wireServer(scope, options.serverOptions, sessionId, void 0, !wantsStream);
|
|
@@ -60464,23 +61062,23 @@ async function runWebStandardMcp(scope, request, options) {
|
|
|
60464
61062
|
}
|
|
60465
61063
|
return response;
|
|
60466
61064
|
}
|
|
60467
|
-
var
|
|
61065
|
+
var import_utils107;
|
|
60468
61066
|
var init_web_standard_mcp = __esm({
|
|
60469
61067
|
"libs/sdk/src/transport/web-standard-mcp.ts"() {
|
|
60470
61068
|
"use strict";
|
|
60471
|
-
|
|
61069
|
+
import_utils107 = require("@frontmcp/utils");
|
|
60472
61070
|
init_build_scoped_server_options();
|
|
60473
61071
|
}
|
|
60474
61072
|
});
|
|
60475
61073
|
|
|
60476
61074
|
// libs/sdk/src/scope/flows/http.request.flow.ts
|
|
60477
|
-
var import_auth57, import_lazy_zod108,
|
|
61075
|
+
var import_auth57, import_lazy_zod108, import_utils108, plan42, httpRequestStateSchema, name43, Stage43, HttpRequestFlow;
|
|
60478
61076
|
var init_http_request_flow = __esm({
|
|
60479
61077
|
"libs/sdk/src/scope/flows/http.request.flow.ts"() {
|
|
60480
61078
|
"use strict";
|
|
60481
61079
|
import_auth57 = require("@frontmcp/auth");
|
|
60482
61080
|
import_lazy_zod108 = require("@frontmcp/lazy-zod");
|
|
60483
|
-
|
|
61081
|
+
import_utils108 = require("@frontmcp/utils");
|
|
60484
61082
|
init_session_verify_flow();
|
|
60485
61083
|
init_common();
|
|
60486
61084
|
init_schema7();
|
|
@@ -60559,7 +61157,7 @@ var init_http_request_flow = __esm({
|
|
|
60559
61157
|
const { request } = this.rawInput;
|
|
60560
61158
|
this.requestStartTime = Date.now();
|
|
60561
61159
|
const ctx = this.tryGetContext();
|
|
60562
|
-
this.requestId = ctx?.requestId ?? `req-${(0,
|
|
61160
|
+
this.requestId = ctx?.requestId ?? `req-${(0, import_utils108.randomUUID)()}`;
|
|
60563
61161
|
const headers = request.headers ?? {};
|
|
60564
61162
|
const body = request.body;
|
|
60565
61163
|
const userAgent = headers["user-agent"];
|
|
@@ -61244,13 +61842,13 @@ var init_http_request_flow = __esm({
|
|
|
61244
61842
|
});
|
|
61245
61843
|
|
|
61246
61844
|
// libs/sdk/src/scope/scope.instance.ts
|
|
61247
|
-
var import_reflect_metadata25, import_guard8,
|
|
61845
|
+
var import_reflect_metadata25, import_guard8, import_utils109, SCOPE_NON_DISPATCHABLE_FLOWS, Scope;
|
|
61248
61846
|
var init_scope_instance = __esm({
|
|
61249
61847
|
"libs/sdk/src/scope/scope.instance.ts"() {
|
|
61250
61848
|
"use strict";
|
|
61251
61849
|
import_reflect_metadata25 = require("reflect-metadata");
|
|
61252
61850
|
import_guard8 = require("@frontmcp/guard");
|
|
61253
|
-
|
|
61851
|
+
import_utils109 = require("@frontmcp/utils");
|
|
61254
61852
|
init_agent_registry();
|
|
61255
61853
|
init_call_agent_flow();
|
|
61256
61854
|
init_app_registry();
|
|
@@ -61291,8 +61889,10 @@ var init_scope_instance = __esm({
|
|
|
61291
61889
|
init_tool_registry();
|
|
61292
61890
|
init_tool_utils();
|
|
61293
61891
|
init_ui();
|
|
61892
|
+
init_ui_option_warnings();
|
|
61294
61893
|
init_bus();
|
|
61295
61894
|
init_event_stores();
|
|
61895
|
+
init_request_state();
|
|
61296
61896
|
init_transport_registry();
|
|
61297
61897
|
init_http_ip_filter_flow();
|
|
61298
61898
|
init_http_request_flow();
|
|
@@ -61316,6 +61916,8 @@ var init_scope_instance = __esm({
|
|
|
61316
61916
|
transportService;
|
|
61317
61917
|
// TODO: migrate transport service to transport.registry
|
|
61318
61918
|
notificationService;
|
|
61919
|
+
/** ioredis client owned by the HA manager and transport bus; closed in shutdown(). */
|
|
61920
|
+
haRedisClient;
|
|
61319
61921
|
toolUIRegistry;
|
|
61320
61922
|
authUiRegistry;
|
|
61321
61923
|
entryPath;
|
|
@@ -61383,7 +61985,7 @@ var init_scope_instance = __esm({
|
|
|
61383
61985
|
await this.scopeProviders.ready;
|
|
61384
61986
|
const scopeRef = { kind: "scope", id: this.id, ref: _Scope };
|
|
61385
61987
|
const scopeProviders = this.scopeProviders;
|
|
61386
|
-
const perf = (0,
|
|
61988
|
+
const perf = (0, import_utils109.getEnvFlag)("FRONTMCP_PERF");
|
|
61387
61989
|
const t0 = perf ? performance.now() : 0;
|
|
61388
61990
|
const mark = perf ? (label) => this.logger.info(`[PERF] ${label}: ${(performance.now() - t0).toFixed(1)}ms`) : () => {
|
|
61389
61991
|
};
|
|
@@ -61393,24 +61995,26 @@ var init_scope_instance = __esm({
|
|
|
61393
61995
|
this.scopeApps = new AppRegistry(this.scopeProviders, this.metadata.apps, scopeRef);
|
|
61394
61996
|
this.logger.info(`Initializing ${this.metadata.apps.length} app(s)...`);
|
|
61395
61997
|
const transportConfig = this.metadata.transport;
|
|
61396
|
-
const isDistributed = (0,
|
|
61998
|
+
const isDistributed = (0, import_utils109.getRuntimeContext)().deployment === "distributed";
|
|
61397
61999
|
if (isDistributed && this.metadata.redis && !this.cliMode) {
|
|
61398
62000
|
try {
|
|
61399
|
-
const haRedis = this.
|
|
62001
|
+
const haRedis = this.createHaRedisClient();
|
|
61400
62002
|
this.haManager = HaManager.create({
|
|
61401
62003
|
redis: haRedis,
|
|
61402
|
-
nodeId: (0,
|
|
62004
|
+
nodeId: (0, import_utils109.getMachineId)(),
|
|
61403
62005
|
logger: this.logger
|
|
61404
62006
|
});
|
|
61405
62007
|
await this.haManager.start();
|
|
61406
62008
|
this.logger.info("[HA] Manager started for distributed deployment");
|
|
61407
62009
|
} catch (err) {
|
|
61408
62010
|
this.logger.warn("[HA] Failed to start HA manager \u2014 running without HA", { error: err });
|
|
62011
|
+
this.haManager = void 0;
|
|
62012
|
+
await this.closeHaRedisClient();
|
|
61409
62013
|
}
|
|
61410
62014
|
}
|
|
61411
62015
|
let transportBus;
|
|
61412
|
-
if (this.haManager &&
|
|
61413
|
-
transportBus = new RedisTransportBus(this.
|
|
62016
|
+
if (this.haManager && this.haRedisClient && isDistributed) {
|
|
62017
|
+
transportBus = new RedisTransportBus(this.haRedisClient, (0, import_utils109.getMachineId)(), {
|
|
61414
62018
|
logger: this.logger
|
|
61415
62019
|
});
|
|
61416
62020
|
this.logger.info("[HA] Transport bus created for distributed session routing");
|
|
@@ -61421,11 +62025,10 @@ var init_scope_instance = __esm({
|
|
|
61421
62025
|
effectivePersistence = { sqlite: resolvedTopLevelSqlite };
|
|
61422
62026
|
}
|
|
61423
62027
|
this.transportService = new TransportService(this, effectivePersistence, transportBus);
|
|
61424
|
-
|
|
61425
|
-
|
|
61426
|
-
const resolvedPrefix = persistCfg && typeof persistCfg === "object" && persistCfg.redis?.keyPrefix ? persistCfg.redis.keyPrefix : "mcp:transport:";
|
|
62028
|
+
warnIfRequestStateKeyNotShared({ logger: this.logger, metadata: this.metadata });
|
|
62029
|
+
if (this.haManager && isDistributed && this.transportService.getBackendKind() === "redis") {
|
|
61427
62030
|
this.haManager.startOrphanScanner({
|
|
61428
|
-
sessionKeyPrefix:
|
|
62031
|
+
sessionKeyPrefix: this.transportService.getSessionKeyPrefix(),
|
|
61429
62032
|
onOrphan: (sessionId, previousNodeId) => {
|
|
61430
62033
|
this.logger.info(
|
|
61431
62034
|
`[HA] Orphaned session ${sessionId.slice(0, 20)} from ${previousNodeId} \u2014 available for recreation`
|
|
@@ -61433,7 +62036,7 @@ var init_scope_instance = __esm({
|
|
|
61433
62036
|
}
|
|
61434
62037
|
});
|
|
61435
62038
|
}
|
|
61436
|
-
if ((0,
|
|
62039
|
+
if ((0, import_utils109.getRuntimeContext)().deployment === "serverless") {
|
|
61437
62040
|
const protocolCfg = transportConfig?.protocol;
|
|
61438
62041
|
const hasSSE = typeof protocolCfg === "string" ? protocolCfg !== "stateless-api" : protocolCfg?.sse === true;
|
|
61439
62042
|
if (hasSSE) {
|
|
@@ -61460,7 +62063,7 @@ var init_scope_instance = __esm({
|
|
|
61460
62063
|
sqlite: elicitationSqlite,
|
|
61461
62064
|
keyPrefix: elicitationRedis?.keyPrefix ?? "mcp:elicit:",
|
|
61462
62065
|
logger: this.logger,
|
|
61463
|
-
isEdgeRuntime: (0,
|
|
62066
|
+
isEdgeRuntime: (0, import_utils109.isEdgeRuntime)()
|
|
61464
62067
|
});
|
|
61465
62068
|
this._elicitationStore = elicitStore;
|
|
61466
62069
|
this.elicitationBackendType = elicitType;
|
|
@@ -61474,14 +62077,22 @@ var init_scope_instance = __esm({
|
|
|
61474
62077
|
);
|
|
61475
62078
|
const tasksEnabledForCli = this.cliMode && hasPersistentBackend;
|
|
61476
62079
|
const hasDistributedTaskBackend = Boolean(tasksConfig?.redis ?? this.metadata.redis);
|
|
61477
|
-
const onEdgeRuntime = (0,
|
|
62080
|
+
const onEdgeRuntime = (0, import_utils109.isEdgeRuntime)();
|
|
61478
62081
|
const tasksUnavailableOnEdge = onEdgeRuntime && !hasDistributedTaskBackend && !tasksExplicitlyEnabled;
|
|
61479
62082
|
if (tasksUnavailableOnEdge) {
|
|
61480
62083
|
this.logger.info(
|
|
61481
62084
|
"[tasks] Background tasks are unavailable on this edge/serverless runtime: the in-process runner cannot continue past the HTTP response, and an in-memory store is not shared between isolates. Serving without tasks. Configure `tasks.redis` (Upstash Redis over HTTP works on Workers) to enable them."
|
|
61482
62085
|
);
|
|
61483
62086
|
}
|
|
61484
|
-
const
|
|
62087
|
+
const gateTasksRedis = tasksConfig?.redis ?? this.metadata.redis;
|
|
62088
|
+
const tasksUseSqlite = Boolean(tasksConfig?.sqlite ?? (gateTasksRedis ? void 0 : resolvedTopLevelSqlite));
|
|
62089
|
+
const tasksUnavailableOnVercelKv = !tasksExplicitlyEnabled && !tasksUseSqlite && resolvesToVercelKvTaskBackend(gateTasksRedis);
|
|
62090
|
+
if (tasksUnavailableOnVercelKv && !tasksExplicitlyDisabled) {
|
|
62091
|
+
this.logger.warn(
|
|
62092
|
+
"[tasks] Background tasks are disabled: Vercel KV has no pub/sub, which task results and cancellation require. Serving without tasks. Configure `tasks.redis` with Redis or Upstash to enable them."
|
|
62093
|
+
);
|
|
62094
|
+
}
|
|
62095
|
+
const shouldInitTasks = !tasksExplicitlyDisabled && !tasksUnavailableOnEdge && !tasksUnavailableOnVercelKv && (!this.cliMode || tasksEnabledForCli || isTaskWorker);
|
|
61485
62096
|
const tasksPromise = shouldInitTasks ? (async () => {
|
|
61486
62097
|
const tasksRedis = tasksConfig?.redis ?? this.metadata.redis;
|
|
61487
62098
|
const tasksSqlite = tasksConfig?.sqlite ?? (tasksRedis ? void 0 : resolvedTopLevelSqlite);
|
|
@@ -61980,6 +62591,16 @@ var init_scope_instance = __esm({
|
|
|
61980
62591
|
async compileUIWidgets() {
|
|
61981
62592
|
const toolsWithUI = this.scopeTools.getTools(true).filter((t) => hasUIConfig(t.metadata));
|
|
61982
62593
|
if (toolsWithUI.length === 0) return;
|
|
62594
|
+
for (const tool of toolsWithUI) {
|
|
62595
|
+
const resourceUri = tool.metadata.ui?.resourceUri;
|
|
62596
|
+
this.toolUIRegistry.registerTool(tool.metadata.name, typeof resourceUri === "string" ? resourceUri : void 0);
|
|
62597
|
+
for (const message of describeIgnoredUiOptions(
|
|
62598
|
+
tool.metadata.name,
|
|
62599
|
+
tool.metadata.ui
|
|
62600
|
+
)) {
|
|
62601
|
+
this.logger.warn(message);
|
|
62602
|
+
}
|
|
62603
|
+
}
|
|
61983
62604
|
this.scopeResources.registerDynamicResource(StaticWidgetResourceTemplate);
|
|
61984
62605
|
this.logger.verbose(`Registered UI resource template for ${toolsWithUI.length} tool(s) with UI configs`);
|
|
61985
62606
|
const staticModeTools = toolsWithUI.filter(
|
|
@@ -62558,6 +63179,29 @@ var init_scope_instance = __esm({
|
|
|
62558
63179
|
}
|
|
62559
63180
|
throw new FlowExitedWithoutOutputError();
|
|
62560
63181
|
}
|
|
63182
|
+
/**
|
|
63183
|
+
* Build the ioredis client shared by the HA manager and the transport bus from `metadata.redis`.
|
|
63184
|
+
* The client reconnects on its own and has a permanent, rate-limited 'error' listener.
|
|
63185
|
+
*/
|
|
63186
|
+
createHaRedisClient() {
|
|
63187
|
+
const redis = this.metadata.redis;
|
|
63188
|
+
if (!redis || redis.provider === "vercel-kv") {
|
|
63189
|
+
throw new Error("Distributed HA requires a TCP Redis (ioredis); Vercel KV over REST has no Lua/pub-sub support");
|
|
63190
|
+
}
|
|
63191
|
+
const client = (0, import_utils109.createRedisClient)({ ...redis, label: "ha", logger: this.logger });
|
|
63192
|
+
this.haRedisClient = client;
|
|
63193
|
+
return client;
|
|
63194
|
+
}
|
|
63195
|
+
async closeHaRedisClient() {
|
|
63196
|
+
const client = this.haRedisClient;
|
|
63197
|
+
if (!client) return;
|
|
63198
|
+
this.haRedisClient = void 0;
|
|
63199
|
+
try {
|
|
63200
|
+
await client.quit();
|
|
63201
|
+
} catch {
|
|
63202
|
+
client.disconnect();
|
|
63203
|
+
}
|
|
63204
|
+
}
|
|
62561
63205
|
/**
|
|
62562
63206
|
* Shut down the scope and release resources.
|
|
62563
63207
|
* Disconnects channel service connectors, unsubscribes event handlers,
|
|
@@ -62571,6 +63215,7 @@ var init_scope_instance = __esm({
|
|
|
62571
63215
|
this.logger.error("[HA] Manager shutdown failed", { error: err });
|
|
62572
63216
|
}
|
|
62573
63217
|
}
|
|
63218
|
+
await this.closeHaRedisClient();
|
|
62574
63219
|
if (this._channelTeardown) {
|
|
62575
63220
|
try {
|
|
62576
63221
|
await this._channelTeardown();
|
|
@@ -63692,6 +64337,178 @@ var init_scope_registry = __esm({
|
|
|
63692
64337
|
}
|
|
63693
64338
|
});
|
|
63694
64339
|
|
|
64340
|
+
// libs/sdk/src/transport/ipc-server.transport.ts
|
|
64341
|
+
function isIpcStdioRequested() {
|
|
64342
|
+
return !!process.env["FRONTMCP_DEV_STDIO_FD"] && typeof process.send === "function";
|
|
64343
|
+
}
|
|
64344
|
+
var IPC_READY_MESSAGE, IpcServerTransport;
|
|
64345
|
+
var init_ipc_server_transport = __esm({
|
|
64346
|
+
"libs/sdk/src/transport/ipc-server.transport.ts"() {
|
|
64347
|
+
"use strict";
|
|
64348
|
+
IPC_READY_MESSAGE = { __frontmcp: "ready" };
|
|
64349
|
+
IpcServerTransport = class {
|
|
64350
|
+
onclose;
|
|
64351
|
+
onerror;
|
|
64352
|
+
onmessage;
|
|
64353
|
+
started = false;
|
|
64354
|
+
handleMessage = (raw) => {
|
|
64355
|
+
if (!raw || typeof raw !== "object" || raw.__frontmcp !== void 0) return;
|
|
64356
|
+
this.onmessage?.(raw);
|
|
64357
|
+
};
|
|
64358
|
+
handleDisconnect = () => {
|
|
64359
|
+
this.onclose?.();
|
|
64360
|
+
};
|
|
64361
|
+
async start() {
|
|
64362
|
+
if (this.started) throw new Error("IpcServerTransport already started");
|
|
64363
|
+
if (typeof process.send !== "function") {
|
|
64364
|
+
throw new Error("IpcServerTransport requires a process forked with an IPC channel");
|
|
64365
|
+
}
|
|
64366
|
+
this.started = true;
|
|
64367
|
+
process.on("message", this.handleMessage);
|
|
64368
|
+
process.once("disconnect", this.handleDisconnect);
|
|
64369
|
+
process.send(IPC_READY_MESSAGE);
|
|
64370
|
+
}
|
|
64371
|
+
async send(message) {
|
|
64372
|
+
const send = process.send;
|
|
64373
|
+
if (!process.connected || typeof send !== "function") {
|
|
64374
|
+
throw new Error("IPC channel is closed");
|
|
64375
|
+
}
|
|
64376
|
+
await new Promise((resolve, reject) => {
|
|
64377
|
+
send.call(process, message, (err) => err ? reject(err) : resolve());
|
|
64378
|
+
});
|
|
64379
|
+
}
|
|
64380
|
+
async close() {
|
|
64381
|
+
process.off("message", this.handleMessage);
|
|
64382
|
+
process.off("disconnect", this.handleDisconnect);
|
|
64383
|
+
this.started = false;
|
|
64384
|
+
this.onclose?.();
|
|
64385
|
+
}
|
|
64386
|
+
};
|
|
64387
|
+
}
|
|
64388
|
+
});
|
|
64389
|
+
|
|
64390
|
+
// libs/sdk/src/server/middleware/csp.middleware.ts
|
|
64391
|
+
function readCspFromEnv() {
|
|
64392
|
+
if (!(0, import_utils110.getEnvFlag)("FRONTMCP_CSP_ENABLED")) return void 0;
|
|
64393
|
+
const rawDirectives = (0, import_utils110.getEnv)("FRONTMCP_CSP_DIRECTIVES") ?? "";
|
|
64394
|
+
const directives = {};
|
|
64395
|
+
for (const part of rawDirectives.split(";")) {
|
|
64396
|
+
const trimmed = part.trim();
|
|
64397
|
+
if (!trimmed) continue;
|
|
64398
|
+
const spaceIdx = trimmed.indexOf(" ");
|
|
64399
|
+
if (spaceIdx > 0) {
|
|
64400
|
+
directives[trimmed.slice(0, spaceIdx)] = trimmed.slice(spaceIdx + 1);
|
|
64401
|
+
} else {
|
|
64402
|
+
directives[trimmed] = "";
|
|
64403
|
+
}
|
|
64404
|
+
}
|
|
64405
|
+
return {
|
|
64406
|
+
enabled: true,
|
|
64407
|
+
directives,
|
|
64408
|
+
reportUri: (0, import_utils110.getEnv)("FRONTMCP_CSP_REPORT_URI"),
|
|
64409
|
+
reportOnly: (0, import_utils110.getEnvFlag)("FRONTMCP_CSP_REPORT_ONLY")
|
|
64410
|
+
};
|
|
64411
|
+
}
|
|
64412
|
+
function buildCspHeaderValue(options) {
|
|
64413
|
+
const parts = [];
|
|
64414
|
+
for (const [directive, value] of Object.entries(options.directives)) {
|
|
64415
|
+
parts.push(value ? `${directive} ${value}` : directive);
|
|
64416
|
+
}
|
|
64417
|
+
if (options.reportUri) {
|
|
64418
|
+
parts.push(`report-uri ${options.reportUri}`);
|
|
64419
|
+
}
|
|
64420
|
+
return parts.join("; ");
|
|
64421
|
+
}
|
|
64422
|
+
function getCspHeaderName(reportOnly) {
|
|
64423
|
+
return reportOnly ? "Content-Security-Policy-Report-Only" : "Content-Security-Policy";
|
|
64424
|
+
}
|
|
64425
|
+
function readSecurityHeadersFromEnv() {
|
|
64426
|
+
return {
|
|
64427
|
+
hsts: readHeaderEnv("FRONTMCP_HSTS"),
|
|
64428
|
+
contentTypeOptions: readHeaderEnv("FRONTMCP_CONTENT_TYPE_OPTIONS", "nosniff"),
|
|
64429
|
+
frameOptions: readHeaderEnv("FRONTMCP_FRAME_OPTIONS", "DENY"),
|
|
64430
|
+
custom: readCustomHeadersFromEnv()
|
|
64431
|
+
};
|
|
64432
|
+
}
|
|
64433
|
+
function readHeaderEnv(name44, fallback) {
|
|
64434
|
+
const value = (0, import_utils110.getEnv)(name44);
|
|
64435
|
+
if (value === void 0 || value === "") return fallback;
|
|
64436
|
+
return ["off", "false", "none"].includes(value.trim().toLowerCase()) ? void 0 : value;
|
|
64437
|
+
}
|
|
64438
|
+
function readCustomHeadersFromEnv() {
|
|
64439
|
+
const raw = (0, import_utils110.getEnv)("FRONTMCP_HEADERS_CUSTOM");
|
|
64440
|
+
if (!raw) return void 0;
|
|
64441
|
+
try {
|
|
64442
|
+
const parsed = JSON.parse(raw);
|
|
64443
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return void 0;
|
|
64444
|
+
return Object.fromEntries(
|
|
64445
|
+
Object.entries(parsed).filter((entry) => typeof entry[1] === "string")
|
|
64446
|
+
);
|
|
64447
|
+
} catch {
|
|
64448
|
+
return void 0;
|
|
64449
|
+
}
|
|
64450
|
+
}
|
|
64451
|
+
function applySecurityHeaders(res, headers, csp) {
|
|
64452
|
+
if (headers.hsts) {
|
|
64453
|
+
res.setHeader("Strict-Transport-Security", headers.hsts);
|
|
64454
|
+
}
|
|
64455
|
+
if (headers.contentTypeOptions) {
|
|
64456
|
+
res.setHeader("X-Content-Type-Options", headers.contentTypeOptions);
|
|
64457
|
+
}
|
|
64458
|
+
if (headers.frameOptions) {
|
|
64459
|
+
res.setHeader("X-Frame-Options", headers.frameOptions);
|
|
64460
|
+
}
|
|
64461
|
+
if (headers.custom) {
|
|
64462
|
+
for (const [name44, value] of Object.entries(headers.custom)) {
|
|
64463
|
+
res.setHeader(name44, value);
|
|
64464
|
+
}
|
|
64465
|
+
}
|
|
64466
|
+
if (csp?.enabled) {
|
|
64467
|
+
const headerName = getCspHeaderName(csp.reportOnly);
|
|
64468
|
+
const headerValue = buildCspHeaderValue(csp);
|
|
64469
|
+
if (headerValue) {
|
|
64470
|
+
res.setHeader(headerName, headerValue);
|
|
64471
|
+
}
|
|
64472
|
+
}
|
|
64473
|
+
}
|
|
64474
|
+
function resolveSecurityHeaders(options = {}) {
|
|
64475
|
+
const env = readSecurityHeadersFromEnv();
|
|
64476
|
+
const pick = (explicit, fromEnv) => explicit === false ? void 0 : explicit ?? fromEnv;
|
|
64477
|
+
const resolved = {
|
|
64478
|
+
hsts: pick(options.hsts, env.hsts),
|
|
64479
|
+
contentTypeOptions: pick(options.contentTypeOptions, env.contentTypeOptions),
|
|
64480
|
+
frameOptions: pick(options.frameOptions, env.frameOptions),
|
|
64481
|
+
custom: { ...env.custom, ...options.custom }
|
|
64482
|
+
};
|
|
64483
|
+
let csp;
|
|
64484
|
+
if (options.csp?.enabled === false) {
|
|
64485
|
+
csp = void 0;
|
|
64486
|
+
} else if (options.csp?.enabled === true) {
|
|
64487
|
+
const directives = {};
|
|
64488
|
+
for (const [name44, value] of Object.entries(options.csp.directives ?? {})) {
|
|
64489
|
+
directives[name44] = Array.isArray(value) ? value.join(" ") : value;
|
|
64490
|
+
}
|
|
64491
|
+
csp = {
|
|
64492
|
+
enabled: true,
|
|
64493
|
+
directives,
|
|
64494
|
+
reportUri: options.csp.reportUri,
|
|
64495
|
+
reportOnly: options.csp.reportOnly ?? false
|
|
64496
|
+
};
|
|
64497
|
+
} else {
|
|
64498
|
+
csp = readCspFromEnv();
|
|
64499
|
+
}
|
|
64500
|
+
const headers = {};
|
|
64501
|
+
applySecurityHeaders({ setHeader: (name44, value) => void (headers[name44] = value) }, resolved, csp);
|
|
64502
|
+
return headers;
|
|
64503
|
+
}
|
|
64504
|
+
var import_utils110;
|
|
64505
|
+
var init_csp_middleware = __esm({
|
|
64506
|
+
"libs/sdk/src/server/middleware/csp.middleware.ts"() {
|
|
64507
|
+
"use strict";
|
|
64508
|
+
import_utils110 = require("@frontmcp/utils");
|
|
64509
|
+
}
|
|
64510
|
+
});
|
|
64511
|
+
|
|
63695
64512
|
// libs/sdk/src/transport/web-response.renderer.ts
|
|
63696
64513
|
function toByteStream(streamLike) {
|
|
63697
64514
|
const iter = streamLike[Symbol.asyncIterator];
|
|
@@ -63796,6 +64613,7 @@ function isCloudflareWorkersRuntime(request) {
|
|
|
63796
64613
|
return typeof cloudflareProperties === "object" && cloudflareProperties !== null;
|
|
63797
64614
|
}
|
|
63798
64615
|
function resolvePeerAddress(request, ctx) {
|
|
64616
|
+
if (carriedPeerAddresses.has(request)) return carriedPeerAddresses.get(request);
|
|
63799
64617
|
if (typeof ctx?.requestIP === "function") return ctx.requestIP(request)?.address;
|
|
63800
64618
|
if (typeof ctx?.remoteAddr?.hostname === "string") return ctx.remoteAddr.hostname;
|
|
63801
64619
|
if (isCloudflareWorkersRuntime(request)) return request.headers.get("cf-connecting-ip") ?? void 0;
|
|
@@ -63814,7 +64632,13 @@ function mapHttpCors(httpCors, scope) {
|
|
|
63814
64632
|
}
|
|
63815
64633
|
function createWebFetchHandler(scope, options = {}) {
|
|
63816
64634
|
const httpConfig = scope.metadata.http;
|
|
63817
|
-
const
|
|
64635
|
+
const healthConfig = scope.metadata.health ?? {};
|
|
64636
|
+
const healthEnabled = healthConfig.enabled !== false;
|
|
64637
|
+
const healthzPath = healthConfig.healthzPath ?? "/healthz";
|
|
64638
|
+
const readyzPath = healthConfig.readyzPath ?? "/readyz";
|
|
64639
|
+
const readyzEnabled = isReadyzEnabled(healthConfig);
|
|
64640
|
+
const bodyLimit = parseByteLimit(httpConfig?.bodyLimit);
|
|
64641
|
+
const securityHeaders = resolveSecurityHeaders(httpConfig?.securityHeaders);
|
|
63818
64642
|
const normalizePath = (p) => {
|
|
63819
64643
|
const withSlash = p.startsWith("/") ? p : `/${p}`;
|
|
63820
64644
|
let end = withSlash.length;
|
|
@@ -63858,7 +64682,13 @@ function createWebFetchHandler(scope, options = {}) {
|
|
|
63858
64682
|
for (const [k, v] of Object.entries(corsHeadersFor(request))) headers.set(k, v);
|
|
63859
64683
|
return new Response(response.body, { status: response.status, statusText: response.statusText, headers });
|
|
63860
64684
|
};
|
|
63861
|
-
|
|
64685
|
+
const withSecurityHeaders = (response) => {
|
|
64686
|
+
const headers = new Headers(response.headers);
|
|
64687
|
+
for (const [k, v] of Object.entries(securityHeaders)) if (!headers.has(k)) headers.set(k, v);
|
|
64688
|
+
headers.delete("x-powered-by");
|
|
64689
|
+
return new Response(response.body, { status: response.status, statusText: response.statusText, headers });
|
|
64690
|
+
};
|
|
64691
|
+
const handleRequest = async (request, ctx, env) => {
|
|
63862
64692
|
const url = new URL(request.url);
|
|
63863
64693
|
if (hostValidation) {
|
|
63864
64694
|
const rejection = validateHostHeaders(
|
|
@@ -63873,17 +64703,34 @@ function createWebFetchHandler(scope, options = {}) {
|
|
|
63873
64703
|
return Response.json({ error: rejection.error, message: rejection.message }, { status: rejection.status });
|
|
63874
64704
|
}
|
|
63875
64705
|
}
|
|
64706
|
+
const limited = await enforceBodyLimit(request, bodyLimit, ctx);
|
|
64707
|
+
if (limited instanceof Response) return withCors(limited, request);
|
|
64708
|
+
request = limited;
|
|
63876
64709
|
if (corsEnabled && request.method === "OPTIONS") {
|
|
63877
64710
|
return new Response(null, { status: 204, headers: corsHeadersFor(request) });
|
|
63878
64711
|
}
|
|
63879
|
-
if (healthPaths.
|
|
63880
|
-
|
|
63881
|
-
|
|
63882
|
-
|
|
63883
|
-
|
|
63884
|
-
|
|
63885
|
-
|
|
63886
|
-
|
|
64712
|
+
if (options.healthPaths ? options.healthPaths.includes(url.pathname) : healthEnabled) {
|
|
64713
|
+
const isReadyz = !options.healthPaths && url.pathname === readyzPath && readyzEnabled;
|
|
64714
|
+
const isHealthz = options.healthPaths ? url.pathname !== "/readyz" : url.pathname === healthzPath || url.pathname === "/health";
|
|
64715
|
+
if (isReadyz && scope.healthService) {
|
|
64716
|
+
const readiness = await scope.healthService.getReadyz();
|
|
64717
|
+
return withCors(
|
|
64718
|
+
Response.json(
|
|
64719
|
+
{ ...readiness, transport: "web-fetch" },
|
|
64720
|
+
{ status: readiness.status === "ready" ? 200 : 503, headers: { "Cache-Control": "no-store" } }
|
|
64721
|
+
),
|
|
64722
|
+
request
|
|
64723
|
+
);
|
|
64724
|
+
}
|
|
64725
|
+
if (isHealthz || isReadyz || options.healthPaths) {
|
|
64726
|
+
return withCors(
|
|
64727
|
+
Response.json(
|
|
64728
|
+
{ status: "ok", server: scope.metadata.info, transport: "web-fetch" },
|
|
64729
|
+
{ headers: { "Cache-Control": "no-store" } }
|
|
64730
|
+
),
|
|
64731
|
+
request
|
|
64732
|
+
);
|
|
64733
|
+
}
|
|
63887
64734
|
}
|
|
63888
64735
|
if (!entryPaths.has(normalizePath(url.pathname))) {
|
|
63889
64736
|
const authResponse = await runMatchingHttpFlowWeb(scope, request, { ctx, env });
|
|
@@ -63897,13 +64744,60 @@ function createWebFetchHandler(scope, options = {}) {
|
|
|
63897
64744
|
const rendered = await runHttpRequestFlowWeb(scope, request, { ctx, env });
|
|
63898
64745
|
return withCors(rendered ?? Response.json({ error: "Not Found" }, { status: 404 }), request);
|
|
63899
64746
|
};
|
|
64747
|
+
return async function handle(request, ctx, env) {
|
|
64748
|
+
return withSecurityHeaders(await handleRequest(request, ctx, env));
|
|
64749
|
+
};
|
|
64750
|
+
}
|
|
64751
|
+
function parseByteLimit(limit) {
|
|
64752
|
+
if (typeof limit === "number" && Number.isFinite(limit) && limit >= 0) return limit;
|
|
64753
|
+
if (typeof limit === "string") {
|
|
64754
|
+
const match = /^(\d+(?:\.\d+)?)\s*(b|kb|mb|gb)?$/i.exec(limit.trim());
|
|
64755
|
+
if (match) return Math.floor(Number(match[1]) * BYTE_UNITS[(match[2] ?? "b").toLowerCase()]);
|
|
64756
|
+
}
|
|
64757
|
+
return DEFAULT_BODY_LIMIT_BYTES;
|
|
64758
|
+
}
|
|
64759
|
+
function payloadTooLarge(limit, length) {
|
|
64760
|
+
const error = new PayloadTooLargeError(limit, length);
|
|
64761
|
+
return Response.json({ jsonrpc: "2.0", error: error.toJsonRpcError(), id: null }, { status: 413 });
|
|
64762
|
+
}
|
|
64763
|
+
async function enforceBodyLimit(request, limit, ctx) {
|
|
64764
|
+
const method = request.method.toUpperCase();
|
|
64765
|
+
if (method === "GET" || method === "HEAD" || method === "OPTIONS" || !request.body) return request;
|
|
64766
|
+
const declared = request.headers.get("content-length");
|
|
64767
|
+
if (declared !== null) {
|
|
64768
|
+
const length = Number(declared);
|
|
64769
|
+
if (Number.isFinite(length) && length > limit) return payloadTooLarge(limit, length);
|
|
64770
|
+
}
|
|
64771
|
+
const peerAddress = resolvePeerAddress(request, ctx);
|
|
64772
|
+
const reader = request.body.getReader();
|
|
64773
|
+
const chunks = [];
|
|
64774
|
+
let total = 0;
|
|
64775
|
+
for (; ; ) {
|
|
64776
|
+
const { done, value } = await reader.read();
|
|
64777
|
+
if (done) break;
|
|
64778
|
+
total += value.byteLength;
|
|
64779
|
+
if (total > limit) {
|
|
64780
|
+
await reader.cancel().catch(() => void 0);
|
|
64781
|
+
return payloadTooLarge(limit, total);
|
|
64782
|
+
}
|
|
64783
|
+
chunks.push(value);
|
|
64784
|
+
}
|
|
64785
|
+
const buffered = new Uint8Array(total);
|
|
64786
|
+
let offset = 0;
|
|
64787
|
+
for (const chunk of chunks) {
|
|
64788
|
+
buffered.set(chunk, offset);
|
|
64789
|
+
offset += chunk.byteLength;
|
|
64790
|
+
}
|
|
64791
|
+
const rebuilt = new Request(request.url, { method: request.method, headers: request.headers, body: buffered });
|
|
64792
|
+
carriedPeerAddresses.set(rebuilt, peerAddress);
|
|
64793
|
+
return rebuilt;
|
|
63900
64794
|
}
|
|
63901
64795
|
async function runHttpRequestFlowWeb(scope, request, opts = {}) {
|
|
63902
64796
|
const url = new URL(request.url);
|
|
63903
64797
|
const serverRequest = await toServerRequest(request, url, opts.ctx, opts.persistent, opts.env);
|
|
63904
64798
|
let output;
|
|
63905
64799
|
try {
|
|
63906
|
-
output = await (0,
|
|
64800
|
+
output = await (0, import_utils111.runRequestExclusive)(
|
|
63907
64801
|
() => scope.runFlow("http:request", {
|
|
63908
64802
|
request: serverRequest,
|
|
63909
64803
|
response: {}
|
|
@@ -63921,7 +64815,7 @@ async function runMatchingHttpFlowWeb(scope, request, opts = {}) {
|
|
|
63921
64815
|
if (!flowName) return void 0;
|
|
63922
64816
|
let output;
|
|
63923
64817
|
try {
|
|
63924
|
-
output = await (0,
|
|
64818
|
+
output = await (0, import_utils111.runRequestExclusive)(
|
|
63925
64819
|
() => scope.runFlow(flowName, {
|
|
63926
64820
|
request: serverRequest,
|
|
63927
64821
|
response: {}
|
|
@@ -63987,22 +64881,7 @@ async function toServerRequest(request, url, ctx, persistent, env) {
|
|
|
63987
64881
|
function misconfigurationResponse(error) {
|
|
63988
64882
|
const misconfiguration = findMisconfiguration(error);
|
|
63989
64883
|
if (!misconfiguration) return void 0;
|
|
63990
|
-
return Response.json(
|
|
63991
|
-
{ error: "server_misconfigured", code: misconfiguration.code, message: misconfiguration.remedy },
|
|
63992
|
-
{ status: 500 }
|
|
63993
|
-
);
|
|
63994
|
-
}
|
|
63995
|
-
function findMisconfiguration(error) {
|
|
63996
|
-
let current = error;
|
|
63997
|
-
for (let depth = 0; current instanceof Error && depth < 5; depth++) {
|
|
63998
|
-
const code = current.code;
|
|
63999
|
-
if (typeof code === "string" && MISCONFIGURATION_REMEDIES[code]) {
|
|
64000
|
-
return { code, remedy: MISCONFIGURATION_REMEDIES[code] };
|
|
64001
|
-
}
|
|
64002
|
-
if (current.name === "ZodError") return { code: "CONFIG_INVALID", remedy: CONFIG_INVALID_REMEDY };
|
|
64003
|
-
current = current.cause;
|
|
64004
|
-
}
|
|
64005
|
-
return void 0;
|
|
64884
|
+
return Response.json(misconfigurationBody(misconfiguration), { status: 500 });
|
|
64006
64885
|
}
|
|
64007
64886
|
function createDeferredServerBuild(build, options = {}) {
|
|
64008
64887
|
const now = options.now ?? Date.now;
|
|
@@ -64057,7 +64936,7 @@ function flowErrorToHttpOutput(error) {
|
|
|
64057
64936
|
kind: "json",
|
|
64058
64937
|
status: 500,
|
|
64059
64938
|
contentType: "application/json; charset=utf-8",
|
|
64060
|
-
body:
|
|
64939
|
+
body: misconfigurationBody(misconfiguration)
|
|
64061
64940
|
};
|
|
64062
64941
|
}
|
|
64063
64942
|
if (error instanceof FlowControl) {
|
|
@@ -64083,27 +64962,24 @@ function flowErrorToHttpOutput(error) {
|
|
|
64083
64962
|
}
|
|
64084
64963
|
return { kind: "text", status: 500, body: "Internal Server Error", contentType: "text/plain; charset=utf-8" };
|
|
64085
64964
|
}
|
|
64086
|
-
var
|
|
64965
|
+
var import_utils111, CLOUDFLARE_WORKERS_USER_AGENT, carriedPeerAddresses, DEFAULT_BODY_LIMIT_BYTES, BYTE_UNITS, STARTUP_RETRY_MIN_MS, STARTUP_RETRY_MAX_MS;
|
|
64087
64966
|
var init_web_fetch_handler = __esm({
|
|
64088
64967
|
"libs/sdk/src/transport/web-fetch-handler.ts"() {
|
|
64089
64968
|
"use strict";
|
|
64090
|
-
|
|
64969
|
+
import_utils111 = require("@frontmcp/utils");
|
|
64091
64970
|
init_common();
|
|
64092
64971
|
init_server_tokens();
|
|
64093
64972
|
init_path_utils();
|
|
64094
64973
|
init_errors();
|
|
64974
|
+
init_misconfiguration();
|
|
64975
|
+
init_health_routes();
|
|
64976
|
+
init_csp_middleware();
|
|
64095
64977
|
init_host_validation();
|
|
64096
64978
|
init_web_response_renderer();
|
|
64097
64979
|
CLOUDFLARE_WORKERS_USER_AGENT = "Cloudflare-Workers";
|
|
64098
|
-
|
|
64099
|
-
|
|
64100
|
-
|
|
64101
|
-
JWT_SECRET_REQUIRED: "Set JWT_SECRET in the deployment environment (e.g. `wrangler secret put JWT_SECRET`). Tokens are signed with it; production refuses the random per-process fallback because tokens would not survive a restart or verify across instances.",
|
|
64102
|
-
// The startup checks: a server whose entries ask for protection nothing gives them does not start.
|
|
64103
|
-
UNENFORCED_METADATA: "An entry declares a field only a plugin enforces (approval, featureFlag, ...) and no installed plugin that enforces it reaches the entry, so the server refuses to start. Install the plugin or remove the field; the server log names the entries.",
|
|
64104
|
-
AUTH_CONFIGURATION_ERROR: "The auth or authorities configuration is invalid (for example, entries declare authorities and the server has no authorities option, or a rule checks nothing), so the server refuses to start. The server log names the entries."
|
|
64105
|
-
};
|
|
64106
|
-
CONFIG_INVALID_REMEDY = "The FrontMCP configuration failed validation, so the server refuses to start. The server log names the invalid fields.";
|
|
64980
|
+
carriedPeerAddresses = /* @__PURE__ */ new WeakMap();
|
|
64981
|
+
DEFAULT_BODY_LIMIT_BYTES = 4 * 1024 * 1024;
|
|
64982
|
+
BYTE_UNITS = { b: 1, kb: 1024, mb: 1024 ** 2, gb: 1024 ** 3 };
|
|
64107
64983
|
STARTUP_RETRY_MIN_MS = 1e3;
|
|
64108
64984
|
STARTUP_RETRY_MAX_MS = 6e4;
|
|
64109
64985
|
}
|
|
@@ -64135,9 +65011,9 @@ var init_noop_server = __esm({
|
|
|
64135
65011
|
});
|
|
64136
65012
|
|
|
64137
65013
|
// libs/sdk/src/server/security/security-audit.ts
|
|
64138
|
-
function auditSecurityDefaults(config,
|
|
65014
|
+
function auditSecurityDefaults(config, isProduction7) {
|
|
64139
65015
|
const findings = [];
|
|
64140
|
-
if (!
|
|
65016
|
+
if (!isProduction7 && config.deploymentMode !== "distributed") {
|
|
64141
65017
|
return findings;
|
|
64142
65018
|
}
|
|
64143
65019
|
const strict = config.security?.strict === true;
|
|
@@ -64185,13 +65061,13 @@ function auditSecurityDefaults(config, isProduction6) {
|
|
|
64185
65061
|
message: `Server bound to ${bindAddress}.`
|
|
64186
65062
|
});
|
|
64187
65063
|
}
|
|
64188
|
-
const dnsProtectionEnabled = config.security?.dnsRebindingProtection?.enabled
|
|
65064
|
+
const dnsProtectionEnabled = config.security?.dnsRebindingProtection?.enabled !== false;
|
|
64189
65065
|
if (!dnsProtectionEnabled) {
|
|
64190
65066
|
findings.push({
|
|
64191
65067
|
level: "warn",
|
|
64192
65068
|
code: "DNS_REBINDING_UNPROTECTED",
|
|
64193
|
-
message: "DNS rebinding protection is disabled.",
|
|
64194
|
-
recommendation: "
|
|
65069
|
+
message: "DNS rebinding protection is disabled (security.dnsRebindingProtection.enabled is false).",
|
|
65070
|
+
recommendation: "Remove `enabled: false`, or set security.dnsRebindingProtection.allowedHosts, to prevent DNS rebinding attacks."
|
|
64195
65071
|
});
|
|
64196
65072
|
} else {
|
|
64197
65073
|
findings.push({
|
|
@@ -64371,15 +65247,16 @@ var init_base_host_adapter = __esm({
|
|
|
64371
65247
|
});
|
|
64372
65248
|
|
|
64373
65249
|
// libs/sdk/src/server/adapters/express.host.adapter.ts
|
|
64374
|
-
var http, import_cors, import_express,
|
|
65250
|
+
var http, import_cors, import_express, import_utils112, DEFAULT_EXPRESS_BODY_LIMIT, ExpressHostAdapter;
|
|
64375
65251
|
var init_express_host_adapter = __esm({
|
|
64376
65252
|
"libs/sdk/src/server/adapters/express.host.adapter.ts"() {
|
|
64377
65253
|
"use strict";
|
|
64378
65254
|
http = __toESM(require("node:http"));
|
|
64379
65255
|
import_cors = __toESM(require("cors"));
|
|
64380
65256
|
import_express = __toESM(require("express"));
|
|
64381
|
-
|
|
65257
|
+
import_utils112 = require("@frontmcp/utils");
|
|
64382
65258
|
init_mcp_error();
|
|
65259
|
+
init_csp_middleware();
|
|
64383
65260
|
init_host_validation_middleware();
|
|
64384
65261
|
init_resolve_allowed_hosts();
|
|
64385
65262
|
init_base_host_adapter();
|
|
@@ -64394,6 +65271,12 @@ var init_express_host_adapter = __esm({
|
|
|
64394
65271
|
deriveHostValidation;
|
|
64395
65272
|
constructor(options) {
|
|
64396
65273
|
super();
|
|
65274
|
+
this.app.disable("x-powered-by");
|
|
65275
|
+
const securityHeaders = resolveSecurityHeaders(options?.securityHeaders);
|
|
65276
|
+
this.app.use((_req, res, next) => {
|
|
65277
|
+
for (const [name44, value] of Object.entries(securityHeaders)) res.setHeader(name44, value);
|
|
65278
|
+
next();
|
|
65279
|
+
});
|
|
64397
65280
|
const corsOptions = options?.cors;
|
|
64398
65281
|
const corsEnabled = corsOptions?.origin !== void 0 && corsOptions.origin !== false;
|
|
64399
65282
|
if (corsEnabled) {
|
|
@@ -64561,8 +65444,8 @@ var init_express_host_adapter = __esm({
|
|
|
64561
65444
|
}
|
|
64562
65445
|
async cleanupStaleSocket(socketPath) {
|
|
64563
65446
|
try {
|
|
64564
|
-
if (await (0,
|
|
64565
|
-
await (0,
|
|
65447
|
+
if (await (0, import_utils112.fileExists)(socketPath)) {
|
|
65448
|
+
await (0, import_utils112.unlink)(socketPath);
|
|
64566
65449
|
}
|
|
64567
65450
|
} catch {
|
|
64568
65451
|
}
|
|
@@ -64585,11 +65468,11 @@ var init_node_express_host = __esm({
|
|
|
64585
65468
|
});
|
|
64586
65469
|
|
|
64587
65470
|
// libs/sdk/src/server/server.instance.ts
|
|
64588
|
-
var
|
|
65471
|
+
var import_utils113, DEFAULT_CORS, FrontMcpServerInstance;
|
|
64589
65472
|
var init_server_instance = __esm({
|
|
64590
65473
|
"libs/sdk/src/server/server.instance.ts"() {
|
|
64591
65474
|
"use strict";
|
|
64592
|
-
|
|
65475
|
+
import_utils113 = require("@frontmcp/utils");
|
|
64593
65476
|
init_common();
|
|
64594
65477
|
init_health2();
|
|
64595
65478
|
init_metrics2();
|
|
@@ -64621,6 +65504,7 @@ var init_server_instance = __esm({
|
|
|
64621
65504
|
this.host = new ExpressHostAdapter2({
|
|
64622
65505
|
...corsConfig ? { cors: corsConfig } : {},
|
|
64623
65506
|
...this.config.security ? { security: this.config.security } : {},
|
|
65507
|
+
...this.config.securityHeaders ? { securityHeaders: this.config.securityHeaders } : {},
|
|
64624
65508
|
...this.config.bodyLimit !== void 0 ? { bodyLimit: this.config.bodyLimit } : {},
|
|
64625
65509
|
...this.config.urlencodedLimit !== void 0 ? { urlencodedLimit: this.config.urlencodedLimit } : {}
|
|
64626
65510
|
});
|
|
@@ -64691,9 +65575,9 @@ var init_server_instance = __esm({
|
|
|
64691
65575
|
}
|
|
64692
65576
|
async start() {
|
|
64693
65577
|
this.prepare();
|
|
64694
|
-
const deploymentMode = (0,
|
|
65578
|
+
const deploymentMode = (0, import_utils113.getRuntimeContext)().deployment;
|
|
64695
65579
|
const bindAddress = resolveBindAddress(this.config.security, deploymentMode);
|
|
64696
|
-
const
|
|
65580
|
+
const isProduction7 = process.env["NODE_ENV"] === "production";
|
|
64697
65581
|
const findings = auditSecurityDefaults(
|
|
64698
65582
|
{
|
|
64699
65583
|
cors: this.config.cors,
|
|
@@ -64701,7 +65585,7 @@ var init_server_instance = __esm({
|
|
|
64701
65585
|
resolvedBindAddress: bindAddress,
|
|
64702
65586
|
deploymentMode
|
|
64703
65587
|
},
|
|
64704
|
-
|
|
65588
|
+
isProduction7
|
|
64705
65589
|
);
|
|
64706
65590
|
logSecurityFindings(findings, console);
|
|
64707
65591
|
await this.host.start(this.config.socketPath ?? this.config.port, bindAddress);
|
|
@@ -64929,11 +65813,11 @@ function resolveConfigInput(optionsOrClass) {
|
|
|
64929
65813
|
}
|
|
64930
65814
|
return optionsOrClass;
|
|
64931
65815
|
}
|
|
64932
|
-
var
|
|
65816
|
+
var import_utils114, stdioServing, FrontMcpInstance;
|
|
64933
65817
|
var init_front_mcp = __esm({
|
|
64934
65818
|
"libs/sdk/src/front-mcp/front-mcp.ts"() {
|
|
64935
65819
|
"use strict";
|
|
64936
|
-
|
|
65820
|
+
import_utils114 = require("@frontmcp/utils");
|
|
64937
65821
|
init_common();
|
|
64938
65822
|
init_direct();
|
|
64939
65823
|
init_errors();
|
|
@@ -64945,6 +65829,7 @@ var init_front_mcp = __esm({
|
|
|
64945
65829
|
init_scope_registry();
|
|
64946
65830
|
init_skill_instructions_helper();
|
|
64947
65831
|
init_task();
|
|
65832
|
+
init_ipc_server_transport();
|
|
64948
65833
|
init_web_fetch_handler();
|
|
64949
65834
|
init_front_mcp_providers();
|
|
64950
65835
|
init_static_startup_check();
|
|
@@ -65064,7 +65949,13 @@ var init_front_mcp = __esm({
|
|
|
65064
65949
|
}
|
|
65065
65950
|
}
|
|
65066
65951
|
static async bootstrap(options) {
|
|
65067
|
-
const
|
|
65952
|
+
const sqlitePath = process.env["FRONTMCP_SQLITE_PATH"];
|
|
65953
|
+
const parsedConfig = frontMcpMetadataSchema.parse(
|
|
65954
|
+
sqlitePath ? {
|
|
65955
|
+
...options,
|
|
65956
|
+
sqlite: { ...options.sqlite ?? {}, path: sqlitePath }
|
|
65957
|
+
} : options
|
|
65958
|
+
);
|
|
65068
65959
|
const daemonSocket = process.env["FRONTMCP_DAEMON_SOCKET"];
|
|
65069
65960
|
if (daemonSocket) {
|
|
65070
65961
|
await _FrontMcpInstance2.runUnixSocket({ ...parsedConfig, socketPath: daemonSocket });
|
|
@@ -65137,7 +66028,7 @@ var init_front_mcp = __esm({
|
|
|
65137
66028
|
frontMcp.log?.info("FrontMCP fetch handler created (web-standard transport)");
|
|
65138
66029
|
return createWebFetchHandler(scope);
|
|
65139
66030
|
};
|
|
65140
|
-
if (!(0,
|
|
66031
|
+
if (!(0, import_utils114.isEdgeRuntime)()) return build(false);
|
|
65141
66032
|
assertStaticStartupConfig(options);
|
|
65142
66033
|
const server = createDeferredServerBuild(() => build(true));
|
|
65143
66034
|
return async (request, ctx, env) => {
|
|
@@ -65282,8 +66173,8 @@ var init_front_mcp = __esm({
|
|
|
65282
66173
|
frontMcp.log?.info(`MCP server listening on unix://${socketPath}`);
|
|
65283
66174
|
const cleanup = async () => {
|
|
65284
66175
|
try {
|
|
65285
|
-
if (await (0,
|
|
65286
|
-
await (0,
|
|
66176
|
+
if (await (0, import_utils114.fileExists)(socketPath)) {
|
|
66177
|
+
await (0, import_utils114.unlink)(socketPath);
|
|
65287
66178
|
}
|
|
65288
66179
|
} catch {
|
|
65289
66180
|
}
|
|
@@ -65427,7 +66318,7 @@ var init_front_mcp = __esm({
|
|
|
65427
66318
|
};
|
|
65428
66319
|
const mcpServer = new McpServer2(scope.metadata.info, serverOptions);
|
|
65429
66320
|
startupCleanups.push(() => mcpServer.close());
|
|
65430
|
-
const sessionId = `stdio:${(0,
|
|
66321
|
+
const sessionId = `stdio:${(0, import_utils114.randomUUID)()}`;
|
|
65431
66322
|
const handlers = createMcpHandlers2({ scope, serverOptions, composeInstructions });
|
|
65432
66323
|
for (const handler of handlers) {
|
|
65433
66324
|
const originalHandler = handler.handler;
|
|
@@ -65441,7 +66332,7 @@ var init_front_mcp = __esm({
|
|
|
65441
66332
|
};
|
|
65442
66333
|
mcpServer.setRequestHandler(handler.requestSchema, wrappedHandler);
|
|
65443
66334
|
}
|
|
65444
|
-
const transport = new StdioServerTransport();
|
|
66335
|
+
const transport = isIpcStdioRequested() ? new IpcServerTransport() : new StdioServerTransport();
|
|
65445
66336
|
startupCleanups.push(() => transport.close());
|
|
65446
66337
|
await mcpServer.connect(transport);
|
|
65447
66338
|
startupSucceeded = true;
|
|
@@ -65747,9 +66638,9 @@ function FrontMcp(providedMetadata) {
|
|
|
65747
66638
|
Reflect.defineMetadata(FrontMcpTokens[property] ?? property, metadata[property], target);
|
|
65748
66639
|
}
|
|
65749
66640
|
Reflect.defineMetadata(FRONTMCP_CONFIG_METADATA_KEY, metadata, target);
|
|
65750
|
-
const isServerless2 = (0,
|
|
65751
|
-
const isSchemaExtract = (0,
|
|
65752
|
-
const isStdio = (0,
|
|
66641
|
+
const isServerless2 = (0, import_utils115.getEnvFlag)("FRONTMCP_SERVERLESS");
|
|
66642
|
+
const isSchemaExtract = (0, import_utils115.getEnvFlag)("FRONTMCP_SCHEMA_EXTRACT");
|
|
66643
|
+
const isStdio = (0, import_utils115.getEnvFlag)("FRONTMCP_STDIO");
|
|
65753
66644
|
const taskWorkerId = typeof process !== "undefined" ? process.env?.["FRONTMCP_RUN_TASK_ID"] : void 0;
|
|
65754
66645
|
if (taskWorkerId && metadata.serve !== false) {
|
|
65755
66646
|
void (async () => {
|
|
@@ -65775,7 +66666,7 @@ function FrontMcp(providedMetadata) {
|
|
|
65775
66666
|
} else if (isServerless2) {
|
|
65776
66667
|
const ServerlessInstance = getFrontMcpInstance();
|
|
65777
66668
|
const { setServerlessHandler: setServerlessHandler2, setServerlessHandlerPromise: setServerlessHandlerPromise2, setServerlessHandlerError: setServerlessHandlerError2 } = getServerlessHandlerFns();
|
|
65778
|
-
const isWorker = (0,
|
|
66669
|
+
const isWorker = (0, import_utils115.getEnvFlag)("FRONTMCP_WORKER");
|
|
65779
66670
|
const handlerPromise = isWorker ? ServerlessInstance.createFetchHandler(metadata) : ServerlessInstance.createHandler(metadata);
|
|
65780
66671
|
setServerlessHandlerPromise2(handlerPromise);
|
|
65781
66672
|
handlerPromise.then(setServerlessHandler2).catch((err) => {
|
|
@@ -65788,12 +66679,12 @@ function FrontMcp(providedMetadata) {
|
|
|
65788
66679
|
}
|
|
65789
66680
|
};
|
|
65790
66681
|
}
|
|
65791
|
-
var import_reflect_metadata28,
|
|
66682
|
+
var import_reflect_metadata28, import_utils115, FRONT_MCP_DECORATOR_BASENAMES, FRONTMCP_CONFIG_METADATA_KEY, _FrontMcpInstance, _serverlessHandlerFns;
|
|
65792
66683
|
var init_front_mcp_decorator = __esm({
|
|
65793
66684
|
"libs/sdk/src/common/decorators/front-mcp.decorator.ts"() {
|
|
65794
66685
|
"use strict";
|
|
65795
66686
|
import_reflect_metadata28 = require("reflect-metadata");
|
|
65796
|
-
|
|
66687
|
+
import_utils115 = require("@frontmcp/utils");
|
|
65797
66688
|
init_decorator_errors();
|
|
65798
66689
|
init_mcp_error();
|
|
65799
66690
|
init_metadata();
|
|
@@ -66507,7 +67398,7 @@ var init_dynamic_adapter = __esm({
|
|
|
66507
67398
|
* @param options - Adapter options including required `name` field
|
|
66508
67399
|
* @throws Error if `name` is missing/empty or if a duplicate name is detected
|
|
66509
67400
|
*/
|
|
66510
|
-
static init(options) {
|
|
67401
|
+
static init(options = {}) {
|
|
66511
67402
|
const typedOptions = options;
|
|
66512
67403
|
const adapterName = typedOptions.name;
|
|
66513
67404
|
if (!adapterName || typeof adapterName !== "string" || adapterName.trim() === "") {
|
|
@@ -66546,49 +67437,6 @@ var init_dynamic_adapter = __esm({
|
|
|
66546
67437
|
}
|
|
66547
67438
|
});
|
|
66548
67439
|
|
|
66549
|
-
// libs/sdk/src/common/dynamic/dynamic.plugin.ts
|
|
66550
|
-
function isDynamicPluginClass(value) {
|
|
66551
|
-
return typeof value === "function" && value.prototype instanceof DynamicPlugin;
|
|
66552
|
-
}
|
|
66553
|
-
var DynamicPlugin;
|
|
66554
|
-
var init_dynamic_plugin = __esm({
|
|
66555
|
-
"libs/sdk/src/common/dynamic/dynamic.plugin.ts"() {
|
|
66556
|
-
"use strict";
|
|
66557
|
-
init_transport_errors();
|
|
66558
|
-
init_dynamic_utils();
|
|
66559
|
-
DynamicPlugin = class {
|
|
66560
|
-
get(token) {
|
|
66561
|
-
throw new MethodNotImplementedError("DynamicPlugin", "get");
|
|
66562
|
-
}
|
|
66563
|
-
/**
|
|
66564
|
-
* Static init() method to create a plugin provider.
|
|
66565
|
-
* @param options - Input options (with optional fields for defaults)
|
|
66566
|
-
*/
|
|
66567
|
-
static init(options) {
|
|
66568
|
-
const extraProviders = options.providers;
|
|
66569
|
-
const typedOptions = options;
|
|
66570
|
-
if ("useFactory" in options) {
|
|
66571
|
-
return {
|
|
66572
|
-
...typedOptions,
|
|
66573
|
-
provide: this,
|
|
66574
|
-
inject: options.inject,
|
|
66575
|
-
useFactory: options.useFactory,
|
|
66576
|
-
providers: dedupePluginProviders(extraProviders ?? [])
|
|
66577
|
-
};
|
|
66578
|
-
}
|
|
66579
|
-
const dyn = collectDynamicProviders(this, typedOptions);
|
|
66580
|
-
const mergedProviders = dedupePluginProviders([...dyn ?? [], ...extraProviders ?? []]);
|
|
66581
|
-
return {
|
|
66582
|
-
...typedOptions,
|
|
66583
|
-
provide: this,
|
|
66584
|
-
useValue: new this(options),
|
|
66585
|
-
providers: mergedProviders
|
|
66586
|
-
};
|
|
66587
|
-
}
|
|
66588
|
-
};
|
|
66589
|
-
}
|
|
66590
|
-
});
|
|
66591
|
-
|
|
66592
67440
|
// libs/sdk/src/common/dynamic/index.ts
|
|
66593
67441
|
var init_dynamic = __esm({
|
|
66594
67442
|
"libs/sdk/src/common/dynamic/index.ts"() {
|
|
@@ -66752,12 +67600,12 @@ var init_adapter_entry = __esm({
|
|
|
66752
67600
|
});
|
|
66753
67601
|
|
|
66754
67602
|
// libs/sdk/src/common/entries/tool.entry.ts
|
|
66755
|
-
var import_lazy_zod109,
|
|
67603
|
+
var import_lazy_zod109, import_utils117, ToolEntry;
|
|
66756
67604
|
var init_tool_entry = __esm({
|
|
66757
67605
|
"libs/sdk/src/common/entries/tool.entry.ts"() {
|
|
66758
67606
|
"use strict";
|
|
66759
67607
|
import_lazy_zod109 = require("@frontmcp/lazy-zod");
|
|
66760
|
-
|
|
67608
|
+
import_utils117 = require("@frontmcp/utils");
|
|
66761
67609
|
init_base_entry();
|
|
66762
67610
|
ToolEntry = class extends BaseEntry {
|
|
66763
67611
|
owner;
|
|
@@ -66824,7 +67672,7 @@ var init_tool_entry = __esm({
|
|
|
66824
67672
|
try {
|
|
66825
67673
|
return (0, import_lazy_zod109.toJSONSchema)(import_lazy_zod109.z.object(this.inputSchema), { io: "input", unrepresentable: "any" });
|
|
66826
67674
|
} catch (error) {
|
|
66827
|
-
if ((0,
|
|
67675
|
+
if ((0, import_utils117.isDebug)() || (0, import_utils117.isDevelopment)()) {
|
|
66828
67676
|
console.warn("[ToolEntry] Failed to convert Zod schema to JSON Schema:", error);
|
|
66829
67677
|
}
|
|
66830
67678
|
return { type: "object", properties: {} };
|
|
@@ -66870,7 +67718,7 @@ var init_tool_entry = __esm({
|
|
|
66870
67718
|
const json = (0, import_lazy_zod109.toJSONSchema)(zodSchema);
|
|
66871
67719
|
return json && json["type"] === "object" ? json : null;
|
|
66872
67720
|
} catch (error) {
|
|
66873
|
-
if ((0,
|
|
67721
|
+
if ((0, import_utils117.isDebug)() || (0, import_utils117.isDevelopment)()) {
|
|
66874
67722
|
console.warn("[ToolEntry] Failed to convert output Zod schema to JSON Schema:", error);
|
|
66875
67723
|
}
|
|
66876
67724
|
return null;
|
|
@@ -68188,6 +69036,7 @@ __export(index_exports, {
|
|
|
68188
69036
|
httpRequestInputSchema: () => httpRequestInputSchema,
|
|
68189
69037
|
httpRespond: () => httpRespond,
|
|
68190
69038
|
incrementalAuthConfigSchema: () => import_auth5.incrementalAuthConfigSchema,
|
|
69039
|
+
initOptionsOf: () => initOptionsOf,
|
|
68191
69040
|
intentSchema: () => intentSchema,
|
|
68192
69041
|
isAlive: () => isAlive,
|
|
68193
69042
|
isAnonymousSubject: () => import_auth61.isAnonymousSubject,
|
|
@@ -68310,6 +69159,7 @@ __export(index_exports, {
|
|
|
68310
69159
|
resolveSchemaDescriptionFormat: () => resolveSchemaDescriptionFormat,
|
|
68311
69160
|
resolveToolVisibility: () => resolveToolVisibility,
|
|
68312
69161
|
resolveWithFallbacks: () => resolveWithFallbacks,
|
|
69162
|
+
resolvesToVercelKvTaskBackend: () => resolvesToVercelKvTaskBackend,
|
|
68313
69163
|
resource: () => frontMcpResource,
|
|
68314
69164
|
resourceTemplate: () => frontMcpResourceTemplate,
|
|
68315
69165
|
resourceUriMatches: () => resourceUriMatches,
|
|
@@ -68534,22 +69384,22 @@ function createMemorySkillProvider(options = {}) {
|
|
|
68534
69384
|
init_skill_utils();
|
|
68535
69385
|
|
|
68536
69386
|
// libs/sdk/src/skill/skill-directory-loader.ts
|
|
68537
|
-
var
|
|
69387
|
+
var import_utils118 = require("@frontmcp/utils");
|
|
68538
69388
|
init_skill_metadata();
|
|
68539
69389
|
init_sdk_errors();
|
|
68540
69390
|
init_skill_md_parser();
|
|
68541
69391
|
async function scanSkillResources(dirPath) {
|
|
68542
69392
|
const resources = {};
|
|
68543
|
-
const scriptsPath = (0,
|
|
68544
|
-
const referencesPath = (0,
|
|
68545
|
-
const assetsPath = (0,
|
|
68546
|
-
const examplesPath = (0,
|
|
69393
|
+
const scriptsPath = (0, import_utils118.joinPath)(dirPath, "scripts");
|
|
69394
|
+
const referencesPath = (0, import_utils118.joinPath)(dirPath, "references");
|
|
69395
|
+
const assetsPath = (0, import_utils118.joinPath)(dirPath, "assets");
|
|
69396
|
+
const examplesPath = (0, import_utils118.joinPath)(dirPath, "examples");
|
|
68547
69397
|
const checks = await Promise.all([
|
|
68548
69398
|
checkDirectory(scriptsPath),
|
|
68549
69399
|
checkDirectory(referencesPath),
|
|
68550
69400
|
checkDirectory(assetsPath),
|
|
68551
69401
|
checkDirectory(examplesPath),
|
|
68552
|
-
(0,
|
|
69402
|
+
(0, import_utils118.fileExists)((0, import_utils118.joinPath)(dirPath, "SKILL.md"))
|
|
68553
69403
|
]);
|
|
68554
69404
|
if (checks[0]) resources.scripts = scriptsPath;
|
|
68555
69405
|
if (checks[1]) resources.references = referencesPath;
|
|
@@ -68562,7 +69412,7 @@ async function scanSkillResources(dirPath) {
|
|
|
68562
69412
|
}
|
|
68563
69413
|
async function checkDirectory(path3) {
|
|
68564
69414
|
try {
|
|
68565
|
-
const s = await (0,
|
|
69415
|
+
const s = await (0, import_utils118.stat)(path3);
|
|
68566
69416
|
return s.isDirectory();
|
|
68567
69417
|
} catch (err) {
|
|
68568
69418
|
if (err.code === "ENOENT") return false;
|
|
@@ -68575,16 +69425,16 @@ async function findNestedSkillMd(dirPath, maxDepth = Number.POSITIVE_INFINITY) {
|
|
|
68575
69425
|
if (depth > maxDepth) return;
|
|
68576
69426
|
let entries;
|
|
68577
69427
|
try {
|
|
68578
|
-
entries = await (0,
|
|
69428
|
+
entries = await (0, import_utils118.readdir)(current);
|
|
68579
69429
|
} catch (err) {
|
|
68580
69430
|
if (err.code === "ENOENT") return;
|
|
68581
69431
|
throw err;
|
|
68582
69432
|
}
|
|
68583
69433
|
for (const entry of entries) {
|
|
68584
|
-
const full = (0,
|
|
69434
|
+
const full = (0, import_utils118.joinPath)(current, entry);
|
|
68585
69435
|
let entryStat;
|
|
68586
69436
|
try {
|
|
68587
|
-
entryStat = await (0,
|
|
69437
|
+
entryStat = await (0, import_utils118.stat)(full);
|
|
68588
69438
|
} catch (err) {
|
|
68589
69439
|
if (err.code === "ENOENT") continue;
|
|
68590
69440
|
throw err;
|
|
@@ -68600,19 +69450,19 @@ async function findNestedSkillMd(dirPath, maxDepth = Number.POSITIVE_INFINITY) {
|
|
|
68600
69450
|
return found.sort();
|
|
68601
69451
|
}
|
|
68602
69452
|
async function loadSkillDirectory(dirPath, logger) {
|
|
68603
|
-
const skillMdPath = (0,
|
|
68604
|
-
const exists = await (0,
|
|
69453
|
+
const skillMdPath = (0, import_utils118.joinPath)(dirPath, "SKILL.md");
|
|
69454
|
+
const exists = await (0, import_utils118.fileExists)(skillMdPath);
|
|
68605
69455
|
if (!exists) {
|
|
68606
|
-
throw new InvalidSkillError((0,
|
|
69456
|
+
throw new InvalidSkillError((0, import_utils118.basename)(dirPath), "SKILL.md not found in directory");
|
|
68607
69457
|
}
|
|
68608
69458
|
let content;
|
|
68609
69459
|
let partialMetadata;
|
|
68610
69460
|
try {
|
|
68611
|
-
content = await (0,
|
|
69461
|
+
content = await (0, import_utils118.readFile)(skillMdPath, "utf-8");
|
|
68612
69462
|
const { frontmatter, body } = parseSkillMdFrontmatter(content);
|
|
68613
69463
|
partialMetadata = skillMdFrontmatterToMetadata(frontmatter, body);
|
|
68614
69464
|
} catch (err) {
|
|
68615
|
-
const name44 = (0,
|
|
69465
|
+
const name44 = (0, import_utils118.basename)(dirPath);
|
|
68616
69466
|
const message = err instanceof Error ? err.message : String(err);
|
|
68617
69467
|
throw new InvalidSkillError(name44, `Failed to read or parse SKILL.md: ${message}`);
|
|
68618
69468
|
}
|
|
@@ -68623,13 +69473,13 @@ async function loadSkillDirectory(dirPath, logger) {
|
|
|
68623
69473
|
}
|
|
68624
69474
|
const nested = await findNestedSkillMd(dirPath);
|
|
68625
69475
|
if (nested.length > 0) {
|
|
68626
|
-
const skillName2 = partialMetadata.name ?? (0,
|
|
69476
|
+
const skillName2 = partialMetadata.name ?? (0, import_utils118.basename)(dirPath);
|
|
68627
69477
|
throw new InvalidSkillError(
|
|
68628
69478
|
skillName2,
|
|
68629
69479
|
`Skill directory contains nested SKILL.md files (forbidden by SEP-2640 \xA7Resource Mapping): ${nested.join(", ")}`
|
|
68630
69480
|
);
|
|
68631
69481
|
}
|
|
68632
|
-
const dirName = (0,
|
|
69482
|
+
const dirName = (0, import_utils118.basename)(dirPath);
|
|
68633
69483
|
if (partialMetadata.name && dirName && partialMetadata.name !== dirName) {
|
|
68634
69484
|
const msg = `Skill name "${partialMetadata.name}" does not match directory name "${dirName}"`;
|
|
68635
69485
|
if (logger) {
|
|
@@ -69430,6 +70280,7 @@ var ChannelListHook = FlowHooksOf("channels:list");
|
|
|
69430
70280
|
httpRequestInputSchema,
|
|
69431
70281
|
httpRespond,
|
|
69432
70282
|
incrementalAuthConfigSchema,
|
|
70283
|
+
initOptionsOf,
|
|
69433
70284
|
intentSchema,
|
|
69434
70285
|
isAlive,
|
|
69435
70286
|
isAnonymousSubject,
|
|
@@ -69552,6 +70403,7 @@ var ChannelListHook = FlowHooksOf("channels:list");
|
|
|
69552
70403
|
resolveSchemaDescriptionFormat,
|
|
69553
70404
|
resolveToolVisibility,
|
|
69554
70405
|
resolveWithFallbacks,
|
|
70406
|
+
resolvesToVercelKvTaskBackend,
|
|
69555
70407
|
resource,
|
|
69556
70408
|
resourceTemplate,
|
|
69557
70409
|
resourceUriMatches,
|