Skip to content

Commit 8292fbc

Browse files
authored
Merge pull request #7505 from meanderix/feature/mcp-make-workspace-root-default-cwd
feat: Adjusted MCPConnection logic so the cwd is resolved to current workspace folder.
2 parents 54ba728 + e321fa9 commit 8292fbc

File tree

2 files changed

+77
-2
lines changed

2 files changed

+77
-2
lines changed

core/context/mcp/MCPConnection.ts

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
2+
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
3+
import { fileURLToPath } from "url";
4+
25
import {
36
SSEClientTransport,
47
SseError,
58
} from "@modelcontextprotocol/sdk/client/sse.js";
69
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
710
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
811
import { WebSocketClientTransport } from "@modelcontextprotocol/sdk/client/websocket.js";
9-
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
1012
import { Agent as HttpsAgent } from "https";
1113
import {
1214
IDE,
@@ -22,6 +24,7 @@ import {
2224
MCPServerStatus,
2325
MCPTool,
2426
} from "../..";
27+
import { resolveRelativePathInDir } from "../../util/ideUtils";
2528
import { getEnvPathFromUserShell } from "../../util/shellPath";
2629
import { getOauthToken } from "./MCPOauth";
2730

@@ -413,6 +416,44 @@ class MCPConnection {
413416
};
414417
}
415418

419+
/**
420+
* Resolves the current working directory of the current workspace.
421+
* @param cwd The cwd parameter provided by user.
422+
* @returns Current working directory (user-provided cwd or workspace root).
423+
*/
424+
private async resolveCwd(cwd?: string) {
425+
if (!cwd) {
426+
return this.resolveWorkspaceCwd(undefined);
427+
}
428+
429+
if (cwd.startsWith("file://")) {
430+
return fileURLToPath(cwd);
431+
}
432+
433+
// Return cwd if cwd is an absolute path.
434+
if (cwd.charAt(0) === "/") {
435+
return cwd;
436+
}
437+
438+
return this.resolveWorkspaceCwd(cwd);
439+
}
440+
441+
private async resolveWorkspaceCwd(cwd: string | undefined) {
442+
const IDE = this.extras?.ide;
443+
if (IDE) {
444+
const target = cwd ?? ".";
445+
const resolved = await resolveRelativePathInDir(target, IDE);
446+
if (resolved) {
447+
if (resolved.startsWith("file://")) {
448+
return fileURLToPath(resolved);
449+
}
450+
return resolved;
451+
}
452+
return resolved;
453+
}
454+
return cwd;
455+
}
456+
416457
private constructWebsocketTransport(
417458
options: InternalWebsocketMcpOptions,
418459
): WebSocketClientTransport {
@@ -499,11 +540,13 @@ class MCPConnection {
499540
options.args || [],
500541
);
501542

543+
const cwd = await this.resolveCwd(options.cwd);
544+
502545
const transport = new StdioClientTransport({
503546
command,
504547
args,
505548
env,
506-
cwd: options.cwd,
549+
cwd,
507550
stderr: "pipe",
508551
});
509552

core/context/mcp/MCPConnection.vitest.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
InternalStdioMcpOptions,
66
InternalWebsocketMcpOptions,
77
} from "../..";
8+
import * as ideUtils from "../../util/ideUtils";
89
import MCPConnection from "./MCPConnection";
910

1011
// Mock the shell path utility
@@ -145,6 +146,37 @@ describe("MCPConnection", () => {
145146
});
146147
});
147148

149+
describe("resolveCwd", () => {
150+
const baseOptions = {
151+
name: "test-mcp",
152+
id: "test-id",
153+
type: "stdio" as const,
154+
command: "test-cmd",
155+
args: [],
156+
};
157+
158+
it("should return absolute cwd unchanged", async () => {
159+
const conn = new MCPConnection(baseOptions);
160+
161+
await expect((conn as any).resolveCwd("/tmp/project")).resolves.toBe(
162+
"/tmp/project",
163+
);
164+
});
165+
166+
it("should resolve relative cwd using IDE workspace", async () => {
167+
const ide = {} as any;
168+
const mockResolve = vi
169+
.spyOn(ideUtils, "resolveRelativePathInDir")
170+
.mockResolvedValue("file:///workspace/src");
171+
const conn = new MCPConnection(baseOptions, { ide });
172+
173+
await expect((conn as any).resolveCwd("src")).resolves.toBe(
174+
"/workspace/src",
175+
);
176+
expect(mockResolve).toHaveBeenCalledWith("src", ide);
177+
});
178+
});
179+
148180
describe("connectClient", () => {
149181
const options: InternalStdioMcpOptions = {
150182
name: "test-mcp",

0 commit comments

Comments
 (0)