From 592ad0ddabdcd5351364c0a2e333ab7cc762a8f2 Mon Sep 17 00:00:00 2001 From: Sebastien Tardif Date: Fri, 28 Aug 2026 07:59:37 -0700 Subject: [PATCH] fix: set native MCP server cwd to the workspace folder VS Code starts McpStdioServerDefinition in $HOME unless cwd is set. Relative MCP paths and --contain then apply to the home directory. Assign workspaceFolders[0].uri after the positional constructor. Signed-off-by: Sebastien Tardif --- AGENTS.md | 2 +- src/mcp/register.ts | 14 +++++++++++--- test/unit/mcpRegister.test.ts | 15 +++++++++++++++ 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 5d12644..0630b8a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -57,7 +57,7 @@ test/ managedLifecycle.test.ts Managed install with real file I/O (26 tests) mcpConfig.test.ts MCP config with real temp directories (14 tests) managedInstall.test.ts Managed Update compares latest vs managed binary (10 tests) - mcpRegister.test.ts Native MCP definition helper for binary path (2 tests) + mcpRegister.test.ts Native MCP definition helper for binary path (6 tests) statusRefresh.test.ts Status and MCP refresh order after input change (1 test) outputChannel.test.ts Output channel logging wrapper (22 tests) patchloomCli.test.ts Patchloom CLI integration with real binary + managed install e2e MCP (49 tests incl. e2e) diff --git a/src/mcp/register.ts b/src/mcp/register.ts index 5fd219c..ea60348 100644 --- a/src/mcp/register.ts +++ b/src/mcp/register.ts @@ -61,6 +61,8 @@ interface VsCodeLmWithMcp { interface VsCodeWithMcpApi { EventEmitter: typeof VSCode.EventEmitter; + Uri: { file(path: string): VSCode.Uri }; + workspace: { workspaceFolders?: readonly VSCode.WorkspaceFolder[] }; lm: VsCodeLmWithMcp; McpStdioServerDefinition?: McpStdioServerDefinitionCtor; } @@ -76,12 +78,17 @@ function mcpStdioCtor(vscode: VsCodeWithMcpApi): McpStdioServerDefinitionCtor | export function createMcpStdioServerDefinition( Ctor: McpStdioServerDefinitionCtor, - descriptor: McpServerBinaryDescriptor + descriptor: McpServerBinaryDescriptor, + cwd?: unknown ): unknown | undefined { const args = [...descriptor.args]; const env = descriptor.env ?? {}; try { - return new Ctor(descriptor.label, descriptor.command, args, env); + const definition = new Ctor(descriptor.label, descriptor.command, args, env); + if (cwd !== undefined && definition && typeof definition === "object") { + (definition as { cwd?: unknown }).cwd = cwd; + } + return definition; } catch { return undefined; } @@ -118,9 +125,10 @@ export async function registerMcpServerProviderWithBinary(context: VSCode.Extens onDidChangeMcpServerDefinitions: emitter.event, provideMcpServerDefinitions: async () => { const runtime = await getPatchloomRuntimeConfig(); + const workspaceCwd = vscode.workspace.workspaceFolders?.[0]?.uri; const definitions: unknown[] = []; for (const descriptor of mcpServerDefinitionsForBinary(resolvedBinaryPath, runtime.extraEnv)) { - const definition = createMcpStdioServerDefinition(Ctor, descriptor); + const definition = createMcpStdioServerDefinition(Ctor, descriptor, workspaceCwd); if (definition !== undefined) { definitions.push(definition); } diff --git a/test/unit/mcpRegister.test.ts b/test/unit/mcpRegister.test.ts index e274013..de2096f 100644 --- a/test/unit/mcpRegister.test.ts +++ b/test/unit/mcpRegister.test.ts @@ -6,6 +6,8 @@ import { } from "../../src/mcp/register.js"; class FakeStdio { + cwd?: { fsPath: string }; + constructor( public label: string, public command: string, @@ -58,3 +60,16 @@ test("createMcpStdioServerDefinition forwards PATCHLOOM env", () => { }) as FakeStdio; assert.equal(instance.env.PATCHLOOM_MCP_SURFACE, "core"); }); + +test("createMcpStdioServerDefinition assigns workspace cwd after construct", () => { + const instance = createMcpStdioServerDefinition( + FakeStdio, + { + label: "Patchloom MCP", + command: "/opt/patchloom", + args: ["mcp-server"] + }, + { fsPath: "/workspace/demo" } + ) as FakeStdio; + assert.equal(instance.cwd?.fsPath, "/workspace/demo"); +});