From 01d7200e7bf6d94e812d60cf03ec43063a1d403e Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Mon, 30 Mar 2026 15:51:37 -0400 Subject: [PATCH] fix: copy mcp.json into auto-mode worktrees (#2791) (#3251) Add mcp.json to ROOT_STATE_FILES and copyPlanningArtifacts so MCP server configurations are available inside worktrees. Co-authored-by: Claude Opus 4.6 --- src/resources/extensions/gsd/auto-worktree.ts | 2 + .../tests/integration/auto-worktree.test.ts | 59 +++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/src/resources/extensions/gsd/auto-worktree.ts b/src/resources/extensions/gsd/auto-worktree.ts index f86e4f6bc..ad27e2f20 100644 --- a/src/resources/extensions/gsd/auto-worktree.ts +++ b/src/resources/extensions/gsd/auto-worktree.ts @@ -84,6 +84,7 @@ const ROOT_STATE_FILES = [ "QUEUE.md", "completed-units.json", "metrics.json", + "mcp.json", // NOTE: project preferences are intentionally NOT in ROOT_STATE_FILES. // Forward-sync (main → worktree) is handled explicitly in syncGsdStateToWorktree(). // Back-sync (worktree → main) must NEVER overwrite the project root's copy @@ -1078,6 +1079,7 @@ function copyPlanningArtifacts(srcBase: string, wtPath: string): void { "STATE.md", "KNOWLEDGE.md", "OVERRIDES.md", + "mcp.json", ]) { safeCopy(join(srcGsd, file), join(dstGsd, file), { force: true }); } diff --git a/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts b/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts index 38aa285b6..500fe6329 100644 --- a/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +++ b/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts @@ -20,6 +20,7 @@ import { enterAutoWorktree, getAutoWorktreeOriginalBase, getActiveAutoWorktreeContext, + syncGsdStateToWorktree, } from "../../auto-worktree.ts"; // Note: execSync is used intentionally in tests for git operations with @@ -286,4 +287,62 @@ describe("auto-worktree lifecycle", () => { teardownAutoWorktree(tempDir, "M004"); } }); + + test("#2791: mcp.json copied into worktree via copyPlanningArtifacts", () => { + tempDir = createTempRepo(); + const msDir = join(tempDir, ".gsd", "milestones", "M003"); + mkdirSync(msDir, { recursive: true }); + writeFileSync(join(msDir, "CONTEXT.md"), "# M003 Context\n"); + run("git add .", tempDir); + run("git commit -m \"add milestone\"", tempDir); + + // Create mcp.json in .gsd/ AFTER the commit (untracked, like real usage). + // copyPlanningArtifacts should copy it into the worktree's .gsd/. + writeFileSync( + join(tempDir, ".gsd", "mcp.json"), + JSON.stringify({ servers: { test: { command: "echo" } } }), + ); + + const wtPath = createAutoWorktree(tempDir, "M003"); + + try { + assert.ok( + existsSync(join(wtPath, ".gsd", "mcp.json")), + "mcp.json should be copied into worktree .gsd/ on creation", + ); + } finally { + teardownAutoWorktree(tempDir, "M003"); + } + }); + + test("#2791: mcp.json synced via syncGsdStateToWorktree (ROOT_STATE_FILES)", () => { + tempDir = createTempRepo(); + const msDir = join(tempDir, ".gsd", "milestones", "M003"); + mkdirSync(msDir, { recursive: true }); + writeFileSync(join(msDir, "CONTEXT.md"), "# M003 Context\n"); + run("git add .", tempDir); + run("git commit -m \"add milestone\"", tempDir); + + // Create worktree first (no mcp.json yet) + const wtPath = createAutoWorktree(tempDir, "M003"); + + try { + // Now add mcp.json to the main .gsd/ after worktree was created + writeFileSync( + join(tempDir, ".gsd", "mcp.json"), + JSON.stringify({ servers: { test: { command: "echo" } } }), + ); + + // Sync should pick up the new mcp.json + const { synced } = syncGsdStateToWorktree(tempDir, wtPath); + + assert.ok(synced.includes("mcp.json"), "mcp.json should be in the synced list"); + assert.ok( + existsSync(join(wtPath, ".gsd", "mcp.json")), + "mcp.json should exist in worktree after sync", + ); + } finally { + teardownAutoWorktree(tempDir, "M003"); + } + }); });