Skip to content

Commit 8bd09ca

Browse files
committed
Fixed async issue
1 parent 2dc9b63 commit 8bd09ca

File tree

1 file changed

+40
-21
lines changed

1 file changed

+40
-21
lines changed

src/mcipy/mcp_integration.py

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
fetching their tool definitions, and building MCI-compatible toolset schemas.
66
"""
77

8-
import asyncio
8+
import asyncio, concurrent.futures
99
from datetime import UTC, datetime, timedelta
1010
from typing import Any
1111

@@ -75,6 +75,18 @@ def _annotations_to_tags(mcp_annotations: Any) -> list[str]:
7575

7676
return tags
7777

78+
@staticmethod
79+
async def fetch_and_build_toolset_async(
80+
server_name: str,
81+
server_config: StdioMCPServer | HttpMCPServer,
82+
schema_version: str,
83+
env_context: dict[str, Any],
84+
template_engine: TemplateEngine,
85+
) -> ToolsetSchema:
86+
return await MCPIntegration._async_fetch_and_build_toolset(
87+
server_name, server_config, schema_version, env_context, template_engine
88+
)
89+
7890
@staticmethod
7991
def fetch_and_build_toolset(
8092
server_name: str,
@@ -84,30 +96,37 @@ def fetch_and_build_toolset(
8496
template_engine: TemplateEngine,
8597
) -> ToolsetSchema:
8698
"""
87-
Fetch tools from an MCP server and build a toolset schema.
88-
89-
Args:
90-
server_name: Name of the MCP server
91-
server_config: MCP server configuration (STDIO or HTTP)
92-
schema_version: Schema version to use for the toolset
93-
env_context: Environment context for templating
94-
template_engine: Template engine for processing placeholders
95-
96-
Returns:
97-
ToolsetSchema with tools from the MCP server and expiration date
99+
Sync convenience for callers.
98100
99-
Raises:
100-
MCPIntegrationError: If MCP server connection or tool fetching fails
101+
- If NO event loop is running, use asyncio.run(...) in this thread.
102+
- If a loop IS running (e.g., inside an async CLI), offload the async
103+
work to a separate thread that owns its own loop, and block until it finishes.
101104
"""
102-
# Run async operation in sync context
103-
try:
104-
result = asyncio.run(
105-
MCPIntegration._async_fetch_and_build_toolset(
106-
server_name, server_config, schema_version, env_context, template_engine
107-
)
105+
async def _coro():
106+
return await MCPIntegration.fetch_and_build_toolset_async(
107+
server_name, server_config, schema_version, env_context, template_engine
108108
)
109-
return result
109+
110+
try:
111+
# detect running loop
112+
try:
113+
asyncio.get_running_loop()
114+
loop_running = True
115+
except RuntimeError:
116+
loop_running = False
117+
118+
if not loop_running:
119+
return asyncio.run(_coro())
120+
121+
# Run in separate thread if a loop is active
122+
def _run_in_thread():
123+
return asyncio.run(_coro())
124+
125+
with concurrent.futures.ThreadPoolExecutor(max_workers=1) as ex:
126+
return ex.submit(_run_in_thread).result()
127+
110128
except Exception as e:
129+
# <-- place your error handler HERE
111130
raise MCPIntegrationError(
112131
f"Failed to fetch from MCP server '{server_name}': {e}"
113132
) from e

0 commit comments

Comments
 (0)