Skip to content
Draft
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
15 changes: 15 additions & 0 deletions packages/opencode/src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,21 @@ function mergeConfigConcatArrays(target: Info, source: Info): Info {
function normalizeLoadedConfig(data: unknown, source: string) {
if (!isRecord(data)) return data
const copy = { ...data }
if (isRecord(copy.mcp)) {
copy.mcp = Object.fromEntries(
Object.entries(copy.mcp).map(([name, server]) => {
if (!isRecord(server) || !isRecord(server.env)) return [name, server]
const { env, ...rest } = server
return [
name,
{
...rest,
...(!("environment" in server) && { environment: env }),
},
]
}),
)
}
const hadLegacy = "theme" in copy || "keybinds" in copy || "tui" in copy
if (!hadLegacy) return copy
delete copy.theme
Expand Down
3 changes: 3 additions & 0 deletions packages/opencode/src/config/mcp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ export class Local extends Schema.Class<Local>("McpLocalConfig")({
environment: Schema.optional(Schema.Record(Schema.String, Schema.String)).annotate({
description: "Environment variables to set when running the MCP server",
}),
env: Schema.optional(Schema.Record(Schema.String, Schema.String)).annotate({
description: "@deprecated Use environment. Alias for environment variables to set when running the MCP server.",
}),
enabled: Schema.optional(Schema.Boolean).annotate({
description: "Enable or disable the MCP server on startup",
}),
Expand Down
35 changes: 35 additions & 0 deletions packages/opencode/test/config/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,41 @@ test("loads JSON config file", async () => {
})
})

test("loads native MCP env alias as environment", async () => {
await using tmp = await tmpdir({
init: async (dir) => {
await writeConfig(dir, {
$schema: "https://opencode.ai/config.json",
mcp: {
postgres: {
type: "local",
command: ["cmd.exe", "/c", "npx", "-y", "@yawlabs/postgres-mcp@latest"],
env: {
DATABASE_URL: "postgres://postgres:secret@localhost:5432/demo1",
ALLOW_WRITES: "1",
},
},
},
})
},
})

await Instance.provide({
directory: tmp.path,
fn: async () => {
const config = await load()
expect(config.mcp?.postgres).toEqual({
type: "local",
command: ["cmd.exe", "/c", "npx", "-y", "@yawlabs/postgres-mcp@latest"],
environment: {
DATABASE_URL: "postgres://postgres:secret@localhost:5432/demo1",
ALLOW_WRITES: "1",
},
})
},
})
})

test("loads Claude Code MCP servers from home and project config", async () => {
await writeClaudeConfig(path.join(Global.Path.home, ".claude.json"), {
mcpServers: {
Expand Down
Loading