fix(claudecode-mcp): write global MCP to documented ~/.claude.json path#1633
Open
sirmacik wants to merge 3 commits into
Open
fix(claudecode-mcp): write global MCP to documented ~/.claude.json path#1633sirmacik wants to merge 3 commits into
sirmacik wants to merge 3 commits into
Conversation
Per Claude Code docs (https://docs.claude.com/en/docs/claude-code/mcp), user-scope MCP servers are stored in `~/.claude.json` at HOME root — NOT inside `~/.claude/`. Earlier rulesync versions (≤ v8.17.0) wrote to the wrong path `~/.claude/.claude.json`. Issue dyoshikawa#1387 described this exact bug; it was closed by the reporter as "filed prematurely" but the root cause is still present in main. ## Changes ### src/features/mcp/claudecode-mcp.ts - `getSettablePaths({ global: true })` now returns the documented path `{ relativeDirPath: ".", relativeFilePath: ".claude.json" }`. - `fromFile` falls back to the legacy path `~/.claude/.claude.json` with a deprecation warning via the optional `logger` parameter when the recommended path is absent. Mirrors the backward-compatibility pattern established by PR dyoshikawa#333 (`RulesyncMcp.fromFile` for legacy `.rulesync/.mcp.json`). - `fromRulesyncMcp` always writes to the recommended path; the legacy file is never modified, deleted, or renamed by rulesync. ### Migration philosophy Rulesync intentionally does NOT actively migrate user files at legacy paths. The pattern is consistent with every prior legacy-path change in the project (dyoshikawa#333, commit 5787195): read-fallback + deprecation warning, never touch user data. Users who want to fully eliminate any ghost-MCP risk from Claude Code's runtime behavior should manually delete `~/.claude/.claude.json` after upgrading. ### Tests - `fromFile`: 5 new tests - prefers recommended path when both exist - falls back to legacy path with deprecation warning when only legacy exists - does NOT fall back to legacy in local mode - initializes empty mcpServers when neither file exists - works without a logger when reading the legacy path - `fromRulesyncMcp`: 4 tests - fresh install: initializes recommended path - does NOT modify legacy file (byte-identical assertion) - does not touch legacy file in local mode - preserves unrelated keys on `~/.claude.json` via RMW - Existing global-mode tests updated to assert the new path. ### E2E - Updated the global-MCP matrix entry: claudecode → `.claude.json`. - New test: `should preserve legacy ~/.claude/.claude.json when writing to recommended path (global)` — byte-identical legacy assertion at CLI level. ## Verification - `pnpm test src/features/mcp/claudecode-mcp.test.ts`: 56 tests pass. - `pnpm test:e2e src/e2e/e2e-mcp.spec.ts`: 47 tests pass. - `pnpm cicheck`: clean. ## Notes for upgrading users After upgrading, rulesync writes global MCP to `~/.claude.json` (the documented path). If you had a previous rulesync version that wrote to `~/.claude/.claude.json`, that file is left in place untouched. To fully eliminate any ghost-MCP risk from Claude Code's runtime behavior, manually delete the legacy file: rm ~/.claude/.claude.json ## Related - Closes dyoshikawa#1387 (was closed prematurely by reporter without fix). - Related-but-out-of-scope: dyoshikawa#1275 (`global` flag not passed to `ClaudecodeMcp` constructor) — separate concern, separate PR.
Contributor
|
Thank you for your contribution! Unfortunately, you currently have 3 open PRs (including this one), which exceeds the limit of 2 for external contributors. Please wait for an existing PR to be reviewed/merged, or close one before opening a new one. See CONTRIBUTING.md for details. |
Contributor
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This fixes Claude Code global MCP output to use the documented user-scope path:
~/.claude.json.Rulesync currently writes Claude Code global MCP to
~/.claude/.claude.json. That path worked in some environments, but it does not match Claude Code's documented MCP location and makes the generated config harder to audit, automate against, or reason about.Closes #1387.
Why this needs care
Claude Code is widely used, including in enterprise setups where config files may be managed, audited, backed up, or inspected by automation. We should fix the path bug without introducing a destructive migration.
Earlier drafts considered deleting or archiving the legacy file to prevent possible stale/ghost MCP entries. I backed away from that after checking rulesync's own precedent: PR #333 introduced legacy path handling for
.rulesync/.mcp.jsonby reading the legacy path with a deprecation warning, but never modifying it.This PR follows that same pattern.
Behavior after this change
fromRulesyncMcp({ global: true })writes to the documented path:~/.claude.jsonfromFile({ global: true })reads from:~/.claude.jsonfirst~/.claude/.claude.jsonif the recommended path is absentThis keeps the migration conservative: rulesync fixes its output path while leaving any user-owned legacy file untouched.
Notes for upgrading users
If you previously generated Claude Code global MCP with rulesync, you may have this legacy file:
~/.claude/.claude.jsonAfter upgrading, rulesync writes to:
~/.claude.jsonIf you want to fully avoid any risk of Claude Code reading stale MCP entries from the legacy path, manually inspect and remove the old file after confirming your new config is correct:
rm ~/.claude/.claude.jsonRulesync intentionally does not do this automatically.
Changes
ClaudecodeMcp.getSettablePaths({ global: true })to return:relativeDirPath: "."relativeFilePath: ".claude.json"ClaudecodeMcp.fromFile.fromRulesyncMcpwrite behavior focused on the recommended path only.~/.claude.jsonkeysVerification
pnpm test src/features/mcp/claudecode-mcp.test.tspnpm test:e2e src/e2e/e2e-mcp.spec.tspnpm cicheckAll pass locally.
Risk
Low-to-medium.
The path change is straightforward and matches Claude Code documentation. The main risk is upgrade behavior for users who already have the legacy file. To minimize that risk, this PR deliberately avoids destructive actions and follows the existing rulesync legacy-path precedent from PR #333.