feat(mcp): register headroom MCP server with dsh (DeepSeek Harness) - #3036
feat(mcp): register headroom MCP server with dsh (DeepSeek Harness)#3036Zenjibad wants to merge 31 commits into
Conversation
JerrettDavis
left a comment
There was a problem hiding this comment.
The happy-path registrar tests pass, but the file parser needs to fail safely before this is ready. _read_block() assumes that any start marker has a matching end marker and calls text.index(_MARKER_END, start) unguarded. A realistic interrupted/truncated prior write makes both headroom mcp install and uninstall raise ValueError instead of returning a controlled FAILED result. I reproduced this with a cordis.patch.yml containing only # --- Headroom MCP server ---; register_server() crashes at dsh.py:77.
Malformed fenced YAML is also currently treated as “no existing server,” after which registration appends a second managed block. The first corrupt block remains first, so future reads keep seeing it and the user file is made harder to recover. Please treat an incomplete or unparsable owned block as corrupt managed state: refuse to append/overwrite without explicit force (and return a useful FAILED/MISMATCH detail), make unregister handle it deliberately, and add regressions for an unmatched start marker and malformed fenced YAML while proving unrelated patch bytes remain unchanged. Since this mutates a user-owned config, an atomic replacement for rewrite paths would also avoid creating the exact truncated state on interruption.
PR governanceThis PR follows the template and is marked ready for human review. |
|
Addressed the review feedback:
Regressions added in
12 tests pass; |
|
Also added full Serena parity on top of the corrupt-state fixes (addressing the same reviewer thread, plus the 'full parity' scope):
|
|
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
The marker-fenced block is appended directly after the existing patch
text. When cordis.patch.yml does not end with a newline, the start marker
glues onto the last line ('...3080# --- Headroom MCP server ---') and the
marker becomes part of a YAML comment. Normalize the base text to end with
a newline before appending in both register_server and unregister_server.
Description
Adds a
DshRegistrarsoheadroom mcp installalso registers headroom's MCP server (headroom_compress/headroom_retrieve/headroom_stats) with DeepSeek Harness. It writes the@deepseek-ai/dsh-mcp-clientrow into dsh's$DSH_HOME/cordis.patch.yml.Depends on #2994.
Closes # (no issue)
Type of Change
Changes Made
headroom/mcp_registry/dsh.py—DshRegistrar(detect/register/unregister, marker-fenced YAML block).headroom/mcp_registry/install.py— registerDshRegistraringet_all_registrars().tests/test_mcp_registry_dsh.py— 7 unit tests.Testing
pytest)ruff check .)ruff format --check .)Test Output
Real Behavior Proof
uv run python -m pytest tests/test_mcp_registry_dsh.py -q; a liveDshRegistrar().register_server(...)against a temp$DSH_HOME; anddsh --profile headless --patch <patch>.memorix.cordis.ymlshape;get_serverround-trips. Live boot:@deepseek-ai/dsh-mcp-clientspawnsheadroom mcp serve; the model listsmcp__headroom__headroom_compress|retrieve|statsand, with a real key, callsheadroom_compressand returns the compressed output + hash (a76e1fa6…).headroom_retrieve/headroom_statsagainst a live proxy (they need the proxy running).Runtime Rollout Safety
headroom mcp uninstall.headroom mcp uninstall.Review Readiness
Checklist
CHANGELOG.mdAdditional Notes
@deepseek-ai/dsh-mcp-clientships with@deepseek-ai/dsh(verified — a dependency, no separate install).headroom mcp serveneeds the[mcp]extra (included in the[proxy]extra);retrieve/statsneed the proxy running.