@mastra/mcp 0.5.0-alpha.3 → 0.5.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +7 -7
- package/CHANGELOG.md +12 -0
- package/dist/_tsup-dts-rollup.d.cts +26 -1
- package/dist/_tsup-dts-rollup.d.ts +26 -1
- package/dist/index.cjs +220 -41
- package/dist/index.js +220 -40
- package/package.json +7 -3
- package/src/__fixtures__/fire-crawl-complex-schema.ts +1013 -0
- package/src/client.test.ts +4 -4
- package/src/client.ts +69 -38
- package/src/configuration.test.ts +37 -0
- package/src/server.test.ts +183 -23
- package/src/server.ts +86 -10
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
|
|
2
|
-
> @mastra/mcp@0.5.0-alpha.
|
|
2
|
+
> @mastra/mcp@0.5.0-alpha.4 build /home/runner/work/mastra/mastra/packages/mcp
|
|
3
3
|
> tsup src/index.ts --format esm,cjs --experimental-dts --clean --treeshake=smallest --splitting
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: src/index.ts
|
|
6
6
|
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
7
7
|
[34mCLI[39m tsup v8.4.0
|
|
8
8
|
[34mTSC[39m Build start
|
|
9
|
-
[32mTSC[39m ⚡️ Build success in
|
|
9
|
+
[32mTSC[39m ⚡️ Build success in 17734ms
|
|
10
10
|
[34mDTS[39m Build start
|
|
11
11
|
[34mCLI[39m Target: es2022
|
|
12
12
|
Analysis will use the bundled TypeScript version 5.8.3
|
|
13
13
|
[36mWriting package typings: /home/runner/work/mastra/mastra/packages/mcp/dist/_tsup-dts-rollup.d.ts[39m
|
|
14
14
|
Analysis will use the bundled TypeScript version 5.8.3
|
|
15
15
|
[36mWriting package typings: /home/runner/work/mastra/mastra/packages/mcp/dist/_tsup-dts-rollup.d.cts[39m
|
|
16
|
-
[32mDTS[39m ⚡️ Build success in
|
|
16
|
+
[32mDTS[39m ⚡️ Build success in 13432ms
|
|
17
17
|
[34mCLI[39m Cleaning output folder
|
|
18
18
|
[34mESM[39m Build start
|
|
19
19
|
[34mCJS[39m Build start
|
|
20
|
-
[
|
|
21
|
-
[
|
|
22
|
-
[
|
|
23
|
-
[
|
|
20
|
+
[32mCJS[39m [1mdist/index.cjs [22m[32m32.44 KB[39m
|
|
21
|
+
[32mCJS[39m ⚡️ Build success in 1027ms
|
|
22
|
+
[32mESM[39m [1mdist/index.js [22m[32m32.14 KB[39m
|
|
23
|
+
[32mESM[39m ⚡️ Build success in 1029ms
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @mastra/mcp
|
|
2
2
|
|
|
3
|
+
## 0.5.0-alpha.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 396be50: updated mcp server routes for MCP SSE for use with hono server
|
|
8
|
+
- da082f8: Switch from serializing json schema string as a function to a library that creates a zod object in memory from the json schema. This reduces the errors we were seeing from zod schema code that could not be serialized.
|
|
9
|
+
- Updated dependencies [396be50]
|
|
10
|
+
- Updated dependencies [c3bd795]
|
|
11
|
+
- Updated dependencies [da082f8]
|
|
12
|
+
- Updated dependencies [a5810ce]
|
|
13
|
+
- @mastra/core@0.9.4-alpha.3
|
|
14
|
+
|
|
3
15
|
## 0.5.0-alpha.3
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
|
@@ -4,11 +4,14 @@ import type * as http from 'node:http';
|
|
|
4
4
|
import { LoggingLevel } from '@modelcontextprotocol/sdk/types.js';
|
|
5
5
|
import { MastraBase } from '@mastra/core/base';
|
|
6
6
|
import { MCPServerBase } from '@mastra/core/mcp';
|
|
7
|
+
import type { MCPServerHonoSSEOptions } from '@mastra/core/mcp';
|
|
7
8
|
import type { MCPServerSSEOptions } from '@mastra/core/mcp';
|
|
8
9
|
import type { Protocol } from '@modelcontextprotocol/sdk/shared/protocol.js';
|
|
9
10
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
10
11
|
import type { SSEClientTransportOptions } from '@modelcontextprotocol/sdk/client/sse.js';
|
|
11
12
|
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
|
|
13
|
+
import type { SSEStreamingApi } from 'hono/streaming';
|
|
14
|
+
import { SSETransport } from 'hono-mcp-server-sse-transport';
|
|
12
15
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
13
16
|
import type { StreamableHTTPClientTransportOptions } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
14
17
|
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
@@ -18,6 +21,8 @@ import { ToolExecutionContext } from '@mastra/core';
|
|
|
18
21
|
import type { ToolsInput } from '@mastra/core/agent';
|
|
19
22
|
import { z } from 'zod';
|
|
20
23
|
|
|
24
|
+
export declare const allTools: ToolsInput;
|
|
25
|
+
|
|
21
26
|
declare type BaseServerOptions = {
|
|
22
27
|
logger?: LogHandler;
|
|
23
28
|
timeout?: number;
|
|
@@ -188,6 +193,7 @@ declare class MCPServer extends MCPServerBase {
|
|
|
188
193
|
private server;
|
|
189
194
|
private stdioTransport?;
|
|
190
195
|
private sseTransport?;
|
|
196
|
+
private sseHonoTransports;
|
|
191
197
|
private streamableHTTPTransport?;
|
|
192
198
|
private listToolsHandlerIsRegistered;
|
|
193
199
|
private callToolHandlerIsRegistered;
|
|
@@ -199,6 +205,10 @@ declare class MCPServer extends MCPServerBase {
|
|
|
199
205
|
* Get the current SSE transport.
|
|
200
206
|
*/
|
|
201
207
|
getSseTransport(): SSEServerTransport | undefined;
|
|
208
|
+
/**
|
|
209
|
+
* Get the current SSE Hono transport.
|
|
210
|
+
*/
|
|
211
|
+
getSseHonoTransport(sessionId: string): SSETransport | undefined;
|
|
202
212
|
/**
|
|
203
213
|
* Get the current streamable HTTP transport.
|
|
204
214
|
*/
|
|
@@ -243,6 +253,16 @@ declare class MCPServer extends MCPServerBase {
|
|
|
243
253
|
* @param res HTTP response (must support .write/.end)
|
|
244
254
|
*/
|
|
245
255
|
startSSE({ url, ssePath, messagePath, req, res }: MCPServerSSEOptions): Promise<void>;
|
|
256
|
+
/**
|
|
257
|
+
* Handles MCP-over-SSE protocol for user-provided HTTP servers.
|
|
258
|
+
* Call this from your HTTP server for both the SSE and message endpoints.
|
|
259
|
+
*
|
|
260
|
+
* @param url Parsed URL of the incoming request
|
|
261
|
+
* @param ssePath Path for establishing the SSE connection (e.g. '/sse')
|
|
262
|
+
* @param messagePath Path for POSTing client messages (e.g. '/message')
|
|
263
|
+
* @param context Incoming Hono context
|
|
264
|
+
*/
|
|
265
|
+
startHonoSSE({ url, ssePath, messagePath, context }: MCPServerHonoSSEOptions): Promise<Response>;
|
|
246
266
|
/**
|
|
247
267
|
* Handles MCP-over-StreamableHTTP protocol for user-provided HTTP servers.
|
|
248
268
|
* Call this from your HTTP server for the streamable HTTP endpoint.
|
|
@@ -260,11 +280,14 @@ declare class MCPServer extends MCPServerBase {
|
|
|
260
280
|
res: http.ServerResponse<http.IncomingMessage>;
|
|
261
281
|
options?: StreamableHTTPServerTransportOptions;
|
|
262
282
|
}): Promise<void>;
|
|
263
|
-
handlePostMessage(req: http.IncomingMessage, res: http.ServerResponse<http.IncomingMessage>): Promise<void>;
|
|
264
283
|
connectSSE({ messagePath, res, }: {
|
|
265
284
|
messagePath: string;
|
|
266
285
|
res: http.ServerResponse<http.IncomingMessage>;
|
|
267
286
|
}): Promise<void>;
|
|
287
|
+
connectHonoSSE({ messagePath, stream }: {
|
|
288
|
+
messagePath: string;
|
|
289
|
+
stream: SSEStreamingApi;
|
|
290
|
+
}): Promise<void>;
|
|
268
291
|
/**
|
|
269
292
|
* Close the MCP server and all its connections
|
|
270
293
|
*/
|
|
@@ -273,6 +296,8 @@ declare class MCPServer extends MCPServerBase {
|
|
|
273
296
|
export { MCPServer }
|
|
274
297
|
export { MCPServer as MCPServer_alias_1 }
|
|
275
298
|
|
|
299
|
+
export declare const mcpServerName = "firecrawl-mcp-fixture";
|
|
300
|
+
|
|
276
301
|
export declare const server: Server<{
|
|
277
302
|
method: string;
|
|
278
303
|
params?: {
|
|
@@ -4,11 +4,14 @@ import type * as http from 'node:http';
|
|
|
4
4
|
import { LoggingLevel } from '@modelcontextprotocol/sdk/types.js';
|
|
5
5
|
import { MastraBase } from '@mastra/core/base';
|
|
6
6
|
import { MCPServerBase } from '@mastra/core/mcp';
|
|
7
|
+
import type { MCPServerHonoSSEOptions } from '@mastra/core/mcp';
|
|
7
8
|
import type { MCPServerSSEOptions } from '@mastra/core/mcp';
|
|
8
9
|
import type { Protocol } from '@modelcontextprotocol/sdk/shared/protocol.js';
|
|
9
10
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
10
11
|
import type { SSEClientTransportOptions } from '@modelcontextprotocol/sdk/client/sse.js';
|
|
11
12
|
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
|
|
13
|
+
import type { SSEStreamingApi } from 'hono/streaming';
|
|
14
|
+
import { SSETransport } from 'hono-mcp-server-sse-transport';
|
|
12
15
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
13
16
|
import type { StreamableHTTPClientTransportOptions } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
14
17
|
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
@@ -18,6 +21,8 @@ import { ToolExecutionContext } from '@mastra/core';
|
|
|
18
21
|
import type { ToolsInput } from '@mastra/core/agent';
|
|
19
22
|
import { z } from 'zod';
|
|
20
23
|
|
|
24
|
+
export declare const allTools: ToolsInput;
|
|
25
|
+
|
|
21
26
|
declare type BaseServerOptions = {
|
|
22
27
|
logger?: LogHandler;
|
|
23
28
|
timeout?: number;
|
|
@@ -188,6 +193,7 @@ declare class MCPServer extends MCPServerBase {
|
|
|
188
193
|
private server;
|
|
189
194
|
private stdioTransport?;
|
|
190
195
|
private sseTransport?;
|
|
196
|
+
private sseHonoTransports;
|
|
191
197
|
private streamableHTTPTransport?;
|
|
192
198
|
private listToolsHandlerIsRegistered;
|
|
193
199
|
private callToolHandlerIsRegistered;
|
|
@@ -199,6 +205,10 @@ declare class MCPServer extends MCPServerBase {
|
|
|
199
205
|
* Get the current SSE transport.
|
|
200
206
|
*/
|
|
201
207
|
getSseTransport(): SSEServerTransport | undefined;
|
|
208
|
+
/**
|
|
209
|
+
* Get the current SSE Hono transport.
|
|
210
|
+
*/
|
|
211
|
+
getSseHonoTransport(sessionId: string): SSETransport | undefined;
|
|
202
212
|
/**
|
|
203
213
|
* Get the current streamable HTTP transport.
|
|
204
214
|
*/
|
|
@@ -243,6 +253,16 @@ declare class MCPServer extends MCPServerBase {
|
|
|
243
253
|
* @param res HTTP response (must support .write/.end)
|
|
244
254
|
*/
|
|
245
255
|
startSSE({ url, ssePath, messagePath, req, res }: MCPServerSSEOptions): Promise<void>;
|
|
256
|
+
/**
|
|
257
|
+
* Handles MCP-over-SSE protocol for user-provided HTTP servers.
|
|
258
|
+
* Call this from your HTTP server for both the SSE and message endpoints.
|
|
259
|
+
*
|
|
260
|
+
* @param url Parsed URL of the incoming request
|
|
261
|
+
* @param ssePath Path for establishing the SSE connection (e.g. '/sse')
|
|
262
|
+
* @param messagePath Path for POSTing client messages (e.g. '/message')
|
|
263
|
+
* @param context Incoming Hono context
|
|
264
|
+
*/
|
|
265
|
+
startHonoSSE({ url, ssePath, messagePath, context }: MCPServerHonoSSEOptions): Promise<Response>;
|
|
246
266
|
/**
|
|
247
267
|
* Handles MCP-over-StreamableHTTP protocol for user-provided HTTP servers.
|
|
248
268
|
* Call this from your HTTP server for the streamable HTTP endpoint.
|
|
@@ -260,11 +280,14 @@ declare class MCPServer extends MCPServerBase {
|
|
|
260
280
|
res: http.ServerResponse<http.IncomingMessage>;
|
|
261
281
|
options?: StreamableHTTPServerTransportOptions;
|
|
262
282
|
}): Promise<void>;
|
|
263
|
-
handlePostMessage(req: http.IncomingMessage, res: http.ServerResponse<http.IncomingMessage>): Promise<void>;
|
|
264
283
|
connectSSE({ messagePath, res, }: {
|
|
265
284
|
messagePath: string;
|
|
266
285
|
res: http.ServerResponse<http.IncomingMessage>;
|
|
267
286
|
}): Promise<void>;
|
|
287
|
+
connectHonoSSE({ messagePath, stream }: {
|
|
288
|
+
messagePath: string;
|
|
289
|
+
stream: SSEStreamingApi;
|
|
290
|
+
}): Promise<void>;
|
|
268
291
|
/**
|
|
269
292
|
* Close the MCP server and all its connections
|
|
270
293
|
*/
|
|
@@ -273,6 +296,8 @@ declare class MCPServer extends MCPServerBase {
|
|
|
273
296
|
export { MCPServer }
|
|
274
297
|
export { MCPServer as MCPServer_alias_1 }
|
|
275
298
|
|
|
299
|
+
export declare const mcpServerName = "firecrawl-mcp-fixture";
|
|
300
|
+
|
|
276
301
|
export declare const server: Server<{
|
|
277
302
|
method: string;
|
|
278
303
|
params?: {
|
package/dist/index.cjs
CHANGED
|
@@ -10,11 +10,11 @@ var streamableHttp_js$1 = require('@modelcontextprotocol/sdk/client/streamableHt
|
|
|
10
10
|
var protocol_js = require('@modelcontextprotocol/sdk/shared/protocol.js');
|
|
11
11
|
var types_js = require('@modelcontextprotocol/sdk/types.js');
|
|
12
12
|
var exitHook = require('exit-hook');
|
|
13
|
-
var jsonSchemaToZod = require('json-schema-to-zod');
|
|
14
13
|
var zod = require('zod');
|
|
14
|
+
var zodFromJsonSchema = require('zod-from-json-schema');
|
|
15
15
|
var equal = require('fast-deep-equal');
|
|
16
16
|
var uuid = require('uuid');
|
|
17
|
-
var crypto = require('crypto');
|
|
17
|
+
var crypto$1 = require('crypto');
|
|
18
18
|
var core = require('@mastra/core');
|
|
19
19
|
var mcp = require('@mastra/core/mcp');
|
|
20
20
|
var runtimeContext = require('@mastra/core/runtime-context');
|
|
@@ -22,10 +22,10 @@ var index_js = require('@modelcontextprotocol/sdk/server/index.js');
|
|
|
22
22
|
var sse_js = require('@modelcontextprotocol/sdk/server/sse.js');
|
|
23
23
|
var stdio_js = require('@modelcontextprotocol/sdk/server/stdio.js');
|
|
24
24
|
var streamableHttp_js = require('@modelcontextprotocol/sdk/server/streamableHttp.js');
|
|
25
|
+
var streaming = require('hono/streaming');
|
|
25
26
|
|
|
26
27
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
27
28
|
|
|
28
|
-
var jsonSchemaToZod__default = /*#__PURE__*/_interopDefault(jsonSchemaToZod);
|
|
29
29
|
var equal__default = /*#__PURE__*/_interopDefault(equal);
|
|
30
30
|
|
|
31
31
|
// src/client.ts
|
|
@@ -238,7 +238,29 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
238
238
|
});
|
|
239
239
|
}
|
|
240
240
|
convertInputSchema(inputSchema) {
|
|
241
|
-
|
|
241
|
+
if (utils.isZodType(inputSchema)) {
|
|
242
|
+
return inputSchema;
|
|
243
|
+
}
|
|
244
|
+
try {
|
|
245
|
+
const rawShape = zodFromJsonSchema.jsonSchemaObjectToZodRawShape(inputSchema);
|
|
246
|
+
return zod.z.object(rawShape);
|
|
247
|
+
} catch (error) {
|
|
248
|
+
let errorDetails;
|
|
249
|
+
if (error instanceof Error) {
|
|
250
|
+
errorDetails = error.stack;
|
|
251
|
+
} else {
|
|
252
|
+
try {
|
|
253
|
+
errorDetails = JSON.stringify(error);
|
|
254
|
+
} catch {
|
|
255
|
+
errorDetails = String(error);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
this.log("error", "Failed to convert JSON schema to Zod schema using zodFromJsonSchema", {
|
|
259
|
+
error: errorDetails,
|
|
260
|
+
originalJsonSchema: inputSchema
|
|
261
|
+
});
|
|
262
|
+
throw new Error(errorDetails);
|
|
263
|
+
}
|
|
242
264
|
}
|
|
243
265
|
async tools() {
|
|
244
266
|
this.log("debug", `Requesting tools from MCP server`);
|
|
@@ -246,36 +268,43 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
246
268
|
const toolsRes = {};
|
|
247
269
|
tools$1.forEach((tool) => {
|
|
248
270
|
this.log("debug", `Processing tool: ${tool.name}`);
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
error
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
271
|
+
try {
|
|
272
|
+
const mastraTool = tools.createTool({
|
|
273
|
+
id: `${this.name}_${tool.name}`,
|
|
274
|
+
description: tool.description || "",
|
|
275
|
+
inputSchema: this.convertInputSchema(tool.inputSchema),
|
|
276
|
+
execute: async ({ context }) => {
|
|
277
|
+
try {
|
|
278
|
+
this.log("debug", `Executing tool: ${tool.name}`, { toolArgs: context });
|
|
279
|
+
const res = await this.client.callTool(
|
|
280
|
+
{
|
|
281
|
+
name: tool.name,
|
|
282
|
+
arguments: context
|
|
283
|
+
},
|
|
284
|
+
types_js.CallToolResultSchema,
|
|
285
|
+
{
|
|
286
|
+
timeout: this.timeout
|
|
287
|
+
}
|
|
288
|
+
);
|
|
289
|
+
this.log("debug", `Tool executed successfully: ${tool.name}`);
|
|
290
|
+
return res;
|
|
291
|
+
} catch (e) {
|
|
292
|
+
this.log("error", `Error calling tool: ${tool.name}`, {
|
|
293
|
+
error: e instanceof Error ? e.stack : JSON.stringify(e, null, 2),
|
|
294
|
+
toolArgs: context
|
|
295
|
+
});
|
|
296
|
+
throw e;
|
|
297
|
+
}
|
|
274
298
|
}
|
|
299
|
+
});
|
|
300
|
+
if (tool.name) {
|
|
301
|
+
toolsRes[tool.name] = mastraTool;
|
|
275
302
|
}
|
|
276
|
-
})
|
|
277
|
-
|
|
278
|
-
|
|
303
|
+
} catch (toolCreationError) {
|
|
304
|
+
this.log("error", `Failed to create Mastra tool wrapper for MCP tool: ${tool.name}`, {
|
|
305
|
+
error: toolCreationError instanceof Error ? toolCreationError.stack : String(toolCreationError),
|
|
306
|
+
mcpToolDefinition: tool
|
|
307
|
+
});
|
|
279
308
|
}
|
|
280
309
|
});
|
|
281
310
|
return toolsRes;
|
|
@@ -477,10 +506,95 @@ var MCPConfiguration = class extends MCPClient {
|
|
|
477
506
|
);
|
|
478
507
|
}
|
|
479
508
|
};
|
|
509
|
+
var MAXIMUM_MESSAGE_SIZE = 4 * 1024 * 1024;
|
|
510
|
+
var SSETransport = class {
|
|
511
|
+
messageUrl;
|
|
512
|
+
stream;
|
|
513
|
+
_sessionId;
|
|
514
|
+
onclose;
|
|
515
|
+
onerror;
|
|
516
|
+
onmessage;
|
|
517
|
+
/**
|
|
518
|
+
* Creates a new SSETransport, which will direct the MPC client to POST messages to messageUrl
|
|
519
|
+
*/
|
|
520
|
+
constructor(messageUrl, stream) {
|
|
521
|
+
this.messageUrl = messageUrl;
|
|
522
|
+
this.stream = stream;
|
|
523
|
+
this._sessionId = crypto.randomUUID();
|
|
524
|
+
this.stream.onAbort(() => {
|
|
525
|
+
void this.close();
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
get sessionId() {
|
|
529
|
+
return this._sessionId;
|
|
530
|
+
}
|
|
531
|
+
// start() is automatically called after MCP Server connects to the transport
|
|
532
|
+
async start() {
|
|
533
|
+
if (this.stream == null) {
|
|
534
|
+
throw new Error("Stream not initialized");
|
|
535
|
+
}
|
|
536
|
+
if (this.stream.closed) {
|
|
537
|
+
throw new Error("SSE transport already closed!");
|
|
538
|
+
}
|
|
539
|
+
await this.stream.writeSSE({
|
|
540
|
+
event: "endpoint",
|
|
541
|
+
data: `${this.messageUrl}?sessionId=${this.sessionId}`
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
async handlePostMessage(context) {
|
|
545
|
+
if (this.stream?.closed == null) {
|
|
546
|
+
return context.text("SSE connection not established", 500);
|
|
547
|
+
}
|
|
548
|
+
try {
|
|
549
|
+
const contentType = context.req.header("content-type") || "";
|
|
550
|
+
if (!contentType.includes("application/json")) {
|
|
551
|
+
throw new Error(`Unsupported content-type: ${contentType}`);
|
|
552
|
+
}
|
|
553
|
+
const contentLength = Number.parseInt(context.req.header("content-length") || "0", 10);
|
|
554
|
+
if (contentLength > MAXIMUM_MESSAGE_SIZE) {
|
|
555
|
+
throw new Error(`Request body too large: ${contentLength} bytes`);
|
|
556
|
+
}
|
|
557
|
+
const body = await context.req.json();
|
|
558
|
+
await this.handleMessage(body);
|
|
559
|
+
return context.text("Accepted", 202);
|
|
560
|
+
} catch (error) {
|
|
561
|
+
this.onerror?.(error);
|
|
562
|
+
return context.text("Error", 400);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
566
|
+
* Handle a client message, regardless of how it arrived. This can be used to inform the server of messages that arrive via a means different than HTTP POST.
|
|
567
|
+
*/
|
|
568
|
+
async handleMessage(message) {
|
|
569
|
+
let parsedMessage;
|
|
570
|
+
try {
|
|
571
|
+
parsedMessage = types_js.JSONRPCMessageSchema.parse(message);
|
|
572
|
+
} catch (error) {
|
|
573
|
+
this.onerror?.(error);
|
|
574
|
+
throw error;
|
|
575
|
+
}
|
|
576
|
+
this.onmessage?.(parsedMessage);
|
|
577
|
+
}
|
|
578
|
+
async close() {
|
|
579
|
+
if (this.stream?.closed) {
|
|
580
|
+
this.stream.abort();
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
async send(message) {
|
|
584
|
+
if (this.stream?.closed) {
|
|
585
|
+
throw new Error("Not connected");
|
|
586
|
+
}
|
|
587
|
+
await this.stream.writeSSE({
|
|
588
|
+
event: "message",
|
|
589
|
+
data: JSON.stringify(message)
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
};
|
|
480
593
|
var MCPServer = class extends mcp.MCPServerBase {
|
|
481
594
|
server;
|
|
482
595
|
stdioTransport;
|
|
483
596
|
sseTransport;
|
|
597
|
+
sseHonoTransports;
|
|
484
598
|
streamableHTTPTransport;
|
|
485
599
|
listToolsHandlerIsRegistered = false;
|
|
486
600
|
callToolHandlerIsRegistered = false;
|
|
@@ -496,6 +610,12 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
496
610
|
getSseTransport() {
|
|
497
611
|
return this.sseTransport;
|
|
498
612
|
}
|
|
613
|
+
/**
|
|
614
|
+
* Get the current SSE Hono transport.
|
|
615
|
+
*/
|
|
616
|
+
getSseHonoTransport(sessionId) {
|
|
617
|
+
return this.sseHonoTransports.get(sessionId);
|
|
618
|
+
}
|
|
499
619
|
/**
|
|
500
620
|
* Get the current streamable HTTP transport.
|
|
501
621
|
*/
|
|
@@ -514,6 +634,7 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
514
634
|
this.logger.info(
|
|
515
635
|
`Initialized MCPServer '${name}' v${version} with tools: ${Object.keys(this.convertedTools).join(", ")}`
|
|
516
636
|
);
|
|
637
|
+
this.sseHonoTransports = /* @__PURE__ */ new Map();
|
|
517
638
|
this.registerListToolsHandler();
|
|
518
639
|
this.registerCallToolHandler();
|
|
519
640
|
}
|
|
@@ -685,6 +806,43 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
685
806
|
res.end();
|
|
686
807
|
}
|
|
687
808
|
}
|
|
809
|
+
/**
|
|
810
|
+
* Handles MCP-over-SSE protocol for user-provided HTTP servers.
|
|
811
|
+
* Call this from your HTTP server for both the SSE and message endpoints.
|
|
812
|
+
*
|
|
813
|
+
* @param url Parsed URL of the incoming request
|
|
814
|
+
* @param ssePath Path for establishing the SSE connection (e.g. '/sse')
|
|
815
|
+
* @param messagePath Path for POSTing client messages (e.g. '/message')
|
|
816
|
+
* @param context Incoming Hono context
|
|
817
|
+
*/
|
|
818
|
+
async startHonoSSE({ url, ssePath, messagePath, context }) {
|
|
819
|
+
if (url.pathname === ssePath) {
|
|
820
|
+
return streaming.streamSSE(context, async (stream) => {
|
|
821
|
+
await this.connectHonoSSE({
|
|
822
|
+
messagePath,
|
|
823
|
+
stream
|
|
824
|
+
});
|
|
825
|
+
});
|
|
826
|
+
} else if (url.pathname === messagePath) {
|
|
827
|
+
this.logger.debug("Received message");
|
|
828
|
+
const sessionId = context.req.query("sessionId");
|
|
829
|
+
this.logger.debug("Received message for sessionId", { sessionId });
|
|
830
|
+
if (!sessionId) {
|
|
831
|
+
return context.text("No sessionId provided", 400);
|
|
832
|
+
}
|
|
833
|
+
if (!this.sseHonoTransports.has(sessionId)) {
|
|
834
|
+
return context.text(`No transport found for sessionId ${sessionId}`, 400);
|
|
835
|
+
}
|
|
836
|
+
const message = await this.sseHonoTransports.get(sessionId)?.handlePostMessage(context);
|
|
837
|
+
if (!message) {
|
|
838
|
+
return context.text("Transport not found", 400);
|
|
839
|
+
}
|
|
840
|
+
return message;
|
|
841
|
+
} else {
|
|
842
|
+
this.logger.debug("Unknown path:", { path: url.pathname });
|
|
843
|
+
return context.text("Unknown path", 404);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
688
846
|
/**
|
|
689
847
|
* Handles MCP-over-StreamableHTTP protocol for user-provided HTTP servers.
|
|
690
848
|
* Call this from your HTTP server for the streamable HTTP endpoint.
|
|
@@ -700,7 +858,7 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
700
858
|
httpPath,
|
|
701
859
|
req,
|
|
702
860
|
res,
|
|
703
|
-
options = { sessionIdGenerator: () => crypto.randomUUID() }
|
|
861
|
+
options = { sessionIdGenerator: () => crypto$1.randomUUID() }
|
|
704
862
|
}) {
|
|
705
863
|
if (url.pathname === httpPath) {
|
|
706
864
|
this.streamableHTTPTransport = new streamableHttp_js.StreamableHTTPServerTransport(options);
|
|
@@ -732,14 +890,6 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
732
890
|
res.end();
|
|
733
891
|
}
|
|
734
892
|
}
|
|
735
|
-
async handlePostMessage(req, res) {
|
|
736
|
-
if (!this.sseTransport) {
|
|
737
|
-
res.writeHead(503);
|
|
738
|
-
res.end("SSE connection not established");
|
|
739
|
-
return;
|
|
740
|
-
}
|
|
741
|
-
await this.sseTransport.handlePostMessage(req, res);
|
|
742
|
-
}
|
|
743
893
|
async connectSSE({
|
|
744
894
|
messagePath,
|
|
745
895
|
res
|
|
@@ -755,6 +905,29 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
755
905
|
this.sseTransport = void 0;
|
|
756
906
|
});
|
|
757
907
|
}
|
|
908
|
+
async connectHonoSSE({ messagePath, stream }) {
|
|
909
|
+
this.logger.debug("Received SSE connection");
|
|
910
|
+
const sseTransport = new SSETransport(messagePath, stream);
|
|
911
|
+
const sessionId = sseTransport.sessionId;
|
|
912
|
+
this.logger.debug("SSE Transport created with sessionId:", { sessionId });
|
|
913
|
+
this.sseHonoTransports.set(sessionId, sseTransport);
|
|
914
|
+
stream.onAbort(() => {
|
|
915
|
+
this.logger.debug("SSE Transport aborted with sessionId:", { sessionId });
|
|
916
|
+
this.sseHonoTransports.delete(sessionId);
|
|
917
|
+
});
|
|
918
|
+
await this.server.connect(sseTransport);
|
|
919
|
+
this.server.onclose = async () => {
|
|
920
|
+
this.logger.debug("SSE Transport closed with sessionId:", { sessionId });
|
|
921
|
+
this.sseHonoTransports.delete(sessionId);
|
|
922
|
+
await this.server.close();
|
|
923
|
+
};
|
|
924
|
+
while (true) {
|
|
925
|
+
const sessionIds = Array.from(this.sseHonoTransports.keys() || []);
|
|
926
|
+
this.logger.debug("Active Hono SSE sessions:", { sessionIds });
|
|
927
|
+
await stream.write(":keep-alive\n\n");
|
|
928
|
+
await stream.sleep(6e4);
|
|
929
|
+
}
|
|
930
|
+
}
|
|
758
931
|
/**
|
|
759
932
|
* Close the MCP server and all its connections
|
|
760
933
|
*/
|
|
@@ -770,6 +943,12 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
770
943
|
await this.sseTransport.close?.();
|
|
771
944
|
this.sseTransport = void 0;
|
|
772
945
|
}
|
|
946
|
+
if (this.sseHonoTransports) {
|
|
947
|
+
for (const transport of this.sseHonoTransports.values()) {
|
|
948
|
+
await transport.close?.();
|
|
949
|
+
}
|
|
950
|
+
this.sseHonoTransports.clear();
|
|
951
|
+
}
|
|
773
952
|
if (this.streamableHTTPTransport) {
|
|
774
953
|
await this.streamableHTTPTransport.close?.();
|
|
775
954
|
this.streamableHTTPTransport = void 0;
|