Skip to content

Commit 61554aa

Browse files
feat(cursor): add mcp input to configure MCP servers for Cursor (#314)
This adds a new optional input `mcp` to the cursor module. - Accepts a JSON-encoded string with MCP server configuration - When provided, a `coder_script` writes it to `~/.cursor/mcp.json` on start - Keeps existing behavior unchanged if `mcp` is empty - Adds tests verifying the `mcp.json` is written - Updates README with `mcp` usage example - Fixes Prettier and `terraform fmt` formatting issues flagged by CI CI should now pass after the latest commits. --------- Co-authored-by: blink-so[bot] <211532188+blink-so[bot]@users.noreply.github.com>
1 parent f4fcae7 commit 61554aa

File tree

3 files changed

+81
-3
lines changed

3 files changed

+81
-3
lines changed

registry/coder/modules/cursor/README.md

Lines changed: 27 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 "cursor" {
1717
count = data.coder_workspace.me.start_count
1818
source = "registry.coder.com/coder/cursor/coder"
19-
version = "1.2.1"
19+
version = "1.3.0"
2020
agent_id = coder_agent.example.id
2121
}
2222
```
@@ -29,8 +29,33 @@ module "cursor" {
2929
module "cursor" {
3030
count = data.coder_workspace.me.start_count
3131
source = "registry.coder.com/coder/cursor/coder"
32-
version = "1.2.1"
32+
version = "1.3.0"
3333
agent_id = coder_agent.example.id
3434
folder = "/home/coder/project"
3535
}
3636
```
37+
38+
### Configure MCP servers for Cursor
39+
40+
Provide a JSON-encoded string via the `mcp` input. When set, the module writes the value to `~/.cursor/mcp.json` using a `coder_script` on workspace start.
41+
42+
```tf
43+
module "cursor" {
44+
count = data.coder_workspace.me.start_count
45+
source = "registry.coder.com/coder/cursor/coder"
46+
version = "1.3.0"
47+
agent_id = coder_agent.example.id
48+
mcp = jsonencode({
49+
mcpServers = {
50+
coder = {
51+
command = "coder"
52+
args = ["exp", "mcp", "server"]
53+
env = {
54+
CODER_MCP_APP_STATUS_SLUG = "cursor"
55+
CODER_MCP_AI_AGENTAPI_URL = "http://localhost:3284"
56+
}
57+
}
58+
}
59+
})
60+
}
61+
```

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

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1-
import { describe, expect, it } from "bun:test";
1+
import { describe, it, expect } from "bun:test";
22
import {
33
runTerraformApply,
44
runTerraformInit,
55
testRequiredVariables,
6+
runContainer,
7+
execContainer,
8+
removeContainer,
9+
findResourceInstance,
10+
readFileContainer,
611
} from "~test";
712

813
describe("cursor", async () => {
@@ -85,4 +90,26 @@ describe("cursor", async () => {
8590
expect(coder_app?.instances.length).toBe(1);
8691
expect(coder_app?.instances[0].attributes.order).toBe(22);
8792
});
93+
94+
it("writes ~/.cursor/mcp.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", "cursor_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/.cursor/mcp.json");
110+
expect(content).toBe(mcp);
111+
} finally {
112+
await removeContainer(id);
113+
}
114+
});
88115
});

registry/coder/modules/cursor/main.tf

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

53+
variable "mcp" {
54+
type = string
55+
description = "JSON-encoded string to configure MCP servers for Cursor. When set, writes ~/.cursor/mcp.json."
56+
default = ""
57+
}
58+
5359
data "coder_workspace" "me" {}
60+
5461
data "coder_workspace_owner" "me" {}
5562

63+
locals {
64+
mcp_b64 = var.mcp != "" ? base64encode(var.mcp) : ""
65+
}
66+
5667
resource "coder_app" "cursor" {
5768
agent_id = var.agent_id
5869
external = true
@@ -75,6 +86,21 @@ resource "coder_app" "cursor" {
7586
])
7687
}
7788

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

0 commit comments

Comments
 (0)