'use strict'; // Check the portable MCP contract without starting a server or printing credentials. const assert = require('node:assert/strict'); const fs = require('node:fs'); const path = require('node:path'); const ROOT = path.resolve(__dirname, '..'); function readJson(filePath) { return JSON.parse(fs.readFileSync(filePath, 'utf8').replace(/^\uFEFF/, '')); } function isAbsoluteLike(value) { const text = String(value || '').trim(); return path.isAbsolute(text) || /^[A-Za-z]:[\\/]/.test(text) || /^\\\\/.test(text); } function checkConfig(filePath, { packageConfig = false } = {}) { assert(fs.existsSync(filePath), `缺少 MCP 配置:${filePath}`); const raw = fs.readFileSync(filePath, 'utf8'); assert(!/(?:r:|sk-(?!ant-))[A-Za-z0-9._~+/=-]{6,}/i.test(raw), `MCP 配置疑似包含凭据:${filePath}`); const config = readJson(filePath); const entry = config?.mcpServers?.['qiwei-assistant']; assert(entry && typeof entry === 'object', `${filePath} 未注册 qiwei-assistant`); assert(Array.isArray(entry.args), `${filePath} args 必须是数组`); assert(typeof entry.command === 'string' && entry.command.trim(), `${filePath} 缺少 command`); assert(typeof entry.cwd === 'string' && entry.cwd.trim(), `${filePath} 缺少 cwd`); assert(!isAbsoluteLike(entry.cwd), `${filePath} cwd 不能依赖绝对路径`); for (const arg of entry.args) assert(!isAbsoluteLike(arg), `${filePath} args 不能依赖绝对路径`); for (const [key, value] of Object.entries(entry.env || {})) { assert(typeof value === 'string', `${filePath} env.${key} 必须是字符串`); assert(!isAbsoluteLike(value), `${filePath} env.${key} 不能依赖绝对路径`); } if (packageConfig) { assert(entry.args.includes('mcp'), `${filePath} 未配置 mcp 子命令`); assert(/^\.([\\/])qiwei-workbench(?:\.exe)?$/i.test(entry.command), `${filePath} 未指向包内工作台`); assert(entry.cwd === '.', `${filePath} 交付包 cwd 必须为 .`); assert(entry.env?.QIWEI_PACKAGE_ROOT === '.', `${filePath} 缺少包根环境标记`); } else { assert(entry.command === 'node', `${filePath} 开发配置应使用 PATH 中的 node`); assert(entry.args.includes('./mcp/src/server.js'), `${filePath} 开发配置未指向源码入口`); } return { status: 'ok', file: path.relative(ROOT, filePath).replace(/\\/g, '/'), server: 'qiwei-assistant', command: entry.command, portable: true, }; } function main() { const packageDir = process.argv[2] ? path.resolve(process.argv[2]) : ''; const results = [checkConfig(path.join(ROOT, '.mcp.json'))]; if (packageDir) results.push(checkConfig(path.join(packageDir, '.mcp.json'), { packageConfig: true })); process.stdout.write(`${JSON.stringify({ status: 'ok', configs: results }, null, 2)}\n`); } try { main(); } catch (error) { process.stderr.write(`${error.message}\n`); process.exit(1); }