Skip to content

Commit 6b19ec4

Browse files
cdeustclaude
andauthored
fix(mcp): ${CLAUDE_PLUGIN_ROOT} substitution + cortex-doctor mcp diagnostic (#22)
* fix(mcp): robust .mcp.json + cortex-doctor mcp diagnostic (v3.15.2) Discord user reported MCP server "✘ failed" with no actionable error. Root cause: .mcp.json used a fragile Python -c one-liner that swallowed launcher startup errors and depended on installed_plugins.json having a specific key shape that breaks across plugin upgrades, custom marketplace names, and missing python3 symlinks. Fixes: - .mcp.json now uses ${CLAUDE_PLUGIN_ROOT}/scripts/launcher.py — Anthropic's documented plugin substitution variable, already used by every hook in this repo (.claude/hooks/hooks.json). The launcher self-orients via __file__ so manual installs continue to work (backward compatible). - New `cortex-doctor mcp` subcommand: end-to-end MCP startup diagnostics. Tells the user exactly which check failed, what command/path was tried, and the actual error string — no more silent failures. Use --json for Discord-paste-friendly output. - 36 new tests (test_doctor_mcp.py + scripts/test_launcher_resolution.py) cover happy path + every named failure mode (missing plugins.json, missing key, stale installPath, missing launcher, broken launcher, unset DATABASE_URL). Plus 6 contract tests guarding .mcp.json shape against regression to the inline `-c` wrapper. Backward compatible: - `cortex-doctor` (no args) preserves legacy full-setup verification. - launcher.py still self-orients via __file__ for manual installs. Platform-agnostic: no Windows/Mac-specific code paths. Bumps: pyproject.toml + .claude-plugin/marketplace.json → 3.15.2; CHANGELOG entry added. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(mcp): add cortex-doctor mcp + launcher tests + v3.15.2 bump Completes the v3.15.2 release started in fbf9354 (which only captured .mcp.json + the contract test due to a staging hiccup): - mcp_server/doctor_mcp.py — new module implementing `cortex-doctor mcp` end-to-end MCP startup diagnostics. Each check reports the exact command/path attempted and the actual error string; supports --json for Discord-paste-friendly output. Covers: python interpreter on PATH, installed_plugins.json shape, CLAUDE_PLUGIN_ROOT env, launcher smoke probe (catches errors the old `-c` wrapper hid), DATABASE_URL, PG reachability, pgvector/pg_trgm extensions, critical Python deps, and optional sentence-transformers/flashrank/tree-sitter. - mcp_server/doctor.py — adds subcommand dispatch. `cortex-doctor` (no args) preserves legacy full-setup verification; `cortex-doctor mcp` routes to doctor_mcp.run_mcp. - tests_py/test_doctor_mcp.py + tests_py/scripts/test_launcher_resolution.py — 49 new tests covering happy path + every named failure mode (missing plugins.json, missing key, stale installPath, missing/broken launcher, unset/invalid DATABASE_URL, env-var-set/unset/invalid for launcher resolution). - pyproject.toml + .claude-plugin/marketplace.json → 3.15.2. - CHANGELOG.md — entry documenting the Discord report and the fix. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(deps): pin tree-sitter-language-pack <1.7 + ruff format CI fix Two CI gates failing on PR #22 — both are latent / dep-drift issues, not introduced by the v3.15.2 fixes themselves. tree-sitter-language-pack 1.7.0+ changed Parser API; pip resolves >=0.24.0 to the latest (1.8.0 on CI right now), breaking 'parser.parse(...)' calls in tests_py/core/test_ast_*.py and tests_py/benchmarks/test_codebase_alteration.py with 'builtins.Parser has no attribute parse'. Pinning <1.7 keeps the contract that v3.15.2 was tested against. The latent break would also hit main on its next CI run; this commit protects both. Lint failure on tests_py/scripts/test_mcp_json_contract.py was a stale ruff format from the parallel-agent merge. --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 308ed41 commit 6b19ec4

10 files changed

Lines changed: 1407 additions & 12 deletions

File tree

.claude-plugin/marketplace.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@
66
},
77
"metadata": {
88
"description": "Persistent memory and cognitive profiling plugins for Claude Code",
9-
"version": "3.15.1"
9+
"version": "3.15.2"
1010
},
1111
"plugins": [
1212
{
1313
"name": "cortex",
1414
"source": "./",
1515
"description": "Persistent memory and cognitive profiling for Claude Code — thermodynamic memory with heat/decay, intent-aware retrieval, biological plasticity, codebase intelligence, and cognitive profiling. 47 MCP tools with enriched schemas. PostgreSQL + pgvector in CLI mode; automatic SQLite fallback in Cowork/sandboxed mode. Curated wiki (ADRs, specs, lessons) with audit-artefact filtering. Consolidate is set-based SQL batched — decay/plasticity/pruning run 100-500× faster on large stores. Workflow graph with caller-qualified CALLS chains rendering full method-to-method dependencies (native tree-sitter, no AP required). Side panel humanized for non-technical users. Ingests codebase analysis (ai-automatised-pipeline) and PRDs (prd-spec-generator) into wiki + memory + knowledge graph. Docker image available.",
16-
"version": "3.15.1",
16+
"version": "3.15.2",
1717
"author": {
1818
"name": "Clement Deust",
1919
"email": "admin@ai-architect.tools"

.mcp.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
"cortex": {
44
"command": "python3",
55
"args": [
6-
"-c",
7-
"import json,os; p=json.load(open(os.path.expanduser('~/.claude/plugins/installed_plugins.json')))['plugins']['cortex@cortex-plugins'][0]['installPath']; os.execvp('python3',['python3',os.path.join(p,'scripts','launcher.py'),'mcp_server'])"
6+
"${CLAUDE_PLUGIN_ROOT}/scripts/launcher.py",
7+
"mcp_server"
88
],
99
"env": {
1010
"DATABASE_URL": "postgresql://localhost:5432/cortex",

CHANGELOG.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,37 @@ adheres to [Semantic Versioning](https://semver.org/).
66

77
## [Unreleased]
88

9+
## [3.15.2] - 2026-05-09
10+
11+
### Fixed
12+
- **MCP startup robustness** — Discord user reported the Cortex MCP server
13+
failing to start with no actionable error. Root cause: `.mcp.json` used a
14+
fragile `python -c` one-liner that read `~/.claude/plugins/installed_plugins.json`
15+
to dynamically resolve the install path. The wrapper swallowed all
16+
launcher startup errors invisibly and broke under: (a) plugin upgrade
17+
leaving stale `installPath`, (b) custom marketplace install names, (c)
18+
`python3` not on PATH, (d) any `installed_plugins.json` shape change by
19+
Claude Code. `.mcp.json` now uses `${CLAUDE_PLUGIN_ROOT}/scripts/launcher.py`
20+
— Anthropic's documented plugin substitution variable, already used by
21+
every hook in this repo. The launcher self-orients via `__file__` so
22+
manual installs continue to work.
23+
24+
### Added
25+
- **`cortex-doctor mcp`** — new diagnostic subcommand for end-to-end MCP
26+
startup checks. Tells the user *exactly* which check failed, what
27+
command/path was tried, and the actual error string — no more silent
28+
"✘ failed". Checks: python interpreter on PATH, `installed_plugins.json`
29+
shape, `CLAUDE_PLUGIN_ROOT` env, launcher smoke probe (catches errors
30+
the old `-c` wrapper hid), `DATABASE_URL`, critical Python deps. Use
31+
`--json` for Discord-paste-friendly output.
32+
33+
### Verification
34+
- 36 new tests added (`tests_py/test_doctor_mcp.py`,
35+
`tests_py/scripts/test_launcher_resolution.py`); all pass.
36+
- Backward-compatible: `cortex-doctor` (no subcommand) preserves legacy
37+
full-setup verification behaviour.
38+
- Platform-agnostic: no Windows/Mac-specific code paths.
39+
940
## [3.15.1] - 2026-05-05
1041

1142
### Fixed

mcp_server/doctor.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -271,12 +271,29 @@ def _i10_config() -> Check:
271271

272272

273273
def run() -> int:
274-
"""Run all checks. Print a report. Return 0 on required-green, 1 otherwise.
275-
276-
Optional checks (``Check.optional=True``) warn on failure but do not
277-
cause a non-zero exit. Only core-required checks (PG connection,
278-
Python version, etc.) gate the exit code.
274+
"""Entry point. Dispatches to subcommand if given, else full check.
275+
276+
Subcommands:
277+
(none) Full setup verification (Python, PG, extensions, etc.)
278+
mcp MCP startup diagnostics (Discord-debug-friendly)
279+
Flags:
280+
--json Emit machine-readable JSON report
281+
--copy Prepend a "paste me in Discord" header to the
282+
human output (useful for issue templates)
279283
"""
284+
argv = sys.argv[1:]
285+
if argv and argv[0] == "mcp":
286+
from mcp_server.doctor_mcp import run_mcp
287+
288+
flags = argv[1:]
289+
json_output = "--json" in flags
290+
copy_header = "--copy" in flags
291+
return run_mcp(json_output=json_output, copy_header=copy_header)
292+
return _run_full_check()
293+
294+
295+
def _run_full_check() -> int:
296+
"""Full setup verification (legacy `cortex-doctor` behaviour)."""
280297
checks = [c() for c in CHECKS]
281298
width = max(len(c.name) for c in checks) + 2
282299

0 commit comments

Comments
 (0)