diff --git a/apps/gittensory-ui/src/routes/docs.mcp-clients.tsx b/apps/gittensory-ui/src/routes/docs.mcp-clients.tsx
index 10bd2612db..849f8280b6 100644
--- a/apps/gittensory-ui/src/routes/docs.mcp-clients.tsx
+++ b/apps/gittensory-ui/src/routes/docs.mcp-clients.tsx
@@ -39,7 +39,8 @@ function McpClients() {
code={`gittensory-mcp init-client --print codex
gittensory-mcp init-client --print claude
gittensory-mcp init-client --print cursor
-gittensory-mcp init-client --print mcp`}
+gittensory-mcp init-client --print mcp
+gittensory-mcp init-client --print windsurf`}
/>
--print mcp uses the same JSON snippet as Claude Desktop and Cursor for other
diff --git a/packages/gittensory-mcp/README.md b/packages/gittensory-mcp/README.md
index a6da3b9656..27afff8c9e 100644
--- a/packages/gittensory-mcp/README.md
+++ b/packages/gittensory-mcp/README.md
@@ -48,6 +48,7 @@ gittensory-mcp init-client --print codex
gittensory-mcp init-client --print claude
gittensory-mcp init-client --print cursor
gittensory-mcp init-client --print vscode
+gittensory-mcp init-client --print windsurf
gittensory-mcp init-client --print codex --agent-profile miner-planner
gittensory-mcp completion bash
gittensory-mcp completion zsh
@@ -159,7 +160,7 @@ The same capabilities are exposed to MCP clients as:
### Client config
-`init-client --print ` prints the stdio MCP config for a host: `codex` (TOML), `claude`, `cursor`, and `mcp` (the shared `mcpServers` JSON shape), and `vscode` (VS Code's native `servers` map with `"type": "stdio"`, for `.vscode/mcp.json`). It prints config only; it never edits client files.
+`init-client --print ` prints the stdio MCP config for a host: `codex` (TOML), `claude`, `cursor`, `mcp`, and `windsurf` (the shared `mcpServers` JSON shape; Windsurf reads `~/.codeium/windsurf/mcp_config.json`), and `vscode` (VS Code's native `servers` map with `"type": "stdio"`, for `.vscode/mcp.json`). It prints config only; it never edits client files.
### Agent profiles
diff --git a/packages/gittensory-mcp/bin/gittensory-mcp.js b/packages/gittensory-mcp/bin/gittensory-mcp.js
index 280189ec7c..54d4127d33 100755
--- a/packages/gittensory-mcp/bin/gittensory-mcp.js
+++ b/packages/gittensory-mcp/bin/gittensory-mcp.js
@@ -1860,7 +1860,7 @@ function printHelp() {
gittensory-mcp changelog [--json]
gittensory-mcp doctor [--profile name] [--cwd path] [--exit-code] [--json]
gittensory-mcp cache status|list|clear [--json]
- gittensory-mcp init-client --print codex|claude|cursor|mcp|vscode [--agent-profile miner-planner|maintainer-triage|repo-owner-intake] [--json]
+ gittensory-mcp init-client --print codex|claude|cursor|mcp|vscode|windsurf [--agent-profile miner-planner|maintainer-triage|repo-owner-intake] [--json]
gittensory-mcp decision-pack --login [--json]
gittensory-mcp repo-decision --login --repo owner/repo [--json]
gittensory-mcp analyze-branch --login [--repo owner/repo] [--base origin/main] [--branch-eligibility eligible|ineligible|unknown] [--pending-merged-prs 3] [--expected-open-prs 0] [--projected-credibility 0.8] [--scenario-note "..."] [--validation "passed|npm test|summary"] [--json]
@@ -2402,7 +2402,7 @@ function shellArg(value) {
function initClient(options) {
const client = String(options.print ?? options.client ?? "").toLowerCase();
- if (!client) throw new Error("Pass --print codex, --print claude, --print cursor, --print mcp, or --print vscode.");
+ if (!client) throw new Error("Pass --print codex, --print claude, --print cursor, --print mcp, --print vscode, or --print windsurf.");
const command = options.command ?? "gittensory-mcp";
const snippet = clientSnippet(client, command);
const agentProfile = resolveAgentProfile(options.agentProfile);
@@ -2801,7 +2801,9 @@ function redactPrivateValidationMetrics(text) {
function clientSnippet(client, command) {
if (client === "codex") return `[mcp_servers.gittensory]\ncommand = ${JSON.stringify(command)}\nargs = ["--stdio"]`;
- if (client === "claude" || client === "cursor" || client === "mcp") {
+ // claude/cursor/mcp and Windsurf all consume the shared `mcpServers` JSON shape (Windsurf reads
+ // ~/.codeium/windsurf/mcp_config.json), so they share one snippet.
+ if (client === "claude" || client === "cursor" || client === "mcp" || client === "windsurf") {
return JSON.stringify(
{
mcpServers: {
@@ -2832,7 +2834,7 @@ function clientSnippet(client, command) {
2,
);
}
- throw new Error(`Unsupported client: ${client}. Use codex, claude, cursor, mcp, or vscode.`);
+ throw new Error(`Unsupported client: ${client}. Use codex, claude, cursor, mcp, vscode, or windsurf.`);
}
async function getDecisionPackWithCache(login) {
diff --git a/test/unit/mcp-cli-basics.test.ts b/test/unit/mcp-cli-basics.test.ts
index 8405314ad4..23a9cc5921 100644
--- a/test/unit/mcp-cli-basics.test.ts
+++ b/test/unit/mcp-cli-basics.test.ts
@@ -28,6 +28,10 @@ describe("gittensory-mcp CLI — basics", () => {
const generic = JSON.parse(run(["init-client", "--print", "mcp", "--json"])) as { snippet: string };
expect(generic.snippet).toBe(claude.snippet);
+ // Windsurf consumes the same shared `mcpServers` JSON shape (~/.codeium/windsurf/mcp_config.json).
+ const windsurf = JSON.parse(run(["init-client", "--print", "windsurf", "--json"])) as { snippet: string };
+ expect(windsurf.snippet).toBe(claude.snippet);
+
const vscode = JSON.parse(run(["init-client", "--print", "vscode", "--json"])) as { snippet: string };
// VS Code uses a `servers` map with an explicit transport type, not the `mcpServers` shape.
expect(vscode.snippet).toContain('"servers"');