mcpmate 0.1.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/LICENSE +21 -0
- package/README.md +176 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +191 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/export.d.ts +5 -0
- package/dist/commands/export.d.ts.map +1 -0
- package/dist/commands/export.js +117 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/install.d.ts +4 -0
- package/dist/commands/install.d.ts.map +1 -0
- package/dist/commands/install.js +120 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/list.d.ts +4 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +62 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/openclaw.d.ts +6 -0
- package/dist/commands/openclaw.d.ts.map +1 -0
- package/dist/commands/openclaw.js +163 -0
- package/dist/commands/openclaw.js.map +1 -0
- package/dist/commands/search.d.ts +4 -0
- package/dist/commands/search.d.ts.map +1 -0
- package/dist/commands/search.js +88 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/template.d.ts +5 -0
- package/dist/commands/template.d.ts.map +1 -0
- package/dist/commands/template.js +122 -0
- package/dist/commands/template.js.map +1 -0
- package/dist/commands/toggle.d.ts +3 -0
- package/dist/commands/toggle.d.ts.map +1 -0
- package/dist/commands/toggle.js +53 -0
- package/dist/commands/toggle.js.map +1 -0
- package/dist/commands/uninstall.d.ts +2 -0
- package/dist/commands/uninstall.d.ts.map +1 -0
- package/dist/commands/uninstall.js +48 -0
- package/dist/commands/uninstall.js.map +1 -0
- package/package.json +56 -0
- package/src/cli.ts +191 -0
- package/src/commands/export.ts +127 -0
- package/src/commands/install.ts +139 -0
- package/src/commands/list.ts +75 -0
- package/src/commands/openclaw.ts +186 -0
- package/src/commands/search.ts +99 -0
- package/src/commands/template.ts +135 -0
- package/src/commands/toggle.ts +58 -0
- package/src/commands/uninstall.ts +51 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.uninstallServer = uninstallServer;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const os_1 = __importDefault(require("os"));
|
|
11
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
12
|
+
const CONFIG_DIR = path_1.default.join(os_1.default.homedir(), '.mcpm');
|
|
13
|
+
const SERVERS_FILE = path_1.default.join(CONFIG_DIR, 'servers.json');
|
|
14
|
+
async function getInstalledServers() {
|
|
15
|
+
if (await fs_extra_1.default.pathExists(SERVERS_FILE)) {
|
|
16
|
+
return await fs_extra_1.default.readJson(SERVERS_FILE);
|
|
17
|
+
}
|
|
18
|
+
return {};
|
|
19
|
+
}
|
|
20
|
+
async function saveInstalledServers(servers) {
|
|
21
|
+
await fs_extra_1.default.ensureDir(CONFIG_DIR);
|
|
22
|
+
await fs_extra_1.default.writeJson(SERVERS_FILE, servers, { spaces: 2 });
|
|
23
|
+
}
|
|
24
|
+
async function uninstallServer(serverName) {
|
|
25
|
+
console.log(chalk_1.default.blue('ποΈ Uninstalling MCP server...'));
|
|
26
|
+
console.log(chalk_1.default.gray(`Server: ${serverName}`));
|
|
27
|
+
console.log();
|
|
28
|
+
const servers = await getInstalledServers();
|
|
29
|
+
if (!servers[serverName]) {
|
|
30
|
+
console.log(chalk_1.default.yellow(`β οΈ Server "${serverName}" is not installed.`));
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const { confirm } = await inquirer_1.default.prompt([{
|
|
34
|
+
type: 'confirm',
|
|
35
|
+
name: 'confirm',
|
|
36
|
+
message: `Are you sure you want to uninstall "${serverName}"?`,
|
|
37
|
+
default: false
|
|
38
|
+
}]);
|
|
39
|
+
if (!confirm) {
|
|
40
|
+
console.log(chalk_1.default.gray('Uninstallation cancelled.'));
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
delete servers[serverName];
|
|
44
|
+
await saveInstalledServers(servers);
|
|
45
|
+
console.log();
|
|
46
|
+
console.log(chalk_1.default.green('β
Server uninstalled successfully!'));
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=uninstall.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uninstall.js","sourceRoot":"","sources":["../../src/commands/uninstall.ts"],"names":[],"mappings":";;;;;AAqBA,0CA6BC;AAlDD,kDAA0B;AAC1B,wDAA0B;AAC1B,gDAAwB;AACxB,4CAAoB;AACpB,wDAAgC;AAEhC,MAAM,UAAU,GAAG,cAAI,CAAC,IAAI,CAAC,YAAE,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;AACpD,MAAM,YAAY,GAAG,cAAI,CAAC,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;AAE3D,KAAK,UAAU,mBAAmB;IAChC,IAAI,MAAM,kBAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QACtC,OAAO,MAAM,kBAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,KAAK,UAAU,oBAAoB,CAAC,OAA4B;IAC9D,MAAM,kBAAE,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAC/B,MAAM,kBAAE,CAAC,SAAS,CAAC,YAAY,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;AAC3D,CAAC;AAEM,KAAK,UAAU,eAAe,CAAC,UAAkB;IACtD,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC,CAAC;IAC3D,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,WAAW,UAAU,EAAE,CAAC,CAAC,CAAC;IACjD,OAAO,CAAC,GAAG,EAAE,CAAC;IAEd,MAAM,OAAO,GAAG,MAAM,mBAAmB,EAAE,CAAC;IAE5C,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,MAAM,CAAC,eAAe,UAAU,qBAAqB,CAAC,CAAC,CAAC;QAC1E,OAAO;IACT,CAAC;IAED,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,kBAAQ,CAAC,MAAM,CAAC,CAAC;YACzC,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,uCAAuC,UAAU,IAAI;YAC9D,OAAO,EAAE,KAAK;SACf,CAAC,CAAC,CAAC;IAEJ,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC,CAAC;QACrD,OAAO;IACT,CAAC;IAED,OAAO,OAAO,CAAC,UAAU,CAAC,CAAC;IAC3B,MAAM,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAEpC,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC,CAAC;AACjE,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mcpmate",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP Mate - The ultimate MCP server manager for OpenClaw and Chinese developers",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"mcpmate": "dist/cli.js",
|
|
8
|
+
"mcm": "dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"dev": "ts-node src/cli.ts",
|
|
13
|
+
"start": "node dist/cli.js",
|
|
14
|
+
"test": "jest"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"mcp",
|
|
18
|
+
"model-context-protocol",
|
|
19
|
+
"cli",
|
|
20
|
+
"server-manager",
|
|
21
|
+
"openclaw",
|
|
22
|
+
"feishu",
|
|
23
|
+
"dingtalk",
|
|
24
|
+
"china"
|
|
25
|
+
],
|
|
26
|
+
"author": "Clawton",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/clawton/mcpmate.git"
|
|
31
|
+
},
|
|
32
|
+
"bugs": {
|
|
33
|
+
"url": "https://github.com/clawton/mcpmate/issues"
|
|
34
|
+
},
|
|
35
|
+
"homepage": "https://github.com/clawton/mcpmate#readme",
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"commander": "^11.1.0",
|
|
38
|
+
"chalk": "^4.1.2",
|
|
39
|
+
"inquirer": "^8.2.6",
|
|
40
|
+
"axios": "^1.6.2",
|
|
41
|
+
"fs-extra": "^11.2.0",
|
|
42
|
+
"yaml": "^2.3.4"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/node": "^20.10.4",
|
|
46
|
+
"@types/fs-extra": "^11.0.4",
|
|
47
|
+
"@types/inquirer": "^9.0.7",
|
|
48
|
+
"typescript": "^5.3.3",
|
|
49
|
+
"ts-node": "^10.9.2",
|
|
50
|
+
"jest": "^29.7.0",
|
|
51
|
+
"@types/jest": "^29.5.11"
|
|
52
|
+
},
|
|
53
|
+
"engines": {
|
|
54
|
+
"node": ">=18.0.0"
|
|
55
|
+
}
|
|
56
|
+
}
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import { searchServers } from './commands/search';
|
|
6
|
+
import { installServer } from './commands/install';
|
|
7
|
+
import { listServers } from './commands/list';
|
|
8
|
+
import { uninstallServer } from './commands/uninstall';
|
|
9
|
+
import { enableServer, disableServer } from './commands/toggle';
|
|
10
|
+
import { exportConfig } from './commands/export';
|
|
11
|
+
import { openclawCommand } from './commands/openclaw';
|
|
12
|
+
import { templateCommand } from './commands/template';
|
|
13
|
+
|
|
14
|
+
const program = new Command();
|
|
15
|
+
|
|
16
|
+
program
|
|
17
|
+
.name('mcpmate')
|
|
18
|
+
.alias('mcm')
|
|
19
|
+
.description('MCP Mate - The ultimate MCP server manager for OpenClaw and Chinese developers')
|
|
20
|
+
.version('0.1.0');
|
|
21
|
+
|
|
22
|
+
program
|
|
23
|
+
.command('search')
|
|
24
|
+
.description('Search for MCP servers in the registry')
|
|
25
|
+
.argument('<query>', 'Search query')
|
|
26
|
+
.option('-c, --category <category>', 'Filter by category')
|
|
27
|
+
.action(async (query, options) => {
|
|
28
|
+
try {
|
|
29
|
+
await searchServers(query, options);
|
|
30
|
+
} catch (error) {
|
|
31
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
program
|
|
37
|
+
.command('install')
|
|
38
|
+
.description('Install an MCP server')
|
|
39
|
+
.argument('<server>', 'Server name or package')
|
|
40
|
+
.option('-g, --global', 'Install globally')
|
|
41
|
+
.action(async (server, options) => {
|
|
42
|
+
try {
|
|
43
|
+
await installServer(server, options);
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
program
|
|
51
|
+
.command('list')
|
|
52
|
+
.alias('ls')
|
|
53
|
+
.description('List installed MCP servers')
|
|
54
|
+
.option('-a, --all', 'Show all servers including disabled')
|
|
55
|
+
.action(async (options) => {
|
|
56
|
+
try {
|
|
57
|
+
await listServers(options);
|
|
58
|
+
} catch (error) {
|
|
59
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
program
|
|
65
|
+
.command('uninstall')
|
|
66
|
+
.alias('remove')
|
|
67
|
+
.description('Uninstall an MCP server')
|
|
68
|
+
.argument('<server>', 'Server name')
|
|
69
|
+
.action(async (server) => {
|
|
70
|
+
try {
|
|
71
|
+
await uninstallServer(server);
|
|
72
|
+
} catch (error) {
|
|
73
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
program
|
|
79
|
+
.command('enable')
|
|
80
|
+
.description('Enable an MCP server')
|
|
81
|
+
.argument('<server>', 'Server name')
|
|
82
|
+
.action(async (server) => {
|
|
83
|
+
try {
|
|
84
|
+
await enableServer(server);
|
|
85
|
+
} catch (error) {
|
|
86
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
program
|
|
92
|
+
.command('disable')
|
|
93
|
+
.description('Disable an MCP server')
|
|
94
|
+
.argument('<server>', 'Server name')
|
|
95
|
+
.action(async (server) => {
|
|
96
|
+
try {
|
|
97
|
+
await disableServer(server);
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
program
|
|
105
|
+
.command('export')
|
|
106
|
+
.description('Export MCP configuration')
|
|
107
|
+
.option('-f, --format <format>', 'Export format (claude|cursor|openclaw)', 'openclaw')
|
|
108
|
+
.option('-o, --output <path>', 'Output file path')
|
|
109
|
+
.action(async (options) => {
|
|
110
|
+
try {
|
|
111
|
+
await exportConfig(options);
|
|
112
|
+
} catch (error) {
|
|
113
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
114
|
+
process.exit(1);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Template commands (εΊζ―樑ζΏ)
|
|
119
|
+
const template = program
|
|
120
|
+
.command('template')
|
|
121
|
+
.alias('t')
|
|
122
|
+
.description('Scene templates for quick setup');
|
|
123
|
+
|
|
124
|
+
template
|
|
125
|
+
.command('list')
|
|
126
|
+
.description('List available templates')
|
|
127
|
+
.action(async () => {
|
|
128
|
+
try {
|
|
129
|
+
await templateCommand.list();
|
|
130
|
+
} catch (error) {
|
|
131
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
132
|
+
process.exit(1);
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
template
|
|
137
|
+
.command('use')
|
|
138
|
+
.description('Use a template')
|
|
139
|
+
.argument('<template>', 'Template name')
|
|
140
|
+
.action(async (templateName) => {
|
|
141
|
+
try {
|
|
142
|
+
await templateCommand.use(templateName);
|
|
143
|
+
} catch (error) {
|
|
144
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
145
|
+
process.exit(1);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// OpenClaw integration commands
|
|
150
|
+
const openclaw = program
|
|
151
|
+
.command('openclaw')
|
|
152
|
+
.alias('oc')
|
|
153
|
+
.description('OpenClaw integration commands');
|
|
154
|
+
|
|
155
|
+
openclaw
|
|
156
|
+
.command('setup')
|
|
157
|
+
.description('Setup MCP servers for OpenClaw')
|
|
158
|
+
.action(async () => {
|
|
159
|
+
try {
|
|
160
|
+
await openclawCommand.setup();
|
|
161
|
+
} catch (error) {
|
|
162
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
163
|
+
process.exit(1);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
openclaw
|
|
168
|
+
.command('sync')
|
|
169
|
+
.description('Sync MCP configuration to OpenClaw')
|
|
170
|
+
.action(async () => {
|
|
171
|
+
try {
|
|
172
|
+
await openclawCommand.sync();
|
|
173
|
+
} catch (error) {
|
|
174
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
175
|
+
process.exit(1);
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
openclaw
|
|
180
|
+
.command('status')
|
|
181
|
+
.description('Show OpenClaw MCP configuration status')
|
|
182
|
+
.action(async () => {
|
|
183
|
+
try {
|
|
184
|
+
await openclawCommand.status();
|
|
185
|
+
} catch (error) {
|
|
186
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
187
|
+
process.exit(1);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
program.parse();
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
import YAML from 'yaml';
|
|
6
|
+
|
|
7
|
+
const CONFIG_DIR = path.join(os.homedir(), '.mcpm');
|
|
8
|
+
const SERVERS_FILE = path.join(CONFIG_DIR, 'servers.json');
|
|
9
|
+
|
|
10
|
+
async function getInstalledServers(): Promise<Record<string, any>> {
|
|
11
|
+
if (await fs.pathExists(SERVERS_FILE)) {
|
|
12
|
+
return await fs.readJson(SERVERS_FILE);
|
|
13
|
+
}
|
|
14
|
+
return {};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function generateClaudeConfig(servers: Record<string, any>): any {
|
|
18
|
+
const mcpServers: Record<string, any> = {};
|
|
19
|
+
|
|
20
|
+
Object.values(servers)
|
|
21
|
+
.filter((s: any) => s.enabled)
|
|
22
|
+
.forEach((server: any) => {
|
|
23
|
+
mcpServers[server.name] = {
|
|
24
|
+
command: server.command,
|
|
25
|
+
args: server.args,
|
|
26
|
+
env: server.env
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
return { mcpServers };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function generateCursorConfig(servers: Record<string, any>): any {
|
|
34
|
+
// Cursor uses a similar format to Claude
|
|
35
|
+
return generateClaudeConfig(servers);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function generateOpenClawConfig(servers: Record<string, any>): any {
|
|
39
|
+
// OpenClaw specific format
|
|
40
|
+
const mcpServers: Record<string, any> = {};
|
|
41
|
+
|
|
42
|
+
Object.values(servers)
|
|
43
|
+
.filter((s: any) => s.enabled)
|
|
44
|
+
.forEach((server: any) => {
|
|
45
|
+
mcpServers[server.name] = {
|
|
46
|
+
command: server.command,
|
|
47
|
+
args: server.args,
|
|
48
|
+
env: server.env,
|
|
49
|
+
enabled: true
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
version: '1.0',
|
|
55
|
+
mcpServers,
|
|
56
|
+
metadata: {
|
|
57
|
+
exportedAt: new Date().toISOString(),
|
|
58
|
+
tool: 'mcp-server-manager',
|
|
59
|
+
version: '0.1.0'
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export async function exportConfig(options: { format?: string; output?: string }): Promise<void> {
|
|
65
|
+
const format = options.format || 'openclaw';
|
|
66
|
+
const servers = await getInstalledServers();
|
|
67
|
+
const enabledServers = Object.values(servers).filter((s: any) => s.enabled);
|
|
68
|
+
|
|
69
|
+
if (enabledServers.length === 0) {
|
|
70
|
+
console.log(chalk.yellow('β οΈ No enabled servers to export.'));
|
|
71
|
+
console.log(chalk.gray('Enable servers with:'), chalk.cyan('mcpm enable <server>'));
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
console.log(chalk.blue('π€ Exporting MCP configuration...'));
|
|
76
|
+
console.log(chalk.gray(`Format: ${format}`));
|
|
77
|
+
console.log(chalk.gray(`Servers: ${enabledServers.length}`));
|
|
78
|
+
console.log();
|
|
79
|
+
|
|
80
|
+
let config: any;
|
|
81
|
+
let ext: string;
|
|
82
|
+
|
|
83
|
+
switch (format) {
|
|
84
|
+
case 'claude':
|
|
85
|
+
config = generateClaudeConfig(servers);
|
|
86
|
+
ext = 'json';
|
|
87
|
+
break;
|
|
88
|
+
case 'cursor':
|
|
89
|
+
config = generateCursorConfig(servers);
|
|
90
|
+
ext = 'json';
|
|
91
|
+
break;
|
|
92
|
+
case 'openclaw':
|
|
93
|
+
default:
|
|
94
|
+
config = generateOpenClawConfig(servers);
|
|
95
|
+
ext = 'yaml';
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const outputPath = options.output || `mcp-config.${ext}`;
|
|
100
|
+
|
|
101
|
+
if (ext === 'json') {
|
|
102
|
+
await fs.writeJson(outputPath, config, { spaces: 2 });
|
|
103
|
+
} else {
|
|
104
|
+
await fs.writeFile(outputPath, YAML.stringify(config));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
console.log(chalk.green('β
Configuration exported successfully!'));
|
|
108
|
+
console.log(chalk.gray(`Output: ${path.resolve(outputPath)}`));
|
|
109
|
+
console.log();
|
|
110
|
+
console.log(chalk.blue('π‘ Next steps:'));
|
|
111
|
+
|
|
112
|
+
switch (format) {
|
|
113
|
+
case 'claude':
|
|
114
|
+
console.log(chalk.gray(' 1. Copy the configuration to Claude Desktop settings'));
|
|
115
|
+
console.log(chalk.gray(' 2. Restart Claude Desktop'));
|
|
116
|
+
break;
|
|
117
|
+
case 'cursor':
|
|
118
|
+
console.log(chalk.gray(' 1. Copy the configuration to Cursor MCP settings'));
|
|
119
|
+
console.log(chalk.gray(' 2. Restart Cursor'));
|
|
120
|
+
break;
|
|
121
|
+
case 'openclaw':
|
|
122
|
+
default:
|
|
123
|
+
console.log(chalk.gray(' 1. Run:'), chalk.cyan('mcpm openclaw sync'));
|
|
124
|
+
console.log(chalk.gray(' 2. Or manually copy to OpenClaw MCP configuration'));
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import inquirer from 'inquirer';
|
|
3
|
+
import fs from 'fs-extra';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import os from 'os';
|
|
6
|
+
|
|
7
|
+
interface ServerConfig {
|
|
8
|
+
name: string;
|
|
9
|
+
command: string;
|
|
10
|
+
args: string[];
|
|
11
|
+
env?: Record<string, string>;
|
|
12
|
+
enabled: boolean;
|
|
13
|
+
installedAt: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const CONFIG_DIR = path.join(os.homedir(), '.mcpm');
|
|
17
|
+
const SERVERS_FILE = path.join(CONFIG_DIR, 'servers.json');
|
|
18
|
+
|
|
19
|
+
async function ensureConfigDir(): Promise<void> {
|
|
20
|
+
await fs.ensureDir(CONFIG_DIR);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function getInstalledServers(): Promise<Record<string, ServerConfig>> {
|
|
24
|
+
await ensureConfigDir();
|
|
25
|
+
if (await fs.pathExists(SERVERS_FILE)) {
|
|
26
|
+
return await fs.readJson(SERVERS_FILE);
|
|
27
|
+
}
|
|
28
|
+
return {};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function saveInstalledServers(servers: Record<string, ServerConfig>): Promise<void> {
|
|
32
|
+
await ensureConfigDir();
|
|
33
|
+
await fs.writeJson(SERVERS_FILE, servers, { spaces: 2 });
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Mock installation logic for MVP
|
|
37
|
+
const SERVER_TEMPLATES: Record<string, Partial<ServerConfig>> = {
|
|
38
|
+
'@modelcontextprotocol/server-postgres': {
|
|
39
|
+
command: 'docker',
|
|
40
|
+
args: ['run', '-i', '--rm', 'mcp/postgres'],
|
|
41
|
+
env: {
|
|
42
|
+
POSTGRES_HOST: 'localhost',
|
|
43
|
+
POSTGRES_PORT: '5432',
|
|
44
|
+
POSTGRES_DB: 'postgres',
|
|
45
|
+
POSTGRES_USER: 'postgres'
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
'@modelcontextprotocol/server-github': {
|
|
49
|
+
command: 'docker',
|
|
50
|
+
args: ['run', '-i', '--rm', 'mcp/github'],
|
|
51
|
+
env: {
|
|
52
|
+
GITHUB_PERSONAL_ACCESS_TOKEN: ''
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
'@modelcontextprotocol/server-filesystem': {
|
|
56
|
+
command: 'docker',
|
|
57
|
+
args: ['run', '-i', '--rm', '-v', '${HOME}:/home/user', 'mcp/filesystem'],
|
|
58
|
+
env: {}
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export async function installServer(serverName: string, options: { global?: boolean }): Promise<void> {
|
|
63
|
+
console.log(chalk.blue('π¦ Installing MCP server...'));
|
|
64
|
+
console.log(chalk.gray(`Server: ${serverName}`));
|
|
65
|
+
console.log();
|
|
66
|
+
|
|
67
|
+
const installedServers = await getInstalledServers();
|
|
68
|
+
|
|
69
|
+
// Check if already installed
|
|
70
|
+
if (installedServers[serverName]) {
|
|
71
|
+
console.log(chalk.yellow(`β οΈ Server "${serverName}" is already installed.`));
|
|
72
|
+
console.log(chalk.gray('Use "mcpm update" to update or "mcpm uninstall" to remove.'));
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Get server template
|
|
77
|
+
const template = SERVER_TEMPLATES[serverName];
|
|
78
|
+
if (!template) {
|
|
79
|
+
console.log(chalk.yellow(`β οΈ Server "${serverName}" not found in registry.`));
|
|
80
|
+
console.log(chalk.gray('Searching for similar servers...'));
|
|
81
|
+
// TODO: Implement fuzzy search
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Interactive configuration
|
|
86
|
+
const config: ServerConfig = {
|
|
87
|
+
name: serverName,
|
|
88
|
+
command: template.command || 'docker',
|
|
89
|
+
args: template.args || [],
|
|
90
|
+
env: {},
|
|
91
|
+
enabled: true,
|
|
92
|
+
installedAt: new Date().toISOString()
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// Prompt for environment variables
|
|
96
|
+
if (template.env) {
|
|
97
|
+
console.log(chalk.blue('π§ Configuration required:\n'));
|
|
98
|
+
|
|
99
|
+
for (const [key, defaultValue] of Object.entries(template.env)) {
|
|
100
|
+
const { value } = await inquirer.prompt([{
|
|
101
|
+
type: 'input',
|
|
102
|
+
name: 'value',
|
|
103
|
+
message: `${key}${defaultValue ? ` (default: ${defaultValue})` : ''}:`,
|
|
104
|
+
default: defaultValue || undefined
|
|
105
|
+
}]);
|
|
106
|
+
|
|
107
|
+
if (value) {
|
|
108
|
+
config.env = config.env || {};
|
|
109
|
+
config.env[key] = value;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Confirm installation
|
|
115
|
+
const { confirm } = await inquirer.prompt([{
|
|
116
|
+
type: 'confirm',
|
|
117
|
+
name: 'confirm',
|
|
118
|
+
message: 'Install this server?',
|
|
119
|
+
default: true
|
|
120
|
+
}]);
|
|
121
|
+
|
|
122
|
+
if (!confirm) {
|
|
123
|
+
console.log(chalk.gray('Installation cancelled.'));
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Save configuration
|
|
128
|
+
installedServers[serverName] = config;
|
|
129
|
+
await saveInstalledServers(installedServers);
|
|
130
|
+
|
|
131
|
+
console.log();
|
|
132
|
+
console.log(chalk.green('β
Server installed successfully!'));
|
|
133
|
+
console.log(chalk.gray(`Configuration saved to: ${SERVERS_FILE}`));
|
|
134
|
+
console.log();
|
|
135
|
+
console.log(chalk.blue('π‘ Next steps:'));
|
|
136
|
+
console.log(chalk.gray(' - Enable the server:'), chalk.cyan(`mcpm enable ${serverName}`));
|
|
137
|
+
console.log(chalk.gray(' - Export configuration:'), chalk.cyan('mcpm export'));
|
|
138
|
+
console.log(chalk.gray(' - View all servers:'), chalk.cyan('mcpm list'));
|
|
139
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
|
|
6
|
+
interface ServerConfig {
|
|
7
|
+
name: string;
|
|
8
|
+
command: string;
|
|
9
|
+
args: string[];
|
|
10
|
+
env?: Record<string, string>;
|
|
11
|
+
enabled: boolean;
|
|
12
|
+
installedAt: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const CONFIG_DIR = path.join(os.homedir(), '.mcpm');
|
|
16
|
+
const SERVERS_FILE = path.join(CONFIG_DIR, 'servers.json');
|
|
17
|
+
|
|
18
|
+
async function getInstalledServers(): Promise<Record<string, ServerConfig>> {
|
|
19
|
+
if (await fs.pathExists(SERVERS_FILE)) {
|
|
20
|
+
return await fs.readJson(SERVERS_FILE);
|
|
21
|
+
}
|
|
22
|
+
return {};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function listServers(options: { all?: boolean }): Promise<void> {
|
|
26
|
+
console.log(chalk.blue('π Installed MCP servers\n'));
|
|
27
|
+
|
|
28
|
+
const servers = await getInstalledServers();
|
|
29
|
+
const serverList = Object.values(servers);
|
|
30
|
+
|
|
31
|
+
if (serverList.length === 0) {
|
|
32
|
+
console.log(chalk.yellow('No servers installed yet.'));
|
|
33
|
+
console.log(chalk.gray('Search and install servers with:'), chalk.cyan('mcpm search <query>'));
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Filter enabled/disabled
|
|
38
|
+
const filteredServers = options.all
|
|
39
|
+
? serverList
|
|
40
|
+
: serverList.filter(s => s.enabled);
|
|
41
|
+
|
|
42
|
+
if (filteredServers.length === 0 && !options.all) {
|
|
43
|
+
console.log(chalk.yellow('No enabled servers.'));
|
|
44
|
+
console.log(chalk.gray('Use --all to see disabled servers.'));
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Group by status
|
|
49
|
+
const enabledServers = filteredServers.filter(s => s.enabled);
|
|
50
|
+
const disabledServers = filteredServers.filter(s => !s.enabled);
|
|
51
|
+
|
|
52
|
+
if (enabledServers.length > 0) {
|
|
53
|
+
console.log(chalk.green(`β
Enabled (${enabledServers.length}):\n`));
|
|
54
|
+
enabledServers.forEach((server, index) => {
|
|
55
|
+
console.log(chalk.white(` ${index + 1}. ${chalk.bold(server.name)}`));
|
|
56
|
+
console.log(chalk.gray(` Command: ${server.command} ${server.args.join(' ')}`));
|
|
57
|
+
console.log(chalk.gray(` Installed: ${new Date(server.installedAt).toLocaleDateString()}`));
|
|
58
|
+
console.log();
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (disabledServers.length > 0) {
|
|
63
|
+
console.log(chalk.gray(`βΈοΈ Disabled (${disabledServers.length}):\n`));
|
|
64
|
+
disabledServers.forEach((server, index) => {
|
|
65
|
+
console.log(chalk.gray(` ${index + 1}. ${server.name}`));
|
|
66
|
+
console.log();
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
console.log(chalk.blue('π‘ Commands:'));
|
|
71
|
+
console.log(chalk.gray(' Enable:'), chalk.cyan('mcpm enable <server>'));
|
|
72
|
+
console.log(chalk.gray(' Disable:'), chalk.cyan('mcpm disable <server>'));
|
|
73
|
+
console.log(chalk.gray(' Uninstall:'), chalk.cyan('mcpm uninstall <server>'));
|
|
74
|
+
console.log(chalk.gray(' Export:'), chalk.cyan('mcpm export'));
|
|
75
|
+
}
|