Skip to main content
Glama
Abdullah007bajwa

Excalidraw MCP Server

create_element

Add shapes, text, arrows, or drawings to Excalidraw diagrams by specifying type, position, and styling properties.

Instructions

Create a new Excalidraw element

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
typeYes
xYes
yYes
widthNo
heightNo
backgroundColorNo
strokeColorNo
strokeWidthNo
roughnessNo
opacityNo
textNo
fontSizeNo
fontFamilyNo

Implementation Reference

  • Handler function for the 'create_element' tool. Validates input using ElementSchema, generates a unique ID, constructs a detailed Excalidraw element object with defaults and special handling for lines/arrows, stores it in the elements Map, and returns a confirmation message.
    case 'create_element': {
      if (args.fontFamily && typeof args.fontFamily === 'string') {
        const fontMap = { "virgil": 1, "helvetica": 2, "cascadia": 3 };
        args.fontFamily = fontMap[args.fontFamily.toLowerCase()] ?? 1;
      }
    
      const params = ElementSchema.passthrough().parse(args);
      const id = generateId();
      const now = Date.now();
      const seed = Math.floor(Math.random() * 2 ** 31);
      const versionNonce = Math.floor(Math.random() * 2 ** 31);
    
      const element = {
        id,
        type: params.type,
        x: params.x,
        y: params.y,
        width: params.width ?? 10,
        height: params.height ?? 10,
        seed,
        version: 1,
        versionNonce,
        isDeleted: false,
        locked: params.locked ?? false,
        angle: params.angle ?? 0,
        fillStyle: params.fillStyle ?? 'hachure',
        strokeWidth: params.strokeWidth ?? 1,
        strokeStyle: params.strokeStyle ?? 'solid',
        roughness: params.roughness ?? 1,
        opacity: params.opacity !== undefined ? Math.max(0, Math.min(100, params.opacity * 100)) : 100,
        groupIds: [],
        frameId: null,
        roundness: params.roundness ?? null,
        boundElements: null,
        link: null,
        updated: now,
        strokeColor: params.strokeColor ?? '#000000',
        backgroundColor: params.backgroundColor ?? 'transparent',
        text: params.text ?? '',
        fontSize: params.fontSize ?? 20,
        fontFamily: params.fontFamily ?? 1,
        textAlign: params.textAlign ?? 'center',
        verticalAlign: params.verticalAlign ?? 'middle',
        containerId: null,
        originalText: params.text ?? '',
        points: params.points,
        startBinding: null,
        endBinding: null,
        lastCommittedPoint: null,
        startArrowhead: null,
        endArrowhead: null,
        fileId: null,
        scale: [1, 1],
        status: 'saved',
      };
    
      if ((element.type === 'arrow' || element.type === 'line') && (!element.points || element.points.length < 2)) {
        element.points = [[0, 0], [element.width || 10, element.height || 0]];
        if (element.type === 'arrow') {
          element.startArrowhead = element.startArrowhead ?? null;
          element.endArrowhead = element.endArrowhead ?? 'arrow';
        }
      }
    
      Object.keys(element).forEach(key => {
        if (element[key] === undefined) delete element[key];
      });
    
      elements.set(id, element);
      return {
        content: [{ type: 'text', text: JSON.stringify({ id: element.id, type: element.type, created: true }, null, 2) }]
      };
    }
  • Zod schema (ElementSchema) used for input validation in the create_element handler.
    const ElementSchema = z.object({
      type: z.enum(Object.values(EXCALIDRAW_ELEMENT_TYPES)),
      x: z.number(),
      y: z.number(),
      width: z.number().optional(),
      height: z.number().optional(),
      points: z.array(z.object({ x: z.number(), y: z.number() })).optional(),
      backgroundColor: z.string().optional(),
      strokeColor: z.string().optional(),
      strokeWidth: z.number().optional(),
      roughness: z.number().optional(),
      opacity: z.number().optional(),
      text: z.string().optional(),
      fontSize: z.number().optional(),
      fontFamily: z.number().optional(),
      locked: z.boolean().optional() // ADDED: Make sure locked status is saved
    });
  • src/index.js:94-118 (registration)
    Tool registration in MCP server capabilities, including description and input schema definition.
    create_element: {
      description: 'Create a new Excalidraw element',
      inputSchema: {
        type: 'object',
        properties: {
          type: { 
            type: 'string', 
            enum: Object.values(EXCALIDRAW_ELEMENT_TYPES) 
          },
          x: { type: 'number' },
          y: { type: 'number' },
          width: { type: 'number' },
          height: { type: 'number' },
          backgroundColor: { type: 'string' },
          strokeColor: { type: 'string' },
          strokeWidth: { type: 'number' },
          roughness: { type: 'number' },
          opacity: { type: 'number' },
          text: { type: 'string' },
          fontSize: { type: 'number' },
          fontFamily: { type: 'string' }
        },
        required: ['type', 'x', 'y']
      }
    },
  • generateId function imported and used to create unique element IDs in the handler.
    export function generateId() {
      return Date.now().toString(36) + Math.random().toString(36).substr(2);
    } 

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/Abdullah007bajwa/mcp_excalidraw'

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