@vrs-soft/wecom-aibot-mcp 2.4.2 → 2.4.3
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/dist/bin.js +37 -9
- package/dist/config-wizard.d.ts +5 -0
- package/dist/config-wizard.js +32 -0
- package/dist/http-server.d.ts +4 -1
- package/dist/http-server.js +19 -6
- package/package.json +1 -1
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, deleteRobotConfigInteractive, uninstall, addMcpConfig, detectUserIdFromMessage, ensureHookInstalled, listAllRobots, ensureGlobalConfigs, getAuthToken, setAuthToken, updateMcpAuthHeaders, runRemoteInstallWizard, VERSION, } from './config-wizard.js';
|
|
16
|
+
import { runConfigWizard, loadConfig, saveConfig, deleteRobotConfigInteractive, uninstall, addMcpConfig, detectUserIdFromMessage, ensureHookInstalled, listAllRobots, ensureGlobalConfigs, getAuthToken, setAuthToken, getHttpsConfig, setHttpsConfig, updateMcpAuthHeaders, runRemoteInstallWizard, VERSION, } 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';
|
|
@@ -251,8 +251,10 @@ async function startMcpServerForeground(isDebug = false) {
|
|
|
251
251
|
logger.log(' ║ Claude Code 审批通道 ║');
|
|
252
252
|
logger.log(' ╚════════════════════════════════════════════════════════╝');
|
|
253
253
|
logger.log('');
|
|
254
|
-
|
|
255
|
-
|
|
254
|
+
const httpsConfig = getHttpsConfig() ?? undefined;
|
|
255
|
+
const protocol = httpsConfig ? 'HTTPS' : 'HTTP';
|
|
256
|
+
logger.log(`[mcp] 启动 MCP ${protocol} Server (端口: ${HTTP_PORT})...`);
|
|
257
|
+
await startHttpServer(server, HTTP_PORT, httpsConfig);
|
|
256
258
|
startKeepaliveMonitor();
|
|
257
259
|
logger.log(`[mcp] MCP Server 已就绪`);
|
|
258
260
|
logger.log(`[mcp] HTTP endpoint: http://127.0.0.1:${HTTP_PORT}/mcp`);
|
|
@@ -504,18 +506,44 @@ async function main() {
|
|
|
504
506
|
console.log('[setup] 安装完成!请重启 Claude Code 以加载配置');
|
|
505
507
|
}
|
|
506
508
|
else if (wantServer) {
|
|
507
|
-
//
|
|
508
|
-
console.log('\n[setup] Server
|
|
509
|
-
|
|
510
|
-
if (!savedConfig?.botId)
|
|
511
|
-
await runConfigWizard();
|
|
509
|
+
// 服务器端:分两步——先完成 Server 安装,再配置机器人
|
|
510
|
+
console.log('\n[setup] ─── 步骤 1/2:Server 安装 ───\n');
|
|
511
|
+
console.log(' Server 负责运行 HTTP MCP 服务,Bot 配置在下一步单独完成\n');
|
|
512
512
|
const readline = await import('readline');
|
|
513
513
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
514
|
-
const token = await new Promise(resolve => rl.question('Auth Token(Client
|
|
514
|
+
const token = await new Promise(resolve => rl.question('Auth Token(Client 端连接时需填写相同 Token,留空跳过): ', a => { rl.close(); resolve(a.trim()); }));
|
|
515
515
|
if (token)
|
|
516
516
|
setAuthToken(token);
|
|
517
|
+
// HTTPS 证书配置
|
|
518
|
+
const defaultCertPath = path.join(os.homedir(), '.wecom-aibot-mcp', 'cert.pem');
|
|
519
|
+
const defaultKeyPath = path.join(os.homedir(), '.wecom-aibot-mcp', 'key.pem');
|
|
520
|
+
console.log('\n HTTPS 证书配置(留空跳过,保持 HTTP 模式)');
|
|
521
|
+
console.log(' 默认证书位置(将证书文件放到此路径即可):');
|
|
522
|
+
console.log(` 证书: ${defaultCertPath}`);
|
|
523
|
+
console.log(` 私钥: ${defaultKeyPath}`);
|
|
524
|
+
console.log(' 如使用 Let\'s Encrypt,路径通常为:');
|
|
525
|
+
console.log(' /etc/letsencrypt/live/<域名>/fullchain.pem');
|
|
526
|
+
console.log(' /etc/letsencrypt/live/<域名>/privkey.pem\n');
|
|
527
|
+
const rl2 = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
528
|
+
const certInput = await new Promise(resolve => rl2.question(`SSL 证书路径(直接回车使用默认): `, a => { rl2.close(); resolve(a.trim()); }));
|
|
529
|
+
const certPath = certInput || defaultCertPath;
|
|
530
|
+
if (fs.existsSync(certPath)) {
|
|
531
|
+
const rl3 = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
532
|
+
const keyInput = await new Promise(resolve => rl3.question(`SSL 私钥路径(直接回车使用默认): `, a => { rl3.close(); resolve(a.trim()); }));
|
|
533
|
+
const keyPath = keyInput || defaultKeyPath;
|
|
534
|
+
setHttpsConfig(certPath, keyPath);
|
|
535
|
+
console.log(`[setup] HTTPS 已配置: ${certPath}`);
|
|
536
|
+
}
|
|
537
|
+
else if (certInput) {
|
|
538
|
+
console.log(`[setup] ⚠️ 证书文件不存在: ${certPath},跳过 HTTPS 配置`);
|
|
539
|
+
}
|
|
540
|
+
else {
|
|
541
|
+
console.log(`[setup] 将证书放到默认位置后重新运行 --setup --server 即可启用 HTTPS`);
|
|
542
|
+
}
|
|
517
543
|
console.log('\n[setup] Server 配置完成!');
|
|
518
544
|
console.log(' 启动: npx @vrs-soft/wecom-aibot-mcp --http-only --start');
|
|
545
|
+
console.log('\n[setup] ─── 步骤 2/2:配置企业微信机器人 ───\n');
|
|
546
|
+
await addMcpConfig();
|
|
519
547
|
}
|
|
520
548
|
else if (wantChannel) {
|
|
521
549
|
// Channel 客户端
|
package/dist/config-wizard.d.ts
CHANGED
|
@@ -10,6 +10,11 @@ export declare const VERSION: string;
|
|
|
10
10
|
export declare function loadConfig(): WecomConfig | null;
|
|
11
11
|
export declare function getAuthToken(): string | undefined;
|
|
12
12
|
export declare function setAuthToken(token: string | undefined): boolean;
|
|
13
|
+
export declare function getHttpsConfig(): {
|
|
14
|
+
certPath: string;
|
|
15
|
+
keyPath: string;
|
|
16
|
+
} | null;
|
|
17
|
+
export declare function setHttpsConfig(certPath: string, keyPath: string): boolean;
|
|
13
18
|
export declare function updateMcpAuthHeaders(token?: string): void;
|
|
14
19
|
export declare function listAllMcpInstances(): Array<{
|
|
15
20
|
name: string;
|
package/dist/config-wizard.js
CHANGED
|
@@ -104,6 +104,38 @@ export function setAuthToken(token) {
|
|
|
104
104
|
fs.writeFileSync(SERVER_CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
105
105
|
return true;
|
|
106
106
|
}
|
|
107
|
+
// 获取 HTTPS 证书配置(从 server.json 读取)
|
|
108
|
+
export function getHttpsConfig() {
|
|
109
|
+
if (!fs.existsSync(SERVER_CONFIG_FILE))
|
|
110
|
+
return null;
|
|
111
|
+
try {
|
|
112
|
+
const config = JSON.parse(fs.readFileSync(SERVER_CONFIG_FILE, 'utf-8'));
|
|
113
|
+
if (config.certPath && config.keyPath) {
|
|
114
|
+
return { certPath: config.certPath, keyPath: config.keyPath };
|
|
115
|
+
}
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// 设置 HTTPS 证书配置(写入 server.json)
|
|
123
|
+
export function setHttpsConfig(certPath, keyPath) {
|
|
124
|
+
ensureConfigDir();
|
|
125
|
+
let config = {};
|
|
126
|
+
if (fs.existsSync(SERVER_CONFIG_FILE)) {
|
|
127
|
+
try {
|
|
128
|
+
config = JSON.parse(fs.readFileSync(SERVER_CONFIG_FILE, 'utf-8'));
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
// ignore
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
config.certPath = certPath;
|
|
135
|
+
config.keyPath = keyPath;
|
|
136
|
+
fs.writeFileSync(SERVER_CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
107
139
|
// 更新 ~/.claude.json 中 wecom-aibot MCP 配置的 auth headers
|
|
108
140
|
export function updateMcpAuthHeaders(token) {
|
|
109
141
|
if (!fs.existsSync(CLAUDE_CONFIG_FILE))
|
package/dist/http-server.d.ts
CHANGED
|
@@ -62,7 +62,10 @@ export declare function getCCRegistryEntry(ccId: string): CCRegistryEntry | null
|
|
|
62
62
|
export declare function getCCCount(): number;
|
|
63
63
|
export declare function getCCCountByRobot(robotName: string): number;
|
|
64
64
|
export declare function getOnlineCcIds(): string[];
|
|
65
|
-
export declare function startHttpServer(_server: McpServer, port?: number
|
|
65
|
+
export declare function startHttpServer(_server: McpServer, port?: number, httpsConfig?: {
|
|
66
|
+
certPath: string;
|
|
67
|
+
keyPath: string;
|
|
68
|
+
}): Promise<void>;
|
|
66
69
|
export declare function stopHttpServer(): void;
|
|
67
70
|
export declare function cleanupPortFile(): void;
|
|
68
71
|
export {};
|
package/dist/http-server.js
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* - Session → robotName → WebSocket Connection
|
|
14
14
|
*/
|
|
15
15
|
import * as http from 'http';
|
|
16
|
+
import * as https from 'https';
|
|
16
17
|
import * as path from 'path';
|
|
17
18
|
import * as os from 'os';
|
|
18
19
|
import * as fs from 'fs';
|
|
@@ -461,12 +462,12 @@ ${onlineList.map(id => `• 【${id}】`).join('\n')}
|
|
|
461
462
|
示例:引用【${onlineList[0]}】的消息后回复`;
|
|
462
463
|
await client.sendText(reply);
|
|
463
464
|
}
|
|
464
|
-
export async function startHttpServer(_server, port = HTTP_PORT) {
|
|
465
|
+
export async function startHttpServer(_server, port = HTTP_PORT, httpsConfig) {
|
|
465
466
|
startTime = Date.now();
|
|
466
467
|
// 初始化 MCP Server
|
|
467
468
|
initMcpServer();
|
|
468
469
|
return new Promise((resolve, reject) => {
|
|
469
|
-
|
|
470
|
+
const requestHandler = async (req, res) => {
|
|
470
471
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
471
472
|
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS');
|
|
472
473
|
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, Mcp-Session-Id');
|
|
@@ -758,7 +759,16 @@ export async function startHttpServer(_server, port = HTTP_PORT) {
|
|
|
758
759
|
}
|
|
759
760
|
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
760
761
|
res.end(JSON.stringify({ error: 'Not Found' }));
|
|
761
|
-
}
|
|
762
|
+
};
|
|
763
|
+
// 根据是否有 HTTPS 配置创建对应的 server
|
|
764
|
+
if (httpsConfig) {
|
|
765
|
+
const cert = fs.readFileSync(httpsConfig.certPath, 'utf-8');
|
|
766
|
+
const key = fs.readFileSync(httpsConfig.keyPath, 'utf-8');
|
|
767
|
+
httpServer = https.createServer({ cert, key }, requestHandler);
|
|
768
|
+
}
|
|
769
|
+
else {
|
|
770
|
+
httpServer = http.createServer(requestHandler);
|
|
771
|
+
}
|
|
762
772
|
httpServer.on('error', (err) => {
|
|
763
773
|
if (err.code === 'EADDRINUSE') {
|
|
764
774
|
reject(new Error(`端口 ${port} 已被占用`));
|
|
@@ -767,9 +777,12 @@ export async function startHttpServer(_server, port = HTTP_PORT) {
|
|
|
767
777
|
reject(err);
|
|
768
778
|
}
|
|
769
779
|
});
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
780
|
+
// HTTPS 模式绑定所有网卡(供远程客户端访问),HTTP 模式只绑本地
|
|
781
|
+
const host = httpsConfig ? '0.0.0.0' : '127.0.0.1';
|
|
782
|
+
const protocol = httpsConfig ? 'https' : 'http';
|
|
783
|
+
httpServer.listen(port, host, async () => {
|
|
784
|
+
logger.log(`[http] MCP Server 已启动: ${protocol}://${host}:${port}`);
|
|
785
|
+
logger.log(`[http] MCP endpoint: ${protocol}://${host}:${port}/mcp (stateless mode)`);
|
|
773
786
|
// 自动连接所有配置的机器人
|
|
774
787
|
await connectAllRobots();
|
|
775
788
|
resolve();
|