mcp_call.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. // TF-MCP 直连通用调用器(客户端会话失效时的应急通道)
  2. // 用法:
  3. // node mcp_call.js execute_sql_query "SELECT ..."
  4. // node mcp_call.js get_out_shafts "model_id=2012326636757958658"
  5. // node mcp_call.js get_max_resistance_path "model_id=2012326636757958658 node_id=3958"
  6. // key=value 参数:model_id/node_id 等保持字符串;tun_id/page_no/page_size/skip/include_diagonal 转数字
  7. const BASE = 'http://39.97.59.228:8071/mcp';
  8. const NUM_KEYS = new Set(['tun_id', 'page_no', 'page_size', 'skip', 'include_diagonal']);
  9. function buildArgs(tool, raw) {
  10. if (tool === 'execute_sql_query') return { sql_query: raw };
  11. const args = {};
  12. for (const kv of raw.split(/\s+/)) {
  13. const i = kv.indexOf('=');
  14. if (i < 0) continue;
  15. const k = kv.slice(0, i), v = kv.slice(i + 1);
  16. args[k] = NUM_KEYS.has(k) ? Number(v) : v;
  17. }
  18. return args;
  19. }
  20. async function rpc(sid, body) {
  21. const headers = { 'Content-Type': 'application/json', 'Accept': 'application/json, text/event-stream' };
  22. if (sid) headers['Mcp-Session-Id'] = sid;
  23. const r = await fetch(BASE, { method: 'POST', headers, body: JSON.stringify(body) });
  24. if (r.status === 202) return {};
  25. if (!r.ok) throw new Error(`HTTP ${r.status}: ${(await r.text()).slice(0, 200)}`);
  26. const sid2 = r.headers.get('mcp-session-id');
  27. const text = await r.text();
  28. const data = text.split('\n').filter(l => l.startsWith('data:')).map(l => l.slice(5).trim()).join('');
  29. return sid2 ? { sid: sid2, json: JSON.parse(data) } : { json: JSON.parse(data) };
  30. }
  31. (async () => {
  32. const tool = process.argv[2];
  33. const raw = process.argv[3] || '';
  34. 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' } } });
  35. const sid = init.sid;
  36. await rpc(sid, { jsonrpc: '2.0', method: 'notifications/initialized' });
  37. const res = await rpc(sid, { jsonrpc: '2.0', id: 2, method: 'tools/call', params: { name: tool, arguments: buildArgs(tool, raw) } });
  38. if (res.json.error) { console.error(JSON.stringify(res.json.error)); process.exit(1); }
  39. const txt = res.json.result.content.map(c => c.text).join('');
  40. let payload;
  41. try { payload = JSON.parse(txt); } catch { console.log(txt); return; }
  42. if (payload.success === false) { console.log('TOOL_FAIL:', txt.slice(0, 500)); process.exit(1); }
  43. const r = payload.result;
  44. if (Array.isArray(r)) {
  45. if (r.length && typeof r[0] === 'object') {
  46. const keys = Object.keys(r[0]);
  47. console.log(keys.join('|'));
  48. for (const row of r) console.log(keys.map(k => row[k]).join('|'));
  49. } else console.log(r.join(','));
  50. } else console.log(typeof r === 'string' ? r : JSON.stringify(r));
  51. })().catch(e => { console.error('FAILED:', e.message); process.exit(1); });