headroom/tests/test_cli/test_mcp_status.py
Eyal Mizrachi 9e376afabe
fix(mcp): mcp status checks ~/.claude.json, not only ~/.claude/mcp.json (#990)
## Description

`headroom mcp status` only inspected `~/.claude/mcp.json`, but servers
registered via `claude mcp add` (user scope) live in `~/.claude.json`.
So `status` printed `✗ No config file` even when headroom was registered
and `claude mcp list` reported it Connected. This detects the
registration across every location Claude Code uses.

## Type of Change

- [x] Bug fix (non-breaking change that fixes an issue)

## Changes Made

- Add `find_headroom_registration()` that checks `~/.claude.json`,
`~/.claude/mcp.json`, then `./.mcp.json` (first match wins).
- Use it in `mcp status` for both the "Configured" check and the
proxy-URL lookup.

## Testing

- [x] Unit tests pass (`pytest`)
- [x] New tests added for new functionality
- [x] Manual testing performed

### Test Output

```text
$ pytest tests/test_cli/test_mcp_status.py -q
5 passed in 0.13s
```

## Real Behavior Proof

- Environment: Linux, Python 3.13, editable build of this branch
- Exact command / steps: registered headroom in ~/.claude.json, then ran
`headroom mcp status`
- Observed result: prints `✓ Configured` with the ~/.claude.json path
(previously `✗ No config file`)
- Not tested: project-scoped ./.mcp.json discovery in a real multi-repo
workflow

## Review Readiness

- [x] I have performed a self-review
- [x] This PR is ready for human review

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: JerrettDavis <mxjerrett@gmail.com>
2026-07-15 09:25:52 -05:00

89 lines
3.1 KiB
Python

from __future__ import annotations
import json
from pathlib import Path
import pytest
from headroom.cli import mcp as mcp_cli
def _write_servers(path: Path, servers: dict) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps({"mcpServers": servers}), encoding="utf-8")
def test_find_registration_in_claude_json(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
claude_json = tmp_path / ".claude.json"
_write_servers(
claude_json,
{
"headroom": {
"command": "headroom",
"args": ["mcp", "serve"],
"env": {"HEADROOM_PROXY_URL": "http://x:1"},
}
},
)
monkeypatch.setattr(mcp_cli, "CLAUDE_JSON_PATH", claude_json)
monkeypatch.setattr(mcp_cli, "MCP_CONFIG_PATH", tmp_path / ".claude" / "mcp.json")
monkeypatch.chdir(tmp_path)
found = mcp_cli.find_headroom_registration()
assert found is not None
path, cfg = found
assert path == claude_json
assert cfg["env"]["HEADROOM_PROXY_URL"] == "http://x:1"
def test_find_registration_falls_back_to_mcp_json(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
mcp_json = tmp_path / "mcp.json"
_write_servers(mcp_json, {"headroom": {"command": "headroom"}})
monkeypatch.setattr(mcp_cli, "CLAUDE_JSON_PATH", tmp_path / ".claude.json") # absent
monkeypatch.setattr(mcp_cli, "MCP_CONFIG_PATH", mcp_json)
monkeypatch.chdir(tmp_path)
found = mcp_cli.find_headroom_registration()
assert found is not None and found[0] == mcp_json
def test_find_registration_prefers_claude_json(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
claude_json = tmp_path / ".claude.json"
mcp_json = tmp_path / "mcp.json"
_write_servers(claude_json, {"headroom": {"command": "a"}})
_write_servers(mcp_json, {"headroom": {"command": "b"}})
monkeypatch.setattr(mcp_cli, "CLAUDE_JSON_PATH", claude_json)
monkeypatch.setattr(mcp_cli, "MCP_CONFIG_PATH", mcp_json)
monkeypatch.chdir(tmp_path)
found = mcp_cli.find_headroom_registration()
assert found is not None and found[0] == claude_json # ~/.claude.json takes precedence
def test_find_registration_none_when_absent(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
monkeypatch.setattr(mcp_cli, "CLAUDE_JSON_PATH", tmp_path / ".claude.json")
monkeypatch.setattr(mcp_cli, "MCP_CONFIG_PATH", tmp_path / "mcp.json")
monkeypatch.chdir(tmp_path)
assert mcp_cli.find_headroom_registration() is None
def test_find_registration_skips_malformed_json(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
claude_json = tmp_path / ".claude.json"
claude_json.write_text("{ not valid json", encoding="utf-8")
mcp_json = tmp_path / "mcp.json"
_write_servers(mcp_json, {"headroom": {"command": "ok"}})
monkeypatch.setattr(mcp_cli, "CLAUDE_JSON_PATH", claude_json)
monkeypatch.setattr(mcp_cli, "MCP_CONFIG_PATH", mcp_json)
monkeypatch.chdir(tmp_path)
found = mcp_cli.find_headroom_registration()
assert found is not None and found[0] == mcp_json # malformed file skipped, next match used