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,186 @@
|
|
|
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
|
+
// OpenClaw configuration paths
|
|
11
|
+
const OPENCLAW_CONFIG_PATHS = [
|
|
12
|
+
path.join(os.homedir(), '.openclaw', 'mcp.yaml'),
|
|
13
|
+
path.join(os.homedir(), '.openclaw', 'mcp.json'),
|
|
14
|
+
path.join(os.homedir(), '.openclaw', 'config', 'mcp.yaml'),
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
async function getInstalledServers(): Promise<Record<string, any>> {
|
|
18
|
+
if (await fs.pathExists(SERVERS_FILE)) {
|
|
19
|
+
return await fs.readJson(SERVERS_FILE);
|
|
20
|
+
}
|
|
21
|
+
return {};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function findOpenClawConfig(): Promise<string | null> {
|
|
25
|
+
for (const configPath of OPENCLAW_CONFIG_PATHS) {
|
|
26
|
+
if (await fs.pathExists(configPath)) {
|
|
27
|
+
return configPath;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function ensureOpenClawConfigDir(): Promise<string> {
|
|
34
|
+
const openclawDir = path.join(os.homedir(), '.openclaw');
|
|
35
|
+
await fs.ensureDir(openclawDir);
|
|
36
|
+
return path.join(openclawDir, 'mcp.yaml');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const openclawCommand = {
|
|
40
|
+
async setup(): Promise<void> {
|
|
41
|
+
console.log(chalk.blue('🔧 Setting up OpenClaw MCP integration...\n'));
|
|
42
|
+
|
|
43
|
+
const existingConfig = await findOpenClawConfig();
|
|
44
|
+
|
|
45
|
+
if (existingConfig) {
|
|
46
|
+
console.log(chalk.green('✅ OpenClaw configuration found:'));
|
|
47
|
+
console.log(chalk.gray(` ${existingConfig}`));
|
|
48
|
+
console.log();
|
|
49
|
+
console.log(chalk.blue('💡 Run the following to sync your MCP servers:'));
|
|
50
|
+
console.log(chalk.cyan(' mcpm openclaw sync'));
|
|
51
|
+
} else {
|
|
52
|
+
console.log(chalk.yellow('⚠️ No existing OpenClaw configuration found.'));
|
|
53
|
+
console.log(chalk.gray('Creating new configuration...\n'));
|
|
54
|
+
|
|
55
|
+
const configPath = await ensureOpenClawConfigDir();
|
|
56
|
+
const initialConfig = {
|
|
57
|
+
version: '1.0',
|
|
58
|
+
mcpServers: {},
|
|
59
|
+
metadata: {
|
|
60
|
+
createdAt: new Date().toISOString(),
|
|
61
|
+
tool: 'mcp-server-manager'
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
await fs.writeFile(configPath, YAML.stringify(initialConfig));
|
|
66
|
+
|
|
67
|
+
console.log(chalk.green('✅ OpenClaw configuration created:'));
|
|
68
|
+
console.log(chalk.gray(` ${configPath}`));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
console.log();
|
|
72
|
+
console.log(chalk.blue('📚 Next steps:'));
|
|
73
|
+
console.log(chalk.gray(' 1. Install MCP servers:'), chalk.cyan('mcpm install <server>'));
|
|
74
|
+
console.log(chalk.gray(' 2. Enable servers:'), chalk.cyan('mcpm enable <server>'));
|
|
75
|
+
console.log(chalk.gray(' 3. Sync to OpenClaw:'), chalk.cyan('mcpm openclaw sync'));
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
async sync(): Promise<void> {
|
|
79
|
+
console.log(chalk.blue('🔄 Syncing MCP configuration to OpenClaw...\n'));
|
|
80
|
+
|
|
81
|
+
const servers = await getInstalledServers();
|
|
82
|
+
const enabledServers = Object.values(servers).filter((s: any) => s.enabled);
|
|
83
|
+
|
|
84
|
+
if (enabledServers.length === 0) {
|
|
85
|
+
console.log(chalk.yellow('⚠️ No enabled servers to sync.'));
|
|
86
|
+
console.log(chalk.gray('Enable servers with:'), chalk.cyan('mcpm enable <server>'));
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const configPath = await findOpenClawConfig() || await ensureOpenClawConfigDir();
|
|
91
|
+
|
|
92
|
+
// Build MCP servers config
|
|
93
|
+
const mcpServers: Record<string, any> = {};
|
|
94
|
+
enabledServers.forEach((server: any) => {
|
|
95
|
+
mcpServers[server.name] = {
|
|
96
|
+
command: server.command,
|
|
97
|
+
args: server.args,
|
|
98
|
+
env: server.env || {},
|
|
99
|
+
enabled: true
|
|
100
|
+
};
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Read existing config or create new
|
|
104
|
+
let existingConfig: any = {};
|
|
105
|
+
if (await fs.pathExists(configPath)) {
|
|
106
|
+
const content = await fs.readFile(configPath, 'utf-8');
|
|
107
|
+
existingConfig = YAML.parse(content) || {};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Merge configs
|
|
111
|
+
const newConfig = {
|
|
112
|
+
...existingConfig,
|
|
113
|
+
version: existingConfig.version || '1.0',
|
|
114
|
+
mcpServers,
|
|
115
|
+
metadata: {
|
|
116
|
+
...(existingConfig.metadata || {}),
|
|
117
|
+
lastSyncedAt: new Date().toISOString(),
|
|
118
|
+
tool: 'mcp-server-manager',
|
|
119
|
+
version: '0.1.0'
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
await fs.writeFile(configPath, YAML.stringify(newConfig));
|
|
124
|
+
|
|
125
|
+
console.log(chalk.green('✅ Synced successfully!'));
|
|
126
|
+
console.log(chalk.gray(`Configuration: ${configPath}`));
|
|
127
|
+
console.log(chalk.gray(`Servers synced: ${enabledServers.length}`));
|
|
128
|
+
console.log();
|
|
129
|
+
|
|
130
|
+
enabledServers.forEach((server: any) => {
|
|
131
|
+
console.log(chalk.gray(` • ${server.name}`));
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
console.log();
|
|
135
|
+
console.log(chalk.blue('💡 Restart OpenClaw to apply changes.'));
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
async status(): Promise<void> {
|
|
139
|
+
console.log(chalk.blue('📊 OpenClaw MCP Configuration Status\n'));
|
|
140
|
+
|
|
141
|
+
const configPath = await findOpenClawConfig();
|
|
142
|
+
|
|
143
|
+
if (!configPath) {
|
|
144
|
+
console.log(chalk.yellow('⚠️ OpenClaw configuration not found.'));
|
|
145
|
+
console.log(chalk.gray('Run setup first:'), chalk.cyan('mcpm openclaw setup'));
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
console.log(chalk.green('✅ Configuration found:'));
|
|
150
|
+
console.log(chalk.gray(` ${configPath}`));
|
|
151
|
+
console.log();
|
|
152
|
+
|
|
153
|
+
const content = await fs.readFile(configPath, 'utf-8');
|
|
154
|
+
const config = YAML.parse(content) || {};
|
|
155
|
+
|
|
156
|
+
if (config.metadata) {
|
|
157
|
+
console.log(chalk.blue('Metadata:'));
|
|
158
|
+
if (config.metadata.lastSyncedAt) {
|
|
159
|
+
console.log(chalk.gray(` Last synced: ${new Date(config.metadata.lastSyncedAt).toLocaleString()}`));
|
|
160
|
+
}
|
|
161
|
+
if (config.metadata.tool) {
|
|
162
|
+
console.log(chalk.gray(` Managed by: ${config.metadata.tool}`));
|
|
163
|
+
}
|
|
164
|
+
console.log();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const mcpServers = config.mcpServers || {};
|
|
168
|
+
const serverCount = Object.keys(mcpServers).length;
|
|
169
|
+
|
|
170
|
+
if (serverCount === 0) {
|
|
171
|
+
console.log(chalk.yellow('No MCP servers configured.'));
|
|
172
|
+
} else {
|
|
173
|
+
console.log(chalk.blue(`MCP Servers (${serverCount}):\n`));
|
|
174
|
+
Object.entries(mcpServers).forEach(([name, server]: [string, any]) => {
|
|
175
|
+
const status = server.enabled !== false ? chalk.green('✅') : chalk.gray('⏸️');
|
|
176
|
+
console.log(` ${status} ${name}`);
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
console.log();
|
|
181
|
+
console.log(chalk.blue('💡 Commands:'));
|
|
182
|
+
console.log(chalk.gray(' Sync:'), chalk.cyan('mcpm openclaw sync'));
|
|
183
|
+
console.log(chalk.gray(' List local:'), chalk.cyan('mcpm list'));
|
|
184
|
+
console.log(chalk.gray(' Install:'), chalk.cyan('mcpm install <server>'));
|
|
185
|
+
}
|
|
186
|
+
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import axios from 'axios';
|
|
3
|
+
|
|
4
|
+
interface ServerInfo {
|
|
5
|
+
name: string;
|
|
6
|
+
description: string;
|
|
7
|
+
author: string;
|
|
8
|
+
category: string;
|
|
9
|
+
downloads: number;
|
|
10
|
+
rating: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Mock registry data for MVP
|
|
14
|
+
const MOCK_REGISTRY: ServerInfo[] = [
|
|
15
|
+
{
|
|
16
|
+
name: '@modelcontextprotocol/server-postgres',
|
|
17
|
+
description: 'PostgreSQL database integration',
|
|
18
|
+
author: 'Anthropic',
|
|
19
|
+
category: 'database',
|
|
20
|
+
downloads: 15000,
|
|
21
|
+
rating: 4.5
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: '@modelcontextprotocol/server-github',
|
|
25
|
+
description: 'GitHub API integration',
|
|
26
|
+
author: 'Anthropic',
|
|
27
|
+
category: 'version-control',
|
|
28
|
+
downloads: 12000,
|
|
29
|
+
rating: 4.7
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: '@modelcontextprotocol/server-filesystem',
|
|
33
|
+
description: 'Local filesystem access',
|
|
34
|
+
author: 'Anthropic',
|
|
35
|
+
category: 'filesystem',
|
|
36
|
+
downloads: 20000,
|
|
37
|
+
rating: 4.6
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: '@modelcontextprotocol/server-puppeteer',
|
|
41
|
+
description: 'Web scraping and browser automation',
|
|
42
|
+
author: 'Anthropic',
|
|
43
|
+
category: 'automation',
|
|
44
|
+
downloads: 8000,
|
|
45
|
+
rating: 4.3
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: '@modelcontextprotocol/server-redis',
|
|
49
|
+
description: 'Redis database integration',
|
|
50
|
+
author: 'Community',
|
|
51
|
+
category: 'database',
|
|
52
|
+
downloads: 6000,
|
|
53
|
+
rating: 4.4
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: '@modelcontextprotocol/server-slack',
|
|
57
|
+
description: 'Slack workspace integration',
|
|
58
|
+
author: 'Anthropic',
|
|
59
|
+
category: 'communication',
|
|
60
|
+
downloads: 9000,
|
|
61
|
+
rating: 4.5
|
|
62
|
+
}
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
export async function searchServers(query: string, options: { category?: string }): Promise<void> {
|
|
66
|
+
console.log(chalk.blue('🔍 Searching for MCP servers...'));
|
|
67
|
+
console.log(chalk.gray(`Query: "${query}"`));
|
|
68
|
+
|
|
69
|
+
if (options.category) {
|
|
70
|
+
console.log(chalk.gray(`Category: ${options.category}`));
|
|
71
|
+
}
|
|
72
|
+
console.log();
|
|
73
|
+
|
|
74
|
+
// Filter servers based on query
|
|
75
|
+
const filteredServers = MOCK_REGISTRY.filter(server => {
|
|
76
|
+
const matchesQuery = server.name.toLowerCase().includes(query.toLowerCase()) ||
|
|
77
|
+
server.description.toLowerCase().includes(query.toLowerCase());
|
|
78
|
+
const matchesCategory = !options.category || server.category === options.category;
|
|
79
|
+
return matchesQuery && matchesCategory;
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
if (filteredServers.length === 0) {
|
|
83
|
+
console.log(chalk.yellow('No servers found matching your query.'));
|
|
84
|
+
console.log(chalk.gray('Try searching with different keywords or browse all with: mcpm list --all'));
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
console.log(chalk.green(`Found ${filteredServers.length} server(s):\n`));
|
|
89
|
+
|
|
90
|
+
filteredServers.forEach((server, index) => {
|
|
91
|
+
console.log(chalk.white(`${index + 1}. ${chalk.bold(server.name)}`));
|
|
92
|
+
console.log(chalk.gray(` ${server.description}`));
|
|
93
|
+
console.log(chalk.gray(` Category: ${server.category} | Author: ${server.author}`));
|
|
94
|
+
console.log(chalk.gray(` Downloads: ${server.downloads.toLocaleString()} | Rating: ${'⭐'.repeat(Math.floor(server.rating))}`));
|
|
95
|
+
console.log();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
console.log(chalk.blue('💡 Install a server with:'), chalk.cyan('mcpm install <server-name>'));
|
|
99
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import inquirer from 'inquirer';
|
|
3
|
+
import { installServer } from './install';
|
|
4
|
+
|
|
5
|
+
interface Template {
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
servers: string[];
|
|
9
|
+
category: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const TEMPLATES: Record<string, Template> = {
|
|
13
|
+
'ecommerce-analytics': {
|
|
14
|
+
name: 'ecommerce-analytics',
|
|
15
|
+
description: '电商数据分析场景 - 包含数据库、缓存、电商 API',
|
|
16
|
+
category: '电商',
|
|
17
|
+
servers: [
|
|
18
|
+
'@modelcontextprotocol/server-postgres',
|
|
19
|
+
'@modelcontextprotocol/server-redis',
|
|
20
|
+
'@custom/taobao-api',
|
|
21
|
+
'@custom/jingdong-api'
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
'content-creation': {
|
|
25
|
+
name: 'content-creation',
|
|
26
|
+
description: '内容创作场景 - 小红书、抖音内容创作助手',
|
|
27
|
+
category: '内容',
|
|
28
|
+
servers: [
|
|
29
|
+
'@modelcontextprotocol/server-filesystem',
|
|
30
|
+
'@custom/xiaohongshu-api',
|
|
31
|
+
'@custom/douyin-api'
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
'wechat-miniprogram': {
|
|
35
|
+
name: 'wechat-miniprogram',
|
|
36
|
+
description: '微信小程序开发场景',
|
|
37
|
+
category: '开发',
|
|
38
|
+
servers: [
|
|
39
|
+
'@modelcontextprotocol/server-filesystem',
|
|
40
|
+
'@custom/wechat-devtools',
|
|
41
|
+
'@modelcontextprotocol/server-git'
|
|
42
|
+
]
|
|
43
|
+
},
|
|
44
|
+
'alipay-miniprogram': {
|
|
45
|
+
name: 'alipay-miniprogram',
|
|
46
|
+
description: '支付宝小程序开发场景',
|
|
47
|
+
category: '开发',
|
|
48
|
+
servers: [
|
|
49
|
+
'@modelcontextprotocol/server-filesystem',
|
|
50
|
+
'@custom/alipay-devtools',
|
|
51
|
+
'@modelcontextprotocol/server-git'
|
|
52
|
+
]
|
|
53
|
+
},
|
|
54
|
+
'backend-api': {
|
|
55
|
+
name: 'backend-api',
|
|
56
|
+
description: '后端 API 开发场景 - 数据库、缓存、消息队列',
|
|
57
|
+
category: '开发',
|
|
58
|
+
servers: [
|
|
59
|
+
'@modelcontextprotocol/server-postgres',
|
|
60
|
+
'@modelcontextprotocol/server-redis',
|
|
61
|
+
'@modelcontextprotocol/server-sqlite'
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const templateCommand = {
|
|
67
|
+
async list(): Promise<void> {
|
|
68
|
+
console.log(chalk.blue('📋 Available Templates\n'));
|
|
69
|
+
|
|
70
|
+
const templates = Object.values(TEMPLATES);
|
|
71
|
+
|
|
72
|
+
templates.forEach((template, index) => {
|
|
73
|
+
console.log(chalk.white(`${index + 1}. ${chalk.bold(template.name)}`));
|
|
74
|
+
console.log(chalk.gray(` ${template.description}`));
|
|
75
|
+
console.log(chalk.gray(` Category: ${template.category}`));
|
|
76
|
+
console.log(chalk.gray(` Servers: ${template.servers.length}`));
|
|
77
|
+
console.log();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
console.log(chalk.blue('💡 Use a template:'), chalk.cyan('mcpmate template use <template-name>'));
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
async use(templateName: string): Promise<void> {
|
|
84
|
+
const template = TEMPLATES[templateName];
|
|
85
|
+
|
|
86
|
+
if (!template) {
|
|
87
|
+
console.log(chalk.yellow(`⚠️ Template "${templateName}" not found.`));
|
|
88
|
+
console.log(chalk.gray('Available templates:'));
|
|
89
|
+
Object.keys(TEMPLATES).forEach(name => {
|
|
90
|
+
console.log(chalk.gray(` - ${name}`));
|
|
91
|
+
});
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
console.log(chalk.blue('📦 Using template:'), chalk.bold(template.name));
|
|
96
|
+
console.log(chalk.gray(template.description));
|
|
97
|
+
console.log();
|
|
98
|
+
|
|
99
|
+
console.log(chalk.blue('This template includes:'));
|
|
100
|
+
template.servers.forEach(server => {
|
|
101
|
+
console.log(chalk.gray(` • ${server}`));
|
|
102
|
+
});
|
|
103
|
+
console.log();
|
|
104
|
+
|
|
105
|
+
const { confirm } = await inquirer.prompt([{
|
|
106
|
+
type: 'confirm',
|
|
107
|
+
name: 'confirm',
|
|
108
|
+
message: 'Install all servers in this template?',
|
|
109
|
+
default: true
|
|
110
|
+
}]);
|
|
111
|
+
|
|
112
|
+
if (!confirm) {
|
|
113
|
+
console.log(chalk.gray('Installation cancelled.'));
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
console.log();
|
|
118
|
+
console.log(chalk.blue('🚀 Installing servers...\n'));
|
|
119
|
+
|
|
120
|
+
for (const server of template.servers) {
|
|
121
|
+
try {
|
|
122
|
+
await installServer(server, {});
|
|
123
|
+
console.log();
|
|
124
|
+
} catch (error) {
|
|
125
|
+
console.log(chalk.yellow(`⚠️ Failed to install ${server}, continuing...`));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
console.log();
|
|
130
|
+
console.log(chalk.green('✅ Template installation completed!'));
|
|
131
|
+
console.log(chalk.blue('💡 Next steps:'));
|
|
132
|
+
console.log(chalk.gray(' - Enable servers:'), chalk.cyan('mcpmate enable <server>'));
|
|
133
|
+
console.log(chalk.gray(' - Sync to OpenClaw:'), chalk.cyan('mcpmate openclaw sync'));
|
|
134
|
+
}
|
|
135
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
|
|
6
|
+
const CONFIG_DIR = path.join(os.homedir(), '.mcpm');
|
|
7
|
+
const SERVERS_FILE = path.join(CONFIG_DIR, 'servers.json');
|
|
8
|
+
|
|
9
|
+
async function getInstalledServers(): Promise<Record<string, any>> {
|
|
10
|
+
if (await fs.pathExists(SERVERS_FILE)) {
|
|
11
|
+
return await fs.readJson(SERVERS_FILE);
|
|
12
|
+
}
|
|
13
|
+
return {};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async function saveInstalledServers(servers: Record<string, any>): Promise<void> {
|
|
17
|
+
await fs.ensureDir(CONFIG_DIR);
|
|
18
|
+
await fs.writeJson(SERVERS_FILE, servers, { spaces: 2 });
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function enableServer(serverName: string): Promise<void> {
|
|
22
|
+
const servers = await getInstalledServers();
|
|
23
|
+
|
|
24
|
+
if (!servers[serverName]) {
|
|
25
|
+
console.log(chalk.yellow(`⚠️ Server "${serverName}" is not installed.`));
|
|
26
|
+
console.log(chalk.gray('Install it first with:'), chalk.cyan(`mcpm install ${serverName}`));
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (servers[serverName].enabled) {
|
|
31
|
+
console.log(chalk.yellow(`⚠️ Server "${serverName}" is already enabled.`));
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
servers[serverName].enabled = true;
|
|
36
|
+
await saveInstalledServers(servers);
|
|
37
|
+
|
|
38
|
+
console.log(chalk.green(`✅ Server "${serverName}" enabled successfully!`));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export async function disableServer(serverName: string): Promise<void> {
|
|
42
|
+
const servers = await getInstalledServers();
|
|
43
|
+
|
|
44
|
+
if (!servers[serverName]) {
|
|
45
|
+
console.log(chalk.yellow(`⚠️ Server "${serverName}" is not installed.`));
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!servers[serverName].enabled) {
|
|
50
|
+
console.log(chalk.yellow(`⚠️ Server "${serverName}" is already disabled.`));
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
servers[serverName].enabled = false;
|
|
55
|
+
await saveInstalledServers(servers);
|
|
56
|
+
|
|
57
|
+
console.log(chalk.gray(`⏸️ Server "${serverName}" disabled.`));
|
|
58
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
import inquirer from 'inquirer';
|
|
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
|
+
async function saveInstalledServers(servers: Record<string, any>): Promise<void> {
|
|
18
|
+
await fs.ensureDir(CONFIG_DIR);
|
|
19
|
+
await fs.writeJson(SERVERS_FILE, servers, { spaces: 2 });
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function uninstallServer(serverName: string): Promise<void> {
|
|
23
|
+
console.log(chalk.blue('🗑️ Uninstalling MCP server...'));
|
|
24
|
+
console.log(chalk.gray(`Server: ${serverName}`));
|
|
25
|
+
console.log();
|
|
26
|
+
|
|
27
|
+
const servers = await getInstalledServers();
|
|
28
|
+
|
|
29
|
+
if (!servers[serverName]) {
|
|
30
|
+
console.log(chalk.yellow(`⚠️ Server "${serverName}" is not installed.`));
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const { confirm } = await inquirer.prompt([{
|
|
35
|
+
type: 'confirm',
|
|
36
|
+
name: 'confirm',
|
|
37
|
+
message: `Are you sure you want to uninstall "${serverName}"?`,
|
|
38
|
+
default: false
|
|
39
|
+
}]);
|
|
40
|
+
|
|
41
|
+
if (!confirm) {
|
|
42
|
+
console.log(chalk.gray('Uninstallation cancelled.'));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
delete servers[serverName];
|
|
47
|
+
await saveInstalledServers(servers);
|
|
48
|
+
|
|
49
|
+
console.log();
|
|
50
|
+
console.log(chalk.green('✅ Server uninstalled successfully!'));
|
|
51
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"lib": ["ES2020"],
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"rootDir": "./src",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"declaration": true,
|
|
14
|
+
"declarationMap": true,
|
|
15
|
+
"sourceMap": true
|
|
16
|
+
},
|
|
17
|
+
"include": ["src/**/*"],
|
|
18
|
+
"exclude": ["node_modules", "dist", "**/*.test.ts"]
|
|
19
|
+
}
|