JavaScript 65.5%
Python 17.8%
CSS 13%
HTML 3.7%
1// perm-mcp — serveur MCP stdio minimal exposant l'outil `approve` utilisé par2// `claude --permission-prompt-tool mcp__adminka__approve`. Chaque demande de3// permission est relayée au backend admin-ka (long-poll HTTP local) qui la4// transforme en carte Autoriser/Refuser dans le chat.5import readline from 'node:readline';6import dns from 'node:dns';78const PERM_URL = process.env.ADMIN_KA_PERM_URL || 'http://127.0.0.1:3300/internal/perm';9const PERM_TOKEN = process.env.ADMIN_KA_PERM_TOKEN || '';1011// fetch (undici) échoue sur les noms Bonjour .local qui résolvent en IPv612// link-local — on force la résolution IPv4 avant l'appel.13async function resolvedPermUrl() {14 const u = new URL(PERM_URL);15 if (/^\d+\.\d+\.\d+\.\d+$/.test(u.hostname) || u.hostname === 'localhost') return PERM_URL;16 const { address } = await dns.promises.lookup(u.hostname, { family: 4 });17 u.hostname = address;18 return u.toString();19}2021const rl = readline.createInterface({ input: process.stdin });2223function send(obj) {24 process.stdout.write(JSON.stringify(obj) + '\n');25}2627rl.on('line', async (line) => {28 line = line.trim();29 if (!line) return;30 let msg;31 try { msg = JSON.parse(line); } catch { return; }32 const { id, method, params } = msg;33 if (method === 'initialize') {34 send({35 jsonrpc: '2.0', id,36 result: {37 protocolVersion: (params && params.protocolVersion) || '2024-11-05',38 capabilities: { tools: {} },39 serverInfo: { name: 'adminka', version: '1.0.0' },40 },41 });42 return;43 }44 if (method === 'notifications/initialized') return;45 if (method === 'ping') { send({ jsonrpc: '2.0', id, result: {} }); return; }46 if (method === 'tools/list') {47 send({48 jsonrpc: '2.0', id,49 result: {50 tools: [{51 name: 'approve',52 description: 'Demande de permission relayée à administration-ka.com',53 inputSchema: {54 type: 'object',55 properties: {56 tool_name: { type: 'string' },57 input: { type: 'object' },58 tool_use_id: { type: 'string' },59 },60 required: ['tool_name', 'input'],61 },62 }],63 },64 });65 return;66 }67 if (method === 'tools/call' && params && params.name === 'approve') {68 const args = params.arguments || {};69 let decision;70 try {71 const url = await resolvedPermUrl();72 const resp = await fetch(url, {73 method: 'POST',74 headers: { 'Content-Type': 'application/json' },75 body: JSON.stringify({ token: PERM_TOKEN, tool_name: args.tool_name, input: args.input, tool_use_id: args.tool_use_id }),76 });77 decision = await resp.json();78 if (decision.error) decision = { behavior: 'deny', message: 'Erreur backend: ' + decision.error };79 } catch (e) {80 decision = { behavior: 'deny', message: 'Backend admin-ka injoignable: ' + e.message };81 }82 send({83 jsonrpc: '2.0', id,84 result: { content: [{ type: 'text', text: JSON.stringify(decision) }] },85 });86 return;87 }88 if (id !== undefined) {89 send({ jsonrpc: '2.0', id, error: { code: -32601, message: 'method not found: ' + method } });90 }91});92