Skip to main content
Glama
rest-api.ts10.2 kB
#!/usr/bin/env node /** * REST API Adapter for Mermaid MCP Connector * Exposes MCP functionality as REST endpoints for ChatGPT and web integrations */ import express, { Request, Response } from 'express'; import cors from 'cors'; import { MermaidMCPConnector } from './index.js'; const app = express(); const PORT = process.env.PORT || 3000; // Middleware app.use(cors()); app.use(express.json()); // Initialize MCP Connector const connector = new MermaidMCPConnector(); // Connect to MCP server lazily (only when first tool is called) let connecting: Promise<void> | null = null; async function ensureConnected() { if (!connecting) { connecting = connector.connect().catch((error) => { console.error('Failed to connect to MCP server:', error); connecting = null; throw error; }); } return connecting; } // Health check app.get('/health', (req: Request, res: Response) => { res.json({ status: 'ok', service: 'mermaid-mcp-connector' }); }); // Get available tools app.get('/api/tools', async (req: Request, res: Response) => { try { await ensureConnected(); const tools = await connector.listTools(); res.json({ success: true, tools }); } catch (error: any) { res.status(500).json({ success: false, error: error.message }); } }); // Generate diagram app.post('/api/diagram/generate', async (req: Request, res: Response) => { try { const { description, code, type, filename } = req.body; if (!description && !code) { return res.status(400).json({ success: false, error: 'Either description or code is required' }); } await ensureConnected(); const result = await connector.generateDiagram({ description, code, type, filename }); // Extract SVG and Mermaid code from MCP response let svg = ''; let mermaidCode = code || ''; let metadata: any = {}; // Parse MCP response content if (result.content && Array.isArray(result.content)) { for (const item of result.content) { if (item.type === 'text' && item.text) { // Extract SVG from markdown code block const svgMatch = item.text.match(/```svg\n([\s\S]*?)\n```/); if (svgMatch) { svg = svgMatch[1]; } // Extract Mermaid code from markdown code block const mermaidMatch = item.text.match(/```mermaid\n([\s\S]*?)\n```/); if (mermaidMatch) { mermaidCode = mermaidMatch[1]; } // Extract metadata (Type, Dimensions, etc.) const typeMatch = item.text.match(/\*\*Type:\*\*\s*(\w+)/); const dimensionsMatch = item.text.match(/\*\*Dimensions:\*\*\s*(\d+)x(\d+)px/); const renderTimeMatch = item.text.match(/\*\*Render Time:\*\*\s*(\d+)ms/); const nodesMatch = item.text.match(/\*\*Nodes:\*\*\s*(\d+)/); const edgesMatch = item.text.match(/\*\*Edges:\*\*\s*(\d+)/); const fileMatch = item.text.match(/\*\*File:\*\*\s*(.+)/); if (typeMatch || dimensionsMatch || renderTimeMatch) { metadata = { diagramType: typeMatch ? typeMatch[1] : 'unknown', width: dimensionsMatch ? parseInt(dimensionsMatch[1]) : 800, height: dimensionsMatch ? parseInt(dimensionsMatch[2]) : 600, renderTime: renderTimeMatch ? parseInt(renderTimeMatch[1]) : 0, nodeCount: nodesMatch ? parseInt(nodesMatch[1]) : 0, edgeCount: edgesMatch ? parseInt(edgesMatch[1]) : 0, filepath: fileMatch ? fileMatch[1].trim() : undefined, timestamp: new Date().toISOString() }; } } } } // Enhanced response format for frontend integration const enhancedResponse = { success: true, // Raw SVG markup for inline rendering (dangerouslySetInnerHTML) svg: svg, // Base64 Data URL for <img> tags svgDataUrl: svg ? `data:image/svg+xml;base64,${Buffer.from(svg).toString('base64')}` : '', // Mermaid code for editing/re-rendering mermaidCode: mermaidCode, // Metadata for display metadata: metadata, // Original MCP response (for debugging/advanced use) raw: result }; res.json(enhancedResponse); } catch (error: any) { res.status(500).json({ success: false, error: error.message }); } }); // Get diagram types app.get('/api/diagram/types', async (req: Request, res: Response) => { try { await ensureConnected(); const result = await connector.getDiagramTypes(); res.json({ success: true, result }); } catch (error: any) { res.status(500).json({ success: false, error: error.message }); } }); // Get templates app.get('/api/templates', async (req: Request, res: Response) => { try { const category = req.query.category as string | undefined; await ensureConnected(); const result = await connector.getTemplates(category); res.json({ success: true, result }); } catch (error: any) { res.status(500).json({ success: false, error: error.message }); } }); // Validate syntax app.post('/api/diagram/validate', async (req: Request, res: Response) => { try { const { code } = req.body; if (!code) { return res.status(400).json({ success: false, error: 'Code is required' }); } await ensureConnected(); const result = await connector.validateSyntax(code); res.json({ success: true, result }); } catch (error: any) { res.status(500).json({ success: false, error: error.message }); } }); // Export diagram app.post('/api/diagram/export', async (req: Request, res: Response) => { try { const { code, format, filename } = req.body; if (!code || !format) { return res.status(400).json({ success: false, error: 'Code and format are required' }); } if (!['svg', 'png', 'pdf'].includes(format)) { return res.status(400).json({ success: false, error: 'Format must be svg, png, or pdf' }); } await ensureConnected(); const result = await connector.exportDiagram({ code, format, filename }); res.json({ success: true, result }); } catch (error: any) { res.status(500).json({ success: false, error: error.message }); } }); // OpenAPI spec for ChatGPT plugin app.get('/openapi.json', (req: Request, res: Response) => { const spec = { openapi: '3.0.0', info: { title: 'Mermaid MCP Connector API', description: 'REST API for generating Mermaid diagrams via MCP', version: '1.0.0' }, servers: [ { url: `http://localhost:${PORT}` } ], paths: { '/api/diagram/generate': { post: { summary: 'Generate a Mermaid diagram', operationId: 'generateDiagram', requestBody: { required: true, content: { 'application/json': { schema: { type: 'object', properties: { description: { type: 'string', description: 'Natural language description of the diagram' }, code: { type: 'string', description: 'Mermaid code to render' }, type: { type: 'string', description: 'Type of diagram (flowchart, sequence, etc.)' }, filename: { type: 'string', description: 'Output filename' } } } } } }, responses: { '200': { description: 'Diagram generated successfully' } } } }, '/api/diagram/types': { get: { summary: 'Get available diagram types', operationId: 'getDiagramTypes', responses: { '200': { description: 'List of diagram types' } } } }, '/api/templates': { get: { summary: 'Get available templates', operationId: 'getTemplates', parameters: [ { name: 'category', in: 'query', schema: { type: 'string' }, description: 'Template category' } ], responses: { '200': { description: 'List of templates' } } } } } }; res.json(spec); }); // ChatGPT plugin manifest app.get('/.well-known/ai-plugin.json', (req: Request, res: Response) => { const manifest = { schema_version: 'v1', name_for_human: 'Mermaid Diagram Generator', name_for_model: 'mermaid_diagram', description_for_human: 'Generate professional Mermaid diagrams from natural language', description_for_model: 'Generate flowcharts, sequence diagrams, architecture diagrams, and more using Mermaid syntax. Supports 22+ diagram types and 50+ templates.', auth: { type: 'none' }, api: { type: 'openapi', url: `http://localhost:${PORT}/openapi.json` }, logo_url: 'https://mermaid.js.org/favicon.svg', contact_email: 'narasimha.ponnada@hotmail.com', legal_info_url: 'https://github.com/Narasimhaponnada/mermaid-mcp' }; res.json(manifest); }); // Graceful shutdown process.on('SIGINT', async () => { console.log('\nShutting down...'); await connector.disconnect(); process.exit(0); }); // Start server app.listen(PORT, () => { console.log(`🚀 Mermaid MCP Connector API running on http://localhost:${PORT}`); console.log(`📚 OpenAPI spec: http://localhost:${PORT}/openapi.json`); console.log(`🤖 ChatGPT manifest: http://localhost:${PORT}/.well-known/ai-plugin.json`); }); export default app;

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/Narasimhaponnada/mcp-mermiad'

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