feat: 实现 open_prefab 工具,优化预制体创建稳定性,并完成全量源码 (JS/TS)、文档与配置的汉化合规审计

This commit is contained in:
火焰库拉
2026-02-13 13:52:27 +08:00
parent 8df6f5a415
commit 24bc7b7b1f
11 changed files with 2024 additions and 1547 deletions

View File

@@ -1,101 +1,149 @@
const http = require('http');
const COCOS_PORT = 3456;
/**
* MCP 桥接代理脚本
* 负责在标准 MCP 客户端 (stdin/stdout) 与 Cocos Creator 插件 (HTTP) 之间转发请求。
*/
const http = require("http");
/**
* 当前 Cocos Creator 插件监听的端口
* @type {number}
*/
const COCOS_PORT = 3456;
/**
* 发送调试日志到标准的错误输出流水
* @param {string} msg 日志消息
*/
function debugLog(msg) {
process.stderr.write(`[Proxy Debug] ${msg}\n`);
process.stderr.write(`[代理调试] ${msg}\n`);
}
process.stdin.on('data', (data) => {
const lines = data.toString().split('\n');
lines.forEach(line => {
if (!line.trim()) return;
try {
const request = JSON.parse(line);
handleRequest(request);
} catch (e) {}
});
// 监听标准输入以获取 MCP 请求
process.stdin.on("data", (data) => {
const lines = data.toString().split("\n");
lines.forEach((line) => {
if (!line.trim()) return;
try {
const request = JSON.parse(line);
handleRequest(request);
} catch (e) {
// 忽略非 JSON 输入
}
});
});
/**
* 处理 JSON-RPC 请求
* @param {Object} req RPC 请求对象
*/
function handleRequest(req) {
const { method, id, params } = req;
const { method, id, params } = req;
if (method === 'initialize') {
sendToAI({
jsonrpc: "2.0", id: id,
result: {
protocolVersion: "2024-11-05",
capabilities: { tools: {} },
serverInfo: { name: "cocos-bridge", version: "1.0.0" }
}
});
return;
}
// 处理握手初始化
if (method === "initialize") {
sendToAI({
jsonrpc: "2.0",
id: id,
result: {
protocolVersion: "2024-11-05",
capabilities: { tools: {} },
serverInfo: { name: "cocos-bridge", version: "1.0.0" },
},
});
return;
}
if (method === 'tools/list') {
// 使用 GET 获取列表
forwardToCocos('/list-tools', null, id, 'GET');
return;
}
// 获取工具列表
if (method === "tools/list") {
forwardToCocos("/list-tools", null, id, "GET");
return;
}
if (method === 'tools/call') {
// 使用 POST 执行工具
forwardToCocos('/call-tool', {
name: params.name,
arguments: params.arguments
}, id, 'POST');
return;
}
// 执行具体工具
if (method === "tools/call") {
forwardToCocos(
"/call-tool",
{
name: params.name,
arguments: params.arguments,
},
id,
"POST",
);
return;
}
if (id !== undefined) sendToAI({ jsonrpc: "2.0", id: id, result: {} });
// 默认空响应
if (id !== undefined) sendToAI({ jsonrpc: "2.0", id: id, result: {} });
}
function forwardToCocos(path, payload, id, method = 'POST') {
const postData = payload ? JSON.stringify(payload) : '';
const options = {
hostname: '127.0.0.1',
port: COCOS_PORT,
path: path,
method: method,
headers: { 'Content-Type': 'application/json' }
};
/**
* 将请求通过 HTTP 转发给 Cocos Creator 插件
* @param {string} path API 路径
* @param {Object|null} payload 发送的数据体
* @param {string|number} id RPC 请求标识符
* @param {string} method HTTP 方法 (默认 POST)
*/
function forwardToCocos(path, payload, id, method = "POST") {
const postData = payload ? JSON.stringify(payload) : "";
if (postData) {
options.headers['Content-Length'] = Buffer.byteLength(postData);
}
const options = {
hostname: "127.0.0.1",
port: COCOS_PORT,
path: path,
method: method,
headers: { "Content-Type": "application/json" },
};
const request = http.request(options, (res) => {
let resData = '';
res.on('data', d => resData += d);
res.on('end', () => {
try {
const cocosRes = JSON.parse(resData);
// 检查关键字段
if (path === '/list-tools' && !cocosRes.tools) {
// 如果报错,把 Cocos 返回的所有内容打印到 Trae 的 stderr 日志里
debugLog(`CRITICAL: Cocos returned no tools. Received: ${resData}`);
sendError(id, -32603, "Invalid Cocos response: missing tools array");
} else {
sendToAI({ jsonrpc: "2.0", id: id, result: cocosRes });
}
} catch (e) {
debugLog(`JSON Parse Error. Cocos Sent: ${resData}`);
sendError(id, -32603, "Cocos returned non-JSON data");
}
});
});
if (postData) {
options.headers["Content-Length"] = Buffer.byteLength(postData);
}
request.on('error', (e) => {
debugLog(`Cocos is offline: ${e.message}`);
sendError(id, -32000, "Cocos Plugin Offline");
});
const request = http.request(options, (res) => {
let resData = "";
res.on("data", (d) => (resData += d));
res.on("end", () => {
try {
const cocosRes = JSON.parse(resData);
if (postData) request.write(postData);
request.end();
// 检查关键字段,确保 Cocos 插件返回了期望的数据格式
if (path === "/list-tools" && !cocosRes.tools) {
debugLog(`致命错误: Cocos 未返回工具列表。接收内容: ${resData}`);
sendError(id, -32603, "Cocos 响应无效:缺少 tools 数组");
} else {
sendToAI({ jsonrpc: "2.0", id: id, result: cocosRes });
}
} catch (e) {
debugLog(`JSON 解析错误。Cocos 发送内容: ${resData}`);
sendError(id, -32603, "Cocos 返回了非 JSON 数据");
}
});
});
request.on("error", (e) => {
debugLog(`Cocos 插件已离线: ${e.message}`);
sendError(id, -32000, "Cocos 插件离线");
});
if (postData) request.write(postData);
request.end();
}
function sendToAI(obj) { process.stdout.write(JSON.stringify(obj) + '\n'); }
/**
* 将结果发送给 AI (通过标准输出)
* @param {Object} obj 结果对象
*/
function sendToAI(obj) {
process.stdout.write(JSON.stringify(obj) + "\n");
}
/**
* 发送 RPC 错误响应
* @param {string|number} id RPC 请求标识符
* @param {number} code 错误码
* @param {string} message 错误消息
*/
function sendError(id, code, message) {
sendToAI({ jsonrpc: "2.0", id: id, error: { code, message } });
}
sendToAI({ jsonrpc: "2.0", id: id, error: { code, message } });
}