@1mcp/agent 0.29.0-beta4 → 0.29.0-beta6
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/build/constants/mcp.d.ts +5 -1
- package/build/constants/mcp.d.ts.map +1 -1
- package/build/constants/mcp.js +5 -1
- package/build/constants/mcp.js.map +1 -1
- package/build/core/client/clientManager.d.ts +15 -0
- package/build/core/client/clientManager.d.ts.map +1 -1
- package/build/core/client/clientManager.js +88 -9
- package/build/core/client/clientManager.js.map +1 -1
- package/build/core/loading/mcpLoadingManager.d.ts +1 -2
- package/build/core/loading/mcpLoadingManager.d.ts.map +1 -1
- package/build/core/loading/mcpLoadingManager.js +8 -24
- package/build/core/loading/mcpLoadingManager.js.map +1 -1
- package/build/core/loading/parallelExecutor.d.ts +91 -0
- package/build/core/loading/parallelExecutor.d.ts.map +1 -0
- package/build/core/loading/parallelExecutor.js +130 -0
- package/build/core/loading/parallelExecutor.js.map +1 -0
- package/build/transport/http/restorableStreamableTransport.d.ts +56 -11
- package/build/transport/http/restorableStreamableTransport.d.ts.map +1 -1
- package/build/transport/http/restorableStreamableTransport.js +93 -21
- package/build/transport/http/restorableStreamableTransport.js.map +1 -1
- package/build/transport/http/routes/streamableHttpRoutes.d.ts +2 -1
- package/build/transport/http/routes/streamableHttpRoutes.d.ts.map +1 -1
- package/build/transport/http/routes/streamableHttpRoutes.js +105 -236
- package/build/transport/http/routes/streamableHttpRoutes.js.map +1 -1
- package/build/transport/http/utils/sdkInternals.d.ts +32 -0
- package/build/transport/http/utils/sdkInternals.d.ts.map +1 -0
- package/build/transport/http/utils/sdkInternals.js +6 -0
- package/build/transport/http/utils/sdkInternals.js.map +1 -0
- package/build/transport/http/utils/sessionService.d.ts +76 -0
- package/build/transport/http/utils/sessionService.d.ts.map +1 -0
- package/build/transport/http/utils/sessionService.js +232 -0
- package/build/transport/http/utils/sessionService.js.map +1 -0
- package/build/transport/stdioProxyTransport.d.ts +15 -4
- package/build/transport/stdioProxyTransport.d.ts.map +1 -1
- package/build/transport/stdioProxyTransport.js +35 -47
- package/build/transport/stdioProxyTransport.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import logger from '../../logger/logger.js';
|
|
3
|
+
/**
|
|
4
|
+
* Events emitted by ParallelExecutor during execution
|
|
5
|
+
*/
|
|
6
|
+
export var ParallelExecutorEvent;
|
|
7
|
+
(function (ParallelExecutorEvent) {
|
|
8
|
+
/** Emitted when an item begins processing */
|
|
9
|
+
ParallelExecutorEvent["ItemStart"] = "item-start";
|
|
10
|
+
/** Emitted when an item completes processing (success or failure) */
|
|
11
|
+
ParallelExecutorEvent["ItemComplete"] = "item-complete";
|
|
12
|
+
/** Emitted when a batch of items completes processing */
|
|
13
|
+
ParallelExecutorEvent["BatchComplete"] = "batch-complete";
|
|
14
|
+
})(ParallelExecutorEvent || (ParallelExecutorEvent = {}));
|
|
15
|
+
/**
|
|
16
|
+
* ParallelExecutor - Executes items in parallel with concurrency control
|
|
17
|
+
*
|
|
18
|
+
* This utility processes multiple items concurrently while respecting a maximum
|
|
19
|
+
* concurrency limit. Items are processed in batches, and events are emitted for
|
|
20
|
+
* observability during execution.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* const executor = new ParallelExecutor<string, number>();
|
|
25
|
+
*
|
|
26
|
+
* executor.on(ParallelExecutorEvent.ItemStart, (item) => {
|
|
27
|
+
* console.log(`Processing: ${item}`);
|
|
28
|
+
* });
|
|
29
|
+
*
|
|
30
|
+
* const results = await executor.execute(
|
|
31
|
+
* ['a', 'b', 'c'],
|
|
32
|
+
* async (item) => {
|
|
33
|
+
* return item.length; // Some async operation
|
|
34
|
+
* },
|
|
35
|
+
* { maxConcurrent: 2 }
|
|
36
|
+
* );
|
|
37
|
+
*
|
|
38
|
+
* // Results: Map {'a' => 1, 'b' => 1, 'c' => 1}
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export class ParallelExecutor extends EventEmitter {
|
|
42
|
+
constructor() {
|
|
43
|
+
super();
|
|
44
|
+
this.setMaxListeners(100); // Allow many listeners for observability
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Execute items in parallel with concurrency control
|
|
48
|
+
*
|
|
49
|
+
* @param items - Array of items to process
|
|
50
|
+
* @param handler - Async function that processes each item
|
|
51
|
+
* @param options - Execution options including max concurrency
|
|
52
|
+
* @returns Map of items to their successful results only. Failed items are not included
|
|
53
|
+
* but can be tracked via ItemComplete events (which emit Error objects)
|
|
54
|
+
* @throws Never throws - individual item failures are caught and logged, other items continue processing
|
|
55
|
+
* @remarks Errors from individual items do not prevent other items from processing.
|
|
56
|
+
* Failed items emit ItemComplete events with Error objects and are logged,
|
|
57
|
+
* then excluded from the returned results Map. Use event listeners to track failures.
|
|
58
|
+
*/
|
|
59
|
+
async execute(items, handler, options) {
|
|
60
|
+
const results = new Map();
|
|
61
|
+
// Process items in batches based on maxConcurrent
|
|
62
|
+
for (let i = 0; i < items.length; i += options.maxConcurrent) {
|
|
63
|
+
const batch = items.slice(i, i + options.maxConcurrent);
|
|
64
|
+
// Start all items in this batch
|
|
65
|
+
const batchPromises = batch.map(async (item) => {
|
|
66
|
+
this.emit(ParallelExecutorEvent.ItemStart, item);
|
|
67
|
+
try {
|
|
68
|
+
const result = await handler(item);
|
|
69
|
+
results.set(item, result);
|
|
70
|
+
this.emit(ParallelExecutorEvent.ItemComplete, item, result);
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
const errorObj = error instanceof Error ? error : new Error(String(error));
|
|
75
|
+
// Still emit the completion event, but don't set in results Map
|
|
76
|
+
// This allows other items to continue processing
|
|
77
|
+
this.emit(ParallelExecutorEvent.ItemComplete, item, errorObj);
|
|
78
|
+
throw errorObj; // Re-throw for Promise.allSettled handling
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
// Wait for this batch to complete before starting next batch
|
|
82
|
+
const batchResults = await Promise.allSettled(batchPromises);
|
|
83
|
+
// Log and track failed items from this batch
|
|
84
|
+
const failedItems = [];
|
|
85
|
+
batchResults.forEach((result, index) => {
|
|
86
|
+
if (result.status === 'rejected') {
|
|
87
|
+
failedItems.push({ item: batch[index], result });
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
if (failedItems.length > 0) {
|
|
91
|
+
for (const { item, result } of failedItems) {
|
|
92
|
+
const error = result.reason;
|
|
93
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
94
|
+
logger.error(`Failed to process item in parallel execution: ${item}`, {
|
|
95
|
+
error: errorMessage,
|
|
96
|
+
itemType: typeof item,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Emit batch complete event
|
|
101
|
+
this.emit(ParallelExecutorEvent.BatchComplete, batch);
|
|
102
|
+
}
|
|
103
|
+
return results;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Type-safe event listener registration
|
|
107
|
+
*/
|
|
108
|
+
on(event, listener) {
|
|
109
|
+
return super.on(event, listener);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Type-safe one-time event listener registration
|
|
113
|
+
*/
|
|
114
|
+
once(event, listener) {
|
|
115
|
+
return super.once(event, listener);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Type-safe event listener removal
|
|
119
|
+
*/
|
|
120
|
+
off(event, listener) {
|
|
121
|
+
return super.off(event, listener);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Type-safe event emission
|
|
125
|
+
*/
|
|
126
|
+
emit(event, ...args) {
|
|
127
|
+
return super.emit(event, ...args);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=parallelExecutor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parallelExecutor.js","sourceRoot":"","sources":["../../../src/core/loading/parallelExecutor.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Metadata about a transport's restoration state, used for debugging
|
|
4
|
+
* and monitoring session restoration flow.
|
|
4
5
|
*/
|
|
5
6
|
export interface RestorationInfo {
|
|
6
7
|
isRestored: boolean;
|
|
7
8
|
sessionId?: string;
|
|
8
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* Result type for operations that may fail.
|
|
12
|
+
* Uses discriminated union to make invalid states unrepresentable.
|
|
13
|
+
*/
|
|
14
|
+
export type OperationResult = {
|
|
15
|
+
success: true;
|
|
16
|
+
error?: never;
|
|
17
|
+
} | {
|
|
18
|
+
success: false;
|
|
19
|
+
error: string;
|
|
20
|
+
};
|
|
9
21
|
/**
|
|
10
22
|
* RestorableStreamableHTTPServerTransport extends the MCP SDK's StreamableHTTPServerTransport
|
|
11
23
|
* to provide proper session restoration capabilities with type-safe access to internal properties.
|
|
@@ -13,22 +25,55 @@ export interface RestorationInfo {
|
|
|
13
25
|
* This wrapper class encapsulates the initialization logic needed for restored sessions,
|
|
14
26
|
* providing a clean interface that's less likely to break with SDK updates.
|
|
15
27
|
*
|
|
28
|
+
* @remarks
|
|
29
|
+
* The class works by:
|
|
30
|
+
* 1. Storing a restored sessionId that overrides the SDK's getter
|
|
31
|
+
* 2. Providing methods to safely access and modify internal SDK properties
|
|
32
|
+
* 3. Returning success/failure status from operations for proper error handling
|
|
33
|
+
*
|
|
16
34
|
* @example
|
|
17
35
|
* ```typescript
|
|
18
|
-
* //
|
|
36
|
+
* // SessionService handles the full restoration flow:
|
|
19
37
|
* const transport = new RestorableStreamableHTTPServerTransport({
|
|
20
|
-
* sessionIdGenerator: () =>
|
|
38
|
+
* sessionIdGenerator: () => originalSessionId,
|
|
21
39
|
* });
|
|
22
|
-
* transport.markAsInitialized();
|
|
23
|
-
*
|
|
24
|
-
* //
|
|
25
|
-
* if (transport.isRestored()) {
|
|
26
|
-
* // Handle restored session logic
|
|
27
|
-
* }
|
|
40
|
+
* const initResult = transport.markAsInitialized();
|
|
41
|
+
* transport.setSessionId(originalSessionId);
|
|
42
|
+
* // Now transport.isRestored() returns true
|
|
28
43
|
* ```
|
|
29
44
|
*/
|
|
30
45
|
export declare class RestorableStreamableHTTPServerTransport extends StreamableHTTPServerTransport {
|
|
31
46
|
private _isRestored;
|
|
47
|
+
private _restoredSessionId?;
|
|
48
|
+
/**
|
|
49
|
+
* Sets the sessionId for a restored session.
|
|
50
|
+
*
|
|
51
|
+
* When restoring a session, we need to ensure the sessionId is available immediately
|
|
52
|
+
* without waiting for the sessionIdGenerator to be called by the SDK. This method
|
|
53
|
+
* directly sets the sessionId on the underlying transport.
|
|
54
|
+
*
|
|
55
|
+
* @param sessionId - The sessionId to set for the restored session
|
|
56
|
+
* @returns OperationResult indicating success or failure with error details
|
|
57
|
+
*/
|
|
58
|
+
setSessionId(sessionId: string): OperationResult;
|
|
59
|
+
/**
|
|
60
|
+
* Override sessionId getter to return restored sessionId if available.
|
|
61
|
+
*
|
|
62
|
+
* This ensures that even if the underlying transport hasn't generated the sessionId yet,
|
|
63
|
+
* we return the correct restored sessionId. If no restored session ID exists, delegates
|
|
64
|
+
* to the parent class's getter by manually accessing the property descriptor.
|
|
65
|
+
*
|
|
66
|
+
* @remarks
|
|
67
|
+
* We cannot use `super.sessionId` directly because this override shadows the parent's
|
|
68
|
+
* getter. Instead, we use Object.getOwnPropertyDescriptor to access the parent's
|
|
69
|
+
* property descriptor and call its getter with the correct context.
|
|
70
|
+
*
|
|
71
|
+
* Type assertion to `object` is safe here because we know the prototype chain exists:
|
|
72
|
+
* this -> RestorableStreamableHTTPServerTransport -> StreamableHTTPServerTransport -> Object.prototype
|
|
73
|
+
* Object.getOwnPropertyDescriptor requires an object type, and TypeScript cannot infer this
|
|
74
|
+
* from the double getPrototypeOf call.
|
|
75
|
+
*/
|
|
76
|
+
get sessionId(): string | undefined;
|
|
32
77
|
/**
|
|
33
78
|
* Marks the transport as initialized for restored sessions.
|
|
34
79
|
*
|
|
@@ -37,9 +82,9 @@ export declare class RestorableStreamableHTTPServerTransport extends StreamableH
|
|
|
37
82
|
* The MCP SDK checks the _initialized flag and rejects requests if it's false.
|
|
38
83
|
* This method safely sets that flag to allow the restored session to work.
|
|
39
84
|
*
|
|
40
|
-
* @
|
|
85
|
+
* @returns OperationResult indicating success or failure with error details
|
|
41
86
|
*/
|
|
42
|
-
markAsInitialized():
|
|
87
|
+
markAsInitialized(): OperationResult;
|
|
43
88
|
/**
|
|
44
89
|
* Returns whether this transport was created for a restored session.
|
|
45
90
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"restorableStreamableTransport.d.ts","sourceRoot":"","sources":["../../../src/transport/http/restorableStreamableTransport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;
|
|
1
|
+
{"version":3,"file":"restorableStreamableTransport.d.ts","sourceRoot":"","sources":["../../../src/transport/http/restorableStreamableTransport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AAKnG;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnG;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,uCAAwC,SAAQ,6BAA6B;IACxF,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,kBAAkB,CAAC,CAAS;IAEpC;;;;;;;;;OASG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe;IAwBhD;;;;;;;;;;;;;;;;OAgBG;IACH,IAAa,SAAS,IAAI,MAAM,GAAG,SAAS,CAiB3C;IAED;;;;;;;;;OASG;IACH,iBAAiB,IAAI,eAAe;IAyBpC;;;;OAIG;IACH,UAAU,IAAI,OAAO;IAIrB;;;;OAIG;IACH,kBAAkB,IAAI,eAAe;CAUtC"}
|
|
@@ -7,22 +7,95 @@ import logger from '../../logger/logger.js';
|
|
|
7
7
|
* This wrapper class encapsulates the initialization logic needed for restored sessions,
|
|
8
8
|
* providing a clean interface that's less likely to break with SDK updates.
|
|
9
9
|
*
|
|
10
|
+
* @remarks
|
|
11
|
+
* The class works by:
|
|
12
|
+
* 1. Storing a restored sessionId that overrides the SDK's getter
|
|
13
|
+
* 2. Providing methods to safely access and modify internal SDK properties
|
|
14
|
+
* 3. Returning success/failure status from operations for proper error handling
|
|
15
|
+
*
|
|
10
16
|
* @example
|
|
11
17
|
* ```typescript
|
|
12
|
-
* //
|
|
18
|
+
* // SessionService handles the full restoration flow:
|
|
13
19
|
* const transport = new RestorableStreamableHTTPServerTransport({
|
|
14
|
-
* sessionIdGenerator: () =>
|
|
20
|
+
* sessionIdGenerator: () => originalSessionId,
|
|
15
21
|
* });
|
|
16
|
-
* transport.markAsInitialized();
|
|
17
|
-
*
|
|
18
|
-
* //
|
|
19
|
-
* if (transport.isRestored()) {
|
|
20
|
-
* // Handle restored session logic
|
|
21
|
-
* }
|
|
22
|
+
* const initResult = transport.markAsInitialized();
|
|
23
|
+
* transport.setSessionId(originalSessionId);
|
|
24
|
+
* // Now transport.isRestored() returns true
|
|
22
25
|
* ```
|
|
23
26
|
*/
|
|
24
27
|
export class RestorableStreamableHTTPServerTransport extends StreamableHTTPServerTransport {
|
|
25
28
|
_isRestored = false;
|
|
29
|
+
_restoredSessionId;
|
|
30
|
+
/**
|
|
31
|
+
* Sets the sessionId for a restored session.
|
|
32
|
+
*
|
|
33
|
+
* When restoring a session, we need to ensure the sessionId is available immediately
|
|
34
|
+
* without waiting for the sessionIdGenerator to be called by the SDK. This method
|
|
35
|
+
* directly sets the sessionId on the underlying transport.
|
|
36
|
+
*
|
|
37
|
+
* @param sessionId - The sessionId to set for the restored session
|
|
38
|
+
* @returns OperationResult indicating success or failure with error details
|
|
39
|
+
*/
|
|
40
|
+
setSessionId(sessionId) {
|
|
41
|
+
this._restoredSessionId = sessionId;
|
|
42
|
+
try {
|
|
43
|
+
// Access the underlying _webStandardTransport where sessionId is stored
|
|
44
|
+
// StreamableHTTPServerTransport is a wrapper with getter-only sessionId
|
|
45
|
+
// The actual sessionId is on _webStandardTransport which allows setting
|
|
46
|
+
const internalTransport = this;
|
|
47
|
+
const webStandardTransport = internalTransport._webStandardTransport;
|
|
48
|
+
if (webStandardTransport) {
|
|
49
|
+
webStandardTransport.sessionId = sessionId;
|
|
50
|
+
return { success: true };
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
success: false,
|
|
54
|
+
error: 'No webStandardTransport found - SDK internal structure may have changed or transport is not properly initialized',
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
59
|
+
logger.warn(`Failed to set sessionId "${sessionId}" on underlying transport: ${errorMessage}`);
|
|
60
|
+
return { success: false, error: errorMessage };
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Override sessionId getter to return restored sessionId if available.
|
|
65
|
+
*
|
|
66
|
+
* This ensures that even if the underlying transport hasn't generated the sessionId yet,
|
|
67
|
+
* we return the correct restored sessionId. If no restored session ID exists, delegates
|
|
68
|
+
* to the parent class's getter by manually accessing the property descriptor.
|
|
69
|
+
*
|
|
70
|
+
* @remarks
|
|
71
|
+
* We cannot use `super.sessionId` directly because this override shadows the parent's
|
|
72
|
+
* getter. Instead, we use Object.getOwnPropertyDescriptor to access the parent's
|
|
73
|
+
* property descriptor and call its getter with the correct context.
|
|
74
|
+
*
|
|
75
|
+
* Type assertion to `object` is safe here because we know the prototype chain exists:
|
|
76
|
+
* this -> RestorableStreamableHTTPServerTransport -> StreamableHTTPServerTransport -> Object.prototype
|
|
77
|
+
* Object.getOwnPropertyDescriptor requires an object type, and TypeScript cannot infer this
|
|
78
|
+
* from the double getPrototypeOf call.
|
|
79
|
+
*/
|
|
80
|
+
get sessionId() {
|
|
81
|
+
// First check if we have a restored sessionId
|
|
82
|
+
if (this._restoredSessionId) {
|
|
83
|
+
return this._restoredSessionId;
|
|
84
|
+
}
|
|
85
|
+
// Otherwise delegate to parent class's getter directly
|
|
86
|
+
// Use Object.getOwnPropertyDescriptor to get the parent's property descriptor
|
|
87
|
+
// and call the getter with the parent's context
|
|
88
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
89
|
+
const proto = Object.getPrototypeOf(Object.getPrototypeOf(this));
|
|
90
|
+
if (!proto)
|
|
91
|
+
return undefined;
|
|
92
|
+
const descriptor = Object.getOwnPropertyDescriptor(proto, 'sessionId');
|
|
93
|
+
if (descriptor?.get) {
|
|
94
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
95
|
+
return descriptor.get.call(this);
|
|
96
|
+
}
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
26
99
|
/**
|
|
27
100
|
* Marks the transport as initialized for restored sessions.
|
|
28
101
|
*
|
|
@@ -31,27 +104,29 @@ export class RestorableStreamableHTTPServerTransport extends StreamableHTTPServe
|
|
|
31
104
|
* The MCP SDK checks the _initialized flag and rejects requests if it's false.
|
|
32
105
|
* This method safely sets that flag to allow the restored session to work.
|
|
33
106
|
*
|
|
34
|
-
* @
|
|
107
|
+
* @returns OperationResult indicating success or failure with error details
|
|
35
108
|
*/
|
|
36
109
|
markAsInitialized() {
|
|
37
110
|
try {
|
|
38
111
|
// Use type-safe interface to access internal SDK properties
|
|
39
|
-
//
|
|
40
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment
|
|
112
|
+
// MCP SDK private property _initialized is not exposed in public types
|
|
41
113
|
const internalTransport = this;
|
|
42
|
-
//
|
|
43
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
114
|
+
// Accessing private SDK property for session restoration functionality
|
|
44
115
|
if (internalTransport._initialized !== undefined) {
|
|
45
|
-
//
|
|
46
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
116
|
+
// Setting private SDK property to mark session as initialized for restoration
|
|
47
117
|
internalTransport._initialized = true;
|
|
48
118
|
}
|
|
119
|
+
// Note: If _initialized is undefined, we still mark as restored since the SDK may have changed
|
|
120
|
+
// This provides graceful degradation while allowing session restoration to proceed
|
|
49
121
|
this._isRestored = true;
|
|
50
122
|
logger.debug('Transport marked as initialized for restored session');
|
|
123
|
+
return { success: true };
|
|
51
124
|
}
|
|
52
125
|
catch (error) {
|
|
53
|
-
|
|
54
|
-
|
|
126
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
127
|
+
logger.warn(`Failed to mark transport as initialized: ${errorMessage}`);
|
|
128
|
+
this._isRestored = false;
|
|
129
|
+
return { success: false, error: errorMessage };
|
|
55
130
|
}
|
|
56
131
|
}
|
|
57
132
|
/**
|
|
@@ -69,13 +144,10 @@ export class RestorableStreamableHTTPServerTransport extends StreamableHTTPServe
|
|
|
69
144
|
*/
|
|
70
145
|
getRestorationInfo() {
|
|
71
146
|
// Use type-safe interface to access potentially private sessionId
|
|
72
|
-
// Reason: sessionId property may not be exposed in public SDK types
|
|
73
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment
|
|
74
147
|
const internalTransport = this;
|
|
75
148
|
return {
|
|
76
149
|
isRestored: this._isRestored,
|
|
77
|
-
//
|
|
78
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment
|
|
150
|
+
// Accessing potentially private sessionId property for debugging
|
|
79
151
|
sessionId: internalTransport.sessionId,
|
|
80
152
|
};
|
|
81
153
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"restorableStreamableTransport.js","sourceRoot":"","sources":["../../../src/transport/http/restorableStreamableTransport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AAEnG,OAAO,MAAM,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"restorableStreamableTransport.js","sourceRoot":"","sources":["../../../src/transport/http/restorableStreamableTransport.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { AsyncLoadingOrchestrator } from '../../../core/capabilities/asyncLoadingOrchestrator.js';
|
|
2
2
|
import { ServerManager } from '../../../core/server/serverManager.js';
|
|
3
3
|
import { StreamableSessionRepository } from '../../../transport/http/storage/streamableSessionRepository.js';
|
|
4
|
+
import { SessionService } from '../../../transport/http/utils/sessionService.js';
|
|
4
5
|
import { RequestHandler, Router } from 'express';
|
|
5
|
-
export declare function setupStreamableHttpRoutes(router: Router, serverManager: ServerManager, sessionRepository: StreamableSessionRepository, authMiddleware: RequestHandler, availabilityMiddleware?: RequestHandler, asyncOrchestrator?: AsyncLoadingOrchestrator, customTemplate?: string): void;
|
|
6
|
+
export declare function setupStreamableHttpRoutes(router: Router, serverManager: ServerManager, sessionRepository: StreamableSessionRepository, authMiddleware: RequestHandler, availabilityMiddleware?: RequestHandler, asyncOrchestrator?: AsyncLoadingOrchestrator, customTemplate?: string, injectedSessionService?: SessionService): void;
|
|
6
7
|
//# sourceMappingURL=streamableHttpRoutes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"streamableHttpRoutes.d.ts","sourceRoot":"","sources":["../../../../src/transport/http/routes/streamableHttpRoutes.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,wBAAwB,EAAE,MAAM,oDAAoD,CAAC;AAC9F,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"streamableHttpRoutes.d.ts","sourceRoot":"","sources":["../../../../src/transport/http/routes/streamableHttpRoutes.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,wBAAwB,EAAE,MAAM,oDAAoD,CAAC;AAC9F,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAWlE,OAAO,EAAE,2BAA2B,EAAE,MAAM,4DAA4D,CAAC;AAEzG,OAAO,EAAE,cAAc,EAAE,MAAM,6CAA6C,CAAC;AAE7E,OAAO,EAAW,cAAc,EAAY,MAAM,EAAE,MAAM,SAAS,CAAC;AAsDpE,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,aAAa,EAC5B,iBAAiB,EAAE,2BAA2B,EAC9C,cAAc,EAAE,cAAc,EAC9B,sBAAsB,CAAC,EAAE,cAAc,EACvC,iBAAiB,CAAC,EAAE,wBAAwB,EAC5C,cAAc,CAAC,EAAE,MAAM,EACvB,sBAAsB,CAAC,EAAE,cAAc,GACtC,IAAI,CAqJN"}
|