This repository was archived by the owner on May 16, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 35
feat: support StreamableHTTPClientTransport #64
Merged
benjamincburns
merged 12 commits into
langchain-ai:main
from
leo237:feature/streamable-http
May 13, 2025
Merged
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
0ca7648
Added support for basic streamable http adapter
b265abf
added tests
07ff66b
updated example
e88ef0c
Updated readme
05f4b67
fixes formatting issues
ee26a0f
Use Streamable HTTP for all URLs first, fallback to SSE
benjamincburns c193c20
partial test rework
benjamincburns b33a2de
fix tests, add example (not working yet)
benjamincburns 0f42f28
fixes, add Streaming HTTP example w/ SSE fallback, update REAMDE
benjamincburns ce96b23
bump to latest MCP sdk
benjamincburns 84f0f70
minor tweak
benjamincburns 972158c
use "http" as transport ID instead of "streamable"
benjamincburns File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,4 +5,5 @@ index.d.cts | |
| node_modules | ||
| dist | ||
| .yarn | ||
| .env | ||
| .env | ||
| .eslintcache | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,7 +9,8 @@ This library provides a lightweight wrapper that makes [Anthropic Model Context | |
|
|
||
| - 🔌 **Transport Options** | ||
|
|
||
| - Connect to MCP servers via stdio (local) or SSE (remote) | ||
| - Connect to MCP servers via stdio (local) or Streamable HTTP (remote) | ||
| - Streamable HTTP automatically falls back to SSE for compatibility with legacy MCP server implementations | ||
| - Support for custom headers in SSE connections for authentication | ||
| - Configurable reconnection strategies for both transport types | ||
|
|
||
|
|
@@ -38,13 +39,13 @@ npm install @langchain/mcp-adapters | |
|
|
||
| ### Optional Dependencies | ||
|
|
||
| For SSE connections with custom headers in Node.js: | ||
| For SSE connections with custom headers in Node.js (does not apply to Streamable HTTP): | ||
|
|
||
| ```bash | ||
| npm install eventsource | ||
| ``` | ||
|
|
||
| For enhanced SSE header support: | ||
| For enhanced SSE header support (does not apply to Streamable HTTP): | ||
|
|
||
| ```bash | ||
| npm install extended-eventsource | ||
|
|
@@ -155,14 +156,19 @@ const client = new MultiServerMCPClient({ | |
| args: ["-y", "@modelcontextprotocol/server-filesystem"], | ||
| }, | ||
|
|
||
| // SSE transport example with reconnection configuration | ||
| // Sreamable HTTP transport example, with auth headers and automatic SSE fallback disabled (defaults to enabled) | ||
| weather: { | ||
| transport: "sse", | ||
| url: "https://example.com/mcp-weather", | ||
| url: "https://example.com/weather/mcp", | ||
| headers: { | ||
| Authorization: "Bearer token123", | ||
| }, | ||
| useNodeEventSource: true, | ||
| } | ||
| automaticSSEFallback: false | ||
| }, | ||
|
|
||
| // how to force SSE, for old servers that are known to only support SSE (streamable HTTP falls back automatically if unsure) | ||
| github: { | ||
| transport: "sse", // also works with "type" field instead of "transport" | ||
| url: "https://example.com/mcp", | ||
| reconnect: { | ||
| enabled: true, | ||
| maxAttempts: 5, | ||
|
|
@@ -212,8 +218,8 @@ When loading MCP tools either directly through `loadMcpTools` or via `MultiServe | |
| | Option | Type | Default | Description | | ||
| | ------------------------------ | ------- | ------- | ------------------------------------------------------------------------------------ | | ||
| | `throwOnLoadError` | boolean | `true` | Whether to throw an error if a tool fails to load | | ||
| | `prefixToolNameWithServerName` | boolean | `false` | If true, prefixes all tool names with the server name (e.g., `serverName__toolName`) | | ||
| | `additionalToolNamePrefix` | string | `""` | Additional prefix to add to tool names (e.g., `prefix__serverName__toolName`) | | ||
| | `prefixToolNameWithServerName` | boolean | `true` | If true, prefixes all tool names with the server name (e.g., `serverName__toolName`) | | ||
| | `additionalToolNamePrefix` | string | `mcp` | Additional prefix to add to tool names (e.g., `prefix__serverName__toolName`) | | ||
|
Comment on lines
+221
to
+222
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These defaults weren't actually changed in this PR (see checks in tests to verify) - just updated in README and config schema to reflect the actual defaults |
||
|
|
||
| ## Response Handling | ||
|
|
||
|
|
@@ -361,8 +367,8 @@ Example Zod error for an invalid SSE URL: | |
|
|
||
| When using in browsers: | ||
|
|
||
| - Native EventSource API doesn't support custom headers | ||
| - Consider using a proxy or pass authentication via query parameters | ||
| - EventSource API doesn't support custom headers for SSE | ||
| - Consider using a proxy or pass authentication via query parameters to avoid leaking credentials to client | ||
| - May require CORS configuration on the server side | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,10 @@ | ||
| import { vi, describe, test, expect, beforeEach, type Mock } from "vitest"; | ||
| import { ZodError } from "zod"; | ||
| import { Connection } from "../src/client.js"; | ||
| import type { | ||
| ClientConfig, | ||
| Connection, | ||
| StdioConnection, | ||
| } from "../src/client.js"; | ||
|
|
||
| import "./mocks.js"; | ||
|
|
||
|
|
@@ -11,6 +15,9 @@ const { StdioClientTransport } = await import( | |
| const { SSEClientTransport } = await import( | ||
| "@modelcontextprotocol/sdk/client/sse.js" | ||
| ); | ||
| const { StreamableHTTPClientTransport } = await import( | ||
| "@modelcontextprotocol/sdk/client/streamableHttp.js" | ||
| ); | ||
| const { MultiServerMCPClient, MCPClientError } = await import( | ||
| "../src/client.js" | ||
| ); | ||
|
|
@@ -44,6 +51,23 @@ describe("MultiServerMCPClient", () => { | |
| expect(Client).toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| test("should process valid streamable HTTP connection config", async () => { | ||
| const config = { | ||
| "test-server": { | ||
| transport: "http" as const, | ||
| url: "http://localhost:8000/mcp", | ||
| }, | ||
| }; | ||
|
|
||
| const client = new MultiServerMCPClient(config); | ||
| expect(client).toBeDefined(); | ||
|
|
||
| // Initialize connections and verify | ||
| await client.initializeConnections(); | ||
| expect(StreamableHTTPClientTransport).toHaveBeenCalled(); | ||
| expect(Client).toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| test("should process valid SSE connection config", async () => { | ||
| const config = { | ||
| "test-server": { | ||
|
|
@@ -324,6 +348,10 @@ describe("MultiServerMCPClient", () => { | |
| }, | ||
| }); | ||
|
|
||
| const conf = client.config; | ||
| expect(conf.additionalToolNamePrefix).toBe("mcp"); | ||
| expect(conf.prefixToolNameWithServerName).toBe(true); | ||
|
Comment on lines
+351
to
+353
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added this during test troubleshooting because the defaults reverted due to me accidentally setting |
||
|
|
||
| await client.initializeConnections(); | ||
| const tools = await client.getTools(); | ||
|
|
||
|
|
@@ -522,5 +550,30 @@ describe("MultiServerMCPClient", () => { | |
| // Should not have created a client | ||
| expect(Client).not.toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| test("should throw on streamable HTTP transport creation errors", async () => { | ||
| // Force an error when creating transport | ||
| (StreamableHTTPClientTransport as Mock).mockImplementationOnce(() => { | ||
| throw new Error("Streamable HTTP transport creation failed"); | ||
| }); | ||
|
|
||
| const client = new MultiServerMCPClient({ | ||
| "test-server": { | ||
| transport: "http" as const, | ||
| url: "http://localhost:8000/mcp", | ||
| }, | ||
| }); | ||
|
|
||
| // Should throw error when connecting | ||
| await expect( | ||
| async () => await client.initializeConnections() | ||
| ).rejects.toThrow(); | ||
|
|
||
| // Should have attempted to create transport | ||
| expect(StreamableHTTPClientTransport).toHaveBeenCalled(); | ||
|
|
||
| // Should not have created a client | ||
| expect(Client).not.toHaveBeenCalled(); | ||
| }); | ||
| }); | ||
| }); | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.