@vrs-soft/wecom-aibot-mcp 1.5.0 → 2.3.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 +50 -337
- package/dist/bin.js +172 -85
- package/dist/channel-server.d.ts +15 -0
- package/dist/channel-server.js +492 -0
- package/dist/channel-server.test.d.ts +5 -0
- package/dist/channel-server.test.js +324 -0
- package/dist/client-pool.js +4 -3
- package/dist/client.js +49 -49
- package/dist/config-wizard.d.ts +13 -3
- package/dist/config-wizard.js +424 -141
- package/dist/connection-log.js +7 -6
- package/dist/connection-manager.d.ts +0 -8
- package/dist/connection-manager.js +11 -23
- package/dist/daemon.js +7 -6
- package/dist/headless-state.d.ts +0 -12
- package/dist/headless-state.js +11 -35
- package/dist/http-server.d.ts +21 -2
- package/dist/http-server.js +421 -88
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/keepalive-monitor.js +5 -4
- package/dist/logger.d.ts +51 -0
- package/dist/logger.js +84 -0
- package/dist/message-bus.d.ts +13 -1
- package/dist/message-bus.js +56 -3
- package/dist/project-config.d.ts +16 -0
- package/dist/project-config.js +91 -12
- package/dist/tools/index.js +226 -57
- package/package.json +1 -1
- package/skills/headless-mode/SKILL.md +136 -181
package/dist/bin.js
CHANGED
|
@@ -13,7 +13,7 @@ import { spawn } from 'child_process';
|
|
|
13
13
|
import * as fs from 'fs';
|
|
14
14
|
import * as path from 'path';
|
|
15
15
|
import * as os from 'os';
|
|
16
|
-
import { runConfigWizard, loadConfig, saveConfig,
|
|
16
|
+
import { runConfigWizard, loadConfig, saveConfig, deleteRobotConfigInteractive, uninstall, addMcpConfig, detectUserIdFromMessage, ensureHookInstalled, listAllRobots, ensureGlobalConfigs, } from './config-wizard.js';
|
|
17
17
|
import { initClient } from './client.js';
|
|
18
18
|
import { registerTools } from './tools/index.js';
|
|
19
19
|
import { startHttpServer, stopHttpServer, HTTP_PORT } from './http-server.js';
|
|
@@ -21,7 +21,8 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
|
21
21
|
import { getAllConnectionStates } from './connection-manager.js';
|
|
22
22
|
import { loadStats, cleanupOldLogs } from './connection-log.js';
|
|
23
23
|
import { startKeepaliveMonitor, stopKeepaliveMonitor } from './keepalive-monitor.js';
|
|
24
|
-
|
|
24
|
+
import { logger } from './logger.js';
|
|
25
|
+
const VERSION = '2.0.0';
|
|
25
26
|
const PID_FILE = path.join(os.homedir(), '.wecom-aibot-mcp', 'server.pid');
|
|
26
27
|
function showHelp() {
|
|
27
28
|
console.log(`
|
|
@@ -41,12 +42,17 @@ function showHelp() {
|
|
|
41
42
|
--start 启动 MCP Server(后台服务模式)
|
|
42
43
|
--stop 停止 MCP Server
|
|
43
44
|
--debug 前台启动 MCP Server(日志直接输出到终端,用于调试)
|
|
45
|
+
--channel 启动 Channel MCP Proxy(stdio 代理 + SSE 唤醒)
|
|
46
|
+
--http-only 仅启动 HTTP Server(远程部署场景,不安装 Channel MCP 配置)
|
|
47
|
+
--channel-only 仅配置 Channel MCP(本地连接远程 HTTP Server)
|
|
44
48
|
--status 显示服务状态和机器人配置
|
|
45
49
|
--config 重新配置默认机器人(修改 Bot ID / Secret / 目标用户)
|
|
46
50
|
--add 添加新的机器人配置(多机器人场景)
|
|
51
|
+
--rename [名称] 重命名机器人(可选参数:旧名称,交互式输入新名称)
|
|
47
52
|
--list 列出所有已配置的机器人及其占用状态
|
|
48
|
-
--delete [名称]
|
|
53
|
+
--delete [名称] 删除指定的机器人配置(保留 MCP 配置)
|
|
49
54
|
--uninstall 卸载并删除所有配置(包括 MCP 配置、hook、skill)
|
|
55
|
+
--clean-cache 清空 CC 注册表缓存(清理异常断线残留的 ccId)
|
|
50
56
|
|
|
51
57
|
使用流程:
|
|
52
58
|
1. 首次安装: npx @vrs-soft/wecom-aibot-mcp
|
|
@@ -60,18 +66,34 @@ function showHelp() {
|
|
|
60
66
|
|
|
61
67
|
4. 停止服务: npx @vrs-soft/wecom-aibot-mcp --stop
|
|
62
68
|
|
|
63
|
-
|
|
69
|
+
拆分部署(远程 HTTP + 本地 Channel):
|
|
64
70
|
|
|
65
|
-
|
|
71
|
+
远程服务器:
|
|
72
|
+
npx @vrs-soft/wecom-aibot-mcp --http-only --start
|
|
73
|
+
# 只启动 HTTP Server,不写入本地 MCP 配置
|
|
66
74
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
+
本地机器:
|
|
76
|
+
MCP_URL=http://远程IP:18963 npx @vrs-soft/wecom-aibot-mcp --channel-only
|
|
77
|
+
# 必须通过 MCP_URL 指定远程 HTTP MCP 地址
|
|
78
|
+
# 只配置 Channel MCP,连接远程 HTTP Server
|
|
79
|
+
|
|
80
|
+
MCP 配置(默认安装同时配置两种模式):
|
|
81
|
+
|
|
82
|
+
HTTP Transport(轮询模式):
|
|
83
|
+
"wecom-aibot": {
|
|
84
|
+
"type": "http",
|
|
85
|
+
"url": "http://127.0.0.1:18963/mcp"
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
Channel Transport(SSE 推送模式):
|
|
89
|
+
"wecom-aibot-channel": {
|
|
90
|
+
"command": "npx",
|
|
91
|
+
"args": ["@vrs-soft/wecom-aibot-mcp", "--channel"]
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
Channel 模式优势:微信消息自动唤醒 agent,无需主动轮询
|
|
95
|
+
启动 Channel 模式(研究预览):
|
|
96
|
+
claude --dangerously-load-development-channels server:wecom-aibot-channel
|
|
75
97
|
|
|
76
98
|
更多信息: https://github.com/eric2877/wecom-aibot-mcp
|
|
77
99
|
`);
|
|
@@ -100,11 +122,11 @@ function showStatus() {
|
|
|
100
122
|
for (const robot of allRobots) {
|
|
101
123
|
const usage = robotUsage.get(robot.name);
|
|
102
124
|
const statusTag = usage ? ` [使用中]` : '';
|
|
103
|
-
console.log(` ${robot.name}${statusTag}`);
|
|
104
|
-
console.log(` Bot ID
|
|
105
|
-
console.log(`
|
|
125
|
+
console.log(` Bot名称: ${robot.name}${statusTag}`);
|
|
126
|
+
console.log(` Bot ID: ${robot.botId}`);
|
|
127
|
+
console.log(` 目标用户:${robot.targetUserId}`);
|
|
106
128
|
if (usage) {
|
|
107
|
-
console.log(`
|
|
129
|
+
console.log(` 使用者: ${usage.agentName}`);
|
|
108
130
|
}
|
|
109
131
|
console.log('');
|
|
110
132
|
}
|
|
@@ -159,7 +181,7 @@ function stopServer() {
|
|
|
159
181
|
return true;
|
|
160
182
|
}
|
|
161
183
|
catch (err) {
|
|
162
|
-
|
|
184
|
+
logger.error('[mcp] 停止服务失败:', err);
|
|
163
185
|
if (fs.existsSync(PID_FILE)) {
|
|
164
186
|
fs.unlinkSync(PID_FILE);
|
|
165
187
|
}
|
|
@@ -183,14 +205,20 @@ async function waitForConnection(client, timeoutMs = 10000) {
|
|
|
183
205
|
});
|
|
184
206
|
}
|
|
185
207
|
// 启动 MCP Server(前台运行,供 --start 使用)
|
|
186
|
-
async function startMcpServerForeground() {
|
|
208
|
+
async function startMcpServerForeground(isDebug = false) {
|
|
187
209
|
const savedConfig = loadConfig();
|
|
188
210
|
if (!savedConfig || !savedConfig.botId || !savedConfig.secret || !savedConfig.targetUserId) {
|
|
189
|
-
|
|
211
|
+
logger.error('[mcp] 未找到配置,请先运行: npx @vrs-soft/wecom-aibot-mcp');
|
|
190
212
|
process.exit(1);
|
|
191
213
|
}
|
|
192
214
|
// 写入 PID 文件
|
|
193
215
|
fs.writeFileSync(PID_FILE, String(process.pid));
|
|
216
|
+
// Debug 模式:创建 debug 标记文件
|
|
217
|
+
if (isDebug) {
|
|
218
|
+
const debugFile = path.join(os.homedir(), '.wecom-aibot-mcp', 'debug');
|
|
219
|
+
fs.writeFileSync(debugFile, 'true');
|
|
220
|
+
console.log('[mcp] Debug 标记文件已创建');
|
|
221
|
+
}
|
|
194
222
|
// 确保 hook 已安装
|
|
195
223
|
ensureHookInstalled();
|
|
196
224
|
// 加载统计并清理旧日志
|
|
@@ -203,20 +231,20 @@ async function startMcpServerForeground() {
|
|
|
203
231
|
});
|
|
204
232
|
registerTools(server);
|
|
205
233
|
// 启动 HTTP 服务
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
234
|
+
logger.log('');
|
|
235
|
+
logger.log(' ╔════════════════════════════════════════════════════════╗');
|
|
236
|
+
logger.log(` ║ 企业微信智能机器人 MCP 服务 v${VERSION} ║`);
|
|
237
|
+
logger.log(' ║ Claude Code 审批通道 ║');
|
|
238
|
+
logger.log(' ╚════════════════════════════════════════════════════════╝');
|
|
239
|
+
logger.log('');
|
|
240
|
+
logger.log(`[mcp] 启动 MCP HTTP Server (端口: ${HTTP_PORT})...`);
|
|
213
241
|
await startHttpServer(server);
|
|
214
242
|
startKeepaliveMonitor();
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
243
|
+
logger.log(`[mcp] MCP Server 已就绪`);
|
|
244
|
+
logger.log(`[mcp] HTTP endpoint: http://127.0.0.1:${HTTP_PORT}/mcp`);
|
|
245
|
+
logger.log(`[mcp] 健康检查: http://127.0.0.1:${HTTP_PORT}/health`);
|
|
246
|
+
logger.log(`[mcp] 微信模式:enter_headless_mode 时建立连接`);
|
|
247
|
+
logger.log(`[mcp] PID: ${process.pid}`);
|
|
220
248
|
// 退出处理
|
|
221
249
|
const gracefulShutdown = () => {
|
|
222
250
|
console.log('[mcp] 正在关闭...');
|
|
@@ -225,6 +253,14 @@ async function startMcpServerForeground() {
|
|
|
225
253
|
if (fs.existsSync(PID_FILE)) {
|
|
226
254
|
fs.unlinkSync(PID_FILE);
|
|
227
255
|
}
|
|
256
|
+
// Debug 模式:删除 debug 标记文件
|
|
257
|
+
if (isDebug) {
|
|
258
|
+
const debugFile = path.join(os.homedir(), '.wecom-aibot-mcp', 'debug');
|
|
259
|
+
if (fs.existsSync(debugFile)) {
|
|
260
|
+
fs.unlinkSync(debugFile);
|
|
261
|
+
console.log('[mcp] Debug 标记文件已删除');
|
|
262
|
+
}
|
|
263
|
+
}
|
|
228
264
|
process.exit(0);
|
|
229
265
|
};
|
|
230
266
|
process.on('SIGINT', gracefulShutdown);
|
|
@@ -235,7 +271,7 @@ function startMcpServerBackground() {
|
|
|
235
271
|
// 检查配置是否存在
|
|
236
272
|
const savedConfig = loadConfig();
|
|
237
273
|
if (!savedConfig || !savedConfig.botId || !savedConfig.secret || !savedConfig.targetUserId) {
|
|
238
|
-
|
|
274
|
+
logger.error('[mcp] 未找到配置,请先运行: npx @vrs-soft/wecom-aibot-mcp');
|
|
239
275
|
process.exit(1);
|
|
240
276
|
}
|
|
241
277
|
// 检查是否已运行
|
|
@@ -251,17 +287,21 @@ function startMcpServerBackground() {
|
|
|
251
287
|
});
|
|
252
288
|
child.unref();
|
|
253
289
|
console.log('[mcp] MCP Server 已在后台启动');
|
|
254
|
-
|
|
290
|
+
logger.log(`[mcp] HTTP endpoint: http://127.0.0.1:18963/mcp`);
|
|
255
291
|
console.log('[mcp] 健康检查: curl http://127.0.0.1:18963/health');
|
|
256
292
|
console.log('[mcp] 停止服务: npx @vrs-soft/wecom-aibot-mcp --stop');
|
|
257
293
|
console.log('[mcp] 调试模式: npx @vrs-soft/wecom-aibot-mcp --debug');
|
|
258
294
|
}
|
|
259
295
|
async function main() {
|
|
260
296
|
const args = process.argv.slice(2);
|
|
297
|
+
// 确定安装模式
|
|
298
|
+
const installMode = args.includes('--http-only') ? 'http-only' :
|
|
299
|
+
args.includes('--channel-only') ? 'channel-only' : 'full';
|
|
261
300
|
// --reinstall 命令需要先删除再安装,跳过开头的 ensureGlobalConfigs
|
|
262
|
-
|
|
301
|
+
// --http-only 模式不需要写 MCP 配置
|
|
302
|
+
if (!args.includes('--reinstall') && !args.includes('--http-only')) {
|
|
263
303
|
// 强制覆盖所有全局配置(不依赖智能体)
|
|
264
|
-
ensureGlobalConfigs();
|
|
304
|
+
ensureGlobalConfigs(installMode);
|
|
265
305
|
}
|
|
266
306
|
// 解析命令行参数
|
|
267
307
|
if (args.includes('--help') || args.includes('-h')) {
|
|
@@ -278,18 +318,16 @@ async function main() {
|
|
|
278
318
|
console.log('[mcp] 配置位置:');
|
|
279
319
|
console.log(' - ~/.claude.json (MCP Server 配置)');
|
|
280
320
|
console.log(' - ~/.claude/settings.local.json (权限和 Hook)');
|
|
281
|
-
console.log(' - ~/.claude/skills/headless-mode/ (Skill)');
|
|
282
321
|
console.log(' - ~/.wecom-aibot-mcp/version.json (版本记录)');
|
|
283
322
|
console.log('\n[mcp] 请重启 Claude Code 以加载最新配置');
|
|
284
323
|
process.exit(0);
|
|
285
324
|
}
|
|
286
325
|
// --reinstall 命令:删除所有全局配置(保留机器人配置)后重新安装
|
|
287
326
|
if (args.includes('--reinstall')) {
|
|
288
|
-
|
|
327
|
+
logger.log('\n[mcp] 重新安装全局配置...');
|
|
289
328
|
console.log('[mcp] 保留所有机器人配置: ~/.wecom-aibot-mcp/config.json 和 robot-*.json');
|
|
290
329
|
const CLAUDE_CONFIG_FILE = path.join(os.homedir(), '.claude.json');
|
|
291
330
|
const CLAUDE_SETTINGS_FILE = path.join(os.homedir(), '.claude', 'settings.local.json');
|
|
292
|
-
const SKILL_DIR = path.join(os.homedir(), '.claude', 'skills', 'headless-mode');
|
|
293
331
|
const VERSION_FILE = path.join(os.homedir(), '.wecom-aibot-mcp', 'version.json');
|
|
294
332
|
const HOOK_SCRIPT = path.join(os.homedir(), '.wecom-aibot-mcp', 'permission-hook.sh');
|
|
295
333
|
// 1. 删除 ~/.claude.json 中的 wecom-aibot 配置
|
|
@@ -319,25 +357,20 @@ async function main() {
|
|
|
319
357
|
}
|
|
320
358
|
fs.writeFileSync(CLAUDE_SETTINGS_FILE, JSON.stringify(config, null, 2));
|
|
321
359
|
}
|
|
322
|
-
// 3.
|
|
323
|
-
if (fs.existsSync(SKILL_DIR)) {
|
|
324
|
-
fs.rmSync(SKILL_DIR, { recursive: true });
|
|
325
|
-
console.log('[mcp] 已删除 ~/.claude/skills/headless-mode/');
|
|
326
|
-
}
|
|
327
|
-
// 4. 删除版本文件
|
|
360
|
+
// 3. 删除版本文件
|
|
328
361
|
if (fs.existsSync(VERSION_FILE)) {
|
|
329
362
|
fs.unlinkSync(VERSION_FILE);
|
|
330
363
|
console.log('[mcp] 已删除 ~/.wecom-aibot-mcp/version.json');
|
|
331
364
|
}
|
|
332
|
-
//
|
|
365
|
+
// 4. 删除 hook 脚本
|
|
333
366
|
if (fs.existsSync(HOOK_SCRIPT)) {
|
|
334
367
|
fs.unlinkSync(HOOK_SCRIPT);
|
|
335
368
|
console.log('[mcp] 已删除 ~/.wecom-aibot-mcp/permission-hook.sh');
|
|
336
369
|
}
|
|
337
|
-
//
|
|
338
|
-
|
|
370
|
+
// 5. 重新安装全局配置
|
|
371
|
+
logger.log('\n[mcp] 正在重新安装...');
|
|
339
372
|
ensureGlobalConfigs();
|
|
340
|
-
|
|
373
|
+
logger.log('\n[mcp] ✅ 重新安装完成!');
|
|
341
374
|
console.log('[mcp] 请重启 Claude Code 以加载最新配置');
|
|
342
375
|
process.exit(0);
|
|
343
376
|
}
|
|
@@ -350,6 +383,27 @@ async function main() {
|
|
|
350
383
|
stopServer();
|
|
351
384
|
process.exit(0);
|
|
352
385
|
}
|
|
386
|
+
// --clean-cache 命令:清空 CC 注册表缓存
|
|
387
|
+
if (args.includes('--clean-cache')) {
|
|
388
|
+
if (!isServerRunning()) {
|
|
389
|
+
console.log('[mcp] 服务未运行,无需清理缓存');
|
|
390
|
+
process.exit(0);
|
|
391
|
+
}
|
|
392
|
+
try {
|
|
393
|
+
const res = await fetch(`http://127.0.0.1:${HTTP_PORT}/admin/clean-cache`, { method: 'POST' });
|
|
394
|
+
const data = await res.json();
|
|
395
|
+
if (data.ok) {
|
|
396
|
+
console.log(`[mcp] 已清空 CC 注册表,共清理 ${data.cleared} 条`);
|
|
397
|
+
if (data.entries.length > 0) {
|
|
398
|
+
console.log(`[mcp] 已清理: ${data.entries.join(', ')}`);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
catch (err) {
|
|
403
|
+
console.error('[mcp] 清理失败:', err);
|
|
404
|
+
}
|
|
405
|
+
process.exit(0);
|
|
406
|
+
}
|
|
353
407
|
// --uninstall 命令:先停止服务再卸载
|
|
354
408
|
if (args.includes('--uninstall')) {
|
|
355
409
|
if (isServerRunning()) {
|
|
@@ -366,8 +420,8 @@ async function main() {
|
|
|
366
420
|
// --delete 命令:删除单个机器人配置
|
|
367
421
|
const deleteIndex = args.indexOf('--delete');
|
|
368
422
|
if (deleteIndex !== -1) {
|
|
369
|
-
const
|
|
370
|
-
await
|
|
423
|
+
const robotName = args[deleteIndex + 1]; // 可选参数:机器人名称
|
|
424
|
+
await deleteRobotConfigInteractive(robotName);
|
|
371
425
|
process.exit(0);
|
|
372
426
|
}
|
|
373
427
|
// --start --foreground:前台启动(内部调用,输出到日志文件)
|
|
@@ -375,17 +429,52 @@ async function main() {
|
|
|
375
429
|
await startMcpServerForeground();
|
|
376
430
|
return; // 保持运行,不 exit
|
|
377
431
|
}
|
|
432
|
+
// --channel:启动 Channel MCP 代理(stdio)
|
|
433
|
+
// 注意:必须在 --debug 之前检查,否则 --channel --debug 会先触发 HTTP Server
|
|
434
|
+
if (args.includes('--channel')) {
|
|
435
|
+
// 检查 HTTP MCP 的 debug 标记文件
|
|
436
|
+
const debugFile = path.join(os.homedir(), '.wecom-aibot-mcp', 'debug');
|
|
437
|
+
const isDebug = fs.existsSync(debugFile) || args.includes('--debug');
|
|
438
|
+
if (isDebug) {
|
|
439
|
+
console.log('[channel] Debug 模式:日志输出到 stderr(跟随 HTTP MCP debug)');
|
|
440
|
+
if (!fs.existsSync(debugFile)) {
|
|
441
|
+
fs.writeFileSync(debugFile, 'true');
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
console.log('[channel] Starting Channel MCP Proxy...');
|
|
445
|
+
const { startChannelServer } = await import('./channel-server.js');
|
|
446
|
+
await startChannelServer();
|
|
447
|
+
// Channel MCP 退出时不删除 debug 文件(由 HTTP MCP 管理)
|
|
448
|
+
return; // 保持运行,不 exit
|
|
449
|
+
}
|
|
378
450
|
// --debug:前台启动,日志直接输出到终端
|
|
379
451
|
if (args.includes('--debug')) {
|
|
380
452
|
console.log('[mcp] Debug 模式:前台运行,Ctrl+C 退出');
|
|
381
|
-
|
|
382
|
-
const debugFile = path.join(os.homedir(), '.wecom-aibot-mcp', 'debug');
|
|
383
|
-
fs.writeFileSync(debugFile, 'true');
|
|
384
|
-
await startMcpServerForeground();
|
|
385
|
-
// 退出时删除标记文件
|
|
386
|
-
fs.unlinkSync(debugFile);
|
|
453
|
+
await startMcpServerForeground(true);
|
|
387
454
|
return;
|
|
388
455
|
}
|
|
456
|
+
// --http-only:仅启动 HTTP Server(远程部署场景)
|
|
457
|
+
if (args.includes('--http-only') && !args.includes('--start')) {
|
|
458
|
+
console.log('[mcp] HTTP-only 模式:仅启动 HTTP Server');
|
|
459
|
+
console.log('[mcp] 不写入 MCP 配置(远程部署场景)');
|
|
460
|
+
console.log('[mcp] 使用 --http-only --start 启动服务');
|
|
461
|
+
process.exit(0);
|
|
462
|
+
}
|
|
463
|
+
// --channel-only:仅配置 Channel MCP(本地连接远程 HTTP Server)
|
|
464
|
+
if (args.includes('--channel-only')) {
|
|
465
|
+
const mcpUrl = process.env.MCP_URL;
|
|
466
|
+
if (!mcpUrl) {
|
|
467
|
+
console.log('[mcp] ❌ Channel-only 模式需要指定远程 HTTP MCP 地址');
|
|
468
|
+
console.log('[mcp] 请设置环境变量 MCP_URL:');
|
|
469
|
+
console.log('[mcp] MCP_URL=http://远程IP:18963 npx @vrs-soft/wecom-aibot-mcp --channel-only');
|
|
470
|
+
process.exit(1);
|
|
471
|
+
}
|
|
472
|
+
console.log(`[mcp] Channel-only 模式:Channel MCP 已配置`);
|
|
473
|
+
console.log(`[mcp] 连接地址: ${mcpUrl}`);
|
|
474
|
+
console.log('[mcp] 请确保远程 HTTP Server 已启动');
|
|
475
|
+
console.log('[mcp] 启动 Channel: npx @vrs-soft/wecom-aibot-mcp --channel');
|
|
476
|
+
process.exit(0);
|
|
477
|
+
}
|
|
389
478
|
// --start:后台启动
|
|
390
479
|
if (args.includes('--start')) {
|
|
391
480
|
startMcpServerBackground();
|
|
@@ -393,12 +482,12 @@ async function main() {
|
|
|
393
482
|
}
|
|
394
483
|
const reconfig = args.includes('--config');
|
|
395
484
|
const isInteractive = process.stdin.isTTY; // 是否为用户交互模式
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
485
|
+
logger.log('');
|
|
486
|
+
logger.log(' ╔════════════════════════════════════════════════════════╗');
|
|
487
|
+
logger.log(` ║ 企业微信智能机器人 MCP 服务 v${VERSION} ║`);
|
|
488
|
+
logger.log(' ║ Claude Code 审批通道 ║');
|
|
489
|
+
logger.log(' ╚════════════════════════════════════════════════════════╝');
|
|
490
|
+
logger.log('');
|
|
402
491
|
// 加载统计并清理旧日志(保留 1 小时)
|
|
403
492
|
loadStats();
|
|
404
493
|
cleanupOldLogs(1 / 24);
|
|
@@ -429,8 +518,8 @@ async function main() {
|
|
|
429
518
|
}
|
|
430
519
|
else {
|
|
431
520
|
// 非 TTY 模式(MCP HTTP),必须有配置
|
|
432
|
-
|
|
433
|
-
|
|
521
|
+
logger.error('[config] 未找到配置,且当前为非交互模式。');
|
|
522
|
+
logger.error('[config] 请在终端运行: npx @vrs-soft/wecom-aibot-mcp --config');
|
|
434
523
|
process.exit(1);
|
|
435
524
|
}
|
|
436
525
|
}
|
|
@@ -443,11 +532,7 @@ async function main() {
|
|
|
443
532
|
const tempClient = initClient(config.botId, config.secret, config.targetUserId || 'placeholder', 'temp-validation');
|
|
444
533
|
const connected = await waitForConnection(tempClient, 10000);
|
|
445
534
|
if (!connected) {
|
|
446
|
-
console.log('[mcp]
|
|
447
|
-
console.log('[mcp] 请检查上面的错误提示,修复后重新配置');
|
|
448
|
-
// 删除无效配置,让用户重新输入
|
|
449
|
-
deleteConfig();
|
|
450
|
-
console.log('\n请检查:');
|
|
535
|
+
console.log('[mcp] ❌ 连接失败,请检查:');
|
|
451
536
|
console.log(' 1. Bot ID 和 Secret 是否正确');
|
|
452
537
|
console.log(' 2. 新建机器人需等待约 2 分钟同步');
|
|
453
538
|
console.log(' 3. 是否已完成授权(机器人详情 → 可使用权限 → 授权)');
|
|
@@ -456,35 +541,37 @@ async function main() {
|
|
|
456
541
|
process.exit(1);
|
|
457
542
|
}
|
|
458
543
|
// 连接成功
|
|
459
|
-
|
|
460
|
-
//
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
544
|
+
logger.log('\n[mcp] ✅ 机器人凭证验证成功!');
|
|
545
|
+
// 保存配置(使用原用户 ID 或等待识别)
|
|
546
|
+
if (!config.targetUserId || config.targetUserId === 'placeholder' || config.targetUserId === '') {
|
|
547
|
+
// 新机器人,需要识别用户 ID
|
|
548
|
+
const userId = await detectUserIdFromMessage(tempClient, 180);
|
|
549
|
+
if (!userId) {
|
|
550
|
+
logger.log('\n[mcp] 未能在规定时间内识别用户 ID');
|
|
551
|
+
console.log('[mcp] 请重新运行配置:npx @vrs-soft/wecom-aibot-mcp --config');
|
|
552
|
+
tempClient.disconnect();
|
|
553
|
+
process.exit(1);
|
|
554
|
+
}
|
|
555
|
+
config.targetUserId = userId;
|
|
467
556
|
}
|
|
468
|
-
// 更新配置中的用户 ID
|
|
469
|
-
config.targetUserId = userId;
|
|
470
557
|
// 保存最终配置
|
|
471
558
|
saveConfig(config, instanceName);
|
|
472
|
-
|
|
473
|
-
|
|
559
|
+
logger.log('\n[mcp] ✅ 配置完成!');
|
|
560
|
+
logger.log(`[mcp] 用户 ID: ${config.targetUserId}`);
|
|
474
561
|
// 配置完成后断开连接
|
|
475
562
|
tempClient.disconnect();
|
|
476
563
|
// 首次安装后自动后台启动服务
|
|
477
|
-
|
|
564
|
+
logger.log('\n[mcp] 正在后台启动 MCP Server...');
|
|
478
565
|
startMcpServerBackground();
|
|
479
566
|
console.log('[mcp] 请重启 Claude Code 以加载 MCP 服务\n');
|
|
480
567
|
process.exit(0);
|
|
481
568
|
}
|
|
482
569
|
// 已有配置,显示状态并提示启动命令
|
|
483
570
|
showStatus();
|
|
484
|
-
|
|
571
|
+
logger.log('\n[mcp] 使用 --start 启动服务,--stop 停止服务');
|
|
485
572
|
console.log('[mcp] 命令: npx @vrs-soft/wecom-aibot-mcp --start\n');
|
|
486
573
|
}
|
|
487
574
|
main().catch((err) => {
|
|
488
|
-
|
|
575
|
+
logger.error('[mcp] 启动失败:', err);
|
|
489
576
|
process.exit(1);
|
|
490
577
|
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Channel MCP 透明代理服务器
|
|
3
|
+
*
|
|
4
|
+
* 作为 HTTP MCP 的透明代理 + SSE Channel 唤醒能力
|
|
5
|
+
*
|
|
6
|
+
* 核心职责:
|
|
7
|
+
* 1. 声明完整工具列表(和 HTTP MCP 完全一样)
|
|
8
|
+
* 2. 转发所有请求到 HTTP MCP(需要初始化 session)
|
|
9
|
+
* 3. enter_headless_mode 后建立 SSE 连接
|
|
10
|
+
* 4. SSE 消息 → notifications/claude/channel 唤醒 agent
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* 启动 Channel MCP Server
|
|
14
|
+
*/
|
|
15
|
+
export declare function startChannelServer(): Promise<void>;
|