Blogger MCP Server

by niyonabil
Verified
/** * Mock du SDK MCP pour éviter les problèmes de dépendances * Cette implémentation simplifiée fournit les fonctionnalités essentielles * du SDK MCP sans dépendre de la version exacte du package */ import { z } from 'zod'; import * as http from 'http'; import { ServerMode } from './types'; // Interface pour les outils du serveur MCP export interface MCPTool<T extends z.ZodType> { name: string; description: string; parameters: T; handler: (params: z.infer<T>) => Promise<any>; } // Interface pour les options du serveur MCP export interface MCPServerOptions { name: string; version: string; mode: ServerMode; } // Interface pour le transport du serveur MCP export interface ServerTransport { start: () => Promise<void>; stop: () => Promise<void>; onRequest?: (handler: (request: any) => Promise<any>) => void; } // Classe principale du serveur MCP export class MCPServer { private options: MCPServerOptions; private tools: Map<string, MCPTool<any>> = new Map(); private transport: ServerTransport | null = null; constructor(options: MCPServerOptions) { this.options = options; } // Ajoute un outil au serveur addTool<T extends z.ZodType>(tool: MCPTool<T>): void { this.tools.set(tool.name, tool); } // Connecte le serveur à un transport async connect(transport: ServerTransport): Promise<void> { this.transport = transport; if (this.transport.onRequest) { this.transport.onRequest(async (request) => { try { const { tool, params } = request; if (!this.tools.has(tool)) { return { error: `Outil non trouvé: ${tool}` }; } const mcpTool = this.tools.get(tool)!; try { const validatedParams = mcpTool.parameters.parse(params); const result = await mcpTool.handler(validatedParams); return result; } catch (error) { if (error instanceof z.ZodError) { return { error: `Paramètres invalides: ${error.message}` }; } return { error: `Erreur lors de l'exécution de l'outil: ${error}` }; } } catch (error) { return { error: `Erreur interne du serveur: ${error}` }; } }); } } // Démarre le serveur async start(): Promise<void> { if (!this.transport) { throw new Error('Le serveur doit être connecté à un transport avant de démarrer'); } await this.transport.start(); } // Arrête le serveur async stop(): Promise<void> { if (this.transport) { await this.transport.stop(); } } } // Transport pour le mode stdio export class StdioServerTransport implements ServerTransport { private requestHandler: ((request: any) => Promise<any>) | null = null; async start(): Promise<void> { process.stdin.setEncoding('utf-8'); process.stdin.on('data', async (data) => { try { const request = JSON.parse(data.toString()); if (this.requestHandler) { const response = await this.requestHandler(request); process.stdout.write(JSON.stringify(response) + '\n'); } } catch (error) { process.stdout.write(JSON.stringify({ error: `Erreur de parsing: ${error}` }) + '\n'); } }); } async stop(): Promise<void> { // Rien à faire pour le mode stdio } onRequest(handler: (request: any) => Promise<any>): void { this.requestHandler = handler; } } // Transport pour le mode HTTP export class HttpServerTransport implements ServerTransport { private server: http.Server | null = null; private requestHandler: ((request: any) => Promise<any>) | null = null; private host: string; private port: number; constructor(options: { host: string, port: number }) { this.host = options.host; this.port = options.port; } async start(): Promise<void> { this.server = http.createServer(async (req, res) => { res.setHeader('Content-Type', 'application/json'); res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); if (req.method === 'OPTIONS') { res.statusCode = 200; res.end(); return; } if (req.method !== 'POST') { res.statusCode = 405; res.end(JSON.stringify({ error: 'Méthode non autorisée' })); return; } try { let body = ''; req.on('data', (chunk) => { body += chunk.toString(); }); req.on('end', async () => { try { const request = JSON.parse(body); if (this.requestHandler) { const response = await this.requestHandler(request); res.statusCode = 200; res.end(JSON.stringify(response)); } else { res.statusCode = 500; res.end(JSON.stringify({ error: 'Gestionnaire de requêtes non configuré' })); } } catch (error) { res.statusCode = 400; res.end(JSON.stringify({ error: `Erreur de parsing: ${error}` })); } }); } catch (error) { res.statusCode = 500; res.end(JSON.stringify({ error: `Erreur interne du serveur: ${error}` })); } }); return new Promise((resolve) => { if (this.server) { this.server.listen(this.port, this.host, () => { resolve(); }); } }); } async stop(): Promise<void> { return new Promise((resolve, reject) => { if (this.server) { this.server.close((err) => { if (err) { reject(err); } else { resolve(); } }); } else { resolve(); } }); } onRequest(handler: (request: any) => Promise<any>): void { this.requestHandler = handler; } } // Classe pour les templates de ressources export class ResourceTemplate<T> { constructor(private resource: T) {} get(): T { return this.resource; } }