@frontmcp/sdk 1.0.0-beta.1 → 1.0.0-beta.11
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 +2 -2
- package/agent/agent.instance.d.ts.map +1 -1
- package/agent/agent.scope.d.ts +5 -4
- package/agent/agent.scope.d.ts.map +1 -1
- package/agent/flows/call-agent.flow.d.ts.map +1 -1
- package/app/instances/app.esm.instance.d.ts +7 -4
- package/app/instances/app.esm.instance.d.ts.map +1 -1
- package/app/instances/app.local.instance.d.ts +3 -3
- package/app/instances/app.local.instance.d.ts.map +1 -1
- package/app/instances/app.remote.instance.d.ts +7 -4
- package/app/instances/app.remote.instance.d.ts.map +1 -1
- package/auth/auth.registry.d.ts +2 -2
- package/auth/auth.registry.d.ts.map +1 -1
- package/auth/instances/instance.remote-primary-auth.d.ts.map +1 -1
- package/auth/session/utils/session-id.utils.d.ts +9 -6
- package/auth/session/utils/session-id.utils.d.ts.map +1 -1
- package/common/decorators/agent.decorator.d.ts +32 -7
- package/common/decorators/agent.decorator.d.ts.map +1 -1
- package/common/decorators/job.decorator.d.ts +56 -7
- package/common/decorators/job.decorator.d.ts.map +1 -1
- package/common/decorators/prompt.decorator.d.ts +7 -1
- package/common/decorators/prompt.decorator.d.ts.map +1 -1
- package/common/decorators/resource.decorator.d.ts +12 -2
- package/common/decorators/resource.decorator.d.ts.map +1 -1
- package/common/decorators/skill.decorator.d.ts.map +1 -1
- package/common/decorators/tool.decorator.d.ts +33 -42
- package/common/decorators/tool.decorator.d.ts.map +1 -1
- package/common/entries/app.entry.d.ts +8 -5
- package/common/entries/app.entry.d.ts.map +1 -1
- package/common/entries/plugin.entry.d.ts +1 -2
- package/common/entries/plugin.entry.d.ts.map +1 -1
- package/common/entries/provider.entry.d.ts +1 -2
- package/common/entries/provider.entry.d.ts.map +1 -1
- package/common/entries/resource.entry.d.ts +13 -0
- package/common/entries/resource.entry.d.ts.map +1 -1
- package/common/entries/scope.entry.d.ts +36 -8
- package/common/entries/scope.entry.d.ts.map +1 -1
- package/common/interfaces/app.interface.d.ts +1 -4
- package/common/interfaces/app.interface.d.ts.map +1 -1
- package/common/interfaces/internal/registry.interface.d.ts +15 -83
- package/common/interfaces/internal/registry.interface.d.ts.map +1 -1
- package/common/interfaces/plugin.interface.d.ts +1 -3
- package/common/interfaces/plugin.interface.d.ts.map +1 -1
- package/common/interfaces/provider.interface.d.ts +1 -3
- package/common/interfaces/provider.interface.d.ts.map +1 -1
- package/common/interfaces/resource.interface.d.ts +38 -0
- package/common/interfaces/resource.interface.d.ts.map +1 -1
- package/common/interfaces/scope.interface.d.ts +2 -4
- package/common/interfaces/scope.interface.d.ts.map +1 -1
- package/common/interfaces/skill.interface.d.ts +16 -0
- package/common/interfaces/skill.interface.d.ts.map +1 -1
- package/common/metadata/agent.metadata.d.ts +37 -6
- package/common/metadata/agent.metadata.d.ts.map +1 -1
- package/common/records/skill.record.d.ts +2 -0
- package/common/records/skill.record.d.ts.map +1 -1
- package/common/types/options/elicitation/schema.d.ts +2 -4
- package/common/types/options/elicitation/schema.d.ts.map +1 -1
- package/common/types/options/ext-apps/index.d.ts +1 -1
- package/common/types/options/ext-apps/index.d.ts.map +1 -1
- package/common/types/options/ext-apps/interfaces.d.ts +55 -0
- package/common/types/options/ext-apps/interfaces.d.ts.map +1 -1
- package/common/types/options/ext-apps/schema.d.ts +3 -1
- package/common/types/options/ext-apps/schema.d.ts.map +1 -1
- package/common/types/options/ext-apps/typecheck.d.ts +2 -0
- package/common/types/options/ext-apps/typecheck.d.ts.map +1 -0
- package/common/types/options/http/schema.d.ts +3 -1
- package/common/types/options/http/schema.d.ts.map +1 -1
- package/common/types/options/http/typecheck.d.ts +2 -0
- package/common/types/options/http/typecheck.d.ts.map +1 -0
- package/common/types/options/logging/schema.d.ts +3 -2
- package/common/types/options/logging/schema.d.ts.map +1 -1
- package/common/types/options/redis/index.d.ts +1 -1
- package/common/types/options/redis/index.d.ts.map +1 -1
- package/common/types/options/redis/interfaces.d.ts +4 -0
- package/common/types/options/redis/interfaces.d.ts.map +1 -1
- package/common/types/options/redis/schema.d.ts +7 -4
- package/common/types/options/redis/schema.d.ts.map +1 -1
- package/common/types/options/redis/typecheck.d.ts +2 -0
- package/common/types/options/redis/typecheck.d.ts.map +1 -0
- package/common/types/options/skills-http/schema.d.ts +3 -2
- package/common/types/options/skills-http/schema.d.ts.map +1 -1
- package/common/types/options/skills-http/typecheck.d.ts +2 -0
- package/common/types/options/skills-http/typecheck.d.ts.map +1 -0
- package/common/types/options/sqlite/index.d.ts +1 -0
- package/common/types/options/sqlite/index.d.ts.map +1 -1
- package/common/types/options/sqlite/interfaces.d.ts +25 -0
- package/common/types/options/sqlite/interfaces.d.ts.map +1 -0
- package/common/types/options/sqlite/schema.d.ts +3 -1
- package/common/types/options/sqlite/schema.d.ts.map +1 -1
- package/common/types/options/sqlite/typecheck.d.ts +2 -0
- package/common/types/options/sqlite/typecheck.d.ts.map +1 -0
- package/common/utils/decide-request-intent.utils.d.ts.map +1 -1
- package/completion/flows/complete.flow.d.ts.map +1 -1
- package/elicitation/flows/elicitation-request.flow.d.ts.map +1 -1
- package/elicitation/flows/elicitation-result.flow.d.ts.map +1 -1
- package/elicitation/helpers/fallback.helper.d.ts.map +1 -1
- package/elicitation/send-elicitation-result.tool.d.ts.map +1 -1
- package/errors/index.d.ts +1 -1
- package/errors/index.d.ts.map +1 -1
- package/errors/transport.errors.d.ts +6 -0
- package/errors/transport.errors.d.ts.map +1 -1
- package/esm/index.mjs +836 -286
- package/flows/flow.instance.d.ts +2 -3
- package/flows/flow.instance.d.ts.map +1 -1
- package/front-mcp/front-mcp.d.ts +2 -2
- package/front-mcp/front-mcp.d.ts.map +1 -1
- package/front-mcp/front-mcp.providers.d.ts.map +1 -1
- package/hooks/hook.registry.d.ts +2 -2
- package/hooks/hook.registry.d.ts.map +1 -1
- package/index.js +1050 -499
- package/job/job.instance.d.ts +2 -2
- package/job/job.instance.d.ts.map +1 -1
- package/notification/notification.service.d.ts +5 -1
- package/notification/notification.service.d.ts.map +1 -1
- package/package.json +10 -10
- package/plugin/plugin.registry.d.ts +9 -4
- package/plugin/plugin.registry.d.ts.map +1 -1
- package/prompt/prompt.instance.d.ts +2 -2
- package/prompt/prompt.instance.d.ts.map +1 -1
- package/prompt/prompt.registry.d.ts +2 -2
- package/prompt/prompt.registry.d.ts.map +1 -1
- package/provider/provider.registry.d.ts +7 -9
- package/provider/provider.registry.d.ts.map +1 -1
- package/resource/flows/read-resource.flow.d.ts.map +1 -1
- package/resource/resource.instance.d.ts +22 -3
- package/resource/resource.instance.d.ts.map +1 -1
- package/resource/resource.registry.d.ts +2 -2
- package/resource/resource.registry.d.ts.map +1 -1
- package/scope/flows/http.request.flow.d.ts.map +1 -1
- package/scope/scope.instance.d.ts +4 -3
- package/scope/scope.instance.d.ts.map +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/skill-http.utils.d.ts +4 -3
- package/skill/skill-http.utils.d.ts.map +1 -1
- package/skill/skill-md-parser.d.ts.map +1 -1
- package/skill/skill-storage.factory.d.ts +3 -3
- package/skill/skill-storage.factory.d.ts.map +1 -1
- package/skill/skill-validator.d.ts +2 -2
- package/skill/skill-validator.d.ts.map +1 -1
- package/skill/skill.instance.d.ts +6 -2
- package/skill/skill.instance.d.ts.map +1 -1
- package/skill/skill.registry.d.ts +2 -3
- package/skill/skill.registry.d.ts.map +1 -1
- package/skill/skill.utils.d.ts +11 -2
- package/skill/skill.utils.d.ts.map +1 -1
- package/tool/flows/call-tool.flow.d.ts.map +1 -1
- package/tool/flows/tools-list.flow.d.ts.map +1 -1
- package/tool/tool.instance.d.ts +2 -2
- package/tool/tool.instance.d.ts.map +1 -1
- package/tool/tool.registry.d.ts +2 -2
- package/tool/tool.registry.d.ts.map +1 -1
- package/transport/adapters/streamable-http-transport.d.ts +23 -0
- package/transport/adapters/streamable-http-transport.d.ts.map +1 -1
- package/transport/adapters/transport.local.adapter.d.ts +29 -1
- package/transport/adapters/transport.local.adapter.d.ts.map +1 -1
- package/transport/adapters/transport.sse.adapter.d.ts.map +1 -1
- package/transport/adapters/transport.streamable-http.adapter.d.ts +13 -4
- package/transport/adapters/transport.streamable-http.adapter.d.ts.map +1 -1
- package/transport/flows/handle.sse.flow.d.ts.map +1 -1
- package/transport/flows/handle.stateless-http.flow.d.ts.map +1 -1
- package/transport/flows/handle.streamable-http.flow.d.ts +50 -1
- package/transport/flows/handle.streamable-http.flow.d.ts.map +1 -1
- package/transport/mcp-handlers/initialize-request.handler.d.ts.map +1 -1
- package/transport/transport.local.d.ts +2 -0
- package/transport/transport.local.d.ts.map +1 -1
- package/transport/transport.registry.d.ts +8 -0
- package/transport/transport.registry.d.ts.map +1 -1
- package/transport/transport.remote.d.ts +2 -0
- package/transport/transport.remote.d.ts.map +1 -1
- package/transport/transport.types.d.ts +10 -0
- package/transport/transport.types.d.ts.map +1 -1
- package/workflow/workflow.instance.d.ts +2 -2
- package/workflow/workflow.instance.d.ts.map +1 -1
package/esm/index.mjs
CHANGED
|
@@ -623,7 +623,7 @@ var init_schema3 = __esm({
|
|
|
623
623
|
maxAge: z4.number().optional()
|
|
624
624
|
});
|
|
625
625
|
httpOptionsSchema = z4.object({
|
|
626
|
-
port: z4.number().optional().default(
|
|
626
|
+
port: z4.number().optional().default(Number(process.env["PORT"]) || 3e3),
|
|
627
627
|
entryPath: z4.string().default(""),
|
|
628
628
|
// Using z.any() because hostFactory accepts FrontMcpServer | ((config) => FrontMcpServer)
|
|
629
629
|
// which Zod cannot validate at runtime - type safety is enforced via TypeScript interface
|
|
@@ -1794,19 +1794,11 @@ var init_schema10 = __esm({
|
|
|
1794
1794
|
}
|
|
1795
1795
|
});
|
|
1796
1796
|
|
|
1797
|
-
// libs/sdk/src/common/types/options/ext-apps/interfaces.ts
|
|
1798
|
-
var init_interfaces2 = __esm({
|
|
1799
|
-
"libs/sdk/src/common/types/options/ext-apps/interfaces.ts"() {
|
|
1800
|
-
"use strict";
|
|
1801
|
-
}
|
|
1802
|
-
});
|
|
1803
|
-
|
|
1804
1797
|
// libs/sdk/src/common/types/options/ext-apps/index.ts
|
|
1805
1798
|
var init_ext_apps = __esm({
|
|
1806
1799
|
"libs/sdk/src/common/types/options/ext-apps/index.ts"() {
|
|
1807
1800
|
"use strict";
|
|
1808
1801
|
init_schema10();
|
|
1809
|
-
init_interfaces2();
|
|
1810
1802
|
}
|
|
1811
1803
|
});
|
|
1812
1804
|
|
|
@@ -2392,6 +2384,7 @@ var init_logger_metadata = __esm({
|
|
|
2392
2384
|
|
|
2393
2385
|
// libs/sdk/src/common/metadata/agent.metadata.ts
|
|
2394
2386
|
import { z as z29 } from "zod";
|
|
2387
|
+
import { rateLimitConfigSchema as rateLimitConfigSchema2, concurrencyConfigSchema as concurrencyConfigSchema2, timeoutConfigSchema as timeoutConfigSchema2 } from "@frontmcp/guard";
|
|
2395
2388
|
function withConfig(configPath, options) {
|
|
2396
2389
|
if (typeof options === "function") {
|
|
2397
2390
|
return { configPath, transform: options };
|
|
@@ -2480,9 +2473,9 @@ var init_agent_metadata = __esm({
|
|
|
2480
2473
|
execution: executionConfigSchema.optional(),
|
|
2481
2474
|
tags: z29.array(z29.string().min(1)).optional(),
|
|
2482
2475
|
hideFromDiscovery: z29.boolean().optional().default(false),
|
|
2483
|
-
rateLimit:
|
|
2484
|
-
concurrency:
|
|
2485
|
-
timeout:
|
|
2476
|
+
rateLimit: rateLimitConfigSchema2.optional(),
|
|
2477
|
+
concurrency: concurrencyConfigSchema2.optional(),
|
|
2478
|
+
timeout: timeoutConfigSchema2.optional()
|
|
2486
2479
|
}).passthrough();
|
|
2487
2480
|
}
|
|
2488
2481
|
});
|
|
@@ -4105,7 +4098,7 @@ var init_provider_errors = __esm({
|
|
|
4105
4098
|
});
|
|
4106
4099
|
|
|
4107
4100
|
// libs/sdk/src/errors/transport.errors.ts
|
|
4108
|
-
var MethodNotImplementedError, UnsupportedTransportTypeError, TransportBusRequiredError, InvalidTransportSessionError, TransportNotConnectedError, TransportAlreadyStartedError, UnsupportedContentTypeError;
|
|
4101
|
+
var MethodNotImplementedError, UnsupportedTransportTypeError, TransportBusRequiredError, InvalidTransportSessionError, TransportNotConnectedError, TransportAlreadyStartedError, UnsupportedContentTypeError, TransportServiceNotAvailableError;
|
|
4109
4102
|
var init_transport_errors = __esm({
|
|
4110
4103
|
"libs/sdk/src/errors/transport.errors.ts"() {
|
|
4111
4104
|
"use strict";
|
|
@@ -4148,6 +4141,11 @@ var init_transport_errors = __esm({
|
|
|
4148
4141
|
this.contentType = contentType2;
|
|
4149
4142
|
}
|
|
4150
4143
|
};
|
|
4144
|
+
TransportServiceNotAvailableError = class extends InternalMcpError {
|
|
4145
|
+
constructor() {
|
|
4146
|
+
super("Transport service not available", "TRANSPORT_SERVICE_NOT_AVAILABLE");
|
|
4147
|
+
}
|
|
4148
|
+
};
|
|
4151
4149
|
}
|
|
4152
4150
|
});
|
|
4153
4151
|
|
|
@@ -4570,6 +4568,7 @@ __export(errors_exports, {
|
|
|
4570
4568
|
TransportAlreadyStartedError: () => TransportAlreadyStartedError,
|
|
4571
4569
|
TransportBusRequiredError: () => TransportBusRequiredError,
|
|
4572
4570
|
TransportNotConnectedError: () => TransportNotConnectedError,
|
|
4571
|
+
TransportServiceNotAvailableError: () => TransportServiceNotAvailableError,
|
|
4573
4572
|
UnauthorizedError: () => UnauthorizedError,
|
|
4574
4573
|
UnsupportedClientVersionError: () => UnsupportedClientVersionError,
|
|
4575
4574
|
UnsupportedContentTypeError: () => UnsupportedContentTypeError,
|
|
@@ -6628,12 +6627,12 @@ var init_provider_registry = __esm({
|
|
|
6628
6627
|
*/
|
|
6629
6628
|
getProviderInfo(token) {
|
|
6630
6629
|
const def = this.defs.get(token);
|
|
6631
|
-
|
|
6632
|
-
if (!def || !instance)
|
|
6630
|
+
if (!def)
|
|
6633
6631
|
throw new ProviderNotRegisteredError(
|
|
6634
6632
|
tokenName2(token),
|
|
6635
6633
|
"not a registered DEFAULT provider and not a constructable class"
|
|
6636
6634
|
);
|
|
6635
|
+
const instance = this.instances.get(token);
|
|
6637
6636
|
return {
|
|
6638
6637
|
token,
|
|
6639
6638
|
def,
|
|
@@ -7642,7 +7641,7 @@ function supportsElicitation(capabilities, mode) {
|
|
|
7642
7641
|
if (mode === "url") {
|
|
7643
7642
|
return capabilities.elicitation.url !== void 0;
|
|
7644
7643
|
}
|
|
7645
|
-
return
|
|
7644
|
+
return true;
|
|
7646
7645
|
}
|
|
7647
7646
|
function matchCustomMappings(clientName, mappings) {
|
|
7648
7647
|
if (!mappings || mappings.length === 0) {
|
|
@@ -7729,8 +7728,9 @@ var init_notification_service = __esm({
|
|
|
7729
7728
|
emergency: 7
|
|
7730
7729
|
};
|
|
7731
7730
|
NotificationService = class _NotificationService {
|
|
7732
|
-
constructor(scope) {
|
|
7731
|
+
constructor(scope, options = {}) {
|
|
7733
7732
|
this.scope = scope;
|
|
7733
|
+
this.options = options;
|
|
7734
7734
|
this.logger = scope.logger.child("NotificationService");
|
|
7735
7735
|
}
|
|
7736
7736
|
logger;
|
|
@@ -7747,6 +7747,9 @@ var init_notification_service = __esm({
|
|
|
7747
7747
|
terminatedSessions = /* @__PURE__ */ new Set();
|
|
7748
7748
|
/** Maximum number of terminated sessions to track before eviction */
|
|
7749
7749
|
static MAX_TERMINATED_SESSIONS = 1e4;
|
|
7750
|
+
get maxTerminatedSessions() {
|
|
7751
|
+
return this.options.maxTerminatedSessions ?? _NotificationService.MAX_TERMINATED_SESSIONS;
|
|
7752
|
+
}
|
|
7750
7753
|
/**
|
|
7751
7754
|
* Initialize the notification service and subscribe to registry changes.
|
|
7752
7755
|
* Called after all registries are ready.
|
|
@@ -7828,7 +7831,7 @@ var init_notification_service = __esm({
|
|
|
7828
7831
|
const wasRegistered = this.unregisterServer(sessionId);
|
|
7829
7832
|
this.scope.providers.cleanupSession(sessionId);
|
|
7830
7833
|
this.logger.verbose(`Cleaned up provider cache for terminated session: ${sessionId.slice(0, 20)}...`);
|
|
7831
|
-
if (this.terminatedSessions.size >=
|
|
7834
|
+
if (this.terminatedSessions.size >= this.maxTerminatedSessions) {
|
|
7832
7835
|
const oldest = this.terminatedSessions.values().next().value;
|
|
7833
7836
|
if (oldest) {
|
|
7834
7837
|
this.terminatedSessions.delete(oldest);
|
|
@@ -8510,7 +8513,14 @@ async function handleWaitingFallback(deps, error) {
|
|
|
8510
8513
|
);
|
|
8511
8514
|
}
|
|
8512
8515
|
}, ttl);
|
|
8513
|
-
scope.elicitationStore
|
|
8516
|
+
const store = scope.elicitationStore;
|
|
8517
|
+
if (!store) {
|
|
8518
|
+
resolved = true;
|
|
8519
|
+
clearTimeout(timeoutHandle);
|
|
8520
|
+
reject(new ElicitationStoreNotInitializedError());
|
|
8521
|
+
return;
|
|
8522
|
+
}
|
|
8523
|
+
store.subscribeFallbackResult(
|
|
8514
8524
|
error.elicitId,
|
|
8515
8525
|
(result) => {
|
|
8516
8526
|
if (!resolved) {
|
|
@@ -8591,7 +8601,7 @@ var init_tool_instance = __esm({
|
|
|
8591
8601
|
this.name = record.metadata.id || record.metadata.name;
|
|
8592
8602
|
this.fullName = this.owner.id + ":" + this.name;
|
|
8593
8603
|
this.scope = this._providers.getActiveScope();
|
|
8594
|
-
this.hooks = this.scope.
|
|
8604
|
+
this.hooks = this.scope.hooks;
|
|
8595
8605
|
this.inputSchema = record.metadata.inputSchema ?? {};
|
|
8596
8606
|
const meta = record.metadata;
|
|
8597
8607
|
this.rawInputSchema = meta["rawInputSchema"];
|
|
@@ -9016,7 +9026,7 @@ function resourceRemote(url, targetName, options) {
|
|
|
9016
9026
|
}
|
|
9017
9027
|
};
|
|
9018
9028
|
}
|
|
9019
|
-
var Resource;
|
|
9029
|
+
var Resource, _ResourceTemplate;
|
|
9020
9030
|
var init_resource_decorator = __esm({
|
|
9021
9031
|
"libs/sdk/src/common/decorators/resource.decorator.ts"() {
|
|
9022
9032
|
"use strict";
|
|
@@ -9029,6 +9039,7 @@ var init_resource_decorator = __esm({
|
|
|
9029
9039
|
remote: resourceRemote
|
|
9030
9040
|
});
|
|
9031
9041
|
Resource = FrontMcpResource;
|
|
9042
|
+
_ResourceTemplate = FrontMcpResourceTemplate;
|
|
9032
9043
|
}
|
|
9033
9044
|
});
|
|
9034
9045
|
|
|
@@ -9201,8 +9212,7 @@ var init_tools_list_flow = __esm({
|
|
|
9201
9212
|
);
|
|
9202
9213
|
}
|
|
9203
9214
|
const sessionId = authInfo.sessionId;
|
|
9204
|
-
const
|
|
9205
|
-
const platformType = authInfo.sessionIdPayload?.platformType ?? (sessionId ? scope.notifications?.getPlatformType(sessionId) : void 0) ?? "unknown";
|
|
9215
|
+
const platformType = authInfo.sessionIdPayload?.platformType ?? (sessionId ? this.scope.notifications?.getPlatformType(sessionId) : void 0) ?? "unknown";
|
|
9206
9216
|
this.logger.verbose(`parseInput: detected platform=${platformType}`);
|
|
9207
9217
|
const cursor = params?.cursor;
|
|
9208
9218
|
if (cursor) this.logger.verbose(`parseInput: cursor=${cursor}`);
|
|
@@ -9309,8 +9319,7 @@ var init_tools_list_flow = __esm({
|
|
|
9309
9319
|
try {
|
|
9310
9320
|
const allResolved = this.state.required.resolvedTools;
|
|
9311
9321
|
const platformType = this.state.platformType ?? "unknown";
|
|
9312
|
-
const
|
|
9313
|
-
const paginationConfig = scope.pagination?.tools;
|
|
9322
|
+
const paginationConfig = this.scope.metadata.pagination?.tools;
|
|
9314
9323
|
const usePagination = this.shouldPaginate(allResolved.length, paginationConfig);
|
|
9315
9324
|
const sortedResolved = [...allResolved].sort((a, b) => a.finalName.localeCompare(b.finalName));
|
|
9316
9325
|
let resolved = sortedResolved;
|
|
@@ -9370,12 +9379,12 @@ var init_tools_list_flow = __esm({
|
|
|
9370
9379
|
this.logger.warn(`parseTools: toolUI not available in scope for ${finalName}`);
|
|
9371
9380
|
return item;
|
|
9372
9381
|
}
|
|
9373
|
-
const
|
|
9382
|
+
const scope = this.scope;
|
|
9374
9383
|
let manifest;
|
|
9375
9384
|
let detectedType;
|
|
9376
9385
|
try {
|
|
9377
|
-
manifest =
|
|
9378
|
-
detectedType =
|
|
9386
|
+
manifest = scope.toolUI.getManifest(finalName);
|
|
9387
|
+
detectedType = scope.toolUI.detectUIType(uiConfig.template);
|
|
9379
9388
|
} catch (error) {
|
|
9380
9389
|
this.logger.warn(`parseTools: failed to access toolUI for ${finalName}`, error);
|
|
9381
9390
|
return item;
|
|
@@ -9897,8 +9906,11 @@ var init_call_tool_flow = __esm({
|
|
|
9897
9906
|
const authInfo = this.state.authInfo;
|
|
9898
9907
|
const authInfoWithTransport = authInfo;
|
|
9899
9908
|
const sessionId = authInfo?.sessionId ?? "anonymous";
|
|
9900
|
-
const
|
|
9901
|
-
|
|
9909
|
+
const store = this.scope.elicitationStore;
|
|
9910
|
+
if (!store) {
|
|
9911
|
+
throw new InternalMcpError("Elicitation store not initialized");
|
|
9912
|
+
}
|
|
9913
|
+
await store.setPendingFallback({
|
|
9902
9914
|
elicitId: error.elicitId,
|
|
9903
9915
|
sessionId,
|
|
9904
9916
|
toolName: error.toolName,
|
|
@@ -9909,11 +9921,11 @@ var init_call_tool_flow = __esm({
|
|
|
9909
9921
|
expiresAt: Date.now() + error.ttl
|
|
9910
9922
|
});
|
|
9911
9923
|
const transportType = authInfoWithTransport?.transport?.type;
|
|
9912
|
-
if (transportType === "streamable-http" && canDeliverNotifications(scope, sessionId)) {
|
|
9924
|
+
if (transportType === "streamable-http" && canDeliverNotifications(this.scope, sessionId)) {
|
|
9913
9925
|
this.logger.info("execute: using waiting fallback for streamable-http", {
|
|
9914
9926
|
elicitId: error.elicitId
|
|
9915
9927
|
});
|
|
9916
|
-
const deps = { scope, sessionId, logger: this.logger };
|
|
9928
|
+
const deps = { scope: this.scope, sessionId, logger: this.logger };
|
|
9917
9929
|
const result = await handleWaitingFallback(deps, error);
|
|
9918
9930
|
toolContext.output = result;
|
|
9919
9931
|
this.logger.verbose("execute:done (elicitation waiting fallback)");
|
|
@@ -10023,6 +10035,10 @@ ${JSON.stringify(error.schema, null, 2)}
|
|
|
10023
10035
|
const useStructuredContent = resolvedMode.useStructuredContent;
|
|
10024
10036
|
let htmlContent;
|
|
10025
10037
|
let uiMeta = {};
|
|
10038
|
+
if (!scope.toolUI) {
|
|
10039
|
+
this.logger.verbose("applyUI: toolUI not available, skipping UI rendering");
|
|
10040
|
+
return;
|
|
10041
|
+
}
|
|
10026
10042
|
if (servingMode === "static") {
|
|
10027
10043
|
this.logger.verbose("applyUI: UI using static mode (structured data only)", {
|
|
10028
10044
|
tool: tool.metadata.name,
|
|
@@ -10240,8 +10256,8 @@ var init_send_elicitation_result_tool = __esm({
|
|
|
10240
10256
|
async execute(input) {
|
|
10241
10257
|
const { elicitId, action, content } = input;
|
|
10242
10258
|
this.logger.info("sendElicitationResult: processing", { elicitId, action });
|
|
10243
|
-
const
|
|
10244
|
-
if (!
|
|
10259
|
+
const store = this.scope.elicitationStore;
|
|
10260
|
+
if (!store) {
|
|
10245
10261
|
this.logger.error("sendElicitationResult: scope or elicitationStore not available");
|
|
10246
10262
|
return {
|
|
10247
10263
|
content: [
|
|
@@ -10253,7 +10269,7 @@ var init_send_elicitation_result_tool = __esm({
|
|
|
10253
10269
|
isError: true
|
|
10254
10270
|
};
|
|
10255
10271
|
}
|
|
10256
|
-
const pending = await
|
|
10272
|
+
const pending = await store.getPendingFallback(elicitId);
|
|
10257
10273
|
if (!pending) {
|
|
10258
10274
|
this.logger.warn("sendElicitationResult: no pending elicitation found", { elicitId });
|
|
10259
10275
|
return {
|
|
@@ -10267,7 +10283,7 @@ var init_send_elicitation_result_tool = __esm({
|
|
|
10267
10283
|
};
|
|
10268
10284
|
}
|
|
10269
10285
|
if (Date.now() > pending.expiresAt) {
|
|
10270
|
-
await
|
|
10286
|
+
await store.deletePendingFallback(elicitId);
|
|
10271
10287
|
this.logger.warn("sendElicitationResult: elicitation expired", { elicitId });
|
|
10272
10288
|
return {
|
|
10273
10289
|
content: [
|
|
@@ -10283,8 +10299,8 @@ var init_send_elicitation_result_tool = __esm({
|
|
|
10283
10299
|
status: action,
|
|
10284
10300
|
...action === "accept" && content !== void 0 && { content }
|
|
10285
10301
|
};
|
|
10286
|
-
await
|
|
10287
|
-
await
|
|
10302
|
+
await store.setResolvedResult(elicitId, elicitResult, pending.sessionId);
|
|
10303
|
+
await store.deletePendingFallback(elicitId);
|
|
10288
10304
|
this.logger.info("sendElicitationResult: re-invoking original tool", {
|
|
10289
10305
|
elicitId,
|
|
10290
10306
|
toolName: pending.toolName
|
|
@@ -10294,7 +10310,7 @@ var init_send_elicitation_result_tool = __esm({
|
|
|
10294
10310
|
ctx.setPreResolvedElicitResult(elicitResult);
|
|
10295
10311
|
}
|
|
10296
10312
|
try {
|
|
10297
|
-
const toolResult = await scope.runFlowForOutput("tools:call-tool", {
|
|
10313
|
+
const toolResult = await this.scope.runFlowForOutput("tools:call-tool", {
|
|
10298
10314
|
request: {
|
|
10299
10315
|
method: "tools/call",
|
|
10300
10316
|
params: {
|
|
@@ -10309,19 +10325,19 @@ var init_send_elicitation_result_tool = __esm({
|
|
|
10309
10325
|
elicitId,
|
|
10310
10326
|
toolName: pending.toolName
|
|
10311
10327
|
});
|
|
10312
|
-
await
|
|
10328
|
+
await store.publishFallbackResult(elicitId, pending.sessionId, {
|
|
10313
10329
|
success: true,
|
|
10314
10330
|
result: toolResult
|
|
10315
10331
|
});
|
|
10316
|
-
await
|
|
10332
|
+
await store.deleteResolvedResult(elicitId);
|
|
10317
10333
|
return toolResult;
|
|
10318
10334
|
} catch (error) {
|
|
10319
10335
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
10320
|
-
await
|
|
10336
|
+
await store.publishFallbackResult(elicitId, pending.sessionId, {
|
|
10321
10337
|
success: false,
|
|
10322
10338
|
error: errorMessage
|
|
10323
10339
|
});
|
|
10324
|
-
await
|
|
10340
|
+
await store.deleteResolvedResult(elicitId);
|
|
10325
10341
|
this.logger.error("sendElicitationResult: original tool failed", {
|
|
10326
10342
|
elicitId,
|
|
10327
10343
|
toolName: pending.toolName,
|
|
@@ -11010,19 +11026,26 @@ var init_resource_instance = __esm({
|
|
|
11010
11026
|
init_mcp_error();
|
|
11011
11027
|
init_errors();
|
|
11012
11028
|
ResourceInstance = class extends ResourceEntry2 {
|
|
11013
|
-
|
|
11029
|
+
_providers;
|
|
11014
11030
|
scope;
|
|
11015
11031
|
hooks;
|
|
11032
|
+
/**
|
|
11033
|
+
* Get the provider registry for this resource.
|
|
11034
|
+
* Used by flows to build context-aware providers for CONTEXT-scoped dependencies.
|
|
11035
|
+
*/
|
|
11036
|
+
get providers() {
|
|
11037
|
+
return this._providers;
|
|
11038
|
+
}
|
|
11016
11039
|
/** Parsed URI template info for template resources */
|
|
11017
11040
|
templateInfo;
|
|
11018
11041
|
constructor(record, providers, owner) {
|
|
11019
11042
|
super(record);
|
|
11020
11043
|
this.owner = owner;
|
|
11021
|
-
this.
|
|
11044
|
+
this._providers = providers;
|
|
11022
11045
|
this.name = record.metadata.name;
|
|
11023
11046
|
this.fullName = this.owner.id + ":" + this.name;
|
|
11024
11047
|
this.scope = this.providers.getActiveScope();
|
|
11025
|
-
this.hooks = this.scope.
|
|
11048
|
+
this.hooks = this.scope.hooks;
|
|
11026
11049
|
this.isTemplate = "uriTemplate" in record.metadata;
|
|
11027
11050
|
if (this.isTemplate) {
|
|
11028
11051
|
const templateMetadata = record.metadata;
|
|
@@ -11053,6 +11076,18 @@ var init_resource_instance = __esm({
|
|
|
11053
11076
|
getMetadata() {
|
|
11054
11077
|
return this.record.metadata;
|
|
11055
11078
|
}
|
|
11079
|
+
/**
|
|
11080
|
+
* Get an argument completer from the resource class prototype.
|
|
11081
|
+
* Returns a completer function if the resource class overrides getArgumentCompleter,
|
|
11082
|
+
* or null if no completer is available.
|
|
11083
|
+
*/
|
|
11084
|
+
getArgumentCompleter(argName) {
|
|
11085
|
+
const cls = this.record.provide;
|
|
11086
|
+
if (typeof cls === "function" && cls.prototype && typeof cls.prototype.getArgumentCompleter === "function") {
|
|
11087
|
+
return cls.prototype.getArgumentCompleter.call(cls.prototype, argName);
|
|
11088
|
+
}
|
|
11089
|
+
return null;
|
|
11090
|
+
}
|
|
11056
11091
|
/**
|
|
11057
11092
|
* Match a URI against this resource.
|
|
11058
11093
|
* For static resources: exact match against uri
|
|
@@ -11168,6 +11203,7 @@ var init_resource_types = __esm({
|
|
|
11168
11203
|
// libs/sdk/src/resource/flows/read-resource.flow.ts
|
|
11169
11204
|
import { z as z40 } from "zod";
|
|
11170
11205
|
import { ReadResourceRequestSchema, ReadResourceResultSchema } from "@frontmcp/protocol";
|
|
11206
|
+
import { randomBytes as randomBytes2 } from "@frontmcp/utils";
|
|
11171
11207
|
var inputSchema4, outputSchema3, stateSchema3, plan3, name3, Stage3, ReadResourceFlow;
|
|
11172
11208
|
var init_read_resource_flow = __esm({
|
|
11173
11209
|
"libs/sdk/src/resource/flows/read-resource.flow.ts"() {
|
|
@@ -11277,11 +11313,14 @@ var init_read_resource_flow = __esm({
|
|
|
11277
11313
|
this.logger.info(`findResource: looking for resource with URI "${uri}"`);
|
|
11278
11314
|
if (isUIResourceUri(uri)) {
|
|
11279
11315
|
this.logger.info(`findResource: detected UI resource URI "${uri}"`);
|
|
11280
|
-
const scope = this.scope;
|
|
11281
11316
|
const { sessionId, authInfo } = this.state;
|
|
11282
|
-
const platformType = authInfo?.sessionIdPayload?.platformType ?? (sessionId ? scope.notifications.getPlatformType(sessionId) : void 0);
|
|
11317
|
+
const platformType = authInfo?.sessionIdPayload?.platformType ?? (sessionId ? this.scope.notifications.getPlatformType(sessionId) : void 0);
|
|
11283
11318
|
this.logger.verbose(`findResource: platform type for session: ${platformType ?? "unknown"}`);
|
|
11284
|
-
|
|
11319
|
+
if (!this.scope.toolUI) {
|
|
11320
|
+
this.logger.verbose("findResource: toolUI not available, skipping UI resource handling");
|
|
11321
|
+
throw new ResourceNotFoundError(uri);
|
|
11322
|
+
}
|
|
11323
|
+
const uiResult = handleUIResourceRead(uri, this.scope.toolUI, platformType);
|
|
11285
11324
|
if (uiResult.handled) {
|
|
11286
11325
|
if (uiResult.error) {
|
|
11287
11326
|
this.logger.warn(`findResource: UI resource error - ${uiResult.error}`);
|
|
@@ -11317,7 +11356,15 @@ var init_read_resource_flow = __esm({
|
|
|
11317
11356
|
const { ctx } = this.input;
|
|
11318
11357
|
const { resource, input, params } = this.state.required;
|
|
11319
11358
|
try {
|
|
11320
|
-
const
|
|
11359
|
+
const sessionKey = this.state.sessionId ?? ctx.authInfo?.sessionId ?? `req-${Date.now()}-${Buffer.from(randomBytes2(16)).toString("hex")}`;
|
|
11360
|
+
const resourceViews = await resource.providers.buildViews(sessionKey, new Map(this.deps));
|
|
11361
|
+
const mergedContextDeps = new Map(this.deps);
|
|
11362
|
+
for (const [token, instance] of resourceViews.context) {
|
|
11363
|
+
if (!mergedContextDeps.has(token)) {
|
|
11364
|
+
mergedContextDeps.set(token, instance);
|
|
11365
|
+
}
|
|
11366
|
+
}
|
|
11367
|
+
const contextProviders = new FlowContextProviders(resource.providers, mergedContextDeps);
|
|
11321
11368
|
const context = resource.create(input.uri, params, { ...ctx, contextProviders });
|
|
11322
11369
|
const resourceHooks = this.scope.hooks.getClsHooks(resource.record.provide).map((hook) => {
|
|
11323
11370
|
hook.run = async () => {
|
|
@@ -12759,7 +12806,7 @@ var init_prompt_instance = __esm({
|
|
|
12759
12806
|
this.name = record.metadata.name;
|
|
12760
12807
|
this.fullName = this.owner.id + ":" + this.name;
|
|
12761
12808
|
this.scope = this._providers.getActiveScope();
|
|
12762
|
-
this.hooks = this.scope.
|
|
12809
|
+
this.hooks = this.scope.hooks;
|
|
12763
12810
|
this.ready = this.initialize();
|
|
12764
12811
|
}
|
|
12765
12812
|
async initialize() {
|
|
@@ -14225,7 +14272,7 @@ var init_skill_md_parser = __esm({
|
|
|
14225
14272
|
|
|
14226
14273
|
// libs/sdk/src/skill/skill.utils.ts
|
|
14227
14274
|
import { isClass as isClass11, getMetadata as getMetadata13, depsOfClass as depsOfClass8 } from "@frontmcp/di";
|
|
14228
|
-
import { readFile as readFile2 } from "@frontmcp/utils";
|
|
14275
|
+
import { readFile as readFile2, readdir, fileExists } from "@frontmcp/utils";
|
|
14229
14276
|
function collectSkillMetadata(cls) {
|
|
14230
14277
|
const extended = getMetadata13(extendedSkillMetadata, cls);
|
|
14231
14278
|
const seed = extended ? { ...extended } : {};
|
|
@@ -14305,12 +14352,16 @@ async function loadInstructions(source, basePath) {
|
|
|
14305
14352
|
}
|
|
14306
14353
|
throw new InvalidInstructionSourceError();
|
|
14307
14354
|
}
|
|
14308
|
-
function buildSkillContent(metadata, instructions) {
|
|
14355
|
+
function buildSkillContent(metadata, instructions, resolvedReferences) {
|
|
14356
|
+
let finalInstructions = instructions;
|
|
14357
|
+
if (resolvedReferences && resolvedReferences.length > 0) {
|
|
14358
|
+
finalInstructions += buildReferencesTable(resolvedReferences);
|
|
14359
|
+
}
|
|
14309
14360
|
return {
|
|
14310
14361
|
id: metadata.id ?? metadata.name,
|
|
14311
14362
|
name: metadata.name,
|
|
14312
14363
|
description: metadata.description,
|
|
14313
|
-
instructions,
|
|
14364
|
+
instructions: finalInstructions,
|
|
14314
14365
|
tools: normalizeToolRefs(metadata.tools),
|
|
14315
14366
|
parameters: metadata.parameters,
|
|
14316
14367
|
examples: metadata.examples,
|
|
@@ -14318,9 +14369,73 @@ function buildSkillContent(metadata, instructions) {
|
|
|
14318
14369
|
compatibility: metadata.compatibility,
|
|
14319
14370
|
specMetadata: metadata.specMetadata,
|
|
14320
14371
|
allowedTools: metadata.allowedTools,
|
|
14321
|
-
resources: metadata.resources
|
|
14372
|
+
resources: metadata.resources,
|
|
14373
|
+
resolvedReferences
|
|
14322
14374
|
};
|
|
14323
14375
|
}
|
|
14376
|
+
function buildReferencesTable(refs) {
|
|
14377
|
+
const lines = ["", "", "## References", "", "| Reference | Description |", "| --------- | ----------- |"];
|
|
14378
|
+
for (const ref of refs) {
|
|
14379
|
+
lines.push(`| \`${ref.name}\` | ${ref.description} |`);
|
|
14380
|
+
}
|
|
14381
|
+
return lines.join("\n");
|
|
14382
|
+
}
|
|
14383
|
+
async function resolveReferences(refsDir) {
|
|
14384
|
+
if (!await fileExists(refsDir)) return void 0;
|
|
14385
|
+
let files;
|
|
14386
|
+
try {
|
|
14387
|
+
files = (await readdir(refsDir)).filter((f) => f.endsWith(".md")).sort();
|
|
14388
|
+
} catch {
|
|
14389
|
+
return void 0;
|
|
14390
|
+
}
|
|
14391
|
+
if (files.length === 0) return void 0;
|
|
14392
|
+
const refs = [];
|
|
14393
|
+
for (const file of files) {
|
|
14394
|
+
const content = await readFile2(`${refsDir}/${file}`, "utf-8");
|
|
14395
|
+
const filenameWithoutExt = file.replace(/\.md$/, "");
|
|
14396
|
+
let name33 = filenameWithoutExt;
|
|
14397
|
+
let description = "";
|
|
14398
|
+
const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
14399
|
+
if (fmMatch) {
|
|
14400
|
+
const fmLines = fmMatch[1].split(/\r?\n/);
|
|
14401
|
+
for (const line of fmLines) {
|
|
14402
|
+
const colonIdx = line.indexOf(":");
|
|
14403
|
+
if (colonIdx === -1) continue;
|
|
14404
|
+
const key = line.slice(0, colonIdx).trim();
|
|
14405
|
+
const val = line.slice(colonIdx + 1).trim().replace(/^["']|["']$/g, "");
|
|
14406
|
+
if (key === "name" && val) name33 = val;
|
|
14407
|
+
if (key === "description" && val) description = val;
|
|
14408
|
+
}
|
|
14409
|
+
}
|
|
14410
|
+
if (!description) {
|
|
14411
|
+
const body = fmMatch ? content.substring(content.indexOf("---", 3) + 3).trim() : content.trim();
|
|
14412
|
+
description = extractFirstParagraph(body);
|
|
14413
|
+
}
|
|
14414
|
+
refs.push({ name: name33, description, filename: file });
|
|
14415
|
+
}
|
|
14416
|
+
return refs;
|
|
14417
|
+
}
|
|
14418
|
+
function extractFirstParagraph(body) {
|
|
14419
|
+
const lines = body.split(/\r?\n/);
|
|
14420
|
+
let foundHeading = false;
|
|
14421
|
+
const paragraphLines = [];
|
|
14422
|
+
for (const line of lines) {
|
|
14423
|
+
const trimmed = line.trim();
|
|
14424
|
+
if (!foundHeading && trimmed.startsWith("#")) {
|
|
14425
|
+
foundHeading = true;
|
|
14426
|
+
continue;
|
|
14427
|
+
}
|
|
14428
|
+
if (foundHeading) {
|
|
14429
|
+
if (trimmed === "") {
|
|
14430
|
+
if (paragraphLines.length > 0) break;
|
|
14431
|
+
continue;
|
|
14432
|
+
}
|
|
14433
|
+
if (trimmed.startsWith("#") || trimmed.startsWith("|") || trimmed.startsWith("-")) break;
|
|
14434
|
+
paragraphLines.push(trimmed);
|
|
14435
|
+
}
|
|
14436
|
+
}
|
|
14437
|
+
return paragraphLines.join(" ").slice(0, 200) || "";
|
|
14438
|
+
}
|
|
14324
14439
|
function normalizeToolRefs(tools) {
|
|
14325
14440
|
if (!tools) return [];
|
|
14326
14441
|
return tools.map((tool) => {
|
|
@@ -14439,6 +14554,7 @@ var init_skill_utils = __esm({
|
|
|
14439
14554
|
});
|
|
14440
14555
|
|
|
14441
14556
|
// libs/sdk/src/skill/skill.instance.ts
|
|
14557
|
+
import { dirname, pathResolve } from "@frontmcp/utils";
|
|
14442
14558
|
function createSkillInstance(record, providers, owner) {
|
|
14443
14559
|
return new SkillInstance(record, providers, owner);
|
|
14444
14560
|
}
|
|
@@ -14500,6 +14616,8 @@ var init_skill_instance = __esm({
|
|
|
14500
14616
|
const filePath = this.record.filePath;
|
|
14501
14617
|
const lastSlash = filePath.lastIndexOf("/");
|
|
14502
14618
|
basePath = lastSlash > 0 ? filePath.substring(0, lastSlash) : void 0;
|
|
14619
|
+
} else if (this.record.kind === "VALUE" /* VALUE */ && this.record.callerDir) {
|
|
14620
|
+
basePath = this.record.callerDir;
|
|
14503
14621
|
}
|
|
14504
14622
|
this.cachedInstructions = await loadInstructions(this.metadata.instructions, basePath);
|
|
14505
14623
|
return this.cachedInstructions;
|
|
@@ -14508,12 +14626,33 @@ var init_skill_instance = __esm({
|
|
|
14508
14626
|
* Load the full skill content.
|
|
14509
14627
|
* Results are cached after the first load.
|
|
14510
14628
|
*/
|
|
14629
|
+
/**
|
|
14630
|
+
* Resolve the base directory for this skill (for file/reference resolution).
|
|
14631
|
+
*/
|
|
14632
|
+
getBaseDir() {
|
|
14633
|
+
if (this.record.kind === "FILE" /* FILE */) {
|
|
14634
|
+
return dirname(this.record.filePath) || void 0;
|
|
14635
|
+
}
|
|
14636
|
+
if (this.record.kind === "VALUE" /* VALUE */ && this.record.callerDir) {
|
|
14637
|
+
return this.record.callerDir;
|
|
14638
|
+
}
|
|
14639
|
+
return void 0;
|
|
14640
|
+
}
|
|
14511
14641
|
async load() {
|
|
14512
14642
|
if (this.cachedContent !== void 0) {
|
|
14513
14643
|
return this.cachedContent;
|
|
14514
14644
|
}
|
|
14515
14645
|
const instructions = await this.loadInstructions();
|
|
14516
|
-
const
|
|
14646
|
+
const refsPath = this.metadata.resources?.references;
|
|
14647
|
+
let resolvedRefs;
|
|
14648
|
+
if (refsPath) {
|
|
14649
|
+
const baseDir = this.getBaseDir();
|
|
14650
|
+
const refsDir = refsPath.startsWith("/") ? refsPath : baseDir ? pathResolve(baseDir, refsPath) : void 0;
|
|
14651
|
+
if (refsDir) {
|
|
14652
|
+
resolvedRefs = await resolveReferences(refsDir);
|
|
14653
|
+
}
|
|
14654
|
+
}
|
|
14655
|
+
const baseContent = buildSkillContent(this.metadata, instructions, resolvedRefs);
|
|
14517
14656
|
this.cachedContent = {
|
|
14518
14657
|
...baseContent,
|
|
14519
14658
|
tags: this.tags,
|
|
@@ -15793,6 +15932,13 @@ var init_plugin_registry = __esm({
|
|
|
15793
15932
|
getPluginNames() {
|
|
15794
15933
|
return [...this.defs.values()].map((rec) => rec.metadata.name);
|
|
15795
15934
|
}
|
|
15935
|
+
/**
|
|
15936
|
+
* Returns all ToolRegistries created by plugins in this registry.
|
|
15937
|
+
* Used for propagating server-level plugin tools to the scope.
|
|
15938
|
+
*/
|
|
15939
|
+
getToolRegistries() {
|
|
15940
|
+
return [...this.pTools.values()];
|
|
15941
|
+
}
|
|
15796
15942
|
buildMap(list) {
|
|
15797
15943
|
const tokens = /* @__PURE__ */ new Set();
|
|
15798
15944
|
const defs = /* @__PURE__ */ new Map();
|
|
@@ -15809,12 +15955,14 @@ var init_plugin_registry = __esm({
|
|
|
15809
15955
|
buildGraph() {
|
|
15810
15956
|
for (const token of this.tokens) {
|
|
15811
15957
|
const rec = this.defs.get(token);
|
|
15958
|
+
if (!rec) throw new RegistryDependencyNotRegisteredError("Plugin", tokenName10(token), "self");
|
|
15812
15959
|
const deps = pluginDiscoveryDeps(rec);
|
|
15813
15960
|
for (const d of deps) {
|
|
15814
15961
|
if (!this.providers.get(d)) {
|
|
15815
15962
|
throw new RegistryDependencyNotRegisteredError("Plugin", tokenName10(token), tokenName10(d));
|
|
15816
15963
|
}
|
|
15817
|
-
this.graph.get(token)
|
|
15964
|
+
const edges = this.graph.get(token);
|
|
15965
|
+
if (edges) edges.add(d);
|
|
15818
15966
|
}
|
|
15819
15967
|
}
|
|
15820
15968
|
}
|
|
@@ -15822,7 +15970,8 @@ var init_plugin_registry = __esm({
|
|
|
15822
15970
|
this.logger?.verbose(`PluginRegistry: initializing ${this.tokens.size} plugin(s)`);
|
|
15823
15971
|
for (const token of this.tokens) {
|
|
15824
15972
|
const rec = this.defs.get(token);
|
|
15825
|
-
|
|
15973
|
+
if (!rec) continue;
|
|
15974
|
+
const deps = this.graph.get(token) ?? /* @__PURE__ */ new Set();
|
|
15826
15975
|
const providers = new ProviderRegistry(rec.metadata.providers ?? [], this.providers);
|
|
15827
15976
|
await providers.ready;
|
|
15828
15977
|
const pluginOwner = {
|
|
@@ -15865,9 +16014,9 @@ var init_plugin_registry = __esm({
|
|
|
15865
16014
|
const klass = rec.provide;
|
|
15866
16015
|
pluginInstance = new klass(...depsInstances);
|
|
15867
16016
|
} else if (rec.kind === "FACTORY" /* FACTORY */) {
|
|
15868
|
-
const
|
|
16017
|
+
const factoryDeps = [...rec.inject()];
|
|
15869
16018
|
const args = [];
|
|
15870
|
-
for (const d of
|
|
16019
|
+
for (const d of factoryDeps) args.push(await this.providers.resolveBootstrapDep(d));
|
|
15871
16020
|
pluginInstance = rec.useFactory(...args);
|
|
15872
16021
|
} else if (rec.kind === "VALUE" /* VALUE */) {
|
|
15873
16022
|
pluginInstance = rec.useValue;
|
|
@@ -17661,7 +17810,7 @@ var init_config_symbols = __esm({
|
|
|
17661
17810
|
});
|
|
17662
17811
|
|
|
17663
17812
|
// libs/sdk/src/builtin/config/providers/env-loader.ts
|
|
17664
|
-
import { readFile as readFile3, fileExists, getCwd, getEnv as getEnv2, setEnv, pathResolve } from "@frontmcp/utils";
|
|
17813
|
+
import { readFile as readFile3, fileExists as fileExists2, getCwd, getEnv as getEnv2, setEnv, pathResolve as pathResolve2 } from "@frontmcp/utils";
|
|
17665
17814
|
function parseEnvContent(content) {
|
|
17666
17815
|
const result = {};
|
|
17667
17816
|
const lines = content.split("\n");
|
|
@@ -17689,13 +17838,13 @@ function parseEnvContent(content) {
|
|
|
17689
17838
|
}
|
|
17690
17839
|
async function loadEnvFiles(basePath = getCwd(), envPath = ".env", localEnvPath = ".env.local") {
|
|
17691
17840
|
const result = {};
|
|
17692
|
-
const envFile =
|
|
17693
|
-
if (await
|
|
17841
|
+
const envFile = pathResolve2(basePath, envPath);
|
|
17842
|
+
if (await fileExists2(envFile)) {
|
|
17694
17843
|
const content = await readFile3(envFile);
|
|
17695
17844
|
Object.assign(result, parseEnvContent(content));
|
|
17696
17845
|
}
|
|
17697
|
-
const localFile =
|
|
17698
|
-
if (await
|
|
17846
|
+
const localFile = pathResolve2(basePath, localEnvPath);
|
|
17847
|
+
if (await fileExists2(localFile)) {
|
|
17699
17848
|
const content = await readFile3(localFile);
|
|
17700
17849
|
Object.assign(result, parseEnvContent(content));
|
|
17701
17850
|
}
|
|
@@ -17816,7 +17965,7 @@ var init_env_loader = __esm({
|
|
|
17816
17965
|
|
|
17817
17966
|
// libs/sdk/src/builtin/config/providers/config-loader.ts
|
|
17818
17967
|
import * as yaml2 from "js-yaml";
|
|
17819
|
-
import { readFile as readFile4, fileExists as
|
|
17968
|
+
import { readFile as readFile4, fileExists as fileExists3, getCwd as getCwd2, pathResolve as pathResolve3 } from "@frontmcp/utils";
|
|
17820
17969
|
async function loadConfig(schema, options = {}) {
|
|
17821
17970
|
const {
|
|
17822
17971
|
basePath = getCwd2(),
|
|
@@ -17857,8 +18006,8 @@ async function loadYamlConfig(basePath, configPath) {
|
|
|
17857
18006
|
const extensions = ["", ".yml", ".yaml"];
|
|
17858
18007
|
const baseName = configPath.replace(/\.(ya?ml)$/, "");
|
|
17859
18008
|
for (const ext of extensions) {
|
|
17860
|
-
const fullPath =
|
|
17861
|
-
if (await
|
|
18009
|
+
const fullPath = pathResolve3(basePath, baseName + ext);
|
|
18010
|
+
if (await fileExists3(fullPath)) {
|
|
17862
18011
|
const content = await readFile4(fullPath);
|
|
17863
18012
|
const parsed = yaml2.load(content);
|
|
17864
18013
|
if (parsed && typeof parsed === "object") {
|
|
@@ -18341,7 +18490,7 @@ var init_flow_instance = __esm({
|
|
|
18341
18490
|
this.FlowClass = this.record.provide;
|
|
18342
18491
|
this.ready = this.initialize();
|
|
18343
18492
|
this.plan = this.record.metadata.plan;
|
|
18344
|
-
this.hooks = scope.
|
|
18493
|
+
this.hooks = scope.hooks;
|
|
18345
18494
|
this.logger = scope.logger.child("FlowInstance");
|
|
18346
18495
|
}
|
|
18347
18496
|
async initialize() {
|
|
@@ -18709,8 +18858,8 @@ var init_flow_registry = __esm({
|
|
|
18709
18858
|
const rec = this.defs.get(token);
|
|
18710
18859
|
const deps = rec.metadata.dependsOn ?? [];
|
|
18711
18860
|
for (const d of deps) {
|
|
18712
|
-
if (d ==
|
|
18713
|
-
this.graph.get(token).add(
|
|
18861
|
+
if (d == ScopeEntry3) {
|
|
18862
|
+
this.graph.get(token).add(ScopeEntry3);
|
|
18714
18863
|
} else {
|
|
18715
18864
|
if (!this.providers.get(d)) {
|
|
18716
18865
|
throw new RegistryDependencyNotRegisteredError("Flow", tokenName11(token), tokenName11(d));
|
|
@@ -19031,7 +19180,7 @@ var init_agent_scope = __esm({
|
|
|
19031
19180
|
{
|
|
19032
19181
|
scope: ProviderScope4.GLOBAL,
|
|
19033
19182
|
name: "ScopeEntry",
|
|
19034
|
-
provide:
|
|
19183
|
+
provide: ScopeEntry3,
|
|
19035
19184
|
useValue: agentScopeEntry
|
|
19036
19185
|
},
|
|
19037
19186
|
// Also register as Scope so getActiveScope() returns the agent's scope
|
|
@@ -19142,6 +19291,12 @@ var init_agent_scope = __esm({
|
|
|
19142
19291
|
get toolUI() {
|
|
19143
19292
|
return this.parentScope.toolUI;
|
|
19144
19293
|
}
|
|
19294
|
+
get skills() {
|
|
19295
|
+
return this.parentScope.skills;
|
|
19296
|
+
}
|
|
19297
|
+
get scopeMetadata() {
|
|
19298
|
+
return this.parentScope.metadata;
|
|
19299
|
+
}
|
|
19145
19300
|
// ============================================================================
|
|
19146
19301
|
// Flow Execution
|
|
19147
19302
|
// ============================================================================
|
|
@@ -19200,18 +19355,42 @@ var init_agent_scope = __esm({
|
|
|
19200
19355
|
get agents() {
|
|
19201
19356
|
return this.agentScope.agents;
|
|
19202
19357
|
}
|
|
19358
|
+
get skills() {
|
|
19359
|
+
return this.agentScope.skills;
|
|
19360
|
+
}
|
|
19203
19361
|
get notifications() {
|
|
19204
19362
|
return this.agentScope.notifications;
|
|
19205
19363
|
}
|
|
19206
19364
|
get toolUI() {
|
|
19207
19365
|
return this.agentScope.toolUI;
|
|
19208
19366
|
}
|
|
19367
|
+
get transportService() {
|
|
19368
|
+
return void 0;
|
|
19369
|
+
}
|
|
19370
|
+
get rateLimitManager() {
|
|
19371
|
+
return void 0;
|
|
19372
|
+
}
|
|
19373
|
+
get elicitationStore() {
|
|
19374
|
+
return void 0;
|
|
19375
|
+
}
|
|
19376
|
+
get metadata() {
|
|
19377
|
+
return this.agentScope.scopeMetadata;
|
|
19378
|
+
}
|
|
19379
|
+
get record() {
|
|
19380
|
+
return void 0;
|
|
19381
|
+
}
|
|
19382
|
+
get ready() {
|
|
19383
|
+
return this.agentScope.ready;
|
|
19384
|
+
}
|
|
19209
19385
|
registryFlows(...flows) {
|
|
19210
19386
|
return this.agentScope.registryFlows(...flows);
|
|
19211
19387
|
}
|
|
19212
19388
|
runFlow(name33, input, deps) {
|
|
19213
19389
|
return this.agentScope.runFlow(name33, input, deps);
|
|
19214
19390
|
}
|
|
19391
|
+
runFlowForOutput(name33, input, deps) {
|
|
19392
|
+
return this.agentScope.runFlowForOutput(name33, input, deps);
|
|
19393
|
+
}
|
|
19215
19394
|
};
|
|
19216
19395
|
}
|
|
19217
19396
|
});
|
|
@@ -19259,7 +19438,7 @@ var init_agent_instance = __esm({
|
|
|
19259
19438
|
this.id = record.metadata.id ?? record.metadata.name;
|
|
19260
19439
|
this.fullName = this.owner.id + ":" + this.name;
|
|
19261
19440
|
this.scope = this.providers.getActiveScope();
|
|
19262
|
-
this.hooks = this.scope.
|
|
19441
|
+
this.hooks = this.scope.hooks;
|
|
19263
19442
|
this.inputSchema = record.metadata.inputSchema ?? {};
|
|
19264
19443
|
this.outputSchema = record.metadata.outputSchema;
|
|
19265
19444
|
this.systemInstructions = record.metadata.systemInstructions;
|
|
@@ -22392,10 +22571,10 @@ var init_esm_cache = __esm({
|
|
|
22392
22571
|
if (!this.cacheDir) return void 0;
|
|
22393
22572
|
try {
|
|
22394
22573
|
const path = __require("node:path");
|
|
22395
|
-
const { fileExists:
|
|
22574
|
+
const { fileExists: fileExists6, readJSON } = __require("@frontmcp/utils");
|
|
22396
22575
|
const entryDir = this.getEntryDir(packageName, version);
|
|
22397
22576
|
const metaPath = path.join(entryDir, "meta.json");
|
|
22398
|
-
if (!await
|
|
22577
|
+
if (!await fileExists6(metaPath)) {
|
|
22399
22578
|
return void 0;
|
|
22400
22579
|
}
|
|
22401
22580
|
const meta = await readJSON(metaPath);
|
|
@@ -22405,7 +22584,7 @@ var init_esm_cache = __esm({
|
|
|
22405
22584
|
if (Date.now() - meta.cachedAt > this.maxAgeMs) {
|
|
22406
22585
|
return void 0;
|
|
22407
22586
|
}
|
|
22408
|
-
if (!await
|
|
22587
|
+
if (!await fileExists6(meta.bundlePath)) {
|
|
22409
22588
|
return void 0;
|
|
22410
22589
|
}
|
|
22411
22590
|
this.memoryStore.set(memKey, meta);
|
|
@@ -22469,20 +22648,20 @@ var init_esm_cache = __esm({
|
|
|
22469
22648
|
if (!this.cacheDir) return;
|
|
22470
22649
|
try {
|
|
22471
22650
|
const path = __require("node:path");
|
|
22472
|
-
const { fileExists:
|
|
22473
|
-
const { readdir } = __require("@frontmcp/utils");
|
|
22474
|
-
if (!await
|
|
22651
|
+
const { fileExists: fileExists6, readJSON, rm } = __require("@frontmcp/utils");
|
|
22652
|
+
const { readdir: readdir2 } = __require("@frontmcp/utils");
|
|
22653
|
+
if (!await fileExists6(this.cacheDir)) {
|
|
22475
22654
|
return;
|
|
22476
22655
|
}
|
|
22477
22656
|
let entries;
|
|
22478
22657
|
try {
|
|
22479
|
-
entries = await
|
|
22658
|
+
entries = await readdir2(this.cacheDir);
|
|
22480
22659
|
} catch {
|
|
22481
22660
|
return;
|
|
22482
22661
|
}
|
|
22483
22662
|
for (const dirEntry of entries) {
|
|
22484
22663
|
const metaPath = path.join(this.cacheDir, dirEntry, "meta.json");
|
|
22485
|
-
if (await
|
|
22664
|
+
if (await fileExists6(metaPath)) {
|
|
22486
22665
|
const meta = await readJSON(metaPath);
|
|
22487
22666
|
if (meta?.packageName === packageName) {
|
|
22488
22667
|
await rm(path.join(this.cacheDir, dirEntry), { recursive: true, force: true });
|
|
@@ -22508,20 +22687,20 @@ var init_esm_cache = __esm({
|
|
|
22508
22687
|
if (!this.cacheDir) return removed;
|
|
22509
22688
|
try {
|
|
22510
22689
|
const path = __require("node:path");
|
|
22511
|
-
const { fileExists:
|
|
22512
|
-
const { readdir } = __require("@frontmcp/utils");
|
|
22513
|
-
if (!await
|
|
22690
|
+
const { fileExists: fileExists6, readJSON, rm } = __require("@frontmcp/utils");
|
|
22691
|
+
const { readdir: readdir2 } = __require("@frontmcp/utils");
|
|
22692
|
+
if (!await fileExists6(this.cacheDir)) {
|
|
22514
22693
|
return removed;
|
|
22515
22694
|
}
|
|
22516
22695
|
let entries;
|
|
22517
22696
|
try {
|
|
22518
|
-
entries = await
|
|
22697
|
+
entries = await readdir2(this.cacheDir);
|
|
22519
22698
|
} catch {
|
|
22520
22699
|
return removed;
|
|
22521
22700
|
}
|
|
22522
22701
|
for (const dirEntry of entries) {
|
|
22523
22702
|
const metaPath = path.join(this.cacheDir, dirEntry, "meta.json");
|
|
22524
|
-
if (await
|
|
22703
|
+
if (await fileExists6(metaPath)) {
|
|
22525
22704
|
const meta = await readJSON(metaPath);
|
|
22526
22705
|
if (meta && now - meta.cachedAt > threshold) {
|
|
22527
22706
|
await rm(path.join(this.cacheDir, dirEntry), { recursive: true, force: true });
|
|
@@ -24287,20 +24466,22 @@ function createSessionId(protocol, token, options) {
|
|
|
24287
24466
|
return { id, payload };
|
|
24288
24467
|
}
|
|
24289
24468
|
function updateSessionPayload(sessionId, updates) {
|
|
24469
|
+
let payload;
|
|
24290
24470
|
const existing = cache.get(sessionId);
|
|
24291
24471
|
if (existing) {
|
|
24292
|
-
|
|
24293
|
-
|
|
24294
|
-
|
|
24295
|
-
|
|
24296
|
-
|
|
24297
|
-
|
|
24298
|
-
const payload = decrypted;
|
|
24299
|
-
Object.assign(payload, updates);
|
|
24300
|
-
cache.set(sessionId, payload);
|
|
24301
|
-
return true;
|
|
24472
|
+
payload = existing;
|
|
24473
|
+
} else {
|
|
24474
|
+
const decrypted = safeDecrypt(sessionId);
|
|
24475
|
+
if (hasValidSessionStructure(decrypted) || isValidPublicSessionPayload(decrypted)) {
|
|
24476
|
+
payload = decrypted;
|
|
24477
|
+
}
|
|
24302
24478
|
}
|
|
24303
|
-
return
|
|
24479
|
+
if (!payload) return null;
|
|
24480
|
+
Object.assign(payload, updates);
|
|
24481
|
+
const newSessionId = encryptJson(payload);
|
|
24482
|
+
cache.set(sessionId, payload);
|
|
24483
|
+
cache.set(newSessionId, payload);
|
|
24484
|
+
return newSessionId;
|
|
24304
24485
|
}
|
|
24305
24486
|
var cache;
|
|
24306
24487
|
var init_session_id_utils = __esm({
|
|
@@ -25503,7 +25684,7 @@ var init_oauth_authorize_flow = __esm({
|
|
|
25503
25684
|
|
|
25504
25685
|
// libs/sdk/src/auth/flows/oauth.register.flow.ts
|
|
25505
25686
|
import { z as z56 } from "zod";
|
|
25506
|
-
import { randomUUID as randomUUID12, randomBytes as
|
|
25687
|
+
import { randomUUID as randomUUID12, randomBytes as randomBytes3, base64urlEncode, isProduction as isProduction3 } from "@frontmcp/utils";
|
|
25507
25688
|
var CLIENTS, inputSchema16, outputSchema14, registrationRequestSchema, stateSchema14, plan14, name15, Stage15, OauthRegisterFlow;
|
|
25508
25689
|
var init_oauth_register_flow = __esm({
|
|
25509
25690
|
"libs/sdk/src/auth/flows/oauth.register.flow.ts"() {
|
|
@@ -25605,7 +25786,7 @@ var init_oauth_register_flow = __esm({
|
|
|
25605
25786
|
const client_id = randomUUID12();
|
|
25606
25787
|
let client_secret;
|
|
25607
25788
|
if (token_endpoint_auth_method === "client_secret_post" || token_endpoint_auth_method === "client_secret_basic") {
|
|
25608
|
-
client_secret = base64urlEncode(
|
|
25789
|
+
client_secret = base64urlEncode(randomBytes3(24));
|
|
25609
25790
|
}
|
|
25610
25791
|
this.registered = {
|
|
25611
25792
|
client_id,
|
|
@@ -26831,7 +27012,7 @@ var init_oauth_provider_callback_flow = __esm({
|
|
|
26831
27012
|
|
|
26832
27013
|
// libs/sdk/src/auth/instances/instance.local-primary-auth.ts
|
|
26833
27014
|
import { SignJWT } from "jose";
|
|
26834
|
-
import { randomBytes as
|
|
27015
|
+
import { randomBytes as randomBytes4, randomUUID as randomUUID16, sha256Hex as sha256Hex4, getEnv as getEnv3, base64urlDecode } from "@frontmcp/utils";
|
|
26835
27016
|
import { JwksService as JwksService4, InMemoryAuthorizationStore as InMemoryAuthorizationStore2, verifyPkce } from "@frontmcp/auth";
|
|
26836
27017
|
import {
|
|
26837
27018
|
InMemoryOrchestratedTokenStore,
|
|
@@ -26854,7 +27035,7 @@ var init_instance_local_primary_auth = __esm({
|
|
|
26854
27035
|
init_cimd();
|
|
26855
27036
|
init_oauth_provider_callback_flow();
|
|
26856
27037
|
init_auth_internal_errors();
|
|
26857
|
-
DEFAULT_NO_AUTH_SECRET =
|
|
27038
|
+
DEFAULT_NO_AUTH_SECRET = randomBytes4(32);
|
|
26858
27039
|
LocalPrimaryAuth = class extends FrontMcpAuth {
|
|
26859
27040
|
constructor(scope, providers, options) {
|
|
26860
27041
|
super(options);
|
|
@@ -27772,11 +27953,21 @@ var init_http_request_flow = __esm({
|
|
|
27772
27953
|
const sessionId = authorization.session.id;
|
|
27773
27954
|
request[ServerRequestTokens.sessionId] = sessionId;
|
|
27774
27955
|
if (this.scope.notifications.isSessionTerminated(sessionId)) {
|
|
27775
|
-
|
|
27776
|
-
|
|
27777
|
-
|
|
27956
|
+
const body = request.body;
|
|
27957
|
+
if (body?.method === "initialize") {
|
|
27958
|
+
this.logger.info(
|
|
27959
|
+
`[${this.requestId}] Initialize with terminated session ${sessionId.slice(0, 20)}... - allowing reconnect`
|
|
27960
|
+
);
|
|
27961
|
+
authorization.session = void 0;
|
|
27962
|
+
delete request[ServerRequestTokens.sessionId];
|
|
27963
|
+
delete request.headers["mcp-session-id"];
|
|
27964
|
+
} else {
|
|
27965
|
+
this.logger.warn(`[${this.requestId}] Request to terminated session: ${sessionId.slice(0, 20)}...`);
|
|
27966
|
+
this.respond(httpRespond.notFound("Session not found"));
|
|
27967
|
+
return;
|
|
27968
|
+
}
|
|
27778
27969
|
}
|
|
27779
|
-
const protocol = authorization.session
|
|
27970
|
+
const protocol = authorization.session?.payload?.protocol;
|
|
27780
27971
|
if (protocol) {
|
|
27781
27972
|
this.logger.info(`[${this.requestId}] decision from session: ${protocol}`);
|
|
27782
27973
|
this.state.set("intent", protocol);
|
|
@@ -27899,6 +28090,18 @@ var init_http_request_flow = __esm({
|
|
|
27899
28090
|
this.respond(httpRespond.notFound("Session not found"));
|
|
27900
28091
|
return;
|
|
27901
28092
|
}
|
|
28093
|
+
const authorization = request[ServerRequestTokens.auth];
|
|
28094
|
+
if (authorization?.token) {
|
|
28095
|
+
const transportService = this.scope.transportService;
|
|
28096
|
+
if (transportService) {
|
|
28097
|
+
for (const protocol of ["streamable-http", "sse"]) {
|
|
28098
|
+
try {
|
|
28099
|
+
await transportService.destroyTransporter(protocol, authorization.token, sessionId);
|
|
28100
|
+
} catch {
|
|
28101
|
+
}
|
|
28102
|
+
}
|
|
28103
|
+
}
|
|
28104
|
+
}
|
|
27902
28105
|
this.logger.info(`[${this.requestId}] Session terminated: ${sessionId}`);
|
|
27903
28106
|
this.respond(httpRespond.noContent());
|
|
27904
28107
|
} catch (error) {
|
|
@@ -28076,8 +28279,13 @@ var init_transport_remote = __esm({
|
|
|
28076
28279
|
async destroy(_reason) {
|
|
28077
28280
|
throw new MethodNotImplementedError("RemoteTransporter", "destroy");
|
|
28078
28281
|
}
|
|
28282
|
+
get isInitialized() {
|
|
28283
|
+
return false;
|
|
28284
|
+
}
|
|
28079
28285
|
markAsInitialized() {
|
|
28080
28286
|
}
|
|
28287
|
+
resetForReinitialization() {
|
|
28288
|
+
}
|
|
28081
28289
|
};
|
|
28082
28290
|
}
|
|
28083
28291
|
});
|
|
@@ -28337,6 +28545,11 @@ var init_sse_transport = __esm({
|
|
|
28337
28545
|
// libs/sdk/src/transport/mcp-handlers/initialize-request.handler.ts
|
|
28338
28546
|
import { InitializeRequestSchema } from "@frontmcp/protocol";
|
|
28339
28547
|
import { LATEST_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS } from "@frontmcp/protocol";
|
|
28548
|
+
function persistInitPayload(sessionId, initPayload, ctx) {
|
|
28549
|
+
updateSessionPayload(sessionId, initPayload);
|
|
28550
|
+
const transport = ctx.authInfo?.transport;
|
|
28551
|
+
transport?.setInitSessionPayload(initPayload);
|
|
28552
|
+
}
|
|
28340
28553
|
function guardClientVersion(clientVersion) {
|
|
28341
28554
|
const parsed = new Date(clientVersion);
|
|
28342
28555
|
if (isNaN(parsed.getTime())) {
|
|
@@ -28375,6 +28588,10 @@ function initializeRequestHandler({
|
|
|
28375
28588
|
elicitation: request.params.capabilities.elicitation
|
|
28376
28589
|
};
|
|
28377
28590
|
scope.notifications.setClientCapabilities(sessionId, clientCapabilities);
|
|
28591
|
+
await scope.transportService.updateStoredSessionCapabilities(
|
|
28592
|
+
sessionId,
|
|
28593
|
+
clientCapabilities
|
|
28594
|
+
);
|
|
28378
28595
|
detectedPlatform = detectPlatformFromCapabilities(clientCapabilities);
|
|
28379
28596
|
}
|
|
28380
28597
|
if (request.params.clientInfo) {
|
|
@@ -28393,22 +28610,30 @@ function initializeRequestHandler({
|
|
|
28393
28610
|
if (finalPlatform) {
|
|
28394
28611
|
ctx.authInfo.sessionIdPayload.platformType = finalPlatform;
|
|
28395
28612
|
}
|
|
28396
|
-
|
|
28397
|
-
|
|
28398
|
-
|
|
28399
|
-
|
|
28400
|
-
|
|
28401
|
-
|
|
28613
|
+
persistInitPayload(
|
|
28614
|
+
sessionId,
|
|
28615
|
+
{
|
|
28616
|
+
clientName,
|
|
28617
|
+
clientVersion,
|
|
28618
|
+
supportsElicitation: clientSupportsElicitation,
|
|
28619
|
+
...finalPlatform && { platformType: finalPlatform }
|
|
28620
|
+
},
|
|
28621
|
+
ctx
|
|
28622
|
+
);
|
|
28402
28623
|
}
|
|
28403
28624
|
} else if (ctx.authInfo?.sessionIdPayload) {
|
|
28404
28625
|
ctx.authInfo.sessionIdPayload.supportsElicitation = clientSupportsElicitation;
|
|
28405
28626
|
if (detectedPlatform) {
|
|
28406
28627
|
ctx.authInfo.sessionIdPayload.platformType = detectedPlatform;
|
|
28407
28628
|
}
|
|
28408
|
-
|
|
28409
|
-
|
|
28410
|
-
|
|
28411
|
-
|
|
28629
|
+
persistInitPayload(
|
|
28630
|
+
sessionId,
|
|
28631
|
+
{
|
|
28632
|
+
supportsElicitation: clientSupportsElicitation,
|
|
28633
|
+
...detectedPlatform && { platformType: detectedPlatform }
|
|
28634
|
+
},
|
|
28635
|
+
ctx
|
|
28636
|
+
);
|
|
28412
28637
|
}
|
|
28413
28638
|
}
|
|
28414
28639
|
const requestedVersion = request.params.protocolVersion;
|
|
@@ -29388,15 +29613,43 @@ var init_transport_local_adapter = __esm({
|
|
|
29388
29613
|
* New elicit requests will cancel any pending one.
|
|
29389
29614
|
*/
|
|
29390
29615
|
pendingElicit;
|
|
29616
|
+
/**
|
|
29617
|
+
* Session payload fields set during MCP initialize.
|
|
29618
|
+
* Stored on the adapter instance so they survive across requests in SSE mode
|
|
29619
|
+
* (where each POST creates a fresh anonymous HTTP session) and are available
|
|
29620
|
+
* in distributed environments without relying on local in-memory caches.
|
|
29621
|
+
*/
|
|
29622
|
+
initSessionPayload;
|
|
29623
|
+
/**
|
|
29624
|
+
* Called by the initialize request handler to persist initialization data
|
|
29625
|
+
* on the transport adapter instance. This data is merged into the session
|
|
29626
|
+
* payload on every subsequent request via ensureAuthInfo().
|
|
29627
|
+
*/
|
|
29628
|
+
setInitSessionPayload(payload) {
|
|
29629
|
+
this.initSessionPayload = payload;
|
|
29630
|
+
}
|
|
29391
29631
|
#requestId = 1;
|
|
29392
29632
|
ready;
|
|
29393
29633
|
server;
|
|
29634
|
+
/**
|
|
29635
|
+
* Whether this transport has already been initialized via the MCP initialize handshake.
|
|
29636
|
+
* Override in subclasses that track initialization state.
|
|
29637
|
+
*/
|
|
29638
|
+
get isInitialized() {
|
|
29639
|
+
return false;
|
|
29640
|
+
}
|
|
29394
29641
|
/**
|
|
29395
29642
|
* Marks this transport as pre-initialized for session recreation.
|
|
29396
29643
|
* Override in subclasses that need to set the MCP SDK's _initialized flag.
|
|
29397
29644
|
*/
|
|
29398
29645
|
markAsInitialized() {
|
|
29399
29646
|
}
|
|
29647
|
+
/**
|
|
29648
|
+
* Resets initialization state to allow re-initialization.
|
|
29649
|
+
* Override in subclasses that support session re-initialization.
|
|
29650
|
+
*/
|
|
29651
|
+
resetForReinitialization() {
|
|
29652
|
+
}
|
|
29400
29653
|
connectServer() {
|
|
29401
29654
|
const { info, apps } = this.scope.metadata;
|
|
29402
29655
|
const hasRemoteApps = apps?.some((app) => this.isRemoteApp(app)) ?? false;
|
|
@@ -29406,6 +29659,7 @@ var init_transport_local_adapter = __esm({
|
|
|
29406
29659
|
const hasAgents = this.scope.agents.hasAny();
|
|
29407
29660
|
const completionsCapability = hasPrompts || hasResources ? { completions: {} } : {};
|
|
29408
29661
|
const remoteCapabilities = hasRemoteApps ? this.buildRemoteCapabilities() : {};
|
|
29662
|
+
const elicitationCapability = this.scope.metadata.elicitation?.enabled ? { elicitation: {} } : {};
|
|
29409
29663
|
const serverOptions = {
|
|
29410
29664
|
instructions: "",
|
|
29411
29665
|
capabilities: {
|
|
@@ -29418,7 +29672,8 @@ var init_transport_local_adapter = __esm({
|
|
|
29418
29672
|
// Include agent capabilities (agents as tools)
|
|
29419
29673
|
...completionsCapability,
|
|
29420
29674
|
// MCP logging protocol support - allows clients to set log level via logging/setLevel
|
|
29421
|
-
logging: {}
|
|
29675
|
+
logging: {},
|
|
29676
|
+
...elicitationCapability
|
|
29422
29677
|
},
|
|
29423
29678
|
serverInfo: info
|
|
29424
29679
|
};
|
|
@@ -29483,8 +29738,28 @@ var init_transport_local_adapter = __esm({
|
|
|
29483
29738
|
}
|
|
29484
29739
|
ensureAuthInfo(req, transport) {
|
|
29485
29740
|
const { token, user, session } = req[ServerRequestTokens.auth];
|
|
29486
|
-
|
|
29487
|
-
|
|
29741
|
+
if (!session?.id) {
|
|
29742
|
+
throw new Error(
|
|
29743
|
+
"Session ID is required in ensureAuthInfo. This indicates a bug in session propagation \u2014 the session should have been set by the flow."
|
|
29744
|
+
);
|
|
29745
|
+
}
|
|
29746
|
+
const sessionId = session.id;
|
|
29747
|
+
const sessionPayload = session.payload ?? { protocol: "streamable-http" };
|
|
29748
|
+
if (this.initSessionPayload) {
|
|
29749
|
+
const init = this.initSessionPayload;
|
|
29750
|
+
if (init.supportsElicitation !== void 0 && sessionPayload.supportsElicitation === void 0) {
|
|
29751
|
+
sessionPayload.supportsElicitation = init.supportsElicitation;
|
|
29752
|
+
}
|
|
29753
|
+
if (init.platformType !== void 0 && sessionPayload.platformType === void 0) {
|
|
29754
|
+
sessionPayload["platformType"] = init.platformType;
|
|
29755
|
+
}
|
|
29756
|
+
if (init.clientName !== void 0 && sessionPayload.clientName === void 0) {
|
|
29757
|
+
sessionPayload.clientName = init.clientName;
|
|
29758
|
+
}
|
|
29759
|
+
if (init.clientVersion !== void 0 && sessionPayload.clientVersion === void 0) {
|
|
29760
|
+
sessionPayload.clientVersion = init.clientVersion;
|
|
29761
|
+
}
|
|
29762
|
+
}
|
|
29488
29763
|
const authInfo = {
|
|
29489
29764
|
token,
|
|
29490
29765
|
user,
|
|
@@ -29504,6 +29779,17 @@ var init_transport_local_adapter = __esm({
|
|
|
29504
29779
|
get elicitStore() {
|
|
29505
29780
|
return this.scope.elicitationStore;
|
|
29506
29781
|
}
|
|
29782
|
+
/**
|
|
29783
|
+
* Get the elicitation store, throwing if not initialized.
|
|
29784
|
+
* Use in contexts where elicitation is required (sendElicitRequest, cancelPendingElicit).
|
|
29785
|
+
*/
|
|
29786
|
+
requireElicitStore() {
|
|
29787
|
+
const store = this.elicitStore;
|
|
29788
|
+
if (!store) {
|
|
29789
|
+
throw new Error("Elicitation store not initialized");
|
|
29790
|
+
}
|
|
29791
|
+
return store;
|
|
29792
|
+
}
|
|
29507
29793
|
/**
|
|
29508
29794
|
* Cancel any pending elicitation request.
|
|
29509
29795
|
* Called before sending a new elicit to enforce single-elicit-per-session.
|
|
@@ -29521,9 +29807,12 @@ var init_transport_local_adapter = __esm({
|
|
|
29521
29807
|
clearTimeout(this.pendingElicit.timeoutHandle);
|
|
29522
29808
|
this.pendingElicit.resolve({ status: "cancel" });
|
|
29523
29809
|
const sessionId = this.key.sessionId;
|
|
29524
|
-
const
|
|
29525
|
-
if (
|
|
29526
|
-
await
|
|
29810
|
+
const store = this.elicitStore;
|
|
29811
|
+
if (store) {
|
|
29812
|
+
const pending = await store.getPending(sessionId);
|
|
29813
|
+
if (pending) {
|
|
29814
|
+
await store.publishResult(pending.elicitId, sessionId, { status: "cancel" });
|
|
29815
|
+
}
|
|
29527
29816
|
}
|
|
29528
29817
|
this.pendingElicit = void 0;
|
|
29529
29818
|
this.logger.info("Cancelled previous pending elicit");
|
|
@@ -30120,7 +30409,7 @@ import {
|
|
|
30120
30409
|
hkdfSha256,
|
|
30121
30410
|
encryptAesGcm,
|
|
30122
30411
|
decryptAesGcm,
|
|
30123
|
-
randomBytes as
|
|
30412
|
+
randomBytes as randomBytes5,
|
|
30124
30413
|
base64urlEncode as base64urlEncode2,
|
|
30125
30414
|
base64urlDecode as base64urlDecode2,
|
|
30126
30415
|
getEnv as getEnv4
|
|
@@ -30144,7 +30433,7 @@ async function deriveElicitationKey(sessionId, secret) {
|
|
|
30144
30433
|
async function encryptElicitationData(data, sessionId, secret) {
|
|
30145
30434
|
const key = await deriveElicitationKey(sessionId, secret);
|
|
30146
30435
|
const plaintext = textEncoder.encode(JSON.stringify(data));
|
|
30147
|
-
const iv =
|
|
30436
|
+
const iv = randomBytes5(12);
|
|
30148
30437
|
const { ciphertext, tag } = encryptAesGcm(key, plaintext, iv);
|
|
30149
30438
|
return {
|
|
30150
30439
|
alg: "A256GCM",
|
|
@@ -30880,7 +31169,8 @@ var init_transport_sse_adapter = __esm({
|
|
|
30880
31169
|
const elicitId = elicitationId ?? `elicit-${this.newRequestId}`;
|
|
30881
31170
|
const sessionId = this.key.sessionId;
|
|
30882
31171
|
const expiresAt = Date.now() + ttl;
|
|
30883
|
-
|
|
31172
|
+
const store = this.requireElicitStore();
|
|
31173
|
+
await store.setPending({
|
|
30884
31174
|
elicitId,
|
|
30885
31175
|
sessionId,
|
|
30886
31176
|
createdAt: Date.now(),
|
|
@@ -30923,10 +31213,10 @@ var init_transport_sse_adapter = __esm({
|
|
|
30923
31213
|
settled = true;
|
|
30924
31214
|
this.pendingElicit = void 0;
|
|
30925
31215
|
await unsubscribe?.();
|
|
30926
|
-
await
|
|
31216
|
+
await store.deletePending(sessionId);
|
|
30927
31217
|
reject(new ElicitationTimeoutError(elicitId, ttl));
|
|
30928
31218
|
}, ttl);
|
|
30929
|
-
|
|
31219
|
+
store.subscribeResult(
|
|
30930
31220
|
elicitId,
|
|
30931
31221
|
(result) => {
|
|
30932
31222
|
safeResolve(result);
|
|
@@ -30940,7 +31230,7 @@ var init_transport_sse_adapter = __esm({
|
|
|
30940
31230
|
clearTimeout(timeoutHandle);
|
|
30941
31231
|
this.pendingElicit = void 0;
|
|
30942
31232
|
await unsubscribe?.();
|
|
30943
|
-
await
|
|
31233
|
+
await store.deletePending(sessionId);
|
|
30944
31234
|
reject(err);
|
|
30945
31235
|
});
|
|
30946
31236
|
this.pendingElicit = {
|
|
@@ -30974,9 +31264,16 @@ var init_streamable_http_transport = __esm({
|
|
|
30974
31264
|
* so we need to create fresh instances for each request.
|
|
30975
31265
|
*/
|
|
30976
31266
|
_constructorOptions;
|
|
31267
|
+
/**
|
|
31268
|
+
* When true, the transport recreates the internal transport for each request.
|
|
31269
|
+
* Decoupled from sessionIdGenerator so stateless transports can still
|
|
31270
|
+
* provide a session ID (e.g., '__stateless__') in the response header.
|
|
31271
|
+
*/
|
|
31272
|
+
_isStateless;
|
|
30977
31273
|
constructor(options = {}) {
|
|
30978
31274
|
super(options);
|
|
30979
31275
|
this._constructorOptions = options;
|
|
31276
|
+
this._isStateless = options.isStateless ?? false;
|
|
30980
31277
|
}
|
|
30981
31278
|
/**
|
|
30982
31279
|
* Returns whether the transport has been initialized.
|
|
@@ -31016,6 +31313,31 @@ var init_streamable_http_transport = __esm({
|
|
|
31016
31313
|
}
|
|
31017
31314
|
this._applyInitState(webTransport, sessionId);
|
|
31018
31315
|
}
|
|
31316
|
+
/**
|
|
31317
|
+
* Resets the transport's initialization state to allow re-initialization.
|
|
31318
|
+
*
|
|
31319
|
+
* This is needed when a client reconnects after terminating its session:
|
|
31320
|
+
* the cached transport is still marked as initialized, but the client
|
|
31321
|
+
* needs to re-initialize. Resetting _initialized and sessionId allows
|
|
31322
|
+
* the MCP SDK to process a fresh initialize request.
|
|
31323
|
+
*
|
|
31324
|
+
* This is the inverse of setInitializationState().
|
|
31325
|
+
*/
|
|
31326
|
+
resetForReinitialization() {
|
|
31327
|
+
const webTransport = this._webStandardTransport;
|
|
31328
|
+
if (!webTransport) {
|
|
31329
|
+
this._pendingInitState = void 0;
|
|
31330
|
+
return;
|
|
31331
|
+
}
|
|
31332
|
+
if (!("_initialized" in webTransport)) {
|
|
31333
|
+
throw new InvalidTransportSessionError(
|
|
31334
|
+
"[RecreateableStreamableHTTPServerTransport] Expected _initialized field not found on internal transport. This may indicate an incompatible MCP SDK version."
|
|
31335
|
+
);
|
|
31336
|
+
}
|
|
31337
|
+
webTransport._initialized = false;
|
|
31338
|
+
webTransport.sessionId = void 0;
|
|
31339
|
+
this._pendingInitState = void 0;
|
|
31340
|
+
}
|
|
31019
31341
|
/**
|
|
31020
31342
|
* Applies initialization state to the internal transport.
|
|
31021
31343
|
* @param webTransport - The internal _webStandardTransport object
|
|
@@ -31040,7 +31362,7 @@ var init_streamable_http_transport = __esm({
|
|
|
31040
31362
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
31041
31363
|
async handleRequest(req, res, body) {
|
|
31042
31364
|
const oldWebTransport = this._webStandardTransport;
|
|
31043
|
-
if (oldWebTransport &&
|
|
31365
|
+
if (oldWebTransport && this._isStateless && oldWebTransport._hasHandledRequest) {
|
|
31044
31366
|
const fresh = new WebStandardStreamableHTTPServerTransport(this._constructorOptions);
|
|
31045
31367
|
fresh.onmessage = oldWebTransport.onmessage;
|
|
31046
31368
|
fresh.onclose = oldWebTransport.onclose;
|
|
@@ -31072,14 +31394,16 @@ var init_transport_streamable_http_adapter = __esm({
|
|
|
31072
31394
|
init_streamable_http_transport();
|
|
31073
31395
|
init_errors();
|
|
31074
31396
|
resolveSessionIdGenerator = (transportType, sessionId) => {
|
|
31075
|
-
return transportType === "stateless-http" ?
|
|
31397
|
+
return transportType === "stateless-http" ? () => "__stateless__" : () => sessionId;
|
|
31076
31398
|
};
|
|
31077
31399
|
TransportStreamableHttpAdapter = class extends LocalTransportAdapter {
|
|
31078
31400
|
createTransport(sessionId, response) {
|
|
31079
31401
|
const sessionIdGenerator = resolveSessionIdGenerator(this.key.type, sessionId);
|
|
31080
31402
|
const eventStore = this.scope.eventStore;
|
|
31403
|
+
const isStateless = this.key.type === "stateless-http";
|
|
31081
31404
|
return new RecreateableStreamableHTTPServerTransport({
|
|
31082
31405
|
sessionIdGenerator,
|
|
31406
|
+
isStateless,
|
|
31083
31407
|
onsessionclosed: () => {
|
|
31084
31408
|
},
|
|
31085
31409
|
onsessioninitialized: (sessionId2) => {
|
|
@@ -31173,6 +31497,7 @@ var init_transport_streamable_http_adapter = __esm({
|
|
|
31173
31497
|
*/
|
|
31174
31498
|
async sendElicitRequest(relatedRequestId, message, requestedSchema, options) {
|
|
31175
31499
|
await this.cancelPendingElicit();
|
|
31500
|
+
const store = this.requireElicitStore();
|
|
31176
31501
|
const sessionId = this.key.sessionId;
|
|
31177
31502
|
const flowOutput = await this.scope.runFlowForOutput("elicitation:request", {
|
|
31178
31503
|
relatedRequestId,
|
|
@@ -31197,7 +31522,7 @@ var init_transport_streamable_http_adapter = __esm({
|
|
|
31197
31522
|
} catch (error) {
|
|
31198
31523
|
this.logger.error("[StreamableHttpAdapter] sendElicitRequest: transport.send() failed", error);
|
|
31199
31524
|
try {
|
|
31200
|
-
await
|
|
31525
|
+
await store.deletePending(sessionId);
|
|
31201
31526
|
this.logger.verbose("[StreamableHttpAdapter] sendElicitRequest: cleaned up pending record after send failure");
|
|
31202
31527
|
} catch (cleanupError) {
|
|
31203
31528
|
this.logger.warn("[StreamableHttpAdapter] sendElicitRequest: failed to clean up pending record", cleanupError);
|
|
@@ -31229,10 +31554,10 @@ var init_transport_streamable_http_adapter = __esm({
|
|
|
31229
31554
|
settled = true;
|
|
31230
31555
|
this.pendingElicit = void 0;
|
|
31231
31556
|
await unsubscribe?.();
|
|
31232
|
-
await
|
|
31557
|
+
await store.deletePending(sessionId);
|
|
31233
31558
|
reject(new ElicitationTimeoutError(elicitId, ttl));
|
|
31234
31559
|
}, ttl);
|
|
31235
|
-
|
|
31560
|
+
store.subscribeResult(
|
|
31236
31561
|
elicitId,
|
|
31237
31562
|
(result) => {
|
|
31238
31563
|
safeResolve(result);
|
|
@@ -31246,7 +31571,7 @@ var init_transport_streamable_http_adapter = __esm({
|
|
|
31246
31571
|
clearTimeout(timeoutHandle);
|
|
31247
31572
|
this.pendingElicit = void 0;
|
|
31248
31573
|
await unsubscribe?.();
|
|
31249
|
-
await
|
|
31574
|
+
await store.deletePending(sessionId);
|
|
31250
31575
|
reject(err);
|
|
31251
31576
|
});
|
|
31252
31577
|
this.pendingElicit = {
|
|
@@ -31257,6 +31582,20 @@ var init_transport_streamable_http_adapter = __esm({
|
|
|
31257
31582
|
};
|
|
31258
31583
|
});
|
|
31259
31584
|
}
|
|
31585
|
+
get isInitialized() {
|
|
31586
|
+
return this.transport.isInitialized || this.transport.hasPendingInitState;
|
|
31587
|
+
}
|
|
31588
|
+
/**
|
|
31589
|
+
* Resets the transport's initialization state to allow re-initialization.
|
|
31590
|
+
* Used when a client retries initialize on an already-initialized session
|
|
31591
|
+
* (e.g., after reconnect following session termination).
|
|
31592
|
+
*/
|
|
31593
|
+
resetForReinitialization() {
|
|
31594
|
+
this.transport.resetForReinitialization();
|
|
31595
|
+
this.logger.info("[StreamableHttpAdapter] Reset transport for re-initialization", {
|
|
31596
|
+
sessionId: this.key.sessionId?.slice(0, 20)
|
|
31597
|
+
});
|
|
31598
|
+
}
|
|
31260
31599
|
/**
|
|
31261
31600
|
* Marks this transport as pre-initialized for session recreation.
|
|
31262
31601
|
* This is needed when recreating a transport from Redis because the
|
|
@@ -31331,6 +31670,9 @@ var init_transport_local = __esm({
|
|
|
31331
31670
|
res.status(500).json(rpcError("Internal error"));
|
|
31332
31671
|
}
|
|
31333
31672
|
}
|
|
31673
|
+
get isInitialized() {
|
|
31674
|
+
return this.adapter.isInitialized;
|
|
31675
|
+
}
|
|
31334
31676
|
/**
|
|
31335
31677
|
* Marks this transport as pre-initialized for session recreation.
|
|
31336
31678
|
* This is needed when recreating a transport from Redis because the
|
|
@@ -31339,6 +31681,9 @@ var init_transport_local = __esm({
|
|
|
31339
31681
|
markAsInitialized() {
|
|
31340
31682
|
this.adapter.markAsInitialized();
|
|
31341
31683
|
}
|
|
31684
|
+
resetForReinitialization() {
|
|
31685
|
+
this.adapter.resetForReinitialization();
|
|
31686
|
+
}
|
|
31342
31687
|
async destroy(reason) {
|
|
31343
31688
|
try {
|
|
31344
31689
|
await this.adapter.destroy(reason);
|
|
@@ -31725,6 +32070,79 @@ var init_ext_apps2 = __esm({
|
|
|
31725
32070
|
// libs/sdk/src/transport/flows/handle.streamable-http.flow.ts
|
|
31726
32071
|
import { z as z62 } from "zod";
|
|
31727
32072
|
import { ElicitResultSchema as ElicitResultSchema2, RequestSchema, CallToolResultSchema as CallToolResultSchema3 } from "@frontmcp/protocol";
|
|
32073
|
+
function resolveStreamableHttpSession(params) {
|
|
32074
|
+
const { rawHeader, authorizationSession, createSession } = params;
|
|
32075
|
+
const rawMcpSessionHeader = typeof rawHeader === "string" ? rawHeader : void 0;
|
|
32076
|
+
const mcpSessionHeader = validateMcpSessionHeader(rawMcpSessionHeader);
|
|
32077
|
+
if (rawHeader !== void 0 && !mcpSessionHeader) {
|
|
32078
|
+
return { responded404: true, createdNew: false };
|
|
32079
|
+
}
|
|
32080
|
+
if (mcpSessionHeader) {
|
|
32081
|
+
if (authorizationSession?.id === mcpSessionHeader) {
|
|
32082
|
+
return { session: authorizationSession, createdNew: false, responded404: false };
|
|
32083
|
+
}
|
|
32084
|
+
return { session: { id: mcpSessionHeader }, createdNew: false, responded404: false };
|
|
32085
|
+
}
|
|
32086
|
+
if (authorizationSession) {
|
|
32087
|
+
return { session: authorizationSession, createdNew: false, responded404: false };
|
|
32088
|
+
}
|
|
32089
|
+
return { session: createSession(), createdNew: true, responded404: false };
|
|
32090
|
+
}
|
|
32091
|
+
function classifyStreamableHttpRequest(params) {
|
|
32092
|
+
const { method, body } = params;
|
|
32093
|
+
if (method.toUpperCase() === "GET") {
|
|
32094
|
+
return { requestType: "sseListener" };
|
|
32095
|
+
}
|
|
32096
|
+
const jsonRpcMethod = body?.method;
|
|
32097
|
+
if (jsonRpcMethod === "initialize") {
|
|
32098
|
+
return { requestType: "initialize" };
|
|
32099
|
+
}
|
|
32100
|
+
if (typeof jsonRpcMethod === "string" && jsonRpcMethod.startsWith("ui/")) {
|
|
32101
|
+
return { requestType: "extApps" };
|
|
32102
|
+
}
|
|
32103
|
+
if (ElicitResultSchema2.safeParse(body?.result).success) {
|
|
32104
|
+
return { requestType: "elicitResult" };
|
|
32105
|
+
}
|
|
32106
|
+
if (jsonRpcMethod && RequestSchema.safeParse(body).success) {
|
|
32107
|
+
return { requestType: "message" };
|
|
32108
|
+
}
|
|
32109
|
+
return { error: "Invalid Request" };
|
|
32110
|
+
}
|
|
32111
|
+
function syncStreamableHttpAuthorizationSession(authorization, session) {
|
|
32112
|
+
if (!authorization.session) {
|
|
32113
|
+
authorization.session = session;
|
|
32114
|
+
}
|
|
32115
|
+
}
|
|
32116
|
+
async function lookupStreamableHttpTransport(params) {
|
|
32117
|
+
const { transportService, token, sessionId, response } = params;
|
|
32118
|
+
const inMemoryTransport = await transportService.getTransporter("streamable-http", token, sessionId);
|
|
32119
|
+
if (inMemoryTransport) {
|
|
32120
|
+
return { kind: "transport", source: "memory", transport: inMemoryTransport };
|
|
32121
|
+
}
|
|
32122
|
+
let recreationError;
|
|
32123
|
+
try {
|
|
32124
|
+
const storedSession = await transportService.getStoredSession("streamable-http", token, sessionId);
|
|
32125
|
+
if (storedSession) {
|
|
32126
|
+
const recreatedTransport = await transportService.recreateTransporter(
|
|
32127
|
+
"streamable-http",
|
|
32128
|
+
token,
|
|
32129
|
+
sessionId,
|
|
32130
|
+
storedSession,
|
|
32131
|
+
response
|
|
32132
|
+
);
|
|
32133
|
+
if (recreatedTransport) {
|
|
32134
|
+
return { kind: "transport", source: "redis", transport: recreatedTransport };
|
|
32135
|
+
}
|
|
32136
|
+
}
|
|
32137
|
+
} catch (error) {
|
|
32138
|
+
recreationError = error;
|
|
32139
|
+
}
|
|
32140
|
+
const wasCreated = await transportService.wasSessionCreatedAsync("streamable-http", token, sessionId);
|
|
32141
|
+
if (wasCreated) {
|
|
32142
|
+
return { kind: "session-expired", recreationError };
|
|
32143
|
+
}
|
|
32144
|
+
return { kind: "session-not-initialized", recreationError };
|
|
32145
|
+
}
|
|
31728
32146
|
var plan19, stateSessionSchema, stateSchema18, name20, Stage20, HandleStreamableHttpFlow;
|
|
31729
32147
|
var init_handle_streamable_http_flow = __esm({
|
|
31730
32148
|
"libs/sdk/src/transport/flows/handle.streamable-http.flow.ts"() {
|
|
@@ -31766,64 +32184,60 @@ var init_handle_streamable_http_flow = __esm({
|
|
|
31766
32184
|
const authorization = request[ServerRequestTokens.auth];
|
|
31767
32185
|
const { token } = authorization;
|
|
31768
32186
|
const logger = this.scopeLogger.child("handle:streamable-http:parseInput");
|
|
31769
|
-
const
|
|
31770
|
-
|
|
31771
|
-
|
|
31772
|
-
|
|
32187
|
+
const sessionResolution = resolveStreamableHttpSession({
|
|
32188
|
+
rawHeader: request.headers?.["mcp-session-id"],
|
|
32189
|
+
authorizationSession: authorization.session,
|
|
32190
|
+
createSession: () => {
|
|
32191
|
+
const query = request.query;
|
|
32192
|
+
const skillsOnlyMode = detectSkillsOnlyMode(query);
|
|
32193
|
+
return createSessionId("streamable-http", token, {
|
|
32194
|
+
userAgent: request.headers?.["user-agent"],
|
|
32195
|
+
platformDetectionConfig: this.scope.metadata.transport?.platformDetection,
|
|
32196
|
+
skillsOnlyMode
|
|
32197
|
+
});
|
|
32198
|
+
}
|
|
32199
|
+
});
|
|
32200
|
+
if (sessionResolution.responded404 || !sessionResolution.session) {
|
|
31773
32201
|
logger.warn("parseInput: invalid mcp-session-id header");
|
|
31774
32202
|
this.respond(httpRespond.sessionNotFound("invalid session id"));
|
|
31775
32203
|
return;
|
|
31776
32204
|
}
|
|
31777
|
-
|
|
31778
|
-
if (mcpSessionHeader) {
|
|
31779
|
-
if (authorization.session?.id === mcpSessionHeader) {
|
|
31780
|
-
session = authorization.session;
|
|
31781
|
-
} else {
|
|
31782
|
-
session = { id: mcpSessionHeader };
|
|
31783
|
-
}
|
|
31784
|
-
} else if (authorization.session) {
|
|
31785
|
-
session = authorization.session;
|
|
31786
|
-
} else {
|
|
31787
|
-
const query = request.query;
|
|
31788
|
-
const skillsOnlyMode = detectSkillsOnlyMode(query);
|
|
31789
|
-
session = createSessionId("streamable-http", token, {
|
|
31790
|
-
userAgent: request.headers?.["user-agent"],
|
|
31791
|
-
platformDetectionConfig: this.scope.metadata.transport?.platformDetection,
|
|
31792
|
-
skillsOnlyMode
|
|
31793
|
-
});
|
|
31794
|
-
}
|
|
32205
|
+
const session = sessionResolution.session;
|
|
31795
32206
|
this.state.set(stateSchema18.parse({ token, session }));
|
|
31796
32207
|
logger.info("parseInput: session resolved", { sessionId: session.id?.slice(0, 20) });
|
|
31797
32208
|
}
|
|
31798
32209
|
async router() {
|
|
31799
32210
|
const { request } = this.rawInput;
|
|
31800
32211
|
const logger = this.scopeLogger.child("handle:streamable-http:router");
|
|
31801
|
-
|
|
31802
|
-
|
|
31803
|
-
|
|
32212
|
+
const classification = classifyStreamableHttpRequest({
|
|
32213
|
+
method: request.method,
|
|
32214
|
+
body: request.body
|
|
32215
|
+
});
|
|
32216
|
+
if ("error" in classification) {
|
|
32217
|
+
logger.warn("router: invalid request, no valid method");
|
|
32218
|
+
this.respond(httpRespond.rpcError("Invalid Request"));
|
|
31804
32219
|
return;
|
|
31805
32220
|
}
|
|
31806
|
-
|
|
31807
|
-
|
|
31808
|
-
|
|
31809
|
-
|
|
32221
|
+
this.state.set("requestType", classification.requestType);
|
|
32222
|
+
if (classification.requestType === "sseListener") {
|
|
32223
|
+
logger.info("router: requestType=sseListener, method=GET");
|
|
32224
|
+
} else if (classification.requestType === "initialize") {
|
|
31810
32225
|
logger.info("router: requestType=initialize, method=POST");
|
|
31811
|
-
} else if (
|
|
31812
|
-
|
|
32226
|
+
} else if (classification.requestType === "extApps") {
|
|
32227
|
+
const method = request.body?.method;
|
|
31813
32228
|
logger.info(`router: requestType=extApps, method=${method}`);
|
|
31814
|
-
} else if (
|
|
31815
|
-
this.state.set("requestType", "elicitResult");
|
|
32229
|
+
} else if (classification.requestType === "elicitResult") {
|
|
31816
32230
|
logger.info("router: requestType=elicitResult, method=POST");
|
|
31817
|
-
} else if (method && RequestSchema.safeParse(request.body).success) {
|
|
31818
|
-
this.state.set("requestType", "message");
|
|
31819
|
-
logger.info(`router: requestType=message, method=${method}`);
|
|
31820
32231
|
} else {
|
|
31821
|
-
|
|
31822
|
-
|
|
32232
|
+
const method = request.body?.method;
|
|
32233
|
+
logger.info(`router: requestType=message, method=${method}`);
|
|
31823
32234
|
}
|
|
31824
32235
|
}
|
|
31825
32236
|
async onInitialize() {
|
|
31826
32237
|
const transportService = this.scope.transportService;
|
|
32238
|
+
if (!transportService) {
|
|
32239
|
+
throw new TransportServiceNotAvailableError();
|
|
32240
|
+
}
|
|
31827
32241
|
const logger = this.scope.logger.child("handle:streamable-http:onInitialize");
|
|
31828
32242
|
const { request, response } = this.rawInput;
|
|
31829
32243
|
const { token, session } = this.state.required;
|
|
@@ -31833,7 +32247,15 @@ var init_handle_streamable_http_flow = __esm({
|
|
|
31833
32247
|
tokenPrefix: token?.slice(0, 10)
|
|
31834
32248
|
});
|
|
31835
32249
|
try {
|
|
32250
|
+
const authorization = request[ServerRequestTokens.auth];
|
|
32251
|
+
syncStreamableHttpAuthorizationSession(authorization, session);
|
|
31836
32252
|
const transport = await transportService.createTransporter("streamable-http", token, session.id, response);
|
|
32253
|
+
if (transport.isInitialized) {
|
|
32254
|
+
logger.info("onInitialize: transport already initialized, resetting for re-initialization", {
|
|
32255
|
+
sessionId: session.id?.slice(0, 20)
|
|
32256
|
+
});
|
|
32257
|
+
transport.resetForReinitialization();
|
|
32258
|
+
}
|
|
31837
32259
|
logger.info("onInitialize: transport created, calling initialize");
|
|
31838
32260
|
await transport.initialize(request, response);
|
|
31839
32261
|
logger.info("onInitialize: completed successfully");
|
|
@@ -31851,6 +32273,9 @@ var init_handle_streamable_http_flow = __esm({
|
|
|
31851
32273
|
}
|
|
31852
32274
|
async onElicitResult() {
|
|
31853
32275
|
const transportService = this.scope.transportService;
|
|
32276
|
+
if (!transportService) {
|
|
32277
|
+
throw new TransportServiceNotAvailableError();
|
|
32278
|
+
}
|
|
31854
32279
|
const logger = this.scopeLogger.child("handle:streamable-http:onElicitResult");
|
|
31855
32280
|
const { request, response } = this.rawInput;
|
|
31856
32281
|
const { token, session } = this.state.required;
|
|
@@ -31901,6 +32326,9 @@ var init_handle_streamable_http_flow = __esm({
|
|
|
31901
32326
|
}
|
|
31902
32327
|
async onMessage() {
|
|
31903
32328
|
const transportService = this.scope.transportService;
|
|
32329
|
+
if (!transportService) {
|
|
32330
|
+
throw new TransportServiceNotAvailableError();
|
|
32331
|
+
}
|
|
31904
32332
|
const logger = this.scopeLogger.child("handle:streamable-http:onMessage");
|
|
31905
32333
|
const { request, response } = this.rawInput;
|
|
31906
32334
|
const { token, session } = this.state.required;
|
|
@@ -31908,44 +32336,21 @@ var init_handle_streamable_http_flow = __esm({
|
|
|
31908
32336
|
sessionId: session.id?.slice(0, 20),
|
|
31909
32337
|
hasToken: !!token
|
|
31910
32338
|
});
|
|
31911
|
-
|
|
31912
|
-
|
|
31913
|
-
|
|
31914
|
-
|
|
31915
|
-
|
|
31916
|
-
|
|
31917
|
-
|
|
31918
|
-
|
|
31919
|
-
|
|
31920
|
-
found: !!storedSession,
|
|
31921
|
-
initialized: storedSession?.initialized
|
|
31922
|
-
});
|
|
31923
|
-
if (storedSession) {
|
|
31924
|
-
logger.verbose("onMessage: recreating transport from stored session", {
|
|
31925
|
-
sessionId: session.id?.slice(0, 20),
|
|
31926
|
-
createdAt: storedSession.createdAt,
|
|
31927
|
-
initialized: storedSession.initialized
|
|
31928
|
-
});
|
|
31929
|
-
transport = await transportService.recreateTransporter(
|
|
31930
|
-
"streamable-http",
|
|
31931
|
-
token,
|
|
31932
|
-
session.id,
|
|
31933
|
-
storedSession,
|
|
31934
|
-
response
|
|
31935
|
-
);
|
|
31936
|
-
logger.verbose("onMessage: transport recreated successfully");
|
|
31937
|
-
}
|
|
31938
|
-
} catch (error) {
|
|
32339
|
+
const transportLookup = await lookupStreamableHttpTransport({
|
|
32340
|
+
transportService,
|
|
32341
|
+
token,
|
|
32342
|
+
sessionId: session.id,
|
|
32343
|
+
response
|
|
32344
|
+
});
|
|
32345
|
+
if (transportLookup.kind !== "transport") {
|
|
32346
|
+
const body = request.body;
|
|
32347
|
+
if (transportLookup.recreationError) {
|
|
31939
32348
|
logger.warn("Failed to recreate transport from stored session", {
|
|
31940
32349
|
sessionId: session.id?.slice(0, 20),
|
|
31941
|
-
error:
|
|
32350
|
+
error: transportLookup.recreationError instanceof Error ? transportLookup.recreationError.message : String(transportLookup.recreationError)
|
|
31942
32351
|
});
|
|
31943
32352
|
}
|
|
31944
|
-
|
|
31945
|
-
if (!transport) {
|
|
31946
|
-
const wasCreated = await transportService.wasSessionCreatedAsync("streamable-http", token, session.id);
|
|
31947
|
-
const body = request.body;
|
|
31948
|
-
if (wasCreated) {
|
|
32353
|
+
if (transportLookup.kind === "session-expired") {
|
|
31949
32354
|
logger.info("Session expired - client should re-initialize", {
|
|
31950
32355
|
sessionId: session.id?.slice(0, 20),
|
|
31951
32356
|
tokenHash: token.slice(0, 8),
|
|
@@ -31967,6 +32372,8 @@ var init_handle_streamable_http_flow = __esm({
|
|
|
31967
32372
|
}
|
|
31968
32373
|
return;
|
|
31969
32374
|
}
|
|
32375
|
+
const transport = transportLookup.transport;
|
|
32376
|
+
logger.verbose("onMessage: transport resolved", { source: transportLookup.source });
|
|
31970
32377
|
try {
|
|
31971
32378
|
await transport.handleRequest(request, response);
|
|
31972
32379
|
this.handled();
|
|
@@ -31985,6 +32392,9 @@ var init_handle_streamable_http_flow = __esm({
|
|
|
31985
32392
|
}
|
|
31986
32393
|
async onSseListener() {
|
|
31987
32394
|
const transportService = this.scope.transportService;
|
|
32395
|
+
if (!transportService) {
|
|
32396
|
+
throw new TransportServiceNotAvailableError();
|
|
32397
|
+
}
|
|
31988
32398
|
const logger = this.scopeLogger.child("handle:streamable-http:onSseListener");
|
|
31989
32399
|
const { request, response } = this.rawInput;
|
|
31990
32400
|
const { token, session } = this.state.required;
|
|
@@ -32022,6 +32432,9 @@ var init_handle_streamable_http_flow = __esm({
|
|
|
32022
32432
|
}
|
|
32023
32433
|
async onExtApps() {
|
|
32024
32434
|
const transportService = this.scope.transportService;
|
|
32435
|
+
if (!transportService) {
|
|
32436
|
+
throw new TransportServiceNotAvailableError();
|
|
32437
|
+
}
|
|
32025
32438
|
const logger = this.scopeLogger.child("handle:streamable-http:onExtApps");
|
|
32026
32439
|
const { request, response } = this.rawInput;
|
|
32027
32440
|
const { token, session } = this.state.required;
|
|
@@ -32072,8 +32485,7 @@ var init_handle_streamable_http_flow = __esm({
|
|
|
32072
32485
|
}
|
|
32073
32486
|
return;
|
|
32074
32487
|
}
|
|
32075
|
-
const
|
|
32076
|
-
const configuredCapabilities = scope.metadata.extApps?.hostCapabilities;
|
|
32488
|
+
const configuredCapabilities = this.scope.metadata.extApps?.hostCapabilities;
|
|
32077
32489
|
const hostCapabilities = {
|
|
32078
32490
|
serverToolProxy: configuredCapabilities?.serverToolProxy ?? true,
|
|
32079
32491
|
logging: configuredCapabilities?.logging ?? true,
|
|
@@ -32082,9 +32494,9 @@ var init_handle_streamable_http_flow = __esm({
|
|
|
32082
32494
|
const handler = createExtAppsMessageHandler({
|
|
32083
32495
|
context: {
|
|
32084
32496
|
sessionId: session.id,
|
|
32085
|
-
logger: scope.logger,
|
|
32497
|
+
logger: this.scope.logger,
|
|
32086
32498
|
callTool: async (name33, args) => {
|
|
32087
|
-
const result = await scope.runFlow("tools:call-tool", {
|
|
32499
|
+
const result = await this.scope.runFlow("tools:call-tool", {
|
|
32088
32500
|
request: { method: "tools/call", params: { name: name33, arguments: args } },
|
|
32089
32501
|
ctx: {
|
|
32090
32502
|
authInfo: {
|
|
@@ -32170,6 +32582,7 @@ var init_handle_sse_flow = __esm({
|
|
|
32170
32582
|
"libs/sdk/src/transport/flows/handle.sse.flow.ts"() {
|
|
32171
32583
|
"use strict";
|
|
32172
32584
|
init_common();
|
|
32585
|
+
init_errors();
|
|
32173
32586
|
init_session_id_utils();
|
|
32174
32587
|
init_skill_mode_utils();
|
|
32175
32588
|
plan20 = {
|
|
@@ -32239,10 +32652,9 @@ var init_handle_sse_flow = __esm({
|
|
|
32239
32652
|
}
|
|
32240
32653
|
async router() {
|
|
32241
32654
|
const { request } = this.rawInput;
|
|
32242
|
-
const scope = this.scope;
|
|
32243
32655
|
const requestPath = normalizeEntryPrefix(request.path);
|
|
32244
|
-
const prefix = normalizeEntryPrefix(scope.entryPath);
|
|
32245
|
-
const scopePath = normalizeScopeBase(scope.routeBase);
|
|
32656
|
+
const prefix = normalizeEntryPrefix(this.scope.entryPath);
|
|
32657
|
+
const scopePath = normalizeScopeBase(this.scope.routeBase);
|
|
32246
32658
|
const basePath = `${prefix}${scopePath}`;
|
|
32247
32659
|
if (requestPath === `${basePath}/sse`) {
|
|
32248
32660
|
this.state.set("requestType", "initialize");
|
|
@@ -32252,6 +32664,9 @@ var init_handle_sse_flow = __esm({
|
|
|
32252
32664
|
}
|
|
32253
32665
|
async onInitialize() {
|
|
32254
32666
|
const transportService = this.scope.transportService;
|
|
32667
|
+
if (!transportService) {
|
|
32668
|
+
throw new TransportServiceNotAvailableError();
|
|
32669
|
+
}
|
|
32255
32670
|
const { request, response } = this.rawInput;
|
|
32256
32671
|
const { token, session } = this.state.required;
|
|
32257
32672
|
const transport = await transportService.createTransporter("sse", token, session.id, response);
|
|
@@ -32263,6 +32678,9 @@ var init_handle_sse_flow = __esm({
|
|
|
32263
32678
|
}
|
|
32264
32679
|
async onMessage() {
|
|
32265
32680
|
const transportService = this.scope.transportService;
|
|
32681
|
+
if (!transportService) {
|
|
32682
|
+
throw new TransportServiceNotAvailableError();
|
|
32683
|
+
}
|
|
32266
32684
|
const logger = this.scopeLogger.child("handle:legacy-sse:onMessage");
|
|
32267
32685
|
const { request, response } = this.rawInput;
|
|
32268
32686
|
const { token, session } = this.state.required;
|
|
@@ -32335,6 +32753,7 @@ var init_handle_stateless_http_flow = __esm({
|
|
|
32335
32753
|
"libs/sdk/src/transport/flows/handle.stateless-http.flow.ts"() {
|
|
32336
32754
|
"use strict";
|
|
32337
32755
|
init_common();
|
|
32756
|
+
init_errors();
|
|
32338
32757
|
plan21 = {
|
|
32339
32758
|
pre: ["parseInput", "router"],
|
|
32340
32759
|
execute: ["handleRequest"],
|
|
@@ -32382,6 +32801,9 @@ var init_handle_stateless_http_flow = __esm({
|
|
|
32382
32801
|
}
|
|
32383
32802
|
async handleRequest() {
|
|
32384
32803
|
const transportService = this.scope.transportService;
|
|
32804
|
+
if (!transportService) {
|
|
32805
|
+
throw new TransportServiceNotAvailableError();
|
|
32806
|
+
}
|
|
32385
32807
|
const logger = this.scope.logger.child("HandleStatelessHttpFlow");
|
|
32386
32808
|
const { request, response } = this.rawInput;
|
|
32387
32809
|
const { token, isAuthenticated, requestType } = this.state;
|
|
@@ -32717,6 +33139,12 @@ var init_transport_registry = __esm({
|
|
|
32717
33139
|
transporter.markAsInitialized();
|
|
32718
33140
|
}
|
|
32719
33141
|
this.insertLocal(key, transporter);
|
|
33142
|
+
if (storedSession.clientCapabilities) {
|
|
33143
|
+
this.scope.notifications.setClientCapabilities(sessionId, storedSession.clientCapabilities);
|
|
33144
|
+
this.scope.logger.verbose("[TransportService] Restored client capabilities from stored session", {
|
|
33145
|
+
sessionId: sessionId.slice(0, 20)
|
|
33146
|
+
});
|
|
33147
|
+
}
|
|
32720
33148
|
if (sessionStore) {
|
|
32721
33149
|
const updatedSession = {
|
|
32722
33150
|
...storedSession,
|
|
@@ -32814,6 +33242,40 @@ var init_transport_registry = __esm({
|
|
|
32814
33242
|
}
|
|
32815
33243
|
throw new InvalidTransportSessionError("Invalid session: cannot destroy non-existent transporter.");
|
|
32816
33244
|
}
|
|
33245
|
+
/**
|
|
33246
|
+
* Update the stored session in Redis with client capabilities from the initialize handshake.
|
|
33247
|
+
* This ensures capabilities survive session recreation (e.g., after server restart or transport eviction).
|
|
33248
|
+
*
|
|
33249
|
+
* Best-effort: failures are logged but do not throw.
|
|
33250
|
+
* No-op when sessionStore is not configured.
|
|
33251
|
+
*/
|
|
33252
|
+
async updateStoredSessionCapabilities(sessionId, clientCapabilities) {
|
|
33253
|
+
if (!this.sessionStore) return;
|
|
33254
|
+
try {
|
|
33255
|
+
const stored = await this.sessionStore.get(sessionId);
|
|
33256
|
+
if (!stored) {
|
|
33257
|
+
this.scope.logger.verbose("[TransportService] Cannot update capabilities: session not found in store", {
|
|
33258
|
+
sessionId: sessionId.slice(0, 20)
|
|
33259
|
+
});
|
|
33260
|
+
return;
|
|
33261
|
+
}
|
|
33262
|
+
const updatedSession = {
|
|
33263
|
+
...stored,
|
|
33264
|
+
clientCapabilities,
|
|
33265
|
+
lastAccessedAt: Date.now()
|
|
33266
|
+
};
|
|
33267
|
+
const defaultTtlMs = this.getDefaultTtlMs();
|
|
33268
|
+
await this.sessionStore.set(sessionId, updatedSession, defaultTtlMs);
|
|
33269
|
+
this.scope.logger.verbose("[TransportService] Persisted client capabilities to session store", {
|
|
33270
|
+
sessionId: sessionId.slice(0, 20)
|
|
33271
|
+
});
|
|
33272
|
+
} catch (err) {
|
|
33273
|
+
this.scope.logger.warn("[TransportService] Failed to persist client capabilities", {
|
|
33274
|
+
sessionId: sessionId.slice(0, 20),
|
|
33275
|
+
error: err instanceof Error ? err.message : String(err)
|
|
33276
|
+
});
|
|
33277
|
+
}
|
|
33278
|
+
}
|
|
32817
33279
|
/**
|
|
32818
33280
|
* Get or create a shared singleton transport for anonymous stateless requests.
|
|
32819
33281
|
* All anonymous requests share the same transport instance.
|
|
@@ -35901,18 +36363,15 @@ var init_complete_flow = __esm({
|
|
|
35901
36363
|
} else {
|
|
35902
36364
|
const resourceMatch = this.scope.resources.findResourceForUri(uri);
|
|
35903
36365
|
if (resourceMatch) {
|
|
35904
|
-
const
|
|
35905
|
-
if (
|
|
35906
|
-
|
|
35907
|
-
|
|
35908
|
-
|
|
35909
|
-
|
|
35910
|
-
|
|
35911
|
-
|
|
35912
|
-
|
|
35913
|
-
} catch (e) {
|
|
35914
|
-
this.logger.warn(`complete: completer failed for resource "${uri}" argument "${argName}": ${e}`);
|
|
35915
|
-
}
|
|
36366
|
+
const completer = resourceMatch.instance.getArgumentCompleter(argName);
|
|
36367
|
+
if (completer) {
|
|
36368
|
+
try {
|
|
36369
|
+
const result = await completer(argValue);
|
|
36370
|
+
values = result.values || [];
|
|
36371
|
+
total = result.total;
|
|
36372
|
+
hasMore = result.hasMore;
|
|
36373
|
+
} catch (e) {
|
|
36374
|
+
this.logger.warn(`complete: completer failed for resource "${uri}" argument "${argName}": ${e}`);
|
|
35916
36375
|
}
|
|
35917
36376
|
}
|
|
35918
36377
|
} else {
|
|
@@ -36031,11 +36490,10 @@ var init_call_agent_flow = __esm({
|
|
|
36031
36490
|
throw new InvalidMethodError(method, "tools/call");
|
|
36032
36491
|
}
|
|
36033
36492
|
const { name: toolName } = params;
|
|
36034
|
-
const scope = this.scope;
|
|
36035
36493
|
const agentId = toolName;
|
|
36036
36494
|
let agent;
|
|
36037
|
-
if (scope.agents) {
|
|
36038
|
-
agent = scope.agents.findById(agentId) ?? scope.agents.findByName(agentId);
|
|
36495
|
+
if (this.scope.agents) {
|
|
36496
|
+
agent = this.scope.agents.findById(agentId) ?? this.scope.agents.findByName(agentId);
|
|
36039
36497
|
}
|
|
36040
36498
|
const agentOwnerId = agent?.owner?.id;
|
|
36041
36499
|
const progressToken = params._meta?.progressToken;
|
|
@@ -36051,8 +36509,7 @@ var init_call_agent_flow = __esm({
|
|
|
36051
36509
|
}
|
|
36052
36510
|
async findAgent() {
|
|
36053
36511
|
this.logger.verbose("findAgent:start");
|
|
36054
|
-
const
|
|
36055
|
-
const agents = scope.agents;
|
|
36512
|
+
const agents = this.scope.agents;
|
|
36056
36513
|
if (!agents) {
|
|
36057
36514
|
this.logger.warn("findAgent: no agent registry available");
|
|
36058
36515
|
throw new AgentNotFoundError(this.state.required.input.name);
|
|
@@ -36473,7 +36930,10 @@ var init_elicitation_request_flow = __esm({
|
|
|
36473
36930
|
async storePendingRecord() {
|
|
36474
36931
|
this.logger.verbose("storePendingRecord:start");
|
|
36475
36932
|
const { elicitId, sessionId, message, mode, expiresAt, requestedSchema } = this.state.required;
|
|
36476
|
-
const
|
|
36933
|
+
const store = this.scope.elicitationStore;
|
|
36934
|
+
if (!store) {
|
|
36935
|
+
throw new ElicitationStoreNotInitializedError();
|
|
36936
|
+
}
|
|
36477
36937
|
const pendingRecord = {
|
|
36478
36938
|
elicitId,
|
|
36479
36939
|
sessionId,
|
|
@@ -36483,7 +36943,7 @@ var init_elicitation_request_flow = __esm({
|
|
|
36483
36943
|
mode,
|
|
36484
36944
|
requestedSchema
|
|
36485
36945
|
};
|
|
36486
|
-
await
|
|
36946
|
+
await store.setPending(pendingRecord);
|
|
36487
36947
|
this.state.set("pendingRecord", pendingRecord);
|
|
36488
36948
|
this.logger.verbose("storePendingRecord:done", { elicitId, sessionId });
|
|
36489
36949
|
}
|
|
@@ -36610,8 +37070,11 @@ var init_elicitation_result_flow = __esm({
|
|
|
36610
37070
|
async lookupPending() {
|
|
36611
37071
|
this.logger.verbose("lookupPending:start");
|
|
36612
37072
|
const { sessionId } = this.state.required;
|
|
36613
|
-
const
|
|
36614
|
-
|
|
37073
|
+
const store = this.scope.elicitationStore;
|
|
37074
|
+
if (!store) {
|
|
37075
|
+
throw new ElicitationStoreNotInitializedError();
|
|
37076
|
+
}
|
|
37077
|
+
const pendingRecord = await store.getPending(sessionId);
|
|
36615
37078
|
this.state.set("pendingRecord", pendingRecord ?? void 0);
|
|
36616
37079
|
if (!pendingRecord) {
|
|
36617
37080
|
this.logger.verbose("lookupPending:notFound", { sessionId });
|
|
@@ -36663,14 +37126,14 @@ var init_elicitation_result_flow = __esm({
|
|
|
36663
37126
|
this.logger.verbose("publishResult:start");
|
|
36664
37127
|
const { pendingRecord, elicitResult } = this.state;
|
|
36665
37128
|
const { sessionId } = this.state.required;
|
|
36666
|
-
const
|
|
36667
|
-
if (!pendingRecord || !elicitResult) {
|
|
37129
|
+
const store = this.scope.elicitationStore;
|
|
37130
|
+
if (!pendingRecord || !elicitResult || !store) {
|
|
36668
37131
|
this.state.set("handled", false);
|
|
36669
37132
|
this.logger.verbose("publishResult:skip (no pending or no result)");
|
|
36670
37133
|
return;
|
|
36671
37134
|
}
|
|
36672
37135
|
try {
|
|
36673
|
-
await
|
|
37136
|
+
await store.publishResult(pendingRecord.elicitId, sessionId, elicitResult);
|
|
36674
37137
|
this.state.set("handled", true);
|
|
36675
37138
|
this.logger.verbose("publishResult:done", {
|
|
36676
37139
|
elicitId: pendingRecord.elicitId,
|
|
@@ -36767,30 +37230,30 @@ var require_dist = __commonJS({
|
|
|
36767
37230
|
sqliteStorageOptionsSchema: () => sqliteStorageOptionsSchema
|
|
36768
37231
|
});
|
|
36769
37232
|
module.exports = __toCommonJS2(index_exports);
|
|
36770
|
-
var
|
|
37233
|
+
var import_utils77 = __require("@frontmcp/utils");
|
|
36771
37234
|
var HKDF_SALT = new TextEncoder().encode("frontmcp-sqlite-storage-v1");
|
|
36772
37235
|
var HKDF_INFO = new TextEncoder().encode("aes-256-gcm-value-encryption");
|
|
36773
37236
|
var KEY_LENGTH = 32;
|
|
36774
37237
|
function deriveEncryptionKey(secret) {
|
|
36775
37238
|
const ikm = new TextEncoder().encode(secret);
|
|
36776
|
-
return (0,
|
|
37239
|
+
return (0, import_utils77.hkdfSha256)(ikm, HKDF_SALT, HKDF_INFO, KEY_LENGTH);
|
|
36777
37240
|
}
|
|
36778
37241
|
var SEPARATOR = ":";
|
|
36779
37242
|
function encryptValue(key, plaintext) {
|
|
36780
|
-
const iv = (0,
|
|
37243
|
+
const iv = (0, import_utils77.randomBytes)(12);
|
|
36781
37244
|
const plaintextBytes = new TextEncoder().encode(plaintext);
|
|
36782
|
-
const { ciphertext, tag } = (0,
|
|
36783
|
-
return [(0,
|
|
37245
|
+
const { ciphertext, tag } = (0, import_utils77.encryptAesGcm)(key, plaintextBytes, iv);
|
|
37246
|
+
return [(0, import_utils77.base64urlEncode)(iv), (0, import_utils77.base64urlEncode)(tag), (0, import_utils77.base64urlEncode)(ciphertext)].join(SEPARATOR);
|
|
36784
37247
|
}
|
|
36785
37248
|
function decryptValue(key, encrypted) {
|
|
36786
37249
|
const parts = encrypted.split(SEPARATOR);
|
|
36787
37250
|
if (parts.length !== 3) {
|
|
36788
37251
|
throw new Error("Invalid encrypted value format");
|
|
36789
37252
|
}
|
|
36790
|
-
const iv = (0,
|
|
36791
|
-
const tag = (0,
|
|
36792
|
-
const ciphertext = (0,
|
|
36793
|
-
const plaintext = (0,
|
|
37253
|
+
const iv = (0, import_utils77.base64urlDecode)(parts[0]);
|
|
37254
|
+
const tag = (0, import_utils77.base64urlDecode)(parts[1]);
|
|
37255
|
+
const ciphertext = (0, import_utils77.base64urlDecode)(parts[2]);
|
|
37256
|
+
const plaintext = (0, import_utils77.decryptAesGcm)(key, ciphertext, iv, tag);
|
|
36794
37257
|
return new TextDecoder().decode(plaintext);
|
|
36795
37258
|
}
|
|
36796
37259
|
var SqliteKvStore = class {
|
|
@@ -38063,7 +38526,7 @@ var init_job_instance = __esm({
|
|
|
38063
38526
|
this.name = record.metadata.id || record.metadata.name;
|
|
38064
38527
|
this.fullName = this.owner.id + ":" + this.name;
|
|
38065
38528
|
this.scope = this._providers.getActiveScope();
|
|
38066
|
-
this.hooks = this.scope.
|
|
38529
|
+
this.hooks = this.scope.hooks;
|
|
38067
38530
|
this.inputSchema = record.metadata.inputSchema ?? {};
|
|
38068
38531
|
this.outputSchema = record.metadata.outputSchema ?? {};
|
|
38069
38532
|
this.ready = this.initialize();
|
|
@@ -38449,7 +38912,7 @@ var init_workflow_instance = __esm({
|
|
|
38449
38912
|
this.name = record.metadata.id || record.metadata.name;
|
|
38450
38913
|
this.fullName = this.owner.id + ":" + this.name;
|
|
38451
38914
|
this.scope = this._providers.getActiveScope();
|
|
38452
|
-
this.hooks = this.scope.
|
|
38915
|
+
this.hooks = this.scope.hooks;
|
|
38453
38916
|
this.ready = this.initialize();
|
|
38454
38917
|
}
|
|
38455
38918
|
async initialize() {
|
|
@@ -40107,13 +40570,12 @@ var init_scope_instance = __esm({
|
|
|
40107
40570
|
init_plugin_registry();
|
|
40108
40571
|
init_elicitation2();
|
|
40109
40572
|
init_flows2();
|
|
40110
|
-
init_elicitation_error();
|
|
40111
40573
|
init_send_elicitation_result_tool();
|
|
40112
40574
|
init_tool_utils();
|
|
40113
40575
|
init_tool_instance();
|
|
40114
40576
|
init_event_stores();
|
|
40115
40577
|
init_job_scope_helper();
|
|
40116
|
-
Scope = class _Scope extends
|
|
40578
|
+
Scope = class _Scope extends ScopeEntry3 {
|
|
40117
40579
|
id;
|
|
40118
40580
|
globalProviders;
|
|
40119
40581
|
logger;
|
|
@@ -40237,20 +40699,21 @@ var init_scope_instance = __esm({
|
|
|
40237
40699
|
};
|
|
40238
40700
|
this.scopePlugins = new PluginRegistry(this.scopeProviders, serverPlugins, scopeRef, serverPluginScopeInfo);
|
|
40239
40701
|
}
|
|
40702
|
+
if (this.scopePlugins) {
|
|
40703
|
+
await this.scopePlugins.ready;
|
|
40704
|
+
}
|
|
40240
40705
|
this.scopeTools = new ToolRegistry(this.scopeProviders, [], scopeRef);
|
|
40241
40706
|
this.scopeResources = new ResourceRegistry(this.scopeProviders, [], scopeRef);
|
|
40242
40707
|
this.scopePrompts = new PromptRegistry(this.scopeProviders, [], scopeRef);
|
|
40243
40708
|
this.scopeAgents = new AgentRegistry(this.scopeProviders, [], scopeRef);
|
|
40244
40709
|
this.scopeSkills = new SkillRegistry(this.scopeProviders, this.metadata.skills ?? [], scopeRef);
|
|
40245
|
-
|
|
40710
|
+
await Promise.all([
|
|
40246
40711
|
this.scopeTools.ready,
|
|
40247
40712
|
this.scopeResources.ready,
|
|
40248
40713
|
this.scopePrompts.ready,
|
|
40249
40714
|
this.scopeAgents.ready,
|
|
40250
40715
|
this.scopeSkills.ready
|
|
40251
|
-
];
|
|
40252
|
-
if (this.scopePlugins) batch2.push(this.scopePlugins.ready);
|
|
40253
|
-
await Promise.all(batch2);
|
|
40716
|
+
]);
|
|
40254
40717
|
if (this.scopePlugins) {
|
|
40255
40718
|
const pluginNames = this.scopePlugins.getPluginNames();
|
|
40256
40719
|
this.logger.verbose(`PluginRegistry initialized (${pluginNames.length} plugin(s): [${pluginNames.join(", ")}])`);
|
|
@@ -40522,7 +40985,7 @@ var init_scope_instance = __esm({
|
|
|
40522
40985
|
{
|
|
40523
40986
|
scope: ProviderScope2.GLOBAL,
|
|
40524
40987
|
name: "ScopeEntry",
|
|
40525
|
-
provide:
|
|
40988
|
+
provide: ScopeEntry3,
|
|
40526
40989
|
useValue: this
|
|
40527
40990
|
},
|
|
40528
40991
|
{
|
|
@@ -40619,9 +41082,6 @@ var init_scope_instance = __esm({
|
|
|
40619
41082
|
* @see createElicitationStore for factory implementation details
|
|
40620
41083
|
*/
|
|
40621
41084
|
get elicitationStore() {
|
|
40622
|
-
if (!this._elicitationStore) {
|
|
40623
|
-
throw new ElicitationStoreNotInitializedError();
|
|
40624
|
-
}
|
|
40625
41085
|
return this._elicitationStore;
|
|
40626
41086
|
}
|
|
40627
41087
|
/**
|
|
@@ -40655,7 +41115,7 @@ var init_scope_instance = __esm({
|
|
|
40655
41115
|
* Register the sendElicitationResult system tool.
|
|
40656
41116
|
* This tool is hidden by default and only shown to clients that don't support elicitation.
|
|
40657
41117
|
*/
|
|
40658
|
-
registerSendElicitationResultTool(
|
|
41118
|
+
registerSendElicitationResultTool(_scopeRef) {
|
|
40659
41119
|
try {
|
|
40660
41120
|
const toolRecord = normalizeTool(SendElicitationResultTool);
|
|
40661
41121
|
const systemToolEntry = new ToolInstance(toolRecord, this.scopeProviders, {
|
|
@@ -40866,7 +41326,7 @@ var init_base_host_adapter = __esm({
|
|
|
40866
41326
|
import * as http from "node:http";
|
|
40867
41327
|
import express from "express";
|
|
40868
41328
|
import cors from "cors";
|
|
40869
|
-
import { fileExists as
|
|
41329
|
+
import { fileExists as fileExists4, unlink } from "@frontmcp/utils";
|
|
40870
41330
|
var ExpressHostAdapter;
|
|
40871
41331
|
var init_express_host_adapter = __esm({
|
|
40872
41332
|
"libs/sdk/src/server/adapters/express.host.adapter.ts"() {
|
|
@@ -40963,7 +41423,7 @@ var init_express_host_adapter = __esm({
|
|
|
40963
41423
|
}
|
|
40964
41424
|
async cleanupStaleSocket(socketPath) {
|
|
40965
41425
|
try {
|
|
40966
|
-
if (await
|
|
41426
|
+
if (await fileExists4(socketPath)) {
|
|
40967
41427
|
await unlink(socketPath);
|
|
40968
41428
|
}
|
|
40969
41429
|
} catch {
|
|
@@ -41088,7 +41548,7 @@ var init_front_mcp_providers = __esm({
|
|
|
41088
41548
|
useValue: metadata
|
|
41089
41549
|
})
|
|
41090
41550
|
};
|
|
41091
|
-
DEFAULT_HTTP_OPTIONS = { port: 3e3, entryPath: "/mcp" };
|
|
41551
|
+
DEFAULT_HTTP_OPTIONS = { port: Number(process.env["PORT"]) || 3e3, entryPath: "/mcp" };
|
|
41092
41552
|
frontMcpServer = AsyncProvider({
|
|
41093
41553
|
name: "frontmcp:server",
|
|
41094
41554
|
scope: ProviderScope5.GLOBAL,
|
|
@@ -42421,7 +42881,7 @@ var front_mcp_exports = {};
|
|
|
42421
42881
|
__export(front_mcp_exports, {
|
|
42422
42882
|
FrontMcpInstance: () => FrontMcpInstance
|
|
42423
42883
|
});
|
|
42424
|
-
import { randomUUID as randomUUID25, fileExists as
|
|
42884
|
+
import { randomUUID as randomUUID25, fileExists as fileExists5, unlink as unlink2 } from "@frontmcp/utils";
|
|
42425
42885
|
var FrontMcpInstance;
|
|
42426
42886
|
var init_front_mcp = __esm({
|
|
42427
42887
|
"libs/sdk/src/front-mcp/front-mcp.ts"() {
|
|
@@ -42464,6 +42924,9 @@ var init_front_mcp = __esm({
|
|
|
42464
42924
|
throw new ServerNotFoundError();
|
|
42465
42925
|
}
|
|
42466
42926
|
await server.start();
|
|
42927
|
+
for (const scope of this.getScopes()) {
|
|
42928
|
+
await scope.emitServerStarted();
|
|
42929
|
+
}
|
|
42467
42930
|
}
|
|
42468
42931
|
/**
|
|
42469
42932
|
* Get the configuration used to create this FrontMCP instance.
|
|
@@ -42479,7 +42942,13 @@ var init_front_mcp = __esm({
|
|
|
42479
42942
|
return this.scopes.getScopes();
|
|
42480
42943
|
}
|
|
42481
42944
|
static async bootstrap(options) {
|
|
42482
|
-
const
|
|
42945
|
+
const parsedConfig = frontMcpMetadataSchema.parse(options);
|
|
42946
|
+
const daemonSocket = process.env["FRONTMCP_DAEMON_SOCKET"];
|
|
42947
|
+
if (daemonSocket) {
|
|
42948
|
+
await _FrontMcpInstance2.runUnixSocket({ ...parsedConfig, socketPath: daemonSocket });
|
|
42949
|
+
return;
|
|
42950
|
+
}
|
|
42951
|
+
const frontMcp = new _FrontMcpInstance2(parsedConfig);
|
|
42483
42952
|
await frontMcp.ready;
|
|
42484
42953
|
await frontMcp.start();
|
|
42485
42954
|
frontMcp.log?.info("FrontMCP bootstrap complete");
|
|
@@ -42650,7 +43119,7 @@ var init_front_mcp = __esm({
|
|
|
42650
43119
|
frontMcp.log?.info(`MCP server listening on unix://${socketPath}`);
|
|
42651
43120
|
const cleanup = async () => {
|
|
42652
43121
|
try {
|
|
42653
|
-
if (await
|
|
43122
|
+
if (await fileExists5(socketPath)) {
|
|
42654
43123
|
await unlink2(socketPath);
|
|
42655
43124
|
}
|
|
42656
43125
|
} catch {
|
|
@@ -43294,6 +43763,7 @@ var init_agent_decorator = __esm({
|
|
|
43294
43763
|
|
|
43295
43764
|
// libs/sdk/src/common/decorators/skill.decorator.ts
|
|
43296
43765
|
import "reflect-metadata";
|
|
43766
|
+
import { dirname as dirname2 } from "@frontmcp/utils";
|
|
43297
43767
|
function FrontMcpSkill(providedMetadata) {
|
|
43298
43768
|
return (target) => {
|
|
43299
43769
|
const metadata = skillMetadataSchema.parse(providedMetadata);
|
|
@@ -43313,13 +43783,33 @@ function FrontMcpSkill(providedMetadata) {
|
|
|
43313
43783
|
function frontMcpSkill(providedMetadata) {
|
|
43314
43784
|
const parsedMetadata = skillMetadataSchema.parse(providedMetadata);
|
|
43315
43785
|
const skillToken = /* @__PURE__ */ Symbol(`skill:${parsedMetadata.name}`);
|
|
43786
|
+
const callerDir = resolveCallerDir();
|
|
43316
43787
|
return {
|
|
43317
43788
|
kind: "VALUE" /* VALUE */,
|
|
43318
43789
|
provide: skillToken,
|
|
43319
43790
|
// Cast to SkillMetadata - Zod's output type has internal type markers that don't match exactly
|
|
43320
|
-
metadata: parsedMetadata
|
|
43791
|
+
metadata: parsedMetadata,
|
|
43792
|
+
callerDir
|
|
43321
43793
|
};
|
|
43322
43794
|
}
|
|
43795
|
+
function resolveCallerDir() {
|
|
43796
|
+
const err = new Error();
|
|
43797
|
+
const stack = err.stack;
|
|
43798
|
+
if (!stack) return void 0;
|
|
43799
|
+
const lines = stack.split("\n");
|
|
43800
|
+
for (let i = 1; i < lines.length; i++) {
|
|
43801
|
+
const line = lines[i];
|
|
43802
|
+
const match = line.match(/\(([^)]+):\d+:\d+\)/) || line.match(/at\s+([^\s:]+):\d+:\d+/);
|
|
43803
|
+
if (match) {
|
|
43804
|
+
const file = match[1];
|
|
43805
|
+
if (file.includes("node_modules") || file.includes("skill.decorator")) {
|
|
43806
|
+
continue;
|
|
43807
|
+
}
|
|
43808
|
+
return dirname2(file);
|
|
43809
|
+
}
|
|
43810
|
+
}
|
|
43811
|
+
return void 0;
|
|
43812
|
+
}
|
|
43323
43813
|
function skillEsm(specifier, targetName, options) {
|
|
43324
43814
|
const parsed = parsePackageSpecifier(specifier);
|
|
43325
43815
|
return {
|
|
@@ -43392,7 +43882,7 @@ var init_skill_decorator = __esm({
|
|
|
43392
43882
|
|
|
43393
43883
|
// libs/sdk/src/common/decorators/job.decorator.ts
|
|
43394
43884
|
import "reflect-metadata";
|
|
43395
|
-
function
|
|
43885
|
+
function _FrontMcpJob(providedMetadata) {
|
|
43396
43886
|
return (target) => {
|
|
43397
43887
|
const metadata = frontMcpJobMetadataSchema.parse(providedMetadata);
|
|
43398
43888
|
Reflect.defineMetadata(FrontMcpJobTokens.type, true, target);
|
|
@@ -43455,7 +43945,7 @@ function jobRemote(url, targetName, options) {
|
|
|
43455
43945
|
}
|
|
43456
43946
|
};
|
|
43457
43947
|
}
|
|
43458
|
-
var Job;
|
|
43948
|
+
var FrontMcpJob, Job;
|
|
43459
43949
|
var init_job_decorator = __esm({
|
|
43460
43950
|
"libs/sdk/src/common/decorators/job.decorator.ts"() {
|
|
43461
43951
|
"use strict";
|
|
@@ -43463,11 +43953,12 @@ var init_job_decorator = __esm({
|
|
|
43463
43953
|
init_job_metadata();
|
|
43464
43954
|
init_package_specifier();
|
|
43465
43955
|
init_validate_remote_url();
|
|
43466
|
-
Object.assign(
|
|
43956
|
+
Object.assign(_FrontMcpJob, {
|
|
43467
43957
|
esm: jobEsm,
|
|
43468
43958
|
remote: jobRemote
|
|
43469
43959
|
});
|
|
43470
|
-
|
|
43960
|
+
FrontMcpJob = _FrontMcpJob;
|
|
43961
|
+
Job = _FrontMcpJob;
|
|
43471
43962
|
}
|
|
43472
43963
|
});
|
|
43473
43964
|
|
|
@@ -43546,7 +44037,7 @@ var init_front_mcp_interface = __esm({
|
|
|
43546
44037
|
|
|
43547
44038
|
// libs/sdk/src/common/interfaces/server.interface.ts
|
|
43548
44039
|
import { IncomingMessage, HttpServerResponse } from "@frontmcp/protocol";
|
|
43549
|
-
var ServerRequest11,
|
|
44040
|
+
var ServerRequest11, ServerResponse4, FrontMcpServer;
|
|
43550
44041
|
var init_server_interface = __esm({
|
|
43551
44042
|
"libs/sdk/src/common/interfaces/server.interface.ts"() {
|
|
43552
44043
|
"use strict";
|
|
@@ -43556,7 +44047,7 @@ var init_server_interface = __esm({
|
|
|
43556
44047
|
body;
|
|
43557
44048
|
authSession;
|
|
43558
44049
|
};
|
|
43559
|
-
|
|
44050
|
+
ServerResponse4 = class extends HttpServerResponse {
|
|
43560
44051
|
};
|
|
43561
44052
|
FrontMcpServer = class {
|
|
43562
44053
|
};
|
|
@@ -43888,6 +44379,29 @@ var init_resource_interface = __esm({
|
|
|
43888
44379
|
this.uri = uri;
|
|
43889
44380
|
this.params = params;
|
|
43890
44381
|
}
|
|
44382
|
+
/**
|
|
44383
|
+
* Override to provide autocompletion for resource template arguments.
|
|
44384
|
+
* Called by the MCP `completion/complete` handler when a client requests
|
|
44385
|
+
* suggestions for a template parameter.
|
|
44386
|
+
*
|
|
44387
|
+
* @param argName - The template parameter name (e.g., 'userId')
|
|
44388
|
+
* @returns A completer function, or null if no completion is available for this argument
|
|
44389
|
+
*
|
|
44390
|
+
* @example
|
|
44391
|
+
* ```typescript
|
|
44392
|
+
* getArgumentCompleter(argName: string): ResourceArgumentCompleter | null {
|
|
44393
|
+
* if (argName === 'userId') {
|
|
44394
|
+
* return async (partial) => ({
|
|
44395
|
+
* values: await this.searchUsers(partial),
|
|
44396
|
+
* });
|
|
44397
|
+
* }
|
|
44398
|
+
* return null;
|
|
44399
|
+
* }
|
|
44400
|
+
* ```
|
|
44401
|
+
*/
|
|
44402
|
+
getArgumentCompleter(_argName) {
|
|
44403
|
+
return null;
|
|
44404
|
+
}
|
|
43891
44405
|
get output() {
|
|
43892
44406
|
return this._output;
|
|
43893
44407
|
}
|
|
@@ -45037,9 +45551,12 @@ var init_decide_request_intent_utils = __esm({
|
|
|
45037
45551
|
outcome: { intent: "sse", reason: "GET /sse with Mcp-Session-Id." }
|
|
45038
45552
|
},
|
|
45039
45553
|
// D) Initialize (POST → SSE)
|
|
45040
|
-
// D1) Stateless initialize (no session, stateless enabled
|
|
45554
|
+
// D1) Stateless initialize (no session, stateless enabled, streamable NOT enabled)
|
|
45555
|
+
// When streamable is also enabled, prefer streamable-http (which creates a session).
|
|
45556
|
+
// Per MCP spec, first initialize naturally has no session — stateless should only
|
|
45557
|
+
// match when it's the sole enabled protocol.
|
|
45041
45558
|
{
|
|
45042
|
-
care: CH_MASK | B_HAS_SESSION | B_STATELESS_EN,
|
|
45559
|
+
care: CH_MASK | B_HAS_SESSION | B_STATELESS_EN | B_STREAMABLE_EN,
|
|
45043
45560
|
match: CH_POST_INIT_SSE | B_STATELESS_EN,
|
|
45044
45561
|
outcome: { intent: "stateless-http", reason: "Stateless initialize (no session)." }
|
|
45045
45562
|
},
|
|
@@ -45058,9 +45575,9 @@ var init_decide_request_intent_utils = __esm({
|
|
|
45058
45575
|
outcome: { intent: "streamable-http", reason: "Initialize with SSE." }
|
|
45059
45576
|
},
|
|
45060
45577
|
// E) Initialize (POST → JSON)
|
|
45061
|
-
// E1) Stateless initialize JSON (no session, stateless enabled
|
|
45578
|
+
// E1) Stateless initialize JSON (no session, stateless enabled, streamable NOT enabled)
|
|
45062
45579
|
{
|
|
45063
|
-
care: CH_MASK | B_HAS_SESSION | B_STATELESS_EN,
|
|
45580
|
+
care: CH_MASK | B_HAS_SESSION | B_STATELESS_EN | B_STREAMABLE_EN,
|
|
45064
45581
|
match: CH_POST_INIT_JSON | B_STATELESS_EN,
|
|
45065
45582
|
outcome: { intent: "stateless-http", reason: "Stateless initialize JSON (no session)." }
|
|
45066
45583
|
},
|
|
@@ -45089,7 +45606,7 @@ var init_decide_request_intent_utils = __esm({
|
|
|
45089
45606
|
}
|
|
45090
45607
|
},
|
|
45091
45608
|
{
|
|
45092
|
-
care: CH_MASK | B_STREAMABLE_EN,
|
|
45609
|
+
care: CH_MASK | B_STREAMABLE_EN | B_STATELESS_EN,
|
|
45093
45610
|
match: CH_POST_SSE,
|
|
45094
45611
|
outcome: {
|
|
45095
45612
|
intent: "unknown",
|
|
@@ -45097,8 +45614,9 @@ var init_decide_request_intent_utils = __esm({
|
|
|
45097
45614
|
recommendation: { httpStatus: 405, message: "Streamable HTTP disabled" }
|
|
45098
45615
|
}
|
|
45099
45616
|
},
|
|
45617
|
+
// Stateless short-lived SSE only when streamable is NOT enabled
|
|
45100
45618
|
{
|
|
45101
|
-
care: CH_MASK | B_HAS_SESSION | B_STATELESS_EN,
|
|
45619
|
+
care: CH_MASK | B_HAS_SESSION | B_STATELESS_EN | B_STREAMABLE_EN,
|
|
45102
45620
|
match: CH_POST_SSE | B_STATELESS_EN,
|
|
45103
45621
|
outcome: { intent: "stateless-http", reason: "Stateless short-lived SSE." }
|
|
45104
45622
|
},
|
|
@@ -45118,7 +45636,7 @@ var init_decide_request_intent_utils = __esm({
|
|
|
45118
45636
|
}
|
|
45119
45637
|
},
|
|
45120
45638
|
{
|
|
45121
|
-
care: CH_MASK | B_STATEFUL_EN | B_STREAMABLE_EN,
|
|
45639
|
+
care: CH_MASK | B_STATEFUL_EN | B_STREAMABLE_EN | B_STATELESS_EN,
|
|
45122
45640
|
match: CH_POST_JSON,
|
|
45123
45641
|
outcome: {
|
|
45124
45642
|
intent: "unknown",
|
|
@@ -45126,8 +45644,9 @@ var init_decide_request_intent_utils = __esm({
|
|
|
45126
45644
|
recommendation: { httpStatus: 405, message: "JSON mode disabled" }
|
|
45127
45645
|
}
|
|
45128
45646
|
},
|
|
45647
|
+
// Stateless JSON only when streamable is NOT enabled
|
|
45129
45648
|
{
|
|
45130
|
-
care: CH_MASK | B_HAS_SESSION | B_STATELESS_EN,
|
|
45649
|
+
care: CH_MASK | B_HAS_SESSION | B_STATELESS_EN | B_STREAMABLE_EN,
|
|
45131
45650
|
match: CH_POST_JSON | B_STATELESS_EN,
|
|
45132
45651
|
outcome: { intent: "stateless-http", reason: "Stateless JSON request." }
|
|
45133
45652
|
},
|
|
@@ -45331,7 +45850,7 @@ var init_internal = __esm({
|
|
|
45331
45850
|
});
|
|
45332
45851
|
|
|
45333
45852
|
// libs/sdk/src/common/interfaces/index.ts
|
|
45334
|
-
var
|
|
45853
|
+
var init_interfaces2 = __esm({
|
|
45335
45854
|
"libs/sdk/src/common/interfaces/index.ts"() {
|
|
45336
45855
|
"use strict";
|
|
45337
45856
|
init_base_interface();
|
|
@@ -45496,18 +46015,40 @@ var init_dynamic = __esm({
|
|
|
45496
46015
|
});
|
|
45497
46016
|
|
|
45498
46017
|
// libs/sdk/src/common/entries/scope.entry.ts
|
|
45499
|
-
var
|
|
46018
|
+
var ScopeEntry3;
|
|
45500
46019
|
var init_scope_entry = __esm({
|
|
45501
46020
|
"libs/sdk/src/common/entries/scope.entry.ts"() {
|
|
45502
46021
|
"use strict";
|
|
45503
46022
|
init_base_entry();
|
|
45504
46023
|
init_utils2();
|
|
45505
|
-
|
|
46024
|
+
ScopeEntry3 = class extends BaseEntry {
|
|
45506
46025
|
get fullPath() {
|
|
45507
46026
|
const prefix = normalizeEntryPrefix(this.entryPath ?? "");
|
|
45508
46027
|
const scope = normalizeScopeBase(this.routeBase ?? "");
|
|
45509
46028
|
return `${prefix}${scope}`;
|
|
45510
46029
|
}
|
|
46030
|
+
/**
|
|
46031
|
+
* Lifecycle callbacks registered by plugins via onServerStarted().
|
|
46032
|
+
* Called after the HTTP server starts listening.
|
|
46033
|
+
*/
|
|
46034
|
+
lifecycleCallbacks = [];
|
|
46035
|
+
/**
|
|
46036
|
+
* Register a callback to run after the server has started.
|
|
46037
|
+
* Plugins can use this for post-startup initialization (e.g., warming caches,
|
|
46038
|
+
* starting background jobs, logging readiness).
|
|
46039
|
+
*/
|
|
46040
|
+
onServerStarted(callback) {
|
|
46041
|
+
this.lifecycleCallbacks.push(callback);
|
|
46042
|
+
}
|
|
46043
|
+
/**
|
|
46044
|
+
* Emit the server-started lifecycle event. Called by FrontMcpInstance after server.start().
|
|
46045
|
+
* @internal
|
|
46046
|
+
*/
|
|
46047
|
+
async emitServerStarted() {
|
|
46048
|
+
for (const cb of this.lifecycleCallbacks) {
|
|
46049
|
+
await cb();
|
|
46050
|
+
}
|
|
46051
|
+
}
|
|
45511
46052
|
};
|
|
45512
46053
|
}
|
|
45513
46054
|
});
|
|
@@ -45738,6 +46279,14 @@ var init_resource_entry = __esm({
|
|
|
45738
46279
|
* Whether this resource is a template (has uriTemplate instead of uri)
|
|
45739
46280
|
*/
|
|
45740
46281
|
isTemplate;
|
|
46282
|
+
/**
|
|
46283
|
+
* Get an argument completer for resource template autocompletion.
|
|
46284
|
+
* Override in subclasses to provide suggestions for template parameters.
|
|
46285
|
+
* Returns null by default (no completion available).
|
|
46286
|
+
*/
|
|
46287
|
+
getArgumentCompleter(_argName) {
|
|
46288
|
+
return null;
|
|
46289
|
+
}
|
|
45741
46290
|
};
|
|
45742
46291
|
}
|
|
45743
46292
|
});
|
|
@@ -46228,7 +46777,7 @@ var init_common = __esm({
|
|
|
46228
46777
|
init_decorators();
|
|
46229
46778
|
init_types();
|
|
46230
46779
|
init_metadata();
|
|
46231
|
-
|
|
46780
|
+
init_interfaces2();
|
|
46232
46781
|
init_tokens();
|
|
46233
46782
|
init_dynamic();
|
|
46234
46783
|
init_records();
|
|
@@ -46745,16 +47294,16 @@ export {
|
|
|
46745
47294
|
ResourceNotFoundError,
|
|
46746
47295
|
ResourceOutputSchema,
|
|
46747
47296
|
ResourceReadError,
|
|
46748
|
-
|
|
47297
|
+
_ResourceTemplate as ResourceTemplate,
|
|
46749
47298
|
ResourceTemplateKind,
|
|
46750
47299
|
ScopeConfigurationError,
|
|
46751
47300
|
ScopeDeniedError,
|
|
46752
|
-
|
|
47301
|
+
ScopeEntry3 as ScopeEntry,
|
|
46753
47302
|
ScopeKind,
|
|
46754
47303
|
ServerNotFoundError,
|
|
46755
47304
|
ServerRequest11 as ServerRequest,
|
|
46756
47305
|
ServerRequestTokens,
|
|
46757
|
-
|
|
47306
|
+
ServerResponse4 as ServerResponse,
|
|
46758
47307
|
ServerlessHandlerNotInitializedError,
|
|
46759
47308
|
SessionHookStage,
|
|
46760
47309
|
SessionIdEmptyError,
|
|
@@ -46787,6 +47336,7 @@ export {
|
|
|
46787
47336
|
TransportAlreadyStartedError,
|
|
46788
47337
|
TransportBusRequiredError,
|
|
46789
47338
|
TransportNotConnectedError,
|
|
47339
|
+
TransportServiceNotAvailableError,
|
|
46790
47340
|
UnauthorizedError,
|
|
46791
47341
|
UnsupportedClientVersionError,
|
|
46792
47342
|
UnsupportedContentTypeError,
|