diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index e1423bf..094d947 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -7,6 +7,7 @@ import { ExcalidrawElement } from '@excalidraw/excalidraw' import '@excalidraw/excalidraw/index.css' +import { convertMermaidToExcalidraw, DEFAULT_MERMAID_CONFIG } from './utils/mermaidConverter' // Type definitions interface ServerElement { @@ -399,6 +400,42 @@ function App(): JSX.Element { } } + const handleMermaidTest = async (): Promise => { + if (!excalidrawAPI) return + + const testMermaid = `graph TD + A[Start] --> B{Decision} + B -->|Yes| C[Do Something] + B -->|No| D[Do Something Else] + C --> E[End] + D --> E` + + try { + const result = await convertMermaidToExcalidraw(testMermaid, DEFAULT_MERMAID_CONFIG) + + if (result.error) { + console.error('Mermaid conversion error:', result.error) + return + } + + if (result.elements && result.elements.length > 0) { + const convertedElements = convertToExcalidrawElements(result.elements, { regenerateIds: false }) + excalidrawAPI.updateScene({ + elements: convertedElements, + captureUpdate: CaptureUpdateAction.IMMEDIATELY + }) + + if (result.files) { + excalidrawAPI.addFiles(Object.values(result.files)) + } + + console.log('Mermaid diagram converted successfully:', result.elements.length, 'elements') + } + } catch (error) { + console.error('Error converting Mermaid diagram:', error) + } + } + return (
{/* Header */} @@ -437,6 +474,7 @@ function App(): JSX.Element {
+ diff --git a/src/index.ts b/src/index.ts index 0c171f5..356ea80 100644 --- a/src/index.ts +++ b/src/index.ts @@ -414,6 +414,41 @@ const tools: Tool[] = [ required: ['elementIds'] } }, + { + name: 'create_from_mermaid', + description: 'Convert a Mermaid diagram to Excalidraw elements and render them on the canvas', + inputSchema: { + type: 'object', + properties: { + mermaidDiagram: { + type: 'string', + description: 'The Mermaid diagram definition (e.g., "graph TD; A-->B; B-->C;")' + }, + config: { + type: 'object', + description: 'Optional Mermaid configuration', + properties: { + startOnLoad: { type: 'boolean' }, + flowchart: { + type: 'object', + properties: { + curve: { type: 'string', enum: ['linear', 'basis'] } + } + }, + themeVariables: { + type: 'object', + properties: { + fontSize: { type: 'string' } + } + }, + maxEdges: { type: 'number' }, + maxTextSize: { type: 'number' } + } + } + }, + required: ['mermaidDiagram'] + } + }, { name: 'batch_create_elements', description: 'Create multiple Excalidraw elements at once - ideal for complex diagrams', @@ -822,6 +857,60 @@ server.setRequestHandler(CallToolRequestSchema, async (request: CallToolRequest) } } + case 'create_from_mermaid': { + const params = z.object({ + mermaidDiagram: z.string(), + config: z.object({ + startOnLoad: z.boolean().optional(), + flowchart: z.object({ + curve: z.enum(['linear', 'basis']).optional() + }).optional(), + themeVariables: z.object({ + fontSize: z.string().optional() + }).optional(), + maxEdges: z.number().optional(), + maxTextSize: z.number().optional() + }).optional() + }).parse(args); + + logger.info('Creating Excalidraw elements from Mermaid diagram via MCP', { + diagramLength: params.mermaidDiagram.length, + hasConfig: !!params.config + }); + + try { + // Send the Mermaid diagram to the frontend via the API + // The frontend will use mermaid-to-excalidraw to convert it + const response = await fetch(`${EXPRESS_SERVER_URL}/api/elements/from-mermaid`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + mermaidDiagram: params.mermaidDiagram, + config: params.config + }) + }); + + if (!response.ok) { + throw new Error(`HTTP server error: ${response.status} ${response.statusText}`); + } + + const result = await response.json() as ApiResponse; + + logger.info('Mermaid diagram sent to frontend for conversion', { + success: result.success + }); + + return { + content: [{ + type: 'text', + text: `Mermaid diagram sent for conversion!\n\n${JSON.stringify(result, null, 2)}\n\n⚠️ Note: The actual conversion happens in the frontend canvas with DOM access. Open the canvas at ${EXPRESS_SERVER_URL} to see the diagram rendered.` + }] + }; + } catch (error) { + throw new Error(`Failed to process Mermaid diagram: ${(error as Error).message}`); + } + } + case 'batch_create_elements': { const params = z.object({ elements: z.array(ElementSchema) }).parse(args); logger.info('Batch creating elements via MCP', { count: params.elements.length });