@mastra/mcp 1.13.1 → 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 +75 -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.js
CHANGED
|
@@ -8,7 +8,7 @@ import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
|
|
|
8
8
|
import { StdioClientTransport, getDefaultEnvironment } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
9
9
|
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
10
10
|
import { DEFAULT_REQUEST_TIMEOUT_MSEC } from '@modelcontextprotocol/sdk/shared/protocol.js';
|
|
11
|
-
import { LoggingMessageNotificationSchema, ListRootsRequestSchema, ListResourcesResultSchema, ReadResourceResultSchema, EmptyResultSchema, ListResourceTemplatesResultSchema, ListPromptsResultSchema, GetPromptResultSchema, PromptListChangedNotificationSchema, ResourceUpdatedNotificationSchema, ResourceListChangedNotificationSchema, ElicitRequestSchema, ProgressNotificationSchema, ListToolsRequestSchema, CallToolRequestSchema, SetLevelRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, McpError, ErrorCode, ListResourceTemplatesRequestSchema, SubscribeRequestSchema, UnsubscribeRequestSchema, ListPromptsRequestSchema, PromptSchema, GetPromptRequestSchema, CallToolResultSchema, JSONRPCMessageSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
11
|
+
import { LoggingMessageNotificationSchema, ListRootsRequestSchema, ListResourcesResultSchema, ReadResourceResultSchema, EmptyResultSchema, ListResourceTemplatesResultSchema, ListPromptsResultSchema, GetPromptResultSchema, PromptListChangedNotificationSchema, ToolListChangedNotificationSchema, ResourceUpdatedNotificationSchema, ResourceListChangedNotificationSchema, ElicitRequestSchema, ProgressNotificationSchema, ListToolsRequestSchema, CallToolRequestSchema, SetLevelRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, McpError, ErrorCode, ListResourceTemplatesRequestSchema, SubscribeRequestSchema, UnsubscribeRequestSchema, ListPromptsRequestSchema, PromptSchema, GetPromptRequestSchema, CallToolResultSchema, JSONRPCMessageSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
12
12
|
import { asyncExitHook, gracefulExit } from 'exit-hook';
|
|
13
13
|
import { createHash, randomUUID } from 'crypto';
|
|
14
14
|
import equal from 'fast-deep-equal';
|
|
@@ -31484,6 +31484,7 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
31484
31484
|
sigHupHandler;
|
|
31485
31485
|
serverInstructions;
|
|
31486
31486
|
_roots;
|
|
31487
|
+
hasElicitationCapability;
|
|
31487
31488
|
requireToolApproval;
|
|
31488
31489
|
onToolError;
|
|
31489
31490
|
/** Provides access to resource operations (list, read, subscribe, etc.) */
|
|
@@ -31514,13 +31515,13 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
31514
31515
|
this.requireToolApproval = server.requireToolApproval;
|
|
31515
31516
|
this.onToolError = server.onToolError ?? "throw";
|
|
31516
31517
|
this._roots = server.roots ?? [];
|
|
31518
|
+
this.hasElicitationCapability = capabilities.elicitation !== void 0;
|
|
31517
31519
|
const hasRoots = this._roots.length > 0 || !!capabilities.roots;
|
|
31518
31520
|
const clientCapabilities = {
|
|
31519
31521
|
...capabilities,
|
|
31520
|
-
//
|
|
31521
|
-
elicitation: {
|
|
31522
|
-
|
|
31523
|
-
},
|
|
31522
|
+
// Only advertise elicitation when explicitly configured or when a handler
|
|
31523
|
+
// registers it before connect(). `elicitation: {}` is legacy form support.
|
|
31524
|
+
...capabilities.elicitation !== void 0 ? { elicitation: { ...capabilities.elicitation } } : {},
|
|
31524
31525
|
// Auto-enable roots capability if roots are provided
|
|
31525
31526
|
...hasRoots ? { roots: { listChanged: true, ...capabilities.roots ?? {} } } : {},
|
|
31526
31527
|
// Advertise MCP Apps extension support so servers know we can render UI resources
|
|
@@ -31935,6 +31936,16 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
31935
31936
|
handler();
|
|
31936
31937
|
});
|
|
31937
31938
|
}
|
|
31939
|
+
/**
|
|
31940
|
+
* Register a handler to be called when the tool list changes on the server.
|
|
31941
|
+
* Use this to re-fetch tools via `tools()` when notified.
|
|
31942
|
+
*/
|
|
31943
|
+
setToolListChangedNotificationHandler(handler) {
|
|
31944
|
+
this.log("debug", "Setting tool list changed notification handler");
|
|
31945
|
+
this.client.setNotificationHandler(ToolListChangedNotificationSchema, () => {
|
|
31946
|
+
handler();
|
|
31947
|
+
});
|
|
31948
|
+
}
|
|
31938
31949
|
setResourceUpdatedNotificationHandler(handler) {
|
|
31939
31950
|
this.log("debug", "Setting resource updated notification handler");
|
|
31940
31951
|
this.client.setNotificationHandler(ResourceUpdatedNotificationSchema, (notification) => {
|
|
@@ -31949,6 +31960,17 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
31949
31960
|
}
|
|
31950
31961
|
setElicitationRequestHandler(handler) {
|
|
31951
31962
|
this.log("debug", "Setting elicitation request handler");
|
|
31963
|
+
if (!this.hasElicitationCapability) {
|
|
31964
|
+
try {
|
|
31965
|
+
this.client.registerCapabilities({ elicitation: { form: {} } });
|
|
31966
|
+
this.hasElicitationCapability = true;
|
|
31967
|
+
} catch (error51) {
|
|
31968
|
+
throw new Error(
|
|
31969
|
+
"Cannot register an elicitation handler after connecting unless elicitation capability was configured before initialization.",
|
|
31970
|
+
{ cause: error51 }
|
|
31971
|
+
);
|
|
31972
|
+
}
|
|
31973
|
+
}
|
|
31952
31974
|
this.client.setRequestHandler(ElicitRequestSchema, async (request) => {
|
|
31953
31975
|
this.log("debug", `Received elicitation request: ${request.params.message}`);
|
|
31954
31976
|
return handler(request.params);
|
|
@@ -32411,7 +32433,7 @@ To fix this you have three different options:
|
|
|
32411
32433
|
*/
|
|
32412
32434
|
onRequest: async (serverName, handler) => {
|
|
32413
32435
|
try {
|
|
32414
|
-
const internalClient = await this.
|
|
32436
|
+
const internalClient = await this.getClientForServer(serverName);
|
|
32415
32437
|
return internalClient.elicitation.onRequest(handler);
|
|
32416
32438
|
} catch (err) {
|
|
32417
32439
|
throw new MastraError(
|
|
@@ -32836,6 +32858,58 @@ To fix this you have three different options:
|
|
|
32836
32858
|
}
|
|
32837
32859
|
};
|
|
32838
32860
|
}
|
|
32861
|
+
/**
|
|
32862
|
+
* Provides access to tool-related notification operations across all configured servers.
|
|
32863
|
+
*
|
|
32864
|
+
* To fetch tools, use `listTools()` or `listToolsets()`.
|
|
32865
|
+
*
|
|
32866
|
+
* @example
|
|
32867
|
+
* ```typescript
|
|
32868
|
+
* // React to tool list changes on a server
|
|
32869
|
+
* await mcp.tools.onListChanged('weatherServer', async () => {
|
|
32870
|
+
* console.log('Tool list changed, re-fetching...');
|
|
32871
|
+
* const tools = await mcp.listTools();
|
|
32872
|
+
* });
|
|
32873
|
+
* ```
|
|
32874
|
+
*/
|
|
32875
|
+
get tools() {
|
|
32876
|
+
this.addToInstanceCache();
|
|
32877
|
+
return {
|
|
32878
|
+
/**
|
|
32879
|
+
* Sets a notification handler for when the tool list changes on a server.
|
|
32880
|
+
*
|
|
32881
|
+
* @param serverName - Name of the server to monitor
|
|
32882
|
+
* @param handler - Callback function invoked when tools are added/removed/modified
|
|
32883
|
+
* @returns Promise resolving when handler is registered
|
|
32884
|
+
* @throws {MastraError} If setting up the handler fails
|
|
32885
|
+
*
|
|
32886
|
+
* @example
|
|
32887
|
+
* ```typescript
|
|
32888
|
+
* await mcp.tools.onListChanged('weatherServer', async () => {
|
|
32889
|
+
* const tools = await mcp.listTools();
|
|
32890
|
+
* });
|
|
32891
|
+
* ```
|
|
32892
|
+
*/
|
|
32893
|
+
onListChanged: async (serverName, handler) => {
|
|
32894
|
+
try {
|
|
32895
|
+
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
32896
|
+
return internalClient.setToolListChangedNotificationHandler(handler);
|
|
32897
|
+
} catch (error51) {
|
|
32898
|
+
throw new MastraError(
|
|
32899
|
+
{
|
|
32900
|
+
id: "MCP_CLIENT_ON_LIST_CHANGED_TOOLS_FAILED",
|
|
32901
|
+
domain: ErrorDomain.MCP,
|
|
32902
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
32903
|
+
details: {
|
|
32904
|
+
serverName
|
|
32905
|
+
}
|
|
32906
|
+
},
|
|
32907
|
+
error51
|
|
32908
|
+
);
|
|
32909
|
+
}
|
|
32910
|
+
}
|
|
32911
|
+
};
|
|
32912
|
+
}
|
|
32839
32913
|
addToInstanceCache() {
|
|
32840
32914
|
if (!mcpClientInstances.has(this.id)) {
|
|
32841
32915
|
mcpClientInstances.set(this.id, this);
|
|
@@ -33127,7 +33201,14 @@ To fix this you have three different options:
|
|
|
33127
33201
|
if (!client) return null;
|
|
33128
33202
|
return client.stderr;
|
|
33129
33203
|
}
|
|
33130
|
-
|
|
33204
|
+
getServerConfig(serverName) {
|
|
33205
|
+
const serverConfig = this.serverConfigs[serverName];
|
|
33206
|
+
if (!serverConfig) {
|
|
33207
|
+
throw new Error(`Server configuration not found for name: ${serverName}`);
|
|
33208
|
+
}
|
|
33209
|
+
return serverConfig;
|
|
33210
|
+
}
|
|
33211
|
+
async getOrCreateClient(name, config2) {
|
|
33131
33212
|
if (this.disconnectPromise) {
|
|
33132
33213
|
await this.disconnectPromise;
|
|
33133
33214
|
}
|
|
@@ -33138,10 +33219,8 @@ To fix this you have three different options:
|
|
|
33138
33219
|
if (!existingClient) {
|
|
33139
33220
|
throw new Error(`Client ${name} exists but is undefined`);
|
|
33140
33221
|
}
|
|
33141
|
-
await existingClient.connect();
|
|
33142
33222
|
return existingClient;
|
|
33143
33223
|
}
|
|
33144
|
-
this.logger.debug("Connecting to MCP server", { name });
|
|
33145
33224
|
const mcpClient = new InternalMastraMCPClient({
|
|
33146
33225
|
name,
|
|
33147
33226
|
server: config2,
|
|
@@ -33150,35 +33229,42 @@ To fix this you have three different options:
|
|
|
33150
33229
|
});
|
|
33151
33230
|
mcpClient.__setLogger(this.logger);
|
|
33152
33231
|
this.mcpClientsById.set(name, mcpClient);
|
|
33232
|
+
return mcpClient;
|
|
33233
|
+
}
|
|
33234
|
+
async getConnectedClient(name, config2) {
|
|
33235
|
+
this.logger.debug("Connecting to MCP server", { name });
|
|
33236
|
+
const mcpClient = await this.getOrCreateClient(name, config2);
|
|
33153
33237
|
try {
|
|
33154
33238
|
await mcpClient.connect();
|
|
33155
33239
|
} catch (e) {
|
|
33156
|
-
|
|
33157
|
-
{
|
|
33158
|
-
id: "MCP_CLIENT_CONNECT_FAILED",
|
|
33159
|
-
domain: ErrorDomain.MCP,
|
|
33160
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
33161
|
-
text: `Failed to connect to MCP server ${name}: ${e instanceof Error ? e.stack || e.message : String(e)}`,
|
|
33162
|
-
details: {
|
|
33163
|
-
name
|
|
33164
|
-
}
|
|
33165
|
-
},
|
|
33166
|
-
e
|
|
33167
|
-
);
|
|
33168
|
-
this.logger.trackException(mastraError);
|
|
33169
|
-
this.logger.error("MCPClient errored connecting to MCP server:", { error: mastraError.toString() });
|
|
33170
|
-
this.mcpClientsById.delete(name);
|
|
33171
|
-
throw mastraError;
|
|
33240
|
+
throw this.handleConnectError(name, e);
|
|
33172
33241
|
}
|
|
33173
33242
|
this.logger.debug("Connected to MCP server", { name });
|
|
33174
33243
|
return mcpClient;
|
|
33175
33244
|
}
|
|
33245
|
+
handleConnectError(name, error51) {
|
|
33246
|
+
const mastraError = new MastraError(
|
|
33247
|
+
{
|
|
33248
|
+
id: "MCP_CLIENT_CONNECT_FAILED",
|
|
33249
|
+
domain: ErrorDomain.MCP,
|
|
33250
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
33251
|
+
text: `Failed to connect to MCP server ${name}: ${error51 instanceof Error ? error51.stack || error51.message : String(error51)}`,
|
|
33252
|
+
details: {
|
|
33253
|
+
name
|
|
33254
|
+
}
|
|
33255
|
+
},
|
|
33256
|
+
error51
|
|
33257
|
+
);
|
|
33258
|
+
this.logger.trackException(mastraError);
|
|
33259
|
+
this.logger.error("MCPClient errored connecting to MCP server:", { error: mastraError.toString() });
|
|
33260
|
+
this.mcpClientsById.delete(name);
|
|
33261
|
+
return mastraError;
|
|
33262
|
+
}
|
|
33176
33263
|
async getConnectedClientForServer(serverName) {
|
|
33177
|
-
|
|
33178
|
-
|
|
33179
|
-
|
|
33180
|
-
|
|
33181
|
-
return this.getConnectedClient(serverName, serverConfig);
|
|
33264
|
+
return this.getConnectedClient(serverName, this.getServerConfig(serverName));
|
|
33265
|
+
}
|
|
33266
|
+
async getClientForServer(serverName) {
|
|
33267
|
+
return this.getOrCreateClient(serverName, this.getServerConfig(serverName));
|
|
33182
33268
|
}
|
|
33183
33269
|
async getToolsForServer(serverName) {
|
|
33184
33270
|
for (let attempt = 1; attempt <= TOOL_DISCOVERY_MAX_ATTEMPTS; attempt++) {
|
|
@@ -33643,16 +33729,55 @@ var SSETransport = class {
|
|
|
33643
33729
|
});
|
|
33644
33730
|
}
|
|
33645
33731
|
};
|
|
33732
|
+
async function broadcastNotification({
|
|
33733
|
+
servers,
|
|
33734
|
+
send,
|
|
33735
|
+
logger,
|
|
33736
|
+
errorId,
|
|
33737
|
+
errorText,
|
|
33738
|
+
errorDetails
|
|
33739
|
+
}) {
|
|
33740
|
+
const errors = [];
|
|
33741
|
+
for (const server of servers) {
|
|
33742
|
+
try {
|
|
33743
|
+
await send(server);
|
|
33744
|
+
} catch (error51) {
|
|
33745
|
+
errors.push(error51);
|
|
33746
|
+
}
|
|
33747
|
+
}
|
|
33748
|
+
if (errors.length === 0) return;
|
|
33749
|
+
const mastraError = new MastraError(
|
|
33750
|
+
{
|
|
33751
|
+
id: errorId,
|
|
33752
|
+
domain: ErrorDomain.MCP,
|
|
33753
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
33754
|
+
text: errorText,
|
|
33755
|
+
details: {
|
|
33756
|
+
...errorDetails,
|
|
33757
|
+
failedInstances: errors.length,
|
|
33758
|
+
totalInstances: servers.length
|
|
33759
|
+
}
|
|
33760
|
+
},
|
|
33761
|
+
errors[0]
|
|
33762
|
+
);
|
|
33763
|
+
logger.error(`${errorText}:`, { error: mastraError.toString() });
|
|
33764
|
+
if (errors.length === servers.length) {
|
|
33765
|
+
logger.trackException(mastraError);
|
|
33766
|
+
throw mastraError;
|
|
33767
|
+
}
|
|
33768
|
+
}
|
|
33769
|
+
|
|
33770
|
+
// src/server/promptActions.ts
|
|
33646
33771
|
var ServerPromptActions = class {
|
|
33647
33772
|
getLogger;
|
|
33648
|
-
|
|
33773
|
+
getSdkServers;
|
|
33649
33774
|
clearDefinedPrompts;
|
|
33650
33775
|
/**
|
|
33651
33776
|
* @internal
|
|
33652
33777
|
*/
|
|
33653
33778
|
constructor(dependencies) {
|
|
33654
33779
|
this.getLogger = dependencies.getLogger;
|
|
33655
|
-
this.
|
|
33780
|
+
this.getSdkServers = dependencies.getSdkServers;
|
|
33656
33781
|
this.clearDefinedPrompts = dependencies.clearDefinedPrompts;
|
|
33657
33782
|
}
|
|
33658
33783
|
/**
|
|
@@ -33661,7 +33786,7 @@ var ServerPromptActions = class {
|
|
|
33661
33786
|
* This clears the internal prompt cache and sends a `notifications/prompts/list_changed`
|
|
33662
33787
|
* message to all clients, prompting them to re-fetch the prompt list.
|
|
33663
33788
|
*
|
|
33664
|
-
* @throws {MastraError} If sending the notification fails
|
|
33789
|
+
* @throws {MastraError} If sending the notification fails on all server instances
|
|
33665
33790
|
*
|
|
33666
33791
|
* @example
|
|
33667
33792
|
* ```typescript
|
|
@@ -33672,47 +33797,39 @@ var ServerPromptActions = class {
|
|
|
33672
33797
|
async notifyListChanged() {
|
|
33673
33798
|
this.getLogger().info("Prompt list change externally notified. Clearing definedPrompts and sending notification.");
|
|
33674
33799
|
this.clearDefinedPrompts();
|
|
33675
|
-
|
|
33676
|
-
|
|
33677
|
-
|
|
33678
|
-
|
|
33679
|
-
|
|
33680
|
-
|
|
33681
|
-
|
|
33682
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
33683
|
-
text: "Failed to send prompt list changed notification"
|
|
33684
|
-
},
|
|
33685
|
-
error51
|
|
33686
|
-
);
|
|
33687
|
-
this.getLogger().error("Failed to send prompt list changed notification:", {
|
|
33688
|
-
error: mastraError.toString()
|
|
33689
|
-
});
|
|
33690
|
-
this.getLogger().trackException(mastraError);
|
|
33691
|
-
throw mastraError;
|
|
33692
|
-
}
|
|
33800
|
+
await broadcastNotification({
|
|
33801
|
+
servers: this.getSdkServers(),
|
|
33802
|
+
send: (server) => server.sendPromptListChanged(),
|
|
33803
|
+
logger: this.getLogger(),
|
|
33804
|
+
errorId: "MCP_SERVER_PROMPT_LIST_CHANGED_NOTIFICATION_FAILED",
|
|
33805
|
+
errorText: "Failed to send prompt list changed notification"
|
|
33806
|
+
});
|
|
33693
33807
|
}
|
|
33694
33808
|
};
|
|
33809
|
+
|
|
33810
|
+
// src/server/resourceActions.ts
|
|
33695
33811
|
var ServerResourceActions = class {
|
|
33696
|
-
|
|
33812
|
+
getSubscribedServers;
|
|
33697
33813
|
getLogger;
|
|
33698
|
-
|
|
33814
|
+
getSdkServers;
|
|
33699
33815
|
/**
|
|
33700
33816
|
* @internal
|
|
33701
33817
|
*/
|
|
33702
33818
|
constructor(dependencies) {
|
|
33703
|
-
this.
|
|
33819
|
+
this.getSubscribedServers = dependencies.getSubscribedServers;
|
|
33704
33820
|
this.getLogger = dependencies.getLogger;
|
|
33705
|
-
this.
|
|
33821
|
+
this.getSdkServers = dependencies.getSdkServers;
|
|
33706
33822
|
}
|
|
33707
33823
|
/**
|
|
33708
33824
|
* Notifies subscribed clients that a specific resource has been updated.
|
|
33709
33825
|
*
|
|
33710
|
-
*
|
|
33711
|
-
* `notifications/resources/updated` message
|
|
33826
|
+
* Only clients that subscribed to the resource URI (via `resources/subscribe`)
|
|
33827
|
+
* receive a `notifications/resources/updated` message prompting them to
|
|
33828
|
+
* re-fetch the resource content.
|
|
33712
33829
|
*
|
|
33713
33830
|
* @param params - Notification parameters
|
|
33714
33831
|
* @param params.uri - URI of the resource that was updated
|
|
33715
|
-
* @throws {MastraError} If sending the notification fails
|
|
33832
|
+
* @throws {MastraError} If sending the notification fails on all subscribed server instances
|
|
33716
33833
|
*
|
|
33717
33834
|
* @example
|
|
33718
33835
|
* ```typescript
|
|
@@ -33721,32 +33838,20 @@ var ServerResourceActions = class {
|
|
|
33721
33838
|
* ```
|
|
33722
33839
|
*/
|
|
33723
33840
|
async notifyUpdated({ uri }) {
|
|
33724
|
-
|
|
33725
|
-
|
|
33726
|
-
try {
|
|
33727
|
-
await this.getSdkServer().sendResourceUpdated({ uri });
|
|
33728
|
-
} catch (error51) {
|
|
33729
|
-
const mastraError = new MastraError(
|
|
33730
|
-
{
|
|
33731
|
-
id: "MCP_SERVER_RESOURCE_UPDATED_NOTIFICATION_FAILED",
|
|
33732
|
-
domain: ErrorDomain.MCP,
|
|
33733
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
33734
|
-
text: "Failed to send resource updated notification",
|
|
33735
|
-
details: {
|
|
33736
|
-
uri
|
|
33737
|
-
}
|
|
33738
|
-
},
|
|
33739
|
-
error51
|
|
33740
|
-
);
|
|
33741
|
-
this.getLogger().trackException(mastraError);
|
|
33742
|
-
this.getLogger().error("Failed to send resource updated notification:", {
|
|
33743
|
-
error: mastraError.toString()
|
|
33744
|
-
});
|
|
33745
|
-
throw mastraError;
|
|
33746
|
-
}
|
|
33747
|
-
} else {
|
|
33841
|
+
const subscribedServers = this.getSubscribedServers(uri);
|
|
33842
|
+
if (subscribedServers.length === 0) {
|
|
33748
33843
|
this.getLogger().debug(`Resource ${uri} was updated, but no active subscriptions for it.`);
|
|
33844
|
+
return;
|
|
33749
33845
|
}
|
|
33846
|
+
this.getLogger().info(`Sending notifications/resources/updated for externally notified resource: ${uri}`);
|
|
33847
|
+
await broadcastNotification({
|
|
33848
|
+
servers: subscribedServers,
|
|
33849
|
+
send: (server) => server.sendResourceUpdated({ uri }),
|
|
33850
|
+
logger: this.getLogger(),
|
|
33851
|
+
errorId: "MCP_SERVER_RESOURCE_UPDATED_NOTIFICATION_FAILED",
|
|
33852
|
+
errorText: "Failed to send resource updated notification",
|
|
33853
|
+
errorDetails: { uri }
|
|
33854
|
+
});
|
|
33750
33855
|
}
|
|
33751
33856
|
/**
|
|
33752
33857
|
* Notifies clients that the overall list of available resources has changed.
|
|
@@ -33755,7 +33860,7 @@ var ServerResourceActions = class {
|
|
|
33755
33860
|
* them to re-fetch the resource list. Resource lists and templates are always evaluated
|
|
33756
33861
|
* per request, so there is no server-side cache to clear.
|
|
33757
33862
|
*
|
|
33758
|
-
* @throws {MastraError} If sending the notification fails
|
|
33863
|
+
* @throws {MastraError} If sending the notification fails on all server instances
|
|
33759
33864
|
*
|
|
33760
33865
|
* @example
|
|
33761
33866
|
* ```typescript
|
|
@@ -33765,28 +33870,110 @@ var ServerResourceActions = class {
|
|
|
33765
33870
|
*/
|
|
33766
33871
|
async notifyListChanged() {
|
|
33767
33872
|
this.getLogger().info("Resource list change externally notified. Sending notification.");
|
|
33768
|
-
|
|
33769
|
-
|
|
33770
|
-
|
|
33771
|
-
|
|
33772
|
-
|
|
33773
|
-
|
|
33774
|
-
|
|
33775
|
-
|
|
33776
|
-
|
|
33777
|
-
|
|
33778
|
-
|
|
33779
|
-
|
|
33780
|
-
|
|
33781
|
-
|
|
33782
|
-
|
|
33783
|
-
|
|
33784
|
-
|
|
33873
|
+
await broadcastNotification({
|
|
33874
|
+
servers: this.getSdkServers(),
|
|
33875
|
+
send: (server) => server.sendResourceListChanged(),
|
|
33876
|
+
logger: this.getLogger(),
|
|
33877
|
+
errorId: "MCP_SERVER_RESOURCE_LIST_CHANGED_NOTIFICATION_FAILED",
|
|
33878
|
+
errorText: "Failed to send resource list changed notification"
|
|
33879
|
+
});
|
|
33880
|
+
}
|
|
33881
|
+
};
|
|
33882
|
+
|
|
33883
|
+
// src/server/toolActions.ts
|
|
33884
|
+
var ServerToolActions = class {
|
|
33885
|
+
getLogger;
|
|
33886
|
+
getSdkServers;
|
|
33887
|
+
addTools;
|
|
33888
|
+
removeTools;
|
|
33889
|
+
/**
|
|
33890
|
+
* @internal
|
|
33891
|
+
*/
|
|
33892
|
+
constructor(dependencies) {
|
|
33893
|
+
this.getLogger = dependencies.getLogger;
|
|
33894
|
+
this.getSdkServers = dependencies.getSdkServers;
|
|
33895
|
+
this.addTools = dependencies.addTools;
|
|
33896
|
+
this.removeTools = dependencies.removeTools;
|
|
33897
|
+
}
|
|
33898
|
+
/**
|
|
33899
|
+
* Registers new tools on the running server and notifies connected clients
|
|
33900
|
+
* that the tool list has changed.
|
|
33901
|
+
*
|
|
33902
|
+
* Tools are keyed by their record key, the same as tools passed to the
|
|
33903
|
+
* `MCPServer` constructor. Adding a tool under an existing key replaces it.
|
|
33904
|
+
*
|
|
33905
|
+
* @param tools - Tools to register
|
|
33906
|
+
* @throws {MastraError} If sending the notification fails on all server instances
|
|
33907
|
+
*
|
|
33908
|
+
* @example
|
|
33909
|
+
* ```typescript
|
|
33910
|
+
* await server.toolActions.add({ myNewTool });
|
|
33911
|
+
* ```
|
|
33912
|
+
*/
|
|
33913
|
+
async add(tools) {
|
|
33914
|
+
this.addTools(tools);
|
|
33915
|
+
await this.notifyListChanged();
|
|
33916
|
+
}
|
|
33917
|
+
/**
|
|
33918
|
+
* Removes tools from the running server and notifies connected clients that
|
|
33919
|
+
* the tool list has changed.
|
|
33920
|
+
*
|
|
33921
|
+
* Unknown tool IDs are ignored (logged as a warning). If no tools were
|
|
33922
|
+
* actually removed, no notification is sent.
|
|
33923
|
+
*
|
|
33924
|
+
* @param toolIds - IDs of the tools to remove
|
|
33925
|
+
* @throws {MastraError} If sending the notification fails on all server instances
|
|
33926
|
+
*
|
|
33927
|
+
* @example
|
|
33928
|
+
* ```typescript
|
|
33929
|
+
* await server.toolActions.remove(['myNewTool']);
|
|
33930
|
+
* ```
|
|
33931
|
+
*/
|
|
33932
|
+
async remove(toolIds) {
|
|
33933
|
+
const removed = this.removeTools(toolIds);
|
|
33934
|
+
if (removed.length === 0) {
|
|
33935
|
+
this.getLogger().debug("No tools were removed; skipping tool list changed notification.");
|
|
33936
|
+
return;
|
|
33785
33937
|
}
|
|
33938
|
+
await this.notifyListChanged();
|
|
33939
|
+
}
|
|
33940
|
+
/**
|
|
33941
|
+
* Notifies clients that the overall list of available tools has changed.
|
|
33942
|
+
*
|
|
33943
|
+
* This sends a `notifications/tools/list_changed` message to all clients,
|
|
33944
|
+
* prompting them to re-fetch the tool list.
|
|
33945
|
+
*
|
|
33946
|
+
* @throws {MastraError} If sending the notification fails on all server instances
|
|
33947
|
+
*
|
|
33948
|
+
* @example
|
|
33949
|
+
* ```typescript
|
|
33950
|
+
* // After changing which tools are available
|
|
33951
|
+
* await server.toolActions.notifyListChanged();
|
|
33952
|
+
* ```
|
|
33953
|
+
*/
|
|
33954
|
+
async notifyListChanged() {
|
|
33955
|
+
this.getLogger().info("Tool list changed. Sending notification.");
|
|
33956
|
+
await broadcastNotification({
|
|
33957
|
+
servers: this.getSdkServers(),
|
|
33958
|
+
send: (server) => server.sendToolListChanged(),
|
|
33959
|
+
logger: this.getLogger(),
|
|
33960
|
+
errorId: "MCP_SERVER_TOOL_LIST_CHANGED_NOTIFICATION_FAILED",
|
|
33961
|
+
errorText: "Failed to send tool list changed notification"
|
|
33962
|
+
});
|
|
33786
33963
|
}
|
|
33787
33964
|
};
|
|
33788
33965
|
|
|
33789
33966
|
// src/server/server.ts
|
|
33967
|
+
var LOG_LEVEL_SEVERITY = {
|
|
33968
|
+
debug: 0,
|
|
33969
|
+
info: 1,
|
|
33970
|
+
notice: 2,
|
|
33971
|
+
warning: 3,
|
|
33972
|
+
error: 4,
|
|
33973
|
+
critical: 5,
|
|
33974
|
+
alert: 6,
|
|
33975
|
+
emergency: 7
|
|
33976
|
+
};
|
|
33790
33977
|
var MCPServer = class extends MCPServerBase {
|
|
33791
33978
|
server;
|
|
33792
33979
|
stdioTransport;
|
|
@@ -33805,8 +33992,12 @@ var MCPServer = class extends MCPServerBase {
|
|
|
33805
33992
|
jsonSchemaValidator;
|
|
33806
33993
|
mapAuthInfoToUser;
|
|
33807
33994
|
fga;
|
|
33808
|
-
subscriptions
|
|
33809
|
-
|
|
33995
|
+
// Resource subscriptions per server instance (main + per HTTP session), set via
|
|
33996
|
+
// resources/subscribe. Note: legacy SSE sessions share the main instance, so they
|
|
33997
|
+
// share one subscription set; streamable HTTP sessions are isolated per session.
|
|
33998
|
+
subscriptionsByInstance = /* @__PURE__ */ new WeakMap();
|
|
33999
|
+
// Minimum logging level per server instance (main + per HTTP session), set via logging/setLevel
|
|
34000
|
+
loggingLevels = /* @__PURE__ */ new WeakMap();
|
|
33810
34001
|
/**
|
|
33811
34002
|
* Provides methods to notify clients about resource changes.
|
|
33812
34003
|
*
|
|
@@ -33830,6 +34021,24 @@ var MCPServer = class extends MCPServerBase {
|
|
|
33830
34021
|
* ```
|
|
33831
34022
|
*/
|
|
33832
34023
|
prompts;
|
|
34024
|
+
/**
|
|
34025
|
+
* Provides methods to dynamically manage tools and notify clients about
|
|
34026
|
+
* tool list changes. Named `toolActions` because `tools()` is the tool
|
|
34027
|
+
* registry getter inherited from `MCPServerBase`.
|
|
34028
|
+
*
|
|
34029
|
+
* @example
|
|
34030
|
+
* ```typescript
|
|
34031
|
+
* // Register a new tool at runtime and notify clients
|
|
34032
|
+
* await server.toolActions.add({ myNewTool });
|
|
34033
|
+
*
|
|
34034
|
+
* // Remove a tool and notify clients
|
|
34035
|
+
* await server.toolActions.remove(['myNewTool']);
|
|
34036
|
+
*
|
|
34037
|
+
* // Notify that the tool list changed (e.g. authorization changes)
|
|
34038
|
+
* await server.toolActions.notifyListChanged();
|
|
34039
|
+
* ```
|
|
34040
|
+
*/
|
|
34041
|
+
toolActions;
|
|
33833
34042
|
/**
|
|
33834
34043
|
* Provides methods for interactive user input collection during tool execution.
|
|
33835
34044
|
*
|
|
@@ -33947,7 +34156,7 @@ var MCPServer = class extends MCPServerBase {
|
|
|
33947
34156
|
this.mapAuthInfoToUser = opts.mapAuthInfoToUser;
|
|
33948
34157
|
this.fga = opts.fga;
|
|
33949
34158
|
const capabilities = {
|
|
33950
|
-
tools: {},
|
|
34159
|
+
tools: { listChanged: true },
|
|
33951
34160
|
logging: { enabled: true }
|
|
33952
34161
|
};
|
|
33953
34162
|
if (this.resourceOptions) {
|
|
@@ -33986,23 +34195,144 @@ var MCPServer = class extends MCPServerBase {
|
|
|
33986
34195
|
this.sseHonoTransports = /* @__PURE__ */ new Map();
|
|
33987
34196
|
this.registerHandlersOnServer(this.server);
|
|
33988
34197
|
this.resources = new ServerResourceActions({
|
|
33989
|
-
|
|
34198
|
+
getSubscribedServers: (uri) => this.getAllSdkServers().filter((server) => this.subscriptionsByInstance.get(server)?.has(uri)),
|
|
33990
34199
|
getLogger: () => this.logger,
|
|
33991
|
-
|
|
34200
|
+
getSdkServers: () => this.getAllSdkServers()
|
|
33992
34201
|
});
|
|
33993
34202
|
this.prompts = new ServerPromptActions({
|
|
33994
34203
|
getLogger: () => this.logger,
|
|
33995
|
-
|
|
34204
|
+
getSdkServers: () => this.getAllSdkServers(),
|
|
33996
34205
|
clearDefinedPrompts: () => {
|
|
33997
34206
|
this.definedPrompts = void 0;
|
|
33998
34207
|
}
|
|
33999
34208
|
});
|
|
34209
|
+
this.toolActions = new ServerToolActions({
|
|
34210
|
+
getLogger: () => this.logger,
|
|
34211
|
+
getSdkServers: () => this.getAllSdkServers(),
|
|
34212
|
+
addTools: (tools) => this.addTools(tools),
|
|
34213
|
+
removeTools: (toolIds) => this.removeTools(toolIds)
|
|
34214
|
+
});
|
|
34000
34215
|
this.elicitation = {
|
|
34001
34216
|
sendRequest: async (request, options) => {
|
|
34002
34217
|
return this.handleElicitationRequest(request, void 0, options);
|
|
34003
34218
|
}
|
|
34004
34219
|
};
|
|
34005
34220
|
}
|
|
34221
|
+
/**
|
|
34222
|
+
* Returns every connected SDK server instance: the main instance (stdio/SSE
|
|
34223
|
+
* transports) plus one instance per streamable HTTP session. Used to
|
|
34224
|
+
* broadcast notifications to all connected clients. Instances without a
|
|
34225
|
+
* connected transport are skipped.
|
|
34226
|
+
*
|
|
34227
|
+
* Note: stateless/serverless requests use transient server instances and
|
|
34228
|
+
* cannot receive notifications.
|
|
34229
|
+
*/
|
|
34230
|
+
getAllSdkServers() {
|
|
34231
|
+
return [this.server, ...this.httpServerInstances.values()].filter((server) => server.transport !== void 0);
|
|
34232
|
+
}
|
|
34233
|
+
/**
|
|
34234
|
+
* Determines whether a log message at the given level should be sent to the
|
|
34235
|
+
* client connected to the given server instance, honoring the minimum level
|
|
34236
|
+
* the client set via `logging/setLevel` (RFC 5424 severity ordering).
|
|
34237
|
+
* When the client never set a level, all messages are sent.
|
|
34238
|
+
*/
|
|
34239
|
+
shouldSendLog(serverInstance, level) {
|
|
34240
|
+
const minimumLevel = this.loggingLevels.get(serverInstance);
|
|
34241
|
+
if (minimumLevel === void 0) return true;
|
|
34242
|
+
return LOG_LEVEL_SEVERITY[level] >= LOG_LEVEL_SEVERITY[minimumLevel];
|
|
34243
|
+
}
|
|
34244
|
+
/**
|
|
34245
|
+
* Sends a `notifications/message` log notification to connected clients.
|
|
34246
|
+
*
|
|
34247
|
+
* The notification is broadcast to every active server instance, honoring
|
|
34248
|
+
* the minimum logging level each client set via `logging/setLevel`.
|
|
34249
|
+
*
|
|
34250
|
+
* @param params - Log message parameters
|
|
34251
|
+
* @param params.level - Log severity level
|
|
34252
|
+
* @param params.data - Arbitrary JSON-serializable data to log
|
|
34253
|
+
* @param params.logger - Optional logger name
|
|
34254
|
+
* @throws {MastraError} If sending the notification fails on all eligible server instances
|
|
34255
|
+
*
|
|
34256
|
+
* @example
|
|
34257
|
+
* ```typescript
|
|
34258
|
+
* await server.sendLoggingMessage({
|
|
34259
|
+
* level: 'info',
|
|
34260
|
+
* data: { message: 'Sync completed', itemsProcessed: 42 },
|
|
34261
|
+
* });
|
|
34262
|
+
* ```
|
|
34263
|
+
*/
|
|
34264
|
+
async sendLoggingMessage(params) {
|
|
34265
|
+
const eligibleServers = this.getAllSdkServers().filter((server) => this.shouldSendLog(server, params.level));
|
|
34266
|
+
if (eligibleServers.length === 0) {
|
|
34267
|
+
this.logger.debug("No eligible clients for log message; skipping.", { level: params.level });
|
|
34268
|
+
return;
|
|
34269
|
+
}
|
|
34270
|
+
await broadcastNotification({
|
|
34271
|
+
servers: eligibleServers,
|
|
34272
|
+
send: (server) => server.sendLoggingMessage(params),
|
|
34273
|
+
logger: this.logger,
|
|
34274
|
+
errorId: "MCP_SERVER_LOGGING_MESSAGE_NOTIFICATION_FAILED",
|
|
34275
|
+
errorText: "Failed to send logging message notification",
|
|
34276
|
+
errorDetails: { level: params.level }
|
|
34277
|
+
});
|
|
34278
|
+
}
|
|
34279
|
+
/**
|
|
34280
|
+
* Registers new tools on the running server. Tools are merged into both the
|
|
34281
|
+
* converted tool registry (used by list/call handlers) and the original
|
|
34282
|
+
* tools config so they survive tool re-conversion when the server is
|
|
34283
|
+
* registered with a Mastra instance.
|
|
34284
|
+
*/
|
|
34285
|
+
addTools(tools) {
|
|
34286
|
+
const converted = this.convertTools(tools);
|
|
34287
|
+
for (const key of Object.keys(converted)) {
|
|
34288
|
+
if (this.convertedTools[key]) {
|
|
34289
|
+
this.logger.warn(`Tool '${key}' already exists and will be replaced.`);
|
|
34290
|
+
}
|
|
34291
|
+
}
|
|
34292
|
+
this.convertedTools = { ...this.convertedTools, ...converted };
|
|
34293
|
+
this.originalTools = { ...this.originalTools, ...tools };
|
|
34294
|
+
if (this.mastra) {
|
|
34295
|
+
for (const [key, tool] of Object.entries(tools)) {
|
|
34296
|
+
if (tool && typeof tool === "object" && "id" in tool) {
|
|
34297
|
+
this.mastra.addTool(tool, this.mastraToolKey(key, tool));
|
|
34298
|
+
}
|
|
34299
|
+
}
|
|
34300
|
+
}
|
|
34301
|
+
}
|
|
34302
|
+
/**
|
|
34303
|
+
* Removes tools from the running server by tool ID.
|
|
34304
|
+
*
|
|
34305
|
+
* @returns The IDs of the tools that were actually removed
|
|
34306
|
+
*/
|
|
34307
|
+
removeTools(toolIds) {
|
|
34308
|
+
const removed = [];
|
|
34309
|
+
const convertedTools = { ...this.convertedTools };
|
|
34310
|
+
const originalTools = { ...this.originalTools };
|
|
34311
|
+
for (const toolId of toolIds) {
|
|
34312
|
+
if (convertedTools[toolId]) {
|
|
34313
|
+
const originalTool = originalTools[toolId];
|
|
34314
|
+
delete convertedTools[toolId];
|
|
34315
|
+
delete originalTools[toolId];
|
|
34316
|
+
removed.push(toolId);
|
|
34317
|
+
if (this.mastra && originalTool && typeof originalTool === "object" && "id" in originalTool) {
|
|
34318
|
+
this.mastra.removeTool(this.mastraToolKey(toolId, originalTool));
|
|
34319
|
+
}
|
|
34320
|
+
} else {
|
|
34321
|
+
this.logger.warn(`Cannot remove tool '${toolId}': tool not found.`);
|
|
34322
|
+
}
|
|
34323
|
+
}
|
|
34324
|
+
this.convertedTools = convertedTools;
|
|
34325
|
+
this.originalTools = originalTools;
|
|
34326
|
+
return removed;
|
|
34327
|
+
}
|
|
34328
|
+
/**
|
|
34329
|
+
* The key a tool is registered under in the Mastra instance's tool
|
|
34330
|
+
* registry: the tool's intrinsic ID when present (avoids collisions across
|
|
34331
|
+
* MCP servers), falling back to its record key. Mirrors __registerMastra.
|
|
34332
|
+
*/
|
|
34333
|
+
mastraToolKey(key, tool) {
|
|
34334
|
+
return "id" in tool && typeof tool.id === "string" ? tool.id : key;
|
|
34335
|
+
}
|
|
34006
34336
|
/**
|
|
34007
34337
|
* Handle an elicitation request by sending it to the connected client.
|
|
34008
34338
|
* This method sends an elicitation/create request to the client and waits for the response.
|
|
@@ -34135,7 +34465,7 @@ var MCPServer = class extends MCPServerBase {
|
|
|
34135
34465
|
*/
|
|
34136
34466
|
createServerInstance() {
|
|
34137
34467
|
const capabilities = {
|
|
34138
|
-
tools: {},
|
|
34468
|
+
tools: { listChanged: true },
|
|
34139
34469
|
logging: { enabled: true }
|
|
34140
34470
|
};
|
|
34141
34471
|
if (this.resourceOptions) {
|
|
@@ -34254,6 +34584,33 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
34254
34584
|
}
|
|
34255
34585
|
};
|
|
34256
34586
|
const proxiedContext = await this.createProxiedRequestContext(extra);
|
|
34587
|
+
const sessionLog = async (level, message, data) => {
|
|
34588
|
+
if (!this.shouldSendLog(serverInstance, level)) return;
|
|
34589
|
+
await extra.sendNotification({
|
|
34590
|
+
method: "notifications/message",
|
|
34591
|
+
params: {
|
|
34592
|
+
level,
|
|
34593
|
+
logger: this.name,
|
|
34594
|
+
data: { message, ...data }
|
|
34595
|
+
}
|
|
34596
|
+
});
|
|
34597
|
+
};
|
|
34598
|
+
const progressToken = extra._meta?.progressToken;
|
|
34599
|
+
const sessionProgress = async (params) => {
|
|
34600
|
+
if (progressToken === void 0) {
|
|
34601
|
+
this.logger.debug("Tool attempted to send progress but the caller sent no progressToken; skipping.", {
|
|
34602
|
+
tool: request.params.name
|
|
34603
|
+
});
|
|
34604
|
+
return;
|
|
34605
|
+
}
|
|
34606
|
+
await extra.sendNotification({
|
|
34607
|
+
method: "notifications/progress",
|
|
34608
|
+
params: {
|
|
34609
|
+
progressToken,
|
|
34610
|
+
...params
|
|
34611
|
+
}
|
|
34612
|
+
});
|
|
34613
|
+
};
|
|
34257
34614
|
const mcpOptions = {
|
|
34258
34615
|
messages: [],
|
|
34259
34616
|
toolCallId: "",
|
|
@@ -34261,7 +34618,9 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
34261
34618
|
// Pass MCP-specific context through the mcp property
|
|
34262
34619
|
mcp: {
|
|
34263
34620
|
elicitation: sessionElicitation,
|
|
34264
|
-
extra
|
|
34621
|
+
extra,
|
|
34622
|
+
log: sessionLog,
|
|
34623
|
+
progress: sessionProgress
|
|
34265
34624
|
},
|
|
34266
34625
|
// @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
|
|
34267
34626
|
get elicitation() {
|
|
@@ -34349,7 +34708,7 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
34349
34708
|
}
|
|
34350
34709
|
});
|
|
34351
34710
|
serverInstance.setRequestHandler(SetLevelRequestSchema, async (request) => {
|
|
34352
|
-
this.
|
|
34711
|
+
this.loggingLevels.set(serverInstance, request.params.level);
|
|
34353
34712
|
this.logger.debug("Logging level set", { level: request.params.level });
|
|
34354
34713
|
return {};
|
|
34355
34714
|
});
|
|
@@ -34393,11 +34752,13 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
34393
34752
|
try {
|
|
34394
34753
|
const resourcesOrResourceContent = await capturedResourceOptions.getResourceContent({ uri, extra });
|
|
34395
34754
|
const resourcesContent = Array.isArray(resourcesOrResourceContent) ? resourcesOrResourceContent : [resourcesOrResourceContent];
|
|
34755
|
+
const resourceMeta = resource._meta ? { _meta: resource._meta } : {};
|
|
34396
34756
|
const contents = resourcesContent.map((resourceContent) => {
|
|
34397
34757
|
if ("text" in resourceContent && resourceContent.text !== void 0) {
|
|
34398
34758
|
return {
|
|
34399
34759
|
uri: resource.uri,
|
|
34400
34760
|
mimeType: resource.mimeType,
|
|
34761
|
+
...resourceMeta,
|
|
34401
34762
|
text: resourceContent.text
|
|
34402
34763
|
};
|
|
34403
34764
|
}
|
|
@@ -34408,6 +34769,7 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
34408
34769
|
return {
|
|
34409
34770
|
uri: resource.uri,
|
|
34410
34771
|
mimeType: resource.mimeType,
|
|
34772
|
+
...resourceMeta,
|
|
34411
34773
|
blob
|
|
34412
34774
|
};
|
|
34413
34775
|
});
|
|
@@ -34438,13 +34800,18 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
34438
34800
|
serverInstance.setRequestHandler(SubscribeRequestSchema, async (request) => {
|
|
34439
34801
|
const uri = request.params.uri;
|
|
34440
34802
|
this.logger.info("Received resources/subscribe request", { uri });
|
|
34441
|
-
this.
|
|
34803
|
+
let subscriptions = this.subscriptionsByInstance.get(serverInstance);
|
|
34804
|
+
if (!subscriptions) {
|
|
34805
|
+
subscriptions = /* @__PURE__ */ new Set();
|
|
34806
|
+
this.subscriptionsByInstance.set(serverInstance, subscriptions);
|
|
34807
|
+
}
|
|
34808
|
+
subscriptions.add(uri);
|
|
34442
34809
|
return {};
|
|
34443
34810
|
});
|
|
34444
34811
|
serverInstance.setRequestHandler(UnsubscribeRequestSchema, async (request) => {
|
|
34445
34812
|
const uri = request.params.uri;
|
|
34446
34813
|
this.logger.info("Received resources/unsubscribe request", { uri });
|
|
34447
|
-
this.
|
|
34814
|
+
this.subscriptionsByInstance.get(serverInstance)?.delete(uri);
|
|
34448
34815
|
return {};
|
|
34449
34816
|
});
|
|
34450
34817
|
}
|
|
@@ -35014,7 +35381,8 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
35014
35381
|
const isStatelessMode = options?.serverless || options && "sessionIdGenerator" in options && options.sessionIdGenerator === void 0;
|
|
35015
35382
|
if (isStatelessMode) {
|
|
35016
35383
|
this.logger.debug("Running in stateless mode");
|
|
35017
|
-
|
|
35384
|
+
const enableJsonResponse = options?.enableJsonResponse ?? !options?.serverlessStreaming;
|
|
35385
|
+
await this.handleServerlessRequest(req, res, { enableJsonResponse });
|
|
35018
35386
|
return;
|
|
35019
35387
|
}
|
|
35020
35388
|
const mergedOptions = {
|
|
@@ -35058,11 +35426,14 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
35058
35426
|
const { isInitializeRequest } = await import('@modelcontextprotocol/sdk/types.js');
|
|
35059
35427
|
if (isInitializeRequest(body)) {
|
|
35060
35428
|
this.logger.debug("Received initialize request, creating new transport");
|
|
35429
|
+
const sessionServerInstance = this.createServerInstance();
|
|
35061
35430
|
transport = new StreamableHTTPServerTransport({
|
|
35062
35431
|
...mergedOptions,
|
|
35063
35432
|
sessionIdGenerator: mergedOptions.sessionIdGenerator,
|
|
35064
35433
|
onsessioninitialized: (id) => {
|
|
35065
35434
|
this.streamableHTTPTransports.set(id, transport);
|
|
35435
|
+
this.httpServerInstances.set(id, sessionServerInstance);
|
|
35436
|
+
this.logger.debug("Session initialized and stored", { sessionId: id });
|
|
35066
35437
|
}
|
|
35067
35438
|
});
|
|
35068
35439
|
transport.onclose = () => {
|
|
@@ -35076,15 +35447,7 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
35076
35447
|
}
|
|
35077
35448
|
}
|
|
35078
35449
|
};
|
|
35079
|
-
const sessionServerInstance = this.createServerInstance();
|
|
35080
35450
|
await sessionServerInstance.connect(transport);
|
|
35081
|
-
if (transport.sessionId) {
|
|
35082
|
-
this.streamableHTTPTransports.set(transport.sessionId, transport);
|
|
35083
|
-
this.httpServerInstances.set(transport.sessionId, sessionServerInstance);
|
|
35084
|
-
this.logger.debug("Session initialized and stored", { sessionId: transport.sessionId });
|
|
35085
|
-
} else {
|
|
35086
|
-
this.logger.warn("Transport initialized without a session ID");
|
|
35087
|
-
}
|
|
35088
35451
|
return await transport.handleRequest(req, res, body);
|
|
35089
35452
|
} else {
|
|
35090
35453
|
this.logger.warn("Received non-initialize POST request without session ID");
|
|
@@ -35155,21 +35518,26 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
35155
35518
|
*
|
|
35156
35519
|
* @param req - Incoming HTTP request
|
|
35157
35520
|
* @param res - HTTP response object
|
|
35521
|
+
* @param options - Transport options for this request
|
|
35522
|
+
* @param options.enableJsonResponse - When `true` (default), buffers and returns a single
|
|
35523
|
+
* JSON-RPC response. When `false`, the request is handled with request-scoped SSE streaming,
|
|
35524
|
+
* so in-request `notifications/progress` reach the client before the final result.
|
|
35158
35525
|
* @private
|
|
35159
35526
|
*/
|
|
35160
|
-
async handleServerlessRequest(req, res) {
|
|
35527
|
+
async handleServerlessRequest(req, res, { enableJsonResponse = true } = {}) {
|
|
35161
35528
|
try {
|
|
35162
35529
|
this.logger.debug("Received serverless request", { method: req.method });
|
|
35163
35530
|
const body = req.method === "POST" ? await this.readJsonBody(req) : void 0;
|
|
35164
35531
|
this.logger.debug("Processing serverless request", {
|
|
35165
35532
|
method: req.method,
|
|
35166
35533
|
bodyMethod: body?.method,
|
|
35167
|
-
id: body?.id
|
|
35534
|
+
id: body?.id,
|
|
35535
|
+
enableJsonResponse
|
|
35168
35536
|
});
|
|
35169
35537
|
const transientServer = this.createServerInstance();
|
|
35170
35538
|
const tempTransport = new StreamableHTTPServerTransport({
|
|
35171
35539
|
sessionIdGenerator: void 0,
|
|
35172
|
-
enableJsonResponse
|
|
35540
|
+
enableJsonResponse
|
|
35173
35541
|
});
|
|
35174
35542
|
await transientServer.connect(tempTransport);
|
|
35175
35543
|
await tempTransport.handleRequest(req, res, body);
|