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 +136 -0
- package/dist/{chunk-QY22QTBR.js → chunk-NS6HV723.js} +62 -54
- package/dist/{trust-scorer-LYC6KZCD.js → chunk-RGKHLY5G.js} +1 -0
- package/dist/{client-detector-SUIJSIYM.js → client-detector-CY7WPF3K.js} +1 -1
- package/dist/index.cjs +2375 -708
- package/dist/index.js +2181 -537
- package/dist/trust-scorer-G74WK25Q.js +7 -0
- package/package.json +3 -10
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
|
|
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(
|
|
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 =
|
|
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
|