Skip to content

feat: adds cwd to the MCP yaml as an option. #6280

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jul 7, 2025
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: 2 additions & 0 deletions core/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1004,6 +1004,8 @@ declare global {
type: "stdio";
command: string;
args: string[];
env?: Record<string, string>;
cwd?: string;
}

interface WebSocketOptions {
Expand Down
1 change: 1 addition & 0 deletions core/config/yaml/loadYaml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ function convertYamlMcpToContinueMcp(
command: server.command,
args: server.args ?? [],
env: server.env,
cwd: server.cwd,
} as any, // TODO: Fix the mcpServers types in config-yaml (discriminated union)
timeout: server.connectionTimeout,
};
Expand Down
128 changes: 128 additions & 0 deletions core/config/yaml/loadYaml.vitest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import { describe, it, expect } from "vitest";
import {
validateConfigYaml,
AssistantUnrolledNonNullable,
} from "@continuedev/config-yaml";

describe("MCP Server cwd configuration", () => {
describe("YAML schema validation", () => {
it("should accept valid MCP server with cwd", () => {
const config: AssistantUnrolledNonNullable = {
name: "test-assistant",
version: "1.0.0",
mcpServers: [
{
name: "test-server",
command: "node",
args: ["server.js"],
env: { NODE_ENV: "production" },
cwd: "/path/to/project",
connectionTimeout: 5000,
},
],
};

const errors = validateConfigYaml(config);
expect(errors).toHaveLength(0);
});

it("should accept MCP server without cwd", () => {
const config: AssistantUnrolledNonNullable = {
name: "test-assistant",
version: "1.0.0",
mcpServers: [
{
name: "test-server",
command: "python",
args: ["-m", "server"],
},
],
};

const errors = validateConfigYaml(config);
expect(errors).toHaveLength(0);
});

it("should accept relative paths in cwd", () => {
const config: AssistantUnrolledNonNullable = {
name: "test-assistant",
version: "1.0.0",
mcpServers: [
{
name: "test-server",
command: "cargo",
args: ["run"],
cwd: "./rust-project",
},
],
};

const errors = validateConfigYaml(config);
expect(errors).toHaveLength(0);
});

it("should accept empty string cwd", () => {
const config: AssistantUnrolledNonNullable = {
name: "test-assistant",
version: "1.0.0",
mcpServers: [
{
name: "test-server",
command: "deno",
args: ["run", "server.ts"],
cwd: "",
},
],
};

const errors = validateConfigYaml(config);
expect(errors).toHaveLength(0);
});
});

describe("MCP server configuration examples", () => {
it("should support common MCP server patterns with cwd", () => {
const configs = [
{
name: "Local project MCP server",
server: {
name: "project-mcp",
command: "npm",
args: ["run", "mcp-server"],
cwd: "/Users/developer/my-project",
},
},
{
name: "Python MCP with virtual environment",
server: {
name: "python-mcp",
command: "python",
args: ["-m", "my_mcp_server"],
env: { PYTHONPATH: "./src" },
cwd: "/home/user/python-project",
},
},
{
name: "Relative path MCP server",
server: {
name: "relative-mcp",
command: "node",
args: ["index.js"],
cwd: "../mcp-servers/filesystem",
},
},
];

configs.forEach(({ name, server }) => {
const config: AssistantUnrolledNonNullable = {
name: "test-assistant",
version: "1.0.0",
mcpServers: [server],
};

const errors = validateConfigYaml(config);
expect(errors).toHaveLength(0);
});
});
});
});
1 change: 1 addition & 0 deletions core/context/mcp/MCPConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ class MCPConnection {
command,
args,
env,
cwd: options.transport.cwd,
stderr: "pipe",
});

Expand Down
22 changes: 22 additions & 0 deletions core/context/mcp/MCPConnection.vitest.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { beforeEach, describe, expect, it, vi } from "vitest";
import MCPConnection from "./MCPConnection";
import { StdioOptions } from "../../index.d.js";

describe("MCPConnection", () => {
beforeEach(() => {
Expand All @@ -25,6 +26,27 @@ describe("MCPConnection", () => {
expect(conn.status).toBe("not-connected");
});

it("should create instance with stdio transport including cwd", () => {
const options = {
name: "test-mcp",
id: "test-id",
transport: {
type: "stdio" as const,
command: "test-cmd",
args: ["--test"],
env: { TEST: "true" },
cwd: "/path/to/working/directory",
},
};

const conn = new MCPConnection(options);
expect(conn).toBeInstanceOf(MCPConnection);
expect(conn.status).toBe("not-connected");
if (conn.options.transport.type === "stdio") {
expect(conn.options.transport.cwd).toBe("/path/to/working/directory");
}
});

it("should create instance with websocket transport", () => {
const options = {
name: "test-mcp",
Expand Down
1 change: 1 addition & 0 deletions core/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1162,6 +1162,7 @@ export interface StdioOptions {
command: string;
args: string[];
env?: Record<string, string>;
cwd?: string;
requestOptions?: RequestOptions;
}

Expand Down
15 changes: 13 additions & 2 deletions docs/docs/customize/deep-dives/mcp.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ MCP blocks follow the established syntax for blocks, with a few additional prope
- `type` (optional): The type of the MCP server: `sse`, `stdio`, `streamable-http`
- `args` (optional): Arguments to pass to the command.
- `env` (optional): Secrets to be injected into the command as environment variables.
- `cwd` (optional): Working directory to run the command in. Can be absolute or relative path.

### Transport Types

Expand All @@ -132,12 +133,22 @@ For local MCP servers that communicate via standard input and output:

```yaml
mcpServers:
- name: Name
- name: SQLite Server
type: stdio
command: npx
args:
- "@modelcontextprotocol/server-sqlite"
- "/path/to/your/database.db"
- "./database.db"
cwd: "/path/to/project"

- name: Local Project Server
command: npm
args:
- "run"
- "mcp-server"
cwd: "./my-project"
env:
NODE_ENV: "production"
```

#### Streamable HTTP Transport
Expand Down
1 change: 1 addition & 0 deletions docs/docs/customize/yaml-migration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ docs:
- `command` (**required**): The command used to start the server.
- `args`: An optional array of arguments for the command.
- `env`: An optional map of environment variables for the server process.
- `cwd`: An optional working directory to run the command in. Can be absolute or relative path.

**Before**

Expand Down
6 changes: 5 additions & 1 deletion docs/docs/reference.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ prompts, context, and tool use. Continue supports any MCP server with the MCP co
- `command` (**required**): The command used to start the server.
- `args`: An optional array of arguments for the command.
- `env`: An optional map of environment variables for the server process.
- `cwd`: An optional working directory to run the command in. Can be absolute or relative path.
- `connectionTimeout`: An optional connection timeout number to the server in milliseconds.

**Example:**
Expand All @@ -395,7 +396,10 @@ mcpServers:
args:
- mcp-server-sqlite
- --db-path
- /Users/NAME/test.db
- ./test.db
cwd: /Users/NAME/project
env:
NODE_ENV: production
```

### `data`
Expand Down
1 change: 1 addition & 0 deletions packages/config-yaml/src/schemas/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const mcpServerSchema = z.object({
faviconUrl: z.string().optional(),
args: z.array(z.string()).optional(),
env: z.record(z.string()).optional(),
cwd: z.string().optional(),
connectionTimeout: z.number().gt(0).optional(),
requestOptions: requestOptionsSchema.optional(),
});
Expand Down
Loading