add-mcp 1.10.0 → 1.10.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Add MCP servers to your favorite coding agents with a single command.
4
4
 
5
- Supports **Claude Code**, **Codex**, **Cursor**, **OpenCode**, **VSCode** and [9 more](#supported-agents).
5
+ Supports **Claude Code**, **Codex**, **Cursor**, **OpenCode**, **VSCode** and [10 more](#supported-agents).
6
6
 
7
7
  ## Install an MCP Server
8
8
 
@@ -49,9 +49,10 @@ MCP servers can be installed to any of these agents:
49
49
  | MCPorter | `mcporter` | `config/mcporter.json` | `~/.mcporter/mcporter.json` (or existing `~/.mcporter/mcporter.jsonc`) |
50
50
  | OpenCode | `opencode` | `opencode.json` | `~/.config/opencode/opencode.json` |
51
51
  | VS Code | `vscode` | `.vscode/mcp.json` | `~/Library/Application Support/Code/User/mcp.json` |
52
+ | Windsurf | `windsurf` | - | `~/.codeium/windsurf/mcp_config.json` |
52
53
  | Zed | `zed` | `.zed/settings.json` | `~/Library/Application Support/Zed/settings.json` |
53
54
 
54
- **Aliases:** `cline-vscode` → `cline`, `gemini` → `gemini-cli`, `github-copilot` → `vscode`
55
+ **Aliases:** `codeium`, `cascade` → `windsurf`, `cline-vscode` → `cline`, `gemini` → `gemini-cli`, `github-copilot` → `vscode`
55
56
 
56
57
  ## Installation Scope
57
58
 
@@ -153,6 +153,12 @@ var copilotConfigPath = join2(
153
153
  process.env.XDG_CONFIG_HOME || join2(home, ".copilot"),
154
154
  "mcp-config.json"
155
155
  );
156
+ var windsurfConfigPath = join2(
157
+ home,
158
+ ".codeium",
159
+ "windsurf",
160
+ "mcp_config.json"
161
+ );
156
162
  function transformGooseConfig(serverName, config) {
157
163
  if (config.url) {
158
164
  const gooseType = config.type === "sse" ? "sse" : "streamable_http";
@@ -503,6 +509,20 @@ var agents = {
503
509
  return existsSync(vscodePath);
504
510
  }
505
511
  },
512
+ windsurf: {
513
+ name: "windsurf",
514
+ displayName: "Windsurf",
515
+ configPath: windsurfConfigPath,
516
+ projectDetectPaths: [],
517
+ // Global only - no project support
518
+ configKey: "mcpServers",
519
+ format: "json",
520
+ supportedTransports: ["stdio", "http", "sse"],
521
+ detectGlobalInstall: async () => {
522
+ return existsSync(join2(home, ".codeium", "windsurf"));
523
+ },
524
+ transformConfig: transformAntigravityConfig
525
+ },
506
526
  zed: {
507
527
  name: "zed",
508
528
  displayName: "Zed",
@@ -669,6 +689,150 @@ async function selectAgentsInteractive(availableAgents, options) {
669
689
  return promptForAgents("Select agents to install to", agentChoices, false);
670
690
  }
671
691
 
692
+ // src/source-parser.ts
693
+ function isUrl(input) {
694
+ return input.startsWith("http://") || input.startsWith("https://");
695
+ }
696
+ function looksLikePath(input) {
697
+ if (input.startsWith("/")) return true;
698
+ if (input.startsWith("~/") || input === "~") return true;
699
+ if (input.startsWith("./") || input.startsWith("../")) return true;
700
+ if (/^[A-Za-z]:[\\/]/.test(input)) return true;
701
+ return false;
702
+ }
703
+ function isCommand(input) {
704
+ if (looksLikePath(input)) {
705
+ return true;
706
+ }
707
+ if (input.includes(" ")) {
708
+ return true;
709
+ }
710
+ if (input.startsWith("npx ") || input.startsWith("node ") || input.startsWith("python ")) {
711
+ return true;
712
+ }
713
+ return false;
714
+ }
715
+ function isPackageName(input) {
716
+ if (input.startsWith("@") && input.includes("/")) {
717
+ return true;
718
+ }
719
+ if (/^[a-z0-9][\w.-]*(@[\w.-]+)?$/i.test(input)) {
720
+ return true;
721
+ }
722
+ return false;
723
+ }
724
+ var commonTlds = /* @__PURE__ */ new Set([
725
+ "com",
726
+ "org",
727
+ "net",
728
+ "io",
729
+ "dev",
730
+ "ai",
731
+ "tech",
732
+ "co",
733
+ "app",
734
+ "cloud",
735
+ "sh",
736
+ "run"
737
+ ]);
738
+ function extractBrandFromHostname(hostname) {
739
+ const parts = hostname.split(".");
740
+ const meaningfulParts = parts.filter((part) => {
741
+ const lower = part.toLowerCase();
742
+ if (commonTlds.has(lower)) return false;
743
+ if (lower === "mcp" || lower === "api" || lower === "www") return false;
744
+ return true;
745
+ });
746
+ if (meaningfulParts.length > 0) {
747
+ return meaningfulParts[0];
748
+ }
749
+ if (parts.length >= 2) {
750
+ return parts[parts.length - 2];
751
+ }
752
+ return "mcp-server";
753
+ }
754
+ function inferName(input, type) {
755
+ if (type === "remote") {
756
+ try {
757
+ const url = new URL(input);
758
+ return extractBrandFromHostname(url.hostname);
759
+ } catch {
760
+ return "mcp-server";
761
+ }
762
+ }
763
+ if (type === "command") {
764
+ if (looksLikePath(input)) {
765
+ const segments = input.split(/[\\/]/);
766
+ const base = segments[segments.length - 1] || "mcp-server";
767
+ const withoutExt = base.replace(/\.[^.]+$/, "");
768
+ return extractPackageName(withoutExt || base);
769
+ }
770
+ const parts = input.split(" ");
771
+ let startIndex = 0;
772
+ if (parts[0] === "npx" || parts[0] === "node" || parts[0] === "python") {
773
+ startIndex = 1;
774
+ }
775
+ for (let i = startIndex; i < parts.length; i++) {
776
+ const part = parts[i];
777
+ if (part && !part.startsWith("-")) {
778
+ return extractPackageName(part);
779
+ }
780
+ }
781
+ return "mcp-server";
782
+ }
783
+ return extractPackageName(input);
784
+ }
785
+ function extractPackageName(input) {
786
+ let name = input;
787
+ const atIndex = name.lastIndexOf("@");
788
+ if (atIndex > 0 && !name.startsWith("@")) {
789
+ name = name.slice(0, atIndex);
790
+ } else if (name.startsWith("@") && name.indexOf("@", 1) > 0) {
791
+ const secondAt = name.indexOf("@", 1);
792
+ name = name.slice(0, secondAt);
793
+ }
794
+ if (name.startsWith("@") && name.includes("/")) {
795
+ const parts = name.split("/");
796
+ name = parts[1] || name;
797
+ }
798
+ name = name.replace(/^mcp-server-/, "");
799
+ name = name.replace(/^server-/, "");
800
+ name = name.replace(/-mcp$/, "");
801
+ return name || "mcp-server";
802
+ }
803
+ function parseSource(input) {
804
+ const trimmed = input.trim();
805
+ if (isUrl(trimmed)) {
806
+ return {
807
+ type: "remote",
808
+ value: trimmed,
809
+ inferredName: inferName(trimmed, "remote")
810
+ };
811
+ }
812
+ if (isCommand(trimmed)) {
813
+ return {
814
+ type: "command",
815
+ value: trimmed,
816
+ inferredName: inferName(trimmed, "command")
817
+ };
818
+ }
819
+ if (isPackageName(trimmed)) {
820
+ return {
821
+ type: "package",
822
+ value: trimmed,
823
+ inferredName: inferName(trimmed, "package")
824
+ };
825
+ }
826
+ return {
827
+ type: "package",
828
+ value: trimmed,
829
+ inferredName: inferName(trimmed, "package")
830
+ };
831
+ }
832
+ function isRemoteSource(parsed) {
833
+ return parsed.type === "remote";
834
+ }
835
+
672
836
  // src/formats/utils.ts
673
837
  function deepMerge(target, source) {
674
838
  const result = { ...target };
@@ -959,9 +1123,17 @@ function buildServerConfig(parsed, options = {}) {
959
1123
  return config2;
960
1124
  }
961
1125
  if (parsed.type === "command") {
962
- const parts = parsed.value.split(" ");
963
- const command = parts[0];
964
- const args = [...parts.slice(1), ...options.args ?? []];
1126
+ let command;
1127
+ let parsedArgs;
1128
+ if (looksLikePath(parsed.value)) {
1129
+ command = parsed.value;
1130
+ parsedArgs = [];
1131
+ } else {
1132
+ const parts = parsed.value.split(" ");
1133
+ command = parts[0];
1134
+ parsedArgs = parts.slice(1);
1135
+ }
1136
+ const args = [...parsedArgs, ...options.args ?? []];
965
1137
  const config2 = {
966
1138
  command,
967
1139
  args
@@ -1207,6 +1379,8 @@ export {
1207
1379
  isTransportSupported,
1208
1380
  buildAgentSelectionChoices,
1209
1381
  selectAgentsInteractive,
1382
+ parseSource,
1383
+ isRemoteSource,
1210
1384
  getNestedValue,
1211
1385
  readConfig2 as readConfig,
1212
1386
  removeServerFromConfig,
package/dist/index.js CHANGED
@@ -13,14 +13,16 @@ import {
13
13
  getProjectCapableAgents,
14
14
  installServer,
15
15
  installServerForAgent,
16
+ isRemoteSource,
16
17
  isTransportSupported,
17
18
  listInstalledServers,
19
+ parseSource,
18
20
  removeServerFromConfig,
19
21
  saveFindRegistries,
20
22
  selectAgentsInteractive,
21
23
  supportsProjectConfig,
22
24
  updateGitignoreWithPaths
23
- } from "./chunk-56AZIA6W.js";
25
+ } from "./chunk-ONLHW5AV.js";
24
26
 
25
27
  // src/index.ts
26
28
  import { program } from "commander";
@@ -31,138 +33,12 @@ import { homedir } from "os";
31
33
  // src/types.ts
32
34
  var agentAliases = {
33
35
  "cline-vscode": "cline",
36
+ codeium: "windsurf",
37
+ cascade: "windsurf",
34
38
  gemini: "gemini-cli",
35
39
  "github-copilot": "vscode"
36
40
  };
37
41
 
38
- // src/source-parser.ts
39
- function isUrl(input) {
40
- return input.startsWith("http://") || input.startsWith("https://");
41
- }
42
- function isCommand(input) {
43
- if (input.includes(" ")) {
44
- return true;
45
- }
46
- if (input.startsWith("npx ") || input.startsWith("node ") || input.startsWith("python ")) {
47
- return true;
48
- }
49
- return false;
50
- }
51
- function isPackageName(input) {
52
- if (input.startsWith("@") && input.includes("/")) {
53
- return true;
54
- }
55
- if (/^[a-z0-9][\w.-]*(@[\w.-]+)?$/i.test(input)) {
56
- return true;
57
- }
58
- return false;
59
- }
60
- var commonTlds = /* @__PURE__ */ new Set([
61
- "com",
62
- "org",
63
- "net",
64
- "io",
65
- "dev",
66
- "ai",
67
- "tech",
68
- "co",
69
- "app",
70
- "cloud",
71
- "sh",
72
- "run"
73
- ]);
74
- function extractBrandFromHostname(hostname) {
75
- const parts = hostname.split(".");
76
- const meaningfulParts = parts.filter((part) => {
77
- const lower = part.toLowerCase();
78
- if (commonTlds.has(lower)) return false;
79
- if (lower === "mcp" || lower === "api" || lower === "www") return false;
80
- return true;
81
- });
82
- if (meaningfulParts.length > 0) {
83
- return meaningfulParts[0];
84
- }
85
- if (parts.length >= 2) {
86
- return parts[parts.length - 2];
87
- }
88
- return "mcp-server";
89
- }
90
- function inferName(input, type) {
91
- if (type === "remote") {
92
- try {
93
- const url = new URL(input);
94
- return extractBrandFromHostname(url.hostname);
95
- } catch {
96
- return "mcp-server";
97
- }
98
- }
99
- if (type === "command") {
100
- const parts = input.split(" ");
101
- let startIndex = 0;
102
- if (parts[0] === "npx" || parts[0] === "node" || parts[0] === "python") {
103
- startIndex = 1;
104
- }
105
- for (let i = startIndex; i < parts.length; i++) {
106
- const part = parts[i];
107
- if (part && !part.startsWith("-")) {
108
- return extractPackageName(part);
109
- }
110
- }
111
- return "mcp-server";
112
- }
113
- return extractPackageName(input);
114
- }
115
- function extractPackageName(input) {
116
- let name = input;
117
- const atIndex = name.lastIndexOf("@");
118
- if (atIndex > 0 && !name.startsWith("@")) {
119
- name = name.slice(0, atIndex);
120
- } else if (name.startsWith("@") && name.indexOf("@", 1) > 0) {
121
- const secondAt = name.indexOf("@", 1);
122
- name = name.slice(0, secondAt);
123
- }
124
- if (name.startsWith("@") && name.includes("/")) {
125
- const parts = name.split("/");
126
- name = parts[1] || name;
127
- }
128
- name = name.replace(/^mcp-server-/, "");
129
- name = name.replace(/^server-/, "");
130
- name = name.replace(/-mcp$/, "");
131
- return name || "mcp-server";
132
- }
133
- function parseSource(input) {
134
- const trimmed = input.trim();
135
- if (isUrl(trimmed)) {
136
- return {
137
- type: "remote",
138
- value: trimmed,
139
- inferredName: inferName(trimmed, "remote")
140
- };
141
- }
142
- if (isCommand(trimmed)) {
143
- return {
144
- type: "command",
145
- value: trimmed,
146
- inferredName: inferName(trimmed, "command")
147
- };
148
- }
149
- if (isPackageName(trimmed)) {
150
- return {
151
- type: "package",
152
- value: trimmed,
153
- inferredName: inferName(trimmed, "package")
154
- };
155
- }
156
- return {
157
- type: "package",
158
- value: trimmed,
159
- inferredName: inferName(trimmed, "package")
160
- };
161
- }
162
- function isRemoteSource(parsed) {
163
- return parsed.type === "remote";
164
- }
165
-
166
42
  // src/find.ts
167
43
  import * as p from "@clack/prompts";
168
44
 
@@ -906,7 +782,7 @@ async function runFind(query, options) {
906
782
  // package.json
907
783
  var package_default = {
908
784
  name: "add-mcp",
909
- version: "1.10.0",
785
+ version: "1.10.3",
910
786
  description: "Add MCP servers to your favorite coding agents with a single command.",
911
787
  author: "Andre Landgraf <andre@neon.tech>",
912
788
  license: "Apache-2.0",
@@ -957,6 +833,7 @@ var package_default = {
957
833
  "mcporter",
958
834
  "opencode",
959
835
  "vscode",
836
+ "windsurf",
960
837
  "zed"
961
838
  ],
962
839
  repository: {
@@ -1823,7 +1700,7 @@ async function main(target, options) {
1823
1700
  if (headerResult.invalid.length > 0) {
1824
1701
  const hint = looksLikeEatenShellVar(headerResult.invalid, ":") ? " (looks like your shell expanded a ${VAR} to an empty string; use single quotes: --header 'Key: ${VAR}' to pass the template literally)" : "";
1825
1702
  p2.log.error(
1826
- `Invalid --header value(s): ${headerResult.invalid.join(", ")}. Use "Key: Value" format.${hint}`
1703
+ `Invalid --header value(s): ${headerResult.invalid.join(", ")}. Use 'Key: Value' format.${hint}`
1827
1704
  );
1828
1705
  process.exit(1);
1829
1706
  }
@@ -1837,7 +1714,7 @@ async function main(target, options) {
1837
1714
  if (envResult.invalid.length > 0) {
1838
1715
  const hint = looksLikeEatenShellVar(envResult.invalid, "=") ? " (looks like your shell expanded a ${VAR} to an empty string; use single quotes: --env 'KEY=${VAR}' to pass the template literally)" : "";
1839
1716
  p2.log.error(
1840
- `Invalid --env value(s): ${envResult.invalid.join(", ")}. Use "KEY=VALUE" format.${hint}`
1717
+ `Invalid --env value(s): ${envResult.invalid.join(", ")}. Use 'KEY=VALUE' format.${hint}`
1841
1718
  );
1842
1719
  process.exit(1);
1843
1720
  }
package/dist/lib.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- type AgentType = "antigravity" | "cline" | "cline-cli" | "claude-code" | "claude-desktop" | "codex" | "cursor" | "gemini-cli" | "goose" | "github-copilot-cli" | "mcporter" | "opencode" | "vscode" | "zed";
1
+ type AgentType = "antigravity" | "cline" | "cline-cli" | "claude-code" | "claude-desktop" | "codex" | "cursor" | "gemini-cli" | "goose" | "github-copilot-cli" | "mcporter" | "opencode" | "vscode" | "windsurf" | "zed";
2
2
  type ConfigFormat = "json" | "yaml" | "toml";
3
3
  interface AgentConfig {
4
4
  /** Internal name */
package/dist/lib.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  listInstalledServers,
11
11
  readConfig,
12
12
  removeServerFromConfig
13
- } from "./chunk-56AZIA6W.js";
13
+ } from "./chunk-ONLHW5AV.js";
14
14
 
15
15
  // src/lib.ts
16
16
  import { existsSync } from "fs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "add-mcp",
3
- "version": "1.10.0",
3
+ "version": "1.10.3",
4
4
  "description": "Add MCP servers to your favorite coding agents with a single command.",
5
5
  "author": "Andre Landgraf <andre@neon.tech>",
6
6
  "license": "Apache-2.0",
@@ -51,6 +51,7 @@
51
51
  "mcporter",
52
52
  "opencode",
53
53
  "vscode",
54
+ "windsurf",
54
55
  "zed"
55
56
  ],
56
57
  "repository": {