@leanmcp/core 0.3.19 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +485 -478
- package/dist/chunk-7SU7UAUW.mjs +272 -0
- package/dist/chunk-LPEX4YW6.mjs +13 -0
- package/dist/dynamodb-session-store-WJ2ALBES.mjs +10 -0
- package/dist/index.d.mts +166 -17
- package/dist/index.d.ts +166 -17
- package/dist/index.js +438 -9
- package/dist/index.mjs +268 -124
- package/dist/server-BEQUIEE2.mjs +25808 -0
- package/package.json +78 -76
package/dist/index.js
CHANGED
|
@@ -482,6 +482,164 @@ var init_validation = __esm({
|
|
|
482
482
|
}
|
|
483
483
|
});
|
|
484
484
|
|
|
485
|
+
// src/dynamodb-session-store.ts
|
|
486
|
+
var dynamodb_session_store_exports = {};
|
|
487
|
+
__export(dynamodb_session_store_exports, {
|
|
488
|
+
DEFAULT_TABLE_NAME: () => DEFAULT_TABLE_NAME,
|
|
489
|
+
DEFAULT_TTL_SECONDS: () => DEFAULT_TTL_SECONDS,
|
|
490
|
+
DynamoDBSessionStore: () => DynamoDBSessionStore
|
|
491
|
+
});
|
|
492
|
+
var import_client_dynamodb, import_lib_dynamodb, DEFAULT_TABLE_NAME, DEFAULT_TTL_SECONDS, DynamoDBSessionStore;
|
|
493
|
+
var init_dynamodb_session_store = __esm({
|
|
494
|
+
"src/dynamodb-session-store.ts"() {
|
|
495
|
+
"use strict";
|
|
496
|
+
import_client_dynamodb = require("@aws-sdk/client-dynamodb");
|
|
497
|
+
import_lib_dynamodb = require("@aws-sdk/lib-dynamodb");
|
|
498
|
+
init_logger();
|
|
499
|
+
DEFAULT_TABLE_NAME = "leanmcp-sessions";
|
|
500
|
+
DEFAULT_TTL_SECONDS = 86400;
|
|
501
|
+
DynamoDBSessionStore = class {
|
|
502
|
+
static {
|
|
503
|
+
__name(this, "DynamoDBSessionStore");
|
|
504
|
+
}
|
|
505
|
+
client;
|
|
506
|
+
tableName;
|
|
507
|
+
ttlSeconds;
|
|
508
|
+
logger;
|
|
509
|
+
constructor(options) {
|
|
510
|
+
this.tableName = options?.tableName || process.env.DYNAMODB_TABLE_NAME || DEFAULT_TABLE_NAME;
|
|
511
|
+
this.ttlSeconds = options?.ttlSeconds || DEFAULT_TTL_SECONDS;
|
|
512
|
+
this.logger = new Logger({
|
|
513
|
+
level: options?.logging ? LogLevel.INFO : LogLevel.NONE,
|
|
514
|
+
prefix: "DynamoDBSessionStore"
|
|
515
|
+
});
|
|
516
|
+
const dynamoClient = new import_client_dynamodb.DynamoDBClient({
|
|
517
|
+
region: options?.region || process.env.AWS_REGION || "us-east-1"
|
|
518
|
+
});
|
|
519
|
+
this.client = import_lib_dynamodb.DynamoDBDocumentClient.from(dynamoClient);
|
|
520
|
+
this.logger.info(`Initialized with table: ${this.tableName}, TTL: ${this.ttlSeconds}s`);
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Check if a session exists in DynamoDB
|
|
524
|
+
*/
|
|
525
|
+
async sessionExists(sessionId) {
|
|
526
|
+
try {
|
|
527
|
+
const result = await this.client.send(new import_lib_dynamodb.GetCommand({
|
|
528
|
+
TableName: this.tableName,
|
|
529
|
+
Key: {
|
|
530
|
+
sessionId
|
|
531
|
+
},
|
|
532
|
+
ProjectionExpression: "sessionId"
|
|
533
|
+
}));
|
|
534
|
+
const exists = !!result.Item;
|
|
535
|
+
this.logger.debug(`Session ${sessionId} exists: ${exists}`);
|
|
536
|
+
return exists;
|
|
537
|
+
} catch (error) {
|
|
538
|
+
this.logger.error(`Error checking session existence: ${error.message}`);
|
|
539
|
+
return false;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* Create a new session in DynamoDB
|
|
544
|
+
*/
|
|
545
|
+
async createSession(sessionId, data) {
|
|
546
|
+
try {
|
|
547
|
+
const now = /* @__PURE__ */ new Date();
|
|
548
|
+
const ttl = Math.floor(Date.now() / 1e3) + this.ttlSeconds;
|
|
549
|
+
await this.client.send(new import_lib_dynamodb.PutCommand({
|
|
550
|
+
TableName: this.tableName,
|
|
551
|
+
Item: {
|
|
552
|
+
sessionId,
|
|
553
|
+
createdAt: now.toISOString(),
|
|
554
|
+
updatedAt: now.toISOString(),
|
|
555
|
+
ttl,
|
|
556
|
+
data: data || {}
|
|
557
|
+
}
|
|
558
|
+
}));
|
|
559
|
+
this.logger.info(`Created session: ${sessionId} (TTL: ${new Date(ttl * 1e3).toISOString()})`);
|
|
560
|
+
} catch (error) {
|
|
561
|
+
this.logger.error(`Error creating session ${sessionId}: ${error.message}`);
|
|
562
|
+
throw new Error(`Failed to create session: ${error.message}`);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
566
|
+
* Get session data from DynamoDB
|
|
567
|
+
*/
|
|
568
|
+
async getSession(sessionId) {
|
|
569
|
+
try {
|
|
570
|
+
const result = await this.client.send(new import_lib_dynamodb.GetCommand({
|
|
571
|
+
TableName: this.tableName,
|
|
572
|
+
Key: {
|
|
573
|
+
sessionId
|
|
574
|
+
}
|
|
575
|
+
}));
|
|
576
|
+
if (!result.Item) {
|
|
577
|
+
this.logger.debug(`Session ${sessionId} not found`);
|
|
578
|
+
return null;
|
|
579
|
+
}
|
|
580
|
+
const sessionData = {
|
|
581
|
+
sessionId: result.Item.sessionId,
|
|
582
|
+
createdAt: new Date(result.Item.createdAt),
|
|
583
|
+
updatedAt: new Date(result.Item.updatedAt),
|
|
584
|
+
ttl: result.Item.ttl,
|
|
585
|
+
data: result.Item.data
|
|
586
|
+
};
|
|
587
|
+
this.logger.debug(`Retrieved session: ${sessionId}`);
|
|
588
|
+
return sessionData;
|
|
589
|
+
} catch (error) {
|
|
590
|
+
this.logger.error(`Error getting session ${sessionId}: ${error.message}`);
|
|
591
|
+
return null;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
595
|
+
* Update session data in DynamoDB
|
|
596
|
+
* Automatically refreshes TTL on each update
|
|
597
|
+
*/
|
|
598
|
+
async updateSession(sessionId, updates) {
|
|
599
|
+
try {
|
|
600
|
+
const ttl = Math.floor(Date.now() / 1e3) + this.ttlSeconds;
|
|
601
|
+
await this.client.send(new import_lib_dynamodb.UpdateCommand({
|
|
602
|
+
TableName: this.tableName,
|
|
603
|
+
Key: {
|
|
604
|
+
sessionId
|
|
605
|
+
},
|
|
606
|
+
UpdateExpression: "SET updatedAt = :now, #data = :data, #ttl = :ttl",
|
|
607
|
+
ExpressionAttributeNames: {
|
|
608
|
+
"#data": "data",
|
|
609
|
+
"#ttl": "ttl"
|
|
610
|
+
},
|
|
611
|
+
ExpressionAttributeValues: {
|
|
612
|
+
":now": (/* @__PURE__ */ new Date()).toISOString(),
|
|
613
|
+
":data": updates.data || {},
|
|
614
|
+
":ttl": ttl
|
|
615
|
+
}
|
|
616
|
+
}));
|
|
617
|
+
this.logger.debug(`Updated session: ${sessionId}`);
|
|
618
|
+
} catch (error) {
|
|
619
|
+
this.logger.error(`Error updating session ${sessionId}: ${error.message}`);
|
|
620
|
+
throw new Error(`Failed to update session: ${error.message}`);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
/**
|
|
624
|
+
* Delete a session from DynamoDB
|
|
625
|
+
*/
|
|
626
|
+
async deleteSession(sessionId) {
|
|
627
|
+
try {
|
|
628
|
+
await this.client.send(new import_lib_dynamodb.DeleteCommand({
|
|
629
|
+
TableName: this.tableName,
|
|
630
|
+
Key: {
|
|
631
|
+
sessionId
|
|
632
|
+
}
|
|
633
|
+
}));
|
|
634
|
+
this.logger.info(`Deleted session: ${sessionId}`);
|
|
635
|
+
} catch (error) {
|
|
636
|
+
this.logger.error(`Error deleting session ${sessionId}: ${error.message}`);
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
});
|
|
642
|
+
|
|
485
643
|
// src/http-server.ts
|
|
486
644
|
function isInitializeRequest(body) {
|
|
487
645
|
return body && body.method === "initialize";
|
|
@@ -558,7 +716,7 @@ async function createHTTPServer(serverInput, options) {
|
|
|
558
716
|
auth: serverOptions.auth
|
|
559
717
|
};
|
|
560
718
|
}
|
|
561
|
-
const [express, { StreamableHTTPServerTransport }, cors] = await Promise.all([
|
|
719
|
+
const [express, { StreamableHTTPServerTransport: StreamableHTTPServerTransport2 }, cors] = await Promise.all([
|
|
562
720
|
// @ts-ignore
|
|
563
721
|
import("express").catch(() => {
|
|
564
722
|
throw new Error("Express not found. Install with: npm install express @types/express");
|
|
@@ -673,6 +831,19 @@ async function createHTTPServer(serverInput, options) {
|
|
|
673
831
|
app.use(express.json());
|
|
674
832
|
const isStateless = httpOptions.stateless !== false;
|
|
675
833
|
console.log(`Starting LeanMCP HTTP Server (${isStateless ? "STATELESS" : "STATEFUL"})...`);
|
|
834
|
+
if (!isStateless && !httpOptions.sessionStore) {
|
|
835
|
+
if (process.env.LEANMCP_LAMBDA === "true") {
|
|
836
|
+
try {
|
|
837
|
+
const { DynamoDBSessionStore: DynamoDBSessionStore2 } = await Promise.resolve().then(() => (init_dynamodb_session_store(), dynamodb_session_store_exports));
|
|
838
|
+
httpOptions.sessionStore = new DynamoDBSessionStore2({
|
|
839
|
+
logging: httpOptions.logging
|
|
840
|
+
});
|
|
841
|
+
logger.info("Auto-configured DynamoDB session store for LeanMCP Lambda");
|
|
842
|
+
} catch (e) {
|
|
843
|
+
logger.warn(`Running on LeanMCP Lambda but failed to initialize DynamoDB session store: ${e.message}`);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
}
|
|
676
847
|
const DASHBOARD_URL = process.env.DASHBOARD_URL || "https://s3-dashboard-build.s3.us-west-2.amazonaws.com/out/index.html";
|
|
677
848
|
let cachedDashboard = null;
|
|
678
849
|
let cacheTimestamp = 0;
|
|
@@ -814,19 +985,129 @@ async function createHTTPServer(serverInput, options) {
|
|
|
814
985
|
if (sessionId && transports[sessionId]) {
|
|
815
986
|
transport = transports[sessionId];
|
|
816
987
|
logger.debug(`Reusing session: ${sessionId}`);
|
|
988
|
+
} else if (sessionId && isInitializeRequest(req.body)) {
|
|
989
|
+
logger.info(`Initialize request with session ${sessionId} - checking for session restoration...`);
|
|
990
|
+
if (httpOptions.sessionStore) {
|
|
991
|
+
const exists = await httpOptions.sessionStore.sessionExists(sessionId);
|
|
992
|
+
if (exists) {
|
|
993
|
+
logger.info(`Restoring session: ${sessionId}`);
|
|
994
|
+
transport = new StreamableHTTPServerTransport2({
|
|
995
|
+
sessionIdGenerator: /* @__PURE__ */ __name(() => sessionId, "sessionIdGenerator"),
|
|
996
|
+
onsessioninitialized: /* @__PURE__ */ __name((sid) => {
|
|
997
|
+
transports[sid] = transport;
|
|
998
|
+
logger.info(`Session restored: ${sid}`);
|
|
999
|
+
}, "onsessioninitialized")
|
|
1000
|
+
});
|
|
1001
|
+
transport.onclose = async () => {
|
|
1002
|
+
if (transport.sessionId) {
|
|
1003
|
+
delete transports[transport.sessionId];
|
|
1004
|
+
logger.debug(`Session cleaned up: ${transport.sessionId}`);
|
|
1005
|
+
if (httpOptions.sessionStore) {
|
|
1006
|
+
await httpOptions.sessionStore.deleteSession(transport.sessionId);
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
};
|
|
1010
|
+
const freshServer = await serverFactory();
|
|
1011
|
+
if (freshServer && typeof freshServer.waitForInit === "function") {
|
|
1012
|
+
await freshServer.waitForInit();
|
|
1013
|
+
}
|
|
1014
|
+
await freshServer.connect(transport);
|
|
1015
|
+
} else {
|
|
1016
|
+
logger.info(`Session ${sessionId} not found in store, creating new session`);
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
if (!transport) {
|
|
1020
|
+
transport = new StreamableHTTPServerTransport2({
|
|
1021
|
+
sessionIdGenerator: /* @__PURE__ */ __name(() => (0, import_node_crypto.randomUUID)(), "sessionIdGenerator"),
|
|
1022
|
+
onsessioninitialized: /* @__PURE__ */ __name(async (newSessionId) => {
|
|
1023
|
+
transports[newSessionId] = transport;
|
|
1024
|
+
logger.info(`Session initialized: ${newSessionId}`);
|
|
1025
|
+
if (httpOptions.sessionStore) {
|
|
1026
|
+
await httpOptions.sessionStore.createSession(newSessionId);
|
|
1027
|
+
}
|
|
1028
|
+
}, "onsessioninitialized")
|
|
1029
|
+
});
|
|
1030
|
+
transport.onclose = async () => {
|
|
1031
|
+
if (transport.sessionId) {
|
|
1032
|
+
delete transports[transport.sessionId];
|
|
1033
|
+
logger.debug(`Session cleaned up: ${transport.sessionId}`);
|
|
1034
|
+
if (httpOptions.sessionStore) {
|
|
1035
|
+
await httpOptions.sessionStore.deleteSession(transport.sessionId);
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
};
|
|
1039
|
+
if (!mcpServer) {
|
|
1040
|
+
throw new Error("MCP server not initialized");
|
|
1041
|
+
}
|
|
1042
|
+
await mcpServer.connect(transport);
|
|
1043
|
+
}
|
|
1044
|
+
} else if (sessionId && !isInitializeRequest(req.body)) {
|
|
1045
|
+
logger.info(`Transport missing for session ${sessionId}, checking session store...`);
|
|
1046
|
+
if (httpOptions.sessionStore) {
|
|
1047
|
+
const exists = await httpOptions.sessionStore.sessionExists(sessionId);
|
|
1048
|
+
if (!exists) {
|
|
1049
|
+
res.status(404).json({
|
|
1050
|
+
jsonrpc: "2.0",
|
|
1051
|
+
error: {
|
|
1052
|
+
code: -32001,
|
|
1053
|
+
message: "Session not found"
|
|
1054
|
+
},
|
|
1055
|
+
id: req.body?.id || null
|
|
1056
|
+
});
|
|
1057
|
+
return;
|
|
1058
|
+
}
|
|
1059
|
+
logger.info(`Auto-restoring session: ${sessionId}`);
|
|
1060
|
+
transport = new StreamableHTTPServerTransport2({
|
|
1061
|
+
sessionIdGenerator: /* @__PURE__ */ __name(() => sessionId, "sessionIdGenerator"),
|
|
1062
|
+
onsessioninitialized: /* @__PURE__ */ __name((sid) => {
|
|
1063
|
+
transports[sid] = transport;
|
|
1064
|
+
logger.info(`Session auto-restored: ${sid}`);
|
|
1065
|
+
}, "onsessioninitialized")
|
|
1066
|
+
});
|
|
1067
|
+
transport.onclose = async () => {
|
|
1068
|
+
if (transport.sessionId) {
|
|
1069
|
+
delete transports[transport.sessionId];
|
|
1070
|
+
logger.debug(`Session cleaned up: ${transport.sessionId}`);
|
|
1071
|
+
if (httpOptions.sessionStore) {
|
|
1072
|
+
await httpOptions.sessionStore.deleteSession(transport.sessionId);
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
};
|
|
1076
|
+
const freshServer = await serverFactory();
|
|
1077
|
+
if (freshServer && typeof freshServer.waitForInit === "function") {
|
|
1078
|
+
await freshServer.waitForInit();
|
|
1079
|
+
}
|
|
1080
|
+
await freshServer.connect(transport);
|
|
1081
|
+
} else {
|
|
1082
|
+
res.status(400).json({
|
|
1083
|
+
jsonrpc: "2.0",
|
|
1084
|
+
error: {
|
|
1085
|
+
code: -32e3,
|
|
1086
|
+
message: "Session expired (no session store configured)"
|
|
1087
|
+
},
|
|
1088
|
+
id: req.body?.id || null
|
|
1089
|
+
});
|
|
1090
|
+
return;
|
|
1091
|
+
}
|
|
817
1092
|
} else if (!sessionId && isInitializeRequest(req.body)) {
|
|
818
1093
|
logger.info("Creating new MCP session...");
|
|
819
|
-
transport = new
|
|
1094
|
+
transport = new StreamableHTTPServerTransport2({
|
|
820
1095
|
sessionIdGenerator: /* @__PURE__ */ __name(() => (0, import_node_crypto.randomUUID)(), "sessionIdGenerator"),
|
|
821
|
-
onsessioninitialized: /* @__PURE__ */ __name((newSessionId) => {
|
|
1096
|
+
onsessioninitialized: /* @__PURE__ */ __name(async (newSessionId) => {
|
|
822
1097
|
transports[newSessionId] = transport;
|
|
823
1098
|
logger.info(`Session initialized: ${newSessionId}`);
|
|
1099
|
+
if (httpOptions.sessionStore) {
|
|
1100
|
+
await httpOptions.sessionStore.createSession(newSessionId);
|
|
1101
|
+
}
|
|
824
1102
|
}, "onsessioninitialized")
|
|
825
1103
|
});
|
|
826
|
-
transport.onclose = () => {
|
|
1104
|
+
transport.onclose = async () => {
|
|
827
1105
|
if (transport.sessionId) {
|
|
828
1106
|
delete transports[transport.sessionId];
|
|
829
1107
|
logger.debug(`Session cleaned up: ${transport.sessionId}`);
|
|
1108
|
+
if (httpOptions.sessionStore) {
|
|
1109
|
+
await httpOptions.sessionStore.deleteSession(transport.sessionId);
|
|
1110
|
+
}
|
|
830
1111
|
}
|
|
831
1112
|
};
|
|
832
1113
|
if (!mcpServer) {
|
|
@@ -882,7 +1163,7 @@ async function createHTTPServer(serverInput, options) {
|
|
|
882
1163
|
if (freshServer && typeof freshServer.waitForInit === "function") {
|
|
883
1164
|
await freshServer.waitForInit();
|
|
884
1165
|
}
|
|
885
|
-
const transport = new
|
|
1166
|
+
const transport = new StreamableHTTPServerTransport2({
|
|
886
1167
|
sessionIdGenerator: void 0
|
|
887
1168
|
});
|
|
888
1169
|
await freshServer.connect(transport);
|
|
@@ -1084,11 +1365,152 @@ var init_auth_helpers = __esm({
|
|
|
1084
1365
|
}
|
|
1085
1366
|
});
|
|
1086
1367
|
|
|
1368
|
+
// src/session-store.ts
|
|
1369
|
+
var init_session_store = __esm({
|
|
1370
|
+
"src/session-store.ts"() {
|
|
1371
|
+
"use strict";
|
|
1372
|
+
}
|
|
1373
|
+
});
|
|
1374
|
+
|
|
1375
|
+
// src/session-provider.ts
|
|
1376
|
+
var import_streamableHttp, LeanMCPSessionProvider;
|
|
1377
|
+
var init_session_provider = __esm({
|
|
1378
|
+
"src/session-provider.ts"() {
|
|
1379
|
+
"use strict";
|
|
1380
|
+
import_streamableHttp = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
|
|
1381
|
+
init_dynamodb_session_store();
|
|
1382
|
+
LeanMCPSessionProvider = class {
|
|
1383
|
+
static {
|
|
1384
|
+
__name(this, "LeanMCPSessionProvider");
|
|
1385
|
+
}
|
|
1386
|
+
transports = /* @__PURE__ */ new Map();
|
|
1387
|
+
sessionStore;
|
|
1388
|
+
constructor(options) {
|
|
1389
|
+
if (options?.sessionStore) {
|
|
1390
|
+
this.sessionStore = options.sessionStore;
|
|
1391
|
+
} else {
|
|
1392
|
+
this.sessionStore = new DynamoDBSessionStore({
|
|
1393
|
+
tableName: options?.tableName,
|
|
1394
|
+
region: options?.region,
|
|
1395
|
+
ttlSeconds: options?.ttlSeconds,
|
|
1396
|
+
logging: options?.logging
|
|
1397
|
+
});
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
/**
|
|
1401
|
+
* Get transport from memory
|
|
1402
|
+
*/
|
|
1403
|
+
get(sessionId) {
|
|
1404
|
+
return this.transports.get(sessionId);
|
|
1405
|
+
}
|
|
1406
|
+
/**
|
|
1407
|
+
* Check if session exists (memory or DynamoDB)
|
|
1408
|
+
*/
|
|
1409
|
+
async has(sessionId) {
|
|
1410
|
+
if (this.transports.has(sessionId)) return true;
|
|
1411
|
+
return this.sessionStore.sessionExists(sessionId);
|
|
1412
|
+
}
|
|
1413
|
+
/**
|
|
1414
|
+
* Store transport and create session in DynamoDB
|
|
1415
|
+
*/
|
|
1416
|
+
async set(sessionId, transport) {
|
|
1417
|
+
this.transports.set(sessionId, transport);
|
|
1418
|
+
await this.sessionStore.createSession(sessionId);
|
|
1419
|
+
}
|
|
1420
|
+
/**
|
|
1421
|
+
* Delete transport and session
|
|
1422
|
+
*/
|
|
1423
|
+
async delete(sessionId) {
|
|
1424
|
+
this.transports.delete(sessionId);
|
|
1425
|
+
await this.sessionStore.deleteSession(sessionId);
|
|
1426
|
+
}
|
|
1427
|
+
/**
|
|
1428
|
+
* Get or recreate transport for a session
|
|
1429
|
+
* This is the key method for Lambda support - handles container recycling
|
|
1430
|
+
*
|
|
1431
|
+
* @param sessionId - Session ID to get or recreate
|
|
1432
|
+
* @param serverFactory - Factory function to create fresh MCP server instances
|
|
1433
|
+
* @param transportOptions - Optional callbacks for transport lifecycle events
|
|
1434
|
+
* @returns Transport instance or null if session doesn't exist
|
|
1435
|
+
*/
|
|
1436
|
+
async getOrRecreate(sessionId, serverFactory, transportOptions) {
|
|
1437
|
+
const existing = this.transports.get(sessionId);
|
|
1438
|
+
if (existing) return existing;
|
|
1439
|
+
const exists = await this.sessionStore.sessionExists(sessionId);
|
|
1440
|
+
if (!exists) return null;
|
|
1441
|
+
const transport = new import_streamableHttp.StreamableHTTPServerTransport({
|
|
1442
|
+
sessionIdGenerator: /* @__PURE__ */ __name(() => sessionId, "sessionIdGenerator"),
|
|
1443
|
+
onsessioninitialized: /* @__PURE__ */ __name((sid) => {
|
|
1444
|
+
this.transports.set(sid, transport);
|
|
1445
|
+
transportOptions?.onsessioninitialized?.(sid);
|
|
1446
|
+
}, "onsessioninitialized")
|
|
1447
|
+
});
|
|
1448
|
+
transport.onclose = () => {
|
|
1449
|
+
this.transports.delete(sessionId);
|
|
1450
|
+
transportOptions?.onclose?.();
|
|
1451
|
+
};
|
|
1452
|
+
const server = await serverFactory();
|
|
1453
|
+
await server.connect(transport);
|
|
1454
|
+
return transport;
|
|
1455
|
+
}
|
|
1456
|
+
/**
|
|
1457
|
+
* Get session data from DynamoDB
|
|
1458
|
+
*/
|
|
1459
|
+
async getSessionData(sessionId) {
|
|
1460
|
+
const session = await this.sessionStore.getSession(sessionId);
|
|
1461
|
+
return session?.data || null;
|
|
1462
|
+
}
|
|
1463
|
+
/**
|
|
1464
|
+
* Update session data in DynamoDB
|
|
1465
|
+
*/
|
|
1466
|
+
async updateSessionData(sessionId, data) {
|
|
1467
|
+
await this.sessionStore.updateSession(sessionId, {
|
|
1468
|
+
data
|
|
1469
|
+
});
|
|
1470
|
+
}
|
|
1471
|
+
/**
|
|
1472
|
+
* Get number of in-memory transports
|
|
1473
|
+
*/
|
|
1474
|
+
get size() {
|
|
1475
|
+
return this.transports.size;
|
|
1476
|
+
}
|
|
1477
|
+
/**
|
|
1478
|
+
* Get all session IDs in memory
|
|
1479
|
+
*/
|
|
1480
|
+
keys() {
|
|
1481
|
+
return this.transports.keys();
|
|
1482
|
+
}
|
|
1483
|
+
/**
|
|
1484
|
+
* Get all transports in memory
|
|
1485
|
+
*/
|
|
1486
|
+
values() {
|
|
1487
|
+
return this.transports.values();
|
|
1488
|
+
}
|
|
1489
|
+
/**
|
|
1490
|
+
* Iterate over all sessions in memory
|
|
1491
|
+
*/
|
|
1492
|
+
entries() {
|
|
1493
|
+
return this.transports.entries();
|
|
1494
|
+
}
|
|
1495
|
+
/**
|
|
1496
|
+
* Clear all in-memory transports (does not affect DynamoDB)
|
|
1497
|
+
*/
|
|
1498
|
+
clear() {
|
|
1499
|
+
this.transports.clear();
|
|
1500
|
+
}
|
|
1501
|
+
};
|
|
1502
|
+
}
|
|
1503
|
+
});
|
|
1504
|
+
|
|
1087
1505
|
// src/index.ts
|
|
1088
1506
|
var index_exports = {};
|
|
1089
1507
|
__export(index_exports, {
|
|
1090
1508
|
Auth: () => Auth,
|
|
1509
|
+
DEFAULT_TABLE_NAME: () => DEFAULT_TABLE_NAME,
|
|
1510
|
+
DEFAULT_TTL_SECONDS: () => DEFAULT_TTL_SECONDS,
|
|
1091
1511
|
Deprecated: () => Deprecated,
|
|
1512
|
+
DynamoDBSessionStore: () => DynamoDBSessionStore,
|
|
1513
|
+
LeanMCPSessionProvider: () => LeanMCPSessionProvider,
|
|
1092
1514
|
LogLevel: () => LogLevel,
|
|
1093
1515
|
Logger: () => Logger,
|
|
1094
1516
|
MCPServer: () => MCPServer,
|
|
@@ -1141,6 +1563,9 @@ var init_index = __esm({
|
|
|
1141
1563
|
init_logger();
|
|
1142
1564
|
init_validation();
|
|
1143
1565
|
init_auth_helpers();
|
|
1566
|
+
init_session_store();
|
|
1567
|
+
init_session_provider();
|
|
1568
|
+
init_dynamodb_session_store();
|
|
1144
1569
|
init_decorators();
|
|
1145
1570
|
init_schema_generator();
|
|
1146
1571
|
init_logger();
|
|
@@ -1454,14 +1879,14 @@ var init_index = __esm({
|
|
|
1454
1879
|
/**
|
|
1455
1880
|
* Auto-register all services from the mcp directory
|
|
1456
1881
|
* Scans the directory recursively and registers all exported classes
|
|
1457
|
-
*
|
|
1882
|
+
*
|
|
1458
1883
|
* @param mcpDir - Path to the mcp directory containing service files
|
|
1459
1884
|
* @param serviceFactories - Optional map of service class names to factory functions for dependency injection
|
|
1460
|
-
*
|
|
1885
|
+
*
|
|
1461
1886
|
* @example
|
|
1462
1887
|
* // Auto-register services with no dependencies
|
|
1463
1888
|
* await server.autoRegisterServices('./mcp');
|
|
1464
|
-
*
|
|
1889
|
+
*
|
|
1465
1890
|
* @example
|
|
1466
1891
|
* // Auto-register with dependency injection
|
|
1467
1892
|
* await server.autoRegisterServices('./mcp', {
|
|
@@ -1614,7 +2039,7 @@ var init_index = __esm({
|
|
|
1614
2039
|
}
|
|
1615
2040
|
/**
|
|
1616
2041
|
* Watch UI manifest for changes and reload resources dynamically
|
|
1617
|
-
*
|
|
2042
|
+
*
|
|
1618
2043
|
* CRITICAL: Only for stateful mode. In stateless mode, each request
|
|
1619
2044
|
* creates a fresh server that reads the manifest directly, making
|
|
1620
2045
|
* watchers both unnecessary and a memory leak source.
|
|
@@ -2143,7 +2568,11 @@ init_index();
|
|
|
2143
2568
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2144
2569
|
0 && (module.exports = {
|
|
2145
2570
|
Auth,
|
|
2571
|
+
DEFAULT_TABLE_NAME,
|
|
2572
|
+
DEFAULT_TTL_SECONDS,
|
|
2146
2573
|
Deprecated,
|
|
2574
|
+
DynamoDBSessionStore,
|
|
2575
|
+
LeanMCPSessionProvider,
|
|
2147
2576
|
LogLevel,
|
|
2148
2577
|
Logger,
|
|
2149
2578
|
MCPServer,
|