From 87235e9aa1e1fc4c4b930df8739935a91030a64d Mon Sep 17 00:00:00 2001 From: Phoebe Nichols Date: Mon, 28 Jul 2025 20:39:55 +0100 Subject: [PATCH 1/5] feat: Expose authProvider to allow token refresh --- packages/mcp/src/client/client.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/mcp/src/client/client.ts b/packages/mcp/src/client/client.ts index 6273c59e01a..08fc4855f88 100644 --- a/packages/mcp/src/client/client.ts +++ b/packages/mcp/src/client/client.ts @@ -74,6 +74,7 @@ type StdioServerDefinition = BaseServerOptions & { url?: never; // Exclude 'url' for Stdio requestInit?: never; // Exclude HTTP options for Stdio eventSourceInit?: never; // Exclude HTTP options for Stdio + authProvider?: never; // Exclude HTTP options for Stdio reconnectionOptions?: never; // Exclude Streamable HTTP specific options sessionId?: never; // Exclude Streamable HTTP specific options }; @@ -89,6 +90,7 @@ type HttpServerDefinition = BaseServerOptions & { // Include relevant options from SDK HTTP transport types requestInit?: StreamableHTTPClientTransportOptions['requestInit']; eventSourceInit?: SSEClientTransportOptions['eventSourceInit']; + authProvider?: StreamableHTTPClientTransportOptions['authProvider']; reconnectionOptions?: StreamableHTTPClientTransportOptions['reconnectionOptions']; sessionId?: StreamableHTTPClientTransportOptions['sessionId']; }; @@ -237,7 +239,7 @@ export class InternalMastraMCPClient extends MastraBase { } private async connectHttp(url: URL) { - const { requestInit, eventSourceInit } = this.serverConfig; + const { requestInit, eventSourceInit, authProvider } = this.serverConfig; this.log('debug', `Attempting to connect to URL: ${url}`); @@ -251,6 +253,7 @@ export class InternalMastraMCPClient extends MastraBase { const streamableTransport = new StreamableHTTPClientTransport(url, { requestInit, reconnectionOptions: this.serverConfig.reconnectionOptions, + authProvider: authProvider, }); await this.client.connect(streamableTransport, { timeout: @@ -269,7 +272,7 @@ export class InternalMastraMCPClient extends MastraBase { this.log('debug', 'Falling back to deprecated HTTP+SSE transport...'); try { // Fallback to SSE transport - const sseTransport = new SSEClientTransport(url, { requestInit, eventSourceInit }); + const sseTransport = new SSEClientTransport(url, { requestInit, eventSourceInit, authProvider }); await this.client.connect(sseTransport, { timeout: this.serverConfig.timeout ?? this.timeout }); this.transport = sseTransport; this.log('debug', 'Successfully connected using deprecated HTTP+SSE transport.'); From ef463ccd2e324e5400f309e8b177a609ec5c1529 Mon Sep 17 00:00:00 2001 From: Phoebe Nichols Date: Mon, 28 Jul 2025 21:57:28 +0100 Subject: [PATCH 2/5] test: Add comprehensive authProvider tests for MCP client MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add tests to verify that authProvider functionality works correctly: - Accept authProvider field in HTTP server configuration - Handle undefined authProvider gracefully - Maintain backward compatibility for clients without authProvider These tests validate the authProvider exposure added for token refresh capability. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- packages/mcp/src/client/client.test.ts | 66 ++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/packages/mcp/src/client/client.test.ts b/packages/mcp/src/client/client.test.ts index bf7540f641a..b84ee690dd2 100644 --- a/packages/mcp/src/client/client.test.ts +++ b/packages/mcp/src/client/client.test.ts @@ -517,3 +517,69 @@ describe('MastraMCPClient - Elicitation Tests', () => { expect(elicitationResultText).toContain('Elicitation response content does not match requested schema'); }); }); + +describe('MastraMCPClient - AuthProvider Tests', () => { + let testServer: { + httpServer: HttpServer; + mcpServer: McpServer; + serverTransport: StreamableHTTPServerTransport; + baseUrl: URL; + }; + let client: InternalMastraMCPClient; + + beforeEach(async () => { + testServer = await setupTestServer(false); + }); + + afterEach(async () => { + await client?.disconnect().catch(() => {}); + await testServer?.mcpServer.close().catch(() => {}); + await testServer?.serverTransport.close().catch(() => {}); + testServer?.httpServer.close(); + }); + + it('should accept authProvider field in HTTP server configuration', async () => { + const mockAuthProvider = { test: 'authProvider' } as any; + + client = new InternalMastraMCPClient({ + name: 'auth-config-test', + server: { + url: testServer.baseUrl, + authProvider: mockAuthProvider, + }, + }); + + const serverConfig = (client as any).serverConfig; + expect(serverConfig.authProvider).toBe(mockAuthProvider); + expect(client).toBeDefined(); + expect(typeof client).toBe('object'); + }); + + it('should handle undefined authProvider gracefully', async () => { + client = new InternalMastraMCPClient({ + name: 'auth-undefined-test', + server: { + url: testServer.baseUrl, + authProvider: undefined, + }, + }); + + await client.connect(); + const tools = await client.tools(); + expect(tools).toHaveProperty('greet'); + }); + + it('should work without authProvider for HTTP transport (backward compatibility)', async () => { + client = new InternalMastraMCPClient({ + name: 'no-auth-http-client', + server: { + url: testServer.baseUrl, + }, + }); + + await client.connect(); + const tools = await client.tools(); + expect(tools).toHaveProperty('greet'); + }); + +}); From a91dba33c3e3b91f52346a9d582c67791da99ed9 Mon Sep 17 00:00:00 2001 From: Phoebe Nichols Date: Tue, 29 Jul 2025 11:00:42 +0100 Subject: [PATCH 3/5] docs: Add authProvider documentation for OAuth token refresh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add comprehensive documentation for the new authProvider option: - OAuth authentication section with usage examples - Configuration reference for authProvider field - Feature list updates to highlight OAuth support - CHANGELOG entry for the new functionality This documents the authProvider functionality that enables automatic token refresh for HTTP-based MCP servers. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- packages/mcp/CHANGELOG.md | 6 ++++++ packages/mcp/README.md | 39 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/packages/mcp/CHANGELOG.md b/packages/mcp/CHANGELOG.md index ab7c34dda84..8364b34af03 100644 --- a/packages/mcp/CHANGELOG.md +++ b/packages/mcp/CHANGELOG.md @@ -1,5 +1,11 @@ # @mastra/mcp +## Unreleased + +### Patch Changes + +- Expose authProvider option for HTTP-based MCP servers to enable OAuth authentication with automatic token refresh. The authProvider is automatically passed to both Streamable HTTP and SSE transports for seamless authentication across different connection types. + ## 0.10.7 ### Patch Changes diff --git a/packages/mcp/README.md b/packages/mcp/README.md index b91d214cb92..c121ff41cb2 100644 --- a/packages/mcp/README.md +++ b/packages/mcp/README.md @@ -378,7 +378,41 @@ mcp.prompts.onListChanged({ Prompt notifications are delivered via SSE or compatible transports. Register handlers before expecting notifications. -## SSE Authentication and Headers (Legacy Fallback) +## Authentication + +### OAuth Token Refresh with AuthProvider + +For HTTP-based MCP servers that require OAuth authentication with automatic token refresh, you can use the `authProvider` option: + +```typescript +const httpClient = new MCPClient({ + servers: { + myOAuthClient: { + url: new URL('https://your-mcp-server.com/mcp'), + authProvider: { + tokens: async () => { + // Your token refresh logic here + const refreshedToken = await refreshAccessToken(); + return { + token: refreshedToken, + type: 'Bearer', + }; + }, + // Additional OAuth provider methods as needed + redirectUrl: 'https://your-app.com/oauth/callback', + clientMetadata: { + /* ... */ + }, + // ... other OAuth provider properties + }, + }, + }, +}); +``` + +The `authProvider` is automatically passed to both Streamable HTTP and SSE transports. + +### SSE Authentication and Headers (Legacy Fallback) When the client falls back to using the legacy SSE (Server-Sent Events) transport and you need to include authentication or custom headers, you need to configure headers in a specific way. The standard `requestInit` headers won't work alone because SSE connections using the browser's `EventSource` API don't support custom headers directly. @@ -456,6 +490,7 @@ Here are the available options within `MastraMCPServerDefinition`: - **`url`**: (Optional, URL) For HTTP servers (Streamable HTTP or SSE): The URL of the server. - **`requestInit`**: (Optional, RequestInit) For HTTP servers: Request configuration for the fetch API. Used for the initial Streamable HTTP connection attempt and subsequent POST requests. Also used for the initial SSE connection attempt. - **`eventSourceInit`**: (Optional, EventSourceInit) **Only** for the legacy SSE fallback: Custom fetch configuration for SSE connections. Required when using custom headers with SSE. +- **`authProvider`**: (Optional, OAuthClientProvider) For HTTP servers: OAuth authentication provider for automatic token refresh. Automatically passed to both Streamable HTTP and SSE transports. - **`logger`**: (Optional, LogHandler) Optional additional handler for logging. - **`timeout`**: (Optional, number) Server-specific timeout in milliseconds, overriding the global client/configuration timeout. - **`capabilities`**: (Optional, ClientCapabilities) Server-specific capabilities configuration. @@ -469,6 +504,8 @@ Here are the available options within `MastraMCPServerDefinition`: - Multiple transport layers with automatic detection: - Stdio-based for local servers (`command`) - HTTP-based for remote servers (`url`): Tries Streamable HTTP first, falls back to legacy SSE. +- OAuth authentication with automatic token refresh (`authProvider`) +- Manual authentication headers for static tokens (`requestInit`, `eventSourceInit`) - Per-server logging capability using all standard MCP log levels - Automatic error handling and logging - Tool execution with context From 72eb12da0c5578cd7a845cdb31d9983cdf4aac42 Mon Sep 17 00:00:00 2001 From: Phoebe Nichols Date: Tue, 29 Jul 2025 11:39:50 +0100 Subject: [PATCH 4/5] Add changeset --- .changeset/fast-steaks-shine.md | 5 +++++ packages/mcp/CHANGELOG.md | 6 ------ 2 files changed, 5 insertions(+), 6 deletions(-) create mode 100644 .changeset/fast-steaks-shine.md diff --git a/.changeset/fast-steaks-shine.md b/.changeset/fast-steaks-shine.md new file mode 100644 index 00000000000..ec36cc2ae0d --- /dev/null +++ b/.changeset/fast-steaks-shine.md @@ -0,0 +1,5 @@ +--- +'@mastra/mcp': minor +--- + +Expose authProvider option for HTTP-based MCP servers to enable OAuth authentication with automatic token refresh. The authProvider is automatically passed to both Streamable HTTP and SSE transports. diff --git a/packages/mcp/CHANGELOG.md b/packages/mcp/CHANGELOG.md index 8364b34af03..ab7c34dda84 100644 --- a/packages/mcp/CHANGELOG.md +++ b/packages/mcp/CHANGELOG.md @@ -1,11 +1,5 @@ # @mastra/mcp -## Unreleased - -### Patch Changes - -- Expose authProvider option for HTTP-based MCP servers to enable OAuth authentication with automatic token refresh. The authProvider is automatically passed to both Streamable HTTP and SSE transports for seamless authentication across different connection types. - ## 0.10.7 ### Patch Changes From eadf6ba4f1a5ddfcc7a164c52e3893a7618e295d Mon Sep 17 00:00:00 2001 From: Ward Peeters Date: Tue, 29 Jul 2025 15:06:12 +0200 Subject: [PATCH 5/5] Update .changeset/fast-steaks-shine.md --- .changeset/fast-steaks-shine.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/fast-steaks-shine.md b/.changeset/fast-steaks-shine.md index ec36cc2ae0d..3a396f14e77 100644 --- a/.changeset/fast-steaks-shine.md +++ b/.changeset/fast-steaks-shine.md @@ -1,5 +1,5 @@ --- -'@mastra/mcp': minor +'@mastra/mcp': patch --- Expose authProvider option for HTTP-based MCP servers to enable OAuth authentication with automatic token refresh. The authProvider is automatically passed to both Streamable HTTP and SSE transports.