@mastra/mcp 1.13.1-alpha.0 → 1.14.0-alpha.0
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/CHANGELOG.md +95 -0
- package/dist/client/client.d.ts +6 -0
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/configuration.d.ts +36 -0
- package/dist/client/configuration.d.ts.map +1 -1
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/docs-mcp-mcp-apps.md +3 -3
- package/dist/docs/references/docs-mcp-overview.md +6 -10
- package/dist/docs/references/reference-tools-mcp-client.md +22 -0
- package/dist/docs/references/reference-tools-mcp-server.md +161 -4
- package/dist/index.cjs +490 -122
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +491 -123
- package/dist/index.js.map +1 -1
- package/dist/server/notificationBroadcast.d.ts +24 -0
- package/dist/server/notificationBroadcast.d.ts.map +1 -0
- package/dist/server/promptActions.d.ts +8 -3
- package/dist/server/promptActions.d.ts.map +1 -1
- package/dist/server/resourceActions.d.ts +14 -8
- package/dist/server/resourceActions.d.ts.map +1 -1
- package/dist/server/server.d.ts +100 -3
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/toolActions.d.ts +77 -0
- package/dist/server/toolActions.d.ts.map +1 -0
- package/package.json +11 -11
package/dist/index.cjs
CHANGED
|
@@ -31491,6 +31491,7 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
31491
31491
|
sigHupHandler;
|
|
31492
31492
|
serverInstructions;
|
|
31493
31493
|
_roots;
|
|
31494
|
+
hasElicitationCapability;
|
|
31494
31495
|
requireToolApproval;
|
|
31495
31496
|
onToolError;
|
|
31496
31497
|
/** Provides access to resource operations (list, read, subscribe, etc.) */
|
|
@@ -31521,13 +31522,13 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
31521
31522
|
this.requireToolApproval = server.requireToolApproval;
|
|
31522
31523
|
this.onToolError = server.onToolError ?? "throw";
|
|
31523
31524
|
this._roots = server.roots ?? [];
|
|
31525
|
+
this.hasElicitationCapability = capabilities.elicitation !== void 0;
|
|
31524
31526
|
const hasRoots = this._roots.length > 0 || !!capabilities.roots;
|
|
31525
31527
|
const clientCapabilities = {
|
|
31526
31528
|
...capabilities,
|
|
31527
|
-
//
|
|
31528
|
-
elicitation: {
|
|
31529
|
-
|
|
31530
|
-
},
|
|
31529
|
+
// Only advertise elicitation when explicitly configured or when a handler
|
|
31530
|
+
// registers it before connect(). `elicitation: {}` is legacy form support.
|
|
31531
|
+
...capabilities.elicitation !== void 0 ? { elicitation: { ...capabilities.elicitation } } : {},
|
|
31531
31532
|
// Auto-enable roots capability if roots are provided
|
|
31532
31533
|
...hasRoots ? { roots: { listChanged: true, ...capabilities.roots ?? {} } } : {},
|
|
31533
31534
|
// Advertise MCP Apps extension support so servers know we can render UI resources
|
|
@@ -31942,6 +31943,16 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
31942
31943
|
handler();
|
|
31943
31944
|
});
|
|
31944
31945
|
}
|
|
31946
|
+
/**
|
|
31947
|
+
* Register a handler to be called when the tool list changes on the server.
|
|
31948
|
+
* Use this to re-fetch tools via `tools()` when notified.
|
|
31949
|
+
*/
|
|
31950
|
+
setToolListChangedNotificationHandler(handler) {
|
|
31951
|
+
this.log("debug", "Setting tool list changed notification handler");
|
|
31952
|
+
this.client.setNotificationHandler(types_js.ToolListChangedNotificationSchema, () => {
|
|
31953
|
+
handler();
|
|
31954
|
+
});
|
|
31955
|
+
}
|
|
31945
31956
|
setResourceUpdatedNotificationHandler(handler) {
|
|
31946
31957
|
this.log("debug", "Setting resource updated notification handler");
|
|
31947
31958
|
this.client.setNotificationHandler(types_js.ResourceUpdatedNotificationSchema, (notification) => {
|
|
@@ -31956,6 +31967,17 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
31956
31967
|
}
|
|
31957
31968
|
setElicitationRequestHandler(handler) {
|
|
31958
31969
|
this.log("debug", "Setting elicitation request handler");
|
|
31970
|
+
if (!this.hasElicitationCapability) {
|
|
31971
|
+
try {
|
|
31972
|
+
this.client.registerCapabilities({ elicitation: { form: {} } });
|
|
31973
|
+
this.hasElicitationCapability = true;
|
|
31974
|
+
} catch (error51) {
|
|
31975
|
+
throw new Error(
|
|
31976
|
+
"Cannot register an elicitation handler after connecting unless elicitation capability was configured before initialization.",
|
|
31977
|
+
{ cause: error51 }
|
|
31978
|
+
);
|
|
31979
|
+
}
|
|
31980
|
+
}
|
|
31959
31981
|
this.client.setRequestHandler(types_js.ElicitRequestSchema, async (request) => {
|
|
31960
31982
|
this.log("debug", `Received elicitation request: ${request.params.message}`);
|
|
31961
31983
|
return handler(request.params);
|
|
@@ -32418,7 +32440,7 @@ To fix this you have three different options:
|
|
|
32418
32440
|
*/
|
|
32419
32441
|
onRequest: async (serverName, handler) => {
|
|
32420
32442
|
try {
|
|
32421
|
-
const internalClient = await this.
|
|
32443
|
+
const internalClient = await this.getClientForServer(serverName);
|
|
32422
32444
|
return internalClient.elicitation.onRequest(handler);
|
|
32423
32445
|
} catch (err) {
|
|
32424
32446
|
throw new error$1.MastraError(
|
|
@@ -32843,6 +32865,58 @@ To fix this you have three different options:
|
|
|
32843
32865
|
}
|
|
32844
32866
|
};
|
|
32845
32867
|
}
|
|
32868
|
+
/**
|
|
32869
|
+
* Provides access to tool-related notification operations across all configured servers.
|
|
32870
|
+
*
|
|
32871
|
+
* To fetch tools, use `listTools()` or `listToolsets()`.
|
|
32872
|
+
*
|
|
32873
|
+
* @example
|
|
32874
|
+
* ```typescript
|
|
32875
|
+
* // React to tool list changes on a server
|
|
32876
|
+
* await mcp.tools.onListChanged('weatherServer', async () => {
|
|
32877
|
+
* console.log('Tool list changed, re-fetching...');
|
|
32878
|
+
* const tools = await mcp.listTools();
|
|
32879
|
+
* });
|
|
32880
|
+
* ```
|
|
32881
|
+
*/
|
|
32882
|
+
get tools() {
|
|
32883
|
+
this.addToInstanceCache();
|
|
32884
|
+
return {
|
|
32885
|
+
/**
|
|
32886
|
+
* Sets a notification handler for when the tool list changes on a server.
|
|
32887
|
+
*
|
|
32888
|
+
* @param serverName - Name of the server to monitor
|
|
32889
|
+
* @param handler - Callback function invoked when tools are added/removed/modified
|
|
32890
|
+
* @returns Promise resolving when handler is registered
|
|
32891
|
+
* @throws {MastraError} If setting up the handler fails
|
|
32892
|
+
*
|
|
32893
|
+
* @example
|
|
32894
|
+
* ```typescript
|
|
32895
|
+
* await mcp.tools.onListChanged('weatherServer', async () => {
|
|
32896
|
+
* const tools = await mcp.listTools();
|
|
32897
|
+
* });
|
|
32898
|
+
* ```
|
|
32899
|
+
*/
|
|
32900
|
+
onListChanged: async (serverName, handler) => {
|
|
32901
|
+
try {
|
|
32902
|
+
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
32903
|
+
return internalClient.setToolListChangedNotificationHandler(handler);
|
|
32904
|
+
} catch (error51) {
|
|
32905
|
+
throw new error$1.MastraError(
|
|
32906
|
+
{
|
|
32907
|
+
id: "MCP_CLIENT_ON_LIST_CHANGED_TOOLS_FAILED",
|
|
32908
|
+
domain: error$1.ErrorDomain.MCP,
|
|
32909
|
+
category: error$1.ErrorCategory.THIRD_PARTY,
|
|
32910
|
+
details: {
|
|
32911
|
+
serverName
|
|
32912
|
+
}
|
|
32913
|
+
},
|
|
32914
|
+
error51
|
|
32915
|
+
);
|
|
32916
|
+
}
|
|
32917
|
+
}
|
|
32918
|
+
};
|
|
32919
|
+
}
|
|
32846
32920
|
addToInstanceCache() {
|
|
32847
32921
|
if (!mcpClientInstances.has(this.id)) {
|
|
32848
32922
|
mcpClientInstances.set(this.id, this);
|
|
@@ -33134,7 +33208,14 @@ To fix this you have three different options:
|
|
|
33134
33208
|
if (!client) return null;
|
|
33135
33209
|
return client.stderr;
|
|
33136
33210
|
}
|
|
33137
|
-
|
|
33211
|
+
getServerConfig(serverName) {
|
|
33212
|
+
const serverConfig = this.serverConfigs[serverName];
|
|
33213
|
+
if (!serverConfig) {
|
|
33214
|
+
throw new Error(`Server configuration not found for name: ${serverName}`);
|
|
33215
|
+
}
|
|
33216
|
+
return serverConfig;
|
|
33217
|
+
}
|
|
33218
|
+
async getOrCreateClient(name, config2) {
|
|
33138
33219
|
if (this.disconnectPromise) {
|
|
33139
33220
|
await this.disconnectPromise;
|
|
33140
33221
|
}
|
|
@@ -33145,10 +33226,8 @@ To fix this you have three different options:
|
|
|
33145
33226
|
if (!existingClient) {
|
|
33146
33227
|
throw new Error(`Client ${name} exists but is undefined`);
|
|
33147
33228
|
}
|
|
33148
|
-
await existingClient.connect();
|
|
33149
33229
|
return existingClient;
|
|
33150
33230
|
}
|
|
33151
|
-
this.logger.debug("Connecting to MCP server", { name });
|
|
33152
33231
|
const mcpClient = new InternalMastraMCPClient({
|
|
33153
33232
|
name,
|
|
33154
33233
|
server: config2,
|
|
@@ -33157,35 +33236,42 @@ To fix this you have three different options:
|
|
|
33157
33236
|
});
|
|
33158
33237
|
mcpClient.__setLogger(this.logger);
|
|
33159
33238
|
this.mcpClientsById.set(name, mcpClient);
|
|
33239
|
+
return mcpClient;
|
|
33240
|
+
}
|
|
33241
|
+
async getConnectedClient(name, config2) {
|
|
33242
|
+
this.logger.debug("Connecting to MCP server", { name });
|
|
33243
|
+
const mcpClient = await this.getOrCreateClient(name, config2);
|
|
33160
33244
|
try {
|
|
33161
33245
|
await mcpClient.connect();
|
|
33162
33246
|
} catch (e) {
|
|
33163
|
-
|
|
33164
|
-
{
|
|
33165
|
-
id: "MCP_CLIENT_CONNECT_FAILED",
|
|
33166
|
-
domain: error$1.ErrorDomain.MCP,
|
|
33167
|
-
category: error$1.ErrorCategory.THIRD_PARTY,
|
|
33168
|
-
text: `Failed to connect to MCP server ${name}: ${e instanceof Error ? e.stack || e.message : String(e)}`,
|
|
33169
|
-
details: {
|
|
33170
|
-
name
|
|
33171
|
-
}
|
|
33172
|
-
},
|
|
33173
|
-
e
|
|
33174
|
-
);
|
|
33175
|
-
this.logger.trackException(mastraError);
|
|
33176
|
-
this.logger.error("MCPClient errored connecting to MCP server:", { error: mastraError.toString() });
|
|
33177
|
-
this.mcpClientsById.delete(name);
|
|
33178
|
-
throw mastraError;
|
|
33247
|
+
throw this.handleConnectError(name, e);
|
|
33179
33248
|
}
|
|
33180
33249
|
this.logger.debug("Connected to MCP server", { name });
|
|
33181
33250
|
return mcpClient;
|
|
33182
33251
|
}
|
|
33252
|
+
handleConnectError(name, error51) {
|
|
33253
|
+
const mastraError = new error$1.MastraError(
|
|
33254
|
+
{
|
|
33255
|
+
id: "MCP_CLIENT_CONNECT_FAILED",
|
|
33256
|
+
domain: error$1.ErrorDomain.MCP,
|
|
33257
|
+
category: error$1.ErrorCategory.THIRD_PARTY,
|
|
33258
|
+
text: `Failed to connect to MCP server ${name}: ${error51 instanceof Error ? error51.stack || error51.message : String(error51)}`,
|
|
33259
|
+
details: {
|
|
33260
|
+
name
|
|
33261
|
+
}
|
|
33262
|
+
},
|
|
33263
|
+
error51
|
|
33264
|
+
);
|
|
33265
|
+
this.logger.trackException(mastraError);
|
|
33266
|
+
this.logger.error("MCPClient errored connecting to MCP server:", { error: mastraError.toString() });
|
|
33267
|
+
this.mcpClientsById.delete(name);
|
|
33268
|
+
return mastraError;
|
|
33269
|
+
}
|
|
33183
33270
|
async getConnectedClientForServer(serverName) {
|
|
33184
|
-
|
|
33185
|
-
|
|
33186
|
-
|
|
33187
|
-
|
|
33188
|
-
return this.getConnectedClient(serverName, serverConfig);
|
|
33271
|
+
return this.getConnectedClient(serverName, this.getServerConfig(serverName));
|
|
33272
|
+
}
|
|
33273
|
+
async getClientForServer(serverName) {
|
|
33274
|
+
return this.getOrCreateClient(serverName, this.getServerConfig(serverName));
|
|
33189
33275
|
}
|
|
33190
33276
|
async getToolsForServer(serverName) {
|
|
33191
33277
|
for (let attempt = 1; attempt <= TOOL_DISCOVERY_MAX_ATTEMPTS; attempt++) {
|
|
@@ -33650,16 +33736,55 @@ var SSETransport = class {
|
|
|
33650
33736
|
});
|
|
33651
33737
|
}
|
|
33652
33738
|
};
|
|
33739
|
+
async function broadcastNotification({
|
|
33740
|
+
servers,
|
|
33741
|
+
send,
|
|
33742
|
+
logger,
|
|
33743
|
+
errorId,
|
|
33744
|
+
errorText,
|
|
33745
|
+
errorDetails
|
|
33746
|
+
}) {
|
|
33747
|
+
const errors = [];
|
|
33748
|
+
for (const server of servers) {
|
|
33749
|
+
try {
|
|
33750
|
+
await send(server);
|
|
33751
|
+
} catch (error51) {
|
|
33752
|
+
errors.push(error51);
|
|
33753
|
+
}
|
|
33754
|
+
}
|
|
33755
|
+
if (errors.length === 0) return;
|
|
33756
|
+
const mastraError = new error$1.MastraError(
|
|
33757
|
+
{
|
|
33758
|
+
id: errorId,
|
|
33759
|
+
domain: error$1.ErrorDomain.MCP,
|
|
33760
|
+
category: error$1.ErrorCategory.THIRD_PARTY,
|
|
33761
|
+
text: errorText,
|
|
33762
|
+
details: {
|
|
33763
|
+
...errorDetails,
|
|
33764
|
+
failedInstances: errors.length,
|
|
33765
|
+
totalInstances: servers.length
|
|
33766
|
+
}
|
|
33767
|
+
},
|
|
33768
|
+
errors[0]
|
|
33769
|
+
);
|
|
33770
|
+
logger.error(`${errorText}:`, { error: mastraError.toString() });
|
|
33771
|
+
if (errors.length === servers.length) {
|
|
33772
|
+
logger.trackException(mastraError);
|
|
33773
|
+
throw mastraError;
|
|
33774
|
+
}
|
|
33775
|
+
}
|
|
33776
|
+
|
|
33777
|
+
// src/server/promptActions.ts
|
|
33653
33778
|
var ServerPromptActions = class {
|
|
33654
33779
|
getLogger;
|
|
33655
|
-
|
|
33780
|
+
getSdkServers;
|
|
33656
33781
|
clearDefinedPrompts;
|
|
33657
33782
|
/**
|
|
33658
33783
|
* @internal
|
|
33659
33784
|
*/
|
|
33660
33785
|
constructor(dependencies) {
|
|
33661
33786
|
this.getLogger = dependencies.getLogger;
|
|
33662
|
-
this.
|
|
33787
|
+
this.getSdkServers = dependencies.getSdkServers;
|
|
33663
33788
|
this.clearDefinedPrompts = dependencies.clearDefinedPrompts;
|
|
33664
33789
|
}
|
|
33665
33790
|
/**
|
|
@@ -33668,7 +33793,7 @@ var ServerPromptActions = class {
|
|
|
33668
33793
|
* This clears the internal prompt cache and sends a `notifications/prompts/list_changed`
|
|
33669
33794
|
* message to all clients, prompting them to re-fetch the prompt list.
|
|
33670
33795
|
*
|
|
33671
|
-
* @throws {MastraError} If sending the notification fails
|
|
33796
|
+
* @throws {MastraError} If sending the notification fails on all server instances
|
|
33672
33797
|
*
|
|
33673
33798
|
* @example
|
|
33674
33799
|
* ```typescript
|
|
@@ -33679,47 +33804,39 @@ var ServerPromptActions = class {
|
|
|
33679
33804
|
async notifyListChanged() {
|
|
33680
33805
|
this.getLogger().info("Prompt list change externally notified. Clearing definedPrompts and sending notification.");
|
|
33681
33806
|
this.clearDefinedPrompts();
|
|
33682
|
-
|
|
33683
|
-
|
|
33684
|
-
|
|
33685
|
-
|
|
33686
|
-
|
|
33687
|
-
|
|
33688
|
-
|
|
33689
|
-
category: error$1.ErrorCategory.THIRD_PARTY,
|
|
33690
|
-
text: "Failed to send prompt list changed notification"
|
|
33691
|
-
},
|
|
33692
|
-
error51
|
|
33693
|
-
);
|
|
33694
|
-
this.getLogger().error("Failed to send prompt list changed notification:", {
|
|
33695
|
-
error: mastraError.toString()
|
|
33696
|
-
});
|
|
33697
|
-
this.getLogger().trackException(mastraError);
|
|
33698
|
-
throw mastraError;
|
|
33699
|
-
}
|
|
33807
|
+
await broadcastNotification({
|
|
33808
|
+
servers: this.getSdkServers(),
|
|
33809
|
+
send: (server) => server.sendPromptListChanged(),
|
|
33810
|
+
logger: this.getLogger(),
|
|
33811
|
+
errorId: "MCP_SERVER_PROMPT_LIST_CHANGED_NOTIFICATION_FAILED",
|
|
33812
|
+
errorText: "Failed to send prompt list changed notification"
|
|
33813
|
+
});
|
|
33700
33814
|
}
|
|
33701
33815
|
};
|
|
33816
|
+
|
|
33817
|
+
// src/server/resourceActions.ts
|
|
33702
33818
|
var ServerResourceActions = class {
|
|
33703
|
-
|
|
33819
|
+
getSubscribedServers;
|
|
33704
33820
|
getLogger;
|
|
33705
|
-
|
|
33821
|
+
getSdkServers;
|
|
33706
33822
|
/**
|
|
33707
33823
|
* @internal
|
|
33708
33824
|
*/
|
|
33709
33825
|
constructor(dependencies) {
|
|
33710
|
-
this.
|
|
33826
|
+
this.getSubscribedServers = dependencies.getSubscribedServers;
|
|
33711
33827
|
this.getLogger = dependencies.getLogger;
|
|
33712
|
-
this.
|
|
33828
|
+
this.getSdkServers = dependencies.getSdkServers;
|
|
33713
33829
|
}
|
|
33714
33830
|
/**
|
|
33715
33831
|
* Notifies subscribed clients that a specific resource has been updated.
|
|
33716
33832
|
*
|
|
33717
|
-
*
|
|
33718
|
-
* `notifications/resources/updated` message
|
|
33833
|
+
* Only clients that subscribed to the resource URI (via `resources/subscribe`)
|
|
33834
|
+
* receive a `notifications/resources/updated` message prompting them to
|
|
33835
|
+
* re-fetch the resource content.
|
|
33719
33836
|
*
|
|
33720
33837
|
* @param params - Notification parameters
|
|
33721
33838
|
* @param params.uri - URI of the resource that was updated
|
|
33722
|
-
* @throws {MastraError} If sending the notification fails
|
|
33839
|
+
* @throws {MastraError} If sending the notification fails on all subscribed server instances
|
|
33723
33840
|
*
|
|
33724
33841
|
* @example
|
|
33725
33842
|
* ```typescript
|
|
@@ -33728,32 +33845,20 @@ var ServerResourceActions = class {
|
|
|
33728
33845
|
* ```
|
|
33729
33846
|
*/
|
|
33730
33847
|
async notifyUpdated({ uri }) {
|
|
33731
|
-
|
|
33732
|
-
|
|
33733
|
-
try {
|
|
33734
|
-
await this.getSdkServer().sendResourceUpdated({ uri });
|
|
33735
|
-
} catch (error51) {
|
|
33736
|
-
const mastraError = new error$1.MastraError(
|
|
33737
|
-
{
|
|
33738
|
-
id: "MCP_SERVER_RESOURCE_UPDATED_NOTIFICATION_FAILED",
|
|
33739
|
-
domain: error$1.ErrorDomain.MCP,
|
|
33740
|
-
category: error$1.ErrorCategory.THIRD_PARTY,
|
|
33741
|
-
text: "Failed to send resource updated notification",
|
|
33742
|
-
details: {
|
|
33743
|
-
uri
|
|
33744
|
-
}
|
|
33745
|
-
},
|
|
33746
|
-
error51
|
|
33747
|
-
);
|
|
33748
|
-
this.getLogger().trackException(mastraError);
|
|
33749
|
-
this.getLogger().error("Failed to send resource updated notification:", {
|
|
33750
|
-
error: mastraError.toString()
|
|
33751
|
-
});
|
|
33752
|
-
throw mastraError;
|
|
33753
|
-
}
|
|
33754
|
-
} else {
|
|
33848
|
+
const subscribedServers = this.getSubscribedServers(uri);
|
|
33849
|
+
if (subscribedServers.length === 0) {
|
|
33755
33850
|
this.getLogger().debug(`Resource ${uri} was updated, but no active subscriptions for it.`);
|
|
33851
|
+
return;
|
|
33756
33852
|
}
|
|
33853
|
+
this.getLogger().info(`Sending notifications/resources/updated for externally notified resource: ${uri}`);
|
|
33854
|
+
await broadcastNotification({
|
|
33855
|
+
servers: subscribedServers,
|
|
33856
|
+
send: (server) => server.sendResourceUpdated({ uri }),
|
|
33857
|
+
logger: this.getLogger(),
|
|
33858
|
+
errorId: "MCP_SERVER_RESOURCE_UPDATED_NOTIFICATION_FAILED",
|
|
33859
|
+
errorText: "Failed to send resource updated notification",
|
|
33860
|
+
errorDetails: { uri }
|
|
33861
|
+
});
|
|
33757
33862
|
}
|
|
33758
33863
|
/**
|
|
33759
33864
|
* Notifies clients that the overall list of available resources has changed.
|
|
@@ -33762,7 +33867,7 @@ var ServerResourceActions = class {
|
|
|
33762
33867
|
* them to re-fetch the resource list. Resource lists and templates are always evaluated
|
|
33763
33868
|
* per request, so there is no server-side cache to clear.
|
|
33764
33869
|
*
|
|
33765
|
-
* @throws {MastraError} If sending the notification fails
|
|
33870
|
+
* @throws {MastraError} If sending the notification fails on all server instances
|
|
33766
33871
|
*
|
|
33767
33872
|
* @example
|
|
33768
33873
|
* ```typescript
|
|
@@ -33772,28 +33877,110 @@ var ServerResourceActions = class {
|
|
|
33772
33877
|
*/
|
|
33773
33878
|
async notifyListChanged() {
|
|
33774
33879
|
this.getLogger().info("Resource list change externally notified. Sending notification.");
|
|
33775
|
-
|
|
33776
|
-
|
|
33777
|
-
|
|
33778
|
-
|
|
33779
|
-
|
|
33780
|
-
|
|
33781
|
-
|
|
33782
|
-
|
|
33783
|
-
|
|
33784
|
-
|
|
33785
|
-
|
|
33786
|
-
|
|
33787
|
-
|
|
33788
|
-
|
|
33789
|
-
|
|
33790
|
-
|
|
33791
|
-
|
|
33880
|
+
await broadcastNotification({
|
|
33881
|
+
servers: this.getSdkServers(),
|
|
33882
|
+
send: (server) => server.sendResourceListChanged(),
|
|
33883
|
+
logger: this.getLogger(),
|
|
33884
|
+
errorId: "MCP_SERVER_RESOURCE_LIST_CHANGED_NOTIFICATION_FAILED",
|
|
33885
|
+
errorText: "Failed to send resource list changed notification"
|
|
33886
|
+
});
|
|
33887
|
+
}
|
|
33888
|
+
};
|
|
33889
|
+
|
|
33890
|
+
// src/server/toolActions.ts
|
|
33891
|
+
var ServerToolActions = class {
|
|
33892
|
+
getLogger;
|
|
33893
|
+
getSdkServers;
|
|
33894
|
+
addTools;
|
|
33895
|
+
removeTools;
|
|
33896
|
+
/**
|
|
33897
|
+
* @internal
|
|
33898
|
+
*/
|
|
33899
|
+
constructor(dependencies) {
|
|
33900
|
+
this.getLogger = dependencies.getLogger;
|
|
33901
|
+
this.getSdkServers = dependencies.getSdkServers;
|
|
33902
|
+
this.addTools = dependencies.addTools;
|
|
33903
|
+
this.removeTools = dependencies.removeTools;
|
|
33904
|
+
}
|
|
33905
|
+
/**
|
|
33906
|
+
* Registers new tools on the running server and notifies connected clients
|
|
33907
|
+
* that the tool list has changed.
|
|
33908
|
+
*
|
|
33909
|
+
* Tools are keyed by their record key, the same as tools passed to the
|
|
33910
|
+
* `MCPServer` constructor. Adding a tool under an existing key replaces it.
|
|
33911
|
+
*
|
|
33912
|
+
* @param tools - Tools to register
|
|
33913
|
+
* @throws {MastraError} If sending the notification fails on all server instances
|
|
33914
|
+
*
|
|
33915
|
+
* @example
|
|
33916
|
+
* ```typescript
|
|
33917
|
+
* await server.toolActions.add({ myNewTool });
|
|
33918
|
+
* ```
|
|
33919
|
+
*/
|
|
33920
|
+
async add(tools) {
|
|
33921
|
+
this.addTools(tools);
|
|
33922
|
+
await this.notifyListChanged();
|
|
33923
|
+
}
|
|
33924
|
+
/**
|
|
33925
|
+
* Removes tools from the running server and notifies connected clients that
|
|
33926
|
+
* the tool list has changed.
|
|
33927
|
+
*
|
|
33928
|
+
* Unknown tool IDs are ignored (logged as a warning). If no tools were
|
|
33929
|
+
* actually removed, no notification is sent.
|
|
33930
|
+
*
|
|
33931
|
+
* @param toolIds - IDs of the tools to remove
|
|
33932
|
+
* @throws {MastraError} If sending the notification fails on all server instances
|
|
33933
|
+
*
|
|
33934
|
+
* @example
|
|
33935
|
+
* ```typescript
|
|
33936
|
+
* await server.toolActions.remove(['myNewTool']);
|
|
33937
|
+
* ```
|
|
33938
|
+
*/
|
|
33939
|
+
async remove(toolIds) {
|
|
33940
|
+
const removed = this.removeTools(toolIds);
|
|
33941
|
+
if (removed.length === 0) {
|
|
33942
|
+
this.getLogger().debug("No tools were removed; skipping tool list changed notification.");
|
|
33943
|
+
return;
|
|
33792
33944
|
}
|
|
33945
|
+
await this.notifyListChanged();
|
|
33946
|
+
}
|
|
33947
|
+
/**
|
|
33948
|
+
* Notifies clients that the overall list of available tools has changed.
|
|
33949
|
+
*
|
|
33950
|
+
* This sends a `notifications/tools/list_changed` message to all clients,
|
|
33951
|
+
* prompting them to re-fetch the tool list.
|
|
33952
|
+
*
|
|
33953
|
+
* @throws {MastraError} If sending the notification fails on all server instances
|
|
33954
|
+
*
|
|
33955
|
+
* @example
|
|
33956
|
+
* ```typescript
|
|
33957
|
+
* // After changing which tools are available
|
|
33958
|
+
* await server.toolActions.notifyListChanged();
|
|
33959
|
+
* ```
|
|
33960
|
+
*/
|
|
33961
|
+
async notifyListChanged() {
|
|
33962
|
+
this.getLogger().info("Tool list changed. Sending notification.");
|
|
33963
|
+
await broadcastNotification({
|
|
33964
|
+
servers: this.getSdkServers(),
|
|
33965
|
+
send: (server) => server.sendToolListChanged(),
|
|
33966
|
+
logger: this.getLogger(),
|
|
33967
|
+
errorId: "MCP_SERVER_TOOL_LIST_CHANGED_NOTIFICATION_FAILED",
|
|
33968
|
+
errorText: "Failed to send tool list changed notification"
|
|
33969
|
+
});
|
|
33793
33970
|
}
|
|
33794
33971
|
};
|
|
33795
33972
|
|
|
33796
33973
|
// src/server/server.ts
|
|
33974
|
+
var LOG_LEVEL_SEVERITY = {
|
|
33975
|
+
debug: 0,
|
|
33976
|
+
info: 1,
|
|
33977
|
+
notice: 2,
|
|
33978
|
+
warning: 3,
|
|
33979
|
+
error: 4,
|
|
33980
|
+
critical: 5,
|
|
33981
|
+
alert: 6,
|
|
33982
|
+
emergency: 7
|
|
33983
|
+
};
|
|
33797
33984
|
var MCPServer = class extends mcp.MCPServerBase {
|
|
33798
33985
|
server;
|
|
33799
33986
|
stdioTransport;
|
|
@@ -33812,8 +33999,12 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
33812
33999
|
jsonSchemaValidator;
|
|
33813
34000
|
mapAuthInfoToUser;
|
|
33814
34001
|
fga;
|
|
33815
|
-
subscriptions
|
|
33816
|
-
|
|
34002
|
+
// Resource subscriptions per server instance (main + per HTTP session), set via
|
|
34003
|
+
// resources/subscribe. Note: legacy SSE sessions share the main instance, so they
|
|
34004
|
+
// share one subscription set; streamable HTTP sessions are isolated per session.
|
|
34005
|
+
subscriptionsByInstance = /* @__PURE__ */ new WeakMap();
|
|
34006
|
+
// Minimum logging level per server instance (main + per HTTP session), set via logging/setLevel
|
|
34007
|
+
loggingLevels = /* @__PURE__ */ new WeakMap();
|
|
33817
34008
|
/**
|
|
33818
34009
|
* Provides methods to notify clients about resource changes.
|
|
33819
34010
|
*
|
|
@@ -33837,6 +34028,24 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
33837
34028
|
* ```
|
|
33838
34029
|
*/
|
|
33839
34030
|
prompts;
|
|
34031
|
+
/**
|
|
34032
|
+
* Provides methods to dynamically manage tools and notify clients about
|
|
34033
|
+
* tool list changes. Named `toolActions` because `tools()` is the tool
|
|
34034
|
+
* registry getter inherited from `MCPServerBase`.
|
|
34035
|
+
*
|
|
34036
|
+
* @example
|
|
34037
|
+
* ```typescript
|
|
34038
|
+
* // Register a new tool at runtime and notify clients
|
|
34039
|
+
* await server.toolActions.add({ myNewTool });
|
|
34040
|
+
*
|
|
34041
|
+
* // Remove a tool and notify clients
|
|
34042
|
+
* await server.toolActions.remove(['myNewTool']);
|
|
34043
|
+
*
|
|
34044
|
+
* // Notify that the tool list changed (e.g. authorization changes)
|
|
34045
|
+
* await server.toolActions.notifyListChanged();
|
|
34046
|
+
* ```
|
|
34047
|
+
*/
|
|
34048
|
+
toolActions;
|
|
33840
34049
|
/**
|
|
33841
34050
|
* Provides methods for interactive user input collection during tool execution.
|
|
33842
34051
|
*
|
|
@@ -33954,7 +34163,7 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
33954
34163
|
this.mapAuthInfoToUser = opts.mapAuthInfoToUser;
|
|
33955
34164
|
this.fga = opts.fga;
|
|
33956
34165
|
const capabilities = {
|
|
33957
|
-
tools: {},
|
|
34166
|
+
tools: { listChanged: true },
|
|
33958
34167
|
logging: { enabled: true }
|
|
33959
34168
|
};
|
|
33960
34169
|
if (this.resourceOptions) {
|
|
@@ -33993,23 +34202,144 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
33993
34202
|
this.sseHonoTransports = /* @__PURE__ */ new Map();
|
|
33994
34203
|
this.registerHandlersOnServer(this.server);
|
|
33995
34204
|
this.resources = new ServerResourceActions({
|
|
33996
|
-
|
|
34205
|
+
getSubscribedServers: (uri) => this.getAllSdkServers().filter((server) => this.subscriptionsByInstance.get(server)?.has(uri)),
|
|
33997
34206
|
getLogger: () => this.logger,
|
|
33998
|
-
|
|
34207
|
+
getSdkServers: () => this.getAllSdkServers()
|
|
33999
34208
|
});
|
|
34000
34209
|
this.prompts = new ServerPromptActions({
|
|
34001
34210
|
getLogger: () => this.logger,
|
|
34002
|
-
|
|
34211
|
+
getSdkServers: () => this.getAllSdkServers(),
|
|
34003
34212
|
clearDefinedPrompts: () => {
|
|
34004
34213
|
this.definedPrompts = void 0;
|
|
34005
34214
|
}
|
|
34006
34215
|
});
|
|
34216
|
+
this.toolActions = new ServerToolActions({
|
|
34217
|
+
getLogger: () => this.logger,
|
|
34218
|
+
getSdkServers: () => this.getAllSdkServers(),
|
|
34219
|
+
addTools: (tools) => this.addTools(tools),
|
|
34220
|
+
removeTools: (toolIds) => this.removeTools(toolIds)
|
|
34221
|
+
});
|
|
34007
34222
|
this.elicitation = {
|
|
34008
34223
|
sendRequest: async (request, options) => {
|
|
34009
34224
|
return this.handleElicitationRequest(request, void 0, options);
|
|
34010
34225
|
}
|
|
34011
34226
|
};
|
|
34012
34227
|
}
|
|
34228
|
+
/**
|
|
34229
|
+
* Returns every connected SDK server instance: the main instance (stdio/SSE
|
|
34230
|
+
* transports) plus one instance per streamable HTTP session. Used to
|
|
34231
|
+
* broadcast notifications to all connected clients. Instances without a
|
|
34232
|
+
* connected transport are skipped.
|
|
34233
|
+
*
|
|
34234
|
+
* Note: stateless/serverless requests use transient server instances and
|
|
34235
|
+
* cannot receive notifications.
|
|
34236
|
+
*/
|
|
34237
|
+
getAllSdkServers() {
|
|
34238
|
+
return [this.server, ...this.httpServerInstances.values()].filter((server) => server.transport !== void 0);
|
|
34239
|
+
}
|
|
34240
|
+
/**
|
|
34241
|
+
* Determines whether a log message at the given level should be sent to the
|
|
34242
|
+
* client connected to the given server instance, honoring the minimum level
|
|
34243
|
+
* the client set via `logging/setLevel` (RFC 5424 severity ordering).
|
|
34244
|
+
* When the client never set a level, all messages are sent.
|
|
34245
|
+
*/
|
|
34246
|
+
shouldSendLog(serverInstance, level) {
|
|
34247
|
+
const minimumLevel = this.loggingLevels.get(serverInstance);
|
|
34248
|
+
if (minimumLevel === void 0) return true;
|
|
34249
|
+
return LOG_LEVEL_SEVERITY[level] >= LOG_LEVEL_SEVERITY[minimumLevel];
|
|
34250
|
+
}
|
|
34251
|
+
/**
|
|
34252
|
+
* Sends a `notifications/message` log notification to connected clients.
|
|
34253
|
+
*
|
|
34254
|
+
* The notification is broadcast to every active server instance, honoring
|
|
34255
|
+
* the minimum logging level each client set via `logging/setLevel`.
|
|
34256
|
+
*
|
|
34257
|
+
* @param params - Log message parameters
|
|
34258
|
+
* @param params.level - Log severity level
|
|
34259
|
+
* @param params.data - Arbitrary JSON-serializable data to log
|
|
34260
|
+
* @param params.logger - Optional logger name
|
|
34261
|
+
* @throws {MastraError} If sending the notification fails on all eligible server instances
|
|
34262
|
+
*
|
|
34263
|
+
* @example
|
|
34264
|
+
* ```typescript
|
|
34265
|
+
* await server.sendLoggingMessage({
|
|
34266
|
+
* level: 'info',
|
|
34267
|
+
* data: { message: 'Sync completed', itemsProcessed: 42 },
|
|
34268
|
+
* });
|
|
34269
|
+
* ```
|
|
34270
|
+
*/
|
|
34271
|
+
async sendLoggingMessage(params) {
|
|
34272
|
+
const eligibleServers = this.getAllSdkServers().filter((server) => this.shouldSendLog(server, params.level));
|
|
34273
|
+
if (eligibleServers.length === 0) {
|
|
34274
|
+
this.logger.debug("No eligible clients for log message; skipping.", { level: params.level });
|
|
34275
|
+
return;
|
|
34276
|
+
}
|
|
34277
|
+
await broadcastNotification({
|
|
34278
|
+
servers: eligibleServers,
|
|
34279
|
+
send: (server) => server.sendLoggingMessage(params),
|
|
34280
|
+
logger: this.logger,
|
|
34281
|
+
errorId: "MCP_SERVER_LOGGING_MESSAGE_NOTIFICATION_FAILED",
|
|
34282
|
+
errorText: "Failed to send logging message notification",
|
|
34283
|
+
errorDetails: { level: params.level }
|
|
34284
|
+
});
|
|
34285
|
+
}
|
|
34286
|
+
/**
|
|
34287
|
+
* Registers new tools on the running server. Tools are merged into both the
|
|
34288
|
+
* converted tool registry (used by list/call handlers) and the original
|
|
34289
|
+
* tools config so they survive tool re-conversion when the server is
|
|
34290
|
+
* registered with a Mastra instance.
|
|
34291
|
+
*/
|
|
34292
|
+
addTools(tools) {
|
|
34293
|
+
const converted = this.convertTools(tools);
|
|
34294
|
+
for (const key of Object.keys(converted)) {
|
|
34295
|
+
if (this.convertedTools[key]) {
|
|
34296
|
+
this.logger.warn(`Tool '${key}' already exists and will be replaced.`);
|
|
34297
|
+
}
|
|
34298
|
+
}
|
|
34299
|
+
this.convertedTools = { ...this.convertedTools, ...converted };
|
|
34300
|
+
this.originalTools = { ...this.originalTools, ...tools };
|
|
34301
|
+
if (this.mastra) {
|
|
34302
|
+
for (const [key, tool] of Object.entries(tools)) {
|
|
34303
|
+
if (tool && typeof tool === "object" && "id" in tool) {
|
|
34304
|
+
this.mastra.addTool(tool, this.mastraToolKey(key, tool));
|
|
34305
|
+
}
|
|
34306
|
+
}
|
|
34307
|
+
}
|
|
34308
|
+
}
|
|
34309
|
+
/**
|
|
34310
|
+
* Removes tools from the running server by tool ID.
|
|
34311
|
+
*
|
|
34312
|
+
* @returns The IDs of the tools that were actually removed
|
|
34313
|
+
*/
|
|
34314
|
+
removeTools(toolIds) {
|
|
34315
|
+
const removed = [];
|
|
34316
|
+
const convertedTools = { ...this.convertedTools };
|
|
34317
|
+
const originalTools = { ...this.originalTools };
|
|
34318
|
+
for (const toolId of toolIds) {
|
|
34319
|
+
if (convertedTools[toolId]) {
|
|
34320
|
+
const originalTool = originalTools[toolId];
|
|
34321
|
+
delete convertedTools[toolId];
|
|
34322
|
+
delete originalTools[toolId];
|
|
34323
|
+
removed.push(toolId);
|
|
34324
|
+
if (this.mastra && originalTool && typeof originalTool === "object" && "id" in originalTool) {
|
|
34325
|
+
this.mastra.removeTool(this.mastraToolKey(toolId, originalTool));
|
|
34326
|
+
}
|
|
34327
|
+
} else {
|
|
34328
|
+
this.logger.warn(`Cannot remove tool '${toolId}': tool not found.`);
|
|
34329
|
+
}
|
|
34330
|
+
}
|
|
34331
|
+
this.convertedTools = convertedTools;
|
|
34332
|
+
this.originalTools = originalTools;
|
|
34333
|
+
return removed;
|
|
34334
|
+
}
|
|
34335
|
+
/**
|
|
34336
|
+
* The key a tool is registered under in the Mastra instance's tool
|
|
34337
|
+
* registry: the tool's intrinsic ID when present (avoids collisions across
|
|
34338
|
+
* MCP servers), falling back to its record key. Mirrors __registerMastra.
|
|
34339
|
+
*/
|
|
34340
|
+
mastraToolKey(key, tool) {
|
|
34341
|
+
return "id" in tool && typeof tool.id === "string" ? tool.id : key;
|
|
34342
|
+
}
|
|
34013
34343
|
/**
|
|
34014
34344
|
* Handle an elicitation request by sending it to the connected client.
|
|
34015
34345
|
* This method sends an elicitation/create request to the client and waits for the response.
|
|
@@ -34142,7 +34472,7 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
34142
34472
|
*/
|
|
34143
34473
|
createServerInstance() {
|
|
34144
34474
|
const capabilities = {
|
|
34145
|
-
tools: {},
|
|
34475
|
+
tools: { listChanged: true },
|
|
34146
34476
|
logging: { enabled: true }
|
|
34147
34477
|
};
|
|
34148
34478
|
if (this.resourceOptions) {
|
|
@@ -34261,6 +34591,33 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
34261
34591
|
}
|
|
34262
34592
|
};
|
|
34263
34593
|
const proxiedContext = await this.createProxiedRequestContext(extra);
|
|
34594
|
+
const sessionLog = async (level, message, data) => {
|
|
34595
|
+
if (!this.shouldSendLog(serverInstance, level)) return;
|
|
34596
|
+
await extra.sendNotification({
|
|
34597
|
+
method: "notifications/message",
|
|
34598
|
+
params: {
|
|
34599
|
+
level,
|
|
34600
|
+
logger: this.name,
|
|
34601
|
+
data: { message, ...data }
|
|
34602
|
+
}
|
|
34603
|
+
});
|
|
34604
|
+
};
|
|
34605
|
+
const progressToken = extra._meta?.progressToken;
|
|
34606
|
+
const sessionProgress = async (params) => {
|
|
34607
|
+
if (progressToken === void 0) {
|
|
34608
|
+
this.logger.debug("Tool attempted to send progress but the caller sent no progressToken; skipping.", {
|
|
34609
|
+
tool: request.params.name
|
|
34610
|
+
});
|
|
34611
|
+
return;
|
|
34612
|
+
}
|
|
34613
|
+
await extra.sendNotification({
|
|
34614
|
+
method: "notifications/progress",
|
|
34615
|
+
params: {
|
|
34616
|
+
progressToken,
|
|
34617
|
+
...params
|
|
34618
|
+
}
|
|
34619
|
+
});
|
|
34620
|
+
};
|
|
34264
34621
|
const mcpOptions = {
|
|
34265
34622
|
messages: [],
|
|
34266
34623
|
toolCallId: "",
|
|
@@ -34268,7 +34625,9 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
34268
34625
|
// Pass MCP-specific context through the mcp property
|
|
34269
34626
|
mcp: {
|
|
34270
34627
|
elicitation: sessionElicitation,
|
|
34271
|
-
extra
|
|
34628
|
+
extra,
|
|
34629
|
+
log: sessionLog,
|
|
34630
|
+
progress: sessionProgress
|
|
34272
34631
|
},
|
|
34273
34632
|
// @ts-expect-error this is to let people know that the elicitation and extra keys are now nested under mcp.elicitation and mcp.extra in tool arguments
|
|
34274
34633
|
get elicitation() {
|
|
@@ -34356,7 +34715,7 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
34356
34715
|
}
|
|
34357
34716
|
});
|
|
34358
34717
|
serverInstance.setRequestHandler(types_js.SetLevelRequestSchema, async (request) => {
|
|
34359
|
-
this.
|
|
34718
|
+
this.loggingLevels.set(serverInstance, request.params.level);
|
|
34360
34719
|
this.logger.debug("Logging level set", { level: request.params.level });
|
|
34361
34720
|
return {};
|
|
34362
34721
|
});
|
|
@@ -34400,11 +34759,13 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
34400
34759
|
try {
|
|
34401
34760
|
const resourcesOrResourceContent = await capturedResourceOptions.getResourceContent({ uri, extra });
|
|
34402
34761
|
const resourcesContent = Array.isArray(resourcesOrResourceContent) ? resourcesOrResourceContent : [resourcesOrResourceContent];
|
|
34762
|
+
const resourceMeta = resource._meta ? { _meta: resource._meta } : {};
|
|
34403
34763
|
const contents = resourcesContent.map((resourceContent) => {
|
|
34404
34764
|
if ("text" in resourceContent && resourceContent.text !== void 0) {
|
|
34405
34765
|
return {
|
|
34406
34766
|
uri: resource.uri,
|
|
34407
34767
|
mimeType: resource.mimeType,
|
|
34768
|
+
...resourceMeta,
|
|
34408
34769
|
text: resourceContent.text
|
|
34409
34770
|
};
|
|
34410
34771
|
}
|
|
@@ -34415,6 +34776,7 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
34415
34776
|
return {
|
|
34416
34777
|
uri: resource.uri,
|
|
34417
34778
|
mimeType: resource.mimeType,
|
|
34779
|
+
...resourceMeta,
|
|
34418
34780
|
blob
|
|
34419
34781
|
};
|
|
34420
34782
|
});
|
|
@@ -34445,13 +34807,18 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
34445
34807
|
serverInstance.setRequestHandler(types_js.SubscribeRequestSchema, async (request) => {
|
|
34446
34808
|
const uri = request.params.uri;
|
|
34447
34809
|
this.logger.info("Received resources/subscribe request", { uri });
|
|
34448
|
-
this.
|
|
34810
|
+
let subscriptions = this.subscriptionsByInstance.get(serverInstance);
|
|
34811
|
+
if (!subscriptions) {
|
|
34812
|
+
subscriptions = /* @__PURE__ */ new Set();
|
|
34813
|
+
this.subscriptionsByInstance.set(serverInstance, subscriptions);
|
|
34814
|
+
}
|
|
34815
|
+
subscriptions.add(uri);
|
|
34449
34816
|
return {};
|
|
34450
34817
|
});
|
|
34451
34818
|
serverInstance.setRequestHandler(types_js.UnsubscribeRequestSchema, async (request) => {
|
|
34452
34819
|
const uri = request.params.uri;
|
|
34453
34820
|
this.logger.info("Received resources/unsubscribe request", { uri });
|
|
34454
|
-
this.
|
|
34821
|
+
this.subscriptionsByInstance.get(serverInstance)?.delete(uri);
|
|
34455
34822
|
return {};
|
|
34456
34823
|
});
|
|
34457
34824
|
}
|
|
@@ -35021,7 +35388,8 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
35021
35388
|
const isStatelessMode = options?.serverless || options && "sessionIdGenerator" in options && options.sessionIdGenerator === void 0;
|
|
35022
35389
|
if (isStatelessMode) {
|
|
35023
35390
|
this.logger.debug("Running in stateless mode");
|
|
35024
|
-
|
|
35391
|
+
const enableJsonResponse = options?.enableJsonResponse ?? !options?.serverlessStreaming;
|
|
35392
|
+
await this.handleServerlessRequest(req, res, { enableJsonResponse });
|
|
35025
35393
|
return;
|
|
35026
35394
|
}
|
|
35027
35395
|
const mergedOptions = {
|
|
@@ -35065,11 +35433,14 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
35065
35433
|
const { isInitializeRequest } = await import('@modelcontextprotocol/sdk/types.js');
|
|
35066
35434
|
if (isInitializeRequest(body)) {
|
|
35067
35435
|
this.logger.debug("Received initialize request, creating new transport");
|
|
35436
|
+
const sessionServerInstance = this.createServerInstance();
|
|
35068
35437
|
transport = new streamableHttp_js$1.StreamableHTTPServerTransport({
|
|
35069
35438
|
...mergedOptions,
|
|
35070
35439
|
sessionIdGenerator: mergedOptions.sessionIdGenerator,
|
|
35071
35440
|
onsessioninitialized: (id) => {
|
|
35072
35441
|
this.streamableHTTPTransports.set(id, transport);
|
|
35442
|
+
this.httpServerInstances.set(id, sessionServerInstance);
|
|
35443
|
+
this.logger.debug("Session initialized and stored", { sessionId: id });
|
|
35073
35444
|
}
|
|
35074
35445
|
});
|
|
35075
35446
|
transport.onclose = () => {
|
|
@@ -35083,15 +35454,7 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
35083
35454
|
}
|
|
35084
35455
|
}
|
|
35085
35456
|
};
|
|
35086
|
-
const sessionServerInstance = this.createServerInstance();
|
|
35087
35457
|
await sessionServerInstance.connect(transport);
|
|
35088
|
-
if (transport.sessionId) {
|
|
35089
|
-
this.streamableHTTPTransports.set(transport.sessionId, transport);
|
|
35090
|
-
this.httpServerInstances.set(transport.sessionId, sessionServerInstance);
|
|
35091
|
-
this.logger.debug("Session initialized and stored", { sessionId: transport.sessionId });
|
|
35092
|
-
} else {
|
|
35093
|
-
this.logger.warn("Transport initialized without a session ID");
|
|
35094
|
-
}
|
|
35095
35458
|
return await transport.handleRequest(req, res, body);
|
|
35096
35459
|
} else {
|
|
35097
35460
|
this.logger.warn("Received non-initialize POST request without session ID");
|
|
@@ -35162,21 +35525,26 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
35162
35525
|
*
|
|
35163
35526
|
* @param req - Incoming HTTP request
|
|
35164
35527
|
* @param res - HTTP response object
|
|
35528
|
+
* @param options - Transport options for this request
|
|
35529
|
+
* @param options.enableJsonResponse - When `true` (default), buffers and returns a single
|
|
35530
|
+
* JSON-RPC response. When `false`, the request is handled with request-scoped SSE streaming,
|
|
35531
|
+
* so in-request `notifications/progress` reach the client before the final result.
|
|
35165
35532
|
* @private
|
|
35166
35533
|
*/
|
|
35167
|
-
async handleServerlessRequest(req, res) {
|
|
35534
|
+
async handleServerlessRequest(req, res, { enableJsonResponse = true } = {}) {
|
|
35168
35535
|
try {
|
|
35169
35536
|
this.logger.debug("Received serverless request", { method: req.method });
|
|
35170
35537
|
const body = req.method === "POST" ? await this.readJsonBody(req) : void 0;
|
|
35171
35538
|
this.logger.debug("Processing serverless request", {
|
|
35172
35539
|
method: req.method,
|
|
35173
35540
|
bodyMethod: body?.method,
|
|
35174
|
-
id: body?.id
|
|
35541
|
+
id: body?.id,
|
|
35542
|
+
enableJsonResponse
|
|
35175
35543
|
});
|
|
35176
35544
|
const transientServer = this.createServerInstance();
|
|
35177
35545
|
const tempTransport = new streamableHttp_js$1.StreamableHTTPServerTransport({
|
|
35178
35546
|
sessionIdGenerator: void 0,
|
|
35179
|
-
enableJsonResponse
|
|
35547
|
+
enableJsonResponse
|
|
35180
35548
|
});
|
|
35181
35549
|
await transientServer.connect(tempTransport);
|
|
35182
35550
|
await tempTransport.handleRequest(req, res, body);
|