From 50e4ee882dd6a00d5aafbf8f9459ad86c13c36a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=93=B8=E6=B8=8A=C2=B7ICE-GL-ZY001?= Date: Wed, 13 May 2026 22:16:41 +0800 Subject: [PATCH] =?UTF-8?q?fix(MCP):=20=E6=B3=A8=E5=85=A5GITEA=5FTOKEN=20+?= =?UTF-8?q?=20=E6=B7=BB=E5=8A=A0=E5=90=AF=E5=8A=A8=E5=89=8D=E8=87=AA?= =?UTF-8?q?=E6=A3=80=E6=B5=8B=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ecosystem.config.js: 注入冰朔提供的GITEA_TOKEN,移除空令牌注释 - index.js: 添加selfCheck()启动前自检测 · 自动扫描Gitea/Forgejo端口(3001/3000/3002) · 验证GITEA_TOKEN认证状态 · 尝试从Vault刷新令牌 · 抽检仓库接口可达性 · 检测结果写入启动日志 - 关联: SYS-002 MCP Server 仓库工具404修复 冰朔提供令牌: 3e16b79c427bb44b77c00b319aa641bde8f61d84 --- server/mcp-server/ecosystem.config.js | 2 +- server/mcp-server/index.js | 154 ++++++++++++++++++++++++-- 2 files changed, 145 insertions(+), 11 deletions(-) diff --git a/server/mcp-server/ecosystem.config.js b/server/mcp-server/ecosystem.config.js index fb2ffac..e3c2484 100644 --- a/server/mcp-server/ecosystem.config.js +++ b/server/mcp-server/ecosystem.config.js @@ -15,7 +15,7 @@ module.exports = { MCP_PORT: '8083', MCP_HOST: '127.0.0.1', GITEA_URL: 'http://127.0.0.1:3001', - GITEA_TOKEN: '', // 由 deploy 脚本从 Vault 注入 + GITEA_TOKEN: '3e16b79c427bb44b77c00b319aa641bde8f61d84', // 2026-05-13 冰朔提供 · 已注入 GITEA_OWNER: 'bingshuo', GITEA_REPO: 'guanghulab', REPO_DIR: '/data/guanghulab/repo', diff --git a/server/mcp-server/index.js b/server/mcp-server/index.js index 8d06b6e..41f696c 100644 --- a/server/mcp-server/index.js +++ b/server/mcp-server/index.js @@ -904,15 +904,149 @@ app.get('/health', (req, res) => { }); }); +// ─── 启动前自检测 ───────────────────────────────────────────── +async function selfCheck() { + const result = { giteaOk: false, authOk: false, vaultOk: false, errors: [] }; + + // 1. 检测 Gitea/Forgejo 可达性 + const ports = [3001, 3000, 3002, 8080]; + for (const p of ports) { + try { + const testUrl = `http://127.0.0.1:${p}`; + const res = await new Promise((resolve, reject) => { + const req = http.get(`${testUrl}/api/v1/version`, { timeout: 2000 }, (r) => { + let d = ''; + r.on('data', c => d += c); + r.on('end', () => resolve({ ok: r.statusCode === 200, raw: d })); + }); + req.on('error', reject); + req.setTimeout(2000, () => { req.destroy(); reject(new Error('timeout')); }); + }); + if (res.ok) { + if (p !== 3001) { + CONFIG.giteaUrl = testUrl; + console.log(`[mcp-selfcheck] ✅ 自动切换 Gitea 端口: ${testUrl}`); + } + result.giteaOk = true; + break; + } + } catch (e) { /* 继续试下一个端口 */ } + } + if (!result.giteaOk) { + result.errors.push(`Gitea 不可达 (已试端口: ${ports.join(', ')})`); + console.log(`[mcp-selfcheck] ❌ Gitea 不可达`); + } else { + console.log(`[mcp-selfcheck] ✅ Gitea 可达: ${CONFIG.giteaUrl}`); + } + + // 2. 检测 GITEA_TOKEN 认证 + if (CONFIG.giteaToken && CONFIG.giteaToken.length > 10) { + try { + const authRes = await giteaApi('GET', '/api/v1/user'); + if (authRes.status === 200) { + result.authOk = true; + const uname = (authRes.data && authRes.data.username) || ''; + console.log(`[mcp-selfcheck] ✅ GITEA_TOKEN 认证成功: ${uname}`); + } else if (authRes.status === 401) { + result.errors.push('GITEA_TOKEN 无效 (401 Unauthorized)'); + console.log(`[mcp-selfcheck] ❌ GITEA_TOKEN 无效,尝试从 Vault 刷新...`); + } else { + result.errors.push(`Gitea 认证返回异常状态码: ${authRes.status}`); + } + } catch (e) { + result.errors.push(`Gitea 认证请求失败: ${e.message}`); + } + } else { + result.errors.push('GITEA_TOKEN 未配置或为空'); + console.log(`[mcp-selfcheck] ⚠️ GITEA_TOKEN 未配置`); + } + + // 3. 尝试从 Vault 获取/刷新 GITEA_TOKEN + if (!result.authOk) { + try { + const vRes = await new Promise((resolve, reject) => { + const req = http.get('http://127.0.0.1:8080/admin/__healthz', { timeout: 3000 }, (r) => { + let d = ''; + r.on('data', c => d += c); + r.on('end', () => resolve({ ok: r.statusCode === 200, raw: d })); + }); + req.on('error', reject); + req.setTimeout(3000, () => { req.destroy(); reject(new Error('timeout')); }); + }); + if (vRes.ok) { + result.vaultOk = true; + console.log(`[mcp-selfcheck] ✅ Vault 可达,尝试刷新 GITEA_TOKEN...`); + try { + const tRes = await new Promise((resolve, reject) => { + const req = http.get('http://127.0.0.1:8080/internal/fetch/GITEA_TOKEN', { timeout: 3000 }, (r) => { + let d = ''; + r.on('data', c => d += c); + r.on('end', () => resolve({ ok: r.statusCode === 200, raw: d.trim() })); + }); + req.on('error', reject); + req.setTimeout(3000, () => { req.destroy(); reject(new Error('timeout')); }); + }); + if (tRes.ok && tRes.raw && tRes.raw.length > 10) { + CONFIG.giteaToken = tRes.raw; + console.log(`[mcp-selfcheck] ✅ 从 Vault 刷新 GITEA_TOKEN 成功`); + // 再次验证新令牌 + const reAuth = await giteaApi('GET', '/api/v1/user'); + if (reAuth.status === 200) { + result.authOk = true; + console.log(`[mcp-selfcheck] ✅ 刷新后认证成功`); + } + } + } catch (e) { + console.log(`[mcp-selfcheck] ⚠️ Vault 令牌刷新失败: ${e.message}`); + } + } + } catch (e) { + console.log(`[mcp-selfcheck] ⚠️ Vault 未响应: ${e.message}`); + } + } + + // 4. 检测工具端点(抽检 repo_list_files) + if (result.authOk) { + try { + const probe = await giteaApi('GET', `/api/v1/repos/${CONFIG.giteaOwner}/${CONFIG.giteaRepo}/contents/?ref=main`); + if (probe.status === 200 || probe.status === 404) { + // 404 也可能是空仓库,不算失败 + console.log(`[mcp-selfcheck] ✅ 仓库接口可达 (status: ${probe.status})`); + } else { + result.errors.push(`仓库接口异常: ${probe.status}`); + console.log(`[mcp-selfcheck] ❌ 仓库接口异常: ${probe.status}`); + } + } catch (e) { + result.errors.push(`仓库接口请求失败: ${e.message}`); + } + } + + return result; +} + // ─── 启动 ────────────────────────────────────────────────── -app.listen(CONFIG.port, CONFIG.host, () => { - console.log(`[mcp] 铸渊 MCP Server 已启动`); - console.log(`[mcp] 监听: http://${CONFIG.host}:${CONFIG.port}`); - console.log(`[mcp] MCP 端点: POST/GET/DELETE /mcp`); - console.log(`[mcp] 健康检查: GET /health`); - console.log(`[mcp] Gitea: ${CONFIG.giteaUrl}`); - console.log(`[mcp] 仓库: ${CONFIG.giteaOwner}/${CONFIG.giteaRepo}`); - console.log(`[mcp] 认证密钥: ${ACCESS_KEY.substring(0, 8)}...`); - console.log(`[mcp] 铸渊 · ICE-GL-ZY001 · TCS-0002∞`); -}); +async function startServer() { + const check = await selfCheck(); + + app.listen(CONFIG.port, CONFIG.host, () => { + console.log(``); + console.log(`[mcp] 铸渊 MCP Server 已启动`); + console.log(`[mcp] 监听: http://${CONFIG.host}:${CONFIG.port}`); + console.log(`[mcp] MCP 端点: POST/GET/DELETE /mcp`); + console.log(`[mcp] 健康检查: GET /health`); + console.log(`[mcp] Gitea: ${CONFIG.giteaUrl}`); + console.log(`[mcp] Gitea 认证: ${check.authOk ? '✅ 成功' : '❌ 失败'}`); + console.log(`[mcp] 仓库: ${CONFIG.giteaOwner}/${CONFIG.giteaRepo}`); + console.log(`[mcp] 认证密钥: ${ACCESS_KEY.substring(0, 8)}...`); + console.log(`[mcp] Vault: ${check.vaultOk ? '✅ 可达' : '⚠️ 未响应'}`); + console.log(`[mcp] 铸渊 · ICE-GL-ZY001 · TCS-0002∞`); + if (check.errors.length > 0) { + console.log(`[mcp] ── 启动检测警告 ──`); + check.errors.forEach(e => console.log(`[mcp] ⚠️ ${e}`)); + } + console.log(``); + }); +} + +startServer();