fix mcp-server review feedback from thread

Agent-Logs-Url: https://github.com/meshtastic/firmware/sessions/91dc128a-ed50-4d07-8bb2-3dc6623a05f7

Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-04-17 22:33:41 +00:00
committed by GitHub
co-authored by thebentern
parent ec3c8378ef
commit bab808cf62
9 changed files with 72 additions and 28 deletions
+14 -6
View File
@@ -10,6 +10,7 @@ artifacts to exist, so these tools build first if needed.
from __future__ import annotations
import subprocess
import threading
import time
from pathlib import Path
from typing import Any
@@ -308,7 +309,7 @@ def _do_1200bps_touch(port: str, settle_ms: int, touch_timeout_s: float = 3.0) -
worker that's still blocked in the background after timeout has already
delivered the signal.
"""
import concurrent.futures
errors: list[BaseException] = []
def _inner() -> None:
try:
@@ -325,12 +326,19 @@ def _do_1200bps_touch(port: str, settle_ms: int, touch_timeout_s: float = 3.0) -
except Exception:
pass
with concurrent.futures.ThreadPoolExecutor(max_workers=1) as pool:
future = pool.submit(_inner)
def _runner() -> None:
try:
future.result(timeout=touch_timeout_s)
except concurrent.futures.TimeoutError:
pass # signal already delivered; worker thread leaks harmlessly
_inner()
except BaseException as exc: # re-raised on caller thread after join
errors.append(exc)
worker = threading.Thread(target=_runner, daemon=True)
worker.start()
worker.join(timeout=touch_timeout_s)
if worker.is_alive():
return # signal already delivered; allow daemon worker to finish/exit
if errors:
raise errors[0]
# Adafruit nRF52 bootloader VID/PID (BOTH RAK4631 and most Feather nRF52 boards).
+9 -10
View File
@@ -54,18 +54,17 @@ def all_sessions() -> list[SerialSession]:
def sweep_dead() -> int:
"""Remove sessions whose subprocess has exited. Returns count removed."""
removed = 0
removed_sessions: list[SerialSession] = []
with _LOCK:
for sid in list(_sessions):
s = _sessions[sid]
for sid, s in list(_sessions.items()):
if s.proc.poll() is not None:
# Leave the session object around for one read so callers can
# see eof=True. We only remove after stopped_at is older than
# a few seconds, so an immediate poll-after-close still sees
# it. For v1 simpler: just leave dead sessions until explicit
# close. No-op.
pass
return removed
removed_sessions.append(_sessions.pop(sid))
for session in removed_sessions:
try:
close_session(session)
except Exception:
pass
return len(removed_sessions)
def shutdown_all() -> None:
@@ -19,7 +19,7 @@ import uuid
from dataclasses import dataclass, field
from typing import Any
from . import config, pio
from . import boards, config, pio
_BUFFER_MAX_LINES = 10_000
_POLL_NEW_PORT_TIMEOUT_S = 3.0
@@ -76,7 +76,43 @@ def open_session(
effective_baud: int = baud
if env is not None:
args.extend(["-e", env])
effective_filters = filters or [] # pio will fill in from env
raw_config: dict[str, Any] = {}
try:
raw = boards.get_board(env).get("raw_config")
if isinstance(raw, dict):
raw_config = raw
except Exception:
raw_config = {}
monitor_speed = raw_config.get("monitor_speed")
has_board_speed = False
if monitor_speed is not None:
try:
effective_baud = int(str(monitor_speed).strip())
has_board_speed = True
except (TypeError, ValueError):
pass
monitor_filters_raw = raw_config.get("monitor_filters")
parsed_board_filters: list[str] = []
if isinstance(monitor_filters_raw, str):
for token in monitor_filters_raw.replace("\n", ",").split(","):
item = token.strip()
if item:
parsed_board_filters.append(item)
elif isinstance(monitor_filters_raw, list):
parsed_board_filters = [
str(item).strip() for item in monitor_filters_raw if str(item).strip()
]
has_board_filters = len(parsed_board_filters) > 0
effective_filters = parsed_board_filters if has_board_filters else (filters or [])
if not has_board_speed:
args.extend(["--baud", str(effective_baud)])
if not has_board_filters:
for f in effective_filters:
args.extend(["--filter", f])
else:
args.extend(["--baud", str(baud)])
effective_filters = filters or ["direct"]
+1 -1
View File
@@ -1,4 +1,4 @@
"""FastMCP server wiring — 32 tools across 6 categories.
"""FastMCP server wiring — 38 tools across 7 categories.
Each tool handler is a thin delegation to a named module (pio.py, admin.py,
etc.). Business logic does not live here.