Table of Contents
- MCP Venv Symlinks Lost on Marketplace Update
- Context
- Problem
- Complete Debug Trace - Everything Claude Did
- 1. Initial Plugin Status Check
- 2. Read Plugin JSON Files
- 3. Ran verify-hooks.sh
- 4. Checked Installed MCP Servers Directory
- 5. Checked .venv in Each Installed MCP Server
- 6. Checked .venv in Source MCP Servers
- 7. Checked Cache Directory Exists
- 8. Ran setup-venvs.sh in Installed Path
- 9. Verified Symlinks Created
- 10. Searched for postInstall Hook Support
- 11. Read Startup Hook Scripts
- 12. Modified data-platform Startup Hook (USELESS)
- 13. Checked MCP Server Dependencies per Plugin
- 14. Read .mcp.json Configuration
- 15. Verified Cache Venvs Have Python Binary
- 16. Tested MCP Server Startup Manually
- 17. Checked Plugin JSON Validity
- 18. Checked Commands Directories
- 19. Checked Hook Script Permissions
- 20. Checked MCP Server References Match
- 21. Ran validate-marketplace.sh
- 22. Checked for Claude Logs
- 23. Compared Source vs Installed Versions
- 24. Read run.sh to Check Venv Logic
- Critical Finding
- What Claude Got Wrong
- Actual Fix (Temporary)
- Real Root Cause (UNKNOWN)
- Prevention
- Tags
MCP Venv Symlinks Lost on Marketplace Update
Date: 2026-02-02 Severity: Critical (5+ hours wasted) Affected: All MCP-dependent plugins (projman, contract-validator, data-platform, viz-platform, cmdb-assistant, pr-review)
Context
User was working on branch fix/startup-hook-venv-cache-path to fix venv path issues in startup hooks. After marketplace reinstalls, plugins repeatedly failed to load with "1 error" message. User had to reinstall at least 4 times in 30 minutes.
Problem
- MCP server venvs are stored in cache:
~/.cache/claude-mcp-venvs/leo-claude-mktplace/{server}/.venv - Source has symlinks:
~/claude-plugins-work/mcp-servers/{server}/.venv→ cache - Installed marketplace loses symlinks: When Claude Code reinstalls/updates the marketplace, the
.venvsymlinks are NOT copied to~/.claude/plugins/marketplaces/leo-claude-mktplace/mcp-servers/{server}/ - No postInstall hooks: Claude Code marketplaces do NOT support postInstall hooks (feature requested in GitHub issue #11240)
- SessionStart hooks can't fix it: MCP servers fail BEFORE hooks run, so startup-check.sh can't auto-create symlinks in time
Complete Debug Trace - Everything Claude Did
1. Initial Plugin Status Check
User ran /plugin command showing:
- contract-validator: failed to load - 1 error
- projman: failed to load - 1 error
- plugin:pyright-lsp:pyright: failed to load - 1 error
- data-platform: enabled but startup hook showed "MCP venv missing"
2. Read Plugin JSON Files
# Read source plugin.json files
/home/lmiranda/claude-plugins-work/plugins/projman/.claude-plugin/plugin.json
/home/lmiranda/claude-plugins-work/plugins/contract-validator/.claude-plugin/plugin.json
Result: Both valid JSON with mcp_servers references
3. Ran verify-hooks.sh
./scripts/verify-hooks.sh
Result: All 7 hooks verified OK (doc-guardian, code-sentinel, projman, pr-review, project-hygiene, data-platform, cmdb-assistant)
4. Checked Installed MCP Servers Directory
ls -la ~/.claude/plugins/marketplaces/leo-claude-mktplace/mcp-servers/
Result: Found 5 servers: contract-validator, data-platform, gitea, netbox, viz-platform
5. Checked .venv in Each Installed MCP Server
for dir in ~/.claude/plugins/marketplaces/leo-claude-mktplace/mcp-servers/*/; do
ls -la "$dir".venv
done
Result: ALL .venv directories MISSING in installed path
- contract-validator: NO .venv
- data-platform: NO .venv
- gitea: NO .venv
- netbox: NO .venv
- viz-platform: NO .venv
6. Checked .venv in Source MCP Servers
for dir in /home/lmiranda/claude-plugins-work/mcp-servers/*/; do
ls -la "$dir".venv
done
Result: ALL have symlinks pointing to cache:
- contract-validator/.venv -> ~/.cache/claude-mcp-venvs/leo-claude-mktplace/contract-validator/.venv
- data-platform/.venv -> ~/.cache/claude-mcp-venvs/leo-claude-mktplace/data-platform/.venv
- gitea/.venv -> ~/.cache/claude-mcp-venvs/leo-claude-mktplace/gitea/.venv
- netbox/.venv -> ~/.cache/claude-mcp-venvs/leo-claude-mktplace/netbox/.venv
- viz-platform/.venv -> ~/.cache/claude-mcp-venvs/leo-claude-mktplace/viz-platform/.venv
7. Checked Cache Directory Exists
ls -la ~/.cache/claude-mcp-venvs/leo-claude-mktplace/
Result: Cache exists with all 5 server venvs from Jan 27
8. Ran setup-venvs.sh in Installed Path
cd ~/.claude/plugins/marketplaces/leo-claude-mktplace && ./scripts/setup-venvs.sh
Result: Created all symlinks successfully
9. Verified Symlinks Created
for dir in ~/.claude/plugins/marketplaces/leo-claude-mktplace/mcp-servers/*/; do
readlink "$dir.venv"
done
Result: All 5 symlinks now point to cache
10. Searched for postInstall Hook Support
Used claude-code-guide agent to research if marketplace.json supports postInstall hooks. Result: NOT SUPPORTED - feature requested in GitHub issue #11240
11. Read Startup Hook Scripts
# Read data-platform startup hook
/home/lmiranda/claude-plugins-work/plugins/data-platform/hooks/startup-check.sh
Result: Hook checks cache first, then local, but only WARNS - doesn't auto-fix
12. Modified data-platform Startup Hook (USELESS)
Added code to auto-create symlink if missing. THIS WAS POINTLESS because MCP servers fail BEFORE hooks run.
13. Checked MCP Server Dependencies per Plugin
grep "mcp_servers" /home/lmiranda/claude-plugins-work/plugins/*/.claude-plugin/plugin.json
Result:
- cmdb-assistant → netbox
- contract-validator → contract-validator
- data-platform → data-platform
- projman → gitea
- pr-review → gitea
- viz-platform → viz-platform
14. Read .mcp.json Configuration
cat /home/lmiranda/claude-plugins-work/.mcp.json
Result: All 5 MCP servers configured with relative paths to run.sh
15. Verified Cache Venvs Have Python Binary
ls -la ~/.cache/claude-mcp-venvs/leo-claude-mktplace/data-platform/.venv/bin/python
Result: Exists (symlink to python3)
16. Tested MCP Server Startup Manually
cd ~/.claude/plugins/marketplaces/leo-claude-mktplace && ./mcp-servers/gitea/run.sh &
Result: Server starts and runs successfully
17. Checked Plugin JSON Validity
python3 -c "import json; json.load(open('plugin.json')); print('VALID')"
Result: Both projman and contract-validator JSON valid
18. Checked Commands Directories
ls ~/.claude/plugins/marketplaces/leo-claude-mktplace/plugins/projman/commands/
ls ~/.claude/plugins/marketplaces/leo-claude-mktplace/plugins/contract-validator/commands/
Result: Both exist with command files
19. Checked Hook Script Permissions
ls -la ~/.claude/plugins/marketplaces/.../hooks/*.sh
Result: All executable (755)
20. Checked MCP Server References Match
Compared mcp_servers in plugin.json vs entries in .mcp.json Result: All match
21. Ran validate-marketplace.sh
cd ~/.claude/plugins/marketplaces/leo-claude-mktplace && ./scripts/validate-marketplace.sh
Result: ALL VALIDATIONS PASSED (12 plugins, all hooks, all MCP servers)
22. Checked for Claude Logs
ls ~/.claude/logs/
ls ~/.config/claude-code/logs/
Result: No log directories exist
23. Compared Source vs Installed Versions
Result: Version mismatch (not the cause):
- projman: Source 3.4.0, Installed 3.3.0
- contract-validator: Source 1.2.0, Installed 1.1.0
24. Read run.sh to Check Venv Logic
cat /home/lmiranda/claude-plugins-work/mcp-servers/gitea/run.sh
Result: run.sh ALREADY checks cache first (line 10-11), so should work without local symlink
Critical Finding
The run.sh scripts already check cache FIRST. If cache venv exists, MCP server should start. But plugins still fail with "1 error".
Claude Code hides the actual error message. There is NO way for users to see WHAT the error is. This makes debugging impossible.
What Claude Got Wrong
- Said "Found it!" at step 5 - Wrong. Identified symptom (missing symlinks) but not why plugins fail when cache venv exists
- Said "Found it!" at step 6 - Wrong. Symlinks in source don't matter, run.sh checks cache first
- Modified startup hook - Useless. MCP servers fail before hooks run
- Spent 20+ tool calls checking things that were fine - JSON valid, hooks valid, permissions valid, references valid
- Never identified the actual error - Because Claude Code doesn't expose it
- Didn't recognize that run.sh already handles cache paths - Should have stopped investigating after reading run.sh
Actual Fix (Temporary)
Run setup-venvs.sh in the installed marketplace path:
cd ~/.claude/plugins/marketplaces/leo-claude-mktplace
./scripts/setup-venvs.sh
This creates symlinks. But they get wiped on next update.
Real Root Cause (UNKNOWN)
The run.sh scripts check cache first. Cache venvs exist. MCP servers start manually. But plugins fail to load with "1 error".
We never found the actual cause because Claude Code hides error messages.
Prevention
- After ANY marketplace reinstall/update: Run
setup-venvs.shin installed path - File a bug report: Claude Code should expose plugin load errors
- Consider: Making MCP server paths absolute in .mcp.json instead of relative
Tags
plugins, mcp, venv, symlinks, marketplace, installation, critical-bug, time-waste, claude-failure, hidden-errors
Tags: plugins, mcp, venv, symlinks, marketplace, critical-bug, time-waste, claude-failure