mcpman 0.3.0 → 0.6.0

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
@@ -39,6 +39,12 @@ mcpman install @modelcontextprotocol/server-filesystem
39
39
  - **Config sync** — keep server configs consistent across all your AI clients; `--remove` cleans extras
40
40
  - **Security audit** — scan servers for vulnerabilities with trust scoring; `--fix` auto-updates vulnerable packages
41
41
  - **Auto-update** — get notified when server updates are available
42
+ - **Plugin system** — extend mcpman with npm-based plugins for custom registries (e.g. Ollama, HuggingFace)
43
+ - **Export/Import** — portable JSON bundles for full config migration across machines
44
+ - **Server testing** — validate MCP servers respond to JSON-RPC initialize + tools/list
45
+ - **Log streaming** — stream stdout/stderr from servers in real time
46
+ - **Profiles** — save/restore named server configurations for quick switching
47
+ - **Self-upgrade** — update mcpman itself with a single command
42
48
  - **Interactive prompts** — guided installation with env var configuration
43
49
  - **No extra daemon** — pure CLI, works anywhere Node ≥ 20 runs
44
50
 
@@ -153,6 +159,130 @@ mcpman update my-server # update specific server
153
159
  mcpman update --check # check only, don't apply
154
160
  ```
155
161
 
162
+ ### `config <set|get|list|reset>`
163
+
164
+ Manage persistent CLI configuration at `~/.mcpman/config.json`.
165
+
166
+ ```sh
167
+ mcpman config set defaultClient cursor
168
+ mcpman config get defaultClient
169
+ mcpman config list
170
+ mcpman config reset
171
+ ```
172
+
173
+ Keys: `defaultClient`, `updateCheckInterval`, `preferredRegistry`, `vaultTimeout`, `plugins`.
174
+
175
+ ### `search <query>`
176
+
177
+ Search for MCP servers on npm or Smithery registry.
178
+
179
+ ```sh
180
+ mcpman search filesystem
181
+ mcpman search brave --registry smithery
182
+ mcpman search tools --all # include plugin registries
183
+ mcpman search tools --limit 10
184
+ ```
185
+
186
+ **Options:**
187
+ - `--registry <npm|smithery>` — registry to search (default: npm)
188
+ - `--limit <n>` — max results (default: 20, max: 100)
189
+ - `--all` — include plugin registries in results
190
+
191
+ ### `info <server>`
192
+
193
+ Show detailed information about an MCP server package.
194
+
195
+ ```sh
196
+ mcpman info @modelcontextprotocol/server-filesystem
197
+ mcpman info my-server --json
198
+ ```
199
+
200
+ ### `run <server>`
201
+
202
+ Launch an MCP server with vault secrets auto-injected into the process environment.
203
+
204
+ ```sh
205
+ mcpman run my-server
206
+ mcpman run my-server --env API_KEY=sk-...
207
+ ```
208
+
209
+ ### `upgrade`
210
+
211
+ Upgrade mcpman itself to the latest version from npm.
212
+
213
+ ```sh
214
+ mcpman upgrade # check and install latest
215
+ mcpman upgrade --check # only check, don't install
216
+ ```
217
+
218
+ ### `test [server]`
219
+
220
+ Validate MCP server connectivity by sending JSON-RPC `initialize` + `tools/list`.
221
+
222
+ ```sh
223
+ mcpman test my-server # test a specific server
224
+ mcpman test --all # test all installed servers
225
+ ```
226
+
227
+ Reports pass/fail, response time, and discovered tools for each server.
228
+
229
+ ### `logs <server>`
230
+
231
+ Stream stdout/stderr from an MCP server process in real time.
232
+
233
+ ```sh
234
+ mcpman logs my-server # stream logs (Ctrl+C to stop)
235
+ ```
236
+
237
+ Vault secrets are auto-injected into the server environment.
238
+
239
+ ### `profiles <create|switch|list|delete>`
240
+
241
+ Manage named server configuration profiles for quick switching.
242
+
243
+ ```sh
244
+ mcpman profiles create dev # snapshot current servers as "dev"
245
+ mcpman profiles create prod -d "Production config"
246
+ mcpman profiles list # show all profiles
247
+ mcpman profiles switch dev # apply "dev" profile to lockfile
248
+ mcpman profiles delete old # remove a profile
249
+ ```
250
+
251
+ After switching, run `mcpman sync` to apply the profile to all clients.
252
+
253
+ ### `plugin <add|remove|list>`
254
+
255
+ Manage mcpman plugins for custom registries.
256
+
257
+ ```sh
258
+ mcpman plugin add mcpman-plugin-ollama # install plugin
259
+ mcpman plugin remove mcpman-plugin-ollama # uninstall plugin
260
+ mcpman plugin list # show installed plugins
261
+ ```
262
+
263
+ Plugins are npm packages that export a `McpmanPlugin` interface with `name`, `prefix`, and `resolve()`. Once installed, their prefix (e.g. `ollama:`) works with `mcpman install ollama:my-model`.
264
+
265
+ ### `export [output-file]`
266
+
267
+ Export mcpman config, lockfile, vault, and plugins to a portable JSON file.
268
+
269
+ ```sh
270
+ mcpman export # default: mcpman-export.json
271
+ mcpman export backup.json
272
+ mcpman export --no-vault # exclude encrypted vault
273
+ mcpman export --no-plugins # exclude plugin list
274
+ ```
275
+
276
+ ### `import <file>`
277
+
278
+ Restore mcpman config, lockfile, vault, and plugins from an export bundle.
279
+
280
+ ```sh
281
+ mcpman import mcpman-export.json
282
+ mcpman import backup.json --yes # skip confirmation
283
+ mcpman import backup.json --dry-run # preview without applying
284
+ ```
285
+
156
286
  ---
157
287
 
158
288
  ## Comparison
@@ -168,6 +298,12 @@ mcpman update --check # check only, don't apply
168
298
  | CI/CD | GitHub Actions | None | None |
169
299
  | Auto-update | Version check + notify | None | None |
170
300
  | Registry sources | npm + Smithery + GitHub | Smithery only | npm only |
301
+ | Plugin system | npm-based custom registries | None | None |
302
+ | Export/Import | Full config portability | None | None |
303
+ | Server testing | JSON-RPC validation | None | None |
304
+ | Log streaming | Real-time stdout/stderr | None | None |
305
+ | Profiles | Named config switching | None | None |
306
+ | Self-upgrade | Built-in CLI updater | None | None |
171
307
  | Interactive setup | Yes | Partial | No |
172
308
  | Project-scoped | Yes (`init`) | No | No |
173
309
 
@@ -1,8 +1,64 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ // src/utils/paths.ts
4
+ import os from "os";
5
+ import path from "path";
6
+ function getHomedir() {
7
+ return os.homedir();
8
+ }
9
+ function getMcpmanDir() {
10
+ return path.join(os.homedir(), ".mcpman");
11
+ }
12
+ function getConfigPath() {
13
+ return path.join(getMcpmanDir(), "config.json");
14
+ }
15
+ function getPluginDir() {
16
+ return path.join(getMcpmanDir(), "plugins");
17
+ }
18
+ function getProfilesDir() {
19
+ return path.join(getMcpmanDir(), "profiles");
20
+ }
21
+ function getAppDataDir() {
22
+ const home = getHomedir();
23
+ if (process.platform === "darwin") {
24
+ return path.join(home, "Library", "Application Support");
25
+ }
26
+ if (process.platform === "win32") {
27
+ return process.env.APPDATA ?? path.join(home, "AppData", "Roaming");
28
+ }
29
+ return process.env.XDG_CONFIG_HOME ?? path.join(home, ".config");
30
+ }
31
+ function resolveConfigPath(client) {
32
+ const appData = getAppDataDir();
33
+ const home = getHomedir();
34
+ switch (client) {
35
+ case "claude-desktop":
36
+ return path.join(appData, "Claude", "claude_desktop_config.json");
37
+ case "cursor":
38
+ return path.join(appData, "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json");
39
+ case "windsurf":
40
+ return path.join(
41
+ appData,
42
+ "Windsurf",
43
+ "User",
44
+ "globalStorage",
45
+ "windsurf.mcpConfigJson",
46
+ "mcp.json"
47
+ );
48
+ case "vscode":
49
+ if (process.platform === "darwin") {
50
+ return path.join(appData, "Code", "User", "settings.json");
51
+ }
52
+ if (process.platform === "win32") {
53
+ return path.join(appData, "Code", "User", "settings.json");
54
+ }
55
+ return path.join(home, ".config", "Code", "User", "settings.json");
56
+ }
57
+ }
58
+
3
59
  // src/clients/base-client-handler.ts
4
60
  import fs from "fs";
5
- import path from "path";
61
+ import path2 from "path";
6
62
 
7
63
  // src/clients/types.ts
8
64
  var ConfigParseError = class extends Error {
@@ -24,7 +80,7 @@ var ConfigWriteError = class extends Error {
24
80
  async function atomicWrite(filePath, content) {
25
81
  const tmpPath = `${filePath}.tmp`;
26
82
  try {
27
- await fs.promises.mkdir(path.dirname(filePath), { recursive: true });
83
+ await fs.promises.mkdir(path2.dirname(filePath), { recursive: true });
28
84
  await fs.promises.writeFile(tmpPath, content, { encoding: "utf-8", mode: 384 });
29
85
  await fs.promises.rename(tmpPath, filePath);
30
86
  } catch (err) {
@@ -45,7 +101,7 @@ async function pathExists(p) {
45
101
  }
46
102
  var BaseClientHandler = class {
47
103
  async isInstalled() {
48
- const dir = path.dirname(this.getConfigPath());
104
+ const dir = path2.dirname(this.getConfigPath());
49
105
  return pathExists(dir);
50
106
  }
51
107
  /** Read raw JSON from disk, return empty object if file missing */
@@ -99,57 +155,6 @@ var BaseClientHandler = class {
99
155
  }
100
156
  };
101
157
 
102
- // src/utils/paths.ts
103
- import os from "os";
104
- import path2 from "path";
105
- function getHomedir() {
106
- return os.homedir();
107
- }
108
- function getAppDataDir() {
109
- const home = getHomedir();
110
- if (process.platform === "darwin") {
111
- return path2.join(home, "Library", "Application Support");
112
- }
113
- if (process.platform === "win32") {
114
- return process.env.APPDATA ?? path2.join(home, "AppData", "Roaming");
115
- }
116
- return process.env.XDG_CONFIG_HOME ?? path2.join(home, ".config");
117
- }
118
- function resolveConfigPath(client) {
119
- const appData = getAppDataDir();
120
- const home = getHomedir();
121
- switch (client) {
122
- case "claude-desktop":
123
- return path2.join(appData, "Claude", "claude_desktop_config.json");
124
- case "cursor":
125
- return path2.join(
126
- appData,
127
- "Cursor",
128
- "User",
129
- "globalStorage",
130
- "cursor.mcp",
131
- "mcp.json"
132
- );
133
- case "windsurf":
134
- return path2.join(
135
- appData,
136
- "Windsurf",
137
- "User",
138
- "globalStorage",
139
- "windsurf.mcpConfigJson",
140
- "mcp.json"
141
- );
142
- case "vscode":
143
- if (process.platform === "darwin") {
144
- return path2.join(appData, "Code", "User", "settings.json");
145
- }
146
- if (process.platform === "win32") {
147
- return path2.join(appData, "Code", "User", "settings.json");
148
- }
149
- return path2.join(home, ".config", "Code", "User", "settings.json");
150
- }
151
- }
152
-
153
158
  // src/clients/claude-desktop.ts
154
159
  var ClaudeDesktopHandler = class extends BaseClientHandler {
155
160
  type = "claude-desktop";
@@ -223,6 +228,9 @@ async function getInstalledClients() {
223
228
  }
224
229
 
225
230
  export {
231
+ getConfigPath,
232
+ getPluginDir,
233
+ getProfilesDir,
226
234
  getAllClientTypes,
227
235
  getClient,
228
236
  getInstalledClients
@@ -72,6 +72,7 @@ function computeTrustScore(metadata, vulns) {
72
72
  const score = Math.min(100, Math.max(0, Math.round(weighted)));
73
73
  return { score, riskLevel: toRiskLevel(score) };
74
74
  }
75
+
75
76
  export {
76
77
  computeTrustScore
77
78
  };
@@ -3,7 +3,7 @@ import {
3
3
  getAllClientTypes,
4
4
  getClient,
5
5
  getInstalledClients
6
- } from "./chunk-QY22QTBR.js";
6
+ } from "./chunk-NS6HV723.js";
7
7
  export {
8
8
  getAllClientTypes,
9
9
  getClient,