alepha 0.20.3 → 0.20.4
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/dist/api/audits/index.d.ts.map +1 -1
- package/dist/api/files/index.d.ts.map +1 -1
- package/dist/api/jobs/index.d.ts +14 -14
- package/dist/api/jobs/index.d.ts.map +1 -1
- package/dist/api/keys/index.d.ts +4 -4
- package/dist/api/organizations/index.d.ts.map +1 -1
- package/dist/api/parameters/index.d.ts +8 -3
- package/dist/api/parameters/index.d.ts.map +1 -1
- package/dist/api/parameters/index.js +20 -4
- package/dist/api/parameters/index.js.map +1 -1
- package/dist/api/payments/index.d.ts.map +1 -1
- package/dist/api/users/index.browser.js +6 -0
- package/dist/api/users/index.browser.js.map +1 -1
- package/dist/api/users/index.d.ts +5037 -139
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +58 -10
- package/dist/api/users/index.js.map +1 -1
- package/dist/bucket/index.d.ts +77 -107
- package/dist/bucket/index.d.ts.map +1 -1
- package/dist/bucket/index.js +148 -4
- package/dist/bucket/index.js.map +1 -1
- package/dist/bucket/index.workerd.js +7 -1
- package/dist/bucket/index.workerd.js.map +1 -1
- package/dist/cache/core/index.d.ts +26 -0
- package/dist/cache/core/index.d.ts.map +1 -1
- package/dist/cache/core/index.js +11 -1
- package/dist/cache/core/index.js.map +1 -1
- package/dist/cache/core/index.workerd.js +11 -1
- package/dist/cache/core/index.workerd.js.map +1 -1
- package/dist/cli/config/index.d.ts +7 -5
- package/dist/cli/config/index.d.ts.map +1 -1
- package/dist/cli/config/index.js +2 -3
- package/dist/cli/config/index.js.map +1 -1
- package/dist/cli/core/index.d.ts +420 -13
- package/dist/cli/core/index.d.ts.map +1 -1
- package/dist/cli/core/index.js +22 -511
- package/dist/cli/core/index.js.map +1 -1
- package/dist/cli/devtools/index.d.ts +4 -8
- package/dist/cli/devtools/index.d.ts.map +1 -1
- package/dist/cli/devtools/index.js +13 -15
- package/dist/cli/devtools/index.js.map +1 -1
- package/dist/cli/platform/index.d.ts +10 -13
- package/dist/cli/platform/index.d.ts.map +1 -1
- package/dist/cli/platform/index.js +18 -15
- package/dist/cli/platform/index.js.map +1 -1
- package/dist/cli/vendor/index.d.ts +10 -13
- package/dist/cli/vendor/index.d.ts.map +1 -1
- package/dist/cli/vendor/index.js +16 -13
- package/dist/cli/vendor/index.js.map +1 -1
- package/dist/core/index.browser.js +27 -3
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +6 -3
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +27 -3
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +27 -3
- package/dist/core/index.native.js.map +1 -1
- package/dist/core/index.workerd.js +27 -3
- package/dist/core/index.workerd.js.map +1 -1
- package/dist/datetime/index.d.ts +69 -10
- package/dist/datetime/index.d.ts.map +1 -1
- package/dist/datetime/index.js +135 -13
- package/dist/datetime/index.js.map +1 -1
- package/dist/email/smtp/index.js +10636 -2
- package/dist/email/smtp/index.js.map +1 -1
- package/dist/fake/index.d.ts +8085 -4
- package/dist/fake/index.d.ts.map +1 -1
- package/dist/fake/index.js +33554 -3
- package/dist/fake/index.js.map +1 -1
- package/dist/lock/core/index.d.ts +30 -2
- package/dist/lock/core/index.d.ts.map +1 -1
- package/dist/lock/core/index.js +35 -12
- package/dist/lock/core/index.js.map +1 -1
- package/dist/mcp/index.d.ts +238 -31
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +198 -71
- package/dist/mcp/index.js.map +1 -1
- package/dist/orm/core/index.browser.js +1 -1
- package/dist/orm/core/index.browser.js.map +1 -1
- package/dist/orm/core/index.bun.js +4 -3
- package/dist/orm/core/index.bun.js.map +1 -1
- package/dist/orm/core/index.d.ts +4877 -9
- package/dist/orm/core/index.d.ts.map +1 -1
- package/dist/orm/core/index.js +4 -3
- package/dist/orm/core/index.js.map +1 -1
- package/dist/orm/postgres/index.d.ts +608 -1
- package/dist/orm/postgres/index.d.ts.map +1 -1
- package/dist/react/core/index.d.ts +102 -1
- package/dist/react/core/index.d.ts.map +1 -1
- package/dist/react/core/index.js +65 -1
- package/dist/react/core/index.js.map +1 -1
- package/dist/react/form/index.d.ts +6 -0
- package/dist/react/form/index.d.ts.map +1 -1
- package/dist/react/form/index.js +7 -7
- package/dist/react/form/index.js.map +1 -1
- package/dist/react/i18n/index.d.ts +7 -1
- package/dist/react/i18n/index.d.ts.map +1 -1
- package/dist/react/i18n/index.js +6 -0
- package/dist/react/i18n/index.js.map +1 -1
- package/dist/react/router/index.browser.js +20 -2
- package/dist/react/router/index.browser.js.map +1 -1
- package/dist/react/router/index.d.ts +36 -4
- package/dist/react/router/index.d.ts.map +1 -1
- package/dist/react/router/index.js +20 -2
- package/dist/react/router/index.js.map +1 -1
- package/dist/react/testing/chunk-6Ep1yQYe.js +16 -0
- package/dist/react/testing/index.d.ts +411 -1
- package/dist/react/testing/index.d.ts.map +1 -1
- package/dist/react/testing/index.js +12293 -13
- package/dist/react/testing/index.js.map +1 -1
- package/dist/react/ui/index.d.ts +195 -1
- package/dist/react/ui/index.d.ts.map +1 -1
- package/dist/react/ui/index.js +61 -1
- package/dist/react/ui/index.js.map +1 -1
- package/dist/scheduler/index.d.ts +84 -3
- package/dist/scheduler/index.d.ts.map +1 -1
- package/dist/scheduler/index.js +390 -1
- package/dist/scheduler/index.js.map +1 -1
- package/dist/scheduler/index.workerd.js +390 -1
- package/dist/scheduler/index.workerd.js.map +1 -1
- package/dist/security/index.d.ts +325 -2
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +1361 -2
- package/dist/security/index.js.map +1 -1
- package/dist/server/auth/index.d.ts +1054 -1
- package/dist/server/auth/index.d.ts.map +1 -1
- package/dist/server/auth/index.js +1223 -1
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/core/index.browser.js +10 -3
- package/dist/server/core/index.browser.js.map +1 -1
- package/dist/server/core/index.d.ts.map +1 -1
- package/dist/server/core/index.js +28 -5
- package/dist/server/core/index.js.map +1 -1
- package/dist/server/metrics/index.d.ts +514 -1
- package/dist/server/metrics/index.d.ts.map +1 -1
- package/dist/server/metrics/index.js +4374 -4
- package/dist/server/metrics/index.js.map +1 -1
- package/dist/server/swagger/index.d.ts.map +1 -1
- package/dist/server/swagger/index.js +3 -4
- package/dist/server/swagger/index.js.map +1 -1
- package/dist/websocket/index.browser.js +11 -5
- package/dist/websocket/index.browser.js.map +1 -1
- package/dist/websocket/index.d.ts +3 -1
- package/dist/websocket/index.d.ts.map +1 -1
- package/dist/websocket/index.js +21 -6
- package/dist/websocket/index.js.map +1 -1
- package/package.json +671 -263
- package/src/api/parameters/services/ParameterProvider.ts +21 -4
- package/src/api/users/__tests__/SessionService.spec.ts +99 -0
- package/src/api/users/__tests__/UserJobs.spec.ts +67 -0
- package/src/api/users/atoms/realmAuthSettingsAtom.ts +15 -0
- package/src/api/users/entities/sessions.ts +6 -0
- package/src/api/users/jobs/UserJobs.ts +44 -17
- package/src/api/users/providers/RealmProvider.ts +4 -0
- package/src/api/users/services/SessionService.ts +27 -0
- package/src/bucket/__tests__/NodeS3BucketProvider.spec.ts +74 -0
- package/src/bucket/index.ts +19 -2
- package/src/bucket/primitives/$bucket.ts +9 -1
- package/src/bucket/providers/CloudflareR2Provider.ts +2 -137
- package/src/bucket/providers/NodeS3BucketProvider.ts +218 -0
- package/src/cache/core/index.ts +29 -0
- package/src/cache/core/primitives/$cache.ts +14 -1
- package/src/cli/config/defineConfig.ts +13 -15
- package/src/cli/core/__tests__/init.spec.ts +6 -7
- package/src/cli/core/services/ProjectScaffolder.ts +18 -14
- package/src/cli/core/tasks/BuildCloudflareTask.ts +5 -0
- package/src/cli/core/templates/agentMd.ts +2 -10
- package/src/cli/core/templates/saasAdminLayoutTsx.ts +3 -3
- package/src/cli/devtools/index.ts +12 -26
- package/src/cli/platform/index.ts +15 -24
- package/src/cli/vendor/atoms/vendorOptions.ts +1 -1
- package/src/cli/vendor/index.ts +14 -23
- package/src/core/Alepha.ts +11 -1
- package/src/core/helpers/ref.ts +18 -0
- package/src/core/index.shared.ts +1 -0
- package/src/core/providers/SchemaValidator.ts +9 -1
- package/src/core/providers/TypeProvider.ts +1 -2
- package/src/datetime/REFACTORING.md +118 -0
- package/src/datetime/providers/DateTimeProvider.ts +203 -24
- package/src/lock/core/index.ts +31 -0
- package/src/lock/core/primitives/$lock.ts +14 -1
- package/src/mcp/__tests__/jsonrpc.spec.ts +1 -1
- package/src/mcp/helpers/jsonrpc.ts +26 -1
- package/src/mcp/index.ts +10 -5
- package/src/mcp/interfaces/McpTypes.ts +83 -6
- package/src/mcp/primitives/$prompt.ts +18 -1
- package/src/mcp/primitives/$resource.ts +18 -1
- package/src/mcp/primitives/$tool.ts +83 -7
- package/src/mcp/providers/McpServerProvider.ts +74 -16
- package/src/mcp/transports/StreamableHttpMcpTransport.ts +226 -0
- package/src/orm/REFACTORING.md +330 -0
- package/src/orm/core/primitives/$transactional.ts +11 -0
- package/src/orm/core/schemas/updateSchema.ts +1 -1
- package/src/orm/core/services/PgRelationManager.ts +4 -2
- package/src/react/core/__tests__/useQuery.browser.spec.tsx +86 -0
- package/src/react/core/hooks/useQuery.ts +153 -0
- package/src/react/core/index.ts +1 -0
- package/src/react/form/services/FormModel.ts +15 -6
- package/src/react/form/services/parseField.ts +8 -0
- package/src/react/i18n/providers/I18nProvider.ts +8 -2
- package/src/react/router/__tests__/$page.spec.tsx +0 -16
- package/src/react/router/__tests__/ssr.spec.tsx +339 -0
- package/src/react/router/primitives/$page.ts +28 -4
- package/src/react/router/providers/ReactPageProvider.ts +27 -9
- package/src/react/ui/atoms/uiThemeListAtom.ts +36 -0
- package/src/react/ui/index.ts +6 -0
- package/src/react/ui/services/SchemaControl.ts +209 -0
- package/src/security/primitives/$issuer.ts +6 -3
- package/src/server/core/__tests__/ServerRouterProvider-serializationError.spec.ts +75 -0
- package/src/server/core/__tests__/ServerRouterProvider-validationError.spec.ts +306 -0
- package/src/server/core/errors/ValidationError.ts +13 -1
- package/src/server/core/primitives/$action.ts +16 -5
- package/src/server/core/providers/ServerRouterProvider.ts +26 -4
- package/src/server/swagger/providers/ServerSwaggerProvider.ts +5 -7
- package/src/websocket/providers/NodeWebSocketServerProvider.ts +10 -4
- package/src/websocket/services/WebSocketClient.ts +11 -5
- package/src/mcp/transports/SseMcpTransport.ts +0 -182
package/dist/mcp/index.js
CHANGED
|
@@ -1,9 +1,25 @@
|
|
|
1
|
-
import { $atom, $inject, $module, $state, Alepha, AlephaError, KIND, Primitive, createPrimitive, t } from "alepha";
|
|
1
|
+
import { $atom, $inject, $module, $state, Alepha, AlephaError, KIND, Primitive, TypeBoxError, createPrimitive, t } from "alepha";
|
|
2
2
|
import { $logger } from "alepha/logger";
|
|
3
3
|
import { $route } from "alepha/server";
|
|
4
4
|
//#region ../../src/mcp/helpers/jsonrpc.ts
|
|
5
5
|
const JSONRPC_VERSION = "2.0";
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* The latest MCP protocol revision Alepha targets.
|
|
8
|
+
* See {@link SUPPORTED_PROTOCOL_VERSIONS} for the full negotiation list.
|
|
9
|
+
*/
|
|
10
|
+
const MCP_PROTOCOL_VERSION = "2025-11-25";
|
|
11
|
+
/**
|
|
12
|
+
* Protocol versions Alepha will accept during `initialize` negotiation,
|
|
13
|
+
* highest preference first. The server echoes back whichever version the
|
|
14
|
+
* client requested if it appears here, otherwise picks the first entry.
|
|
15
|
+
*/
|
|
16
|
+
const SUPPORTED_PROTOCOL_VERSIONS = [
|
|
17
|
+
"2025-11-25",
|
|
18
|
+
"2025-06-18",
|
|
19
|
+
"2025-03-26",
|
|
20
|
+
"2024-11-05"
|
|
21
|
+
];
|
|
22
|
+
const isSupportedProtocolVersion = (v) => typeof v === "string" && SUPPORTED_PROTOCOL_VERSIONS.includes(v);
|
|
7
23
|
const JsonRpcErrorCodes = {
|
|
8
24
|
PARSE_ERROR: -32700,
|
|
9
25
|
INVALID_REQUEST: -32600,
|
|
@@ -170,6 +186,18 @@ var McpServerProvider = class {
|
|
|
170
186
|
resources = /* @__PURE__ */ new Map();
|
|
171
187
|
prompts = /* @__PURE__ */ new Map();
|
|
172
188
|
initialized = false;
|
|
189
|
+
/**
|
|
190
|
+
* Protocol version negotiated with the client during `initialize`.
|
|
191
|
+
* Used by transports to validate the `MCP-Protocol-Version` header on
|
|
192
|
+
* subsequent HTTP requests (per spec 2025-06-18+).
|
|
193
|
+
*/
|
|
194
|
+
negotiatedVersion = MCP_PROTOCOL_VERSION;
|
|
195
|
+
/**
|
|
196
|
+
* Server identity returned during `initialize`. Consumers may override
|
|
197
|
+
* fields directly (e.g. `mcpServer.serverInfo = { name: "roadmap-mcp",
|
|
198
|
+
* version: "0.20.3", description: "..." }`) — the `description` field
|
|
199
|
+
* is supported per spec 2025-11-25 (minor change #2).
|
|
200
|
+
*/
|
|
173
201
|
serverInfo = {
|
|
174
202
|
name: "alepha-mcp",
|
|
175
203
|
version: "1.0.0"
|
|
@@ -298,13 +326,17 @@ var McpServerProvider = class {
|
|
|
298
326
|
}
|
|
299
327
|
}
|
|
300
328
|
handleInitialize(params) {
|
|
329
|
+
const requested = params.protocolVersion;
|
|
330
|
+
const negotiated = isSupportedProtocolVersion(requested) ? requested : SUPPORTED_PROTOCOL_VERSIONS[0];
|
|
301
331
|
this.log.info("MCP client initializing", {
|
|
302
332
|
clientInfo: params.clientInfo,
|
|
303
|
-
|
|
333
|
+
requestedProtocolVersion: requested,
|
|
334
|
+
negotiatedProtocolVersion: negotiated
|
|
304
335
|
});
|
|
305
336
|
this.initialized = true;
|
|
337
|
+
this.negotiatedVersion = negotiated;
|
|
306
338
|
return {
|
|
307
|
-
protocolVersion:
|
|
339
|
+
protocolVersion: negotiated,
|
|
308
340
|
capabilities: this.getCapabilities(),
|
|
309
341
|
serverInfo: this.serverInfo
|
|
310
342
|
};
|
|
@@ -322,11 +354,28 @@ var McpServerProvider = class {
|
|
|
322
354
|
if (!tool) throw new McpToolNotFoundError(name);
|
|
323
355
|
try {
|
|
324
356
|
const result = await tool.execute(args, context);
|
|
325
|
-
|
|
357
|
+
const callResult = { content: [{
|
|
326
358
|
type: "text",
|
|
327
359
|
text: typeof result === "string" ? result : JSON.stringify(result ?? null)
|
|
328
360
|
}] };
|
|
361
|
+
if (tool.hasOutputSchema() && result !== void 0) callResult.structuredContent = result;
|
|
362
|
+
return callResult;
|
|
329
363
|
} catch (error) {
|
|
364
|
+
if (error instanceof TypeBoxError) {
|
|
365
|
+
const path = error.value?.path || "/";
|
|
366
|
+
const message = error.value?.message || error.message;
|
|
367
|
+
return {
|
|
368
|
+
content: [{
|
|
369
|
+
type: "text",
|
|
370
|
+
text: `Validation error at ${path}: ${message}`
|
|
371
|
+
}],
|
|
372
|
+
structuredContent: { errors: [{
|
|
373
|
+
path,
|
|
374
|
+
message
|
|
375
|
+
}] },
|
|
376
|
+
isError: true
|
|
377
|
+
};
|
|
378
|
+
}
|
|
330
379
|
return {
|
|
331
380
|
content: [{
|
|
332
381
|
type: "text",
|
|
@@ -456,11 +505,14 @@ var PromptPrimitive = class extends Primitive {
|
|
|
456
505
|
* Convert the prompt to an MCP prompt descriptor for protocol messages.
|
|
457
506
|
*/
|
|
458
507
|
toDescriptor() {
|
|
459
|
-
|
|
508
|
+
const descriptor = {
|
|
460
509
|
name: this.name,
|
|
461
510
|
description: this.description,
|
|
462
511
|
arguments: this.options.args ? this.schemaToArguments(this.options.args) : []
|
|
463
512
|
};
|
|
513
|
+
if (this.options.title) descriptor.title = this.options.title;
|
|
514
|
+
if (this.options.icons && this.options.icons.length > 0) descriptor.icons = this.options.icons;
|
|
515
|
+
return descriptor;
|
|
464
516
|
}
|
|
465
517
|
/**
|
|
466
518
|
* Convert a TypeBox schema to an array of prompt arguments.
|
|
@@ -561,12 +613,15 @@ var ResourcePrimitive = class extends Primitive {
|
|
|
561
613
|
* Convert the resource to an MCP resource descriptor for protocol messages.
|
|
562
614
|
*/
|
|
563
615
|
toDescriptor() {
|
|
564
|
-
|
|
616
|
+
const descriptor = {
|
|
565
617
|
uri: this.uri,
|
|
566
618
|
name: this.name,
|
|
567
619
|
description: this.description,
|
|
568
620
|
mimeType: this.mimeType
|
|
569
621
|
};
|
|
622
|
+
if (this.options.title) descriptor.title = this.options.title;
|
|
623
|
+
if (this.options.icons && this.options.icons.length > 0) descriptor.icons = this.options.icons;
|
|
624
|
+
return descriptor;
|
|
570
625
|
}
|
|
571
626
|
};
|
|
572
627
|
$resource[KIND] = ResourcePrimitive;
|
|
@@ -633,6 +688,14 @@ var ToolPrimitive = class extends Primitive {
|
|
|
633
688
|
get description() {
|
|
634
689
|
return this.options.description;
|
|
635
690
|
}
|
|
691
|
+
/**
|
|
692
|
+
* Whether the tool declared a result schema. When true, `tools/call`
|
|
693
|
+
* responses include `structuredContent` populated with the validated
|
|
694
|
+
* result (spec 2025-06-18).
|
|
695
|
+
*/
|
|
696
|
+
hasOutputSchema() {
|
|
697
|
+
return !!this.options.schema?.result;
|
|
698
|
+
}
|
|
636
699
|
onInit() {
|
|
637
700
|
this.mcpServer.registerTool(this);
|
|
638
701
|
}
|
|
@@ -655,33 +718,57 @@ var ToolPrimitive = class extends Primitive {
|
|
|
655
718
|
}
|
|
656
719
|
/**
|
|
657
720
|
* Convert the tool to an MCP tool descriptor for protocol messages.
|
|
721
|
+
*
|
|
722
|
+
* Emits the spec 2025-11-25 surface: `title`, `annotations`, `icons`,
|
|
723
|
+
* and (when `schema.result` is defined) `outputSchema` so the server
|
|
724
|
+
* can populate `structuredContent` on call results.
|
|
658
725
|
*/
|
|
659
726
|
toDescriptor() {
|
|
660
|
-
|
|
727
|
+
const inputSchema = this.options.schema?.params ? this.schemaToJsonSchema(this.options.schema.params) : {
|
|
728
|
+
type: "object",
|
|
729
|
+
properties: {},
|
|
730
|
+
required: []
|
|
731
|
+
};
|
|
732
|
+
const descriptor = {
|
|
661
733
|
name: this.name,
|
|
662
734
|
description: this.description,
|
|
663
|
-
inputSchema
|
|
735
|
+
inputSchema
|
|
736
|
+
};
|
|
737
|
+
if (this.options.title) descriptor.title = this.options.title;
|
|
738
|
+
if (this.options.annotations) descriptor.annotations = this.options.annotations;
|
|
739
|
+
if (this.options.icons && this.options.icons.length > 0) descriptor.icons = this.options.icons;
|
|
740
|
+
if (this.options.schema?.result) {
|
|
741
|
+
const out = this.propertyToJsonSchema(this.options.schema.result);
|
|
742
|
+
descriptor.outputSchema = typeof out === "object" && out !== null && "type" in out ? out : {
|
|
664
743
|
type: "object",
|
|
665
744
|
properties: {},
|
|
666
745
|
required: []
|
|
667
|
-
}
|
|
668
|
-
}
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
return descriptor;
|
|
669
749
|
}
|
|
670
750
|
/**
|
|
671
751
|
* Convert a TypeBox schema to JSON Schema format.
|
|
752
|
+
*
|
|
753
|
+
* Emits the 2020-12 dialect annotation at the root (spec 2025-11-25 /
|
|
754
|
+
* SEP-1613 — JSON Schema 2020-12 is the default dialect for MCP).
|
|
755
|
+
* The TypeBox shapes Alepha emits today are already 2020-12-compatible;
|
|
756
|
+
* this is just the dialect declaration.
|
|
672
757
|
*/
|
|
673
|
-
schemaToJsonSchema(schema) {
|
|
758
|
+
schemaToJsonSchema(schema, options) {
|
|
674
759
|
const properties = {};
|
|
675
760
|
const required = [];
|
|
676
761
|
for (const [key, propSchema] of Object.entries(schema.properties)) {
|
|
677
762
|
properties[key] = this.propertyToJsonSchema(propSchema);
|
|
678
763
|
if (!t.schema.isOptional(propSchema)) required.push(key);
|
|
679
764
|
}
|
|
680
|
-
|
|
765
|
+
const result = {
|
|
681
766
|
type: "object",
|
|
682
767
|
properties,
|
|
683
768
|
required
|
|
684
769
|
};
|
|
770
|
+
if (options?.root !== false) result.$schema = "https://json-schema.org/draft/2020-12/schema";
|
|
771
|
+
return result;
|
|
685
772
|
}
|
|
686
773
|
/**
|
|
687
774
|
* Convert a single property schema to JSON Schema format.
|
|
@@ -707,7 +794,7 @@ var ToolPrimitive = class extends Primitive {
|
|
|
707
794
|
else if (t.schema.isArray(schema)) {
|
|
708
795
|
result.type = "array";
|
|
709
796
|
if ("items" in schema) result.items = this.propertyToJsonSchema(schema.items);
|
|
710
|
-
} else if (t.schema.isObject(schema)) Object.assign(result, this.schemaToJsonSchema(schema));
|
|
797
|
+
} else if (t.schema.isObject(schema)) Object.assign(result, this.schemaToJsonSchema(schema, { root: false }));
|
|
711
798
|
else if (t.schema.isUnsafe(schema) || t.schema.isOptional(schema)) {
|
|
712
799
|
const schemaAny = schema;
|
|
713
800
|
if (schemaAny.type === "string") {
|
|
@@ -726,32 +813,59 @@ var ToolPrimitive = class extends Primitive {
|
|
|
726
813
|
};
|
|
727
814
|
$tool[KIND] = ToolPrimitive;
|
|
728
815
|
//#endregion
|
|
729
|
-
//#region ../../src/mcp/transports/
|
|
730
|
-
const
|
|
731
|
-
name: "alepha.mcp.
|
|
732
|
-
description: "Configuration options for the MCP
|
|
733
|
-
schema: t.object({
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
816
|
+
//#region ../../src/mcp/transports/StreamableHttpMcpTransport.ts
|
|
817
|
+
const mcpStreamableHttpOptions = $atom({
|
|
818
|
+
name: "alepha.mcp.streamableHttp.options",
|
|
819
|
+
description: "Configuration options for the MCP Streamable HTTP transport.",
|
|
820
|
+
schema: t.object({
|
|
821
|
+
/**
|
|
822
|
+
* Path for the MCP endpoint. Single endpoint for both requests and
|
|
823
|
+
* (optional) server-streamed responses, per spec 2025-03-26+.
|
|
824
|
+
*/
|
|
825
|
+
path: t.text({ default: "/mcp" }),
|
|
826
|
+
/**
|
|
827
|
+
* Allow-list of `Origin` header values accepted on incoming requests.
|
|
828
|
+
* Empty array (default) means "allow any". When set, browser-originated
|
|
829
|
+
* requests with a non-matching `Origin` are rejected with 403 Forbidden,
|
|
830
|
+
* blocking DNS-rebinding attacks against localhost MCP servers.
|
|
831
|
+
*
|
|
832
|
+
* Server-to-server callers (no `Origin` header) are always allowed.
|
|
833
|
+
*
|
|
834
|
+
* Spec 2025-11-25, PR #1439.
|
|
835
|
+
*/
|
|
836
|
+
allowedOrigins: t.array(t.text(), { default: [] })
|
|
837
|
+
}),
|
|
838
|
+
default: {
|
|
839
|
+
path: "/mcp",
|
|
840
|
+
allowedOrigins: []
|
|
841
|
+
}
|
|
739
842
|
});
|
|
843
|
+
const mcpSseOptions = mcpStreamableHttpOptions;
|
|
740
844
|
/**
|
|
741
|
-
*
|
|
845
|
+
* Streamable HTTP transport for MCP communication.
|
|
846
|
+
*
|
|
847
|
+
* Implements the 2025-03-26+ Streamable HTTP transport: a single `/mcp`
|
|
848
|
+
* endpoint that accepts JSON-RPC over POST and returns either
|
|
849
|
+
* `application/json` (single response, the default) or
|
|
850
|
+
* `text/event-stream` (when the server wants to stream multiple messages).
|
|
742
851
|
*
|
|
743
|
-
*
|
|
744
|
-
*
|
|
852
|
+
* Designed for serverless deployment (Cloudflare Workers, etc.) — there is
|
|
853
|
+
* no long-lived GET stream. GET on the endpoint returns 405 Method Not
|
|
854
|
+
* Allowed; clients that want server-initiated push must rely on the POST
|
|
855
|
+
* response stream when the server upgrades to SSE for that particular call.
|
|
745
856
|
*
|
|
746
|
-
*
|
|
747
|
-
* -
|
|
748
|
-
*
|
|
857
|
+
* Spec compliance:
|
|
858
|
+
* - 2025-06-18: validates `MCP-Protocol-Version` header on every request
|
|
859
|
+
* after `initialize` against the version negotiated and stored on
|
|
860
|
+
* `McpServerProvider`.
|
|
861
|
+
* - 2025-11-25: rejects requests with a non-allow-listed `Origin` header
|
|
862
|
+
* (PR #1439). See {@link mcpStreamableHttpOptions.allowedOrigins}.
|
|
749
863
|
*
|
|
750
864
|
* @example
|
|
751
865
|
* ```ts
|
|
752
866
|
* import { Alepha, run } from "alepha";
|
|
753
867
|
* import { AlephaServer } from "alepha/server";
|
|
754
|
-
* import { AlephaMcp,
|
|
868
|
+
* import { AlephaMcp, StreamableHttpMcpTransport } from "alepha/mcp";
|
|
755
869
|
*
|
|
756
870
|
* class MyTools {
|
|
757
871
|
* // ... tool definitions
|
|
@@ -761,50 +875,36 @@ path: t.text({ default: "/mcp" }) }),
|
|
|
761
875
|
* Alepha.create()
|
|
762
876
|
* .with(AlephaServer)
|
|
763
877
|
* .with(AlephaMcp)
|
|
764
|
-
* .with(
|
|
878
|
+
* .with(StreamableHttpMcpTransport)
|
|
765
879
|
* .with(MyTools)
|
|
766
880
|
* );
|
|
767
881
|
* ```
|
|
768
882
|
*/
|
|
769
|
-
var
|
|
883
|
+
var StreamableHttpMcpTransport = class {
|
|
770
884
|
log = $logger();
|
|
771
|
-
options = $state(
|
|
885
|
+
options = $state(mcpStreamableHttpOptions);
|
|
772
886
|
mcpServer = $inject(McpServerProvider);
|
|
773
887
|
/**
|
|
774
|
-
*
|
|
775
|
-
*
|
|
776
|
-
*
|
|
777
|
-
*
|
|
888
|
+
* GET on the MCP endpoint is not supported in this transport. Returning
|
|
889
|
+
* 405 (rather than serving the legacy two-endpoint SSE pattern) is the
|
|
890
|
+
* spec-allowed response for servers that don't offer server-initiated
|
|
891
|
+
* push outside of an active POST.
|
|
778
892
|
*/
|
|
779
|
-
|
|
893
|
+
notAllowed = $route({
|
|
780
894
|
method: "GET",
|
|
781
895
|
path: this.options.path,
|
|
782
|
-
handler:
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
const endpointEvent = this.formatSseEvent("endpoint", `${this.options.path}`);
|
|
788
|
-
controller.enqueue(encoder.encode(endpointEvent));
|
|
789
|
-
const capabilitiesNotification = createNotification("notifications/capabilities", { capabilities: this.mcpServer.getCapabilities() });
|
|
790
|
-
const capabilitiesEvent = this.formatSseEvent("message", JSON.stringify(capabilitiesNotification));
|
|
791
|
-
controller.enqueue(encoder.encode(capabilitiesEvent));
|
|
792
|
-
},
|
|
793
|
-
cancel: () => {
|
|
794
|
-
this.log.debug("MCP SSE connection closed");
|
|
795
|
-
}
|
|
796
|
-
});
|
|
797
|
-
request.reply.status = 200;
|
|
798
|
-
request.reply.headers = {
|
|
799
|
-
"content-type": "text/event-stream",
|
|
800
|
-
"cache-control": "no-cache",
|
|
801
|
-
connection: "keep-alive"
|
|
802
|
-
};
|
|
803
|
-
request.reply.body = stream;
|
|
896
|
+
handler: (request) => {
|
|
897
|
+
request.reply.status = 405;
|
|
898
|
+
request.reply.headers.allow = "POST";
|
|
899
|
+
request.reply.headers["content-type"] = "application/json";
|
|
900
|
+
request.reply.body = JSON.stringify({ error: "Method Not Allowed. Use POST for MCP messages." });
|
|
804
901
|
}
|
|
805
902
|
});
|
|
806
903
|
/**
|
|
807
904
|
* POST endpoint for client-to-server JSON-RPC messages.
|
|
905
|
+
* Returns `application/json` for single responses; tools that need to
|
|
906
|
+
* stream progress would upgrade to `text/event-stream` (deferred until a
|
|
907
|
+
* concrete need exists).
|
|
808
908
|
*/
|
|
809
909
|
message = $route({
|
|
810
910
|
method: "POST",
|
|
@@ -812,13 +912,40 @@ var SseMcpTransport = class {
|
|
|
812
912
|
schema: { body: t.json() },
|
|
813
913
|
handler: async (request) => {
|
|
814
914
|
try {
|
|
915
|
+
const originRaw = request.headers.origin;
|
|
916
|
+
const origin = Array.isArray(originRaw) ? originRaw[0] : originRaw;
|
|
917
|
+
if (origin && this.options.allowedOrigins.length > 0 && !this.options.allowedOrigins.includes(origin)) {
|
|
918
|
+
this.log.warn("Rejected MCP request with non-allowed Origin", {
|
|
919
|
+
origin,
|
|
920
|
+
allowed: this.options.allowedOrigins
|
|
921
|
+
});
|
|
922
|
+
request.reply.status = 403;
|
|
923
|
+
request.reply.headers["content-type"] = "application/json";
|
|
924
|
+
request.reply.body = JSON.stringify({ error: "Forbidden: Origin not allowed" });
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
815
927
|
const body = typeof request.body === "string" ? request.body : JSON.stringify(request.body);
|
|
816
928
|
this.log.debug("MCP request body", {
|
|
817
929
|
body,
|
|
818
930
|
bodyType: typeof request.body
|
|
819
931
|
});
|
|
820
932
|
const rpcRequest = parseMessage(body);
|
|
821
|
-
const
|
|
933
|
+
const headers = { ...request.headers };
|
|
934
|
+
if (rpcRequest.method !== "initialize") {
|
|
935
|
+
const headerRaw = headers["mcp-protocol-version"];
|
|
936
|
+
const headerVersion = Array.isArray(headerRaw) ? headerRaw[0] : headerRaw;
|
|
937
|
+
if (headerVersion && headerVersion !== this.mcpServer.negotiatedVersion) {
|
|
938
|
+
this.log.warn("MCP-Protocol-Version header mismatch", {
|
|
939
|
+
header: headerVersion,
|
|
940
|
+
negotiated: this.mcpServer.negotiatedVersion
|
|
941
|
+
});
|
|
942
|
+
request.reply.status = 400;
|
|
943
|
+
request.reply.headers["content-type"] = "application/json";
|
|
944
|
+
request.reply.body = JSON.stringify({ error: `MCP-Protocol-Version mismatch: expected ${this.mcpServer.negotiatedVersion}, got ${headerVersion}` });
|
|
945
|
+
return;
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
const context = { headers };
|
|
822
949
|
const response = await this.mcpServer.handleMessage(rpcRequest, context);
|
|
823
950
|
if (response) {
|
|
824
951
|
request.reply.headers["content-type"] = "application/json";
|
|
@@ -837,13 +964,13 @@ var SseMcpTransport = class {
|
|
|
837
964
|
}
|
|
838
965
|
}
|
|
839
966
|
});
|
|
840
|
-
/**
|
|
841
|
-
* Format a message as an SSE event.
|
|
842
|
-
*/
|
|
843
|
-
formatSseEvent(event, data) {
|
|
844
|
-
return `event: ${event}\ndata: ${data}\n\n`;
|
|
845
|
-
}
|
|
846
967
|
};
|
|
968
|
+
/**
|
|
969
|
+
* @deprecated Use {@link StreamableHttpMcpTransport}. The 2024-11-05
|
|
970
|
+
* two-endpoint HTTP+SSE pattern was replaced by Streamable HTTP in spec
|
|
971
|
+
* 2025-03-26. This alias is preserved for one release to ease migration.
|
|
972
|
+
*/
|
|
973
|
+
const SseMcpTransport = StreamableHttpMcpTransport;
|
|
847
974
|
//#endregion
|
|
848
975
|
//#region ../../src/mcp/index.ts
|
|
849
976
|
/**
|
|
@@ -854,7 +981,7 @@ var SseMcpTransport = class {
|
|
|
854
981
|
* - MCP tool definitions
|
|
855
982
|
* - MCP prompt definitions
|
|
856
983
|
* - JSON-RPC protocol
|
|
857
|
-
* -
|
|
984
|
+
* - Streamable HTTP transport (spec 2025-03-26+)
|
|
858
985
|
*
|
|
859
986
|
* @module alepha.mcp
|
|
860
987
|
*/
|
|
@@ -866,9 +993,9 @@ const AlephaMcp = $module({
|
|
|
866
993
|
$prompt
|
|
867
994
|
],
|
|
868
995
|
services: [McpServerProvider],
|
|
869
|
-
variants: [
|
|
996
|
+
variants: [StreamableHttpMcpTransport]
|
|
870
997
|
});
|
|
871
998
|
//#endregion
|
|
872
|
-
export { $prompt, $resource, $tool, AlephaMcp, JSONRPC_VERSION, JsonRpcErrorCodes, JsonRpcParseError, MCP_PROTOCOL_VERSION, McpError, McpErrorCodes, McpForbiddenError, McpInvalidParamsError, McpMethodNotFoundError, McpPromptNotFoundError, McpResourceNotFoundError, McpServerProvider, McpToolNotFoundError, McpUnauthorizedError, PromptPrimitive, ResourcePrimitive, SseMcpTransport, ToolPrimitive, createErrorResponse, createInternalError, createInvalidParamsError, createInvalidRequestError, createMethodNotFoundError, createNotification, createParseError, createResponse, isNotification, isValidJsonRpcRequest, mcpSseOptions, parseMessage };
|
|
999
|
+
export { $prompt, $resource, $tool, AlephaMcp, JSONRPC_VERSION, JsonRpcErrorCodes, JsonRpcParseError, MCP_PROTOCOL_VERSION, McpError, McpErrorCodes, McpForbiddenError, McpInvalidParamsError, McpMethodNotFoundError, McpPromptNotFoundError, McpResourceNotFoundError, McpServerProvider, McpToolNotFoundError, McpUnauthorizedError, PromptPrimitive, ResourcePrimitive, SUPPORTED_PROTOCOL_VERSIONS, SseMcpTransport, StreamableHttpMcpTransport, ToolPrimitive, createErrorResponse, createInternalError, createInvalidParamsError, createInvalidRequestError, createMethodNotFoundError, createNotification, createParseError, createResponse, isNotification, isSupportedProtocolVersion, isValidJsonRpcRequest, mcpSseOptions, mcpStreamableHttpOptions, parseMessage };
|
|
873
1000
|
|
|
874
1001
|
//# sourceMappingURL=index.js.map
|