feat: add mcp_config input variable to vscode-desktop-core module (#753)

## Description

Standardizes handling of `mcp` variables in VSCode Desktop-based
modules.
Made modular enough to pave the way for setting other config files than
`mcp_server.json` and `mcp.json`.

## Type of Change

- [ ] New module
- [ ] New template
- [ ] Bug fix
- [x] Feature/enhancement
- [ ] Documentation
- [ ] Other

## Testing & Validation

- [x] Tests pass (`bun test`)
- [x] Code formatted (`bun fmt`)
- [x] Changes tested locally

---------

Co-authored-by: DevCats <christofer@coder.com>
Co-authored-by: blink-so[bot] <211532188+blink-so[bot]@users.noreply.github.com>
This commit is contained in:
Phorcys
2026-04-03 20:29:46 +02:00
committed by GitHub
parent 516a934694
commit 5ee68d04d1
3 changed files with 82 additions and 13 deletions
@@ -16,7 +16,7 @@ The VSCode Desktop Core module is a building block for modules that need to expo
```tf ```tf
module "vscode-desktop-core" { module "vscode-desktop-core" {
source = "registry.coder.com/coder/vscode-desktop-core/coder" source = "registry.coder.com/coder/vscode-desktop-core/coder"
version = "1.0.2" version = "1.1.0"
agent_id = var.agent_id agent_id = var.agent_id
@@ -3,6 +3,11 @@ import {
runTerraformApply, runTerraformApply,
runTerraformInit, runTerraformInit,
testRequiredVariables, testRequiredVariables,
runContainer,
execContainer,
removeContainer,
findResourceInstance,
readFileContainer,
} from "~test"; } from "~test";
// hardcoded coder_app name in main.tf // hardcoded coder_app name in main.tf
@@ -16,6 +21,7 @@ const defaultVariables = {
coder_app_display_name: "VS Code Desktop", coder_app_display_name: "VS Code Desktop",
protocol: "vscode", protocol: "vscode",
config_dir: "$HOME/.vscode",
}; };
describe("vscode-desktop-core", async () => { describe("vscode-desktop-core", async () => {
@@ -134,4 +140,41 @@ describe("vscode-desktop-core", async () => {
expect(coder_app?.instances[0].attributes.group).toBe("web-app-group"); expect(coder_app?.instances[0].attributes.group).toBe("web-app-group");
}); });
}); });
it("writes mcp_config.json when mcp_config variable provided", async () => {
const id = await runContainer("alpine");
try {
const mcp_config = JSON.stringify({
servers: { demo: { url: "http://localhost:1234" } },
});
const state = await runTerraformApply(import.meta.dir, {
...defaultVariables,
mcp_config,
});
const script = findResourceInstance(
state,
"coder_script",
"vscode-desktop-mcp",
).script;
const resp = await execContainer(id, ["sh", "-c", script]);
if (resp.exitCode !== 0) {
console.log(resp.stdout);
console.log(resp.stderr);
}
expect(resp.exitCode).toBe(0);
const content = await readFileContainer(
id,
`${defaultVariables.config_dir.replace("$HOME", "/root")}/mcp_config.json`,
);
expect(content).toBe(mcp_config);
} finally {
await removeContainer(id);
}
}, 10000);
}); });
@@ -26,11 +26,22 @@ variable "open_recent" {
default = false default = false
} }
variable "mcp_config" {
type = map(any)
description = "MCP server configuration for the IDE. When set, writes mcp_config.json in var.config_dir."
default = null
}
variable "protocol" { variable "protocol" {
type = string type = string
description = "The URI protocol the IDE." description = "The URI protocol the IDE."
} }
variable "config_dir" {
type = string
description = "The path of the IDE's configuration folder."
}
variable "coder_app_icon" { variable "coder_app_icon" {
type = string type = string
description = "The icon of the coder_app." description = "The icon of the coder_app."
@@ -85,21 +96,36 @@ resource "coder_app" "vscode-desktop" {
data.coder_workspace.me.access_url, data.coder_workspace.me.access_url,
"&token=$SESSION_TOKEN", "&token=$SESSION_TOKEN",
]) ])
}
/* resource "coder_script" "vscode-desktop-mcp" {
url = join("", [ agent_id = var.agent_id
"vscode://coder.coder-remote/open", count = var.mcp_config != null ? 1 : 0
"?owner=${data.coder_workspace_owner.me.name}",
"&workspace=${data.coder_workspace.me.name}", icon = var.coder_app_icon
var.folder != "" ? join("", ["&folder=", var.folder]) : "", display_name = "${var.coder_app_display_name} MCP"
var.open_recent ? "&openRecent" : "",
"&url=${data.coder_workspace.me.access_url}", run_on_start = true
"&token=$SESSION_TOKEN", start_blocks_login = false
])
*/ script = <<-EOT
#!/bin/sh
set -euo pipefail
IDE_CONFIG_FOLDER="${var.config_dir}"
IDE_MCP_CONFIG_PATH="$IDE_CONFIG_FOLDER/mcp_config.json"
mkdir -p "$IDE_CONFIG_FOLDER"
echo -n "${base64encode(jsonencode(var.mcp_config))}" | base64 -d > "$IDE_MCP_CONFIG_PATH"
chmod 600 "$IDE_MCP_CONFIG_PATH"
# Cursor/Windsurf use this config instead, no need for chmod as symlinks do not have modes
ln -s "$IDE_MCP_CONFIG_PATH" "$IDE_CONFIG_FOLDER/mcp.json"
EOT
} }
output "ide_uri" { output "ide_uri" {
value = coder_app.vscode-desktop.url value = coder_app.vscode-desktop.url
description = "IDE URI." description = "IDE URI."
} }