Skip to content

MultiServerMCPClient does not support base_path for SSE connections to servers hosted on nested paths #134

@Bajticek

Description

@Bajticek

🔧 MultiServerMCPClient does not support base_path for SSE connections to servers hosted on nested paths

Summary

The current implementation of MultiServerMCPClient in langchain_mcp_adapters does not support the base_path parameter when connecting to SSE endpoints that are hosted on a nested path (e.g., https://domain.com/subdomain instead of the root https://domain.com/).

This makes it incompatible with MCP backends that are reverse-proxied or deployed under a subpath rather than the domain root.


Details

The underlying mcp library (as of v1.6.0) supports a base_path parameter for correctly composing full POST message URLs returned from the SSE endpoint event.

However, the connect_to_server_via_sse method in MultiServerMCPClient currently does not pass any base_path into the sse_client(...) call, even though this is required for correct communication when the server is not deployed at the domain root.

For example, the following line:

sse_transport = await self.exit_stack.enter_async_context(
    sse_client(url, headers, timeout, sse_read_timeout)
)

...results in incorrect message endpoints like:
https://domain.com/mcp/message?...
When it should be:
https://domain.com/subdomain/mcp/message?...

This leads to 404 errors when the actual endpoint is hosted behind a prefix.


Expected Behavior

Allow users to specify a configuration like:

{
  "url": "https://domain.com/subdomain/sse",
  "transport": "sse",
  "base_path": "/subdomain"
}

…and have base_path passed into the sse_client(...) call to ensure message URLs are correctly composed.

Suggested Fix

  • Update the connect_to_server_via_sse method to accept base_path
  • Pass base_path into sse_client(...) (supported since mcp>=1.6.0)
  • Preserve backward compatibility by defaulting to ""

Example patch:

async def connect_to_server_via_sse(..., base_path: str = "", ...):
    ...
    sse_transport = await self.exit_stack.enter_async_context(
        sse_client(
            url,
            headers=headers,
            timeout=timeout,
            sse_read_timeout=sse_read_timeout,
            base_path=base_path,
        )
    )

Current Workarounds

  • Monkeypatching connect_to_server_via_sse to manually inject base_path
  • Using a reverse proxy to rewrite /mcp/... to /subdomain/mcp/...
    Both are viable but brittle or require external infrastructure.

Environment

  • langchain_mcp_adapters: latest (as of May 2025)
  • mcp: 1.7.1
  • Platform: LangChain + LangGraph
  • Use case: MCP SSE servers reverse-proxied behind a nested path

Related

Request

Let me know if you'd be open to a PR — I'm happy to contribute this improvement.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions