diff --git a/core/framework/llm/litellm.py b/core/framework/llm/litellm.py index 9fd7f5ac..923f3ac2 100644 --- a/core/framework/llm/litellm.py +++ b/core/framework/llm/litellm.py @@ -2346,10 +2346,6 @@ class LiteLLMProvider(LLMProvider): kwargs["extra_body"]["store"] = False request_summary = _summarize_request_for_log(kwargs) - logger.debug( - "[stream] prepared request: %s", - json.dumps(request_summary, default=str), - ) if request_summary["system_only"]: logger.warning( "[stream] %s request has no non-system chat messages " diff --git a/core/framework/loader/mcp_registry.py b/core/framework/loader/mcp_registry.py index c9f7fdbe..82f6d30c 100644 --- a/core/framework/loader/mcp_registry.py +++ b/core/framework/loader/mcp_registry.py @@ -137,6 +137,13 @@ class MCPRegistry: Skips entirely when the source-tree ``tools/`` directory cannot be located (e.g. wheel installs). Returns the list of names that were newly registered. + + Also runs a self-heal pass over already-registered defaults: if an + entry's stdio cwd is unreachable on this machine (e.g. the registry + was copied from another developer's box and points at their + ``/Users//...`` path), the entry is overwritten with the + canonical config so the queen can actually spawn it. The user's + ``enabled`` toggle and ``overrides`` are preserved. """ # parents: [0]=loader, [1]=framework, [2]=core, [3]=repo root tools_dir = Path(__file__).resolve().parents[3] / "tools" @@ -165,8 +172,32 @@ class MCPRegistry: ) del existing[stale] mutated = True + + repaired: list[str] = [] + for name, spec in _DEFAULT_LOCAL_SERVERS.items(): + entry = existing.get(name) + if entry is None: + continue + if self._default_entry_runnable(entry, tools_dir, list(spec["args"])): + continue + existing[name] = self._build_default_entry( + name=name, + spec=spec, + cwd=cwd, + preserve_from=entry, + ) + repaired.append(name) + mutated = True + if mutated: self._write_installed(data) + if repaired: + logger.warning( + "MCPRegistry._seed_defaults: repaired %d default server(s) with " + "unreachable cwd/script: %s", + len(repaired), + repaired, + ) for name, spec in _DEFAULT_LOCAL_SERVERS.items(): if name in existing: @@ -188,6 +219,93 @@ class MCPRegistry: logger.info("MCPRegistry: seeded default local servers: %s", added) return added + @staticmethod + def _default_entry_runnable( + entry: dict, tools_dir: Path, canonical_args: list[str] + ) -> bool: + """Return True iff ``entry`` can plausibly be spawned on this machine. + + Checks: + - transport is stdio (only stdio defaults exist today; non-stdio + gets a free pass since we have nothing to compare against) + - stdio.cwd is an existing directory + - the entry script (the first ``.py`` arg, e.g. ``files_server.py``) + exists relative to that cwd + + We deliberately do NOT spawn the subprocess here — this runs on + every read path and must be cheap. A filesystem reachability + check catches the cross-machine `cwd` drift that is the common + failure, without flapping on transient runtime errors. + """ + transport = entry.get("transport") or "stdio" + if transport != "stdio": + return True + manifest = entry.get("manifest") or {} + stdio = manifest.get("stdio") or {} + cwd_str = stdio.get("cwd") + if not cwd_str: + return False + cwd_path = Path(cwd_str) + if not cwd_path.is_dir(): + return False + # Find the script: the first arg ending in .py, falling back to the + # canonical spec if the registered args are unrecognizable. Modules + # invoked via `python -m foo.bar` (no .py arg) are accepted as long + # as the cwd exists — we can't cheaply prove the module imports. + registered_args = stdio.get("args") or [] + script: str | None = next( + (a for a in registered_args if isinstance(a, str) and a.endswith(".py")), + None, + ) + if script is None: + script = next( + (a for a in canonical_args if isinstance(a, str) and a.endswith(".py")), + None, + ) + if script is None: + return True + return (cwd_path / script).is_file() + + @classmethod + def _build_default_entry( + cls, + *, + name: str, + spec: dict[str, Any], + cwd: str, + preserve_from: dict | None, + ) -> dict: + """Construct a fresh canonical entry for a default server. + + When ``preserve_from`` is provided, carries over the user's + ``enabled`` flag and ``overrides`` so a deliberate disable or + custom env var survives the repair. + """ + manifest = { + "name": name, + "description": spec["description"], + "transport": {"supported": ["stdio"], "default": "stdio"}, + "stdio": { + "command": "uv", + "args": list(spec["args"]), + "env": {}, + "cwd": cwd, + }, + } + entry = cls._make_entry( + source="local", + manifest=manifest, + transport="stdio", + installed_by="hive mcp init (auto-repair)", + ) + if preserve_from is not None: + if "enabled" in preserve_from: + entry["enabled"] = bool(preserve_from["enabled"]) + prior_overrides = preserve_from.get("overrides") + if isinstance(prior_overrides, dict): + entry["overrides"] = prior_overrides + return entry + # ── Internal I/O ──────────────────────────────────────────────── def _read_installed(self) -> dict: