@frontmcp/sdk 1.8.4 → 1.8.6
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/agent.instance.d.ts +9 -3
- package/agent/agent.instance.d.ts.map +1 -1
- package/agent/flows/call-agent.flow.d.ts +19 -1
- package/agent/flows/call-agent.flow.d.ts.map +1 -1
- package/agent/hooks/agent.hooks.d.ts +4 -4
- package/agent/hooks/agent.hooks.d.ts.map +1 -1
- package/auth/flows/oauth.auth-ui.flow.d.ts +1 -1
- package/auth/flows/oauth.authorize.flow.d.ts +3 -3
- package/auth/flows/oauth.authorize.flow.d.ts.map +1 -1
- package/auth/flows/oauth.callback.flow.d.ts +2 -2
- package/auth/flows/oauth.connect.flow.d.ts +1 -1
- package/auth/flows/oauth.provider-callback.flow.d.ts +2 -2
- package/auth/flows/oauth.provider-callback.flow.d.ts.map +1 -1
- package/auth/flows/oauth.register.flow.d.ts +1 -1
- package/auth/flows/oauth.token.flow.d.ts +1 -1
- package/auth/flows/oauth.userinfo.flow.d.ts +1 -1
- package/auth/flows/session.verify.flow.d.ts +1 -0
- package/auth/flows/session.verify.flow.d.ts.map +1 -1
- package/auth/flows/well-known.jwks.flow.d.ts +3 -3
- package/auth/flows/well-known.oauth-authorization-server.flow.d.ts +3 -2
- package/auth/flows/well-known.oauth-authorization-server.flow.d.ts.map +1 -1
- package/auth/flows/well-known.prm.flow.d.ts +4 -3
- package/auth/flows/well-known.prm.flow.d.ts.map +1 -1
- package/auth/instances/instance.local-primary-auth.d.ts +30 -19
- package/auth/instances/instance.local-primary-auth.d.ts.map +1 -1
- package/channel/channel-scope.helper.d.ts +13 -1
- package/channel/channel-scope.helper.d.ts.map +1 -1
- package/channel/sources/completion-events.d.ts +24 -0
- package/channel/sources/completion-events.d.ts.map +1 -0
- package/channel/sources/job-completion.source.d.ts +1 -1
- package/channel/sources/job-completion.source.d.ts.map +1 -1
- package/common/dynamic/dynamic.plugin.d.ts +11 -2
- package/common/dynamic/dynamic.plugin.d.ts.map +1 -1
- package/common/entries/agent.entry.d.ts +6 -0
- package/common/entries/agent.entry.d.ts.map +1 -1
- package/common/entries/scope.entry.d.ts +2 -3
- package/common/entries/scope.entry.d.ts.map +1 -1
- package/common/interfaces/internal/primary-auth-provider.interface.d.ts +5 -5
- package/common/interfaces/internal/primary-auth-provider.interface.d.ts.map +1 -1
- package/common/interfaces/tool.interface.d.ts.map +1 -1
- package/common/metadata/tool.metadata.d.ts +2 -2
- package/common/metadata/workflow.metadata.d.ts +1 -1
- package/common/schemas/http-output.schema.d.ts +24 -24
- package/common/utils/list-all-pages.utils.d.ts +17 -0
- package/common/utils/list-all-pages.utils.d.ts.map +1 -0
- package/common/utils/path.utils.d.ts +2 -0
- package/common/utils/path.utils.d.ts.map +1 -1
- package/context/frontmcp-context.d.ts +4 -0
- package/context/frontmcp-context.d.ts.map +1 -1
- package/elicitation/helpers/elicit.helper.d.ts.map +1 -1
- package/esm/index.mjs +1176 -444
- package/front-mcp/front-mcp.d.ts.map +1 -1
- package/index.d.ts +6 -6
- package/index.d.ts.map +1 -1
- package/index.js +1276 -550
- package/job/job-scope.helper.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 +16 -5
- package/remote-mcp/mcp-stateless-client.adapter.d.ts.map +1 -1
- package/scope/flows/http.request.flow.d.ts.map +1 -1
- package/scope/scope.instance.d.ts +3 -3
- package/scope/scope.instance.d.ts.map +1 -1
- package/skill/auth/skill-http-auth.d.ts.map +1 -1
- package/skill/flows/http/llm-full-txt.flow.d.ts +1 -1
- package/skill/flows/http/llm-txt.flow.d.ts +1 -1
- package/skill/flows/http/skills-api.flow.d.ts +1 -1
- package/skill/flows/http/skills-api.flow.d.ts.map +1 -1
- package/skill/flows/load-skill.flow.d.ts.map +1 -1
- package/skill/index.d.ts +1 -1
- package/skill/index.d.ts.map +1 -1
- package/skill/sep-2640/sep-2640.resource-helpers.d.ts +6 -0
- package/skill/sep-2640/sep-2640.resource-helpers.d.ts.map +1 -1
- package/skill/skill-filter.helper.d.ts +25 -0
- package/skill/skill-filter.helper.d.ts.map +1 -1
- package/skill/skill-http.utils.d.ts.map +1 -1
- package/skill/skill.events.d.ts.map +1 -1
- package/skill/skill.registry.d.ts +94 -17
- package/skill/skill.registry.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/transport/flows/handle.mcp-20260728.flow.d.ts +1 -0
- 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.streamable-http.flow.d.ts +11 -1
- package/transport/flows/handle.streamable-http.flow.d.ts.map +1 -1
- package/transport/index.d.ts +1 -1
- package/transport/index.d.ts.map +1 -1
- package/transport/mcp-20260728/client/mcp-stateless.client.d.ts +7 -2
- package/transport/mcp-20260728/client/mcp-stateless.client.d.ts.map +1 -1
- package/transport/mcp-20260728/dispatcher.d.ts +5 -0
- package/transport/mcp-20260728/dispatcher.d.ts.map +1 -1
- package/transport/mcp-20260728/mrtr.d.ts +8 -0
- package/transport/mcp-20260728/mrtr.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/mcp-handlers/skills-load-request.handler.d.ts.map +1 -1
- package/transport/web-fetch-handler.d.ts +33 -0
- package/transport/web-fetch-handler.d.ts.map +1 -1
- package/workflow/engine/workflow.engine.d.ts.map +1 -1
package/index.js
CHANGED
|
@@ -5972,6 +5972,33 @@ var init_errors = __esm({
|
|
|
5972
5972
|
}
|
|
5973
5973
|
});
|
|
5974
5974
|
|
|
5975
|
+
// libs/sdk/src/common/utils/list-all-pages.utils.ts
|
|
5976
|
+
async function listAllPages(method, fetchPage, fail = (message) => new InternalMcpError(message, "LIST_PAGINATION_STALLED")) {
|
|
5977
|
+
const items = [];
|
|
5978
|
+
const seenCursors = /* @__PURE__ */ new Set();
|
|
5979
|
+
let cursor;
|
|
5980
|
+
for (let page = 0; page < MAX_LIST_PAGES; page++) {
|
|
5981
|
+
const result = await fetchPage(cursor);
|
|
5982
|
+
items.push(...result.items ?? []);
|
|
5983
|
+
const next = result.nextCursor;
|
|
5984
|
+
if (!next) return items;
|
|
5985
|
+
if (seenCursors.has(next)) {
|
|
5986
|
+
throw fail(`${method} returned the cursor "${next}" twice`);
|
|
5987
|
+
}
|
|
5988
|
+
seenCursors.add(next);
|
|
5989
|
+
cursor = next;
|
|
5990
|
+
}
|
|
5991
|
+
throw fail(`${method} did not finish within ${MAX_LIST_PAGES} pages`);
|
|
5992
|
+
}
|
|
5993
|
+
var MAX_LIST_PAGES;
|
|
5994
|
+
var init_list_all_pages_utils = __esm({
|
|
5995
|
+
"libs/sdk/src/common/utils/list-all-pages.utils.ts"() {
|
|
5996
|
+
"use strict";
|
|
5997
|
+
init_mcp_error();
|
|
5998
|
+
MAX_LIST_PAGES = 1e3;
|
|
5999
|
+
}
|
|
6000
|
+
});
|
|
6001
|
+
|
|
5975
6002
|
// libs/sdk/src/transport/mcp-handlers/skills-mcp.types.ts
|
|
5976
6003
|
var import_lazy_zod40, SkillsSearchRequestSchema, SkillsSearchResultSchema, SkillsLoadRequestSchema, SkillsLoadResultSchema, SkillsListRequestSchema, SkillsListResultSchema;
|
|
5977
6004
|
var init_skills_mcp_types = __esm({
|
|
@@ -6429,30 +6456,30 @@ var require_dist = __commonJS({
|
|
|
6429
6456
|
sqliteStorageOptionsSchema: () => sqliteStorageOptionsSchema
|
|
6430
6457
|
});
|
|
6431
6458
|
module2.exports = __toCommonJS2(index_exports2);
|
|
6432
|
-
var
|
|
6459
|
+
var import_utils114 = require("@frontmcp/utils");
|
|
6433
6460
|
var HKDF_SALT = new TextEncoder().encode("frontmcp-sqlite-storage-v1");
|
|
6434
6461
|
var HKDF_INFO = new TextEncoder().encode("aes-256-gcm-value-encryption");
|
|
6435
6462
|
var KEY_LENGTH = 32;
|
|
6436
6463
|
function deriveEncryptionKey(secret) {
|
|
6437
6464
|
const ikm = new TextEncoder().encode(secret);
|
|
6438
|
-
return (0,
|
|
6465
|
+
return (0, import_utils114.hkdfSha256)(ikm, HKDF_SALT, HKDF_INFO, KEY_LENGTH);
|
|
6439
6466
|
}
|
|
6440
6467
|
var SEPARATOR = ":";
|
|
6441
6468
|
function encryptValue(key, plaintext) {
|
|
6442
|
-
const iv = (0,
|
|
6469
|
+
const iv = (0, import_utils114.randomBytes)(12);
|
|
6443
6470
|
const plaintextBytes = new TextEncoder().encode(plaintext);
|
|
6444
|
-
const { ciphertext, tag } = (0,
|
|
6445
|
-
return [(0,
|
|
6471
|
+
const { ciphertext, tag } = (0, import_utils114.encryptAesGcm)(key, plaintextBytes, iv);
|
|
6472
|
+
return [(0, import_utils114.base64urlEncode)(iv), (0, import_utils114.base64urlEncode)(tag), (0, import_utils114.base64urlEncode)(ciphertext)].join(SEPARATOR);
|
|
6446
6473
|
}
|
|
6447
6474
|
function decryptValue(key, encrypted) {
|
|
6448
6475
|
const parts = encrypted.split(SEPARATOR);
|
|
6449
6476
|
if (parts.length !== 3) {
|
|
6450
6477
|
throw new Error("Invalid encrypted value format");
|
|
6451
6478
|
}
|
|
6452
|
-
const iv = (0,
|
|
6453
|
-
const tag = (0,
|
|
6454
|
-
const ciphertext = (0,
|
|
6455
|
-
const plaintext = (0,
|
|
6479
|
+
const iv = (0, import_utils114.base64urlDecode)(parts[0]);
|
|
6480
|
+
const tag = (0, import_utils114.base64urlDecode)(parts[1]);
|
|
6481
|
+
const ciphertext = (0, import_utils114.base64urlDecode)(parts[2]);
|
|
6482
|
+
const plaintext = (0, import_utils114.decryptAesGcm)(key, ciphertext, iv, tag);
|
|
6456
6483
|
return new TextDecoder().decode(plaintext);
|
|
6457
6484
|
}
|
|
6458
6485
|
var import_utils210 = require("@frontmcp/utils");
|
|
@@ -10203,7 +10230,33 @@ async function filterDiscoverableSkillResults(scope, registry, results, caller =
|
|
|
10203
10230
|
return entry === void 0 || servable.has(entry);
|
|
10204
10231
|
});
|
|
10205
10232
|
}
|
|
10206
|
-
|
|
10233
|
+
function skillToolsForCaller(loaded, tools, ctx, surface) {
|
|
10234
|
+
const caller = callerSurface(ctx, surface);
|
|
10235
|
+
if (!tools || caller === void 0 || loaded.availableTools.length === 0) return loaded;
|
|
10236
|
+
const availability = new Map(tools.getTools(true).map((tool) => [tool.name, tool.metadata?.availableWhen]));
|
|
10237
|
+
const notOffered = loaded.availableTools.filter((name44) => !isOfferedOnSurface(availability.get(name44), caller));
|
|
10238
|
+
if (notOffered.length === 0) return loaded;
|
|
10239
|
+
return {
|
|
10240
|
+
...loaded,
|
|
10241
|
+
availableTools: loaded.availableTools.filter((name44) => !notOffered.includes(name44)),
|
|
10242
|
+
missingTools: [...loaded.missingTools, ...notOffered],
|
|
10243
|
+
isComplete: false,
|
|
10244
|
+
warning: warningWithMissingTools(loaded.warning, loaded.skill?.name, notOffered)
|
|
10245
|
+
};
|
|
10246
|
+
}
|
|
10247
|
+
function warningWithMissingTools(warning, skillName, names) {
|
|
10248
|
+
const prefix = warning?.match(WARNING_PREFIX);
|
|
10249
|
+
if (warning && prefix && warning.endsWith(WARNING_SUFFIX)) {
|
|
10250
|
+
const parts = warning.slice(prefix[0].length, -WARNING_SUFFIX.length).split("; ");
|
|
10251
|
+
const missing = parts.findIndex((part) => part.startsWith(MISSING_PART));
|
|
10252
|
+
if (missing === -1) parts.unshift(`${MISSING_PART}${names.join(", ")}`);
|
|
10253
|
+
else parts[missing] = `${parts[missing]}, ${names.join(", ")}`;
|
|
10254
|
+
return `${prefix[0]}${parts.join("; ")}${WARNING_SUFFIX}`;
|
|
10255
|
+
}
|
|
10256
|
+
const sentence = `Skill "${skillName ?? "skill"}" references ${MISSING_PART}${names.join(", ")}${WARNING_SUFFIX}`;
|
|
10257
|
+
return warning ? `${warning} ${sentence}` : sentence;
|
|
10258
|
+
}
|
|
10259
|
+
var SKILLS_HTTP_SURFACE, WARNING_PREFIX, WARNING_SUFFIX, MISSING_PART;
|
|
10207
10260
|
var init_skill_filter_helper = __esm({
|
|
10208
10261
|
"libs/sdk/src/skill/skill-filter.helper.ts"() {
|
|
10209
10262
|
"use strict";
|
|
@@ -10212,6 +10265,9 @@ var init_skill_filter_helper = __esm({
|
|
|
10212
10265
|
init_skill_authorities_helper();
|
|
10213
10266
|
init_skill_entry_resolver();
|
|
10214
10267
|
SKILLS_HTTP_SURFACE = "mcp";
|
|
10268
|
+
WARNING_PREFIX = /^Skill "(.*)" references /;
|
|
10269
|
+
WARNING_SUFFIX = ". Some functionality may be limited.";
|
|
10270
|
+
MISSING_PART = "missing tools: ";
|
|
10215
10271
|
}
|
|
10216
10272
|
});
|
|
10217
10273
|
|
|
@@ -10312,7 +10368,13 @@ async function formatSkillsForLlmFull(registry, toolRegistry, visibility = "both
|
|
|
10312
10368
|
}
|
|
10313
10369
|
const loaded = await registry.loadSkill(skill.name);
|
|
10314
10370
|
if (loaded) {
|
|
10315
|
-
|
|
10371
|
+
const { availableTools, missingTools } = skillToolsForCaller(
|
|
10372
|
+
loaded,
|
|
10373
|
+
toolRegistry,
|
|
10374
|
+
void 0,
|
|
10375
|
+
SKILLS_HTTP_SURFACE
|
|
10376
|
+
);
|
|
10377
|
+
parts.push(formatSkillForLLMWithSchemas(loaded.skill, availableTools, missingTools, toolRegistry));
|
|
10316
10378
|
}
|
|
10317
10379
|
}
|
|
10318
10380
|
return parts.join("\n\n---\n\n");
|
|
@@ -10432,6 +10494,7 @@ function skillToApiResponse(skill, loadResult) {
|
|
|
10432
10494
|
var init_skill_http_utils = __esm({
|
|
10433
10495
|
"libs/sdk/src/skill/skill-http.utils.ts"() {
|
|
10434
10496
|
"use strict";
|
|
10497
|
+
init_skill_filter_helper();
|
|
10435
10498
|
}
|
|
10436
10499
|
});
|
|
10437
10500
|
|
|
@@ -10995,7 +11058,11 @@ function skillsLoadRequestHandler({
|
|
|
10995
11058
|
throw toSdkMcpError(err);
|
|
10996
11059
|
}
|
|
10997
11060
|
}
|
|
10998
|
-
const { skill, availableTools, missingTools, isComplete, warning } =
|
|
11061
|
+
const { skill, availableTools, missingTools, isComplete, warning } = skillToolsForCaller(
|
|
11062
|
+
loadResult,
|
|
11063
|
+
toolRegistry,
|
|
11064
|
+
withMcpSurface(scope, ctx)
|
|
11065
|
+
);
|
|
10999
11066
|
if (warning) {
|
|
11000
11067
|
warnings.push(warning);
|
|
11001
11068
|
}
|
|
@@ -12003,6 +12070,7 @@ var init_direct_client = __esm({
|
|
|
12003
12070
|
"use strict";
|
|
12004
12071
|
import_protocol30 = require("@frontmcp/protocol");
|
|
12005
12072
|
import_utils29 = require("@frontmcp/utils");
|
|
12073
|
+
init_list_all_pages_utils();
|
|
12006
12074
|
init_errors();
|
|
12007
12075
|
init_skills_mcp_types();
|
|
12008
12076
|
init_llm_platform();
|
|
@@ -12149,8 +12217,11 @@ var init_direct_client = __esm({
|
|
|
12149
12217
|
// Tool Operations (platform-formatted)
|
|
12150
12218
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
12151
12219
|
async listTools() {
|
|
12152
|
-
const
|
|
12153
|
-
|
|
12220
|
+
const tools = await listAllPages("tools/list", async (cursor) => {
|
|
12221
|
+
const result = await this.mcpClient.listTools(cursor ? { cursor } : void 0);
|
|
12222
|
+
return { items: result.tools, nextCursor: result.nextCursor };
|
|
12223
|
+
});
|
|
12224
|
+
return formatToolsForPlatform(tools, this.platform);
|
|
12154
12225
|
}
|
|
12155
12226
|
async callTool(name44, args) {
|
|
12156
12227
|
const result = await this.mcpClient.callTool({
|
|
@@ -14550,6 +14621,9 @@ function readPublicUrlPin() {
|
|
|
14550
14621
|
function isPublicUrlPinned() {
|
|
14551
14622
|
return readPublicUrlPin() !== void 0;
|
|
14552
14623
|
}
|
|
14624
|
+
function getPinnedPublicUrl() {
|
|
14625
|
+
return readPublicUrlPin();
|
|
14626
|
+
}
|
|
14553
14627
|
function isProxyTrusted() {
|
|
14554
14628
|
try {
|
|
14555
14629
|
if (typeof process !== "undefined" && process.env) {
|
|
@@ -15999,6 +16073,11 @@ async function performElicit(deps, message, requestedSchema, options) {
|
|
|
15999
16073
|
}
|
|
16000
16074
|
const ctx = tryGetContext();
|
|
16001
16075
|
const mrtr = ctx?.getMrtrExchange?.();
|
|
16076
|
+
if (mrtr && mrtr.clientDeclaredRevision === false && mrtr.supportsElicitation?.(options?.mode ?? "form") !== true) {
|
|
16077
|
+
throw new ElicitationNotSupportedError(
|
|
16078
|
+
"This client does not support elicitation: it declared no elicitation capability, and without a session the elicitation fallback has no one to answer it"
|
|
16079
|
+
);
|
|
16080
|
+
}
|
|
16002
16081
|
if (mrtr) {
|
|
16003
16082
|
const zodSchema = requestedSchema instanceof import_lazy_zod45.z.ZodType ? requestedSchema : import_lazy_zod45.z.object(requestedSchema);
|
|
16004
16083
|
const answer = mrtr.resolveElicitation({
|
|
@@ -21944,6 +22023,9 @@ var init_call_tool_flow = __esm({
|
|
|
21944
22023
|
uiResult: import_lazy_zod57.z.any().optional(),
|
|
21945
22024
|
// UI metadata from rendering (merged into _meta)
|
|
21946
22025
|
uiMeta: import_lazy_zod57.z.record(import_lazy_zod57.z.string(), import_lazy_zod57.z.unknown()).optional(),
|
|
22026
|
+
// Metadata hooks add to the result (e.g. the cache plugin's `cache: 'hit'`), merged into the
|
|
22027
|
+
// result's _meta; never merged into rawOutput, which is the tool's data
|
|
22028
|
+
resultMeta: import_lazy_zod57.z.record(import_lazy_zod57.z.string(), import_lazy_zod57.z.unknown()).optional(),
|
|
21947
22029
|
// Progress token from request's _meta (for progress notifications)
|
|
21948
22030
|
progressToken: import_lazy_zod57.z.union([import_lazy_zod57.z.string(), import_lazy_zod57.z.number()]).optional(),
|
|
21949
22031
|
// JSON-RPC request ID (for elicitation routing)
|
|
@@ -22364,6 +22446,7 @@ var init_call_tool_flow = __esm({
|
|
|
22364
22446
|
context.mark("createToolCallContext");
|
|
22365
22447
|
context._toolNameInternal = tool.metadata.id ?? tool.metadata.name;
|
|
22366
22448
|
context._toolInputInternal = input.arguments;
|
|
22449
|
+
context._jsonRpcRequestIdInternal = this.state.jsonRpcRequestId;
|
|
22367
22450
|
const frontmcpContext = context.tryGetContext();
|
|
22368
22451
|
const authInfoWithTransport = authInfo;
|
|
22369
22452
|
if (frontmcpContext && authInfoWithTransport?.transport?.sendElicitRequest) {
|
|
@@ -22770,7 +22853,7 @@ ${JSON.stringify(error.schema, null, 2)}
|
|
|
22770
22853
|
}
|
|
22771
22854
|
async finalize() {
|
|
22772
22855
|
this.logger.verbose("finalize:start");
|
|
22773
|
-
const { tool, rawOutput, uiResult, uiMeta } = this.state;
|
|
22856
|
+
const { tool, rawOutput, uiResult, uiMeta, resultMeta } = this.state;
|
|
22774
22857
|
if (!tool) {
|
|
22775
22858
|
this.logger.verbose("finalize: skipping (no tool in state)");
|
|
22776
22859
|
return;
|
|
@@ -22813,6 +22896,9 @@ ${JSON.stringify(error.schema, null, 2)}
|
|
|
22813
22896
|
if (rawMeta) {
|
|
22814
22897
|
result._meta = { ...result._meta, ...rawMeta };
|
|
22815
22898
|
}
|
|
22899
|
+
if (resultMeta) {
|
|
22900
|
+
result._meta = { ...result._meta, ...resultMeta };
|
|
22901
|
+
}
|
|
22816
22902
|
if (uiResult) {
|
|
22817
22903
|
result.content = uiResult.content;
|
|
22818
22904
|
if (uiResult.structuredContent !== void 0 && uiResult.structuredContent !== null) {
|
|
@@ -25358,6 +25444,56 @@ var init_dynamic_utils = __esm({
|
|
|
25358
25444
|
}
|
|
25359
25445
|
});
|
|
25360
25446
|
|
|
25447
|
+
// libs/sdk/src/common/dynamic/dynamic.plugin.ts
|
|
25448
|
+
function isDynamicPluginClass(value) {
|
|
25449
|
+
return typeof value === "function" && value.prototype instanceof DynamicPlugin;
|
|
25450
|
+
}
|
|
25451
|
+
function initOptionsOf(instance) {
|
|
25452
|
+
return initOptionsByInstance.has(instance) ? { options: initOptionsByInstance.get(instance) } : void 0;
|
|
25453
|
+
}
|
|
25454
|
+
var initOptionsByInstance, DynamicPlugin;
|
|
25455
|
+
var init_dynamic_plugin = __esm({
|
|
25456
|
+
"libs/sdk/src/common/dynamic/dynamic.plugin.ts"() {
|
|
25457
|
+
"use strict";
|
|
25458
|
+
init_transport_errors();
|
|
25459
|
+
init_dynamic_utils();
|
|
25460
|
+
initOptionsByInstance = /* @__PURE__ */ new WeakMap();
|
|
25461
|
+
DynamicPlugin = class {
|
|
25462
|
+
get(token) {
|
|
25463
|
+
throw new MethodNotImplementedError("DynamicPlugin", "get");
|
|
25464
|
+
}
|
|
25465
|
+
/**
|
|
25466
|
+
* Static init() method to create a plugin provider.
|
|
25467
|
+
* @param options - Input options (with optional fields for defaults). Omitted, the plugin is
|
|
25468
|
+
* built with `{}`, as `ApprovalPlugin.init()` is documented.
|
|
25469
|
+
*/
|
|
25470
|
+
static init(options = {}) {
|
|
25471
|
+
const extraProviders = options.providers;
|
|
25472
|
+
const typedOptions = options;
|
|
25473
|
+
if ("useFactory" in options) {
|
|
25474
|
+
return {
|
|
25475
|
+
...typedOptions,
|
|
25476
|
+
provide: this,
|
|
25477
|
+
inject: options.inject,
|
|
25478
|
+
useFactory: options.useFactory,
|
|
25479
|
+
providers: dedupePluginProviders(extraProviders ?? [])
|
|
25480
|
+
};
|
|
25481
|
+
}
|
|
25482
|
+
const dyn = collectDynamicProviders(this, typedOptions);
|
|
25483
|
+
const mergedProviders = dedupePluginProviders([...dyn ?? [], ...extraProviders ?? []]);
|
|
25484
|
+
const instance = new this(options);
|
|
25485
|
+
initOptionsByInstance.set(instance, options);
|
|
25486
|
+
return {
|
|
25487
|
+
...typedOptions,
|
|
25488
|
+
provide: this,
|
|
25489
|
+
useValue: instance,
|
|
25490
|
+
providers: mergedProviders
|
|
25491
|
+
};
|
|
25492
|
+
}
|
|
25493
|
+
};
|
|
25494
|
+
}
|
|
25495
|
+
});
|
|
25496
|
+
|
|
25361
25497
|
// libs/sdk/src/common/interfaces/internal/flow.utils.ts
|
|
25362
25498
|
var FlowState;
|
|
25363
25499
|
var init_flow_utils2 = __esm({
|
|
@@ -27238,7 +27374,11 @@ var init_skill_events = __esm({
|
|
|
27238
27374
|
*/
|
|
27239
27375
|
emit(event) {
|
|
27240
27376
|
for (const listener of [...this.listeners]) {
|
|
27241
|
-
|
|
27377
|
+
try {
|
|
27378
|
+
listener(event);
|
|
27379
|
+
} catch (err) {
|
|
27380
|
+
console.error("SkillEmitter listener error:", err instanceof Error ? err.message : "Unknown error");
|
|
27381
|
+
}
|
|
27242
27382
|
}
|
|
27243
27383
|
}
|
|
27244
27384
|
/**
|
|
@@ -27517,6 +27657,24 @@ var init_skill_instance = __esm({
|
|
|
27517
27657
|
});
|
|
27518
27658
|
|
|
27519
27659
|
// libs/sdk/src/skill/skill.registry.ts
|
|
27660
|
+
function findIdPathCollision(skills) {
|
|
27661
|
+
const byPath = /* @__PURE__ */ new Map();
|
|
27662
|
+
for (const skill of skills) {
|
|
27663
|
+
const path3 = skill.getSkillPath();
|
|
27664
|
+
if (!byPath.has(path3)) byPath.set(path3, skill);
|
|
27665
|
+
}
|
|
27666
|
+
for (const idOwner of skills) {
|
|
27667
|
+
const id = idOwner.metadata.id;
|
|
27668
|
+
if (!id || id === idOwner.getSkillPath()) continue;
|
|
27669
|
+
const pathOwner = byPath.get(id);
|
|
27670
|
+
if (pathOwner) return { idOwner, pathOwner };
|
|
27671
|
+
}
|
|
27672
|
+
return void 0;
|
|
27673
|
+
}
|
|
27674
|
+
function describeIdPathCollision({ idOwner, pathOwner }) {
|
|
27675
|
+
const id = idOwner.metadata.id;
|
|
27676
|
+
return `id "${id}" of skill "${idOwner.metadata.name}" is the skill:// path of skill "${pathOwner.metadata.name}", so skill://${id}/SKILL.md would serve one for the other. Give one of them another id or name.`;
|
|
27677
|
+
}
|
|
27520
27678
|
var import_di22, import_utils61, DEFAULT_LIST_LIMIT, SkillRegistry;
|
|
27521
27679
|
var init_skill_registry = __esm({
|
|
27522
27680
|
"libs/sdk/src/skill/skill.registry.ts"() {
|
|
@@ -27550,16 +27708,30 @@ var init_skill_registry = __esm({
|
|
|
27550
27708
|
dynamicContents = /* @__PURE__ */ new Map();
|
|
27551
27709
|
/**
|
|
27552
27710
|
* Per-id generation counter for dynamic registrations. Bumped on every
|
|
27553
|
-
* registerSkillContent call so a stale unregister
|
|
27554
|
-
* caller cannot remove a
|
|
27711
|
+
* registerSkillContent call, and on every removal, so a stale unregister
|
|
27712
|
+
* handle held by an earlier caller cannot remove a later registration. Never
|
|
27713
|
+
* reset: a counter restarted at 1 would match an old handle's generation.
|
|
27555
27714
|
*/
|
|
27556
27715
|
dynamicGenerations = /* @__PURE__ */ new Map();
|
|
27716
|
+
/**
|
|
27717
|
+
* Ids of skills that left the registry (its own dynamic skills, or an adopted child's) whose copy
|
|
27718
|
+
* in the storage provider is not removed yet: the removal is pending, or the provider failed it.
|
|
27719
|
+
* Provider-backed reads skip them until the removal succeeds or the id is served again. Each maps
|
|
27720
|
+
* to the number of its withdrawal.
|
|
27721
|
+
*/
|
|
27722
|
+
withdrawn = /* @__PURE__ */ new Map();
|
|
27723
|
+
/** Numbers each withdrawal, so a removal that completes late clears only its own. */
|
|
27724
|
+
withdrawals = 0;
|
|
27725
|
+
/** The last storage-provider write queued per skill id ({@link syncProvider}). */
|
|
27726
|
+
providerWrites = /* @__PURE__ */ new Map();
|
|
27557
27727
|
/** Whether a plugin registers skills at runtime ({@link expectDynamicSkills}). */
|
|
27558
27728
|
dynamicSkillsExpected = false;
|
|
27559
27729
|
/** Adopted skills from child registries */
|
|
27560
27730
|
adopted = /* @__PURE__ */ new Map();
|
|
27561
27731
|
/** Children registries */
|
|
27562
27732
|
children = /* @__PURE__ */ new Set();
|
|
27733
|
+
/** The registries that adopted this one: a skill registered here is served through them too. */
|
|
27734
|
+
adopters = /* @__PURE__ */ new Set();
|
|
27563
27735
|
/** O(1) indexes */
|
|
27564
27736
|
byQualifiedId = /* @__PURE__ */ new Map();
|
|
27565
27737
|
/** Owner lineage per skill instance, rebuilt with the index so `lineageOf` is O(1). */
|
|
@@ -27644,8 +27816,10 @@ var init_skill_registry = __esm({
|
|
|
27644
27816
|
const row = this.makeRow(token, instance, lineage, this);
|
|
27645
27817
|
this.localRows.push(row);
|
|
27646
27818
|
try {
|
|
27647
|
-
|
|
27648
|
-
|
|
27819
|
+
await this.syncProvider(instance.metadata.id ?? instance.metadata.name, async () => {
|
|
27820
|
+
const content = await instance.load();
|
|
27821
|
+
await this.storageProvider.add(content);
|
|
27822
|
+
});
|
|
27649
27823
|
} catch (error) {
|
|
27650
27824
|
this.scope.logger.warn(`Failed to load skill ${instance.name}: ${error.message}`);
|
|
27651
27825
|
}
|
|
@@ -27668,6 +27842,10 @@ var init_skill_registry = __esm({
|
|
|
27668
27842
|
await this.adoptFromChild(child, child.owner);
|
|
27669
27843
|
}
|
|
27670
27844
|
}
|
|
27845
|
+
const collision = findIdPathCollision(this.listAllInstances());
|
|
27846
|
+
if (collision) {
|
|
27847
|
+
throw new InvalidSkillError(collision.idOwner.metadata.name, describeIdPathCollision(collision));
|
|
27848
|
+
}
|
|
27671
27849
|
this.reindex();
|
|
27672
27850
|
logAvailabilityFiltering(
|
|
27673
27851
|
"SkillRegistry",
|
|
@@ -27687,24 +27865,31 @@ var init_skill_registry = __esm({
|
|
|
27687
27865
|
const adoptedRows = childRows.map((r) => this.relineage(r, prepend));
|
|
27688
27866
|
this.adopted.set(child, adoptedRows);
|
|
27689
27867
|
this.children.add(child);
|
|
27868
|
+
child.adopters.add(this);
|
|
27690
27869
|
child.subscribe({ immediate: false }, () => {
|
|
27870
|
+
const previous = this.adopted.get(child) ?? [];
|
|
27691
27871
|
const latest = child.listAllIndexed().map((r) => this.relineage(r, prepend));
|
|
27692
27872
|
this.adopted.set(child, latest);
|
|
27693
27873
|
this.reindex();
|
|
27694
|
-
this.
|
|
27874
|
+
this.withdrawGoneAdoptedSkills(previous);
|
|
27695
27875
|
for (const row of latest) {
|
|
27696
|
-
row.instance.
|
|
27697
|
-
|
|
27876
|
+
const skillId = row.instance.metadata.id ?? row.instance.metadata.name;
|
|
27877
|
+
this.syncProvider(skillId, async () => {
|
|
27878
|
+
const content = await row.instance.load();
|
|
27879
|
+
await this.storageProvider.add(content);
|
|
27698
27880
|
}).catch((error) => {
|
|
27699
27881
|
this.scope.logger.warn(`Failed to reload adopted skill ${row.baseName}: ${error.message}`);
|
|
27700
27882
|
});
|
|
27701
27883
|
}
|
|
27884
|
+
this.bump("reset");
|
|
27702
27885
|
});
|
|
27703
27886
|
await Promise.all(
|
|
27704
27887
|
adoptedRows.map(async (row) => {
|
|
27705
27888
|
try {
|
|
27706
|
-
|
|
27707
|
-
|
|
27889
|
+
await this.syncProvider(row.instance.metadata.id ?? row.instance.metadata.name, async () => {
|
|
27890
|
+
const content = await row.instance.load();
|
|
27891
|
+
await this.storageProvider.add(content);
|
|
27892
|
+
});
|
|
27708
27893
|
} catch (error) {
|
|
27709
27894
|
this.scope.logger.warn(`Failed to load adopted skill ${row.baseName}: ${error.message}`);
|
|
27710
27895
|
}
|
|
@@ -27713,6 +27898,37 @@ var init_skill_registry = __esm({
|
|
|
27713
27898
|
this.reindex();
|
|
27714
27899
|
this.bump("reset");
|
|
27715
27900
|
}
|
|
27901
|
+
/**
|
|
27902
|
+
* The `skill://` namespaces this registry's skills are served in: its own, and that of every
|
|
27903
|
+
* registry that adopts it, directly or through another, sibling registries included.
|
|
27904
|
+
*/
|
|
27905
|
+
namespacesServingThis() {
|
|
27906
|
+
const registries = /* @__PURE__ */ new Set();
|
|
27907
|
+
const climb = (registry) => {
|
|
27908
|
+
if (registries.has(registry)) return;
|
|
27909
|
+
registries.add(registry);
|
|
27910
|
+
for (const adopter of registry.adopters) climb(adopter);
|
|
27911
|
+
};
|
|
27912
|
+
climb(this);
|
|
27913
|
+
return [...registries].map((registry) => registry.liveSkills());
|
|
27914
|
+
}
|
|
27915
|
+
/**
|
|
27916
|
+
* This registry's skills and those of every registry it adopted, read from each registry's own rows.
|
|
27917
|
+
* An adopter's copy of a child's rows is refreshed only on the child's change event, which a
|
|
27918
|
+
* registration emits after it has committed its row and awaited the storage provider.
|
|
27919
|
+
*/
|
|
27920
|
+
liveSkills() {
|
|
27921
|
+
const registries = /* @__PURE__ */ new Set();
|
|
27922
|
+
const skills = /* @__PURE__ */ new Set();
|
|
27923
|
+
const descend = (registry) => {
|
|
27924
|
+
if (registries.has(registry)) return;
|
|
27925
|
+
registries.add(registry);
|
|
27926
|
+
for (const row of [...registry.localRows, ...registry.dynamicRows]) skills.add(row.instance);
|
|
27927
|
+
for (const child of registry.children) descend(child);
|
|
27928
|
+
};
|
|
27929
|
+
descend(this);
|
|
27930
|
+
return [...skills];
|
|
27931
|
+
}
|
|
27716
27932
|
/* -------------------- Public API -------------------- */
|
|
27717
27933
|
/**
|
|
27718
27934
|
* Get all skills in the registry.
|
|
@@ -27830,7 +28046,14 @@ var init_skill_registry = __esm({
|
|
|
27830
28046
|
}
|
|
27831
28047
|
}
|
|
27832
28048
|
async search(query, options) {
|
|
27833
|
-
const
|
|
28049
|
+
const topK = options?.topK;
|
|
28050
|
+
const hidden = this.hiddenFromProviderRead();
|
|
28051
|
+
const providerOptions = hidden.size > 0 && typeof topK === "number" && topK >= 0 ? { ...options, topK: topK + hidden.size } : options;
|
|
28052
|
+
let baseResults = await this.storageProvider.search(query, providerOptions);
|
|
28053
|
+
if (hidden.size > 0 || this.withdrawn.size > 0) {
|
|
28054
|
+
baseResults = baseResults.filter((r) => !hidden.has(r.metadata));
|
|
28055
|
+
if (typeof topK === "number" && topK >= 0) baseResults = baseResults.slice(0, topK);
|
|
28056
|
+
}
|
|
27834
28057
|
if (this.dynamicContents.size === 0) return baseResults;
|
|
27835
28058
|
const baseSeen = /* @__PURE__ */ new Set();
|
|
27836
28059
|
let rewrites = 0;
|
|
@@ -27854,7 +28077,6 @@ var init_skill_registry = __esm({
|
|
|
27854
28077
|
const overlayOnly = this.searchDynamicOverlay(query, options, baseSeen);
|
|
27855
28078
|
if (overlayOnly.length === 0 && rewrites === 0) return baseResults;
|
|
27856
28079
|
const merged = [...rewrittenBase, ...overlayOnly].sort((a, b) => b.score - a.score);
|
|
27857
|
-
const topK = options?.topK;
|
|
27858
28080
|
return typeof topK === "number" && topK >= 0 ? merged.slice(0, topK) : merged;
|
|
27859
28081
|
}
|
|
27860
28082
|
/**
|
|
@@ -27909,7 +28131,10 @@ var init_skill_registry = __esm({
|
|
|
27909
28131
|
warning
|
|
27910
28132
|
};
|
|
27911
28133
|
}
|
|
28134
|
+
const hidden = this.hiddenFromProviderRead();
|
|
28135
|
+
if (hidden.has({ name: skillId })) return void 0;
|
|
27912
28136
|
const result = await this.storageProvider.load(skillId);
|
|
28137
|
+
if (result && hidden.has(result.skill)) return void 0;
|
|
27913
28138
|
return result ?? void 0;
|
|
27914
28139
|
}
|
|
27915
28140
|
/**
|
|
@@ -27945,8 +28170,12 @@ var init_skill_registry = __esm({
|
|
|
27945
28170
|
* and `hasMore` stay correct.
|
|
27946
28171
|
*/
|
|
27947
28172
|
async listSkills(options) {
|
|
27948
|
-
|
|
27949
|
-
|
|
28173
|
+
const hidden = this.hiddenFromProviderRead();
|
|
28174
|
+
if (this.dynamicContents.size === 0 && hidden.size === 0) {
|
|
28175
|
+
const page = await this.storageProvider.list(options);
|
|
28176
|
+
if (this.withdrawn.size === 0) return page;
|
|
28177
|
+
}
|
|
28178
|
+
const base = (await this.listAllFromProvider(options)).filter((meta) => !hidden.has(meta));
|
|
27950
28179
|
const baseIds = /* @__PURE__ */ new Set();
|
|
27951
28180
|
const merged = base.map((meta) => {
|
|
27952
28181
|
const id = meta.id ?? meta.name;
|
|
@@ -28006,21 +28235,20 @@ var init_skill_registry = __esm({
|
|
|
28006
28235
|
/**
|
|
28007
28236
|
* Get total skill count.
|
|
28008
28237
|
*
|
|
28009
|
-
*
|
|
28238
|
+
* Counts the provider's rows with overlay rows the provider does not know
|
|
28010
28239
|
* about so callers see the same surface as `search` / `listSkills`.
|
|
28011
28240
|
*/
|
|
28012
28241
|
async count(options) {
|
|
28013
|
-
const
|
|
28014
|
-
if (this.dynamicContents.size === 0)
|
|
28015
|
-
|
|
28016
|
-
|
|
28017
|
-
|
|
28018
|
-
|
|
28019
|
-
});
|
|
28242
|
+
const hidden = this.hiddenFromProviderRead();
|
|
28243
|
+
if (this.dynamicContents.size === 0 && hidden.size === 0) {
|
|
28244
|
+
const counted = await this.storageProvider.count(options);
|
|
28245
|
+
if (this.withdrawn.size === 0) return counted;
|
|
28246
|
+
}
|
|
28247
|
+
const baseList = (await this.listAllFromProvider({ tags: options?.tags, includeHidden: options?.includeHidden })).filter((m) => !hidden.has(m));
|
|
28020
28248
|
const baseIds = /* @__PURE__ */ new Set();
|
|
28021
|
-
for (const m of baseList
|
|
28249
|
+
for (const m of baseList) baseIds.add(m.id ?? m.name);
|
|
28022
28250
|
const overlay = this.collectDynamicMetadata(options).filter((m) => !baseIds.has(m.id ?? m.name));
|
|
28023
|
-
return
|
|
28251
|
+
return baseList.length + overlay.length;
|
|
28024
28252
|
}
|
|
28025
28253
|
/**
|
|
28026
28254
|
* Project a SkillContent into the SkillMetadata shape callers expect from
|
|
@@ -28310,10 +28538,6 @@ var init_skill_registry = __esm({
|
|
|
28310
28538
|
throw new PublicMcpError("registerSkillContent: SkillContent.name is required", "INVALID_PARAMS");
|
|
28311
28539
|
}
|
|
28312
28540
|
const id = content.id;
|
|
28313
|
-
const existingIdx = this.dynamicRows.findIndex((r) => r.instance.name === id);
|
|
28314
|
-
if (existingIdx !== -1) {
|
|
28315
|
-
this.dynamicRows.splice(existingIdx, 1);
|
|
28316
|
-
}
|
|
28317
28541
|
const metadata = {
|
|
28318
28542
|
id,
|
|
28319
28543
|
name: content.name,
|
|
@@ -28349,28 +28573,49 @@ var init_skill_registry = __esm({
|
|
|
28349
28573
|
`[SkillRegistry] Failed to pre-load dynamic skill ${id} from source ${opts?.source ?? "unknown"}: ${error.message}`
|
|
28350
28574
|
);
|
|
28351
28575
|
}
|
|
28576
|
+
const existingIdx = this.dynamicRows.findIndex((r) => r.instance.name === id);
|
|
28577
|
+
const superseded = new Set(opts?.supersedes);
|
|
28578
|
+
const leaving = new Set(
|
|
28579
|
+
this.dynamicRows.filter((r) => r.instance.name === id || superseded.has(r.instance.name)).map((r) => r.instance)
|
|
28580
|
+
);
|
|
28581
|
+
for (const skills of this.namespacesServingThis()) {
|
|
28582
|
+
const collision = findIdPathCollision([...skills.filter((other) => !leaving.has(other)), instance]);
|
|
28583
|
+
if (collision) {
|
|
28584
|
+
throw new PublicMcpError(`registerSkillContent: ${describeIdPathCollision(collision)}`, "INVALID_PARAMS");
|
|
28585
|
+
}
|
|
28586
|
+
}
|
|
28587
|
+
if (existingIdx !== -1) {
|
|
28588
|
+
this.dynamicRows.splice(existingIdx, 1);
|
|
28589
|
+
}
|
|
28590
|
+
const mutable = this.asMutableProvider(this.storageProvider);
|
|
28591
|
+
const removed = this.dynamicRows.filter((r) => superseded.has(r.instance.name) && findIdPathCollision([r.instance, instance])).map((r) => r.instance.name);
|
|
28592
|
+
for (const removedId of removed) {
|
|
28593
|
+
this.withdrawDynamicSkill(removedId, mutable);
|
|
28594
|
+
}
|
|
28352
28595
|
const lineage = this.owner ? [this.owner] : [];
|
|
28353
28596
|
const row = this.makeRow(provideToken, instance, lineage, this);
|
|
28354
28597
|
this.dynamicRows.push(row);
|
|
28355
28598
|
this.dynamicContents.set(id, structuredClone(content));
|
|
28599
|
+
this.withdrawn.delete(id);
|
|
28356
28600
|
const generation = (this.dynamicGenerations.get(id) ?? 0) + 1;
|
|
28357
28601
|
this.dynamicGenerations.set(id, generation);
|
|
28358
|
-
|
|
28359
|
-
|
|
28360
|
-
|
|
28602
|
+
this.reindex();
|
|
28603
|
+
const providerWrites = mutable ? [
|
|
28604
|
+
...removed.map((removedId) => this.removeFromProvider(mutable, removedId)),
|
|
28605
|
+
this.syncProvider(id, async () => {
|
|
28361
28606
|
if (await mutable.exists(id)) {
|
|
28362
28607
|
await mutable.update(id, content);
|
|
28363
28608
|
} else {
|
|
28364
28609
|
await mutable.add(content);
|
|
28365
28610
|
}
|
|
28366
|
-
}
|
|
28611
|
+
}).catch((error) => {
|
|
28367
28612
|
this.scope.logger.warn(
|
|
28368
28613
|
`[SkillRegistry] Failed to index dynamic skill ${id} in storage provider: ${error.message}`
|
|
28369
28614
|
);
|
|
28370
|
-
}
|
|
28371
|
-
|
|
28372
|
-
this.reindex();
|
|
28615
|
+
})
|
|
28616
|
+
] : [];
|
|
28373
28617
|
this.bump("reset");
|
|
28618
|
+
await Promise.all(providerWrites);
|
|
28374
28619
|
let unregistered = false;
|
|
28375
28620
|
const unregister = async () => {
|
|
28376
28621
|
if (unregistered) return;
|
|
@@ -28383,32 +28628,99 @@ var init_skill_registry = __esm({
|
|
|
28383
28628
|
this.scope.logger.debug(
|
|
28384
28629
|
`[SkillRegistry] Registered dynamic skill ${id}${opts?.source ? ` (source: ${opts.source})` : ""}`
|
|
28385
28630
|
);
|
|
28386
|
-
return { id, unregister };
|
|
28631
|
+
return { id, unregister, removed };
|
|
28387
28632
|
}
|
|
28388
28633
|
/**
|
|
28389
28634
|
* Remove a previously-registered dynamic skill by id.
|
|
28390
28635
|
*/
|
|
28391
28636
|
async unregisterSkill(id) {
|
|
28392
|
-
|
|
28393
|
-
if (idx === -1) return false;
|
|
28394
|
-
this.dynamicRows.splice(idx, 1);
|
|
28395
|
-
this.dynamicContents.delete(id);
|
|
28396
|
-
this.dynamicGenerations.delete(id);
|
|
28637
|
+
if (!this.dynamicRows.some((r) => r.instance.name === id)) return false;
|
|
28397
28638
|
const mutable = this.asMutableProvider(this.storageProvider);
|
|
28398
|
-
|
|
28399
|
-
try {
|
|
28400
|
-
await mutable.remove(id);
|
|
28401
|
-
} catch (error) {
|
|
28402
|
-
this.scope.logger.warn(
|
|
28403
|
-
`[SkillRegistry] Failed to remove dynamic skill ${id} from storage provider: ${error.message}`
|
|
28404
|
-
);
|
|
28405
|
-
}
|
|
28406
|
-
}
|
|
28639
|
+
this.withdrawDynamicSkill(id, mutable);
|
|
28407
28640
|
this.reindex();
|
|
28641
|
+
const removal = mutable ? this.removeFromProvider(mutable, id) : void 0;
|
|
28408
28642
|
this.bump("reset");
|
|
28643
|
+
await removal;
|
|
28409
28644
|
this.scope.logger.debug(`[SkillRegistry] Unregistered dynamic skill ${id}`);
|
|
28410
28645
|
return true;
|
|
28411
28646
|
}
|
|
28647
|
+
/**
|
|
28648
|
+
* Take a dynamic skill out of the registry, synchronously. Its generation advances so a handle
|
|
28649
|
+
* from an earlier registration stays a no-op, and while a mutable provider still holds its copy it
|
|
28650
|
+
* is withdrawn from provider-backed reads.
|
|
28651
|
+
*/
|
|
28652
|
+
withdrawDynamicSkill(id, mutable) {
|
|
28653
|
+
this.dynamicRows.splice(
|
|
28654
|
+
this.dynamicRows.findIndex((r) => r.instance.name === id),
|
|
28655
|
+
1
|
|
28656
|
+
);
|
|
28657
|
+
this.dynamicContents.delete(id);
|
|
28658
|
+
this.dynamicGenerations.set(id, (this.dynamicGenerations.get(id) ?? 0) + 1);
|
|
28659
|
+
if (mutable) this.withdrawn.set(id, ++this.withdrawals);
|
|
28660
|
+
}
|
|
28661
|
+
/** Remove a withdrawn skill's copy from the provider. If that fails it stays withdrawn from reads. */
|
|
28662
|
+
async removeFromProvider(mutable, id) {
|
|
28663
|
+
const withdrawal = this.withdrawn.get(id);
|
|
28664
|
+
try {
|
|
28665
|
+
await this.syncProvider(id, () => mutable.remove(id));
|
|
28666
|
+
if (this.withdrawn.get(id) === withdrawal) this.withdrawn.delete(id);
|
|
28667
|
+
} catch (error) {
|
|
28668
|
+
this.scope.logger.warn(
|
|
28669
|
+
`[SkillRegistry] Failed to remove skill ${id} from storage provider; it stays hidden from provider-backed reads: ${error.message}`
|
|
28670
|
+
);
|
|
28671
|
+
}
|
|
28672
|
+
}
|
|
28673
|
+
/**
|
|
28674
|
+
* Run a storage-provider write for one skill id after the ones queued before it for that id, so a
|
|
28675
|
+
* removal that completes late cannot delete the copy a later registration added. The returned
|
|
28676
|
+
* promise settles with the write; a failure does not hold back the next one.
|
|
28677
|
+
*/
|
|
28678
|
+
syncProvider(id, write) {
|
|
28679
|
+
const run = (this.providerWrites.get(id) ?? Promise.resolve()).then(write);
|
|
28680
|
+
const settled = run.then(
|
|
28681
|
+
() => void 0,
|
|
28682
|
+
() => void 0
|
|
28683
|
+
);
|
|
28684
|
+
this.providerWrites.set(id, settled);
|
|
28685
|
+
void settled.then(() => {
|
|
28686
|
+
if (this.providerWrites.get(id) === settled) this.providerWrites.delete(id);
|
|
28687
|
+
});
|
|
28688
|
+
return run;
|
|
28689
|
+
}
|
|
28690
|
+
/**
|
|
28691
|
+
* After a child's change, take the skills that left it (and are not served here some other way)
|
|
28692
|
+
* out of this registry's storage provider too. The re-add on change only adds, so without this an
|
|
28693
|
+
* adopter's provider kept serving a skill the child had removed. Until the removal completes, and
|
|
28694
|
+
* if it fails, provider-backed reads skip it.
|
|
28695
|
+
*/
|
|
28696
|
+
withdrawGoneAdoptedSkills(previous) {
|
|
28697
|
+
const mutable = this.asMutableProvider(this.storageProvider);
|
|
28698
|
+
if (!mutable) return;
|
|
28699
|
+
const skillIdOf = (entry) => entry.metadata.id ?? entry.metadata.name;
|
|
28700
|
+
const live = new Set(this.listAllIndexed().map((r) => skillIdOf(r.instance)));
|
|
28701
|
+
for (const id of live) this.withdrawn.delete(id);
|
|
28702
|
+
for (const row of previous) {
|
|
28703
|
+
const id = skillIdOf(row.instance);
|
|
28704
|
+
if (live.has(id) || this.withdrawn.has(id)) continue;
|
|
28705
|
+
this.withdrawn.set(id, ++this.withdrawals);
|
|
28706
|
+
void this.removeFromProvider(mutable, id);
|
|
28707
|
+
}
|
|
28708
|
+
}
|
|
28709
|
+
/**
|
|
28710
|
+
* Which provider-backed rows a read that starts now must skip: a skill withdrawn when the read
|
|
28711
|
+
* starts (its removal may complete while the provider answers, clearing the withdrawal, yet the
|
|
28712
|
+
* answer can still hold it), or withdrawn by the time the answer arrives.
|
|
28713
|
+
*/
|
|
28714
|
+
hiddenFromProviderRead() {
|
|
28715
|
+
const atStart = new Set(this.withdrawn.keys());
|
|
28716
|
+
return {
|
|
28717
|
+
size: atStart.size,
|
|
28718
|
+
has: (meta) => {
|
|
28719
|
+
const id = meta.id ?? meta.name;
|
|
28720
|
+
return atStart.has(id) || this.withdrawn.has(id);
|
|
28721
|
+
}
|
|
28722
|
+
};
|
|
28723
|
+
}
|
|
28412
28724
|
/* -------------------- Internal helpers -------------------- */
|
|
28413
28725
|
asMutableProvider(provider) {
|
|
28414
28726
|
const candidate = provider;
|
|
@@ -28670,7 +28982,7 @@ var init_plugin_utils = __esm({
|
|
|
28670
28982
|
});
|
|
28671
28983
|
|
|
28672
28984
|
// libs/sdk/src/plugin/plugin.registry.ts
|
|
28673
|
-
var import_reflect_metadata12, import_di24, PluginRegistry;
|
|
28985
|
+
var import_reflect_metadata12, import_di24, installedPluginValues, PluginRegistry;
|
|
28674
28986
|
var init_plugin_registry = __esm({
|
|
28675
28987
|
"libs/sdk/src/plugin/plugin.registry.ts"() {
|
|
28676
28988
|
"use strict";
|
|
@@ -28678,6 +28990,7 @@ var init_plugin_registry = __esm({
|
|
|
28678
28990
|
import_di24 = require("@frontmcp/di");
|
|
28679
28991
|
init_adapter_registry();
|
|
28680
28992
|
init_common();
|
|
28993
|
+
init_dynamic_plugin();
|
|
28681
28994
|
init_dynamic_utils();
|
|
28682
28995
|
init_context_extension();
|
|
28683
28996
|
init_errors();
|
|
@@ -28690,6 +29003,7 @@ var init_plugin_registry = __esm({
|
|
|
28690
29003
|
init_skill_registry();
|
|
28691
29004
|
init_tool_registry();
|
|
28692
29005
|
init_plugin_utils();
|
|
29006
|
+
installedPluginValues = /* @__PURE__ */ new WeakSet();
|
|
28693
29007
|
PluginRegistry = class _PluginRegistry extends RegistryAbstract {
|
|
28694
29008
|
/** providers by token */
|
|
28695
29009
|
pProviders = /* @__PURE__ */ new Map();
|
|
@@ -28878,8 +29192,15 @@ var init_plugin_registry = __esm({
|
|
|
28878
29192
|
pluginInstance: new rec.provide(...depsInstances),
|
|
28879
29193
|
dynamicProviders: rec.providers
|
|
28880
29194
|
};
|
|
28881
|
-
case "VALUE" /* VALUE */:
|
|
28882
|
-
|
|
29195
|
+
case "VALUE" /* VALUE */: {
|
|
29196
|
+
const value = rec.useValue;
|
|
29197
|
+
const init = installedPluginValues.has(value) ? initOptionsOf(value) : void 0;
|
|
29198
|
+
installedPluginValues.add(value);
|
|
29199
|
+
if (init && isDynamicPluginClass(rec.provide)) {
|
|
29200
|
+
return { pluginInstance: new rec.provide(init.options), dynamicProviders: rec.providers };
|
|
29201
|
+
}
|
|
29202
|
+
return { pluginInstance: value, dynamicProviders: rec.providers };
|
|
29203
|
+
}
|
|
28883
29204
|
case "FACTORY" /* FACTORY */: {
|
|
28884
29205
|
const args = [];
|
|
28885
29206
|
for (const d of rec.inject()) args.push(await this.providers.resolveBootstrapDep(d));
|
|
@@ -29393,7 +29714,7 @@ var init_agent_instance = __esm({
|
|
|
29393
29714
|
"hideFromDiscovery"
|
|
29394
29715
|
]);
|
|
29395
29716
|
AgentInstance = class extends AgentEntry {
|
|
29396
|
-
|
|
29717
|
+
providerRegistry;
|
|
29397
29718
|
scope;
|
|
29398
29719
|
hooks;
|
|
29399
29720
|
/** The LLM adapter for this agent */
|
|
@@ -29411,11 +29732,11 @@ var init_agent_instance = __esm({
|
|
|
29411
29732
|
constructor(record, providers, owner) {
|
|
29412
29733
|
super(record);
|
|
29413
29734
|
this.owner = owner;
|
|
29414
|
-
this.
|
|
29735
|
+
this.providerRegistry = providers;
|
|
29415
29736
|
this.name = record.metadata.id ?? record.metadata.name;
|
|
29416
29737
|
this.id = record.metadata.id ?? record.metadata.name;
|
|
29417
29738
|
this.fullName = this.owner.id + ":" + this.name;
|
|
29418
|
-
this.scope = this.
|
|
29739
|
+
this.scope = this.providerRegistry.getActiveScope();
|
|
29419
29740
|
this.hooks = this.scope.hooks;
|
|
29420
29741
|
this.inputSchema = record.metadata.inputSchema ?? {};
|
|
29421
29742
|
this.outputSchema = record.metadata.outputSchema;
|
|
@@ -29474,11 +29795,11 @@ var init_agent_instance = __esm({
|
|
|
29474
29795
|
const adapterOptions = {
|
|
29475
29796
|
providerResolver: {
|
|
29476
29797
|
get: (token) => {
|
|
29477
|
-
return this.
|
|
29798
|
+
return this.providerRegistry.get(token);
|
|
29478
29799
|
},
|
|
29479
29800
|
tryGet: (token) => {
|
|
29480
29801
|
try {
|
|
29481
|
-
return this.
|
|
29802
|
+
return this.providerRegistry.get(token);
|
|
29482
29803
|
} catch {
|
|
29483
29804
|
return void 0;
|
|
29484
29805
|
}
|
|
@@ -29491,7 +29812,7 @@ var init_agent_instance = __esm({
|
|
|
29491
29812
|
}
|
|
29492
29813
|
};
|
|
29493
29814
|
try {
|
|
29494
|
-
const configService = this.
|
|
29815
|
+
const configService = this.providerRegistry.get(ConfigService);
|
|
29495
29816
|
if (configService) {
|
|
29496
29817
|
adapterOptions.configResolver = this.createConfigResolver(configService);
|
|
29497
29818
|
}
|
|
@@ -29599,7 +29920,7 @@ var init_agent_instance = __esm({
|
|
|
29599
29920
|
const toolMetadata = this.buildAgentToolMetadata();
|
|
29600
29921
|
const agentToolFunction = frontMcpTool(toolMetadata)(this.createAgentToolExecuteHandler());
|
|
29601
29922
|
const toolRecord = normalizeTool(agentToolFunction);
|
|
29602
|
-
this.agentToolInstance = new ToolInstance(toolRecord, this.
|
|
29923
|
+
this.agentToolInstance = new ToolInstance(toolRecord, this.providerRegistry, this.owner);
|
|
29603
29924
|
await this.agentToolInstance.ready;
|
|
29604
29925
|
this.scope.logger.debug(`Created agent tool instance: ${this.agentToolInstance.name} for agent ${this.name}`);
|
|
29605
29926
|
} catch (error) {
|
|
@@ -29641,16 +29962,34 @@ var init_agent_instance = __esm({
|
|
|
29641
29962
|
/**
|
|
29642
29963
|
* Create the execute handler for the agent tool.
|
|
29643
29964
|
*
|
|
29644
|
-
*
|
|
29645
|
-
*
|
|
29965
|
+
* The tool's `tools:call-tool` flow has already applied everything the agent declares
|
|
29966
|
+
* (authorities, rate limit, concurrency, timeout and plugin gates, copied onto the tool). The
|
|
29967
|
+
* handler then runs the agent through the `agents:call-agent` flow, so the hooks registered for
|
|
29968
|
+
* agent invocation (`AgentCallHook`, and the agent class's own hooks on that flow) run and the
|
|
29969
|
+
* agent's context gets the request's context providers. The flow's own gates are left to the
|
|
29970
|
+
* tool flow (`gatedBy`), so nothing is counted twice.
|
|
29646
29971
|
*/
|
|
29647
29972
|
createAgentToolExecuteHandler() {
|
|
29648
29973
|
return async (input, toolCtx) => {
|
|
29649
29974
|
const authInfo = toolCtx.authInfo;
|
|
29650
|
-
const
|
|
29651
|
-
const
|
|
29652
|
-
|
|
29653
|
-
|
|
29975
|
+
const progressToken = toolCtx._progressTokenInternal;
|
|
29976
|
+
const requestId = toolCtx._jsonRpcRequestIdInternal;
|
|
29977
|
+
return this.scope.runFlowForOutput("agents:call-agent", {
|
|
29978
|
+
request: {
|
|
29979
|
+
method: "tools/call",
|
|
29980
|
+
params: {
|
|
29981
|
+
name: this.id,
|
|
29982
|
+
arguments: input,
|
|
29983
|
+
...progressToken !== void 0 ? { _meta: { progressToken } } : {}
|
|
29984
|
+
}
|
|
29985
|
+
},
|
|
29986
|
+
ctx: {
|
|
29987
|
+
authInfo,
|
|
29988
|
+
...requestId !== void 0 ? { requestId } : {},
|
|
29989
|
+
...toolCtx.signal ? { signal: toolCtx.signal } : {}
|
|
29990
|
+
},
|
|
29991
|
+
gatedBy: "tools:call-tool"
|
|
29992
|
+
});
|
|
29654
29993
|
};
|
|
29655
29994
|
}
|
|
29656
29995
|
/**
|
|
@@ -29664,6 +30003,10 @@ var init_agent_instance = __esm({
|
|
|
29664
30003
|
getToolInstance() {
|
|
29665
30004
|
return this.agentToolInstance;
|
|
29666
30005
|
}
|
|
30006
|
+
/** The provider registry this agent was registered with (its app's). */
|
|
30007
|
+
get providers() {
|
|
30008
|
+
return this.providerRegistry;
|
|
30009
|
+
}
|
|
29667
30010
|
/**
|
|
29668
30011
|
* The tools this agent can call: those it declares and those its plugins contribute, as its private
|
|
29669
30012
|
* scope holds them. Empty until the agent is initialized.
|
|
@@ -29713,7 +30056,7 @@ var init_agent_instance = __esm({
|
|
|
29713
30056
|
case "VALUE" /* VALUE */:
|
|
29714
30057
|
return this.record.useValue;
|
|
29715
30058
|
case "FACTORY" /* FACTORY */:
|
|
29716
|
-
return this.record.useFactory(this.
|
|
30059
|
+
return this.record.useFactory(this.providerRegistry);
|
|
29717
30060
|
case "ESM" /* ESM */:
|
|
29718
30061
|
throw new AgentNotConfiguredError(`ESM agent "${this.name}" cannot be created via AgentInstance.create()`);
|
|
29719
30062
|
case "REMOTE" /* REMOTE */:
|
|
@@ -29732,11 +30075,13 @@ var init_agent_instance = __esm({
|
|
|
29732
30075
|
* @param llmAdapter - The LLM adapter (passed explicitly to avoid non-null assertion)
|
|
29733
30076
|
*/
|
|
29734
30077
|
buildAgentCtorArgs(input, ctx, llmAdapter) {
|
|
29735
|
-
const scope = this.
|
|
30078
|
+
const scope = this.providerRegistry.getActiveScope();
|
|
29736
30079
|
return {
|
|
29737
30080
|
metadata: this.metadata,
|
|
29738
30081
|
input,
|
|
29739
|
-
providers:
|
|
30082
|
+
// The request's context-aware providers when the agents:call-agent flow built them, so
|
|
30083
|
+
// `this.context` and CONTEXT-scoped providers resolve inside the agent.
|
|
30084
|
+
providers: ctx.contextProviders ?? this.providerRegistry,
|
|
29740
30085
|
logger: scope.logger,
|
|
29741
30086
|
authInfo: ctx.authInfo,
|
|
29742
30087
|
llmAdapter,
|
|
@@ -29807,7 +30152,8 @@ var init_agent_instance = __esm({
|
|
|
29807
30152
|
await this.assertToolAuthorized(tool, ctx.authInfo, args);
|
|
29808
30153
|
const runningTool = { name: tool.name, fullName: tool.fullName };
|
|
29809
30154
|
return runOnSurface(AGENT_SURFACE, () => {
|
|
29810
|
-
const
|
|
30155
|
+
const { contextProviders: _agentProviders, ...toolCtx } = ctx;
|
|
30156
|
+
const toolContext = runAsTool(runningTool, () => tool.create(args, toolCtx));
|
|
29811
30157
|
return runAsTool(runningTool, () => Promise.resolve(toolContext.execute(args)));
|
|
29812
30158
|
});
|
|
29813
30159
|
};
|
|
@@ -30346,6 +30692,53 @@ var init_agent_registry = __esm({
|
|
|
30346
30692
|
}
|
|
30347
30693
|
});
|
|
30348
30694
|
|
|
30695
|
+
// libs/sdk/src/channel/sources/completion-events.ts
|
|
30696
|
+
function completionEventsOf(scope) {
|
|
30697
|
+
let events = byScope.get(scope);
|
|
30698
|
+
if (!events) {
|
|
30699
|
+
events = new ScopeCompletionEvents();
|
|
30700
|
+
byScope.set(scope, events);
|
|
30701
|
+
}
|
|
30702
|
+
return events;
|
|
30703
|
+
}
|
|
30704
|
+
function completionOutputText(value) {
|
|
30705
|
+
if (value === void 0) return void 0;
|
|
30706
|
+
if (typeof value === "string") return value;
|
|
30707
|
+
try {
|
|
30708
|
+
return JSON.stringify(value);
|
|
30709
|
+
} catch {
|
|
30710
|
+
return String(value);
|
|
30711
|
+
}
|
|
30712
|
+
}
|
|
30713
|
+
var CompletionStream, ScopeCompletionEvents, byScope;
|
|
30714
|
+
var init_completion_events = __esm({
|
|
30715
|
+
"libs/sdk/src/channel/sources/completion-events.ts"() {
|
|
30716
|
+
"use strict";
|
|
30717
|
+
CompletionStream = class {
|
|
30718
|
+
listeners = /* @__PURE__ */ new Set();
|
|
30719
|
+
subscribe(listener) {
|
|
30720
|
+
this.listeners.add(listener);
|
|
30721
|
+
return () => {
|
|
30722
|
+
this.listeners.delete(listener);
|
|
30723
|
+
};
|
|
30724
|
+
}
|
|
30725
|
+
emit(event) {
|
|
30726
|
+
for (const listener of [...this.listeners]) {
|
|
30727
|
+
try {
|
|
30728
|
+
listener(event);
|
|
30729
|
+
} catch {
|
|
30730
|
+
}
|
|
30731
|
+
}
|
|
30732
|
+
}
|
|
30733
|
+
};
|
|
30734
|
+
ScopeCompletionEvents = class {
|
|
30735
|
+
agents = new CompletionStream();
|
|
30736
|
+
jobs = new CompletionStream();
|
|
30737
|
+
};
|
|
30738
|
+
byScope = /* @__PURE__ */ new WeakMap();
|
|
30739
|
+
}
|
|
30740
|
+
});
|
|
30741
|
+
|
|
30349
30742
|
// libs/sdk/src/agent/flows/call-agent.flow.ts
|
|
30350
30743
|
var import_auth26, import_guard6, import_lazy_zod60, import_protocol41, inputSchema15, outputSchema14, stateSchema14, plan14, name14, Stage14, CallAgentFlow;
|
|
30351
30744
|
var init_call_agent_flow = __esm({
|
|
@@ -30355,13 +30748,22 @@ var init_call_agent_flow = __esm({
|
|
|
30355
30748
|
import_guard6 = require("@frontmcp/guard");
|
|
30356
30749
|
import_lazy_zod60 = require("@frontmcp/lazy-zod");
|
|
30357
30750
|
import_protocol41 = require("@frontmcp/protocol");
|
|
30751
|
+
init_completion_events();
|
|
30358
30752
|
init_common();
|
|
30359
30753
|
init_errors();
|
|
30360
30754
|
init_hooks_utils();
|
|
30755
|
+
init_flow_context_providers();
|
|
30361
30756
|
inputSchema15 = import_lazy_zod60.z.object({
|
|
30362
30757
|
request: import_protocol41.CallToolRequestSchema,
|
|
30363
30758
|
// z.any() used because ctx is the MCP SDK's ToolCallExtra type which varies by SDK version
|
|
30364
|
-
ctx: import_lazy_zod60.z.any()
|
|
30759
|
+
ctx: import_lazy_zod60.z.any(),
|
|
30760
|
+
/**
|
|
30761
|
+
* Set when the agent's `invoke_<agent>` tool runs this flow. That tool's `tools:call-tool` flow
|
|
30762
|
+
* has already applied the agent's authorities, rate limit, concurrency and timeout (they are
|
|
30763
|
+
* copied onto the tool), so this flow's stages for them leave the checks to it instead of
|
|
30764
|
+
* counting the call twice. Their hooks still run.
|
|
30765
|
+
*/
|
|
30766
|
+
gatedBy: import_lazy_zod60.z.literal("tools:call-tool").optional()
|
|
30365
30767
|
});
|
|
30366
30768
|
outputSchema14 = import_protocol41.CallToolResultSchema;
|
|
30367
30769
|
stateSchema14 = import_lazy_zod60.z.object({
|
|
@@ -30394,7 +30796,13 @@ var init_call_agent_flow = __esm({
|
|
|
30394
30796
|
// Semaphore ticket for concurrency control (set by acquireSemaphore, used by releaseSemaphore)
|
|
30395
30797
|
semaphoreTicket: import_lazy_zod60.z.any().optional(),
|
|
30396
30798
|
// A timed-out execute() that is still running; its concurrency slot is released when it settles
|
|
30397
|
-
abandonedExecution: import_lazy_zod60.z.instanceof(Promise).optional()
|
|
30799
|
+
abandonedExecution: import_lazy_zod60.z.instanceof(Promise).optional(),
|
|
30800
|
+
// When execute() started, and the error it ended with (for the completion event)
|
|
30801
|
+
executionStartedAt: import_lazy_zod60.z.number().optional(),
|
|
30802
|
+
executionError: import_lazy_zod60.z.any().optional(),
|
|
30803
|
+
// The MCP result built from rawOutput (parseOutput), or why it could not be built
|
|
30804
|
+
parsedOutput: import_lazy_zod60.z.any().optional(),
|
|
30805
|
+
outputError: import_lazy_zod60.z.any().optional()
|
|
30398
30806
|
});
|
|
30399
30807
|
plan14 = {
|
|
30400
30808
|
pre: [
|
|
@@ -30407,12 +30815,16 @@ var init_call_agent_flow = __esm({
|
|
|
30407
30815
|
"acquireSemaphore"
|
|
30408
30816
|
],
|
|
30409
30817
|
execute: ["validateInput", "execute", "validateOutput"],
|
|
30410
|
-
finalize: ["releaseSemaphore", "releaseQuota", "finalize"]
|
|
30818
|
+
finalize: ["releaseSemaphore", "releaseQuota", "parseOutput", "emitCompletion", "finalize"]
|
|
30411
30819
|
};
|
|
30412
30820
|
name14 = "agents:call-agent";
|
|
30413
30821
|
({ Stage: Stage14 } = FlowHooksOf(name14));
|
|
30414
30822
|
CallAgentFlow = class extends FlowBase {
|
|
30415
30823
|
logger = this.scopeLogger.child("CallAgentFlow");
|
|
30824
|
+
/** Whether the `invoke_<agent>` tool's flow already applied the agent's gates. */
|
|
30825
|
+
get gatedByToolFlow() {
|
|
30826
|
+
return this.input.gatedBy === "tools:call-tool";
|
|
30827
|
+
}
|
|
30416
30828
|
async parseInput() {
|
|
30417
30829
|
this.logger.verbose("parseInput:start");
|
|
30418
30830
|
let method;
|
|
@@ -30479,6 +30891,10 @@ var init_call_agent_flow = __esm({
|
|
|
30479
30891
|
}
|
|
30480
30892
|
async checkEntryAuthorities() {
|
|
30481
30893
|
this.logger.verbose("checkEntryAuthorities:start");
|
|
30894
|
+
if (this.gatedByToolFlow) {
|
|
30895
|
+
this.logger.verbose("checkEntryAuthorities:skip (checked by the invoke tool flow)");
|
|
30896
|
+
return;
|
|
30897
|
+
}
|
|
30482
30898
|
const engine = this.scope.authoritiesEngine;
|
|
30483
30899
|
const ctxBuilder = this.scope.authoritiesContextBuilder;
|
|
30484
30900
|
if (!engine || !ctxBuilder) {
|
|
@@ -30544,14 +30960,17 @@ var init_call_agent_flow = __esm({
|
|
|
30544
30960
|
const progressToken = this.state.progressToken;
|
|
30545
30961
|
const authInfo = this.state.authInfo;
|
|
30546
30962
|
try {
|
|
30547
|
-
const
|
|
30963
|
+
const sessionKey = authInfo?.sessionId ?? "anonymous";
|
|
30964
|
+
const agentViews = await agent.providers.buildViews(sessionKey, new Map(this.deps), this.scope.providers);
|
|
30965
|
+
const contextProviders = new FlowContextProviders(agent.providers, agentViews.context);
|
|
30966
|
+
const context = agent.create(input.arguments, { ...ctx, progressToken, contextProviders });
|
|
30548
30967
|
this.appendContextHooks(hooksBoundTo(this.scope.hooks.getClsHooks(agent.record.provide), context));
|
|
30549
30968
|
context.mark("createAgentContext");
|
|
30550
30969
|
const frontmcpContext = context.tryGetContext();
|
|
30551
30970
|
const sdkAuthInfo = authInfo;
|
|
30552
|
-
|
|
30971
|
+
const jsonRpcRequestId = this.state.jsonRpcRequestId;
|
|
30972
|
+
if (frontmcpContext && sdkAuthInfo?.transport?.sendElicitRequest && jsonRpcRequestId !== void 0) {
|
|
30553
30973
|
const transport = sdkAuthInfo.transport;
|
|
30554
|
-
const jsonRpcRequestId = this.state.jsonRpcRequestId;
|
|
30555
30974
|
frontmcpContext.setTransport({
|
|
30556
30975
|
sendElicitRequest: transport.sendElicitRequest.bind(transport),
|
|
30557
30976
|
type: transport.type ?? "unknown",
|
|
@@ -30568,7 +30987,7 @@ var init_call_agent_flow = __esm({
|
|
|
30568
30987
|
async acquireQuota() {
|
|
30569
30988
|
this.logger.verbose("acquireQuota:start");
|
|
30570
30989
|
const manager = this.scope.rateLimitManager;
|
|
30571
|
-
if (!manager) {
|
|
30990
|
+
if (!manager || this.gatedByToolFlow) {
|
|
30572
30991
|
this.state.agentContext?.mark("acquireQuota");
|
|
30573
30992
|
this.logger.verbose("acquireQuota:done (no rate limit manager)");
|
|
30574
30993
|
return;
|
|
@@ -30592,7 +31011,7 @@ var init_call_agent_flow = __esm({
|
|
|
30592
31011
|
async acquireSemaphore() {
|
|
30593
31012
|
this.logger.verbose("acquireSemaphore:start");
|
|
30594
31013
|
const manager = this.scope.rateLimitManager;
|
|
30595
|
-
if (!manager) {
|
|
31014
|
+
if (!manager || this.gatedByToolFlow) {
|
|
30596
31015
|
this.state.agentContext?.mark("acquireSemaphore");
|
|
30597
31016
|
this.logger.verbose("acquireSemaphore:done (no rate limit manager)");
|
|
30598
31017
|
return;
|
|
@@ -30637,7 +31056,8 @@ var init_call_agent_flow = __esm({
|
|
|
30637
31056
|
}
|
|
30638
31057
|
agentContext.mark("execute");
|
|
30639
31058
|
const startTime = Date.now();
|
|
30640
|
-
|
|
31059
|
+
this.state.set("executionStartedAt", startTime);
|
|
31060
|
+
const timeoutMs = this.gatedByToolFlow ? agent.metadata.timeout?.executeMs === void 0 ? agent.metadata.execution?.timeout : void 0 : agent.metadata.timeout?.executeMs ?? agent.metadata.execution?.timeout ?? this.scope.rateLimitManager?.config?.defaultTimeout?.executeMs;
|
|
30641
31061
|
const running = (async () => {
|
|
30642
31062
|
agentContext.output = await agentContext.execute(agentContext.input);
|
|
30643
31063
|
})();
|
|
@@ -30648,6 +31068,7 @@ var init_call_agent_flow = __esm({
|
|
|
30648
31068
|
});
|
|
30649
31069
|
this.logger.verbose("execute:done");
|
|
30650
31070
|
} catch (error) {
|
|
31071
|
+
this.state.set("executionError", error);
|
|
30651
31072
|
if (error instanceof import_guard6.ExecutionTimeoutError) {
|
|
30652
31073
|
this.logger.warn("execute: agent execution timed out", {
|
|
30653
31074
|
agent: agent.metadata.name,
|
|
@@ -30656,6 +31077,7 @@ var init_call_agent_flow = __esm({
|
|
|
30656
31077
|
this.state.set("abandonedExecution", running);
|
|
30657
31078
|
throw error;
|
|
30658
31079
|
}
|
|
31080
|
+
if (this.gatedByToolFlow) throw error;
|
|
30659
31081
|
throw new AgentExecutionError(agent.metadata.name, error instanceof Error ? error : void 0);
|
|
30660
31082
|
}
|
|
30661
31083
|
}
|
|
@@ -30693,9 +31115,34 @@ var init_call_agent_flow = __esm({
|
|
|
30693
31115
|
this.state.agentContext?.mark("releaseQuota");
|
|
30694
31116
|
this.logger.verbose("releaseQuota:done");
|
|
30695
31117
|
}
|
|
31118
|
+
async parseOutput() {
|
|
31119
|
+
const { agent, rawOutput } = this.state;
|
|
31120
|
+
if (!agent || rawOutput === void 0) return;
|
|
31121
|
+
const parseResult = agent.safeParseOutput(rawOutput);
|
|
31122
|
+
if (parseResult.success) this.state.set("parsedOutput", parseResult.data);
|
|
31123
|
+
else this.state.set("outputError", parseResult.error);
|
|
31124
|
+
}
|
|
31125
|
+
async emitCompletion() {
|
|
31126
|
+
const { agent, agentContext, executionStartedAt, executionError, outputError, authInfo } = this.state;
|
|
31127
|
+
if (!agent || executionStartedAt === void 0) return;
|
|
31128
|
+
if (executionError instanceof ElicitationFallbackRequired || executionError instanceof FlowControl) return;
|
|
31129
|
+
const failure = executionError ?? (outputError !== void 0 ? new InvalidOutputError() : void 0);
|
|
31130
|
+
const failed = failure !== void 0;
|
|
31131
|
+
const requestId = this.tryGetContext()?.requestId;
|
|
31132
|
+
const sessionId = typeof authInfo?.sessionId === "string" && authInfo.sessionId ? authInfo.sessionId : void 0;
|
|
31133
|
+
completionEventsOf(this.scope).agents.emit({
|
|
31134
|
+
agentId: agent.id,
|
|
31135
|
+
agentName: agent.name,
|
|
31136
|
+
status: failed ? "error" : "success",
|
|
31137
|
+
durationMs: Date.now() - executionStartedAt,
|
|
31138
|
+
...failed ? { error: failure instanceof Error ? failure.message : String(failure) } : { output: completionOutputText(agentContext?.output) },
|
|
31139
|
+
...requestId ? { runId: requestId } : {},
|
|
31140
|
+
...sessionId ? { sessionId } : {}
|
|
31141
|
+
});
|
|
31142
|
+
}
|
|
30696
31143
|
async finalize() {
|
|
30697
31144
|
this.logger.verbose("finalize:start");
|
|
30698
|
-
const { agent, rawOutput, executionMeta } = this.state;
|
|
31145
|
+
const { agent, rawOutput, parsedOutput, outputError, executionMeta } = this.state;
|
|
30699
31146
|
if (!agent) {
|
|
30700
31147
|
this.logger.verbose("finalize: skipping (no agent in state)");
|
|
30701
31148
|
return;
|
|
@@ -30704,15 +31151,14 @@ var init_call_agent_flow = __esm({
|
|
|
30704
31151
|
this.logger.verbose("finalize: skipping (no output - execute stage likely failed)");
|
|
30705
31152
|
return;
|
|
30706
31153
|
}
|
|
30707
|
-
|
|
30708
|
-
if (!parseResult.success) {
|
|
31154
|
+
if (outputError !== void 0 || parsedOutput === void 0) {
|
|
30709
31155
|
this.logger.error("finalize: output validation failed", {
|
|
30710
31156
|
agent: agent.metadata.name,
|
|
30711
|
-
errors:
|
|
31157
|
+
errors: outputError
|
|
30712
31158
|
});
|
|
30713
31159
|
throw new InvalidOutputError();
|
|
30714
31160
|
}
|
|
30715
|
-
const result =
|
|
31161
|
+
const result = parsedOutput;
|
|
30716
31162
|
if (executionMeta) {
|
|
30717
31163
|
result._meta = {
|
|
30718
31164
|
...result._meta,
|
|
@@ -30778,6 +31224,12 @@ var init_call_agent_flow = __esm({
|
|
|
30778
31224
|
__decorateClass([
|
|
30779
31225
|
Stage14("releaseQuota")
|
|
30780
31226
|
], CallAgentFlow.prototype, "releaseQuota", 1);
|
|
31227
|
+
__decorateClass([
|
|
31228
|
+
Stage14("parseOutput")
|
|
31229
|
+
], CallAgentFlow.prototype, "parseOutput", 1);
|
|
31230
|
+
__decorateClass([
|
|
31231
|
+
Stage14("emitCompletion")
|
|
31232
|
+
], CallAgentFlow.prototype, "emitCompletion", 1);
|
|
30781
31233
|
__decorateClass([
|
|
30782
31234
|
Stage14("finalize")
|
|
30783
31235
|
], CallAgentFlow.prototype, "finalize", 1);
|
|
@@ -31285,12 +31737,36 @@ var init_request_validation = __esm({
|
|
|
31285
31737
|
});
|
|
31286
31738
|
|
|
31287
31739
|
// libs/sdk/src/transport/mcp-20260728/request-state.ts
|
|
31288
|
-
function
|
|
31740
|
+
function configuredSecret(name44) {
|
|
31741
|
+
const value = (0, import_utils65.getEnv)(name44);
|
|
31742
|
+
return value && value.trim().length > 0 ? value : void 0;
|
|
31743
|
+
}
|
|
31744
|
+
function resolveKey() {
|
|
31289
31745
|
if (cachedKey) return cachedKey;
|
|
31290
|
-
const
|
|
31291
|
-
|
|
31746
|
+
const vault = configuredSecret("VAULT_SECRET");
|
|
31747
|
+
const jwt = vault ? void 0 : configuredSecret("JWT_SECRET");
|
|
31748
|
+
if (vault) cachedKey = { key: encoder.encode(vault), source: "VAULT_SECRET" };
|
|
31749
|
+
else if (jwt) cachedKey = { key: encoder.encode(jwt), source: "JWT_SECRET" };
|
|
31750
|
+
else cachedKey = { key: (0, import_utils65.randomBytes)(32), source: "per-process" };
|
|
31292
31751
|
return cachedKey;
|
|
31293
31752
|
}
|
|
31753
|
+
function getRequestStateKey() {
|
|
31754
|
+
return resolveKey().key;
|
|
31755
|
+
}
|
|
31756
|
+
function getRequestStateKeySource() {
|
|
31757
|
+
return resolveKey().source;
|
|
31758
|
+
}
|
|
31759
|
+
function warnIfRequestStateKeyNotShared(options) {
|
|
31760
|
+
if (warnedKeyNotShared || !(0, import_utils65.isProduction)()) return;
|
|
31761
|
+
const { metadata } = options;
|
|
31762
|
+
const persistence = metadata.transport?.persistence;
|
|
31763
|
+
const sharesState = Boolean(metadata.redis) || typeof persistence === "object" && persistence !== null;
|
|
31764
|
+
if (!sharesState || getRequestStateKeySource() !== "per-process") return;
|
|
31765
|
+
warnedKeyNotShared = true;
|
|
31766
|
+
options.logger.warn(
|
|
31767
|
+
"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."
|
|
31768
|
+
);
|
|
31769
|
+
}
|
|
31294
31770
|
function computeRequestBinding(method, params) {
|
|
31295
31771
|
const salient = {};
|
|
31296
31772
|
for (const key of ["name", "uri", "arguments"]) {
|
|
@@ -31340,13 +31816,14 @@ function decodeRequestState(state, expected) {
|
|
|
31340
31816
|
if (payload.b !== expected.binding) return { ok: false, reason: "request-mismatch" };
|
|
31341
31817
|
return { ok: true, responses: payload.r };
|
|
31342
31818
|
}
|
|
31343
|
-
var import_utils65, DEFAULT_REQUEST_STATE_TTL_MS, MAX_REQUEST_STATE_BYTES, cachedKey, encoder, decoder;
|
|
31819
|
+
var import_utils65, DEFAULT_REQUEST_STATE_TTL_MS, MAX_REQUEST_STATE_BYTES, cachedKey, warnedKeyNotShared, encoder, decoder;
|
|
31344
31820
|
var init_request_state = __esm({
|
|
31345
31821
|
"libs/sdk/src/transport/mcp-20260728/request-state.ts"() {
|
|
31346
31822
|
"use strict";
|
|
31347
31823
|
import_utils65 = require("@frontmcp/utils");
|
|
31348
31824
|
DEFAULT_REQUEST_STATE_TTL_MS = 10 * 60 * 1e3;
|
|
31349
31825
|
MAX_REQUEST_STATE_BYTES = 256 * 1024;
|
|
31826
|
+
warnedKeyNotShared = false;
|
|
31350
31827
|
encoder = new TextEncoder();
|
|
31351
31828
|
decoder = new TextDecoder();
|
|
31352
31829
|
}
|
|
@@ -31580,10 +32057,17 @@ var init_mrtr = __esm({
|
|
|
31580
32057
|
/** Per-kind call counters, used to derive stable keys across a replay. */
|
|
31581
32058
|
counters = { elicitation: 0, sampling: 0, roots: 0 };
|
|
31582
32059
|
clientCapabilities;
|
|
32060
|
+
/**
|
|
32061
|
+
* Whether the client itself declared this revision. `false` when the SERVER served an
|
|
32062
|
+
* unversioned call as 2026-07-28 (`transport.defaultProtocolVersion`, the Worker default): such a
|
|
32063
|
+
* client, typically a 2025-03-26 one, never agreed to the revision's input-request contract.
|
|
32064
|
+
*/
|
|
32065
|
+
clientDeclaredRevision;
|
|
31583
32066
|
binding;
|
|
31584
32067
|
constructor(params) {
|
|
31585
32068
|
this.responses = { ...params.carriedResponses ?? {}, ...params.inputResponses ?? {} };
|
|
31586
32069
|
this.clientCapabilities = params.clientCapabilities;
|
|
32070
|
+
this.clientDeclaredRevision = params.clientDeclaredRevision ?? true;
|
|
31587
32071
|
this.binding = params.binding;
|
|
31588
32072
|
}
|
|
31589
32073
|
/** True when the client declared the capability a given request kind needs. */
|
|
@@ -31929,7 +32413,7 @@ function shouldCreateTask(params) {
|
|
|
31929
32413
|
return { kind: "create", owner: ownership.owner };
|
|
31930
32414
|
}
|
|
31931
32415
|
async function resumeTask(params) {
|
|
31932
|
-
const { scope, record, authInfo, clientCapabilities, frontmcpContext } = params;
|
|
32416
|
+
const { scope, record, authInfo, clientCapabilities, frontmcpContext, clientDeclaredRevision } = params;
|
|
31933
32417
|
const registry = scope.tasks;
|
|
31934
32418
|
const runner = registry?.runner;
|
|
31935
32419
|
if (!runner) {
|
|
@@ -31940,6 +32424,8 @@ async function resumeTask(params) {
|
|
|
31940
32424
|
new MrtrExchange({
|
|
31941
32425
|
carriedResponses: record.inputResponses ?? {},
|
|
31942
32426
|
clientCapabilities,
|
|
32427
|
+
// A caller that never declared the revision is refused an elicitation as a legacy caller is.
|
|
32428
|
+
clientDeclaredRevision,
|
|
31943
32429
|
binding: {
|
|
31944
32430
|
principal: resolveTaskPrincipal(authInfo),
|
|
31945
32431
|
binding: computeRequestBinding("tasks/resume", { name: record.taskId })
|
|
@@ -31986,6 +32472,7 @@ async function dispatch20260728(options) {
|
|
|
31986
32472
|
scope,
|
|
31987
32473
|
body,
|
|
31988
32474
|
clientCapabilities,
|
|
32475
|
+
clientDeclaredRevision,
|
|
31989
32476
|
frontmcpContext,
|
|
31990
32477
|
authInfo,
|
|
31991
32478
|
isAnonymous,
|
|
@@ -32032,7 +32519,8 @@ async function dispatch20260728(options) {
|
|
|
32032
32519
|
record,
|
|
32033
32520
|
authInfo: { ...authInfo ?? {}, sessionId: ownership.owner },
|
|
32034
32521
|
clientCapabilities,
|
|
32035
|
-
frontmcpContext
|
|
32522
|
+
frontmcpContext,
|
|
32523
|
+
clientDeclaredRevision
|
|
32036
32524
|
})
|
|
32037
32525
|
});
|
|
32038
32526
|
return outcome.kind === "result" ? { kind: "result", result: decorate(outcome.result) } : outcome;
|
|
@@ -32056,13 +32544,15 @@ async function dispatch20260728(options) {
|
|
|
32056
32544
|
};
|
|
32057
32545
|
const carried = decodeRequestState(params["requestState"], binding);
|
|
32058
32546
|
if (!carried.ok && carried.reason !== "absent") {
|
|
32059
|
-
|
|
32547
|
+
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;
|
|
32548
|
+
scope.logger.warn("mcp-20260728: rejected requestState", { method, reason: carried.reason, ...hint && { hint } });
|
|
32060
32549
|
}
|
|
32061
32550
|
const exchange = new MrtrExchange({
|
|
32062
32551
|
inputResponses: params["inputResponses"],
|
|
32063
32552
|
carriedResponses: carried.ok ? carried.responses : {},
|
|
32064
32553
|
clientCapabilities,
|
|
32065
|
-
binding
|
|
32554
|
+
binding,
|
|
32555
|
+
clientDeclaredRevision
|
|
32066
32556
|
});
|
|
32067
32557
|
frontmcpContext?.setMrtrExchange(exchange);
|
|
32068
32558
|
if (notificationSink) frontmcpContext?.setRequestNotificationSink(notificationSink);
|
|
@@ -32212,6 +32702,7 @@ var init_mcp_stateless_client = __esm({
|
|
|
32212
32702
|
"libs/sdk/src/transport/mcp-20260728/client/mcp-stateless.client.ts"() {
|
|
32213
32703
|
"use strict";
|
|
32214
32704
|
import_protocol47 = require("@frontmcp/protocol");
|
|
32705
|
+
init_list_all_pages_utils();
|
|
32215
32706
|
init_header_codec();
|
|
32216
32707
|
init_protocol_20260728_constants();
|
|
32217
32708
|
init_tasks_extension();
|
|
@@ -32252,10 +32743,22 @@ var init_mcp_stateless_client = __esm({
|
|
|
32252
32743
|
* The spec requires this: one malformed tool definition must not prevent the
|
|
32253
32744
|
* other tools from being used, so the offender is excluded and logged rather
|
|
32254
32745
|
* than failing the call.
|
|
32746
|
+
*
|
|
32747
|
+
* Every page is fetched (`nextCursor` is followed to the end), since the
|
|
32748
|
+
* schemas cached here are what later `tools/call` headers are derived from.
|
|
32255
32749
|
*/
|
|
32256
32750
|
async listTools() {
|
|
32257
|
-
const
|
|
32258
|
-
|
|
32751
|
+
const tools = await listAllPages(
|
|
32752
|
+
"tools/list",
|
|
32753
|
+
async (cursor) => {
|
|
32754
|
+
const result = await this.request("tools/list", cursor ? { cursor } : {});
|
|
32755
|
+
return {
|
|
32756
|
+
items: Array.isArray(result["tools"]) ? result["tools"] : [],
|
|
32757
|
+
nextCursor: typeof result["nextCursor"] === "string" ? result["nextCursor"] : void 0
|
|
32758
|
+
};
|
|
32759
|
+
},
|
|
32760
|
+
(message) => new McpStatelessError(-32603, message)
|
|
32761
|
+
);
|
|
32259
32762
|
const usable = [];
|
|
32260
32763
|
for (const tool of tools) {
|
|
32261
32764
|
const validation = validateHeaderParams(tool["inputSchema"]);
|
|
@@ -32274,11 +32777,13 @@ var init_mcp_stateless_client = __esm({
|
|
|
32274
32777
|
async readResource(uri) {
|
|
32275
32778
|
return this.request("resources/read", { uri });
|
|
32276
32779
|
}
|
|
32277
|
-
|
|
32278
|
-
|
|
32780
|
+
/** One page of `resources/list`; pass the previous page's `nextCursor` for the next. */
|
|
32781
|
+
async listResources(cursor) {
|
|
32782
|
+
return this.request("resources/list", cursor ? { cursor } : {});
|
|
32279
32783
|
}
|
|
32280
|
-
|
|
32281
|
-
|
|
32784
|
+
/** One page of `prompts/list`; pass the previous page's `nextCursor` for the next. */
|
|
32785
|
+
async listPrompts(cursor) {
|
|
32786
|
+
return this.request("prompts/list", cursor ? { cursor } : {});
|
|
32282
32787
|
}
|
|
32283
32788
|
async getPrompt(name44, args = {}) {
|
|
32284
32789
|
return this.request("prompts/get", { name: name44, arguments: args });
|
|
@@ -32564,6 +33069,10 @@ var init_mcp_20260728 = __esm({
|
|
|
32564
33069
|
});
|
|
32565
33070
|
|
|
32566
33071
|
// libs/sdk/src/remote-mcp/mcp-stateless-client.adapter.ts
|
|
33072
|
+
function nextCursorOf(result) {
|
|
33073
|
+
const next = result["nextCursor"];
|
|
33074
|
+
return typeof next === "string" && next.length > 0 ? { nextCursor: next } : {};
|
|
33075
|
+
}
|
|
32567
33076
|
async function negotiateRemoteProtocol(url, configured, headers, fetchImpl = fetch) {
|
|
32568
33077
|
if (configured === "2026-07-28") return "2026-07-28";
|
|
32569
33078
|
if (configured !== "auto") return "legacy";
|
|
@@ -32606,16 +33115,22 @@ var init_mcp_stateless_client_adapter = __esm({
|
|
|
32606
33115
|
async callTool(params) {
|
|
32607
33116
|
return this.client.callTool(params.name, params.arguments ?? {});
|
|
32608
33117
|
}
|
|
32609
|
-
async listResources() {
|
|
32610
|
-
const result = await this.client.listResources();
|
|
32611
|
-
return {
|
|
33118
|
+
async listResources(params) {
|
|
33119
|
+
const result = await this.client.listResources(params?.cursor);
|
|
33120
|
+
return {
|
|
33121
|
+
resources: Array.isArray(result["resources"]) ? result["resources"] : [],
|
|
33122
|
+
...nextCursorOf(result)
|
|
33123
|
+
};
|
|
32612
33124
|
}
|
|
32613
33125
|
async readResource(params) {
|
|
32614
33126
|
return this.client.readResource(params.uri);
|
|
32615
33127
|
}
|
|
32616
|
-
async listPrompts() {
|
|
32617
|
-
const result = await this.client.listPrompts();
|
|
32618
|
-
return {
|
|
33128
|
+
async listPrompts(params) {
|
|
33129
|
+
const result = await this.client.listPrompts(params?.cursor);
|
|
33130
|
+
return {
|
|
33131
|
+
prompts: Array.isArray(result["prompts"]) ? result["prompts"] : [],
|
|
33132
|
+
...nextCursorOf(result)
|
|
33133
|
+
};
|
|
32619
33134
|
}
|
|
32620
33135
|
async getPrompt(params) {
|
|
32621
33136
|
return this.client.getPrompt(params.name, params.arguments ?? {});
|
|
@@ -33138,6 +33653,7 @@ var init_mcp_client_service = __esm({
|
|
|
33138
33653
|
"libs/sdk/src/remote-mcp/mcp-client.service.ts"() {
|
|
33139
33654
|
"use strict";
|
|
33140
33655
|
import_protocol48 = require("@frontmcp/protocol");
|
|
33656
|
+
init_list_all_pages_utils();
|
|
33141
33657
|
init_mcp_error();
|
|
33142
33658
|
init_remote_errors();
|
|
33143
33659
|
init_transport_errors();
|
|
@@ -33741,10 +34257,15 @@ var init_mcp_client_service = __esm({
|
|
|
33741
34257
|
const httpOptions = request.transportOptions;
|
|
33742
34258
|
return httpOptions?.fallbackToSSE ?? true;
|
|
33743
34259
|
}
|
|
34260
|
+
// Each list follows `nextCursor` to the end: a FrontMCP remote pages its lists
|
|
34261
|
+
// (40 per page by default), and proxying only the first page silently dropped
|
|
34262
|
+
// everything after it.
|
|
33744
34263
|
async listToolsInternal(connection) {
|
|
33745
34264
|
try {
|
|
33746
|
-
|
|
33747
|
-
|
|
34265
|
+
return await listAllPages("tools/list", async (cursor) => {
|
|
34266
|
+
const result = await connection.client.listTools(cursor ? { cursor } : void 0);
|
|
34267
|
+
return { items: result.tools, nextCursor: result.nextCursor };
|
|
34268
|
+
});
|
|
33748
34269
|
} catch (error) {
|
|
33749
34270
|
this.logger.warn(`Failed to list tools: ${error.message}`);
|
|
33750
34271
|
return [];
|
|
@@ -33752,8 +34273,10 @@ var init_mcp_client_service = __esm({
|
|
|
33752
34273
|
}
|
|
33753
34274
|
async listResourcesInternal(connection) {
|
|
33754
34275
|
try {
|
|
33755
|
-
|
|
33756
|
-
|
|
34276
|
+
return await listAllPages("resources/list", async (cursor) => {
|
|
34277
|
+
const result = await connection.client.listResources(cursor ? { cursor } : void 0);
|
|
34278
|
+
return { items: result.resources, nextCursor: result.nextCursor };
|
|
34279
|
+
});
|
|
33757
34280
|
} catch (error) {
|
|
33758
34281
|
this.logger.warn(`Failed to list resources: ${error.message}`);
|
|
33759
34282
|
return [];
|
|
@@ -33761,8 +34284,10 @@ var init_mcp_client_service = __esm({
|
|
|
33761
34284
|
}
|
|
33762
34285
|
async listResourceTemplatesInternal(connection) {
|
|
33763
34286
|
try {
|
|
33764
|
-
|
|
33765
|
-
|
|
34287
|
+
return await listAllPages("resources/templates/list", async (cursor) => {
|
|
34288
|
+
const result = await connection.client.listResourceTemplates(cursor ? { cursor } : void 0);
|
|
34289
|
+
return { items: result.resourceTemplates, nextCursor: result.nextCursor };
|
|
34290
|
+
});
|
|
33766
34291
|
} catch (error) {
|
|
33767
34292
|
this.logger.warn(`Failed to list resource templates: ${error.message}`);
|
|
33768
34293
|
return [];
|
|
@@ -33770,8 +34295,10 @@ var init_mcp_client_service = __esm({
|
|
|
33770
34295
|
}
|
|
33771
34296
|
async listPromptsInternal(connection) {
|
|
33772
34297
|
try {
|
|
33773
|
-
|
|
33774
|
-
|
|
34298
|
+
return await listAllPages("prompts/list", async (cursor) => {
|
|
34299
|
+
const result = await connection.client.listPrompts(cursor ? { cursor } : void 0);
|
|
34300
|
+
return { items: result.prompts, nextCursor: result.nextCursor };
|
|
34301
|
+
});
|
|
33775
34302
|
} catch (error) {
|
|
33776
34303
|
this.logger.warn(`Failed to list prompts: ${error.message}`);
|
|
33777
34304
|
return [];
|
|
@@ -38029,6 +38556,8 @@ var init_oauth_authorize_flow = __esm({
|
|
|
38029
38556
|
if (state) {
|
|
38030
38557
|
url.searchParams.set("state", state);
|
|
38031
38558
|
}
|
|
38559
|
+
const issuer = this.resolveIssuer(this.rawInput.request);
|
|
38560
|
+
if (issuer) url.searchParams.set("iss", issuer);
|
|
38032
38561
|
this.respond(httpRespond.redirect(url.toString()));
|
|
38033
38562
|
return;
|
|
38034
38563
|
}
|
|
@@ -40148,7 +40677,7 @@ var init_oauth_provider_callback_flow = __esm({
|
|
|
40148
40677
|
if (session.state) {
|
|
40149
40678
|
url.searchParams.set("state", session.state);
|
|
40150
40679
|
}
|
|
40151
|
-
url.searchParams.set("iss", this.getLocalAuth().
|
|
40680
|
+
url.searchParams.set("iss", this.getLocalAuth().issuerFor(this.rawInput.request));
|
|
40152
40681
|
this.logger.info(
|
|
40153
40682
|
`Federated auth complete: ${selectedProviderIds.length} providers authenticated, redirecting to client`
|
|
40154
40683
|
);
|
|
@@ -41061,7 +41590,7 @@ var init_oauth_userinfo_flow = __esm({
|
|
|
41061
41590
|
return;
|
|
41062
41591
|
}
|
|
41063
41592
|
const localAuth = this.scope.auth;
|
|
41064
|
-
const issuer = localAuth.
|
|
41593
|
+
const issuer = localAuth.acceptedIssuersFor?.(this.rawInput.request);
|
|
41065
41594
|
const result = await localAuth.verifyGatewayToken(token, baseUrl, void 0, issuer);
|
|
41066
41595
|
if (!result.ok) {
|
|
41067
41596
|
this.logger.warn("userinfo: token verification failed", { error: result.error });
|
|
@@ -41145,7 +41674,14 @@ var init_session_verify_flow = __esm({
|
|
|
41145
41674
|
import_utils78 = require("@frontmcp/utils");
|
|
41146
41675
|
init_notification_service();
|
|
41147
41676
|
init_session_id_utils();
|
|
41148
|
-
inputSchema23 = httpRequestInputSchema
|
|
41677
|
+
inputSchema23 = httpRequestInputSchema.extend({
|
|
41678
|
+
/**
|
|
41679
|
+
* The request is served without a session (MCP 2026-07-28): an anonymous or static-key caller is
|
|
41680
|
+
* identified for this request only, and no session is minted for it (#629). Minting one needs
|
|
41681
|
+
* `MCP_SESSION_SECRET`, for a session id the client would never present.
|
|
41682
|
+
*/
|
|
41683
|
+
sessionless: import_lazy_zod72.z.boolean().optional()
|
|
41684
|
+
});
|
|
41149
41685
|
stateSchema22 = import_lazy_zod72.z.object({
|
|
41150
41686
|
baseUrl: import_lazy_zod72.z.string().min(1),
|
|
41151
41687
|
authorizationHeader: import_lazy_zod72.z.string().optional(),
|
|
@@ -41203,20 +41739,25 @@ var init_session_verify_flow = __esm({
|
|
|
41203
41739
|
* Encapsulates the shared logic for session creation, payload encryption, and user derivation.
|
|
41204
41740
|
*/
|
|
41205
41741
|
createAnonymousSession(options) {
|
|
41206
|
-
const { authMode,
|
|
41742
|
+
const { authMode, subject, sessionIdHeader } = options;
|
|
41207
41743
|
this.logger.verbose("createAnonymousSession", { authMode, hasExistingSession: !!sessionIdHeader });
|
|
41744
|
+
if (this.rawInput.sessionless) {
|
|
41745
|
+
this.respond({
|
|
41746
|
+
kind: "authorized",
|
|
41747
|
+
authorization: { token: "", user: (0, import_auth39.anonymousCallerClaims)(options, (0, import_utils78.randomUUID)()) }
|
|
41748
|
+
});
|
|
41749
|
+
return;
|
|
41750
|
+
}
|
|
41208
41751
|
const machineId = (0, import_utils78.getMachineId)();
|
|
41209
41752
|
const authSignature = subject ? `${authMode}:${subject}` : authMode;
|
|
41210
41753
|
if (sessionIdHeader) {
|
|
41211
|
-
const
|
|
41212
|
-
|
|
41754
|
+
const body = this.rawInput.request.body;
|
|
41755
|
+
const isInitialize2 = typeof body === "object" && body !== null && "method" in body && body.method === "initialize";
|
|
41756
|
+
const decrypted = decryptPublicSession(sessionIdHeader, authSignature);
|
|
41757
|
+
const existingPayload = decrypted && isInitialize2 && decrypted.nodeId !== machineId ? void 0 : decrypted;
|
|
41758
|
+
if (existingPayload) {
|
|
41213
41759
|
const anonId = existingPayload.uuid ?? `${existingPayload.iat * 1e3}`;
|
|
41214
|
-
const user2 =
|
|
41215
|
-
sub: subject ?? `anon:${anonId}`,
|
|
41216
|
-
iss: issuer,
|
|
41217
|
-
name: subject ? "Static token" : "Anonymous",
|
|
41218
|
-
scope: scopes.join(" ")
|
|
41219
|
-
};
|
|
41760
|
+
const user2 = (0, import_auth39.anonymousCallerClaims)(options, anonId);
|
|
41220
41761
|
this.respond({
|
|
41221
41762
|
kind: "authorized",
|
|
41222
41763
|
authorization: {
|
|
@@ -41230,13 +41771,8 @@ var init_session_verify_flow = __esm({
|
|
|
41230
41771
|
this.logger.verbose("createAnonymousSession: ignoring unrecognized client session id; minting a fresh one");
|
|
41231
41772
|
}
|
|
41232
41773
|
const now = Date.now();
|
|
41233
|
-
const user = {
|
|
41234
|
-
sub: subject ?? `anon:${(0, import_utils78.randomUUID)()}`,
|
|
41235
|
-
iss: issuer,
|
|
41236
|
-
name: subject ? "Static token" : "Anonymous",
|
|
41237
|
-
scope: scopes.join(" ")
|
|
41238
|
-
};
|
|
41239
41774
|
const uuid = (0, import_utils78.randomUUID)();
|
|
41775
|
+
const user = (0, import_auth39.anonymousCallerClaims)(options, uuid);
|
|
41240
41776
|
const platformDetectionConfig = this.scope.metadata.transport?.platformDetection;
|
|
41241
41777
|
const platformType = detectPlatformFromUserAgent(this.state.userAgent, platformDetectionConfig);
|
|
41242
41778
|
const payload = {
|
|
@@ -41429,7 +41965,7 @@ var init_session_verify_flow = __esm({
|
|
|
41429
41965
|
} else {
|
|
41430
41966
|
const configuredAudience = (0, import_auth12.isOrchestratedMode)(authOptions) ? authOptions.expectedAudience : void 0;
|
|
41431
41967
|
const resource = computeResource(this.rawInput.request, this.scope.entryPath, this.scope.routeBase);
|
|
41432
|
-
const issuer = auth.
|
|
41968
|
+
const issuer = auth.acceptedIssuersFor?.(this.rawInput.request);
|
|
41433
41969
|
verify = auth.verifyGatewayToken(token, this.state.required.baseUrl, configuredAudience ?? resource, issuer);
|
|
41434
41970
|
}
|
|
41435
41971
|
const result = await verify;
|
|
@@ -41722,6 +42258,9 @@ var init_well_known_oauth_authorization_server_flow = __esm({
|
|
|
41722
42258
|
wellKnownAsStateSchema = import_lazy_zod74.z.object({
|
|
41723
42259
|
baseUrl: import_lazy_zod74.z.string().min(1),
|
|
41724
42260
|
// baseUrl + entryPrefix (unsuffixed)
|
|
42261
|
+
// The issuer this server names in answer to the request (`LocalPrimaryAuth.issuerFor`, #629): the
|
|
42262
|
+
// one on its authorization responses and tokens. Without it, `baseUrl`.
|
|
42263
|
+
issuer: import_lazy_zod74.z.string().min(1).optional(),
|
|
41725
42264
|
// Root origin (proto://host WITHOUT the entryPath prefix). The OAuth
|
|
41726
42265
|
// endpoints (/oauth/authorize, /oauth/token, /oauth/register, …) are
|
|
41727
42266
|
// registered at literal root paths by their flows, NOT under entryPath, so
|
|
@@ -41753,6 +42292,9 @@ var init_well_known_oauth_authorization_server_flow = __esm({
|
|
|
41753
42292
|
if (!request) throw new FlowInputMissingError("request", "well-known:oauth-authorization-server");
|
|
41754
42293
|
const { metadata } = this.scope;
|
|
41755
42294
|
const baseUrl = getRequestBaseUrl(request, this.scope.entryPath);
|
|
42295
|
+
const issuer = this.scope.auth?.issuerFor?.(
|
|
42296
|
+
request
|
|
42297
|
+
);
|
|
41756
42298
|
const oauthBaseUrl = getRequestBaseUrl(request);
|
|
41757
42299
|
let cimdEnabled = true;
|
|
41758
42300
|
if (metadata.auth && (0, import_auth12.isOrchestratedMode)(metadata.auth)) {
|
|
@@ -41761,6 +42303,7 @@ var init_well_known_oauth_authorization_server_flow = __esm({
|
|
|
41761
42303
|
this.state.set(
|
|
41762
42304
|
wellKnownAsStateSchema.parse({
|
|
41763
42305
|
baseUrl,
|
|
42306
|
+
issuer,
|
|
41764
42307
|
oauthBaseUrl,
|
|
41765
42308
|
// The scopes this server grants (`allowedScopes`, #262): the literal
|
|
41766
42309
|
// entries; a `*` glob names no scope a client could ask for.
|
|
@@ -41775,6 +42318,7 @@ var init_well_known_oauth_authorization_server_flow = __esm({
|
|
|
41775
42318
|
);
|
|
41776
42319
|
}
|
|
41777
42320
|
async collectData() {
|
|
42321
|
+
const { issuer } = this.state;
|
|
41778
42322
|
const {
|
|
41779
42323
|
baseUrl,
|
|
41780
42324
|
oauthBaseUrl,
|
|
@@ -41785,7 +42329,7 @@ var init_well_known_oauth_authorization_server_flow = __esm({
|
|
|
41785
42329
|
cimdEnabled
|
|
41786
42330
|
} = this.state.required;
|
|
41787
42331
|
if (isOrchestrated) {
|
|
41788
|
-
const baseIssuer =
|
|
42332
|
+
const baseIssuer = issuer ?? baseUrl;
|
|
41789
42333
|
this.respond({
|
|
41790
42334
|
kind: "json",
|
|
41791
42335
|
contentType: "application/json; charset=utf-8",
|
|
@@ -41812,6 +42356,8 @@ var init_well_known_oauth_authorization_server_flow = __esm({
|
|
|
41812
42356
|
grant_types_supported: ["authorization_code", "refresh_token"],
|
|
41813
42357
|
scopes_supported: scopesSupported,
|
|
41814
42358
|
code_challenge_methods_supported: ["S256"],
|
|
42359
|
+
// Every authorization response, error responses included, carries `iss` (RFC 9207 §2, §3).
|
|
42360
|
+
authorization_response_iss_parameter_supported: true,
|
|
41815
42361
|
// CIMD support advertisement per draft-ietf-oauth-client-id-metadata-document-00
|
|
41816
42362
|
client_id_metadata_document_supported: cimdEnabled
|
|
41817
42363
|
}
|
|
@@ -41860,14 +42406,16 @@ var init_well_known_prm_flow = __esm({
|
|
|
41860
42406
|
stateSchema24 = import_lazy_zod75.z.object({
|
|
41861
42407
|
resource: import_lazy_zod75.z.string().min(1),
|
|
41862
42408
|
baseUrl: import_lazy_zod75.z.string().min(1),
|
|
41863
|
-
|
|
42409
|
+
// The authorization server to name: the issuer this server names for the request (#629).
|
|
42410
|
+
authorizationServer: import_lazy_zod75.z.string().min(1).optional(),
|
|
42411
|
+
scopesSupported: import_lazy_zod75.z.array(import_lazy_zod75.z.string()),
|
|
41864
42412
|
isOrchestrated: import_lazy_zod75.z.boolean()
|
|
41865
42413
|
});
|
|
41866
42414
|
outputSchema24 = HttpJsonSchema.extend({
|
|
41867
42415
|
body: import_lazy_zod75.z.object({
|
|
41868
42416
|
resource: import_lazy_zod75.z.string().min(1),
|
|
41869
42417
|
authorization_servers: import_lazy_zod75.z.array(import_lazy_zod75.z.string().min(1)).min(1),
|
|
41870
|
-
scopes_supported: import_lazy_zod75.z.array(import_lazy_zod75.z.string()).
|
|
42418
|
+
scopes_supported: import_lazy_zod75.z.array(import_lazy_zod75.z.string()).optional(),
|
|
41871
42419
|
bearer_methods_supported: import_lazy_zod75.z.array(import_lazy_zod75.z.string()).default(["header"])
|
|
41872
42420
|
}).passthrough()
|
|
41873
42421
|
});
|
|
@@ -41891,12 +42439,17 @@ var init_well_known_prm_flow = __esm({
|
|
|
41891
42439
|
if (!request) throw new FlowInputMissingError("request", "well-known:prm");
|
|
41892
42440
|
const resource = computeResource(request, scope.entryPath, scope.routeBase);
|
|
41893
42441
|
const baseUrl = getRequestBaseUrl(request, scope.entryPath);
|
|
41894
|
-
const
|
|
42442
|
+
const authorizationServer = scope.auth?.issuerFor?.(request);
|
|
42443
|
+
const authOptions = scope.auth?.options ?? scope.metadata.auth;
|
|
42444
|
+
const granted = (0, import_auth42.resourceScopesFor)(authOptions);
|
|
42445
|
+
const orchestrated = authOptions?.mode === "local" || authOptions?.mode === "remote";
|
|
42446
|
+
const scopesSupported = orchestrated ? granted : [.../* @__PURE__ */ new Set([...granted, ...scope.getAllSupportedScopes()])];
|
|
41895
42447
|
this.state.set(
|
|
41896
42448
|
stateSchema24.parse({
|
|
41897
42449
|
resource,
|
|
41898
42450
|
baseUrl,
|
|
41899
|
-
|
|
42451
|
+
authorizationServer,
|
|
42452
|
+
scopesSupported,
|
|
41900
42453
|
isOrchestrated: false
|
|
41901
42454
|
//scope.orchestrated,// TODO: fix
|
|
41902
42455
|
})
|
|
@@ -41904,6 +42457,8 @@ var init_well_known_prm_flow = __esm({
|
|
|
41904
42457
|
}
|
|
41905
42458
|
async collectData() {
|
|
41906
42459
|
const { resource, baseUrl, scopesSupported, isOrchestrated } = this.state.required;
|
|
42460
|
+
const { authorizationServer } = this.state;
|
|
42461
|
+
const scopes = scopesSupported.length > 0 ? { scopes_supported: scopesSupported } : {};
|
|
41907
42462
|
if (isOrchestrated) {
|
|
41908
42463
|
this.respond({
|
|
41909
42464
|
kind: "json",
|
|
@@ -41915,8 +42470,8 @@ var init_well_known_prm_flow = __esm({
|
|
|
41915
42470
|
headers: { "cache-control": "no-store" },
|
|
41916
42471
|
body: {
|
|
41917
42472
|
resource,
|
|
41918
|
-
authorization_servers: [baseUrl],
|
|
41919
|
-
|
|
42473
|
+
authorization_servers: [authorizationServer ?? baseUrl],
|
|
42474
|
+
...scopes,
|
|
41920
42475
|
bearer_methods_supported: ["header"]
|
|
41921
42476
|
}
|
|
41922
42477
|
});
|
|
@@ -41929,8 +42484,8 @@ var init_well_known_prm_flow = __esm({
|
|
|
41929
42484
|
headers: { "cache-control": "no-store" },
|
|
41930
42485
|
body: {
|
|
41931
42486
|
resource,
|
|
41932
|
-
authorization_servers: [baseUrl],
|
|
41933
|
-
|
|
42487
|
+
authorization_servers: [authorizationServer ?? baseUrl],
|
|
42488
|
+
...scopes,
|
|
41934
42489
|
bearer_methods_supported: ["header"]
|
|
41935
42490
|
}
|
|
41936
42491
|
});
|
|
@@ -42078,6 +42633,14 @@ function audienceMatchesResource(aud, expected) {
|
|
|
42078
42633
|
function isUnsupportedOperation(error) {
|
|
42079
42634
|
return error instanceof import_utils80.StorageNotSupportedError;
|
|
42080
42635
|
}
|
|
42636
|
+
function originOf2(value) {
|
|
42637
|
+
try {
|
|
42638
|
+
const origin = new URL(value).origin;
|
|
42639
|
+
return origin === "null" ? void 0 : origin;
|
|
42640
|
+
} catch {
|
|
42641
|
+
return void 0;
|
|
42642
|
+
}
|
|
42643
|
+
}
|
|
42081
42644
|
var import_jose, import_auth46, import_utils80, MIN_HS256_SECRET_BYTES, defaultNoAuthSecret, RESERVED_JWT_CLAIMS, LocalPrimaryAuth;
|
|
42082
42645
|
var init_instance_local_primary_auth = __esm({
|
|
42083
42646
|
"libs/sdk/src/auth/instances/instance.local-primary-auth.ts"() {
|
|
@@ -42133,7 +42696,7 @@ var init_instance_local_primary_auth = __esm({
|
|
|
42133
42696
|
this.port = this.providers.getActiveScope().metadata.http?.port ?? 3001;
|
|
42134
42697
|
this.host = (0, import_utils80.getEnv)("FRONTMCP_PUBLIC_HOST")?.trim() || "localhost";
|
|
42135
42698
|
this.issuer = this.deriveIssuer(options);
|
|
42136
|
-
this.
|
|
42699
|
+
this.publicHostPinned = !!(0, import_utils80.getEnv)("FRONTMCP_PUBLIC_HOST")?.trim();
|
|
42137
42700
|
const jwtSecret = (0, import_utils80.getEnv)("JWT_SECRET");
|
|
42138
42701
|
const hasJwtSecret = !!jwtSecret?.trim();
|
|
42139
42702
|
if (hasJwtSecret && jwtSecret) {
|
|
@@ -42174,8 +42737,8 @@ var init_instance_local_primary_auth = __esm({
|
|
|
42174
42737
|
port;
|
|
42175
42738
|
/** The boot-time issuer: the configured one, else this server's listener address (see {@link issuerFor}). */
|
|
42176
42739
|
issuer;
|
|
42177
|
-
/** Whether
|
|
42178
|
-
|
|
42740
|
+
/** Whether `FRONTMCP_PUBLIC_HOST` names the boot-time issuer's host, pinning it for every request. */
|
|
42741
|
+
publicHostPinned;
|
|
42179
42742
|
keys = [];
|
|
42180
42743
|
secret;
|
|
42181
42744
|
logger;
|
|
@@ -42333,27 +42896,52 @@ var init_instance_local_primary_auth = __esm({
|
|
|
42333
42896
|
return void 0;
|
|
42334
42897
|
}
|
|
42335
42898
|
/**
|
|
42336
|
-
* The issuer
|
|
42337
|
-
* `
|
|
42338
|
-
*
|
|
42899
|
+
* The issuer this server names in answer to `request`: in its discovery
|
|
42900
|
+
* documents (`/.well-known/oauth-authorization-server`'s `issuer`, the
|
|
42901
|
+
* protected resource metadata's `authorization_servers`), on its
|
|
42902
|
+
* authorization responses (the RFC 9207 `iss`, errors included), and as the
|
|
42903
|
+
* `iss` of the tokens it issues; the tokens it accepts there must name it
|
|
42904
|
+
* (#269, and see {@link acceptedIssuersFor}). Every entry point asks this, so
|
|
42905
|
+
* none of them can disagree, on the Node server and under a Web fetch
|
|
42906
|
+
* handler alike (#629). In order:
|
|
42339
42907
|
*
|
|
42340
|
-
*
|
|
42341
|
-
*
|
|
42342
|
-
*
|
|
42343
|
-
*
|
|
42344
|
-
*
|
|
42345
|
-
*
|
|
42346
|
-
* Durable Object) has no listener the boot-time issuer could describe, so
|
|
42347
|
-
* the issuer is the request's own origin plus this scope's path;
|
|
42348
|
-
* - otherwise (the Node server) the boot-time issuer.
|
|
42908
|
+
* 1. a configured issuer (`issuer` / `local.issuer`);
|
|
42909
|
+
* 2. with `FRONTMCP_PUBLIC_URL` pinned, that URL plus this scope's path;
|
|
42910
|
+
* 3. with `FRONTMCP_PUBLIC_HOST` set, the boot-time issuer it names the host
|
|
42911
|
+
* of (`http://<host>:<http.port><path>`);
|
|
42912
|
+
* 4. the request's own origin plus this scope's path;
|
|
42913
|
+
* 5. without a request, the boot-time issuer.
|
|
42349
42914
|
*/
|
|
42350
42915
|
issuerFor(request) {
|
|
42351
|
-
|
|
42352
|
-
if (
|
|
42916
|
+
const configured = this.configuredIssuer(this.options);
|
|
42917
|
+
if (configured !== void 0) return configured;
|
|
42918
|
+
const pinned = getPinnedPublicUrl();
|
|
42919
|
+
if (pinned !== void 0) {
|
|
42920
|
+
return request ? computeIssuer(request, this.scope.entryPath, this.scope.routeBase) : `${pinned}${this.scope.fullPath}`;
|
|
42921
|
+
}
|
|
42922
|
+
if (this.publicHostPinned || !request) return this.issuer;
|
|
42923
|
+
return computeIssuer(request, this.scope.entryPath, this.scope.routeBase);
|
|
42924
|
+
}
|
|
42925
|
+
/**
|
|
42926
|
+
* The issuers a token presented with `request` may name: {@link issuerFor}
|
|
42927
|
+
* the request. When the issuer follows the request (nothing pins it) and
|
|
42928
|
+
* local or remote mode lists `expectedAudience`, a token for any listed
|
|
42929
|
+
* address was issued under that address's issuer, so each listed address's
|
|
42930
|
+
* issuer is accepted too, and so is the boot-time issuer that 1.8.4 named on
|
|
42931
|
+
* those tokens. The token's `aud` must still name a listed resource.
|
|
42932
|
+
*/
|
|
42933
|
+
acceptedIssuersFor(request) {
|
|
42934
|
+
const issuer = this.issuerFor(request);
|
|
42353
42935
|
const options = this.options;
|
|
42354
|
-
|
|
42355
|
-
|
|
42356
|
-
|
|
42936
|
+
const followsRequest = !!request && this.configuredIssuer(options) === void 0 && getPinnedPublicUrl() === void 0 && !this.publicHostPinned;
|
|
42937
|
+
if (!followsRequest || !(0, import_auth12.isOrchestratedMode)(options) || options.expectedAudience === void 0) return issuer;
|
|
42938
|
+
const listed = Array.isArray(options.expectedAudience) ? options.expectedAudience : [options.expectedAudience];
|
|
42939
|
+
const accepted = /* @__PURE__ */ new Set([issuer, this.issuer]);
|
|
42940
|
+
for (const audience of listed) {
|
|
42941
|
+
const origin = originOf2(audience);
|
|
42942
|
+
if (origin) accepted.add(`${origin}${this.scope.fullPath}`);
|
|
42943
|
+
}
|
|
42944
|
+
return [...accepted];
|
|
42357
42945
|
}
|
|
42358
42946
|
/**
|
|
42359
42947
|
* Read the `tokenStorage` selection off the auth options. Only
|
|
@@ -42604,10 +43192,10 @@ var init_instance_local_primary_auth = __esm({
|
|
|
42604
43192
|
*
|
|
42605
43193
|
* The secret alone doesn't make a token this server's: every server started
|
|
42606
43194
|
* with the same JWT_SECRET holds it. So a token must also (#269):
|
|
42607
|
-
* - name THIS instance as its issuer (`iss`): `expectedIssuer
|
|
42608
|
-
* take from {@link
|
|
42609
|
-
*
|
|
42610
|
-
* claim; and
|
|
43195
|
+
* - name THIS instance as its issuer (`iss`): `expectedIssuer` (one issuer or
|
|
43196
|
+
* several), which callers take from {@link acceptedIssuersFor} the request,
|
|
43197
|
+
* matching what the token endpoint names when it signs ({@link issuerFor});
|
|
43198
|
+
* the boot-time issuer when not given. Never the token's own claim; and
|
|
42611
43199
|
* - when `expectedAudience` is given, be issued for that protected resource,
|
|
42612
43200
|
* or one of those resources (`aud`, compared as RFC 8707 resource URIs).
|
|
42613
43201
|
* `session:verify` passes the request's resource URL, or the configured
|
|
@@ -42620,7 +43208,7 @@ var init_instance_local_primary_auth = __esm({
|
|
|
42620
43208
|
try {
|
|
42621
43209
|
const { payload, protectedHeader } = await (0, import_jose.jwtVerify)(token, this.secret, {
|
|
42622
43210
|
algorithms: ["HS256"],
|
|
42623
|
-
issuer: expectedIssuer
|
|
43211
|
+
issuer: typeof expectedIssuer === "string" ? expectedIssuer : expectedIssuer ? [...expectedIssuer] : this.issuer,
|
|
42624
43212
|
requiredClaims: ["exp"]
|
|
42625
43213
|
});
|
|
42626
43214
|
if (expectedAudience !== void 0 && !audienceMatchesResource(payload.aud, expectedAudience)) {
|
|
@@ -43576,6 +44164,111 @@ var init_auth_registry = __esm({
|
|
|
43576
44164
|
}
|
|
43577
44165
|
});
|
|
43578
44166
|
|
|
44167
|
+
// libs/sdk/src/server/custom-routes.helper.ts
|
|
44168
|
+
function computeReservedPaths(entryPath, routeBase) {
|
|
44169
|
+
const prefix = normalizeEntryPrefix(entryPath);
|
|
44170
|
+
const base = normalizeScopeBase(routeBase);
|
|
44171
|
+
const mcpBase = `${prefix}${base}`;
|
|
44172
|
+
const exact = /* @__PURE__ */ new Set([
|
|
44173
|
+
mcpBase === "" ? "/" : mcpBase,
|
|
44174
|
+
`${mcpBase}/sse`,
|
|
44175
|
+
`${mcpBase}/message`,
|
|
44176
|
+
"/health",
|
|
44177
|
+
"/metrics"
|
|
44178
|
+
]);
|
|
44179
|
+
return { exact, prefixes: ["/oauth", "/.well-known"] };
|
|
44180
|
+
}
|
|
44181
|
+
function normalizeForCompare(path3) {
|
|
44182
|
+
if (path3.length > 1 && path3.endsWith("/")) return path3.slice(0, -1);
|
|
44183
|
+
return path3;
|
|
44184
|
+
}
|
|
44185
|
+
function assertNotReserved(method, path3, reserved) {
|
|
44186
|
+
const normalized = normalizeForCompare(path3);
|
|
44187
|
+
if (reserved.exact.has(normalized)) {
|
|
44188
|
+
throw new ReservedRouteCollisionError(method, path3, normalized);
|
|
44189
|
+
}
|
|
44190
|
+
for (const prefix of reserved.prefixes) {
|
|
44191
|
+
if (normalized === prefix || normalized.startsWith(`${prefix}/`)) {
|
|
44192
|
+
throw new ReservedRouteCollisionError(method, path3, prefix);
|
|
44193
|
+
}
|
|
44194
|
+
}
|
|
44195
|
+
}
|
|
44196
|
+
function wrapWithAuth(handler, verifySession, logger) {
|
|
44197
|
+
return async (req, res, next) => {
|
|
44198
|
+
let result;
|
|
44199
|
+
try {
|
|
44200
|
+
result = await verifySession(req);
|
|
44201
|
+
} catch (error) {
|
|
44202
|
+
if (error instanceof FlowControl && error.type === "respond") {
|
|
44203
|
+
result = error.output;
|
|
44204
|
+
} else {
|
|
44205
|
+
throw error;
|
|
44206
|
+
}
|
|
44207
|
+
}
|
|
44208
|
+
if (!result || result.kind === "unauthorized") {
|
|
44209
|
+
logger.verbose("custom-route auth: unauthorized");
|
|
44210
|
+
return writeHttpResponse(
|
|
44211
|
+
res,
|
|
44212
|
+
httpRespond.unauthorized({
|
|
44213
|
+
headers: result?.kind === "unauthorized" ? { "WWW-Authenticate": result.prmMetadataHeader } : void 0
|
|
44214
|
+
})
|
|
44215
|
+
);
|
|
44216
|
+
}
|
|
44217
|
+
if (result.kind === "forbidden") {
|
|
44218
|
+
logger.verbose("custom-route auth: forbidden (insufficient scope)");
|
|
44219
|
+
return writeHttpResponse(
|
|
44220
|
+
res,
|
|
44221
|
+
httpRespond.forbidden({
|
|
44222
|
+
headers: { "WWW-Authenticate": result.prmMetadataHeader }
|
|
44223
|
+
})
|
|
44224
|
+
);
|
|
44225
|
+
}
|
|
44226
|
+
req.authSession = result.authorization;
|
|
44227
|
+
req[ServerRequestTokens.auth] = result.authorization;
|
|
44228
|
+
return handler(req, res, next);
|
|
44229
|
+
};
|
|
44230
|
+
}
|
|
44231
|
+
function wrapWithIpFilter(handler, checkClientIp) {
|
|
44232
|
+
return async (req, res, next) => {
|
|
44233
|
+
const rejection = await checkClientIp(req, res);
|
|
44234
|
+
if (rejection) return writeHttpResponse(res, rejection);
|
|
44235
|
+
return handler(req, res, next);
|
|
44236
|
+
};
|
|
44237
|
+
}
|
|
44238
|
+
function registerCustomHttpRoutes(args) {
|
|
44239
|
+
const { routes, server, verifySession, checkClientIp, entryPath, routeBase, logger } = args;
|
|
44240
|
+
if (!routes || routes.length === 0) return;
|
|
44241
|
+
const reserved = computeReservedPaths(entryPath, routeBase);
|
|
44242
|
+
for (const route of routes) {
|
|
44243
|
+
assertNotReserved(route.method, route.path, reserved);
|
|
44244
|
+
const handler = route.auth === true ? wrapWithAuth(route.handler, verifySession, logger) : route.handler;
|
|
44245
|
+
server.registerRoute(route.method, route.path, wrapWithIpFilter(handler, checkClientIp));
|
|
44246
|
+
logger.info(`Registered custom http route: ${route.method} ${route.path}${route.auth ? " (auth)" : ""}`);
|
|
44247
|
+
}
|
|
44248
|
+
}
|
|
44249
|
+
var ReservedRouteCollisionError;
|
|
44250
|
+
var init_custom_routes_helper = __esm({
|
|
44251
|
+
"libs/sdk/src/server/custom-routes.helper.ts"() {
|
|
44252
|
+
"use strict";
|
|
44253
|
+
init_common();
|
|
44254
|
+
init_server_validation();
|
|
44255
|
+
ReservedRouteCollisionError = class extends Error {
|
|
44256
|
+
constructor(method, path3, reserved) {
|
|
44257
|
+
super(
|
|
44258
|
+
`Custom http.route "${method} ${path3}" collides with the reserved FrontMCP path "${reserved}". Reserved prefixes are the MCP entry path (and its /sse + /message siblings), /oauth/*, /.well-known/*, /health, and /metrics. Choose a different path.`
|
|
44259
|
+
);
|
|
44260
|
+
this.method = method;
|
|
44261
|
+
this.path = path3;
|
|
44262
|
+
this.reserved = reserved;
|
|
44263
|
+
this.name = "ReservedRouteCollisionError";
|
|
44264
|
+
}
|
|
44265
|
+
method;
|
|
44266
|
+
path;
|
|
44267
|
+
reserved;
|
|
44268
|
+
};
|
|
44269
|
+
}
|
|
44270
|
+
});
|
|
44271
|
+
|
|
43579
44272
|
// libs/sdk/src/channel/channel-notification.service.ts
|
|
43580
44273
|
var CHANNEL_NOTIFICATION_METHOD, ChannelNotificationService;
|
|
43581
44274
|
var init_channel_notification_service = __esm({
|
|
@@ -44546,6 +45239,12 @@ function wireJobCompletionSource(channel2, sourceConfig, jobEmitterSubscribe, lo
|
|
|
44546
45239
|
return;
|
|
44547
45240
|
}
|
|
44548
45241
|
}
|
|
45242
|
+
if (!event.sessionId) {
|
|
45243
|
+
logger.verbose(
|
|
45244
|
+
`Skipping job completion for channel "${channel2.name}": no sessionId (prevents cross-session leak)`
|
|
45245
|
+
);
|
|
45246
|
+
return;
|
|
45247
|
+
}
|
|
44549
45248
|
logger.verbose(`Job completion event for channel "${channel2.name}": job=${event.jobName}, status=${event.status}`);
|
|
44550
45249
|
channel2.handleEvent(event, event.sessionId).catch((err) => {
|
|
44551
45250
|
logger.error(`Failed to handle job completion event in channel "${channel2.name}"`, { error: err });
|
|
@@ -44558,6 +45257,41 @@ var init_job_completion_source = __esm({
|
|
|
44558
45257
|
}
|
|
44559
45258
|
});
|
|
44560
45259
|
|
|
45260
|
+
// libs/sdk/src/channel/sources/webhook.source.ts
|
|
45261
|
+
function createWebhookMiddleware(channel2, sourceConfig, logger) {
|
|
45262
|
+
return async (req, res) => {
|
|
45263
|
+
const rawHeaders = req.headers ?? {};
|
|
45264
|
+
const normalizedHeaders = {};
|
|
45265
|
+
for (const [key, value] of Object.entries(rawHeaders)) {
|
|
45266
|
+
normalizedHeaders[key.toLowerCase()] = value;
|
|
45267
|
+
}
|
|
45268
|
+
const payload = {
|
|
45269
|
+
body: req.body,
|
|
45270
|
+
headers: normalizedHeaders,
|
|
45271
|
+
method: req.method ?? "POST",
|
|
45272
|
+
query: req.query
|
|
45273
|
+
};
|
|
45274
|
+
logger.verbose(`Webhook received for channel "${channel2.name}" at ${sourceConfig.path}`);
|
|
45275
|
+
try {
|
|
45276
|
+
const notification = await runOnSurface("http-trigger", () => channel2.handleEvent(payload));
|
|
45277
|
+
if (notification) {
|
|
45278
|
+
res.status(200).json({ ok: true, channel: channel2.name });
|
|
45279
|
+
} else {
|
|
45280
|
+
res.status(200).json({ ok: true, channel: channel2.name, skipped: true });
|
|
45281
|
+
}
|
|
45282
|
+
} catch (err) {
|
|
45283
|
+
logger.error(`Webhook handler failed for channel "${channel2.name}"`, { error: err });
|
|
45284
|
+
res.status(500).json({ ok: false, error: "Internal channel error" });
|
|
45285
|
+
}
|
|
45286
|
+
};
|
|
45287
|
+
}
|
|
45288
|
+
var init_webhook_source = __esm({
|
|
45289
|
+
"libs/sdk/src/channel/sources/webhook.source.ts"() {
|
|
45290
|
+
"use strict";
|
|
45291
|
+
init_call_surface();
|
|
45292
|
+
}
|
|
45293
|
+
});
|
|
45294
|
+
|
|
44561
45295
|
// libs/sdk/src/channel/channel-scope.helper.ts
|
|
44562
45296
|
async function registerChannelCapabilities(args) {
|
|
44563
45297
|
const {
|
|
@@ -44568,11 +45302,15 @@ async function registerChannelCapabilities(args) {
|
|
|
44568
45302
|
notificationService,
|
|
44569
45303
|
flowRegistry,
|
|
44570
45304
|
toolRegistry,
|
|
44571
|
-
|
|
44572
|
-
jobEmitterSubscribe,
|
|
45305
|
+
http: http2,
|
|
44573
45306
|
logger
|
|
44574
45307
|
} = args;
|
|
45308
|
+
const completions = completionEventsOf(providers.getActiveScope());
|
|
45309
|
+
const agentEmitterSubscribe = args.agentEmitterSubscribe ?? ((cb) => completions.agents.subscribe(cb));
|
|
45310
|
+
const jobEmitterSubscribe = args.jobEmitterSubscribe ?? ((cb) => completions.jobs.subscribe(cb));
|
|
44575
45311
|
const unsubscribers = [];
|
|
45312
|
+
const reservedPaths = http2 ? computeReservedPaths(http2.entryPath, http2.routeBase) : void 0;
|
|
45313
|
+
const webhookPaths = /* @__PURE__ */ new Map();
|
|
44576
45314
|
const channelRegistry = new ChannelRegistry(providers, channelsList, owner);
|
|
44577
45315
|
await channelRegistry.ready;
|
|
44578
45316
|
const channelNotificationService = new ChannelNotificationService(
|
|
@@ -44588,31 +45326,23 @@ async function registerChannelCapabilities(args) {
|
|
|
44588
45326
|
const sourceType = instance.source.type;
|
|
44589
45327
|
switch (sourceType) {
|
|
44590
45328
|
case "agent-completion": {
|
|
44591
|
-
|
|
44592
|
-
|
|
44593
|
-
|
|
44594
|
-
|
|
44595
|
-
|
|
44596
|
-
|
|
44597
|
-
|
|
44598
|
-
unsubscribers.push(unsub);
|
|
44599
|
-
} else {
|
|
44600
|
-
logger.warn(`Channel "${instance.name}" has agent-completion source but no agent emitter available`);
|
|
44601
|
-
}
|
|
45329
|
+
const unsub = wireAgentCompletionSource(
|
|
45330
|
+
instance,
|
|
45331
|
+
instance.metadata.source,
|
|
45332
|
+
agentEmitterSubscribe,
|
|
45333
|
+
logger
|
|
45334
|
+
);
|
|
45335
|
+
unsubscribers.push(unsub);
|
|
44602
45336
|
break;
|
|
44603
45337
|
}
|
|
44604
45338
|
case "job-completion": {
|
|
44605
|
-
|
|
44606
|
-
|
|
44607
|
-
|
|
44608
|
-
|
|
44609
|
-
|
|
44610
|
-
|
|
44611
|
-
|
|
44612
|
-
unsubscribers.push(unsub);
|
|
44613
|
-
} else {
|
|
44614
|
-
logger.warn(`Channel "${instance.name}" has job-completion source but no job emitter available`);
|
|
44615
|
-
}
|
|
45339
|
+
const unsub = wireJobCompletionSource(
|
|
45340
|
+
instance,
|
|
45341
|
+
instance.metadata.source,
|
|
45342
|
+
jobEmitterSubscribe,
|
|
45343
|
+
logger
|
|
45344
|
+
);
|
|
45345
|
+
unsubscribers.push(unsub);
|
|
44616
45346
|
break;
|
|
44617
45347
|
}
|
|
44618
45348
|
case "app-event": {
|
|
@@ -44621,7 +45351,25 @@ async function registerChannelCapabilities(args) {
|
|
|
44621
45351
|
unsubscribers.push(unsub);
|
|
44622
45352
|
break;
|
|
44623
45353
|
}
|
|
44624
|
-
case "webhook":
|
|
45354
|
+
case "webhook": {
|
|
45355
|
+
const source = instance.metadata.source;
|
|
45356
|
+
if (!http2 || !reservedPaths) {
|
|
45357
|
+
logger.warn(`Channel "${instance.name}" has a webhook source but no HTTP server to serve ${source.path}`);
|
|
45358
|
+
break;
|
|
45359
|
+
}
|
|
45360
|
+
assertNotReserved("POST", source.path, reservedPaths);
|
|
45361
|
+
const claimedBy = webhookPaths.get(source.path);
|
|
45362
|
+
if (claimedBy) {
|
|
45363
|
+
throw new Error(
|
|
45364
|
+
`Channels "${claimedBy}" and "${instance.name}" both declare the webhook path ${source.path}. Give each webhook channel its own path.`
|
|
45365
|
+
);
|
|
45366
|
+
}
|
|
45367
|
+
webhookPaths.set(source.path, instance.name);
|
|
45368
|
+
const handler = createWebhookMiddleware(instance, source, logger);
|
|
45369
|
+
await http2.server.registerRoute("POST", source.path, wrapWithIpFilter(handler, http2.checkClientIp));
|
|
45370
|
+
logger.info(`Registered webhook route for channel "${instance.name}": POST ${source.path}`);
|
|
45371
|
+
break;
|
|
45372
|
+
}
|
|
44625
45373
|
case "manual":
|
|
44626
45374
|
break;
|
|
44627
45375
|
case "service":
|
|
@@ -44704,6 +45452,7 @@ async function registerChannelCapabilities(args) {
|
|
|
44704
45452
|
var init_channel_scope_helper = __esm({
|
|
44705
45453
|
"libs/sdk/src/channel/channel-scope.helper.ts"() {
|
|
44706
45454
|
"use strict";
|
|
45455
|
+
init_custom_routes_helper();
|
|
44707
45456
|
init_tool_instance();
|
|
44708
45457
|
init_tool_utils();
|
|
44709
45458
|
init_channel_notification_service();
|
|
@@ -44713,7 +45462,9 @@ var init_channel_scope_helper = __esm({
|
|
|
44713
45462
|
init_channel_reply_tool();
|
|
44714
45463
|
init_agent_completion_source();
|
|
44715
45464
|
init_app_event_source();
|
|
45465
|
+
init_completion_events();
|
|
44716
45466
|
init_job_completion_source();
|
|
45467
|
+
init_webhook_source();
|
|
44717
45468
|
}
|
|
44718
45469
|
});
|
|
44719
45470
|
|
|
@@ -47780,10 +48531,11 @@ var init_workflow_step_executor = __esm({
|
|
|
47780
48531
|
});
|
|
47781
48532
|
|
|
47782
48533
|
// libs/sdk/src/workflow/engine/workflow.engine.ts
|
|
47783
|
-
var WorkflowEngine;
|
|
48534
|
+
var import_utils86, WorkflowEngine;
|
|
47784
48535
|
var init_workflow_engine = __esm({
|
|
47785
48536
|
"libs/sdk/src/workflow/engine/workflow.engine.ts"() {
|
|
47786
48537
|
"use strict";
|
|
48538
|
+
import_utils86 = require("@frontmcp/utils");
|
|
47787
48539
|
init_workflow_errors();
|
|
47788
48540
|
init_workflow_step_executor();
|
|
47789
48541
|
WorkflowEngine = class {
|
|
@@ -47849,7 +48601,7 @@ var init_workflow_engine = __esm({
|
|
|
47849
48601
|
}
|
|
47850
48602
|
continue;
|
|
47851
48603
|
}
|
|
47852
|
-
const batch = ready.slice(0, this.maxConcurrency);
|
|
48604
|
+
const batch = ready.slice(0, (0, import_utils86.getAsyncContextMode)() === "serialized" ? 1 : this.maxConcurrency);
|
|
47853
48605
|
await Promise.allSettled(
|
|
47854
48606
|
batch.map(async (step) => {
|
|
47855
48607
|
if (step.condition) {
|
|
@@ -47956,11 +48708,11 @@ var init_workflow_engine = __esm({
|
|
|
47956
48708
|
});
|
|
47957
48709
|
|
|
47958
48710
|
// libs/sdk/src/job/execution/job-execution.manager.ts
|
|
47959
|
-
var
|
|
48711
|
+
var import_utils87, JobExecutionManager;
|
|
47960
48712
|
var init_job_execution_manager = __esm({
|
|
47961
48713
|
"libs/sdk/src/job/execution/job-execution.manager.ts"() {
|
|
47962
48714
|
"use strict";
|
|
47963
|
-
|
|
48715
|
+
import_utils87 = require("@frontmcp/utils");
|
|
47964
48716
|
init_principal_utils();
|
|
47965
48717
|
init_call_surface();
|
|
47966
48718
|
init_errors();
|
|
@@ -47980,7 +48732,7 @@ var init_job_execution_manager = __esm({
|
|
|
47980
48732
|
*/
|
|
47981
48733
|
async executeJob(job, input, opts = {}) {
|
|
47982
48734
|
await this.assertMayExecute(job.metadata.permissions, job.name, opts);
|
|
47983
|
-
const runId = (0,
|
|
48735
|
+
const runId = (0, import_utils87.randomUUID)();
|
|
47984
48736
|
const retryConfig = job.metadata.retry ?? {};
|
|
47985
48737
|
const maxAttempts = retryConfig.maxAttempts ?? 1;
|
|
47986
48738
|
const runRecord = {
|
|
@@ -47999,7 +48751,7 @@ var init_job_execution_manager = __esm({
|
|
|
47999
48751
|
};
|
|
48000
48752
|
await this.stateStore.createRun(runRecord);
|
|
48001
48753
|
if (opts.background) {
|
|
48002
|
-
(0,
|
|
48754
|
+
(0, import_utils87.runRequestExclusive)(() => this.executeJobBackground(job, input, runId, opts)).catch(async (err) => {
|
|
48003
48755
|
this.logger.error(`Background job execution failed: ${err}`);
|
|
48004
48756
|
try {
|
|
48005
48757
|
await this.updateState(runId, {
|
|
@@ -48020,7 +48772,7 @@ var init_job_execution_manager = __esm({
|
|
|
48020
48772
|
*/
|
|
48021
48773
|
async executeWorkflow(workflow, jobRegistry, opts = {}) {
|
|
48022
48774
|
await this.assertMayExecute(workflow.metadata.permissions, workflow.name, opts);
|
|
48023
|
-
const runId = (0,
|
|
48775
|
+
const runId = (0, import_utils87.randomUUID)();
|
|
48024
48776
|
const runRecord = {
|
|
48025
48777
|
runId,
|
|
48026
48778
|
jobId: workflow.metadata.id ?? workflow.name,
|
|
@@ -48039,7 +48791,7 @@ var init_job_execution_manager = __esm({
|
|
|
48039
48791
|
};
|
|
48040
48792
|
await this.stateStore.createRun(runRecord);
|
|
48041
48793
|
if (opts.background) {
|
|
48042
|
-
(0,
|
|
48794
|
+
(0, import_utils87.runRequestExclusive)(() => this.executeWorkflowBackground(workflow, jobRegistry, runId, opts)).catch(
|
|
48043
48795
|
async (err) => {
|
|
48044
48796
|
this.logger.error(`Background workflow execution failed: ${err}`);
|
|
48045
48797
|
try {
|
|
@@ -49447,7 +50199,11 @@ async function registerJobCapabilities(args) {
|
|
|
49447
50199
|
for (const dynWf of dynamicWorkflows) {
|
|
49448
50200
|
workflowRegistry.registerDynamic(dynWf);
|
|
49449
50201
|
}
|
|
49450
|
-
const
|
|
50202
|
+
const completions = completionEventsOf(providers.getActiveScope());
|
|
50203
|
+
const executionManager = new JobExecutionManager(stateStore, logger, async (data) => {
|
|
50204
|
+
await notifyFn?.(data);
|
|
50205
|
+
await publishJobCompletion(data, stateStore, completions);
|
|
50206
|
+
});
|
|
49451
50207
|
const managementTools = [
|
|
49452
50208
|
ListJobsTool,
|
|
49453
50209
|
ExecuteJobTool,
|
|
@@ -49476,9 +50232,27 @@ async function registerJobCapabilities(args) {
|
|
|
49476
50232
|
managementTools
|
|
49477
50233
|
};
|
|
49478
50234
|
}
|
|
50235
|
+
async function publishJobCompletion(data, stateStore, completions) {
|
|
50236
|
+
const { type, state, runId } = data;
|
|
50237
|
+
if (type !== "job:status" && type !== "workflow:status") return;
|
|
50238
|
+
if (state !== "completed" && state !== "failed" || typeof runId !== "string") return;
|
|
50239
|
+
const run = await stateStore.getRun(runId);
|
|
50240
|
+
if (!run) return;
|
|
50241
|
+
const workflowName = type === "workflow:status" ? run.workflowName : void 0;
|
|
50242
|
+
completions.jobs.emit({
|
|
50243
|
+
jobName: workflowName ?? run.jobName,
|
|
50244
|
+
jobId: run.jobId,
|
|
50245
|
+
status: state === "completed" ? "success" : "error",
|
|
50246
|
+
...run.completedAt !== void 0 ? { durationMs: run.completedAt - run.startedAt } : {},
|
|
50247
|
+
...state === "completed" ? { output: completionOutputText(run.result) } : { error: run.error?.message },
|
|
50248
|
+
attempt: run.attempt,
|
|
50249
|
+
...run.sessionId ? { sessionId: run.sessionId } : {}
|
|
50250
|
+
});
|
|
50251
|
+
}
|
|
49479
50252
|
var init_job_scope_helper = __esm({
|
|
49480
50253
|
"libs/sdk/src/job/job-scope.helper.ts"() {
|
|
49481
50254
|
"use strict";
|
|
50255
|
+
init_completion_events();
|
|
49482
50256
|
init_execute_workflow_tool();
|
|
49483
50257
|
init_get_workflow_status_tool();
|
|
49484
50258
|
init_list_workflows_tool();
|
|
@@ -49704,111 +50478,6 @@ var init_enforced_metadata_check = __esm({
|
|
|
49704
50478
|
}
|
|
49705
50479
|
});
|
|
49706
50480
|
|
|
49707
|
-
// libs/sdk/src/server/custom-routes.helper.ts
|
|
49708
|
-
function computeReservedPaths(entryPath, routeBase) {
|
|
49709
|
-
const prefix = normalizeEntryPrefix(entryPath);
|
|
49710
|
-
const base = normalizeScopeBase(routeBase);
|
|
49711
|
-
const mcpBase = `${prefix}${base}`;
|
|
49712
|
-
const exact = /* @__PURE__ */ new Set([
|
|
49713
|
-
mcpBase === "" ? "/" : mcpBase,
|
|
49714
|
-
`${mcpBase}/sse`,
|
|
49715
|
-
`${mcpBase}/message`,
|
|
49716
|
-
"/health",
|
|
49717
|
-
"/metrics"
|
|
49718
|
-
]);
|
|
49719
|
-
return { exact, prefixes: ["/oauth", "/.well-known"] };
|
|
49720
|
-
}
|
|
49721
|
-
function normalizeForCompare(path3) {
|
|
49722
|
-
if (path3.length > 1 && path3.endsWith("/")) return path3.slice(0, -1);
|
|
49723
|
-
return path3;
|
|
49724
|
-
}
|
|
49725
|
-
function assertNotReserved(method, path3, reserved) {
|
|
49726
|
-
const normalized = normalizeForCompare(path3);
|
|
49727
|
-
if (reserved.exact.has(normalized)) {
|
|
49728
|
-
throw new ReservedRouteCollisionError(method, path3, normalized);
|
|
49729
|
-
}
|
|
49730
|
-
for (const prefix of reserved.prefixes) {
|
|
49731
|
-
if (normalized === prefix || normalized.startsWith(`${prefix}/`)) {
|
|
49732
|
-
throw new ReservedRouteCollisionError(method, path3, prefix);
|
|
49733
|
-
}
|
|
49734
|
-
}
|
|
49735
|
-
}
|
|
49736
|
-
function wrapWithAuth(handler, verifySession, logger) {
|
|
49737
|
-
return async (req, res, next) => {
|
|
49738
|
-
let result;
|
|
49739
|
-
try {
|
|
49740
|
-
result = await verifySession(req);
|
|
49741
|
-
} catch (error) {
|
|
49742
|
-
if (error instanceof FlowControl && error.type === "respond") {
|
|
49743
|
-
result = error.output;
|
|
49744
|
-
} else {
|
|
49745
|
-
throw error;
|
|
49746
|
-
}
|
|
49747
|
-
}
|
|
49748
|
-
if (!result || result.kind === "unauthorized") {
|
|
49749
|
-
logger.verbose("custom-route auth: unauthorized");
|
|
49750
|
-
return writeHttpResponse(
|
|
49751
|
-
res,
|
|
49752
|
-
httpRespond.unauthorized({
|
|
49753
|
-
headers: result?.kind === "unauthorized" ? { "WWW-Authenticate": result.prmMetadataHeader } : void 0
|
|
49754
|
-
})
|
|
49755
|
-
);
|
|
49756
|
-
}
|
|
49757
|
-
if (result.kind === "forbidden") {
|
|
49758
|
-
logger.verbose("custom-route auth: forbidden (insufficient scope)");
|
|
49759
|
-
return writeHttpResponse(
|
|
49760
|
-
res,
|
|
49761
|
-
httpRespond.forbidden({
|
|
49762
|
-
headers: { "WWW-Authenticate": result.prmMetadataHeader }
|
|
49763
|
-
})
|
|
49764
|
-
);
|
|
49765
|
-
}
|
|
49766
|
-
req.authSession = result.authorization;
|
|
49767
|
-
req[ServerRequestTokens.auth] = result.authorization;
|
|
49768
|
-
return handler(req, res, next);
|
|
49769
|
-
};
|
|
49770
|
-
}
|
|
49771
|
-
function wrapWithIpFilter(handler, checkClientIp) {
|
|
49772
|
-
return async (req, res, next) => {
|
|
49773
|
-
const rejection = await checkClientIp(req, res);
|
|
49774
|
-
if (rejection) return writeHttpResponse(res, rejection);
|
|
49775
|
-
return handler(req, res, next);
|
|
49776
|
-
};
|
|
49777
|
-
}
|
|
49778
|
-
function registerCustomHttpRoutes(args) {
|
|
49779
|
-
const { routes, server, verifySession, checkClientIp, entryPath, routeBase, logger } = args;
|
|
49780
|
-
if (!routes || routes.length === 0) return;
|
|
49781
|
-
const reserved = computeReservedPaths(entryPath, routeBase);
|
|
49782
|
-
for (const route of routes) {
|
|
49783
|
-
assertNotReserved(route.method, route.path, reserved);
|
|
49784
|
-
const handler = route.auth === true ? wrapWithAuth(route.handler, verifySession, logger) : route.handler;
|
|
49785
|
-
server.registerRoute(route.method, route.path, wrapWithIpFilter(handler, checkClientIp));
|
|
49786
|
-
logger.info(`Registered custom http route: ${route.method} ${route.path}${route.auth ? " (auth)" : ""}`);
|
|
49787
|
-
}
|
|
49788
|
-
}
|
|
49789
|
-
var ReservedRouteCollisionError;
|
|
49790
|
-
var init_custom_routes_helper = __esm({
|
|
49791
|
-
"libs/sdk/src/server/custom-routes.helper.ts"() {
|
|
49792
|
-
"use strict";
|
|
49793
|
-
init_common();
|
|
49794
|
-
init_server_validation();
|
|
49795
|
-
ReservedRouteCollisionError = class extends Error {
|
|
49796
|
-
constructor(method, path3, reserved) {
|
|
49797
|
-
super(
|
|
49798
|
-
`Custom http.route "${method} ${path3}" collides with the reserved FrontMCP path "${reserved}". Reserved prefixes are the MCP entry path (and its /sse + /message siblings), /oauth/*, /.well-known/*, /health, and /metrics. Choose a different path.`
|
|
49799
|
-
);
|
|
49800
|
-
this.method = method;
|
|
49801
|
-
this.path = path3;
|
|
49802
|
-
this.reserved = reserved;
|
|
49803
|
-
this.name = "ReservedRouteCollisionError";
|
|
49804
|
-
}
|
|
49805
|
-
method;
|
|
49806
|
-
path;
|
|
49807
|
-
reserved;
|
|
49808
|
-
};
|
|
49809
|
-
}
|
|
49810
|
-
});
|
|
49811
|
-
|
|
49812
50481
|
// libs/sdk/src/skill/errors/tool-not-allowed.error.ts
|
|
49813
50482
|
var ToolNotAllowedError, ToolApprovalRequiredError;
|
|
49814
50483
|
var init_tool_not_allowed_error = __esm({
|
|
@@ -50048,15 +50717,15 @@ var init_skill_session_types = __esm({
|
|
|
50048
50717
|
});
|
|
50049
50718
|
|
|
50050
50719
|
// libs/sdk/src/skill/session/skill-session.manager.ts
|
|
50051
|
-
var
|
|
50720
|
+
var import_utils88, SkillSessionManager;
|
|
50052
50721
|
var init_skill_session_manager = __esm({
|
|
50053
50722
|
"libs/sdk/src/skill/session/skill-session.manager.ts"() {
|
|
50054
50723
|
"use strict";
|
|
50055
|
-
|
|
50724
|
+
import_utils88 = require("@frontmcp/utils");
|
|
50056
50725
|
init_errors();
|
|
50057
50726
|
init_skill_session_types();
|
|
50058
|
-
SkillSessionManager = class extends
|
|
50059
|
-
storage = new
|
|
50727
|
+
SkillSessionManager = class extends import_utils88.EventEmitter {
|
|
50728
|
+
storage = new import_utils88.AsyncLocalStorage();
|
|
50060
50729
|
options;
|
|
50061
50730
|
logger;
|
|
50062
50731
|
store;
|
|
@@ -50983,7 +51652,7 @@ var init_load_skill_flow = __esm({
|
|
|
50983
51652
|
}
|
|
50984
51653
|
await assertSkillAuthorized(this.scope, entry, authInfo);
|
|
50985
51654
|
}
|
|
50986
|
-
loadResults.push({ loadResult: result });
|
|
51655
|
+
loadResults.push({ loadResult: skillToolsForCaller(result, this.scope.tools, ctx) });
|
|
50987
51656
|
}
|
|
50988
51657
|
this.state.set({ loadResults, warnings });
|
|
50989
51658
|
this.logger.verbose("loadSkills:done", { loaded: loadResults.length, notFound: warnings.length });
|
|
@@ -51228,7 +51897,10 @@ async function authorizeSkillHttpRequest(scope, skillsConfig, request, logger) {
|
|
|
51228
51897
|
if (mode === "inherit") {
|
|
51229
51898
|
const authOptions = scope.auth?.options;
|
|
51230
51899
|
if (!authOptions || (0, import_auth12.isPublicMode)(authOptions)) return { allowed: true, authInfo: {} };
|
|
51231
|
-
const verified = await scope.runFlow("session:verify", {
|
|
51900
|
+
const verified = await scope.runFlow("session:verify", {
|
|
51901
|
+
request,
|
|
51902
|
+
sessionless: true
|
|
51903
|
+
});
|
|
51232
51904
|
if (verified?.kind === "authorized") {
|
|
51233
51905
|
return { allowed: true, authInfo: { ...authInfoFromAuthorization(verified.authorization) } };
|
|
51234
51906
|
}
|
|
@@ -51252,11 +51924,11 @@ function createSkillHttpAuthValidator(skillsConfig, logger) {
|
|
|
51252
51924
|
logger
|
|
51253
51925
|
});
|
|
51254
51926
|
}
|
|
51255
|
-
var
|
|
51927
|
+
var import_utils89, SkillHttpAuthValidator;
|
|
51256
51928
|
var init_skill_http_auth = __esm({
|
|
51257
51929
|
"libs/sdk/src/skill/auth/skill-http-auth.ts"() {
|
|
51258
51930
|
"use strict";
|
|
51259
|
-
|
|
51931
|
+
import_utils89 = require("@frontmcp/utils");
|
|
51260
51932
|
init_common();
|
|
51261
51933
|
SkillHttpAuthValidator = class {
|
|
51262
51934
|
skillsConfig;
|
|
@@ -51338,7 +52010,7 @@ var init_skill_http_auth = __esm({
|
|
|
51338
52010
|
const keyBytes = encoder5.encode(key);
|
|
51339
52011
|
if (keyBytes.length === candidateBytes.length) {
|
|
51340
52012
|
try {
|
|
51341
|
-
if ((0,
|
|
52013
|
+
if ((0, import_utils89.timingSafeEqual)(keyBytes, candidateBytes)) {
|
|
51342
52014
|
found = true;
|
|
51343
52015
|
}
|
|
51344
52016
|
} catch {
|
|
@@ -52198,7 +52870,12 @@ var init_skills_api_flow = __esm({
|
|
|
52198
52870
|
respondNotFound();
|
|
52199
52871
|
return;
|
|
52200
52872
|
}
|
|
52201
|
-
const { skill, availableTools, missingTools, isComplete, warning } =
|
|
52873
|
+
const { skill, availableTools, missingTools, isComplete, warning } = skillToolsForCaller(
|
|
52874
|
+
loadResult,
|
|
52875
|
+
toolRegistry,
|
|
52876
|
+
void 0,
|
|
52877
|
+
SKILLS_HTTP_SURFACE
|
|
52878
|
+
);
|
|
52202
52879
|
const skillEntry = createSkillEntryResolver(skillRegistry)(skillId, skill.id);
|
|
52203
52880
|
if (skillEntry) {
|
|
52204
52881
|
if (!await isSkillServable(this.scope, skillEntry, void 0, SKILLS_HTTP_SURFACE)) {
|
|
@@ -52559,6 +53236,8 @@ var init_tool_interface = __esm({
|
|
|
52559
53236
|
_toolNameInternal;
|
|
52560
53237
|
/** @internal Tool input for fallback elicitation - set by CallToolFlow */
|
|
52561
53238
|
_toolInputInternal;
|
|
53239
|
+
/** @internal JSON-RPC id of the tools/call request - set by CallToolFlow, for flows the call is handed on to */
|
|
53240
|
+
_jsonRpcRequestIdInternal;
|
|
52562
53241
|
// ---- INPUT storages (backing fields)
|
|
52563
53242
|
_rawInput;
|
|
52564
53243
|
_input;
|
|
@@ -52591,6 +53270,10 @@ var init_tool_interface = __esm({
|
|
|
52591
53270
|
this._progressToken = progressToken;
|
|
52592
53271
|
this.signal = signal;
|
|
52593
53272
|
}
|
|
53273
|
+
/** @internal The request's progress token, for flows the call is handed on to (the agent tool). */
|
|
53274
|
+
get _progressTokenInternal() {
|
|
53275
|
+
return this._progressToken;
|
|
53276
|
+
}
|
|
52594
53277
|
/**
|
|
52595
53278
|
* Like {@link ExecutionContextBase.fetch}, and also aborted with {@link signal}, so a
|
|
52596
53279
|
* cancelled or timed-out call stops its outbound requests.
|
|
@@ -54636,10 +55319,10 @@ var init_primary_auth_provider_interface = __esm({
|
|
|
54636
55319
|
* @param _expectedAudience The protected resource(s) the token must be for
|
|
54637
55320
|
* (`aud` names at least one), when the caller is a
|
|
54638
55321
|
* resource endpoint.
|
|
54639
|
-
* @param _expectedIssuer The issuer the token must name
|
|
54640
|
-
*
|
|
54641
|
-
* (`LocalPrimaryAuth.
|
|
54642
|
-
* boot-time issuer.
|
|
55322
|
+
* @param _expectedIssuer The issuer the token must name (or one of them):
|
|
55323
|
+
* the ones this instance accepts for the request
|
|
55324
|
+
* (`LocalPrimaryAuth.acceptedIssuersFor`). Default:
|
|
55325
|
+
* its boot-time issuer.
|
|
54643
55326
|
*/
|
|
54644
55327
|
verifyGatewayToken(_token, _requestBaseUrl, _expectedAudience, _expectedIssuer) {
|
|
54645
55328
|
return Promise.resolve({
|
|
@@ -54713,7 +55396,10 @@ function findSkillByPath(scope, skillPath) {
|
|
|
54713
55396
|
const segments = skillPath.split("/").filter((s) => s.length > 0);
|
|
54714
55397
|
if (segments.length === 0) return void 0;
|
|
54715
55398
|
const lastSegment = segments[segments.length - 1];
|
|
54716
|
-
|
|
55399
|
+
const byName = visible.find((s) => s.name === lastSegment && s.getSkillPath() === lastSegment);
|
|
55400
|
+
if (byName) return byName;
|
|
55401
|
+
if (segments.length !== 1) return void 0;
|
|
55402
|
+
return visible.find((s) => s.metadata.id === lastSegment && s.getSkillPath() === s.metadata.name);
|
|
54717
55403
|
}
|
|
54718
55404
|
async function findAndLoadSkillByPath(scope, skillPath) {
|
|
54719
55405
|
const registry = scope.skills;
|
|
@@ -54785,15 +55471,15 @@ async function readSkillFileByPath(instance, filePath) {
|
|
|
54785
55471
|
let candidatePath;
|
|
54786
55472
|
for (const [subdir, configured] of candidateDirs) {
|
|
54787
55473
|
if (segments[0] !== subdir) continue;
|
|
54788
|
-
const dir = configured ? (0,
|
|
54789
|
-
candidatePath = (0,
|
|
55474
|
+
const dir = configured ? (0, import_utils91.isAbsolute)(configured) ? configured : (0, import_utils91.pathResolve)(baseDir, configured) : (0, import_utils91.joinPath)(baseDir, subdir);
|
|
55475
|
+
candidatePath = (0, import_utils91.pathResolve)(dir, ...segments.slice(1));
|
|
54790
55476
|
if (!isInside(candidatePath, dir)) {
|
|
54791
55477
|
throw new PublicMcpError(`Invalid file path "${filePath}".`, "INVALID_PARAMS", 400);
|
|
54792
55478
|
}
|
|
54793
55479
|
break;
|
|
54794
55480
|
}
|
|
54795
55481
|
if (!candidatePath) {
|
|
54796
|
-
candidatePath = (0,
|
|
55482
|
+
candidatePath = (0, import_utils91.pathResolve)(baseDir, ...segments);
|
|
54797
55483
|
if (!isInside(candidatePath, baseDir)) {
|
|
54798
55484
|
throw new PublicMcpError(`Invalid file path "${filePath}".`, "INVALID_PARAMS", 400);
|
|
54799
55485
|
}
|
|
@@ -54801,7 +55487,7 @@ async function readSkillFileByPath(instance, filePath) {
|
|
|
54801
55487
|
const mimeType = guessMimeType(filePath);
|
|
54802
55488
|
let buffer;
|
|
54803
55489
|
try {
|
|
54804
|
-
buffer = await (0,
|
|
55490
|
+
buffer = await (0, import_utils91.readFileBuffer)(candidatePath);
|
|
54805
55491
|
} catch (err) {
|
|
54806
55492
|
if (isFileMissingError(err)) {
|
|
54807
55493
|
throw new ResourceNotFoundError(`skill://${instance.getSkillPath()}/${filePath}`);
|
|
@@ -54844,7 +55530,7 @@ async function tryResolvedSubFile(instance, kind, tail) {
|
|
|
54844
55530
|
const resolvedPath = resolveEntryPath2(instance, kind, absolutePath, filename);
|
|
54845
55531
|
if (!resolvedPath) continue;
|
|
54846
55532
|
try {
|
|
54847
|
-
const buf = await (0,
|
|
55533
|
+
const buf = await (0, import_utils91.readFileBuffer)(resolvedPath);
|
|
54848
55534
|
const text = (Buffer.isBuffer(buf) ? buf : Buffer.from(buf)).toString("utf-8");
|
|
54849
55535
|
return parseSkillMdFrontmatter(text).body;
|
|
54850
55536
|
} catch (err) {
|
|
@@ -54857,18 +55543,18 @@ async function tryResolvedSubFile(instance, kind, tail) {
|
|
|
54857
55543
|
return void 0;
|
|
54858
55544
|
}
|
|
54859
55545
|
function resolveEntryPath2(instance, kind, absolutePath, filename) {
|
|
54860
|
-
if (absolutePath && (0,
|
|
55546
|
+
if (absolutePath && (0, import_utils91.isAbsolute)(absolutePath)) return absolutePath;
|
|
54861
55547
|
if (!filename) return void 0;
|
|
54862
55548
|
const baseDir = instance.getBaseDir();
|
|
54863
55549
|
const configured = instance.getResources()?.[kind];
|
|
54864
55550
|
let dir;
|
|
54865
|
-
if (configured && (0,
|
|
55551
|
+
if (configured && (0, import_utils91.isAbsolute)(configured)) {
|
|
54866
55552
|
dir = configured;
|
|
54867
55553
|
} else if (baseDir) {
|
|
54868
|
-
dir = configured ? (0,
|
|
55554
|
+
dir = configured ? (0, import_utils91.pathResolve)(baseDir, configured) : (0, import_utils91.joinPath)(baseDir, kind);
|
|
54869
55555
|
}
|
|
54870
55556
|
if (!dir) return void 0;
|
|
54871
|
-
const resolved = (0,
|
|
55557
|
+
const resolved = (0, import_utils91.pathResolve)(dir, filename);
|
|
54872
55558
|
if (!isInside(resolved, dir)) return void 0;
|
|
54873
55559
|
return resolved;
|
|
54874
55560
|
}
|
|
@@ -54900,11 +55586,11 @@ function isInside(child, parent) {
|
|
|
54900
55586
|
const parentPrefix = normParent.endsWith("/") ? normParent : `${normParent}/`;
|
|
54901
55587
|
return normChild === normParent || normChild.startsWith(parentPrefix);
|
|
54902
55588
|
}
|
|
54903
|
-
var
|
|
55589
|
+
var import_utils91;
|
|
54904
55590
|
var init_sep_2640_resource_helpers = __esm({
|
|
54905
55591
|
"libs/sdk/src/skill/sep-2640/sep-2640.resource-helpers.ts"() {
|
|
54906
55592
|
"use strict";
|
|
54907
|
-
|
|
55593
|
+
import_utils91 = require("@frontmcp/utils");
|
|
54908
55594
|
init_errors();
|
|
54909
55595
|
init_skill_filter_helper();
|
|
54910
55596
|
init_skill_md_parser();
|
|
@@ -55131,17 +55817,17 @@ async function resolveLastModifiedForSkill(skill) {
|
|
|
55131
55817
|
return void 0;
|
|
55132
55818
|
}
|
|
55133
55819
|
try {
|
|
55134
|
-
const s = await (0,
|
|
55820
|
+
const s = await (0, import_utils92.stat)(record.filePath);
|
|
55135
55821
|
return s.mtime instanceof Date ? s.mtime.toISOString() : void 0;
|
|
55136
55822
|
} catch {
|
|
55137
55823
|
return void 0;
|
|
55138
55824
|
}
|
|
55139
55825
|
}
|
|
55140
|
-
var
|
|
55826
|
+
var import_utils92;
|
|
55141
55827
|
var init_sep_2640_last_modified = __esm({
|
|
55142
55828
|
"libs/sdk/src/skill/sep-2640/sep-2640.last-modified.ts"() {
|
|
55143
55829
|
"use strict";
|
|
55144
|
-
|
|
55830
|
+
import_utils92 = require("@frontmcp/utils");
|
|
55145
55831
|
}
|
|
55146
55832
|
});
|
|
55147
55833
|
|
|
@@ -55331,7 +56017,7 @@ function createDefaultSigner(mod, logger) {
|
|
|
55331
56017
|
"[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)."
|
|
55332
56018
|
);
|
|
55333
56019
|
}
|
|
55334
|
-
const bytes = (0,
|
|
56020
|
+
const bytes = (0, import_utils93.randomBytes)(32);
|
|
55335
56021
|
logger.warn(
|
|
55336
56022
|
"[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."
|
|
55337
56023
|
);
|
|
@@ -55343,12 +56029,12 @@ function createDefaultStore(mod, logger) {
|
|
|
55343
56029
|
);
|
|
55344
56030
|
return new mod.MemoryAuditStore();
|
|
55345
56031
|
}
|
|
55346
|
-
var import_di39,
|
|
56032
|
+
var import_di39, import_utils93, injectedFactory;
|
|
55347
56033
|
var init_skill_audit_helper = __esm({
|
|
55348
56034
|
"libs/sdk/src/skill/skill-audit.helper.ts"() {
|
|
55349
56035
|
"use strict";
|
|
55350
56036
|
import_di39 = require("@frontmcp/di");
|
|
55351
|
-
|
|
56037
|
+
import_utils93 = require("@frontmcp/utils");
|
|
55352
56038
|
}
|
|
55353
56039
|
});
|
|
55354
56040
|
|
|
@@ -55988,11 +56674,11 @@ function createSqliteSessionStore(options, logger) {
|
|
|
55988
56674
|
logger?.info("[SessionStoreFactory] Creating SQLite session store", { path: options.path });
|
|
55989
56675
|
return new SqliteSessionStore(options);
|
|
55990
56676
|
}
|
|
55991
|
-
var
|
|
56677
|
+
var import_utils94;
|
|
55992
56678
|
var init_session_store_factory = __esm({
|
|
55993
56679
|
"libs/sdk/src/auth/session/session-store.factory.ts"() {
|
|
55994
56680
|
"use strict";
|
|
55995
|
-
|
|
56681
|
+
import_utils94 = require("@frontmcp/utils");
|
|
55996
56682
|
init_common();
|
|
55997
56683
|
}
|
|
55998
56684
|
});
|
|
@@ -56067,14 +56753,14 @@ function toClientInfo(value) {
|
|
|
56067
56753
|
const { name: name44, version } = value;
|
|
56068
56754
|
return typeof name44 === "string" && typeof version === "string" ? { name: name44, version } : void 0;
|
|
56069
56755
|
}
|
|
56070
|
-
var import_auth55, import_lazy_zod102, import_protocol52,
|
|
56756
|
+
var import_auth55, import_lazy_zod102, import_protocol52, import_utils95, plan37, subscriptionParamsSchema, requestIdSchema, stateSchema37, name38, Stage38, encoder3, TRACE_META_KEYS, HandleMcp20260728Flow;
|
|
56071
56757
|
var init_handle_mcp_20260728_flow = __esm({
|
|
56072
56758
|
"libs/sdk/src/transport/flows/handle.mcp-20260728.flow.ts"() {
|
|
56073
56759
|
"use strict";
|
|
56074
56760
|
import_auth55 = require("@frontmcp/auth");
|
|
56075
56761
|
import_lazy_zod102 = require("@frontmcp/lazy-zod");
|
|
56076
56762
|
import_protocol52 = require("@frontmcp/protocol");
|
|
56077
|
-
|
|
56763
|
+
import_utils95 = require("@frontmcp/utils");
|
|
56078
56764
|
init_common();
|
|
56079
56765
|
init_context();
|
|
56080
56766
|
init_notification();
|
|
@@ -56098,7 +56784,9 @@ var init_handle_mcp_20260728_flow = __esm({
|
|
|
56098
56784
|
/** Negotiated protocol version for this request. */
|
|
56099
56785
|
version: import_lazy_zod102.z.string().optional(),
|
|
56100
56786
|
requestType: import_lazy_zod102.z.enum(["notification", "subscriptions", "message"]).optional(),
|
|
56101
|
-
isAnonymous: import_lazy_zod102.z.boolean().default(true)
|
|
56787
|
+
isAnonymous: import_lazy_zod102.z.boolean().default(true),
|
|
56788
|
+
/** Whether the client declared this revision itself (not served under it by default). */
|
|
56789
|
+
clientDeclaredRevision: import_lazy_zod102.z.boolean().optional()
|
|
56102
56790
|
});
|
|
56103
56791
|
name38 = "handle:mcp-202607280728";
|
|
56104
56792
|
({ Stage: Stage38 } = FlowHooksOf(name38));
|
|
@@ -56145,6 +56833,7 @@ var init_handle_mcp_20260728_flow = __esm({
|
|
|
56145
56833
|
return;
|
|
56146
56834
|
}
|
|
56147
56835
|
this.state.set("version", result.version);
|
|
56836
|
+
this.state.set("clientDeclaredRevision", strictHeaders);
|
|
56148
56837
|
}
|
|
56149
56838
|
/**
|
|
56150
56839
|
* Resolve a tool's input JSON Schema so `x-mcp-header` annotations can be
|
|
@@ -56169,7 +56858,7 @@ var init_handle_mcp_20260728_flow = __esm({
|
|
|
56169
56858
|
if (!context) return (fn) => fn();
|
|
56170
56859
|
const storage = this.scope.providers.get(FrontMcpContextStorage);
|
|
56171
56860
|
return async (fn) => {
|
|
56172
|
-
await (0,
|
|
56861
|
+
await (0, import_utils95.runRequestExclusive)(() => storage.runWithContext(context, fn));
|
|
56173
56862
|
};
|
|
56174
56863
|
}
|
|
56175
56864
|
findToolSchema(scope, toolName) {
|
|
@@ -56260,10 +56949,12 @@ var init_handle_mcp_20260728_flow = __esm({
|
|
|
56260
56949
|
// authenticated caller.
|
|
56261
56950
|
...authInfoFromAuthorization(auth),
|
|
56262
56951
|
// The shared handlers still key per-request state (provider views, notifications)
|
|
56263
|
-
// off an id.
|
|
56264
|
-
sessionId
|
|
56952
|
+
// off an id. It names the request only, the same per-request id as the request
|
|
56953
|
+
// context's `sessionId`; the request context does not vouch for it (#629).
|
|
56954
|
+
sessionId: auth.session?.id ?? this.tryGetContext()?.sessionId
|
|
56265
56955
|
} : void 0,
|
|
56266
56956
|
isAnonymous: this.state.required.isAnonymous,
|
|
56957
|
+
clientDeclaredRevision: this.state.clientDeclaredRevision !== false,
|
|
56267
56958
|
composeInstructions: () => this.scope.metadata.instructions,
|
|
56268
56959
|
notificationSink: sink,
|
|
56269
56960
|
traceContext: extractTraceContext(meta)
|
|
@@ -56370,12 +57061,36 @@ function getQuerySessionId2(urlPath) {
|
|
|
56370
57061
|
return void 0;
|
|
56371
57062
|
}
|
|
56372
57063
|
}
|
|
56373
|
-
|
|
57064
|
+
function resolveLegacySseSession(params) {
|
|
57065
|
+
const { rawHeader, requestUrl, authorizationSession, createSession } = params;
|
|
57066
|
+
const rawMcpSessionHeader = typeof rawHeader === "string" ? rawHeader : void 0;
|
|
57067
|
+
const mcpSessionHeader = validateMcpSessionHeader(rawMcpSessionHeader);
|
|
57068
|
+
const querySessionId = getQuerySessionId2(requestUrl);
|
|
57069
|
+
const validatedQuerySessionId = querySessionId ? validateMcpSessionHeader(querySessionId) : void 0;
|
|
57070
|
+
if (rawHeader !== void 0 && !mcpSessionHeader) {
|
|
57071
|
+
return { responded404: true, createdNew: false };
|
|
57072
|
+
}
|
|
57073
|
+
if (querySessionId !== void 0 && !validatedQuerySessionId) {
|
|
57074
|
+
return { responded404: true, createdNew: false };
|
|
57075
|
+
}
|
|
57076
|
+
const effectiveSessionId = mcpSessionHeader ?? validatedQuerySessionId;
|
|
57077
|
+
if (effectiveSessionId) {
|
|
57078
|
+
if (authorizationSession?.id === effectiveSessionId) {
|
|
57079
|
+
return { session: authorizationSession, createdNew: false, responded404: false };
|
|
57080
|
+
}
|
|
57081
|
+
return { responded404: true, createdNew: false };
|
|
57082
|
+
}
|
|
57083
|
+
if (authorizationSession) {
|
|
57084
|
+
return { session: authorizationSession, createdNew: false, responded404: false };
|
|
57085
|
+
}
|
|
57086
|
+
return { session: createSession(), createdNew: true, responded404: false };
|
|
57087
|
+
}
|
|
57088
|
+
var import_lazy_zod103, import_utils96, plan38, stateSessionSchema, stateSchema38, name39, Stage39, HandleSseFlow;
|
|
56374
57089
|
var init_handle_sse_flow = __esm({
|
|
56375
57090
|
"libs/sdk/src/transport/flows/handle.sse.flow.ts"() {
|
|
56376
57091
|
"use strict";
|
|
56377
57092
|
import_lazy_zod103 = require("@frontmcp/lazy-zod");
|
|
56378
|
-
|
|
57093
|
+
import_utils96 = require("@frontmcp/utils");
|
|
56379
57094
|
init_session_id_utils();
|
|
56380
57095
|
init_common();
|
|
56381
57096
|
init_errors();
|
|
@@ -56411,39 +57126,26 @@ var init_handle_sse_flow = __esm({
|
|
|
56411
57126
|
const { request } = this.rawInput;
|
|
56412
57127
|
const authorization = request[ServerRequestTokens.auth];
|
|
56413
57128
|
const { token } = authorization;
|
|
56414
|
-
const raw = request.headers?.["mcp-session-id"];
|
|
56415
|
-
const rawMcpSessionHeader = typeof raw === "string" ? raw : void 0;
|
|
56416
|
-
const mcpSessionHeader = validateMcpSessionHeader(rawMcpSessionHeader);
|
|
56417
57129
|
const anyReq = request;
|
|
56418
|
-
const
|
|
56419
|
-
|
|
56420
|
-
|
|
56421
|
-
|
|
56422
|
-
|
|
56423
|
-
|
|
56424
|
-
|
|
57130
|
+
const resolution = resolveLegacySseSession({
|
|
57131
|
+
rawHeader: request.headers?.["mcp-session-id"],
|
|
57132
|
+
requestUrl: anyReq.url ?? anyReq.path,
|
|
57133
|
+
authorizationSession: authorization.session,
|
|
57134
|
+
createSession: () => {
|
|
57135
|
+
const query = request.query;
|
|
57136
|
+
const skillsOnlyMode = detectSkillsOnlyMode(query);
|
|
57137
|
+
return createSessionId("legacy-sse", token, {
|
|
57138
|
+
userAgent: request.headers?.["user-agent"],
|
|
57139
|
+
platformDetectionConfig: this.scope.metadata.transport?.platformDetection,
|
|
57140
|
+
skillsOnlyMode
|
|
57141
|
+
});
|
|
57142
|
+
}
|
|
57143
|
+
});
|
|
57144
|
+
if (resolution.responded404 || !resolution.session) {
|
|
56425
57145
|
this.respond(httpRespond.sessionNotFound("invalid session id"));
|
|
56426
57146
|
return;
|
|
56427
57147
|
}
|
|
56428
|
-
const
|
|
56429
|
-
let session;
|
|
56430
|
-
if (effectiveSessionId) {
|
|
56431
|
-
if (authorization.session?.id === effectiveSessionId) {
|
|
56432
|
-
session = authorization.session;
|
|
56433
|
-
} else {
|
|
56434
|
-
session = { id: effectiveSessionId };
|
|
56435
|
-
}
|
|
56436
|
-
} else if (authorization.session) {
|
|
56437
|
-
session = authorization.session;
|
|
56438
|
-
} else {
|
|
56439
|
-
const query = request.query;
|
|
56440
|
-
const skillsOnlyMode = detectSkillsOnlyMode(query);
|
|
56441
|
-
session = createSessionId("legacy-sse", token, {
|
|
56442
|
-
userAgent: request.headers?.["user-agent"],
|
|
56443
|
-
platformDetectionConfig: this.scope.metadata.transport?.platformDetection,
|
|
56444
|
-
skillsOnlyMode
|
|
56445
|
-
});
|
|
56446
|
-
}
|
|
57148
|
+
const session = resolution.session;
|
|
56447
57149
|
this.state.set(stateSchema38.parse({ token, session }));
|
|
56448
57150
|
}
|
|
56449
57151
|
async router() {
|
|
@@ -56466,10 +57168,10 @@ var init_handle_sse_flow = __esm({
|
|
|
56466
57168
|
const { request, response } = this.rawInput;
|
|
56467
57169
|
const { token, session } = this.state.required;
|
|
56468
57170
|
const transport = await transportService.createTransporter("sse", token, session.id, response);
|
|
56469
|
-
if ((0,
|
|
56470
|
-
const nodeId = (0,
|
|
57171
|
+
if ((0, import_utils96.getRuntimeContext)().deployment === "distributed") {
|
|
57172
|
+
const nodeId = (0, import_utils96.getMachineId)();
|
|
56471
57173
|
response.setHeader(DEFAULT_FRONTMCP_MACHINE_ID_HEADER, nodeId);
|
|
56472
|
-
const cookie = (0,
|
|
57174
|
+
const cookie = (0, import_utils96.buildSetCookie)({ name: DEFAULT_FRONTMCP_NODE_COOKIE, value: nodeId }, request);
|
|
56473
57175
|
if (cookie) {
|
|
56474
57176
|
const existing = response.getHeader("Set-Cookie");
|
|
56475
57177
|
const existingArr = Array.isArray(existing) ? existing : existing ? [String(existing)] : [];
|
|
@@ -56491,12 +57193,12 @@ var init_handle_sse_flow = __esm({
|
|
|
56491
57193
|
const { request, response } = this.rawInput;
|
|
56492
57194
|
const { token, session } = this.state.required;
|
|
56493
57195
|
const transport = await transportService.getTransporter("sse", token, session.id);
|
|
56494
|
-
if (!transport && (0,
|
|
57196
|
+
if (!transport && (0, import_utils96.getRuntimeContext)().deployment === "distributed") {
|
|
56495
57197
|
const storedSession = await transportService.getStoredSession("sse", token, session.id);
|
|
56496
57198
|
if (storedSession) {
|
|
56497
57199
|
const haManager = this.scope.haManager;
|
|
56498
57200
|
const relay = haManager?.getRelay();
|
|
56499
|
-
if (relay && storedSession.session.nodeId && storedSession.session.nodeId !== (0,
|
|
57201
|
+
if (relay && storedSession.session.nodeId && storedSession.session.nodeId !== (0, import_utils96.getMachineId)()) {
|
|
56500
57202
|
const isAlive2 = await haManager.isNodeAlive(storedSession.session.nodeId);
|
|
56501
57203
|
if (isAlive2) {
|
|
56502
57204
|
try {
|
|
@@ -56722,11 +57424,11 @@ var init_ext_apps_types = __esm({
|
|
|
56722
57424
|
function createExtAppsMessageHandler(options) {
|
|
56723
57425
|
return new ExtAppsMessageHandler(options);
|
|
56724
57426
|
}
|
|
56725
|
-
var
|
|
57427
|
+
var import_utils97, ExtAppsMessageHandler, ExtAppsError, ExtAppsMethodNotFoundError, ExtAppsInvalidParamsError, ExtAppsNotSupportedError, ExtAppsToolNotFoundError;
|
|
56726
57428
|
var init_ext_apps_handler = __esm({
|
|
56727
57429
|
"libs/sdk/src/ext-apps/ext-apps.handler.ts"() {
|
|
56728
57430
|
"use strict";
|
|
56729
|
-
|
|
57431
|
+
import_utils97 = require("@frontmcp/utils");
|
|
56730
57432
|
init_ext_apps_types();
|
|
56731
57433
|
ExtAppsMessageHandler = class {
|
|
56732
57434
|
context;
|
|
@@ -56770,7 +57472,7 @@ var init_ext_apps_handler = __esm({
|
|
|
56770
57472
|
code: errorCode,
|
|
56771
57473
|
message: errorMessage,
|
|
56772
57474
|
// Only include stack traces in development to avoid leaking internals in production
|
|
56773
|
-
data: (0,
|
|
57475
|
+
data: (0, import_utils97.isDevelopment)() && error instanceof Error ? { stack: error.stack } : void 0
|
|
56774
57476
|
}
|
|
56775
57477
|
};
|
|
56776
57478
|
}
|
|
@@ -57056,7 +57758,7 @@ function resolveStreamableHttpSession(params) {
|
|
|
57056
57758
|
if (authorizationSession?.id === mcpSessionHeader) {
|
|
57057
57759
|
return { session: authorizationSession, createdNew: false, responded404: false };
|
|
57058
57760
|
}
|
|
57059
|
-
return {
|
|
57761
|
+
return { responded404: true, createdNew: false };
|
|
57060
57762
|
}
|
|
57061
57763
|
if (authorizationSession) {
|
|
57062
57764
|
return { session: authorizationSession, createdNew: false, responded404: false };
|
|
@@ -57132,13 +57834,13 @@ async function lookupStreamableHttpTransport(params) {
|
|
|
57132
57834
|
}
|
|
57133
57835
|
return { kind: "session-not-initialized", recreationError };
|
|
57134
57836
|
}
|
|
57135
|
-
var import_lazy_zod105, import_protocol54,
|
|
57837
|
+
var import_lazy_zod105, import_protocol54, import_utils98, plan40, stateSessionSchema2, stateSchema40, name41, Stage41, HandleStreamableHttpFlow;
|
|
57136
57838
|
var init_handle_streamable_http_flow = __esm({
|
|
57137
57839
|
"libs/sdk/src/transport/flows/handle.streamable-http.flow.ts"() {
|
|
57138
57840
|
"use strict";
|
|
57139
57841
|
import_lazy_zod105 = require("@frontmcp/lazy-zod");
|
|
57140
57842
|
import_protocol54 = require("@frontmcp/protocol");
|
|
57141
|
-
|
|
57843
|
+
import_utils98 = require("@frontmcp/utils");
|
|
57142
57844
|
init_session_id_utils();
|
|
57143
57845
|
init_common();
|
|
57144
57846
|
init_errors();
|
|
@@ -57204,7 +57906,7 @@ var init_handle_streamable_http_flow = __esm({
|
|
|
57204
57906
|
});
|
|
57205
57907
|
}
|
|
57206
57908
|
if (sessionResolution.responded404 || !sessionResolution.session) {
|
|
57207
|
-
logger.warn("parseInput:
|
|
57909
|
+
logger.warn("parseInput: mcp-session-id is not a session this server verified");
|
|
57208
57910
|
this.respond(httpRespond.sessionNotFound("invalid session id"));
|
|
57209
57911
|
return;
|
|
57210
57912
|
}
|
|
@@ -57271,10 +57973,10 @@ var init_handle_streamable_http_flow = __esm({
|
|
|
57271
57973
|
return;
|
|
57272
57974
|
}
|
|
57273
57975
|
}
|
|
57274
|
-
if ((0,
|
|
57275
|
-
const nodeId = (0,
|
|
57976
|
+
if ((0, import_utils98.getRuntimeContext)().deployment === "distributed") {
|
|
57977
|
+
const nodeId = (0, import_utils98.getMachineId)();
|
|
57276
57978
|
response.setHeader(DEFAULT_FRONTMCP_MACHINE_ID_HEADER, nodeId);
|
|
57277
|
-
const cookie = (0,
|
|
57979
|
+
const cookie = (0, import_utils98.buildSetCookie)({ name: DEFAULT_FRONTMCP_NODE_COOKIE, value: nodeId }, request);
|
|
57278
57980
|
if (cookie) {
|
|
57279
57981
|
const existing = response.getHeader("Set-Cookie");
|
|
57280
57982
|
const existingArr = Array.isArray(existing) ? existing : existing ? [String(existing)] : [];
|
|
@@ -57593,21 +58295,21 @@ var init_handle_streamable_http_flow = __esm({
|
|
|
57593
58295
|
});
|
|
57594
58296
|
|
|
57595
58297
|
// libs/sdk/src/transport/transport.error.ts
|
|
57596
|
-
var
|
|
58298
|
+
var import_utils99, JSON_RPC2, rpcError, rpcRequest;
|
|
57597
58299
|
var init_transport_error = __esm({
|
|
57598
58300
|
"libs/sdk/src/transport/transport.error.ts"() {
|
|
57599
58301
|
"use strict";
|
|
57600
|
-
|
|
58302
|
+
import_utils99 = require("@frontmcp/utils");
|
|
57601
58303
|
JSON_RPC2 = "2.0";
|
|
57602
58304
|
rpcError = (message, requestId) => ({
|
|
57603
58305
|
jsonrpc: JSON_RPC2,
|
|
57604
58306
|
error: { code: -32e3, message },
|
|
57605
|
-
id: requestId ?? (0,
|
|
58307
|
+
id: requestId ?? (0, import_utils99.randomUUID)()
|
|
57606
58308
|
// change it to request id + random
|
|
57607
58309
|
});
|
|
57608
58310
|
rpcRequest = (requestId, method, params) => ({
|
|
57609
58311
|
jsonrpc: JSON_RPC2,
|
|
57610
|
-
id: requestId ?? (0,
|
|
58312
|
+
id: requestId ?? (0, import_utils99.randomUUID)(),
|
|
57611
58313
|
method,
|
|
57612
58314
|
...params !== void 0 && { params }
|
|
57613
58315
|
});
|
|
@@ -57670,14 +58372,14 @@ var init_host_validation = __esm({
|
|
|
57670
58372
|
});
|
|
57671
58373
|
|
|
57672
58374
|
// libs/sdk/src/transport/adapters/base-sse-transport.ts
|
|
57673
|
-
var import_content_type, import_raw_body, import_protocol55,
|
|
58375
|
+
var import_content_type, import_raw_body, import_protocol55, import_utils100, MAXIMUM_MESSAGE_SIZE, SSEServerTransport;
|
|
57674
58376
|
var init_base_sse_transport = __esm({
|
|
57675
58377
|
"libs/sdk/src/transport/adapters/base-sse-transport.ts"() {
|
|
57676
58378
|
"use strict";
|
|
57677
58379
|
import_content_type = __toESM(require("content-type"));
|
|
57678
58380
|
import_raw_body = __toESM(require("raw-body"));
|
|
57679
58381
|
import_protocol55 = require("@frontmcp/protocol");
|
|
57680
|
-
|
|
58382
|
+
import_utils100 = require("@frontmcp/utils");
|
|
57681
58383
|
init_transport_errors();
|
|
57682
58384
|
init_host_validation();
|
|
57683
58385
|
MAXIMUM_MESSAGE_SIZE = "4mb";
|
|
@@ -57688,7 +58390,7 @@ var init_base_sse_transport = __esm({
|
|
|
57688
58390
|
constructor(_endpoint, res, options) {
|
|
57689
58391
|
this._endpoint = _endpoint;
|
|
57690
58392
|
this.res = res;
|
|
57691
|
-
this._sessionId = options?.sessionId ?? (0,
|
|
58393
|
+
this._sessionId = options?.sessionId ?? (0, import_utils100.randomUUID)();
|
|
57692
58394
|
this._options = options || { enableDnsRebindingProtection: false };
|
|
57693
58395
|
}
|
|
57694
58396
|
_endpoint;
|
|
@@ -59134,11 +59836,11 @@ var init_transport_remote = __esm({
|
|
|
59134
59836
|
});
|
|
59135
59837
|
|
|
59136
59838
|
// libs/sdk/src/transport/transport.registry.ts
|
|
59137
|
-
var
|
|
59839
|
+
var import_utils101, TransportService;
|
|
59138
59840
|
var init_transport_registry = __esm({
|
|
59139
59841
|
"libs/sdk/src/transport/transport.registry.ts"() {
|
|
59140
59842
|
"use strict";
|
|
59141
|
-
|
|
59843
|
+
import_utils101 = require("@frontmcp/utils");
|
|
59142
59844
|
init_session_store_factory();
|
|
59143
59845
|
init_transport_errors();
|
|
59144
59846
|
init_handle_mcp_20260728_flow();
|
|
@@ -59430,7 +60132,7 @@ var init_transport_registry = __esm({
|
|
|
59430
60132
|
protocol: storedSession.session.protocol,
|
|
59431
60133
|
createdAt: storedSession.createdAt
|
|
59432
60134
|
});
|
|
59433
|
-
const currentNodeId = (0,
|
|
60135
|
+
const currentNodeId = (0, import_utils101.getMachineId)();
|
|
59434
60136
|
if (this.scope.haManager && storedSession.session.nodeId && storedSession.session.nodeId !== currentNodeId) {
|
|
59435
60137
|
const sessionKey = `${this.transportKeyPrefix}${sessionId}`;
|
|
59436
60138
|
const result = await this.scope.haManager.attemptTakeover(sessionKey, storedSession.session.nodeId);
|
|
@@ -59525,7 +60227,7 @@ var init_transport_registry = __esm({
|
|
|
59525
60227
|
authorizationId: key.tokenHash,
|
|
59526
60228
|
protocol: type === "sse" ? "sse" : "streamable-http",
|
|
59527
60229
|
createdAt: Date.now(),
|
|
59528
|
-
nodeId: (0,
|
|
60230
|
+
nodeId: (0, import_utils101.getMachineId)()
|
|
59529
60231
|
},
|
|
59530
60232
|
authorizationId: key.tokenHash,
|
|
59531
60233
|
createdAt: Date.now(),
|
|
@@ -59671,7 +60373,7 @@ var init_transport_registry = __esm({
|
|
|
59671
60373
|
}
|
|
59672
60374
|
/* --------------------------------- internals -------------------------------- */
|
|
59673
60375
|
sha256(value) {
|
|
59674
|
-
return (0,
|
|
60376
|
+
return (0, import_utils101.sha256Hex)(value);
|
|
59675
60377
|
}
|
|
59676
60378
|
/**
|
|
59677
60379
|
* Create a history key from components.
|
|
@@ -59855,9 +60557,9 @@ function persistentSessionCallerKey(authorization) {
|
|
|
59855
60557
|
const sub = authorization?.user?.sub;
|
|
59856
60558
|
if (!(0, import_auth56.isAnonymousSubject)(sub)) {
|
|
59857
60559
|
const iss = authorization?.user?.iss;
|
|
59858
|
-
return `sub:${(0,
|
|
60560
|
+
return `sub:${(0, import_utils102.sha256Hex)(JSON.stringify([typeof iss === "string" ? iss : "", sub]))}`;
|
|
59859
60561
|
}
|
|
59860
|
-
if (authorization?.token) return `token:${(0,
|
|
60562
|
+
if (authorization?.token) return `token:${(0, import_utils102.sha256Hex)(authorization.token)}`;
|
|
59861
60563
|
return null;
|
|
59862
60564
|
}
|
|
59863
60565
|
function claimPersistentSession(session, callerKey, store) {
|
|
@@ -59870,12 +60572,12 @@ function claimPersistentSession(session, callerKey, store) {
|
|
|
59870
60572
|
}
|
|
59871
60573
|
return owners.get(session) === callerKey ? "owner" : "refused";
|
|
59872
60574
|
}
|
|
59873
|
-
var import_auth56,
|
|
60575
|
+
var import_auth56, import_utils102, owners;
|
|
59874
60576
|
var init_persistent_session_owner = __esm({
|
|
59875
60577
|
"libs/sdk/src/transport/persistent-session-owner.ts"() {
|
|
59876
60578
|
"use strict";
|
|
59877
60579
|
import_auth56 = require("@frontmcp/auth");
|
|
59878
|
-
|
|
60580
|
+
import_utils102 = require("@frontmcp/utils");
|
|
59879
60581
|
owners = /* @__PURE__ */ new WeakMap();
|
|
59880
60582
|
}
|
|
59881
60583
|
});
|
|
@@ -59912,7 +60614,7 @@ async function runWebStandardMcp(scope, request, options) {
|
|
|
59912
60614
|
if (options.persistent) {
|
|
59913
60615
|
return options.persistent.transport.handleRequest(request, { authInfo: options.authInfo });
|
|
59914
60616
|
}
|
|
59915
|
-
const sessionId = `web:${(0,
|
|
60617
|
+
const sessionId = `web:${(0, import_utils103.randomUUID)()}`;
|
|
59916
60618
|
const accept = request.headers.get("accept") ?? "";
|
|
59917
60619
|
const wantsStream = request.method === "GET" || options.sse && accept.includes("text/event-stream");
|
|
59918
60620
|
const { mcpServer, transport } = await wireServer(scope, options.serverOptions, sessionId, void 0, !wantsStream);
|
|
@@ -59935,23 +60637,23 @@ async function runWebStandardMcp(scope, request, options) {
|
|
|
59935
60637
|
}
|
|
59936
60638
|
return response;
|
|
59937
60639
|
}
|
|
59938
|
-
var
|
|
60640
|
+
var import_utils103;
|
|
59939
60641
|
var init_web_standard_mcp = __esm({
|
|
59940
60642
|
"libs/sdk/src/transport/web-standard-mcp.ts"() {
|
|
59941
60643
|
"use strict";
|
|
59942
|
-
|
|
60644
|
+
import_utils103 = require("@frontmcp/utils");
|
|
59943
60645
|
init_build_scoped_server_options();
|
|
59944
60646
|
}
|
|
59945
60647
|
});
|
|
59946
60648
|
|
|
59947
60649
|
// libs/sdk/src/scope/flows/http.request.flow.ts
|
|
59948
|
-
var import_auth57, import_lazy_zod108,
|
|
60650
|
+
var import_auth57, import_lazy_zod108, import_utils104, plan42, httpRequestStateSchema, name43, Stage43, HttpRequestFlow;
|
|
59949
60651
|
var init_http_request_flow = __esm({
|
|
59950
60652
|
"libs/sdk/src/scope/flows/http.request.flow.ts"() {
|
|
59951
60653
|
"use strict";
|
|
59952
60654
|
import_auth57 = require("@frontmcp/auth");
|
|
59953
60655
|
import_lazy_zod108 = require("@frontmcp/lazy-zod");
|
|
59954
|
-
|
|
60656
|
+
import_utils104 = require("@frontmcp/utils");
|
|
59955
60657
|
init_session_verify_flow();
|
|
59956
60658
|
init_common();
|
|
59957
60659
|
init_schema7();
|
|
@@ -60030,7 +60732,7 @@ var init_http_request_flow = __esm({
|
|
|
60030
60732
|
const { request } = this.rawInput;
|
|
60031
60733
|
this.requestStartTime = Date.now();
|
|
60032
60734
|
const ctx = this.tryGetContext();
|
|
60033
|
-
this.requestId = ctx?.requestId ?? `req-${(0,
|
|
60735
|
+
this.requestId = ctx?.requestId ?? `req-${(0, import_utils104.randomUUID)()}`;
|
|
60034
60736
|
const headers = request.headers ?? {};
|
|
60035
60737
|
const body = request.body;
|
|
60036
60738
|
const userAgent = headers["user-agent"];
|
|
@@ -60102,7 +60804,10 @@ var init_http_request_flow = __esm({
|
|
|
60102
60804
|
const { request } = this.rawInput;
|
|
60103
60805
|
this.logger.verbose(`[${this.requestId}] checkAuthorization: verifying session`);
|
|
60104
60806
|
try {
|
|
60105
|
-
const result = await this.scope.runFlow("session:verify", {
|
|
60807
|
+
const result = await this.scope.runFlow("session:verify", {
|
|
60808
|
+
request,
|
|
60809
|
+
sessionless: this.servesProtocol20260728()
|
|
60810
|
+
});
|
|
60106
60811
|
if (!result) {
|
|
60107
60812
|
this.logger.error(`[${this.requestId}] failed to verify session`);
|
|
60108
60813
|
throw new SessionVerificationFailedError();
|
|
@@ -60712,13 +61417,13 @@ var init_http_request_flow = __esm({
|
|
|
60712
61417
|
});
|
|
60713
61418
|
|
|
60714
61419
|
// libs/sdk/src/scope/scope.instance.ts
|
|
60715
|
-
var import_reflect_metadata25, import_guard8,
|
|
61420
|
+
var import_reflect_metadata25, import_guard8, import_utils105, SCOPE_NON_DISPATCHABLE_FLOWS, Scope;
|
|
60716
61421
|
var init_scope_instance = __esm({
|
|
60717
61422
|
"libs/sdk/src/scope/scope.instance.ts"() {
|
|
60718
61423
|
"use strict";
|
|
60719
61424
|
import_reflect_metadata25 = require("reflect-metadata");
|
|
60720
61425
|
import_guard8 = require("@frontmcp/guard");
|
|
60721
|
-
|
|
61426
|
+
import_utils105 = require("@frontmcp/utils");
|
|
60722
61427
|
init_agent_registry();
|
|
60723
61428
|
init_call_agent_flow();
|
|
60724
61429
|
init_app_registry();
|
|
@@ -60761,6 +61466,7 @@ var init_scope_instance = __esm({
|
|
|
60761
61466
|
init_ui();
|
|
60762
61467
|
init_bus();
|
|
60763
61468
|
init_event_stores();
|
|
61469
|
+
init_request_state();
|
|
60764
61470
|
init_transport_registry();
|
|
60765
61471
|
init_http_ip_filter_flow();
|
|
60766
61472
|
init_http_request_flow();
|
|
@@ -60851,7 +61557,7 @@ var init_scope_instance = __esm({
|
|
|
60851
61557
|
await this.scopeProviders.ready;
|
|
60852
61558
|
const scopeRef = { kind: "scope", id: this.id, ref: _Scope };
|
|
60853
61559
|
const scopeProviders = this.scopeProviders;
|
|
60854
|
-
const perf = (0,
|
|
61560
|
+
const perf = (0, import_utils105.getEnvFlag)("FRONTMCP_PERF");
|
|
60855
61561
|
const t0 = perf ? performance.now() : 0;
|
|
60856
61562
|
const mark = perf ? (label) => this.logger.info(`[PERF] ${label}: ${(performance.now() - t0).toFixed(1)}ms`) : () => {
|
|
60857
61563
|
};
|
|
@@ -60861,13 +61567,13 @@ var init_scope_instance = __esm({
|
|
|
60861
61567
|
this.scopeApps = new AppRegistry(this.scopeProviders, this.metadata.apps, scopeRef);
|
|
60862
61568
|
this.logger.info(`Initializing ${this.metadata.apps.length} app(s)...`);
|
|
60863
61569
|
const transportConfig = this.metadata.transport;
|
|
60864
|
-
const isDistributed = (0,
|
|
61570
|
+
const isDistributed = (0, import_utils105.getRuntimeContext)().deployment === "distributed";
|
|
60865
61571
|
if (isDistributed && this.metadata.redis && !this.cliMode) {
|
|
60866
61572
|
try {
|
|
60867
61573
|
const haRedis = this.metadata.redis;
|
|
60868
61574
|
this.haManager = HaManager.create({
|
|
60869
61575
|
redis: haRedis,
|
|
60870
|
-
nodeId: (0,
|
|
61576
|
+
nodeId: (0, import_utils105.getMachineId)(),
|
|
60871
61577
|
logger: this.logger
|
|
60872
61578
|
});
|
|
60873
61579
|
await this.haManager.start();
|
|
@@ -60878,7 +61584,7 @@ var init_scope_instance = __esm({
|
|
|
60878
61584
|
}
|
|
60879
61585
|
let transportBus;
|
|
60880
61586
|
if (this.haManager && isDistributed && this.metadata.redis) {
|
|
60881
|
-
transportBus = new RedisTransportBus(this.metadata.redis, (0,
|
|
61587
|
+
transportBus = new RedisTransportBus(this.metadata.redis, (0, import_utils105.getMachineId)(), {
|
|
60882
61588
|
logger: this.logger
|
|
60883
61589
|
});
|
|
60884
61590
|
this.logger.info("[HA] Transport bus created for distributed session routing");
|
|
@@ -60889,6 +61595,7 @@ var init_scope_instance = __esm({
|
|
|
60889
61595
|
effectivePersistence = { sqlite: resolvedTopLevelSqlite };
|
|
60890
61596
|
}
|
|
60891
61597
|
this.transportService = new TransportService(this, effectivePersistence, transportBus);
|
|
61598
|
+
warnIfRequestStateKeyNotShared({ logger: this.logger, metadata: this.metadata });
|
|
60892
61599
|
if (this.haManager && isDistributed) {
|
|
60893
61600
|
const persistCfg = transportConfig?.persistence;
|
|
60894
61601
|
const resolvedPrefix = persistCfg && typeof persistCfg === "object" && persistCfg.redis?.keyPrefix ? persistCfg.redis.keyPrefix : "mcp:transport:";
|
|
@@ -60901,7 +61608,7 @@ var init_scope_instance = __esm({
|
|
|
60901
61608
|
}
|
|
60902
61609
|
});
|
|
60903
61610
|
}
|
|
60904
|
-
if ((0,
|
|
61611
|
+
if ((0, import_utils105.getRuntimeContext)().deployment === "serverless") {
|
|
60905
61612
|
const protocolCfg = transportConfig?.protocol;
|
|
60906
61613
|
const hasSSE = typeof protocolCfg === "string" ? protocolCfg !== "stateless-api" : protocolCfg?.sse === true;
|
|
60907
61614
|
if (hasSSE) {
|
|
@@ -60928,7 +61635,7 @@ var init_scope_instance = __esm({
|
|
|
60928
61635
|
sqlite: elicitationSqlite,
|
|
60929
61636
|
keyPrefix: elicitationRedis?.keyPrefix ?? "mcp:elicit:",
|
|
60930
61637
|
logger: this.logger,
|
|
60931
|
-
isEdgeRuntime: (0,
|
|
61638
|
+
isEdgeRuntime: (0, import_utils105.isEdgeRuntime)()
|
|
60932
61639
|
});
|
|
60933
61640
|
this._elicitationStore = elicitStore;
|
|
60934
61641
|
this.elicitationBackendType = elicitType;
|
|
@@ -60942,7 +61649,7 @@ var init_scope_instance = __esm({
|
|
|
60942
61649
|
);
|
|
60943
61650
|
const tasksEnabledForCli = this.cliMode && hasPersistentBackend;
|
|
60944
61651
|
const hasDistributedTaskBackend = Boolean(tasksConfig?.redis ?? this.metadata.redis);
|
|
60945
|
-
const onEdgeRuntime = (0,
|
|
61652
|
+
const onEdgeRuntime = (0, import_utils105.isEdgeRuntime)();
|
|
60946
61653
|
const tasksUnavailableOnEdge = onEdgeRuntime && !hasDistributedTaskBackend && !tasksExplicitlyEnabled;
|
|
60947
61654
|
if (tasksUnavailableOnEdge) {
|
|
60948
61655
|
this.logger.info(
|
|
@@ -61386,6 +62093,15 @@ var init_scope_instance = __esm({
|
|
|
61386
62093
|
notificationService: this.notificationService,
|
|
61387
62094
|
flowRegistry: this.scopeFlows,
|
|
61388
62095
|
toolRegistry: this.scopeTools,
|
|
62096
|
+
http: {
|
|
62097
|
+
server: this.server,
|
|
62098
|
+
checkClientIp: (request, response) => this.runFlow("http:ip-filter", {
|
|
62099
|
+
request,
|
|
62100
|
+
response
|
|
62101
|
+
}),
|
|
62102
|
+
entryPath: this.entryPath,
|
|
62103
|
+
routeBase: this.routeBase
|
|
62104
|
+
},
|
|
61389
62105
|
logger: this.logger
|
|
61390
62106
|
});
|
|
61391
62107
|
this._scopeChannels = channelResult.channelRegistry;
|
|
@@ -61790,12 +62506,12 @@ var init_scope_instance = __esm({
|
|
|
61790
62506
|
return this._authoritiesScopeMapping;
|
|
61791
62507
|
}
|
|
61792
62508
|
/**
|
|
61793
|
-
* Collect
|
|
61794
|
-
*
|
|
61795
|
-
*
|
|
62509
|
+
* Collect the OAuth scopes entries declare on their `authProviders`. The PRM
|
|
62510
|
+
* endpoint advertises them in `scopes_supported` (RFC 9728) next to the scopes
|
|
62511
|
+
* the auth mode grants (`resourceScopesFor`), not a fixed OIDC list (#629).
|
|
61796
62512
|
*/
|
|
61797
62513
|
getAllSupportedScopes() {
|
|
61798
|
-
const scopes = /* @__PURE__ */ new Set(
|
|
62514
|
+
const scopes = /* @__PURE__ */ new Set();
|
|
61799
62515
|
const collectScopes = (metadata) => {
|
|
61800
62516
|
const authProviders = metadata?.["authProviders"];
|
|
61801
62517
|
if (!Array.isArray(authProviders)) return;
|
|
@@ -63362,7 +64078,7 @@ async function runHttpRequestFlowWeb(scope, request, opts = {}) {
|
|
|
63362
64078
|
const serverRequest = await toServerRequest(request, url, opts.ctx, opts.persistent, opts.env);
|
|
63363
64079
|
let output;
|
|
63364
64080
|
try {
|
|
63365
|
-
output = await (0,
|
|
64081
|
+
output = await (0, import_utils106.runRequestExclusive)(
|
|
63366
64082
|
() => scope.runFlow("http:request", {
|
|
63367
64083
|
request: serverRequest,
|
|
63368
64084
|
response: {}
|
|
@@ -63380,7 +64096,7 @@ async function runMatchingHttpFlowWeb(scope, request, opts = {}) {
|
|
|
63380
64096
|
if (!flowName) return void 0;
|
|
63381
64097
|
let output;
|
|
63382
64098
|
try {
|
|
63383
|
-
output = await (0,
|
|
64099
|
+
output = await (0, import_utils106.runRequestExclusive)(
|
|
63384
64100
|
() => scope.runFlow(flowName, {
|
|
63385
64101
|
request: serverRequest,
|
|
63386
64102
|
response: {}
|
|
@@ -63458,10 +64174,57 @@ function findMisconfiguration(error) {
|
|
|
63458
64174
|
if (typeof code === "string" && MISCONFIGURATION_REMEDIES[code]) {
|
|
63459
64175
|
return { code, remedy: MISCONFIGURATION_REMEDIES[code] };
|
|
63460
64176
|
}
|
|
64177
|
+
if (current.name === "ZodError") return { code: "CONFIG_INVALID", remedy: CONFIG_INVALID_REMEDY };
|
|
63461
64178
|
current = current.cause;
|
|
63462
64179
|
}
|
|
63463
64180
|
return void 0;
|
|
63464
64181
|
}
|
|
64182
|
+
function createDeferredServerBuild(build, options = {}) {
|
|
64183
|
+
const now = options.now ?? Date.now;
|
|
64184
|
+
let built;
|
|
64185
|
+
let inFlight;
|
|
64186
|
+
let failure;
|
|
64187
|
+
return {
|
|
64188
|
+
get(arg) {
|
|
64189
|
+
if (built) return Promise.resolve(built.value);
|
|
64190
|
+
if (inFlight) return inFlight;
|
|
64191
|
+
if (failure && now() < failure.retryAt) return Promise.reject(failure.error);
|
|
64192
|
+
const failures = failure?.count ?? 0;
|
|
64193
|
+
inFlight = build(arg).then(
|
|
64194
|
+
(value) => {
|
|
64195
|
+
built = { value };
|
|
64196
|
+
failure = void 0;
|
|
64197
|
+
inFlight = void 0;
|
|
64198
|
+
return value;
|
|
64199
|
+
},
|
|
64200
|
+
(error) => {
|
|
64201
|
+
const delay = Math.min(STARTUP_RETRY_MAX_MS, STARTUP_RETRY_MIN_MS * 2 ** failures);
|
|
64202
|
+
failure = { error, retryAt: now() + delay, count: failures + 1 };
|
|
64203
|
+
inFlight = void 0;
|
|
64204
|
+
options.onFailure?.(error);
|
|
64205
|
+
throw error;
|
|
64206
|
+
}
|
|
64207
|
+
);
|
|
64208
|
+
return inFlight;
|
|
64209
|
+
},
|
|
64210
|
+
retryAfterSeconds() {
|
|
64211
|
+
if (!failure) return 0;
|
|
64212
|
+
return Math.max(1, Math.ceil((failure.retryAt - now()) / 1e3));
|
|
64213
|
+
}
|
|
64214
|
+
};
|
|
64215
|
+
}
|
|
64216
|
+
function startupFailureResponse(error, retryAfterSeconds = 1) {
|
|
64217
|
+
const misconfigured = misconfigurationResponse(error);
|
|
64218
|
+
if (misconfigured) return misconfigured;
|
|
64219
|
+
return Response.json(
|
|
64220
|
+
{
|
|
64221
|
+
error: "server_unavailable",
|
|
64222
|
+
code: "SERVER_START_FAILED",
|
|
64223
|
+
message: "The server failed to start, so it refuses requests. Its log has the cause; a request after the Retry-After delay tries to start it again."
|
|
64224
|
+
},
|
|
64225
|
+
{ status: 503, headers: { "Retry-After": String(Math.max(1, retryAfterSeconds)) } }
|
|
64226
|
+
);
|
|
64227
|
+
}
|
|
63465
64228
|
function flowErrorToHttpOutput(error) {
|
|
63466
64229
|
const misconfiguration = findMisconfiguration(error);
|
|
63467
64230
|
if (misconfiguration) {
|
|
@@ -63495,11 +64258,11 @@ function flowErrorToHttpOutput(error) {
|
|
|
63495
64258
|
}
|
|
63496
64259
|
return { kind: "text", status: 500, body: "Internal Server Error", contentType: "text/plain; charset=utf-8" };
|
|
63497
64260
|
}
|
|
63498
|
-
var
|
|
64261
|
+
var import_utils106, CLOUDFLARE_WORKERS_USER_AGENT, MISCONFIGURATION_REMEDIES, CONFIG_INVALID_REMEDY, STARTUP_RETRY_MIN_MS, STARTUP_RETRY_MAX_MS;
|
|
63499
64262
|
var init_web_fetch_handler = __esm({
|
|
63500
64263
|
"libs/sdk/src/transport/web-fetch-handler.ts"() {
|
|
63501
64264
|
"use strict";
|
|
63502
|
-
|
|
64265
|
+
import_utils106 = require("@frontmcp/utils");
|
|
63503
64266
|
init_common();
|
|
63504
64267
|
init_server_tokens();
|
|
63505
64268
|
init_path_utils();
|
|
@@ -63515,6 +64278,9 @@ var init_web_fetch_handler = __esm({
|
|
|
63515
64278
|
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.",
|
|
63516
64279
|
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."
|
|
63517
64280
|
};
|
|
64281
|
+
CONFIG_INVALID_REMEDY = "The FrontMCP configuration failed validation, so the server refuses to start. The server log names the invalid fields.";
|
|
64282
|
+
STARTUP_RETRY_MIN_MS = 1e3;
|
|
64283
|
+
STARTUP_RETRY_MAX_MS = 6e4;
|
|
63518
64284
|
}
|
|
63519
64285
|
});
|
|
63520
64286
|
|
|
@@ -63544,9 +64310,9 @@ var init_noop_server = __esm({
|
|
|
63544
64310
|
});
|
|
63545
64311
|
|
|
63546
64312
|
// libs/sdk/src/server/security/security-audit.ts
|
|
63547
|
-
function auditSecurityDefaults(config,
|
|
64313
|
+
function auditSecurityDefaults(config, isProduction7) {
|
|
63548
64314
|
const findings = [];
|
|
63549
|
-
if (!
|
|
64315
|
+
if (!isProduction7 && config.deploymentMode !== "distributed") {
|
|
63550
64316
|
return findings;
|
|
63551
64317
|
}
|
|
63552
64318
|
const strict = config.security?.strict === true;
|
|
@@ -63780,14 +64546,14 @@ var init_base_host_adapter = __esm({
|
|
|
63780
64546
|
});
|
|
63781
64547
|
|
|
63782
64548
|
// libs/sdk/src/server/adapters/express.host.adapter.ts
|
|
63783
|
-
var http, import_cors, import_express,
|
|
64549
|
+
var http, import_cors, import_express, import_utils107, DEFAULT_EXPRESS_BODY_LIMIT, ExpressHostAdapter;
|
|
63784
64550
|
var init_express_host_adapter = __esm({
|
|
63785
64551
|
"libs/sdk/src/server/adapters/express.host.adapter.ts"() {
|
|
63786
64552
|
"use strict";
|
|
63787
64553
|
http = __toESM(require("node:http"));
|
|
63788
64554
|
import_cors = __toESM(require("cors"));
|
|
63789
64555
|
import_express = __toESM(require("express"));
|
|
63790
|
-
|
|
64556
|
+
import_utils107 = require("@frontmcp/utils");
|
|
63791
64557
|
init_mcp_error();
|
|
63792
64558
|
init_host_validation_middleware();
|
|
63793
64559
|
init_resolve_allowed_hosts();
|
|
@@ -63970,8 +64736,8 @@ var init_express_host_adapter = __esm({
|
|
|
63970
64736
|
}
|
|
63971
64737
|
async cleanupStaleSocket(socketPath) {
|
|
63972
64738
|
try {
|
|
63973
|
-
if (await (0,
|
|
63974
|
-
await (0,
|
|
64739
|
+
if (await (0, import_utils107.fileExists)(socketPath)) {
|
|
64740
|
+
await (0, import_utils107.unlink)(socketPath);
|
|
63975
64741
|
}
|
|
63976
64742
|
} catch {
|
|
63977
64743
|
}
|
|
@@ -63994,11 +64760,11 @@ var init_node_express_host = __esm({
|
|
|
63994
64760
|
});
|
|
63995
64761
|
|
|
63996
64762
|
// libs/sdk/src/server/server.instance.ts
|
|
63997
|
-
var
|
|
64763
|
+
var import_utils108, DEFAULT_CORS, FrontMcpServerInstance;
|
|
63998
64764
|
var init_server_instance = __esm({
|
|
63999
64765
|
"libs/sdk/src/server/server.instance.ts"() {
|
|
64000
64766
|
"use strict";
|
|
64001
|
-
|
|
64767
|
+
import_utils108 = require("@frontmcp/utils");
|
|
64002
64768
|
init_common();
|
|
64003
64769
|
init_health2();
|
|
64004
64770
|
init_metrics2();
|
|
@@ -64100,9 +64866,9 @@ var init_server_instance = __esm({
|
|
|
64100
64866
|
}
|
|
64101
64867
|
async start() {
|
|
64102
64868
|
this.prepare();
|
|
64103
|
-
const deploymentMode = (0,
|
|
64869
|
+
const deploymentMode = (0, import_utils108.getRuntimeContext)().deployment;
|
|
64104
64870
|
const bindAddress = resolveBindAddress(this.config.security, deploymentMode);
|
|
64105
|
-
const
|
|
64871
|
+
const isProduction7 = process.env["NODE_ENV"] === "production";
|
|
64106
64872
|
const findings = auditSecurityDefaults(
|
|
64107
64873
|
{
|
|
64108
64874
|
cors: this.config.cors,
|
|
@@ -64110,7 +64876,7 @@ var init_server_instance = __esm({
|
|
|
64110
64876
|
resolvedBindAddress: bindAddress,
|
|
64111
64877
|
deploymentMode
|
|
64112
64878
|
},
|
|
64113
|
-
|
|
64879
|
+
isProduction7
|
|
64114
64880
|
);
|
|
64115
64881
|
logSecurityFindings(findings, console);
|
|
64116
64882
|
await this.host.start(this.config.socketPath ?? this.config.port, bindAddress);
|
|
@@ -64338,11 +65104,11 @@ function resolveConfigInput(optionsOrClass) {
|
|
|
64338
65104
|
}
|
|
64339
65105
|
return optionsOrClass;
|
|
64340
65106
|
}
|
|
64341
|
-
var
|
|
65107
|
+
var import_utils109, stdioServing, FrontMcpInstance;
|
|
64342
65108
|
var init_front_mcp = __esm({
|
|
64343
65109
|
"libs/sdk/src/front-mcp/front-mcp.ts"() {
|
|
64344
65110
|
"use strict";
|
|
64345
|
-
|
|
65111
|
+
import_utils109 = require("@frontmcp/utils");
|
|
64346
65112
|
init_common();
|
|
64347
65113
|
init_direct();
|
|
64348
65114
|
init_errors();
|
|
@@ -64527,11 +65293,16 @@ var init_front_mcp = __esm({
|
|
|
64527
65293
|
*/
|
|
64528
65294
|
static async createFetchHandler(options) {
|
|
64529
65295
|
const build = async (deferred) => {
|
|
64530
|
-
|
|
65296
|
+
let frontMcp;
|
|
64531
65297
|
try {
|
|
65298
|
+
frontMcp = new _FrontMcpInstance2(frontMcpMetadataSchema.parse(options));
|
|
64532
65299
|
await frontMcp.ready;
|
|
64533
65300
|
} catch (err) {
|
|
64534
|
-
if (deferred)
|
|
65301
|
+
if (deferred) {
|
|
65302
|
+
const message = "FrontMCP failed to start; requests are refused until a retry succeeds";
|
|
65303
|
+
if (frontMcp?.log) frontMcp.log.error(message, err);
|
|
65304
|
+
else console.error(`[frontmcp] ${message}`, err);
|
|
65305
|
+
}
|
|
64535
65306
|
throw err;
|
|
64536
65307
|
}
|
|
64537
65308
|
const scope = frontMcp.getPrimaryScope();
|
|
@@ -64541,25 +65312,15 @@ var init_front_mcp = __esm({
|
|
|
64541
65312
|
frontMcp.log?.info("FrontMCP fetch handler created (web-standard transport)");
|
|
64542
65313
|
return createWebFetchHandler(scope);
|
|
64543
65314
|
};
|
|
64544
|
-
if (!(0,
|
|
65315
|
+
if (!(0, import_utils109.isEdgeRuntime)()) return build(false);
|
|
64545
65316
|
assertStaticStartupConfig(options);
|
|
64546
|
-
|
|
64547
|
-
let building;
|
|
65317
|
+
const server = createDeferredServerBuild(() => build(true));
|
|
64548
65318
|
return async (request, ctx, env) => {
|
|
64549
|
-
|
|
64550
|
-
|
|
64551
|
-
|
|
64552
|
-
|
|
64553
|
-
|
|
64554
|
-
});
|
|
64555
|
-
}
|
|
64556
|
-
try {
|
|
64557
|
-
inner = await building;
|
|
64558
|
-
} catch (err) {
|
|
64559
|
-
const misconfigured = misconfigurationResponse(err);
|
|
64560
|
-
if (misconfigured) return misconfigured;
|
|
64561
|
-
throw err;
|
|
64562
|
-
}
|
|
65319
|
+
let inner;
|
|
65320
|
+
try {
|
|
65321
|
+
inner = await server.get();
|
|
65322
|
+
} catch (err) {
|
|
65323
|
+
return startupFailureResponse(err, server.retryAfterSeconds());
|
|
64563
65324
|
}
|
|
64564
65325
|
return inner(request, ctx, env);
|
|
64565
65326
|
};
|
|
@@ -64696,8 +65457,8 @@ var init_front_mcp = __esm({
|
|
|
64696
65457
|
frontMcp.log?.info(`MCP server listening on unix://${socketPath}`);
|
|
64697
65458
|
const cleanup = async () => {
|
|
64698
65459
|
try {
|
|
64699
|
-
if (await (0,
|
|
64700
|
-
await (0,
|
|
65460
|
+
if (await (0, import_utils109.fileExists)(socketPath)) {
|
|
65461
|
+
await (0, import_utils109.unlink)(socketPath);
|
|
64701
65462
|
}
|
|
64702
65463
|
} catch {
|
|
64703
65464
|
}
|
|
@@ -64841,7 +65602,7 @@ var init_front_mcp = __esm({
|
|
|
64841
65602
|
};
|
|
64842
65603
|
const mcpServer = new McpServer2(scope.metadata.info, serverOptions);
|
|
64843
65604
|
startupCleanups.push(() => mcpServer.close());
|
|
64844
|
-
const sessionId = `stdio:${(0,
|
|
65605
|
+
const sessionId = `stdio:${(0, import_utils109.randomUUID)()}`;
|
|
64845
65606
|
const handlers = createMcpHandlers2({ scope, serverOptions, composeInstructions });
|
|
64846
65607
|
for (const handler of handlers) {
|
|
64847
65608
|
const originalHandler = handler.handler;
|
|
@@ -65161,9 +65922,9 @@ function FrontMcp(providedMetadata) {
|
|
|
65161
65922
|
Reflect.defineMetadata(FrontMcpTokens[property] ?? property, metadata[property], target);
|
|
65162
65923
|
}
|
|
65163
65924
|
Reflect.defineMetadata(FRONTMCP_CONFIG_METADATA_KEY, metadata, target);
|
|
65164
|
-
const isServerless2 = (0,
|
|
65165
|
-
const isSchemaExtract = (0,
|
|
65166
|
-
const isStdio = (0,
|
|
65925
|
+
const isServerless2 = (0, import_utils110.getEnvFlag)("FRONTMCP_SERVERLESS");
|
|
65926
|
+
const isSchemaExtract = (0, import_utils110.getEnvFlag)("FRONTMCP_SCHEMA_EXTRACT");
|
|
65927
|
+
const isStdio = (0, import_utils110.getEnvFlag)("FRONTMCP_STDIO");
|
|
65167
65928
|
const taskWorkerId = typeof process !== "undefined" ? process.env?.["FRONTMCP_RUN_TASK_ID"] : void 0;
|
|
65168
65929
|
if (taskWorkerId && metadata.serve !== false) {
|
|
65169
65930
|
void (async () => {
|
|
@@ -65189,7 +65950,7 @@ function FrontMcp(providedMetadata) {
|
|
|
65189
65950
|
} else if (isServerless2) {
|
|
65190
65951
|
const ServerlessInstance = getFrontMcpInstance();
|
|
65191
65952
|
const { setServerlessHandler: setServerlessHandler2, setServerlessHandlerPromise: setServerlessHandlerPromise2, setServerlessHandlerError: setServerlessHandlerError2 } = getServerlessHandlerFns();
|
|
65192
|
-
const isWorker = (0,
|
|
65953
|
+
const isWorker = (0, import_utils110.getEnvFlag)("FRONTMCP_WORKER");
|
|
65193
65954
|
const handlerPromise = isWorker ? ServerlessInstance.createFetchHandler(metadata) : ServerlessInstance.createHandler(metadata);
|
|
65194
65955
|
setServerlessHandlerPromise2(handlerPromise);
|
|
65195
65956
|
handlerPromise.then(setServerlessHandler2).catch((err) => {
|
|
@@ -65202,12 +65963,12 @@ function FrontMcp(providedMetadata) {
|
|
|
65202
65963
|
}
|
|
65203
65964
|
};
|
|
65204
65965
|
}
|
|
65205
|
-
var import_reflect_metadata28,
|
|
65966
|
+
var import_reflect_metadata28, import_utils110, FRONT_MCP_DECORATOR_BASENAMES, FRONTMCP_CONFIG_METADATA_KEY, _FrontMcpInstance, _serverlessHandlerFns;
|
|
65206
65967
|
var init_front_mcp_decorator = __esm({
|
|
65207
65968
|
"libs/sdk/src/common/decorators/front-mcp.decorator.ts"() {
|
|
65208
65969
|
"use strict";
|
|
65209
65970
|
import_reflect_metadata28 = require("reflect-metadata");
|
|
65210
|
-
|
|
65971
|
+
import_utils110 = require("@frontmcp/utils");
|
|
65211
65972
|
init_decorator_errors();
|
|
65212
65973
|
init_mcp_error();
|
|
65213
65974
|
init_metadata();
|
|
@@ -65960,49 +66721,6 @@ var init_dynamic_adapter = __esm({
|
|
|
65960
66721
|
}
|
|
65961
66722
|
});
|
|
65962
66723
|
|
|
65963
|
-
// libs/sdk/src/common/dynamic/dynamic.plugin.ts
|
|
65964
|
-
function isDynamicPluginClass(value) {
|
|
65965
|
-
return typeof value === "function" && value.prototype instanceof DynamicPlugin;
|
|
65966
|
-
}
|
|
65967
|
-
var DynamicPlugin;
|
|
65968
|
-
var init_dynamic_plugin = __esm({
|
|
65969
|
-
"libs/sdk/src/common/dynamic/dynamic.plugin.ts"() {
|
|
65970
|
-
"use strict";
|
|
65971
|
-
init_transport_errors();
|
|
65972
|
-
init_dynamic_utils();
|
|
65973
|
-
DynamicPlugin = class {
|
|
65974
|
-
get(token) {
|
|
65975
|
-
throw new MethodNotImplementedError("DynamicPlugin", "get");
|
|
65976
|
-
}
|
|
65977
|
-
/**
|
|
65978
|
-
* Static init() method to create a plugin provider.
|
|
65979
|
-
* @param options - Input options (with optional fields for defaults)
|
|
65980
|
-
*/
|
|
65981
|
-
static init(options) {
|
|
65982
|
-
const extraProviders = options.providers;
|
|
65983
|
-
const typedOptions = options;
|
|
65984
|
-
if ("useFactory" in options) {
|
|
65985
|
-
return {
|
|
65986
|
-
...typedOptions,
|
|
65987
|
-
provide: this,
|
|
65988
|
-
inject: options.inject,
|
|
65989
|
-
useFactory: options.useFactory,
|
|
65990
|
-
providers: dedupePluginProviders(extraProviders ?? [])
|
|
65991
|
-
};
|
|
65992
|
-
}
|
|
65993
|
-
const dyn = collectDynamicProviders(this, typedOptions);
|
|
65994
|
-
const mergedProviders = dedupePluginProviders([...dyn ?? [], ...extraProviders ?? []]);
|
|
65995
|
-
return {
|
|
65996
|
-
...typedOptions,
|
|
65997
|
-
provide: this,
|
|
65998
|
-
useValue: new this(options),
|
|
65999
|
-
providers: mergedProviders
|
|
66000
|
-
};
|
|
66001
|
-
}
|
|
66002
|
-
};
|
|
66003
|
-
}
|
|
66004
|
-
});
|
|
66005
|
-
|
|
66006
66724
|
// libs/sdk/src/common/dynamic/index.ts
|
|
66007
66725
|
var init_dynamic = __esm({
|
|
66008
66726
|
"libs/sdk/src/common/dynamic/index.ts"() {
|
|
@@ -66166,12 +66884,12 @@ var init_adapter_entry = __esm({
|
|
|
66166
66884
|
});
|
|
66167
66885
|
|
|
66168
66886
|
// libs/sdk/src/common/entries/tool.entry.ts
|
|
66169
|
-
var import_lazy_zod109,
|
|
66887
|
+
var import_lazy_zod109, import_utils112, ToolEntry;
|
|
66170
66888
|
var init_tool_entry = __esm({
|
|
66171
66889
|
"libs/sdk/src/common/entries/tool.entry.ts"() {
|
|
66172
66890
|
"use strict";
|
|
66173
66891
|
import_lazy_zod109 = require("@frontmcp/lazy-zod");
|
|
66174
|
-
|
|
66892
|
+
import_utils112 = require("@frontmcp/utils");
|
|
66175
66893
|
init_base_entry();
|
|
66176
66894
|
ToolEntry = class extends BaseEntry {
|
|
66177
66895
|
owner;
|
|
@@ -66238,7 +66956,7 @@ var init_tool_entry = __esm({
|
|
|
66238
66956
|
try {
|
|
66239
66957
|
return (0, import_lazy_zod109.toJSONSchema)(import_lazy_zod109.z.object(this.inputSchema), { io: "input", unrepresentable: "any" });
|
|
66240
66958
|
} catch (error) {
|
|
66241
|
-
if ((0,
|
|
66959
|
+
if ((0, import_utils112.isDebug)() || (0, import_utils112.isDevelopment)()) {
|
|
66242
66960
|
console.warn("[ToolEntry] Failed to convert Zod schema to JSON Schema:", error);
|
|
66243
66961
|
}
|
|
66244
66962
|
return { type: "object", properties: {} };
|
|
@@ -66284,7 +67002,7 @@ var init_tool_entry = __esm({
|
|
|
66284
67002
|
const json = (0, import_lazy_zod109.toJSONSchema)(zodSchema);
|
|
66285
67003
|
return json && json["type"] === "object" ? json : null;
|
|
66286
67004
|
} catch (error) {
|
|
66287
|
-
if ((0,
|
|
67005
|
+
if ((0, import_utils112.isDebug)() || (0, import_utils112.isDevelopment)()) {
|
|
66288
67006
|
console.warn("[ToolEntry] Failed to convert output Zod schema to JSON Schema:", error);
|
|
66289
67007
|
}
|
|
66290
67008
|
return null;
|
|
@@ -67476,6 +68194,7 @@ __export(index_exports, {
|
|
|
67476
68194
|
create: () => create,
|
|
67477
68195
|
createChildSpanContext: () => createChildSpanContext,
|
|
67478
68196
|
createContextResolver: () => createContextResolver,
|
|
68197
|
+
createDeferredServerBuild: () => createDeferredServerBuild,
|
|
67479
68198
|
createDirectResolver: () => createDirectResolver,
|
|
67480
68199
|
createElicitationStore: () => createElicitationStore,
|
|
67481
68200
|
createElicitationStoreFromStorage: () => createElicitationStoreFromStorage,
|
|
@@ -67583,6 +68302,7 @@ __export(index_exports, {
|
|
|
67583
68302
|
getElicitationSecret: () => getElicitationSecret,
|
|
67584
68303
|
getGlobalStoreConfig: () => getGlobalStoreConfig,
|
|
67585
68304
|
getNestedValue: () => getNestedValue,
|
|
68305
|
+
getPinnedPublicUrl: () => getPinnedPublicUrl,
|
|
67586
68306
|
getRegistryUrl: () => getRegistryUrl,
|
|
67587
68307
|
getRequestBaseUrl: () => getRequestBaseUrl,
|
|
67588
68308
|
getRunningTool: () => getRunningTool,
|
|
@@ -67600,6 +68320,7 @@ __export(index_exports, {
|
|
|
67600
68320
|
httpRequestInputSchema: () => httpRequestInputSchema,
|
|
67601
68321
|
httpRespond: () => httpRespond,
|
|
67602
68322
|
incrementalAuthConfigSchema: () => import_auth5.incrementalAuthConfigSchema,
|
|
68323
|
+
initOptionsOf: () => initOptionsOf,
|
|
67603
68324
|
intentSchema: () => intentSchema,
|
|
67604
68325
|
isAlive: () => isAlive,
|
|
67605
68326
|
isAnonymousSubject: () => import_auth61.isAnonymousSubject,
|
|
@@ -67758,6 +68479,7 @@ __export(index_exports, {
|
|
|
67758
68479
|
skillsConfigOptionsSchema: () => skillsConfigOptionsSchema,
|
|
67759
68480
|
skippedAppBehaviorSchema: () => import_auth5.skippedAppBehaviorSchema,
|
|
67760
68481
|
sqliteOptionsSchema: () => sqliteOptionsSchema,
|
|
68482
|
+
startupFailureResponse: () => startupFailureResponse,
|
|
67761
68483
|
staticAuthOptionsSchema: () => import_auth7.staticAuthOptionsSchema,
|
|
67762
68484
|
storageProviderSchema: () => storageProviderSchema,
|
|
67763
68485
|
supportsStreaming: () => supportsStreaming,
|
|
@@ -67945,22 +68667,22 @@ function createMemorySkillProvider(options = {}) {
|
|
|
67945
68667
|
init_skill_utils();
|
|
67946
68668
|
|
|
67947
68669
|
// libs/sdk/src/skill/skill-directory-loader.ts
|
|
67948
|
-
var
|
|
68670
|
+
var import_utils113 = require("@frontmcp/utils");
|
|
67949
68671
|
init_skill_metadata();
|
|
67950
68672
|
init_sdk_errors();
|
|
67951
68673
|
init_skill_md_parser();
|
|
67952
68674
|
async function scanSkillResources(dirPath) {
|
|
67953
68675
|
const resources = {};
|
|
67954
|
-
const scriptsPath = (0,
|
|
67955
|
-
const referencesPath = (0,
|
|
67956
|
-
const assetsPath = (0,
|
|
67957
|
-
const examplesPath = (0,
|
|
68676
|
+
const scriptsPath = (0, import_utils113.joinPath)(dirPath, "scripts");
|
|
68677
|
+
const referencesPath = (0, import_utils113.joinPath)(dirPath, "references");
|
|
68678
|
+
const assetsPath = (0, import_utils113.joinPath)(dirPath, "assets");
|
|
68679
|
+
const examplesPath = (0, import_utils113.joinPath)(dirPath, "examples");
|
|
67958
68680
|
const checks = await Promise.all([
|
|
67959
68681
|
checkDirectory(scriptsPath),
|
|
67960
68682
|
checkDirectory(referencesPath),
|
|
67961
68683
|
checkDirectory(assetsPath),
|
|
67962
68684
|
checkDirectory(examplesPath),
|
|
67963
|
-
(0,
|
|
68685
|
+
(0, import_utils113.fileExists)((0, import_utils113.joinPath)(dirPath, "SKILL.md"))
|
|
67964
68686
|
]);
|
|
67965
68687
|
if (checks[0]) resources.scripts = scriptsPath;
|
|
67966
68688
|
if (checks[1]) resources.references = referencesPath;
|
|
@@ -67973,7 +68695,7 @@ async function scanSkillResources(dirPath) {
|
|
|
67973
68695
|
}
|
|
67974
68696
|
async function checkDirectory(path3) {
|
|
67975
68697
|
try {
|
|
67976
|
-
const s = await (0,
|
|
68698
|
+
const s = await (0, import_utils113.stat)(path3);
|
|
67977
68699
|
return s.isDirectory();
|
|
67978
68700
|
} catch (err) {
|
|
67979
68701
|
if (err.code === "ENOENT") return false;
|
|
@@ -67986,16 +68708,16 @@ async function findNestedSkillMd(dirPath, maxDepth = Number.POSITIVE_INFINITY) {
|
|
|
67986
68708
|
if (depth > maxDepth) return;
|
|
67987
68709
|
let entries;
|
|
67988
68710
|
try {
|
|
67989
|
-
entries = await (0,
|
|
68711
|
+
entries = await (0, import_utils113.readdir)(current);
|
|
67990
68712
|
} catch (err) {
|
|
67991
68713
|
if (err.code === "ENOENT") return;
|
|
67992
68714
|
throw err;
|
|
67993
68715
|
}
|
|
67994
68716
|
for (const entry of entries) {
|
|
67995
|
-
const full = (0,
|
|
68717
|
+
const full = (0, import_utils113.joinPath)(current, entry);
|
|
67996
68718
|
let entryStat;
|
|
67997
68719
|
try {
|
|
67998
|
-
entryStat = await (0,
|
|
68720
|
+
entryStat = await (0, import_utils113.stat)(full);
|
|
67999
68721
|
} catch (err) {
|
|
68000
68722
|
if (err.code === "ENOENT") continue;
|
|
68001
68723
|
throw err;
|
|
@@ -68011,19 +68733,19 @@ async function findNestedSkillMd(dirPath, maxDepth = Number.POSITIVE_INFINITY) {
|
|
|
68011
68733
|
return found.sort();
|
|
68012
68734
|
}
|
|
68013
68735
|
async function loadSkillDirectory(dirPath, logger) {
|
|
68014
|
-
const skillMdPath = (0,
|
|
68015
|
-
const exists = await (0,
|
|
68736
|
+
const skillMdPath = (0, import_utils113.joinPath)(dirPath, "SKILL.md");
|
|
68737
|
+
const exists = await (0, import_utils113.fileExists)(skillMdPath);
|
|
68016
68738
|
if (!exists) {
|
|
68017
|
-
throw new InvalidSkillError((0,
|
|
68739
|
+
throw new InvalidSkillError((0, import_utils113.basename)(dirPath), "SKILL.md not found in directory");
|
|
68018
68740
|
}
|
|
68019
68741
|
let content;
|
|
68020
68742
|
let partialMetadata;
|
|
68021
68743
|
try {
|
|
68022
|
-
content = await (0,
|
|
68744
|
+
content = await (0, import_utils113.readFile)(skillMdPath, "utf-8");
|
|
68023
68745
|
const { frontmatter, body } = parseSkillMdFrontmatter(content);
|
|
68024
68746
|
partialMetadata = skillMdFrontmatterToMetadata(frontmatter, body);
|
|
68025
68747
|
} catch (err) {
|
|
68026
|
-
const name44 = (0,
|
|
68748
|
+
const name44 = (0, import_utils113.basename)(dirPath);
|
|
68027
68749
|
const message = err instanceof Error ? err.message : String(err);
|
|
68028
68750
|
throw new InvalidSkillError(name44, `Failed to read or parse SKILL.md: ${message}`);
|
|
68029
68751
|
}
|
|
@@ -68034,13 +68756,13 @@ async function loadSkillDirectory(dirPath, logger) {
|
|
|
68034
68756
|
}
|
|
68035
68757
|
const nested = await findNestedSkillMd(dirPath);
|
|
68036
68758
|
if (nested.length > 0) {
|
|
68037
|
-
const skillName2 = partialMetadata.name ?? (0,
|
|
68759
|
+
const skillName2 = partialMetadata.name ?? (0, import_utils113.basename)(dirPath);
|
|
68038
68760
|
throw new InvalidSkillError(
|
|
68039
68761
|
skillName2,
|
|
68040
68762
|
`Skill directory contains nested SKILL.md files (forbidden by SEP-2640 \xA7Resource Mapping): ${nested.join(", ")}`
|
|
68041
68763
|
);
|
|
68042
68764
|
}
|
|
68043
|
-
const dirName = (0,
|
|
68765
|
+
const dirName = (0, import_utils113.basename)(dirPath);
|
|
68044
68766
|
if (partialMetadata.name && dirName && partialMetadata.name !== dirName) {
|
|
68045
68767
|
const msg = `Skill name "${partialMetadata.name}" does not match directory name "${dirName}"`;
|
|
68046
68768
|
if (logger) {
|
|
@@ -68716,6 +69438,7 @@ var ChannelListHook = FlowHooksOf("channels:list");
|
|
|
68716
69438
|
create,
|
|
68717
69439
|
createChildSpanContext,
|
|
68718
69440
|
createContextResolver,
|
|
69441
|
+
createDeferredServerBuild,
|
|
68719
69442
|
createDirectResolver,
|
|
68720
69443
|
createElicitationStore,
|
|
68721
69444
|
createElicitationStoreFromStorage,
|
|
@@ -68822,6 +69545,7 @@ var ChannelListHook = FlowHooksOf("channels:list");
|
|
|
68822
69545
|
getElicitationSecret,
|
|
68823
69546
|
getGlobalStoreConfig,
|
|
68824
69547
|
getNestedValue,
|
|
69548
|
+
getPinnedPublicUrl,
|
|
68825
69549
|
getRegistryUrl,
|
|
68826
69550
|
getRequestBaseUrl,
|
|
68827
69551
|
getRunningTool,
|
|
@@ -68839,6 +69563,7 @@ var ChannelListHook = FlowHooksOf("channels:list");
|
|
|
68839
69563
|
httpRequestInputSchema,
|
|
68840
69564
|
httpRespond,
|
|
68841
69565
|
incrementalAuthConfigSchema,
|
|
69566
|
+
initOptionsOf,
|
|
68842
69567
|
intentSchema,
|
|
68843
69568
|
isAlive,
|
|
68844
69569
|
isAnonymousSubject,
|
|
@@ -68997,6 +69722,7 @@ var ChannelListHook = FlowHooksOf("channels:list");
|
|
|
68997
69722
|
skillsConfigOptionsSchema,
|
|
68998
69723
|
skippedAppBehaviorSchema,
|
|
68999
69724
|
sqliteOptionsSchema,
|
|
69725
|
+
startupFailureResponse,
|
|
69000
69726
|
staticAuthOptionsSchema,
|
|
69001
69727
|
storageProviderSchema,
|
|
69002
69728
|
supportsStreaming,
|