Skip to content

Commit 9125a52

Browse files
feat: add mcp config for kiro and windsurf modules (#391)
## Description - Introduces mcp file creation via `coder_script` in kiro and windsurf modules - Add mcp variable to both modules - Add slug and display_name variables to windsurf to match up with other modules - Add tests for testing mcp file creation for both kiro and windsurf <!-- Briefly describe what this PR does and why --> ## Type of Change - [ ] New module - [ ] Bug fix - [X] Feature/enhancement - [ ] Documentation - [ ] Other ## Module Information <!-- Delete this section if not applicable --> **Path:** `registry/coder/modules/kiro` **New version:** `v1.1.0` **Breaking change:** [ ] Yes [X] No **Path:** `registry/coder/modules/windsurf` **New version:** `v1.2.0` **Breaking change:** [ ] Yes [X] No **Path:** `registry/coder/modules/cursor` **New version:** `v1.3.2` **Breaking change:** [ ] Yes [X] No ## Testing & Validation - [X] Tests pass (`bun test`) - [X] Code formatted (`bun run fmt`) - [X] Changes tested locally
1 parent c8441fc commit 9125a52

File tree

8 files changed

+184
-16
lines changed

8 files changed

+184
-16
lines changed

registry/coder/modules/cursor/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Uses the [Coder Remote VS Code Extension](https://github.com/coder/vscode-coder)
1616
module "cursor" {
1717
count = data.coder_workspace.me.start_count
1818
source = "registry.coder.com/coder/cursor/coder"
19-
version = "1.3.1"
19+
version = "1.3.2"
2020
agent_id = coder_agent.example.id
2121
}
2222
```
@@ -29,7 +29,7 @@ module "cursor" {
2929
module "cursor" {
3030
count = data.coder_workspace.me.start_count
3131
source = "registry.coder.com/coder/cursor/coder"
32-
version = "1.3.1"
32+
version = "1.3.2"
3333
agent_id = coder_agent.example.id
3434
folder = "/home/coder/project"
3535
}
@@ -45,7 +45,7 @@ The following example configures Cursor to use the GitHub MCP server with authen
4545
module "cursor" {
4646
count = data.coder_workspace.me.start_count
4747
source = "registry.coder.com/coder/cursor/coder"
48-
version = "1.3.1"
48+
version = "1.3.2"
4949
agent_id = coder_agent.example.id
5050
folder = "/home/coder/project"
5151
mcp = jsonencode({

registry/coder/modules/cursor/main.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ resource "coder_script" "cursor_mcp" {
9898
set -eu
9999
mkdir -p "$HOME/.cursor"
100100
echo -n "${local.mcp_b64}" | base64 -d > "$HOME/.cursor/mcp.json"
101+
chmod 600 "$HOME/.cursor/mcp.json"
101102
EOT
102103
}
103104

registry/coder/modules/kiro/README.md

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Uses the [Coder Remote VS Code Extension](https://github.com/coder/vscode-coder)
1818
module "kiro" {
1919
count = data.coder_workspace.me.start_count
2020
source = "registry.coder.com/coder/kiro/coder"
21-
version = "1.0.0"
21+
version = "1.1.0"
2222
agent_id = coder_agent.example.id
2323
}
2424
```
@@ -31,21 +31,39 @@ module "kiro" {
3131
module "kiro" {
3232
count = data.coder_workspace.me.start_count
3333
source = "registry.coder.com/coder/kiro/coder"
34-
version = "1.0.0"
34+
version = "1.1.0"
3535
agent_id = coder_agent.example.id
3636
folder = "/home/coder/project"
3737
}
3838
```
3939

40-
### Open with custom display name and order
40+
### Configure MCP servers for Kiro
41+
42+
Provide a JSON-encoded string via the `mcp` input. When set, the module writes the value to `~/.kiro/settings/mcp.json` using a `coder_script` on workspace start.
43+
44+
The following example configures Kiro to use the GitHub MCP server with authentication facilitated by the [`coder_external_auth`](https://coder.com/docs/admin/external-auth#configure-a-github-oauth-app) resource.
4145

4246
```tf
4347
module "kiro" {
44-
count = data.coder_workspace.me.start_count
45-
source = "registry.coder.com/coder/kiro/coder"
46-
version = "1.0.0"
47-
agent_id = coder_agent.example.id
48-
display_name = "Kiro AI IDE"
49-
order = 1
48+
count = data.coder_workspace.me.start_count
49+
source = "registry.coder.com/coder/kiro/coder"
50+
version = "1.1.0"
51+
agent_id = coder_agent.example.id
52+
folder = "/home/coder/project"
53+
mcp = jsonencode({
54+
mcpServers = {
55+
"github" : {
56+
"url" : "https://api.githubcopilot.com/mcp/",
57+
"headers" : {
58+
"Authorization" : "Bearer ${data.coder_external_auth.github.access_token}",
59+
},
60+
"type" : "http"
61+
}
62+
}
63+
})
64+
}
65+
66+
data "coder_external_auth" "github" {
67+
id = "github"
5068
}
5169
```

registry/coder/modules/kiro/main.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ import {
33
runTerraformApply,
44
runTerraformInit,
55
testRequiredVariables,
6+
runContainer,
7+
execContainer,
8+
removeContainer,
9+
findResourceInstance,
10+
readFileContainer,
611
} from "~test";
712

813
describe("kiro", async () => {
@@ -90,4 +95,26 @@ describe("kiro", async () => {
9095

9196
expect(coder_app?.instances[0].attributes.group).toBe("AI IDEs");
9297
});
98+
99+
it("writes ~/.kiro/settings/mcp.json when mcp provided", async () => {
100+
const id = await runContainer("alpine");
101+
try {
102+
const mcp = JSON.stringify({ servers: { demo: { url: "http://localhost:1234" } } });
103+
const state = await runTerraformApply(import.meta.dir, {
104+
agent_id: "foo",
105+
mcp,
106+
});
107+
const script = findResourceInstance(state, "coder_script", "kiro_mcp").script;
108+
const resp = await execContainer(id, ["sh", "-c", script]);
109+
if (resp.exitCode !== 0) {
110+
console.log(resp.stdout);
111+
console.log(resp.stderr);
112+
}
113+
expect(resp.exitCode).toBe(0);
114+
const content = await readFileContainer(id, "/root/.kiro/settings/mcp.json");
115+
expect(content).toBe(mcp);
116+
} finally {
117+
await removeContainer(id);
118+
}
119+
});
93120
});

registry/coder/modules/kiro/main.tf

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,19 @@ variable "display_name" {
5050
default = "Kiro IDE"
5151
}
5252

53+
variable "mcp" {
54+
type = string
55+
description = "JSON-encoded string to configure MCP servers for Kiro. When set, writes ~/.kiro/settings/mcp.json."
56+
default = ""
57+
}
58+
5359
data "coder_workspace" "me" {}
5460
data "coder_workspace_owner" "me" {}
5561

62+
locals {
63+
mcp_b64 = var.mcp != "" ? base64encode(var.mcp) : ""
64+
}
65+
5666
resource "coder_app" "kiro" {
5767
agent_id = var.agent_id
5868
external = true
@@ -75,6 +85,22 @@ resource "coder_app" "kiro" {
7585
])
7686
}
7787

88+
resource "coder_script" "kiro_mcp" {
89+
count = var.mcp != "" ? 1 : 0
90+
agent_id = var.agent_id
91+
display_name = "Kiro MCP"
92+
icon = "/icon/kiro.svg"
93+
run_on_start = true
94+
start_blocks_login = false
95+
script = <<-EOT
96+
#!/bin/sh
97+
set -eu
98+
mkdir -p "$HOME/.kiro/settings"
99+
echo -n "${local.mcp_b64}" | base64 -d > "$HOME/.kiro/settings/mcp.json"
100+
chmod 600 "$HOME/.kiro/settings/mcp.json"
101+
EOT
102+
}
103+
78104
output "kiro_url" {
79105
value = coder_app.kiro.url
80106
description = "Kiro IDE URL."

registry/coder/modules/windsurf/README.md

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Uses the [Coder Remote VS Code Extension](https://github.com/coder/vscode-coder)
1616
module "windsurf" {
1717
count = data.coder_workspace.me.start_count
1818
source = "registry.coder.com/coder/windsurf/coder"
19-
version = "1.1.1"
19+
version = "1.2.0"
2020
agent_id = coder_agent.example.id
2121
}
2222
```
@@ -29,8 +29,39 @@ module "windsurf" {
2929
module "windsurf" {
3030
count = data.coder_workspace.me.start_count
3131
source = "registry.coder.com/coder/windsurf/coder"
32-
version = "1.1.1"
32+
version = "1.2.0"
3333
agent_id = coder_agent.example.id
3434
folder = "/home/coder/project"
3535
}
3636
```
37+
38+
### Configure MCP servers for Windsurf
39+
40+
Provide a JSON-encoded string via the `mcp` input. When set, the module writes the value to `~/.codeium/windsurf/mcp_config.json` using a `coder_script` on workspace start.
41+
42+
The following example configures Windsurf to use the GitHub MCP server with authentication facilitated by the [`coder_external_auth`](https://coder.com/docs/admin/external-auth#configure-a-github-oauth-app) resource.
43+
44+
```tf
45+
module "windsurf" {
46+
count = data.coder_workspace.me.start_count
47+
source = "registry.coder.com/coder/windsurf/coder"
48+
version = "1.2.0"
49+
agent_id = coder_agent.example.id
50+
folder = "/home/coder/project"
51+
mcp = jsonencode({
52+
mcpServers = {
53+
"github" : {
54+
"url" : "https://api.githubcopilot.com/mcp/",
55+
"headers" : {
56+
"Authorization" : "Bearer ${data.coder_external_auth.github.access_token}",
57+
},
58+
"type" : "http"
59+
}
60+
}
61+
})
62+
}
63+
64+
data "coder_external_auth" "github" {
65+
id = "github"
66+
}
67+
```

registry/coder/modules/windsurf/main.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ import {
33
runTerraformApply,
44
runTerraformInit,
55
testRequiredVariables,
6+
runContainer,
7+
execContainer,
8+
removeContainer,
9+
findResourceInstance,
10+
readFileContainer,
611
} from "~test";
712

813
describe("windsurf", async () => {
@@ -85,4 +90,26 @@ describe("windsurf", async () => {
8590
expect(coder_app?.instances.length).toBe(1);
8691
expect(coder_app?.instances[0].attributes.order).toBe(22);
8792
});
93+
94+
it("writes ~/.codeium/windsurf/mcp_config.json when mcp provided", async () => {
95+
const id = await runContainer("alpine");
96+
try {
97+
const mcp = JSON.stringify({ servers: { demo: { url: "http://localhost:1234" } } });
98+
const state = await runTerraformApply(import.meta.dir, {
99+
agent_id: "foo",
100+
mcp,
101+
});
102+
const script = findResourceInstance(state, "coder_script", "windsurf_mcp").script;
103+
const resp = await execContainer(id, ["sh", "-c", script]);
104+
if (resp.exitCode !== 0) {
105+
console.log(resp.stdout);
106+
console.log(resp.stderr);
107+
}
108+
expect(resp.exitCode).toBe(0);
109+
const content = await readFileContainer(id, "/root/.codeium/windsurf/mcp_config.json");
110+
expect(content).toBe(mcp);
111+
} finally {
112+
await removeContainer(id);
113+
}
114+
});
88115
});

registry/coder/modules/windsurf/main.tf

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,37 @@ variable "group" {
3838
default = null
3939
}
4040

41+
variable "slug" {
42+
type = string
43+
description = "The slug of the app."
44+
default = "windsurf"
45+
}
46+
47+
variable "display_name" {
48+
type = string
49+
description = "The display name of the app."
50+
default = "Windsurf Editor"
51+
}
52+
53+
variable "mcp" {
54+
type = string
55+
description = "JSON-encoded string to configure MCP servers for Windsurf. When set, writes ~/.codeium/windsurf/mcp_config.json."
56+
default = ""
57+
}
58+
4159
data "coder_workspace" "me" {}
4260
data "coder_workspace_owner" "me" {}
4361

62+
locals {
63+
mcp_b64 = var.mcp != "" ? base64encode(var.mcp) : ""
64+
}
65+
4466
resource "coder_app" "windsurf" {
4567
agent_id = var.agent_id
4668
external = true
4769
icon = "/icon/windsurf.svg"
48-
slug = "windsurf"
49-
display_name = "Windsurf Editor"
70+
slug = var.slug
71+
display_name = var.display_name
5072
order = var.order
5173
group = var.group
5274
url = join("", [
@@ -63,6 +85,22 @@ resource "coder_app" "windsurf" {
6385
])
6486
}
6587

88+
resource "coder_script" "windsurf_mcp" {
89+
count = var.mcp != "" ? 1 : 0
90+
agent_id = var.agent_id
91+
display_name = "Windsurf MCP"
92+
icon = "/icon/windsurf.svg"
93+
run_on_start = true
94+
start_blocks_login = false
95+
script = <<-EOT
96+
#!/bin/sh
97+
set -eu
98+
mkdir -p "$HOME/.codeium/windsurf"
99+
echo -n "${local.mcp_b64}" | base64 -d > "$HOME/.codeium/windsurf/mcp_config.json"
100+
chmod 600 "$HOME/.codeium/windsurf/mcp_config.json"
101+
EOT
102+
}
103+
66104
output "windsurf_url" {
67105
value = coder_app.windsurf.url
68106
description = "Windsurf Editor URL."

0 commit comments

Comments
 (0)