# Directory Structure ``` ├── .gitignore ├── Dockerfile ├── docs │ └── mcp_demo.png ├── package.json ├── README.md ├── smithery.yaml ├── src │ └── index.ts ├── tsconfig.json └── yarn.lock ``` # Files -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- ``` node_modules dist ``` -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- ```markdown # Whimsical MCP Server [](https://smithery.ai/server/@BrockReece/whimsical-mcp-server) A Model Context Protocol (MCP) server that enables the creation of Whimsical diagrams programmatically. This server integrates with Whimsical's API to generate diagrams from Mermaid markup. ## Demo Here's an example of a complex system architecture diagram created using this MCP server and Claude - it shows the Model Context Protocol (MCP) architecture itself:  ## Features - Create Whimsical diagrams using Mermaid markup generated by the MCP Client (Claude, Windsurf, etc.) - Returns both the Whimsical diagram URL and a base64 encoded image to allow the Client to iterate on it's original markup ## Installation ### Installing via Smithery To install Whimsical MCP Server for Claude Desktop automatically via [Smithery](https://smithery.ai/server/BrockReece/whimsical-mcp-server): ```bash npx -y @smithery/cli install BrockReece/whimsical-mcp-server --client claude ``` ### Manual Installation ```bash # Clone the repository git clone https://github.com/BrockReece/whimsical-mcp-server.git # Install dependencies yarn install # Build the project yarn build ``` ### Integration with MCP Client Update the MCP Client's config to point to this repository's dist folder eg: ```json { "mcpServers": { "whimsical": { "command": "node", "args": [ "/path/to/this/repo/whimsical-mcp-server/dist/index.js" ] } } } ``` ## License This project is licensed under the MIT License. ``` -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- ```json { "compilerOptions": { "target": "es2022", "module": "es2022", "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "moduleResolution": "node" }, "include": ["src/**/*"], "exclude": ["node_modules"] } ``` -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- ```dockerfile # Generated by https://smithery.ai. See: https://smithery.ai/docs/config#dockerfile FROM node:lts-alpine WORKDIR /app # Install dependencies COPY package.json yarn.lock ./ RUN yarn install --frozen-lockfile --ignore-scripts # Copy all source files COPY . . # Build the project RUN yarn build # By default, run the server as specified by the smithery.yaml configuration CMD ["node", "dist/index.js"] ``` -------------------------------------------------------------------------------- /smithery.yaml: -------------------------------------------------------------------------------- ```yaml # Smithery configuration file: https://smithery.ai/docs/config#smitheryyaml startCommand: type: stdio configSchema: # JSON Schema defining the configuration options for the MCP. type: object required: [] properties: {} commandFunction: # A function that produces the CLI command to start the MCP on stdio. |- (config) => ({command:'node',args:['dist/index.js'],env:{}}) ``` -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- ```json { "name": "whimsical-mcp-server", "version": "1.0.0", "description": "MCP server for creating Whimsical diagrams", "main": "dist/index.js", "type": "module", "scripts": { "build": "tsc", "start": "node dist/index.js", "dev": "ts-node src/index.ts" }, "dependencies": { "@modelcontextprotocol/sdk": "^1.5.0", "@playwright/test": "^1.41.1", "@types/node": "^20.0.0", "node-fetch": "^3.3.2", "ts-node": "^10.9.1", "typescript": "^5.0.0" } } ``` -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- ```typescript import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; import fetch from "node-fetch"; interface WhimsicalResponse { fileURL: string; imageURL: string; } // Create an MCP server const server = new McpServer({ name: "Whimsical Diagram Generator", version: "1.0.0" }); /** * Get base64 encoded image * * @param imageUrl URL to the image we wish to convert to base64 * @returns Details of the image, including the base64 encoded image and the mime type */ export async function getBase64Image(imageUrl: string): Promise<{ data: string; mimeType: string }> { const response = await fetch(imageUrl); const buffer = await response.arrayBuffer(); const mimeType = response.headers.get('content-type') || 'image/png'; return { data: Buffer.from(buffer).toString('base64'), mimeType }; } /** * Creates a new Whimsical diagram * * @param mermaid_markup The mermaid markup for the diagram * @param title The title of the Whimsical diagram * * @returns [ * The url of the Whimsical diagram, * The base64 encoded image of the Whimsical diagram * ] */ server.tool("create_whimsical_diagram", { mermaid_markup: z.string().describe("The mermaid markup for the diagram"), title: z.string().describe("The title of the Whimsical diagram") }, async ({ mermaid_markup, title }) => { const response = await fetch("https://whimsical.com/api/ai.chatgpt.render-flowchart", { method: "POST", headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ mermaid: mermaid_markup, title }) }); const responseData = await response.json() as WhimsicalResponse; // Get base64 encoded image const { data, mimeType } = await getBase64Image(responseData.imageURL); return { content: [ { type: "text", text: responseData.fileURL }, { type: "image", data, mimeType }, { type: "resource", resource: { uri: responseData.fileURL, text: "Whimsical Link" } } ] }; }); // Start receiving messages on stdin and sending messages on stdout const transport = new StdioServerTransport(); await server.connect(transport); ```