Skip to content

Commit 02b02c7

Browse files
authored
[Feat] MCP - Add support for streamablehttp_client MCP Servers (#11628)
* feat - add https mcp support * fixes for MCP http integration * fix code QA * bump mcp dep * test_mcp_server_manager_https_server * test mcp server https * fix linting error * bump mcp in poetry * fix import streamablehttp_client * fix streamablehttp_client * fix streamablehttp_client * add streamablehttp_client
1 parent 0cb7dd7 commit 02b02c7

File tree

7 files changed

+363
-19
lines changed

7 files changed

+363
-19
lines changed

.circleci/config.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -785,7 +785,7 @@ jobs:
785785
pip install "pytest-asyncio==0.21.1"
786786
pip install "respx==0.22.0"
787787
pip install "pydantic==2.10.2"
788-
pip install "mcp==1.5.0"
788+
pip install "mcp==1.9.3"
789789
# Run pytest and generate JUnit XML report
790790
- run:
791791
name: Run tests
@@ -920,7 +920,7 @@ jobs:
920920
pip install "respx==0.22.0"
921921
pip install "hypercorn==0.17.3"
922922
pip install "pydantic==2.10.2"
923-
pip install "mcp==1.5.0"
923+
pip install "mcp==1.9.3"
924924
pip install "requests-mock>=1.12.1"
925925
pip install "responses==0.25.7"
926926
pip install "pytest-xdist==3.6.1"

.circleci/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ pydantic==2.10.2
1212
google-cloud-aiplatform==1.43.0
1313
fastapi-sso==0.16.0
1414
uvloop==0.21.0
15-
mcp==1.5.0 # for MCP server
15+
mcp==1.9.3 # for MCP server

litellm/proxy/_experimental/mcp_server/mcp_server_manager.py

Lines changed: 64 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""
22
MCP Client Manager
33
4-
This class is responsible for managing MCP SSE clients.
4+
This class is responsible for managing MCP clients with support for both SSE and HTTP streamable transports.
55
66
This is a Proxy
77
"""
@@ -25,6 +25,12 @@
2525
MCPTransport,
2626
MCPTransportType,
2727
)
28+
29+
try:
30+
from mcp.client.streamable_http import streamablehttp_client
31+
except ImportError:
32+
streamablehttp_client = None # type: ignore
33+
2834
from litellm.types.mcp_server.mcp_server_manager import MCPInfo, MCPServer
2935

3036

@@ -169,16 +175,43 @@ async def _get_tools_from_server(self, server: MCPServer) -> List[MCPTool]:
169175

170176
# Update tool to server mapping
171177
for tool in tools_result.tools:
172-
self.tool_name_to_mcp_server_name_mapping[
173-
tool.name
174-
] = server.name
178+
self.tool_name_to_mcp_server_name_mapping[tool.name] = (
179+
server.name
180+
)
175181

176182
return tools_result.tools
177183
elif server.transport == MCPTransport.http:
178-
# TODO: implement http transport
179-
return []
184+
if streamablehttp_client is None:
185+
verbose_logger.error(
186+
"streamablehttp_client not available - install mcp with HTTP support"
187+
)
188+
raise ValueError(
189+
"streamablehttp_client not available - please run `pip install mcp -U`"
190+
)
191+
verbose_logger.debug(f"Using HTTP streamable transport for {server.url}")
192+
async with streamablehttp_client(
193+
url=server.url,
194+
) as (read_stream, write_stream, get_session_id):
195+
async with ClientSession(read_stream, write_stream) as session:
196+
await session.initialize()
197+
198+
if get_session_id is not None:
199+
session_id = get_session_id()
200+
if session_id:
201+
verbose_logger.debug(f"HTTP session ID: {session_id}")
202+
203+
tools_result = await session.list_tools()
204+
verbose_logger.debug(f"Tools from {server.name}: {tools_result}")
205+
206+
# Update tool to server mapping
207+
for tool in tools_result.tools:
208+
self.tool_name_to_mcp_server_name_mapping[tool.name] = (
209+
server.name
210+
)
211+
212+
return tools_result.tools
180213
else:
181-
# TODO: throw error on transport found or skip
214+
verbose_logger.warning(f"Unsupported transport type: {server.transport}")
182215
return []
183216

184217
def initialize_tool_name_to_mcp_server_name_mapping(self):
@@ -217,8 +250,30 @@ async def call_tool(self, name: str, arguments: Dict[str, Any]):
217250
await session.initialize()
218251
return await session.call_tool(name, arguments)
219252
elif mcp_server.transport == MCPTransport.http:
220-
# TODO: implement http transport
221-
raise NotImplementedError("HTTP transport is not implemented yet")
253+
if streamablehttp_client is None:
254+
verbose_logger.error(
255+
"streamablehttp_client not available - install mcp with HTTP support"
256+
)
257+
raise ValueError(
258+
"streamablehttp_client not available - please run `pip install mcp -U`"
259+
)
260+
verbose_logger.debug(
261+
f"Using HTTP streamable transport for tool call: {name}"
262+
)
263+
async with streamablehttp_client(
264+
url=mcp_server.url,
265+
) as (read_stream, write_stream, get_session_id):
266+
async with ClientSession(read_stream, write_stream) as session:
267+
await session.initialize()
268+
269+
if get_session_id is not None:
270+
session_id = get_session_id()
271+
if session_id:
272+
verbose_logger.debug(
273+
f"HTTP session ID for tool call: {session_id}"
274+
)
275+
276+
return await session.call_tool(name, arguments)
222277
else:
223278
return CallToolResult(content=[], isError=True)
224279

poetry.lock

Lines changed: 6 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ pynacl = {version = "^1.5.0", optional = true}
5555
websockets = {version = "^13.1.0", optional = true}
5656
boto3 = {version = "1.34.34", optional = true}
5757
redisvl = {version = "^0.4.1", optional = true, markers = "python_version >= '3.9' and python_version < '3.14'"}
58-
mcp = {version = "1.5.0", optional = true, python = ">=3.10"}
58+
mcp = {version = "1.9.3", optional = true, python = ">=3.10"}
5959
litellm-proxy-extras = {version = "0.2.3", optional = true}
6060
rich = {version = "13.7.1", optional = true}
6161
litellm-enterprise = {version = "0.1.7", optional = true}

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ mangum==0.17.0 # for aws lambda functions
1515
pynacl==1.5.0 # for encrypting keys
1616
google-cloud-aiplatform==1.47.0 # for vertex ai calls
1717
anthropic[vertex]==0.21.3
18-
mcp==1.5.0 # for MCP server
18+
mcp==1.9.3 # for MCP server
1919
google-generativeai==0.5.0 # for vertex ai calls
2020
async_generator==1.10.0 # for async ollama calls
2121
langfuse==2.45.0 # for langfuse self-hosted logging

0 commit comments

Comments
 (0)