Skip to main content
Glama
stdio.ts5.08 kB
import { t } from './i18n/index.js'; // __I18N_READY__ // src/stdio.ts import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { z, ZodTypeAny } from 'zod'; // ⬇️ IMPORTANT : garde bien les suffixes ".js" car le build ESM référencera build/*.js import { registerAuthTools } from './tools/auth.js'; import { registerSalesTools } from './tools/sales.js'; import { registerDataTools } from './tools/data.js'; import { setSessionAuth, getSessionAuth } from './context.js'; // ==== Session globale (STDIO: une seule connexion) ==== type AuthState = { ok: boolean; SHOPID?: string; APIKEY?: string; scopes?: string[] }; /** Vérifie qu'un objet est un ZodRawShape (Record<string, ZodTypeAny>) */ function isZodRawShape(x: unknown): x is Record<string, ZodTypeAny> { if (!x || typeof x !== 'object' || Array.isArray(x)) return false; for (const v of Object.values(x as Record<string, unknown>)) { if (!v || typeof v !== 'object' || !(v as any)._def) return false; } return true; } /** Normalise en ZodRawShape ; log si correction appliquée */ function ensureZodRawShape( maybeShape: unknown, kind: 'inputSchema' | 'outputSchema', toolName: string ): Record<string, ZodTypeAny> { if (isZodRawShape(maybeShape)) return maybeShape; process.stderr.write(`[caisse][patch] ${kind} absent/non-ZodRawShape → {} pour ${toolName}\n`); return {}; } async function main() { const envShop = process.env.SHOPID ?? process.env.MCP_SHOPID; const envKey = process.env.APIKEY ?? process.env.MCP_APIKEY; if (!getSessionAuth() && envShop && envKey) { setSessionAuth({ ok: true, SHOPID: envShop, APIKEY: envKey, scopes: ['*'] }); process.stderr.write('[caisse][auth] Session initialisée depuis variables d’environnement.\n'); } // --- Logs de contexte --- try { // @ts-ignore const __dir = typeof __dirname !== 'undefined' ? __dirname : '(no __dirname)'; process.stderr.write(`[caisse][path] __dirname=${__dir}\n`); process.stderr.write(`[caisse][env] API_BASE=${process.env.API_BASE ?? ''} \n`); } catch { } // --- Création du serveur MCP --- const server = new McpServer({ name: 'caisse-enregistreuse-api', version: '1.2.0', }); // --- Wrapper registerTool : forcera inputSchema/outputSchema en ZodRawShape --- const registeredToolNames: string[] = []; const _registerTool = (server as any).registerTool.bind(server); (server as any).registerTool = function ( name: string, meta: { title?: string; description?: string; inputSchema?: Record<string, ZodTypeAny>; outputSchema?: Record<string, ZodTypeAny>; annotations?: any; _meta?: Record<string, unknown>; } = {}, handler: any ) { meta.inputSchema = ensureZodRawShape(meta.inputSchema, 'inputSchema', name); // Si un outputSchema est fourni mais pas conforme, on le normalise. if (meta.outputSchema !== undefined) { meta.outputSchema = ensureZodRawShape(meta.outputSchema, 'outputSchema', name); } registeredToolNames.push(name); return _registerTool(name, meta, handler); }; // --- Enregistrement des outils métier --- try { //registerAuthTools(server); registerSalesTools(server); registerDataTools(server); process.stderr.write(`[caisse][info] Tools enregistrés (après registerX): ${JSON.stringify(registeredToolNames)}\n`); } catch (e: any) { process.stderr.write(`[caisse][error] Echec registerXTools: ${e?.stack || e}\n`); } // --- Tool "ping" minimal (inputSchema sous forme de shape, pas z.object) --- (server as any).registerTool( 'ping', { title: t('tools.ping.title'), description: t('tools.ping.description'), inputSchema: { msg: z.string().optional() }, // ✅ ZodRawShape }, async ({ msg }: { msg?: string }) => ({ content: [{ type: 'text', text: `pong${msg ? ': ' + msg : ''}` }], structuredContent: { ok: true, echo: msg ?? null }, }) ); process.stderr.write(`[caisse][info] Tools finaux: ${JSON.stringify(registeredToolNames)}\n`); // --- Démarrage en STDIO --- const transport = new StdioServerTransport(); await server.connect(transport); process.stderr.write(`[caisse][info] Server started and connected successfully (stdio)\n`); } // --- Garde-fous globaux --- process.on('unhandledRejection', (err: any) => { process.stderr.write(`[caisse][fatal] UnhandledRejection: ${err?.stack || err}\n`); }); process.on('uncaughtException', (err: any) => { process.stderr.write(`[caisse][fatal] UncaughtException: ${err?.stack || err}\n`); }); main().catch((e) => { process.stderr.write(`[caisse][fatal] main() failed: ${e?.stack || e}\n`); process.exit(1); });

Implementation Reference

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/paracetamol951/caisse-enregistreuse-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server