Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
14 changes: 11 additions & 3 deletions src/mcp/register.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand Down Expand Up @@ -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);
}
Expand Down
15 changes: 15 additions & 0 deletions test/unit/mcpRegister.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
} from "../../src/mcp/register.js";

class FakeStdio {
cwd?: { fsPath: string };

constructor(
public label: string,
public command: string,
Expand Down Expand Up @@ -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");
});
Loading