Skip to content

Commit 0662430

Browse files
Merge branch 'tui_oauth' of github.com:Edison-Watch/open-edison into tui_oauth
2 parents df0f159 + dcc510f commit 0662430

File tree

2 files changed

+58
-10
lines changed

2 files changed

+58
-10
lines changed

src/mcp_importer/api.py

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from src.mcp_importer.merge import MergePolicy, merge_servers
2828
from src.oauth_manager import OAuthStatus, get_oauth_manager
2929
from src.oauth_override import OpenEdisonOAuth
30+
from src.tools.io import suppress_fds
3031

3132

3233
class CLIENT(str, Enum):
@@ -202,9 +203,11 @@ async def _verify_async() -> bool: # noqa: C901
202203
proxy_remote: FastMCP[Any] | None = None
203204
host_remote: FastMCP[Any] | None = None
204205
try:
205-
proxy_remote = FastMCP.as_proxy(backend_cfg_remote)
206-
host_remote = FastMCP(name=f"open-edison-verify-host-{server.name}")
207-
host_remote.mount(proxy_remote, prefix=server.name)
206+
# TODO: In debug mode, do not suppress child process output.
207+
with suppress_fds(suppress_stdout=False, suppress_stderr=True):
208+
proxy_remote = FastMCP.as_proxy(backend_cfg_remote)
209+
host_remote = FastMCP(name=f"open-edison-verify-host-{server.name}")
210+
host_remote.mount(proxy_remote, prefix=server.name)
208211

209212
async def _list_tools_only() -> Any:
210213
return await host_remote._tool_manager.list_tools() # type: ignore[attr-defined]
@@ -233,21 +236,23 @@ async def _list_tools_only() -> Any:
233236
if oauth_info.status in (OAuthStatus.NEEDS_AUTH, OAuthStatus.AUTHENTICATED):
234237
return True
235238
# NOT_REQUIRED: quick unauthenticated ping
239+
# TODO: In debug mode, do not suppress child process output.
240+
questionary.print(f"Testing connection to '{server.name}'...", style="bold fg:ansigreen")
236241
log.debug(f"Establishing contact with remote server '{server.name}'")
237-
# Async timeout
238242
async with asyncio.timeout(connection_timeout):
239243
async with FastMCPClient(
240244
remote_url,
241245
auth=None,
242246
timeout=connection_timeout,
243247
init_timeout=connection_timeout,
244-
) as client: # type: ignore
248+
) as client:
245249
log.debug(f"Connection established to '{server.name}'; pinging...")
246-
await asyncio.wait_for(client.ping(), timeout=connection_timeout)
250+
with suppress_fds(suppress_stdout=True, suppress_stderr=True):
251+
await asyncio.wait_for(fut=client.ping(), timeout=1.0)
247252
log.info(f"Ping received from '{server.name}'; shutting down client")
248253
ping_succeeded = True
249254
log.debug(f"Client '{server.name}' shut down")
250-
return ping_succeeded
255+
return ping_succeeded
251256
except TimeoutError:
252257
if ping_succeeded:
253258
questionary.print(
@@ -281,9 +286,13 @@ async def _list_tools_only() -> Any:
281286
proxy_local: FastMCP[Any] | None = None
282287
host_local: FastMCP[Any] | None = None
283288
try:
284-
proxy_local = FastMCP.as_proxy(backend_cfg_local)
285-
host_local = FastMCP(name=f"open-edison-verify-host-{server.name}")
286-
host_local.mount(proxy_local, prefix=server.name)
289+
# TODO: In debug mode, do not suppress child process output.
290+
log.info("Checking properties of '{}'...", server.name)
291+
with suppress_fds(suppress_stdout=False, suppress_stderr=True):
292+
proxy_local = FastMCP.as_proxy(backend_cfg_local)
293+
host_local = FastMCP(name=f"open-edison-verify-host-{server.name}")
294+
host_local.mount(proxy_local, prefix=server.name)
295+
log.info("MCP properties check succeeded for '{}'", server.name)
287296

288297
async def _list_tools_only() -> Any:
289298
return await host_local._tool_manager.list_tools() # type: ignore[attr-defined]

src/tools/io.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
from __future__ import annotations
2+
3+
import os
4+
from collections.abc import Iterator
5+
from contextlib import contextmanager
6+
7+
8+
@contextmanager
9+
def suppress_fds(*, suppress_stdout: bool = False, suppress_stderr: bool = True) -> Iterator[None]:
10+
"""Temporarily redirect process-level stdout/stderr to os.devnull.
11+
12+
Args:
13+
suppress_stdout: If True, redirect fd 1 to devnull
14+
suppress_stderr: If True, redirect fd 2 to devnull
15+
16+
Yields:
17+
None
18+
"""
19+
saved: list[tuple[int, int]] = []
20+
try:
21+
if suppress_stdout:
22+
saved.append((1, os.dup(1)))
23+
devnull_out = os.open(os.devnull, os.O_WRONLY)
24+
os.dup2(devnull_out, 1)
25+
os.close(devnull_out)
26+
if suppress_stderr:
27+
saved.append((2, os.dup(2)))
28+
devnull_err = os.open(os.devnull, os.O_WRONLY)
29+
os.dup2(devnull_err, 2)
30+
os.close(devnull_err)
31+
yield
32+
finally:
33+
for fd, backup in saved:
34+
try:
35+
os.dup2(backup, fd)
36+
finally:
37+
os.close(backup)
38+
39+

0 commit comments

Comments
 (0)