[cc-3-8-x-mcp] 重构: 改为 Gateway 私有 Editor Bridge

改了什么:移除项目级 MCP Server 与 universal-mcp-sdk,新增带随机 token 的本机 Editor Bridge、Gateway v2 注册和分级超时转发。

为什么:MCP 协议与多项目路由统一交给全局 Gateway,项目扩展只保留 Cocos Editor.Message 和离线 CLI 职责。

影响范围:扩展启动与面板、编辑器注册、router 转发、安全边界、使用文档及自动化测试。
This commit is contained in:
furao
2026-08-14 12:10:09 +08:00
parent a3b016ea8e
commit ea364d3470
16 changed files with 1167 additions and 314 deletions
+20 -20
View File
@@ -1,19 +1,19 @@
'use strict';
// Cocos MCP 功能面板
// MCP 状态 / 编辑器状态 / 快捷动作 / Debug 注入 / 命令日志 / 同机 worktree
// Editor Bridge 状态 / 编辑器状态 / 快捷动作 / 命令日志 / 同机 worktree
exports.template = /* html */ `
<div class="wrap">
<section class="mcp">
<header>MCP Server <span id="mcpDot" class="dot gray"></span></header>
<header>Editor Bridge <span id="mcpDot" class="dot gray"></span></header>
<div class="row"><label>状态</label><span id="mcpRunning">-</span></div>
<div class="row"><label>端点</label><span id="mcpUrl">-</span></div>
<div class="row"><label>Tools</label><span id="mcpTools">-</span></div>
<div class="row"><label>请求数</label><span id="mcpReqCount">0</span></div>
<div class="mcp-actions">
<ui-button id="btnCopyMcpUrl">复制端点</ui-button>
<ui-button id="btnCopyCli">复制 CLI 命令</ui-button>
<ui-button id="btnCopyMcpUrl">复制诊断信息</ui-button>
<ui-button id="btnCopyCli">复制客户端入口</ui-button>
<ui-button id="btnRestartMcp" class="secondary">重启</ui-button>
</div>
</section>
@@ -154,11 +154,11 @@ exports.methods = {
const w = s.watchers || {};
this.$.watchers.textContent =
(w.refresh ? '●refresh ' : '○refresh ') +
(w.infoInterval ? '●info' : '○info');
(w.registryHeartbeat ? '●registry' : '○registry');
this.$.updatedAt.textContent = s.updatedAt ? s.updatedAt.replace('T', ' ').replace(/\..+$/, '') : '-';
// MCP
const mcp = s.mcpServer || {};
// Editor Bridge
const mcp = s.editorBridge || {};
if (mcp.running) {
this.$.mcpDot.className = 'dot green';
this.$.mcpRunning.textContent = 'running';
@@ -210,9 +210,9 @@ exports.methods = {
}
this.$.worktreeList.innerHTML = list.map(w => {
const name = (w.projectName || w.projectPath || '').split('/').slice(-2).join('/');
const stale = w.staleSec > 90 ? `${w.staleSec}s` : '';
const offline = w.alive === false ? ' ⚠offline' : '';
const selfCls = w.self ? 'wt-row self' : 'wt-row';
return `<div class="${selfCls}"><span class="name">${escapeHtml(name)}${w.self ? ' (本)' : ''}</span><span class="port">:${w.previewPort || '?'} pid${w.editorPid}${stale}</span></div>`;
return `<div class="${selfCls}"><span class="name">${escapeHtml(name)}${w.self ? ' (本)' : ''}</span><span class="port">:${w.previewPort || '?'} pid${w.editorPid}${offline}</span></div>`;
}).join('');
} catch (e) { /* ignore */ }
},
@@ -256,25 +256,25 @@ exports.methods = {
},
async onCopyMcpUrl() {
try {
const cfg = await Editor.Message.request('cc-3-8-x-mcp', 'get-mcp-config');
if (!cfg || !cfg.url) { this.showToast('MCP 未运行'); return; }
await navigator.clipboard.writeText(cfg.url);
this.showToast('已复制: ' + cfg.url);
const cfg = await Editor.Message.request('cc-3-8-x-mcp', 'get-bridge-config');
if (!cfg || !cfg.running) { this.showToast('Editor Bridge 未运行'); return; }
await navigator.clipboard.writeText(JSON.stringify(cfg, null, 2));
this.showToast('已复制 Bridge 诊断信息(不含令牌)');
} catch (e) { this.showToast('失败: ' + (e.message || e)); }
},
async onCopyCli() {
try {
const cfg = await Editor.Message.request('cc-3-8-x-mcp', 'get-mcp-config');
if (!cfg || !cfg.cliAddCommand) { this.showToast('MCP 未运行'); return; }
await navigator.clipboard.writeText(cfg.cliAddCommand);
this.showToast('已复制 CLI 命令');
const cfg = await Editor.Message.request('cc-3-8-x-mcp', 'get-bridge-config');
if (!cfg || !cfg.clientEntry) { this.showToast('Editor Bridge 未运行'); return; }
await navigator.clipboard.writeText(cfg.clientEntry);
this.showToast('客户端只需连接 cocos-mcp-gateway');
} catch (e) { this.showToast('失败: ' + (e.message || e)); }
},
async onRestartMcp() {
this.showToast('重启 MCP…');
this.showToast('重启 Bridge…');
try {
await Editor.Message.request('cc-3-8-x-mcp', 'restart-server');
this.showToast('MCP 已重启');
await Editor.Message.request('cc-3-8-x-mcp', 'restart-bridge');
this.showToast('Editor Bridge 已重启');
this.refreshStatus();
} catch (e) { this.showToast('失败: ' + (e.message || e)); }
},