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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions