@mastra/mcp 1.7.0 → 1.7.1-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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # @mastra/mcp
2
2
 
3
+ ## 1.7.1-alpha.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Close previous SSE transport before accepting a new connection in `MCPServer.connectSSE()`. Previously, sequential SSE connections to the same server would fail with "Already connected to a transport" because the underlying protocol was never closed when the previous client disconnected. ([#16695](https://github.com/mastra-ai/mastra/pull/16695))
8
+
3
9
  ## 1.7.0
4
10
 
5
11
  ### Minor Changes
@@ -3,7 +3,7 @@ name: mastra-mcp
3
3
  description: Documentation for @mastra/mcp. Use when working with @mastra/mcp APIs, configuration, or implementation.
4
4
  metadata:
5
5
  package: "@mastra/mcp"
6
- version: "1.7.0"
6
+ version: "1.7.1-alpha.0"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.7.0",
2
+ "version": "1.7.1-alpha.0",
3
3
  "package": "@mastra/mcp",
4
4
  "exports": {
5
5
  "UnauthorizedError": {
@@ -987,6 +987,53 @@ await agent.generate('Hello!', {
987
987
  })
988
988
  ```
989
989
 
990
+ ## Handling auth failures inside custom fetch
991
+
992
+ A custom `fetch` should not `throw` when authentication is unavailable. The Streamable HTTP transport in the MCP SDK opens a long-lived `GET /mcp` "standalone listener" stream in the background to receive server-pushed notifications. Errors on that stream are retried with exponential backoff, and a thrown `fetch` or a cleanly-closed stream can produce an indefinite reconnect loop at roughly one attempt per second.
993
+
994
+ Return a synthetic `Response` instead. The [MCP Streamable HTTP specification](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports) defines `405 Method Not Allowed` as the signal a server returns when it does not offer the GET SSE stream, and the SDK honors it as a terminal status that stops the listener cleanly. Use this to disable the listener when your server does not push notifications.
995
+
996
+ The following pattern waits for an auth token on POST requests, attaches it to outgoing headers, and short-circuits the GET listener with a synthetic 405:
997
+
998
+ ```typescript
999
+ async function waitForToken(timeoutMs = 5000): Promise<string | null> {
1000
+ // Replace with your token lookup. Return null if no token is available.
1001
+ return getAuthToken({ timeoutMs })
1002
+ }
1003
+
1004
+ const mcpClient = new MCPClient({
1005
+ servers: {
1006
+ apiServer: {
1007
+ url: new URL('https://api.example.com/mcp'),
1008
+ fetch: async (url, init) => {
1009
+ const method = (init?.method || 'GET').toUpperCase()
1010
+
1011
+ // The SDK opens a background GET stream for server-pushed notifications.
1012
+ // If your server does not use it, short-circuit with 405 to stop reconnect attempts.
1013
+ if (method === 'GET') {
1014
+ return new Response(null, { status: 405, statusText: 'Method Not Allowed' })
1015
+ }
1016
+
1017
+ // POST: wait for the token, then forward the request with an Authorization header.
1018
+ const token = await waitForToken()
1019
+ if (!token) {
1020
+ // Forward the request without a token and let the server reject it.
1021
+ // The SDK surfaces non-2xx POST responses as errors to the caller of
1022
+ // tools/list, tools/call, etc., which is the desired behavior here.
1023
+ return fetch(url, init)
1024
+ }
1025
+
1026
+ const headers = new Headers(init?.headers)
1027
+ headers.set('authorization', `Bearer ${token}`)
1028
+ return fetch(url, { ...init, headers })
1029
+ },
1030
+ },
1031
+ },
1032
+ })
1033
+ ```
1034
+
1035
+ Return `405` for the GET listener only when your server does not push notifications back to the client. If your server uses the standalone GET stream, attach the auth token on `GET` requests as well and let the request through.
1036
+
990
1037
  ## Using SSE request headers
991
1038
 
992
1039
  When using the legacy SSE MCP transport, you must configure both `requestInit` and `eventSourceInit` due to a bug in the MCP SDK. Alternatively, you can use a custom `fetch` function which will be automatically used for both POST requests and SSE connections:
package/dist/index.cjs CHANGED
@@ -2314,7 +2314,7 @@ function createSimpleTokenProvider(accessToken, options) {
2314
2314
  });
2315
2315
  }
2316
2316
 
2317
- // ../../node_modules/.pnpm/hono@4.12.14/node_modules/hono/dist/utils/stream.js
2317
+ // ../../node_modules/.pnpm/hono@4.12.18/node_modules/hono/dist/utils/stream.js
2318
2318
  var StreamingApi = class {
2319
2319
  writer;
2320
2320
  encoder;
@@ -2391,7 +2391,7 @@ var StreamingApi = class {
2391
2391
  }
2392
2392
  };
2393
2393
 
2394
- // ../../node_modules/.pnpm/hono@4.12.14/node_modules/hono/dist/helper/streaming/utils.js
2394
+ // ../../node_modules/.pnpm/hono@4.12.18/node_modules/hono/dist/helper/streaming/utils.js
2395
2395
  var isOldBunVersion = () => {
2396
2396
  const version = typeof Bun !== "undefined" ? Bun.version : void 0;
2397
2397
  if (version === void 0) {
@@ -2402,7 +2402,7 @@ var isOldBunVersion = () => {
2402
2402
  return result;
2403
2403
  };
2404
2404
 
2405
- // ../../node_modules/.pnpm/hono@4.12.14/node_modules/hono/dist/utils/html.js
2405
+ // ../../node_modules/.pnpm/hono@4.12.18/node_modules/hono/dist/utils/html.js
2406
2406
  var HtmlEscapedCallbackPhase = {
2407
2407
  Stringify: 1};
2408
2408
  var resolveCallback = async (str, phase, preserveCallbacks, context, buffer) => {
@@ -2433,7 +2433,7 @@ var resolveCallback = async (str, phase, preserveCallbacks, context, buffer) =>
2433
2433
  }
2434
2434
  };
2435
2435
 
2436
- // ../../node_modules/.pnpm/hono@4.12.14/node_modules/hono/dist/helper/streaming/sse.js
2436
+ // ../../node_modules/.pnpm/hono@4.12.18/node_modules/hono/dist/helper/streaming/sse.js
2437
2437
  var SSEStreamingApi = class extends StreamingApi {
2438
2438
  constructor(writable, readable) {
2439
2439
  super(writable, readable);
@@ -4186,6 +4186,10 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
4186
4186
  }) {
4187
4187
  try {
4188
4188
  this.logger.debug("Received SSE connection");
4189
+ if (this.sseTransport) {
4190
+ await this.sseTransport.close?.();
4191
+ this.sseTransport = void 0;
4192
+ }
4189
4193
  this.sseTransport = new sse_js$1.SSEServerTransport(messagePath, res);
4190
4194
  await this.server.connect(this.sseTransport);
4191
4195
  this.server.onclose = async () => {