// TF-MCP 直连通用调用器(客户端会话失效时的应急通道) // 用法: // node mcp_call.js execute_sql_query "SELECT ..." // node mcp_call.js get_out_shafts "model_id=2012326636757958658" // node mcp_call.js get_max_resistance_path "model_id=2012326636757958658 node_id=3958" // key=value 参数:model_id/node_id 等保持字符串;tun_id/page_no/page_size/skip/include_diagonal 转数字 const BASE = 'http://39.97.59.228:8071/mcp'; const NUM_KEYS = new Set(['tun_id', 'page_no', 'page_size', 'skip', 'include_diagonal']); function buildArgs(tool, raw) { if (tool === 'execute_sql_query') return { sql_query: raw }; const args = {}; for (const kv of raw.split(/\s+/)) { const i = kv.indexOf('='); if (i < 0) continue; const k = kv.slice(0, i), v = kv.slice(i + 1); args[k] = NUM_KEYS.has(k) ? Number(v) : v; } return args; } async function rpc(sid, body) { const headers = { 'Content-Type': 'application/json', 'Accept': 'application/json, text/event-stream' }; if (sid) headers['Mcp-Session-Id'] = sid; const r = await fetch(BASE, { method: 'POST', headers, body: JSON.stringify(body) }); if (r.status === 202) return {}; if (!r.ok) throw new Error(`HTTP ${r.status}: ${(await r.text()).slice(0, 200)}`); const sid2 = r.headers.get('mcp-session-id'); const text = await r.text(); const data = text.split('\n').filter(l => l.startsWith('data:')).map(l => l.slice(5).trim()).join(''); return sid2 ? { sid: sid2, json: JSON.parse(data) } : { json: JSON.parse(data) }; } (async () => { const tool = process.argv[2]; const raw = process.argv[3] || ''; const init = await rpc(null, { jsonrpc: '2.0', id: 1, method: 'initialize', params: { protocolVersion: '2024-11-05', capabilities: {}, clientInfo: { name: 'zcode-recover', version: '0.1' } } }); const sid = init.sid; await rpc(sid, { jsonrpc: '2.0', method: 'notifications/initialized' }); const res = await rpc(sid, { jsonrpc: '2.0', id: 2, method: 'tools/call', params: { name: tool, arguments: buildArgs(tool, raw) } }); if (res.json.error) { console.error(JSON.stringify(res.json.error)); process.exit(1); } const txt = res.json.result.content.map(c => c.text).join(''); let payload; try { payload = JSON.parse(txt); } catch { console.log(txt); return; } if (payload.success === false) { console.log('TOOL_FAIL:', txt.slice(0, 500)); process.exit(1); } const r = payload.result; if (Array.isArray(r)) { if (r.length && typeof r[0] === 'object') { const keys = Object.keys(r[0]); console.log(keys.join('|')); for (const row of r) console.log(keys.map(k => row[k]).join('|')); } else console.log(r.join(',')); } else console.log(typeof r === 'string' ? r : JSON.stringify(r)); })().catch(e => { console.error('FAILED:', e.message); process.exit(1); });