Skip to content

Commit 3f367f1

Browse files
authored
Merge branch 'main' into ben/provider-owned-start
2 parents ef649fb + eff8ac7 commit 3f367f1

1 file changed

Lines changed: 44 additions & 35 deletions

File tree

src/openenv/core/env_server/http_server.py

Lines changed: 44 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,20 @@
2222
import uuid
2323
from concurrent.futures import ThreadPoolExecutor
2424
from contextlib import AsyncExitStack
25-
from typing import Any, AsyncContextManager, Callable, cast, Dict, Optional, Type
25+
from typing import (
26+
Any,
27+
AsyncContextManager,
28+
Awaitable,
29+
Callable,
30+
cast,
31+
Dict,
32+
Optional,
33+
Type,
34+
TypeVar,
35+
)
2636

2737
_MISSING = object()
38+
_MCPResult = TypeVar("_MCPResult")
2839

2940
from fastapi import (
3041
Body,
@@ -542,6 +553,25 @@ async def _run_in_session_executor(
542553
loop = asyncio.get_event_loop()
543554
return await loop.run_in_executor(executor, lambda: func(*args, **kwargs))
544555

556+
async def _run_mcp_client_operation(
557+
self,
558+
mcp_client: Any,
559+
mcp_session_factory: Any,
560+
managed_session_id: Optional[str],
561+
operation: Callable[[], Awaitable[_MCPResult]],
562+
) -> _MCPResult:
563+
"""Run an MCP client operation with the appropriate transport lifecycle."""
564+
if managed_session_id and mcp_client.is_connected():
565+
return await operation()
566+
567+
if callable(mcp_session_factory):
568+
mcp_session_cm = cast(AsyncContextManager[Any], mcp_session_factory())
569+
async with mcp_session_cm:
570+
return await operation()
571+
572+
async with mcp_client:
573+
return await operation()
574+
545575
@property
546576
def active_sessions(self) -> int:
547577
"""Return the number of active WebSocket sessions."""
@@ -835,21 +865,12 @@ async def mcp_handler(
835865
)
836866

837867
if mcp_client:
838-
if managed_session_id and mcp_client.is_connected():
839-
# Session-managed with live transport — call
840-
# directly, no redundant re-entry.
841-
tools = await mcp_client.list_tools()
842-
elif callable(mcp_session_factory):
843-
# Stateless request, or session-managed but the
844-
# background transport was lost: (re-)open.
845-
mcp_session_cm = cast(
846-
AsyncContextManager[Any], mcp_session_factory()
847-
)
848-
async with mcp_session_cm:
849-
tools = await mcp_client.list_tools()
850-
else:
851-
async with mcp_client:
852-
tools = await mcp_client.list_tools()
868+
tools = await self._run_mcp_client_operation(
869+
mcp_client,
870+
mcp_session_factory,
871+
managed_session_id,
872+
mcp_client.list_tools,
873+
)
853874

854875
return JsonRpcResponse.success(
855876
result={
@@ -903,26 +924,14 @@ async def mcp_handler(
903924
)
904925

905926
if mcp_client:
906-
if managed_session_id and mcp_client.is_connected():
907-
# Session-managed with live transport.
908-
result = await mcp_client.call_tool(
927+
result = await self._run_mcp_client_operation(
928+
mcp_client,
929+
mcp_session_factory,
930+
managed_session_id,
931+
lambda: mcp_client.call_tool(
909932
name=tool_name, arguments=arguments
910-
)
911-
elif callable(mcp_session_factory):
912-
# Stateless request, or session-managed but the
913-
# background transport was lost: (re-)open.
914-
mcp_session_cm = cast(
915-
AsyncContextManager[Any], mcp_session_factory()
916-
)
917-
async with mcp_session_cm:
918-
result = await mcp_client.call_tool(
919-
name=tool_name, arguments=arguments
920-
)
921-
else:
922-
async with mcp_client:
923-
result = await mcp_client.call_tool(
924-
name=tool_name, arguments=arguments
925-
)
933+
),
934+
)
926935
elif mcp_server:
927936
server_tools = get_server_tools(mcp_server)
928937
if tool_name in server_tools:

0 commit comments

Comments
 (0)