From 28a8eeb750c7a12a37c47b327472691465ae8f5d Mon Sep 17 00:00:00 2001 From: Sutu Sebastian Date: Wed, 27 May 2026 19:17:35 +0300 Subject: [PATCH 1/5] feat(agents): inject workspace root for VS Code MCP init VS Code / Copilot now get `--root ${workspaceFolder}` via agents init --mcp, matching Cursor so Copilot indexes the open workspace when spawn cwd differs. --- .changeset/vscode-mcp-workspace-root.md | 5 + docs/agents.md | 2 +- docs/plans/vscode-mcp-workspace-root.md | 154 ++++++++++++++++++++++++ src/agents-init-mcp-registry.ts | 3 +- src/agents-init-mcp.test.ts | 4 + src/agents-init-mcp.ts | 4 +- 6 files changed, 168 insertions(+), 4 deletions(-) create mode 100644 .changeset/vscode-mcp-workspace-root.md create mode 100644 docs/plans/vscode-mcp-workspace-root.md diff --git a/.changeset/vscode-mcp-workspace-root.md b/.changeset/vscode-mcp-workspace-root.md new file mode 100644 index 00000000..b79fa0ee --- /dev/null +++ b/.changeset/vscode-mcp-workspace-root.md @@ -0,0 +1,5 @@ +--- +"@stainless-code/codemap": patch +--- + +`codemap agents init --mcp` now includes `--root ${workspaceFolder}` in the VS Code / Copilot MCP config (`.vscode/mcp.json`), same as Cursor. diff --git a/docs/agents.md b/docs/agents.md index e8c3c9e1..1d3f4154 100644 --- a/docs/agents.md +++ b/docs/agents.md @@ -142,7 +142,7 @@ Example: `CODEMAP_MCP_TOOLS=query,context,show codemap mcp --no-watch` | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Cursor | `.cursor/mcp.json` — PM-resolved spawn + `mcp --watch --root ${workspaceFolder}` (e.g. `npx codemap`, `pnpm exec codemap`, `yarn exec codemap`, `bunx codemap`) | | Claude Code | `.mcp.json` + `.claude/settings.json` — `permissions.allow` includes `mcp__codemap__*` | -| VS Code / Copilot | `.vscode/mcp.json` — `servers.codemap` with `type: stdio` | +| VS Code / Copilot | `.vscode/mcp.json` — `servers.codemap` with `type: stdio` + `mcp --watch --root ${workspaceFolder}` (PM-resolved spawn, same tail as Cursor) | | Continue | `.continue/mcpServers/codemap-mcp.json` (JSON `mcpServers`; also accepted from Cursor/Cline exports) | | Amazon Q Developer | **`.amazonq/default.json`** (IDE canonical) + **`.amazonq/mcp.json`** (legacy workspace; still read when global `useLegacyMcpJson` is true — AWS default). [AWS MCP IDE docs](https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/mcp-ide.html) | | Gemini CLI | `.gemini/settings.json` — top-level `mcpServers.codemap` | diff --git a/docs/plans/vscode-mcp-workspace-root.md b/docs/plans/vscode-mcp-workspace-root.md new file mode 100644 index 00000000..06e42791 --- /dev/null +++ b/docs/plans/vscode-mcp-workspace-root.md @@ -0,0 +1,154 @@ +# VS Code MCP workspace root — handoff + +> **Status:** implemented (pending release) · **Priority:** P2 · **Effort:** S (~half day) · **Trigger:** fact-check from consumer repo + internal dogfood mismatch +> +> **Motivator:** `codemap agents init --mcp` injects `--root ${workspaceFolder}` for Cursor only. VS Code / Copilot gets `mcp --watch` with no explicit project root. That contradicts codemap's own `.vscode/mcp.json` and leaves index resolution to spawn `cwd` — a guarantee VS Code does not document. +> +> **Origin:** [merchant-dashboard-v2 PR #1569](https://github.com/PaySpaceDevs/merchant-dashboard-v2/pull/1569) — codemap 0.9.2 upgrade + MCP wiring review. + +--- + +## Summary for the next owner + +| Question | Answer | +| ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Is this a VS Code `${workspaceFolder}` resolution bug? | **No.** Init never writes the variable for VS Code; it is not failing to substitute. | +| Is codemap `init --mcp` accidentally broken? | **No.** Intentional registry flag — only Cursor has `workspaceRootArg: true`. | +| Is the VS Code scaffold **correct**? | **Weak / over-optimistic.** Official docs do not guarantee stdio spawn `cwd` = workspace root; codemap dogfoods `--root` on VS Code anyway. | +| Are consumer overrides wrong? | **No.** Keeping `--root ${workspaceFolder}` (and `--no-watch` where needed) on **both** `.cursor/mcp.json` and `.vscode/mcp.json` is the safer choice until upstream aligns. | + +**Recommended fix:** add explicit workspace-root wiring for the `vscode` MCP target (prefer **`workspaceRootArg: true`** for parity with Cursor and with this repo's dogfood config). + +--- + +## Current behavior (source of truth) + +### Registry + +`src/agents-init-mcp-registry.ts` — only **`cursor`** sets `workspaceRootArg: true`. **`vscode`** omits it (defaults false). + +### Spawn builder + +`src/codemap-invocation.ts` — `buildCodemapMcpSpawn(invocation, includeWorkspaceRoot)` appends `--root ${workspaceFolder}` only when the second arg is `true`. + +### Init comment + tests + +- `src/agents-init-mcp.ts` — _"Cursor uses `${workspaceFolder}` root injection; most other clients rely on workspace cwd."_ +- `src/agents-init-mcp.test.ts` — `"includes workspace root for Cursor"` vs `"omits --root for cwd-based clients"`. + +### Docs table gap + +`docs/agents.md` § MCP wiring — Cursor row documents `--root ${workspaceFolder}`; VS Code row only mentions `type: stdio` (does not state that `--root` is omitted by design). + +### Internal inconsistency (dogfood) + +This repository's **`.vscode/mcp.json`** already uses: + +```json +"args": ["src/index.ts", "mcp", "--watch", "--root", "${workspaceFolder}"] +``` + +So maintainers expect explicit `--root` on VS Code while `init --mcp` does not emit it for consumers. + +--- + +## Fact-check vs official docs + +### Codemap CLI semantics + +Per README § Environment / flags: **`--root`** overrides **`CODEMAP_ROOT`** / **`CODEMAP_TEST_BENCH`**, then **`process.cwd()`**. If spawn `cwd` is wrong, the index targets the wrong tree with no `--root`. + +Bundled skill (`templates/agent-content/skill/10-recipes-context.md`): _"spawn `cwd` is the project root unless `--root` overrides."_ + +### VS Code ([MCP configuration reference](https://code.visualstudio.com/docs/copilot/reference/mcp-configuration)) + +| Topic | Finding | +| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Stdio spawn **cwd** | **Not documented** as workspace root. Stdio field table lists `command`, `args`, `env`, `envFile`, sandbox — no guaranteed cwd semantics. | +| `${workspaceFolder}` in config | Documented for values like `envFile` and sandbox paths. | +| `${workspaceFolder}` in **args** | Intended to work (`${}` syntax per [variables reference](https://code.visualstudio.com/docs/reference/variables-reference)); real bugs reported — [vscode#245905](https://github.com/microsoft/vscode/issues/245905) (open), [vscode#251263](https://github.com/microsoft/vscode/issues/251263) (wrong `{workspaceFolder}` syntax vs `${workspaceFolder}`). | +| When cwd is wrong | Community workaround: `"cwd": "${workspaceFolder}"` on the server entry — [vscode#251308](https://github.com/microsoft/vscode/issues/251308) (devcontainer / PATH context). | + +**Conclusion:** Codemap's bet that VS Code stdio MCP **always** runs with workspace `cwd` is **not backed by official documentation** and is **contradicted by issue history** in edge environments (devcontainers, multi-root, remote). + +### Cursor ([MCP docs](https://cursor.com/docs/mcp)) + +- Documents **`${workspaceFolder}`** interpolation in `command`, `args`, `env`, `url`, `headers`. +- Defines it as the folder containing `.cursor/mcp.json`. +- Spawn / PATH issues are common (PM-aware `bunx` / `npx` fix in 0.9.2) — explicit `--root` is still valuable even when variables work. + +--- + +## Options (ranked) + +| # | Change | Pros | Cons | +| ----- | -------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | +| **A** | Set `workspaceRootArg: true` on **`vscode`** in registry | Parity with Cursor; matches dogfood `.vscode/mcp.json`; one code path; uses codemap-native `--root` | Relies on VS Code resolving `${workspaceFolder}` in args (same as Cursor today) | +| **B** | Add `"cwd": "${workspaceFolder}"` to VS Code server entry (keep args without `--root`) | Uses host cwd when variable works; codemap still reads `process.cwd()` | VS Code `cwd` field not in main stdio table (community pattern only); duplicate mechanism vs `--root` | +| **C** | `"env": { "CODEMAP_ROOT": "${workspaceFolder}" }` | Avoids codemap-specific flag in args | Less visible in logs; env substitution still subject to VS Code variable bugs | +| **D** | Document only — tell consumers to hand-patch | Zero code change | Leaves init scaffold wrong vs dogfood; repeats support burden | + +**Recommendation:** **A** (registry one-liner) + update **`docs/agents.md`** VS Code row + extend **`applyAgentsInitMcp`** integration test to assert VS Code args include `--root` and `${workspaceFolder}`. + +Optional follow-up: document **`--no-watch`** as a consumer override when file watcher hangs on large repos (out of scope for this plan's core fix). + +--- + +## Implementation steps + +1. **`src/agents-init-mcp-registry.ts`** — add `workspaceRootArg: true` to the `vscode` entry (or rename flag to `injectWorkspaceRootArg` if the Cursor-only comment is retired). +2. **`src/agents-init-mcp.test.ts`** — in `"writes all default project MCP files"`, assert `vscode.servers.codemap.args` contains `"--root"` and `"${workspaceFolder}"` (mirror Cursor assertions). +3. **`src/agents-init-mcp.ts`** — update the file comment: both Cursor and VS Code get explicit root injection; other cwd-based clients remain unchanged. +4. **`docs/agents.md`** — VS Code row: `servers.codemap` with `type: stdio` **and** `mcp --watch --root ${workspaceFolder}` (same spawn tail as Cursor, different JSON shape). +5. **Re-run** `bun test src/agents-init-mcp.test.ts` (and full `check` if touching registry exports). +6. **CHANGELOG** — patch note under `agents init --mcp` (VS Code workspace root parity). + +--- + +## Acceptance + +- [x] `applyAgentsInitMcp({ targets: ["vscode"] })` writes `--root` + `${workspaceFolder}` in `.vscode/mcp.json`. +- [x] Idempotent merge still preserves foreign servers in `servers`. +- [x] `docs/agents.md` MCP table matches registry behavior. +- [x] No change to Claude / Continue / Cline / Amazon Q / Gemini targets (remain cwd-based unless a separate issue opens). + +--- + +## Consumer guidance (until shipped) + +Projects that already override MCP config (example: large-repo `--no-watch`, explicit `--root` on both IDEs) should **keep overrides**. Re-running `init --mcp` without re-applying: + +- **`--no-watch`** — still required when watch hangs. +- **`--root ${workspaceFolder}`** on VS Code — still recommended until this plan ships. + +Do **not** assume `init --mcp` output is authoritative for VS Code root pinning today. + +--- + +## Related files + +| Path | Role | +| -------------------------------------- | ---------------------------------------------------------- | +| `src/agents-init-mcp-registry.ts` | Per-IDE flags | +| `src/agents-init-mcp.ts` | Init writer | +| `src/codemap-invocation.ts` | Spawn args builder | +| `src/agents-init-mcp.test.ts` | Regression tests | +| `docs/agents.md` | Consumer-facing MCP table | +| `.vscode/mcp.json` | Dogfood reference (already uses `--root`) | +| `docs/plans/cross-project-mcp-root.md` | Separate concern — multi-root tool `root` param at runtime | + +--- + +## Revisit / out of scope + +- **Multi-root MCP `root` tool argument** — see [cross-project-mcp-root.md](./cross-project-mcp-root.md). +- **Default `--no-watch` in init** — environment-specific; consumers override. +- **Fixing VS Code variable resolution bugs** — upstream vscode; codemap can only document workarounds (`cwd`, env, or absolute paths). + +--- + +## References + +- VS Code MCP config: +- Cursor MCP + interpolation: +- Codemap root precedence: [README § Environment / flags](../../README.md#cli) diff --git a/src/agents-init-mcp-registry.ts b/src/agents-init-mcp-registry.ts index 86de7697..a5ae6f6b 100644 --- a/src/agents-init-mcp-registry.ts +++ b/src/agents-init-mcp-registry.ts @@ -31,7 +31,7 @@ export interface AgentsInitMcpTargetDef { readonly docsUrl: string; /** Written by default when `--mcp` has no integration filter. */ readonly defaultOnMcp: boolean; - /** Cursor: inject `--root ${workspaceFolder}`. */ + /** Cursor / VS Code: inject `--root ${workspaceFolder}`. */ readonly workspaceRootArg?: boolean | undefined; /** Matching `agents init --interactive` integration pick, when any. */ readonly integrationTarget?: AgentsInitTarget | undefined; @@ -77,6 +77,7 @@ export const AGENTS_INIT_MCP_REGISTRY: readonly AgentsInitMcpTargetDef[] = docsUrl: "https://code.visualstudio.com/docs/copilot/reference/mcp-configuration", defaultOnMcp: true, + workspaceRootArg: true, integrationTarget: "copilot", }, { diff --git a/src/agents-init-mcp.test.ts b/src/agents-init-mcp.test.ts index b82af33c..bff9ad15 100644 --- a/src/agents-init-mcp.test.ts +++ b/src/agents-init-mcp.test.ts @@ -301,6 +301,10 @@ describe("applyAgentsInitMcp", () => { expect(vscode.servers[CODEMAP_MCP_SERVER_KEY]?.type).toBe("stdio"); expect(vscode.servers[CODEMAP_MCP_SERVER_KEY]?.command).toBe("npx"); expect(vscode.servers[CODEMAP_MCP_SERVER_KEY]?.args?.[0]).toBe("codemap"); + expect(vscode.servers[CODEMAP_MCP_SERVER_KEY]?.args).toContain("--root"); + expect(vscode.servers[CODEMAP_MCP_SERVER_KEY]?.args).toContain( + "${workspaceFolder}", + ); const amazonDefault = JSON.parse( readFileSync(join(dir, ".amazonq", "default.json"), "utf-8"), diff --git a/src/agents-init-mcp.ts b/src/agents-init-mcp.ts index ee5b46e8..bd7a5b35 100644 --- a/src/agents-init-mcp.ts +++ b/src/agents-init-mcp.ts @@ -434,8 +434,8 @@ export interface ApplyAgentsInitMcpOptions { } /** - * Write MCP config for selected integrations. Cursor uses - * `${workspaceFolder}` root injection; most other clients rely on workspace cwd. + * Write MCP config for selected integrations. Cursor and VS Code get + * `${workspaceFolder}` root injection; other cwd-based clients omit `--root`. */ export async function applyAgentsInitMcp( opts: ApplyAgentsInitMcpOptions, From 0d7cf9f7f21d31c88bc23c3b6b345d9a9a309854 Mon Sep 17 00:00:00 2001 From: Sutu Sebastian Date: Wed, 27 May 2026 19:19:19 +0300 Subject: [PATCH 2/5] test(agents): deepen VS Code MCP workspace-root coverage Address PR review: registry assertion, vscode-only/merge/upgrade tests, stale plan doc refresh, changeset migration note, CLI subprocess check. --- .changeset/vscode-mcp-workspace-root.md | 2 +- docs/plans/vscode-mcp-workspace-root.md | 66 ++++++----- src/agents-init-mcp-registry.test.ts | 8 ++ src/agents-init-mcp.test.ts | 140 ++++++++++++++++++++++-- src/agents-init-mcp.ts | 2 +- src/cli.test.ts | 6 + 6 files changed, 180 insertions(+), 44 deletions(-) diff --git a/.changeset/vscode-mcp-workspace-root.md b/.changeset/vscode-mcp-workspace-root.md index b79fa0ee..5208dd45 100644 --- a/.changeset/vscode-mcp-workspace-root.md +++ b/.changeset/vscode-mcp-workspace-root.md @@ -2,4 +2,4 @@ "@stainless-code/codemap": patch --- -`codemap agents init --mcp` now includes `--root ${workspaceFolder}` in the VS Code / Copilot MCP config (`.vscode/mcp.json`), same as Cursor. +`codemap agents init --mcp` now includes `--root ${workspaceFolder}` in the VS Code / Copilot MCP config (`.vscode/mcp.json`), same as Cursor. Re-run `codemap agents init --mcp` (or `--target copilot`) to upgrade an existing `.vscode/mcp.json` from older init output. diff --git a/docs/plans/vscode-mcp-workspace-root.md b/docs/plans/vscode-mcp-workspace-root.md index 06e42791..dab516c5 100644 --- a/docs/plans/vscode-mcp-workspace-root.md +++ b/docs/plans/vscode-mcp-workspace-root.md @@ -2,7 +2,7 @@ > **Status:** implemented (pending release) · **Priority:** P2 · **Effort:** S (~half day) · **Trigger:** fact-check from consumer repo + internal dogfood mismatch > -> **Motivator:** `codemap agents init --mcp` injects `--root ${workspaceFolder}` for Cursor only. VS Code / Copilot gets `mcp --watch` with no explicit project root. That contradicts codemap's own `.vscode/mcp.json` and leaves index resolution to spawn `cwd` — a guarantee VS Code does not document. +> **Motivator:** `codemap agents init --mcp` previously injected `--root ${workspaceFolder}` for Cursor only. VS Code / Copilot now gets the same explicit root (PR #156). Original trigger: consumer repo fact-check + internal dogfood mismatch. > > **Origin:** [merchant-dashboard-v2 PR #1569](https://github.com/PaySpaceDevs/merchant-dashboard-v2/pull/1569) — codemap 0.9.2 upgrade + MCP wiring review. @@ -10,45 +10,39 @@ ## Summary for the next owner -| Question | Answer | -| ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Is this a VS Code `${workspaceFolder}` resolution bug? | **No.** Init never writes the variable for VS Code; it is not failing to substitute. | -| Is codemap `init --mcp` accidentally broken? | **No.** Intentional registry flag — only Cursor has `workspaceRootArg: true`. | -| Is the VS Code scaffold **correct**? | **Weak / over-optimistic.** Official docs do not guarantee stdio spawn `cwd` = workspace root; codemap dogfoods `--root` on VS Code anyway. | -| Are consumer overrides wrong? | **No.** Keeping `--root ${workspaceFolder}` (and `--no-watch` where needed) on **both** `.cursor/mcp.json` and `.vscode/mcp.json` is the safer choice until upstream aligns. | +| Question | Answer | +| ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- | +| Is this a VS Code `${workspaceFolder}` resolution bug? | **No.** Init never failed to substitute — it simply did not write the variable for VS Code before this fix. | +| Is codemap `init --mcp` accidentally broken? | **Was an intentional registry gap** — only Cursor had `workspaceRootArg: true`. **Fixed:** both Cursor and VS Code set the flag. | +| Is the VS Code scaffold **correct**? | **Yes after fix.** Init emits `mcp --watch --root ${workspaceFolder}` on `.vscode/mcp.json`. | +| Are consumer overrides wrong? | **No.** Overrides like `--no-watch` remain valid. Re-run `init --mcp` to pick up `--root` if `.vscode/mcp.json` predates this fix. | **Recommended fix:** add explicit workspace-root wiring for the `vscode` MCP target (prefer **`workspaceRootArg: true`** for parity with Cursor and with this repo's dogfood config). --- -## Current behavior (source of truth) +## Shipped behavior (post PR #156) ### Registry -`src/agents-init-mcp-registry.ts` — only **`cursor`** sets `workspaceRootArg: true`. **`vscode`** omits it (defaults false). +`src/agents-init-mcp-registry.ts` — **`cursor`** and **`vscode`** set `workspaceRootArg: true`. ### Spawn builder -`src/codemap-invocation.ts` — `buildCodemapMcpSpawn(invocation, includeWorkspaceRoot)` appends `--root ${workspaceFolder}` only when the second arg is `true`. +`src/codemap-invocation.ts` — `buildCodemapMcpSpawn(invocation, includeWorkspaceRoot)` appends `--root ${workspaceFolder}` when the registry flag is true. -### Init comment + tests +### Init + tests -- `src/agents-init-mcp.ts` — _"Cursor uses `${workspaceFolder}` root injection; most other clients rely on workspace cwd."_ -- `src/agents-init-mcp.test.ts` — `"includes workspace root for Cursor"` vs `"omits --root for cwd-based clients"`. +- `src/agents-init-mcp.ts` — Cursor and VS Code get `${workspaceFolder}` root injection; cwd-based clients omit `--root`. +- `src/agents-init-mcp.test.ts` — vscode-only write/merge/idempotent/upgrade tests; integration test asserts full args array. -### Docs table gap +### Docs -`docs/agents.md` § MCP wiring — Cursor row documents `--root ${workspaceFolder}`; VS Code row only mentions `type: stdio` (does not state that `--root` is omitted by design). +`docs/agents.md` § MCP wiring — VS Code row documents `mcp --watch --root ${workspaceFolder}` (same spawn tail as Cursor, different JSON shape). -### Internal inconsistency (dogfood) +### Dogfood reference -This repository's **`.vscode/mcp.json`** already uses: - -```json -"args": ["src/index.ts", "mcp", "--watch", "--root", "${workspaceFolder}"] -``` - -So maintainers expect explicit `--root` on VS Code while `init --mcp` does not emit it for consumers. +This repository's **`.vscode/mcp.json`** uses explicit `--root ${workspaceFolder}` — now aligned with consumer init output. --- @@ -94,14 +88,14 @@ Optional follow-up: document **`--no-watch`** as a consumer override when file w --- -## Implementation steps +## Implementation steps (done) -1. **`src/agents-init-mcp-registry.ts`** — add `workspaceRootArg: true` to the `vscode` entry (or rename flag to `injectWorkspaceRootArg` if the Cursor-only comment is retired). -2. **`src/agents-init-mcp.test.ts`** — in `"writes all default project MCP files"`, assert `vscode.servers.codemap.args` contains `"--root"` and `"${workspaceFolder}"` (mirror Cursor assertions). -3. **`src/agents-init-mcp.ts`** — update the file comment: both Cursor and VS Code get explicit root injection; other cwd-based clients remain unchanged. -4. **`docs/agents.md`** — VS Code row: `servers.codemap` with `type: stdio` **and** `mcp --watch --root ${workspaceFolder}` (same spawn tail as Cursor, different JSON shape). -5. **Re-run** `bun test src/agents-init-mcp.test.ts` (and full `check` if touching registry exports). -6. **CHANGELOG** — patch note under `agents init --mcp` (VS Code workspace root parity). +1. [x] **`src/agents-init-mcp-registry.ts`** — `workspaceRootArg: true` on the `vscode` entry. +2. [x] **`src/agents-init-mcp.test.ts`** — assert VS Code args include `--root` and `${workspaceFolder}`. +3. [x] **`src/agents-init-mcp.ts`** — comment: Cursor and VS Code get explicit root injection. +4. [x] **`docs/agents.md`** — VS Code row updated. +5. [x] **`bun test src/agents-init-mcp.test.ts`** (+ registry/cli coverage). +6. [x] **Changeset** — patch note for npm release. --- @@ -114,14 +108,16 @@ Optional follow-up: document **`--no-watch`** as a consumer override when file w --- -## Consumer guidance (until shipped) +## Consumer guidance + +Projects with `.vscode/mcp.json` from **older** init output (no `--root`) should re-run **`codemap agents init --mcp`** (or target **`copilot`** only) to upsert the codemap server entry. Init merge is idempotent and preserves foreign `servers`. -Projects that already override MCP config (example: large-repo `--no-watch`, explicit `--root` on both IDEs) should **keep overrides**. Re-running `init --mcp` without re-applying: +Custom overrides remain valid: -- **`--no-watch`** — still required when watch hangs. -- **`--root ${workspaceFolder}`** on VS Code — still recommended until this plan ships. +- **`--no-watch`** — still required when watch hangs on large repos. +- **Hand-patched `--root ${workspaceFolder}`** — safe to keep; init will converge to the same args on re-run. -Do **not** assume `init --mcp` output is authoritative for VS Code root pinning today. +Do **not** assume VS Code stdio spawn `cwd` equals workspace root — official docs do not guarantee it (see fact-check below). --- diff --git a/src/agents-init-mcp-registry.test.ts b/src/agents-init-mcp-registry.test.ts index a70bb875..6d84c89f 100644 --- a/src/agents-init-mcp-registry.test.ts +++ b/src/agents-init-mcp-registry.test.ts @@ -10,6 +10,14 @@ import { } from "./agents-init-mcp-registry"; describe("AGENTS_INIT_MCP_REGISTRY", () => { + it("cursor and vscode inject workspace root via registry flag", () => { + expect(getAgentsInitMcpTargetDef("cursor").workspaceRootArg).toBe(true); + expect(getAgentsInitMcpTargetDef("vscode").workspaceRootArg).toBe(true); + expect( + getAgentsInitMcpTargetDef("claude-code").workspaceRootArg, + ).toBeUndefined(); + }); + it("has unique ids", () => { const ids = AGENTS_INIT_MCP_REGISTRY.map((def) => def.id); expect(new Set(ids).size).toBe(ids.length); diff --git a/src/agents-init-mcp.test.ts b/src/agents-init-mcp.test.ts index bff9ad15..dca3b49a 100644 --- a/src/agents-init-mcp.test.ts +++ b/src/agents-init-mcp.test.ts @@ -64,7 +64,7 @@ function seedBunInstalledCodemapProject(dir: string): void { } describe("buildCodemapMcpSpawn", () => { - it("includes workspace root for Cursor", () => { + it("includes workspace root when includeWorkspaceRoot is true", () => { expect(buildCodemapMcpSpawn(NPM_LOCAL_INVOCATION, true)).toEqual({ command: "npx", args: ["codemap", "mcp", "--watch", "--root", "${workspaceFolder}"], @@ -179,13 +179,13 @@ describe("mergeCodemapVsCodeServer", () => { other: { command: "npx", args: ["-y", "other"] }, }, }, - buildCodemapMcpSpawn(NPM_LOCAL_INVOCATION, false), + buildCodemapMcpSpawn(NPM_LOCAL_INVOCATION, true), ); expect(merged.servers?.other?.command).toBe("npx"); expect(merged.servers?.[CODEMAP_MCP_SERVER_KEY]).toEqual({ type: "stdio", command: "npx", - args: ["codemap", "mcp", "--watch"], + args: ["codemap", "mcp", "--watch", "--root", "${workspaceFolder}"], }); }); }); @@ -300,11 +300,13 @@ describe("applyAgentsInitMcp", () => { }; expect(vscode.servers[CODEMAP_MCP_SERVER_KEY]?.type).toBe("stdio"); expect(vscode.servers[CODEMAP_MCP_SERVER_KEY]?.command).toBe("npx"); - expect(vscode.servers[CODEMAP_MCP_SERVER_KEY]?.args?.[0]).toBe("codemap"); - expect(vscode.servers[CODEMAP_MCP_SERVER_KEY]?.args).toContain("--root"); - expect(vscode.servers[CODEMAP_MCP_SERVER_KEY]?.args).toContain( + expect(vscode.servers[CODEMAP_MCP_SERVER_KEY]?.args).toEqual([ + "codemap", + "mcp", + "--watch", + "--root", "${workspaceFolder}", - ); + ]); const amazonDefault = JSON.parse( readFileSync(join(dir, ".amazonq", "default.json"), "utf-8"), @@ -380,6 +382,31 @@ describe("applyAgentsInitMcp", () => { } }); + it("writes project .vscode/mcp.json when vscode target selected", async () => { + const dir = mkdtempSync(join(tmpdir(), "codemap-agents-mcp-vs-")); + try { + seedInstalledCodemapProject(dir); + await applyAgentsInitMcp({ projectRoot: dir, targets: ["vscode"] }); + expect(existsSync(join(dir, ".vscode", "mcp.json"))).toBe(true); + expect(existsSync(join(dir, ".cursor", "mcp.json"))).toBe(false); + const vscode = JSON.parse( + readFileSync(join(dir, ".vscode", "mcp.json"), "utf-8"), + ) as { + servers: Record< + string, + { type: string; command: string; args: string[] } + >; + }; + expect(vscode.servers[CODEMAP_MCP_SERVER_KEY]).toEqual({ + type: "stdio", + command: "npx", + args: ["codemap", "mcp", "--watch", "--root", "${workspaceFolder}"], + }); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); + it("writes project .cline/mcp.json when cline target selected", async () => { const dir = mkdtempSync(join(tmpdir(), "codemap-agents-mcp-cl-")); const fakeHome = mkdtempSync(join(tmpdir(), "codemap-agents-mcp-cl-home-")); @@ -451,6 +478,105 @@ describe("applyAgentsInitMcp", () => { } }); + it("merges into existing .vscode/mcp.json without clobbering other servers", async () => { + const dir = mkdtempSync(join(tmpdir(), "codemap-agents-mcp-vs-merge-")); + try { + seedInstalledCodemapProject(dir); + mkdirSync(join(dir, ".vscode"), { recursive: true }); + writeFileSync( + join(dir, ".vscode", "mcp.json"), + `${JSON.stringify( + { + servers: { + foreign: { type: "stdio", command: "node", args: ["server.js"] }, + }, + }, + null, + 2, + )}\n`, + "utf-8", + ); + await applyAgentsInitMcp({ projectRoot: dir, targets: ["vscode"] }); + const parsed = JSON.parse( + readFileSync(join(dir, ".vscode", "mcp.json"), "utf-8"), + ) as { + servers: Record< + string, + { type?: string; command: string; args: string[] } + >; + }; + expect(parsed.servers.foreign).toEqual({ + type: "stdio", + command: "node", + args: ["server.js"], + }); + expect(parsed.servers[CODEMAP_MCP_SERVER_KEY]?.args).toEqual([ + "codemap", + "mcp", + "--watch", + "--root", + "${workspaceFolder}", + ]); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); + + it("is idempotent on vscode re-run", async () => { + const dir = mkdtempSync(join(tmpdir(), "codemap-agents-mcp-vs-idem-")); + try { + seedInstalledCodemapProject(dir); + await applyAgentsInitMcp({ projectRoot: dir, targets: ["vscode"] }); + const before = readFileSync(join(dir, ".vscode", "mcp.json"), "utf-8"); + await applyAgentsInitMcp({ projectRoot: dir, targets: ["vscode"] }); + expect(readFileSync(join(dir, ".vscode", "mcp.json"), "utf-8")).toBe( + before, + ); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); + + it("upgrades stale vscode codemap entry without --root on re-run", async () => { + const dir = mkdtempSync(join(tmpdir(), "codemap-agents-mcp-vs-upgrade-")); + try { + seedInstalledCodemapProject(dir); + mkdirSync(join(dir, ".vscode"), { recursive: true }); + writeFileSync( + join(dir, ".vscode", "mcp.json"), + `${JSON.stringify( + { + servers: { + [CODEMAP_MCP_SERVER_KEY]: { + type: "stdio", + command: "npx", + args: ["codemap", "mcp", "--watch"], + }, + }, + }, + null, + 2, + )}\n`, + "utf-8", + ); + await applyAgentsInitMcp({ projectRoot: dir, targets: ["vscode"] }); + const parsed = JSON.parse( + readFileSync(join(dir, ".vscode", "mcp.json"), "utf-8"), + ) as { + servers: Record; + }; + expect(parsed.servers[CODEMAP_MCP_SERVER_KEY]?.args).toEqual([ + "codemap", + "mcp", + "--watch", + "--root", + "${workspaceFolder}", + ]); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); + it("merges into existing .cursor/mcp.json without clobbering other servers", async () => { const dir = mkdtempSync(join(tmpdir(), "codemap-agents-mcp-")); try { diff --git a/src/agents-init-mcp.ts b/src/agents-init-mcp.ts index bd7a5b35..2847a6e3 100644 --- a/src/agents-init-mcp.ts +++ b/src/agents-init-mcp.ts @@ -52,7 +52,7 @@ export interface ClaudeSettingsFile { }; } -/** Host-specific codemap MCP entry (Cursor root arg, Amazon Q IDE transport fields, …). */ +/** Host-specific codemap MCP entry (workspace-root arg, Amazon Q IDE transport fields, …). */ export function buildMcpServerEntryForDef( def: Pick, invocation: ResolvedCodemapInvocation, diff --git a/src/cli.test.ts b/src/cli.test.ts index ee41d27b..7449ad37 100644 --- a/src/cli.test.ts +++ b/src/cli.test.ts @@ -168,6 +168,12 @@ describe("CLI unknown / invalid args", () => { readFileSync(join(dir, ".cursor", "mcp.json"), "utf-8"), ) as { mcpServers: Record }; expect(parsed.mcpServers.codemap?.command).toBe("npx"); + expect(existsSync(join(dir, ".vscode", "mcp.json"))).toBe(true); + const vscode = JSON.parse( + readFileSync(join(dir, ".vscode", "mcp.json"), "utf-8"), + ) as { servers: Record }; + expect(vscode.servers.codemap?.args).toContain("--root"); + expect(vscode.servers.codemap?.args).toContain("${workspaceFolder}"); } finally { rmSync(dir, { recursive: true, force: true }); } From f682eb4617510dc5b409fe485b576fb6eee24cf5 Mon Sep 17 00:00:00 2001 From: Sutu Sebastian Date: Wed, 27 May 2026 19:20:19 +0300 Subject: [PATCH 3/5] docs(plans): mark vscode MCP root fix as shipped (Option A) Resolve plan doc contradiction post-implementation; rename CLI test title. --- docs/plans/vscode-mcp-workspace-root.md | 8 ++++---- src/cli.test.ts | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/plans/vscode-mcp-workspace-root.md b/docs/plans/vscode-mcp-workspace-root.md index dab516c5..08804d17 100644 --- a/docs/plans/vscode-mcp-workspace-root.md +++ b/docs/plans/vscode-mcp-workspace-root.md @@ -17,7 +17,7 @@ | Is the VS Code scaffold **correct**? | **Yes after fix.** Init emits `mcp --watch --root ${workspaceFolder}` on `.vscode/mcp.json`. | | Are consumer overrides wrong? | **No.** Overrides like `--no-watch` remain valid. Re-run `init --mcp` to pick up `--root` if `.vscode/mcp.json` predates this fix. | -**Recommended fix:** add explicit workspace-root wiring for the `vscode` MCP target (prefer **`workspaceRootArg: true`** for parity with Cursor and with this repo's dogfood config). +**Shipped fix:** Option **A** — `workspaceRootArg: true` on the `vscode` registry entry (parity with Cursor and dogfood `.vscode/mcp.json`). --- @@ -73,7 +73,7 @@ Bundled skill (`templates/agent-content/skill/10-recipes-context.md`): _"spawn ` --- -## Options (ranked) +## Options (decision record — **A** chosen) | # | Change | Pros | Cons | | ----- | -------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | @@ -82,7 +82,7 @@ Bundled skill (`templates/agent-content/skill/10-recipes-context.md`): _"spawn ` | **C** | `"env": { "CODEMAP_ROOT": "${workspaceFolder}" }` | Avoids codemap-specific flag in args | Less visible in logs; env substitution still subject to VS Code variable bugs | | **D** | Document only — tell consumers to hand-patch | Zero code change | Leaves init scaffold wrong vs dogfood; repeats support burden | -**Recommendation:** **A** (registry one-liner) + update **`docs/agents.md`** VS Code row + extend **`applyAgentsInitMcp`** integration test to assert VS Code args include `--root` and `${workspaceFolder}`. +**Chosen:** **A** — implemented in PR #156 (`workspaceRootArg: true` + docs/tests/changeset). Optional follow-up: document **`--no-watch`** as a consumer override when file watcher hangs on large repos (out of scope for this plan's core fix). @@ -117,7 +117,7 @@ Custom overrides remain valid: - **`--no-watch`** — still required when watch hangs on large repos. - **Hand-patched `--root ${workspaceFolder}`** — safe to keep; init will converge to the same args on re-run. -Do **not** assume VS Code stdio spawn `cwd` equals workspace root — official docs do not guarantee it (see fact-check below). +Do **not** assume VS Code stdio spawn `cwd` equals workspace root — official docs do not guarantee it (see [Fact-check vs official docs](#fact-check-vs-official-docs) above). --- diff --git a/src/cli.test.ts b/src/cli.test.ts index 7449ad37..0b3443f1 100644 --- a/src/cli.test.ts +++ b/src/cli.test.ts @@ -150,7 +150,7 @@ describe("CLI unknown / invalid args", () => { } }); - test("agents init --force --mcp writes .cursor/mcp.json under --root", async () => { + test("agents init --force --mcp writes project MCP configs under --root", async () => { const dir = mkdtempSync(join(tmpdir(), "codemap-cli-agents-mcp-")); try { const { exitCode, err } = await runCli([ From 399e1b6d686ec6396d9fd295a0ef492d10e5ccbe Mon Sep 17 00:00:00 2001 From: Sutu Sebastian Date: Wed, 27 May 2026 19:21:24 +0300 Subject: [PATCH 4/5] fix(docs): drop invalid --target copilot from migration text Copilot-only MCP wiring uses --interactive, not a --target flag. --- .changeset/vscode-mcp-workspace-root.md | 2 +- docs/plans/vscode-mcp-workspace-root.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/vscode-mcp-workspace-root.md b/.changeset/vscode-mcp-workspace-root.md index 5208dd45..86c7bfea 100644 --- a/.changeset/vscode-mcp-workspace-root.md +++ b/.changeset/vscode-mcp-workspace-root.md @@ -2,4 +2,4 @@ "@stainless-code/codemap": patch --- -`codemap agents init --mcp` now includes `--root ${workspaceFolder}` in the VS Code / Copilot MCP config (`.vscode/mcp.json`), same as Cursor. Re-run `codemap agents init --mcp` (or `--target copilot`) to upgrade an existing `.vscode/mcp.json` from older init output. +`codemap agents init --mcp` now includes `--root ${workspaceFolder}` in the VS Code / Copilot MCP config (`.vscode/mcp.json`), same as Cursor. Re-run `codemap agents init --mcp` to upgrade an existing `.vscode/mcp.json` from older init output (or `--interactive` and select Copilot only). diff --git a/docs/plans/vscode-mcp-workspace-root.md b/docs/plans/vscode-mcp-workspace-root.md index 08804d17..ffcf15bb 100644 --- a/docs/plans/vscode-mcp-workspace-root.md +++ b/docs/plans/vscode-mcp-workspace-root.md @@ -110,7 +110,7 @@ Optional follow-up: document **`--no-watch`** as a consumer override when file w ## Consumer guidance -Projects with `.vscode/mcp.json` from **older** init output (no `--root`) should re-run **`codemap agents init --mcp`** (or target **`copilot`** only) to upsert the codemap server entry. Init merge is idempotent and preserves foreign `servers`. +Projects with `.vscode/mcp.json` from **older** init output (no `--root`) should re-run **`codemap agents init --mcp`** (or **`--interactive`** and select Copilot only) to upsert the codemap server entry. Init merge is idempotent and preserves foreign `servers`. Custom overrides remain valid: From 5333c2b732e6774da549814ddcb5cb81da04321a Mon Sep 17 00:00:00 2001 From: Sutu Sebastian Date: Wed, 27 May 2026 19:24:16 +0300 Subject: [PATCH 5/5] docs(plans): retire vscode MCP workspace-root plan Lift migration + --root rationale into agents.md; delete shipped plan per docs-governance (delete + lift, no slim-and-keep in plans/). --- docs/agents.md | 2 +- docs/plans/vscode-mcp-workspace-root.md | 150 ------------------------ 2 files changed, 1 insertion(+), 151 deletions(-) delete mode 100644 docs/plans/vscode-mcp-workspace-root.md diff --git a/docs/agents.md b/docs/agents.md index 1d3f4154..488d4c8a 100644 --- a/docs/agents.md +++ b/docs/agents.md @@ -153,7 +153,7 @@ With **`--mcp`** and no `--target` filter, all **project-local** rows above are Merge is idempotent: foreign MCP servers and existing settings keys are preserved; only the `codemap` server entry and permission pattern are upserted. **`command` / spawn args are resolved from the project** (when `@stainless-code/codemap` is listed in `package.json`, the local PM runner is used — e.g. `pnpm exec codemap`, `yarn exec codemap`, `bunx codemap`; otherwise PM dlx of `@stainless-code/codemap@latest` — e.g. `npx @stainless-code/codemap@latest`, `pnpm dlx @stainless-code/codemap@latest`, `yarn dlx @stainless-code/codemap@latest`; yarn classic may fall back to `npx` per `package-manager-detector`; Bun uses **`bunx`**, not `bun x`). Init logs the chosen invocation (`MCP CLI: …`). -**Side-effect-only re-runs:** When `.agents/` already exists, `codemap agents init --mcp`, **`--interactive`** target wiring (or any explicit integration targets), or `--git-hooks` still apply without `--force`. `codemap agents init --no-git-hooks --mcp` uninstalls hook blocks and writes MCP even when `.agents/` is absent. Template refresh still requires `--force`. Unparseable MCP JSON and invalid `mcpServers` / `servers` **shape** are **rejected** (fix the file manually — init never wipes or resets those maps, even with `--force`). Foreign MCP servers in a valid map are always preserved on merge. +**Side-effect-only re-runs:** When `.agents/` already exists, `codemap agents init --mcp`, **`--interactive`** target wiring (or any explicit integration targets), or `--git-hooks` still apply without `--force`. `codemap agents init --no-git-hooks --mcp` uninstalls hook blocks and writes MCP even when `.agents/` is absent. Template refresh still requires `--force`. Unparseable MCP JSON and invalid `mcpServers` / `servers` **shape** are **rejected** (fix the file manually — init never wipes or resets those maps, even with `--force`). Foreign MCP servers in a valid map are always preserved on merge. Re-runs upsert the codemap server entry in place (e.g. add `--root ${workspaceFolder}` on VS Code when an older `.vscode/mcp.json` omitted it). Cursor and VS Code get explicit `--root` because host docs do not guarantee stdio spawn `cwd` equals the workspace folder. ## Section assembler and `*.gen.md` diff --git a/docs/plans/vscode-mcp-workspace-root.md b/docs/plans/vscode-mcp-workspace-root.md deleted file mode 100644 index ffcf15bb..00000000 --- a/docs/plans/vscode-mcp-workspace-root.md +++ /dev/null @@ -1,150 +0,0 @@ -# VS Code MCP workspace root — handoff - -> **Status:** implemented (pending release) · **Priority:** P2 · **Effort:** S (~half day) · **Trigger:** fact-check from consumer repo + internal dogfood mismatch -> -> **Motivator:** `codemap agents init --mcp` previously injected `--root ${workspaceFolder}` for Cursor only. VS Code / Copilot now gets the same explicit root (PR #156). Original trigger: consumer repo fact-check + internal dogfood mismatch. -> -> **Origin:** [merchant-dashboard-v2 PR #1569](https://github.com/PaySpaceDevs/merchant-dashboard-v2/pull/1569) — codemap 0.9.2 upgrade + MCP wiring review. - ---- - -## Summary for the next owner - -| Question | Answer | -| ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- | -| Is this a VS Code `${workspaceFolder}` resolution bug? | **No.** Init never failed to substitute — it simply did not write the variable for VS Code before this fix. | -| Is codemap `init --mcp` accidentally broken? | **Was an intentional registry gap** — only Cursor had `workspaceRootArg: true`. **Fixed:** both Cursor and VS Code set the flag. | -| Is the VS Code scaffold **correct**? | **Yes after fix.** Init emits `mcp --watch --root ${workspaceFolder}` on `.vscode/mcp.json`. | -| Are consumer overrides wrong? | **No.** Overrides like `--no-watch` remain valid. Re-run `init --mcp` to pick up `--root` if `.vscode/mcp.json` predates this fix. | - -**Shipped fix:** Option **A** — `workspaceRootArg: true` on the `vscode` registry entry (parity with Cursor and dogfood `.vscode/mcp.json`). - ---- - -## Shipped behavior (post PR #156) - -### Registry - -`src/agents-init-mcp-registry.ts` — **`cursor`** and **`vscode`** set `workspaceRootArg: true`. - -### Spawn builder - -`src/codemap-invocation.ts` — `buildCodemapMcpSpawn(invocation, includeWorkspaceRoot)` appends `--root ${workspaceFolder}` when the registry flag is true. - -### Init + tests - -- `src/agents-init-mcp.ts` — Cursor and VS Code get `${workspaceFolder}` root injection; cwd-based clients omit `--root`. -- `src/agents-init-mcp.test.ts` — vscode-only write/merge/idempotent/upgrade tests; integration test asserts full args array. - -### Docs - -`docs/agents.md` § MCP wiring — VS Code row documents `mcp --watch --root ${workspaceFolder}` (same spawn tail as Cursor, different JSON shape). - -### Dogfood reference - -This repository's **`.vscode/mcp.json`** uses explicit `--root ${workspaceFolder}` — now aligned with consumer init output. - ---- - -## Fact-check vs official docs - -### Codemap CLI semantics - -Per README § Environment / flags: **`--root`** overrides **`CODEMAP_ROOT`** / **`CODEMAP_TEST_BENCH`**, then **`process.cwd()`**. If spawn `cwd` is wrong, the index targets the wrong tree with no `--root`. - -Bundled skill (`templates/agent-content/skill/10-recipes-context.md`): _"spawn `cwd` is the project root unless `--root` overrides."_ - -### VS Code ([MCP configuration reference](https://code.visualstudio.com/docs/copilot/reference/mcp-configuration)) - -| Topic | Finding | -| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Stdio spawn **cwd** | **Not documented** as workspace root. Stdio field table lists `command`, `args`, `env`, `envFile`, sandbox — no guaranteed cwd semantics. | -| `${workspaceFolder}` in config | Documented for values like `envFile` and sandbox paths. | -| `${workspaceFolder}` in **args** | Intended to work (`${}` syntax per [variables reference](https://code.visualstudio.com/docs/reference/variables-reference)); real bugs reported — [vscode#245905](https://github.com/microsoft/vscode/issues/245905) (open), [vscode#251263](https://github.com/microsoft/vscode/issues/251263) (wrong `{workspaceFolder}` syntax vs `${workspaceFolder}`). | -| When cwd is wrong | Community workaround: `"cwd": "${workspaceFolder}"` on the server entry — [vscode#251308](https://github.com/microsoft/vscode/issues/251308) (devcontainer / PATH context). | - -**Conclusion:** Codemap's bet that VS Code stdio MCP **always** runs with workspace `cwd` is **not backed by official documentation** and is **contradicted by issue history** in edge environments (devcontainers, multi-root, remote). - -### Cursor ([MCP docs](https://cursor.com/docs/mcp)) - -- Documents **`${workspaceFolder}`** interpolation in `command`, `args`, `env`, `url`, `headers`. -- Defines it as the folder containing `.cursor/mcp.json`. -- Spawn / PATH issues are common (PM-aware `bunx` / `npx` fix in 0.9.2) — explicit `--root` is still valuable even when variables work. - ---- - -## Options (decision record — **A** chosen) - -| # | Change | Pros | Cons | -| ----- | -------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | -| **A** | Set `workspaceRootArg: true` on **`vscode`** in registry | Parity with Cursor; matches dogfood `.vscode/mcp.json`; one code path; uses codemap-native `--root` | Relies on VS Code resolving `${workspaceFolder}` in args (same as Cursor today) | -| **B** | Add `"cwd": "${workspaceFolder}"` to VS Code server entry (keep args without `--root`) | Uses host cwd when variable works; codemap still reads `process.cwd()` | VS Code `cwd` field not in main stdio table (community pattern only); duplicate mechanism vs `--root` | -| **C** | `"env": { "CODEMAP_ROOT": "${workspaceFolder}" }` | Avoids codemap-specific flag in args | Less visible in logs; env substitution still subject to VS Code variable bugs | -| **D** | Document only — tell consumers to hand-patch | Zero code change | Leaves init scaffold wrong vs dogfood; repeats support burden | - -**Chosen:** **A** — implemented in PR #156 (`workspaceRootArg: true` + docs/tests/changeset). - -Optional follow-up: document **`--no-watch`** as a consumer override when file watcher hangs on large repos (out of scope for this plan's core fix). - ---- - -## Implementation steps (done) - -1. [x] **`src/agents-init-mcp-registry.ts`** — `workspaceRootArg: true` on the `vscode` entry. -2. [x] **`src/agents-init-mcp.test.ts`** — assert VS Code args include `--root` and `${workspaceFolder}`. -3. [x] **`src/agents-init-mcp.ts`** — comment: Cursor and VS Code get explicit root injection. -4. [x] **`docs/agents.md`** — VS Code row updated. -5. [x] **`bun test src/agents-init-mcp.test.ts`** (+ registry/cli coverage). -6. [x] **Changeset** — patch note for npm release. - ---- - -## Acceptance - -- [x] `applyAgentsInitMcp({ targets: ["vscode"] })` writes `--root` + `${workspaceFolder}` in `.vscode/mcp.json`. -- [x] Idempotent merge still preserves foreign servers in `servers`. -- [x] `docs/agents.md` MCP table matches registry behavior. -- [x] No change to Claude / Continue / Cline / Amazon Q / Gemini targets (remain cwd-based unless a separate issue opens). - ---- - -## Consumer guidance - -Projects with `.vscode/mcp.json` from **older** init output (no `--root`) should re-run **`codemap agents init --mcp`** (or **`--interactive`** and select Copilot only) to upsert the codemap server entry. Init merge is idempotent and preserves foreign `servers`. - -Custom overrides remain valid: - -- **`--no-watch`** — still required when watch hangs on large repos. -- **Hand-patched `--root ${workspaceFolder}`** — safe to keep; init will converge to the same args on re-run. - -Do **not** assume VS Code stdio spawn `cwd` equals workspace root — official docs do not guarantee it (see [Fact-check vs official docs](#fact-check-vs-official-docs) above). - ---- - -## Related files - -| Path | Role | -| -------------------------------------- | ---------------------------------------------------------- | -| `src/agents-init-mcp-registry.ts` | Per-IDE flags | -| `src/agents-init-mcp.ts` | Init writer | -| `src/codemap-invocation.ts` | Spawn args builder | -| `src/agents-init-mcp.test.ts` | Regression tests | -| `docs/agents.md` | Consumer-facing MCP table | -| `.vscode/mcp.json` | Dogfood reference (already uses `--root`) | -| `docs/plans/cross-project-mcp-root.md` | Separate concern — multi-root tool `root` param at runtime | - ---- - -## Revisit / out of scope - -- **Multi-root MCP `root` tool argument** — see [cross-project-mcp-root.md](./cross-project-mcp-root.md). -- **Default `--no-watch` in init** — environment-specific; consumers override. -- **Fixing VS Code variable resolution bugs** — upstream vscode; codemap can only document workarounds (`cwd`, env, or absolute paths). - ---- - -## References - -- VS Code MCP config: -- Cursor MCP + interpolation: -- Codemap root precedence: [README § Environment / flags](../../README.md#cli)