diff --git a/autoassistant/mcp/server.py b/autoassistant/mcp/server.py index 1fa4891..9fd7732 100644 --- a/autoassistant/mcp/server.py +++ b/autoassistant/mcp/server.py @@ -10,13 +10,32 @@ into `output/`. """ +import contextlib import io import logging +import os import sys +from pathlib import Path from mcp.server.fastmcp import FastMCP, Image -from autoassistant.mcp import tools + +def _pin_config(): + """ + autonerves derives its config directory from the process working directory + (`conf.instance` defaults to `os.getcwd()/config`) and autofit reads config + at import time. A server launched from a foreign directory — e.g. a chat + client spawning `wsl.exe`, which lands in a Windows folder — would otherwise + scan unrelated files and crash on import (a `desktop.ini` trips configparser + interpolation). Pin the config to this assistant's own `config/` so the + server runs from any working directory. + """ + from autonerves import conf + + config_path = Path(__file__).resolve().parents[2] / "config" + conf.instance = conf.Config( + str(config_path), output_path=str(config_path.parent / "output") + ) def _route_logging_to_stderr(): @@ -37,6 +56,17 @@ def _route_logging_to_stderr(): handler.setStream(sys.stderr) +# Importing the tool modules imports autofit, which (a) reads autonerves config +# at import and (b) lets jax's xla_bridge log its backend probe to stdout — both +# fatal to the JSON-RPC channel. So, before that import: force CPU (skips the +# jax backend probe), pin the config so it does not depend on the launch +# directory, and redirect any residual import-time stdout to stderr. Rebind +# logging handlers afterwards for anything attached during import. +os.environ.setdefault("JAX_PLATFORMS", "cpu") +_pin_config() +with contextlib.redirect_stdout(sys.stderr): + from autoassistant.mcp import tools + _route_logging_to_stderr() mcp = FastMCP("pyauto-results-inspector") diff --git a/skills/af_inspect_results_mcp.md b/skills/af_inspect_results_mcp.md index 684a1a0..1cc01f7 100644 --- a/skills/af_inspect_results_mcp.md +++ b/skills/af_inspect_results_mcp.md @@ -62,6 +62,27 @@ propagates. Anything the stack needs (`PYTHONPATH` for editable/source checkouts `NUMBA_CACHE_DIR`/`MPLCONFIGDIR` in restricted setups) must be declared in the config's `env` block. +**Windows (Claude Desktop → WSL):** when the interpreter lives in WSL, launch it +through `wsl.exe`. Nothing beyond `PYTHONPATH` is required — the server pins its own +config directory and forces JAX onto CPU before importing autofit, so it does not +depend on the launch directory or extra environment: + +```json +{ + "mcpServers": { + "pyauto-results-inspector": { + "command": "wsl.exe", + "args": ["-e", "bash", "-c", + "PYTHONPATH=/home/you/autofit_assistant /home/you/venv/bin/python -m autoassistant.mcp"] + } + } +} +``` + +For the Microsoft Store build of Claude Desktop, the config and the failure log +(`logs/mcp-server-pyauto-results-inspector.log`) live under +`%LOCALAPPDATA%\Packages\Claude_*\LocalCache\Roaming\Claude\`, not `%APPDATA%\Claude\`. + **Claude Code**: the repo-root `.mcp.json` registers the same server automatically for sessions opened in this repo (marginal there — a Claude Code session can already run the aggregator in Python — but it costs nothing and exercises the same wiring).