Skip to main content
Glama
yctimlin

Excalidraw MCP Server

by yctimlin

create_element

Generate and customize Excalidraw elements (shapes, text, lines) with precise positioning, dimensions, colors, and styles via a structured API for diagram creation and modification.

Instructions

Create a new Excalidraw element

Input Schema

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

Implementation Reference

  • Main handler for the 'create_element' MCP tool: parses input with ElementSchema, generates ID, converts text to label format, calls createElementOnCanvas to sync to the canvas server, and returns success response.
    case 'create_element': {
      const params = ElementSchema.parse(args);
      logger.info('Creating element via MCP', { type: params.type });
    
      const id = generateId();
      const element: ServerElement = {
        id,
        ...params,
        createdAt: new Date().toISOString(),
        updatedAt: new Date().toISOString(),
        version: 1
      };
    
      // Convert text to label format for Excalidraw
      const excalidrawElement = convertTextToLabel(element);
      
      // Create element directly on HTTP server (no local storage)
      const canvasElement = await createElementOnCanvas(excalidrawElement);
      
      if (!canvasElement) {
        throw new Error('Failed to create element: HTTP server unavailable');
      }
      
      logger.info('Element created via MCP and synced to canvas', { 
        id: excalidrawElement.id, 
        type: excalidrawElement.type,
        synced: !!canvasElement 
      });
      
      return {
        content: [{ 
          type: 'text', 
          text: `Element created successfully!\n\n${JSON.stringify(canvasElement, null, 2)}\n\nāœ… Synced to canvas` 
        }]
      };
    }
  • src/index.ts:233-258 (registration)
    Tool registration in the tools array: defines name 'create_element', description, and JSON inputSchema, used in server capabilities for MCP tool discovery.
    {
      name: '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']
      }
    },
  • Zod schema (ElementSchema) used to parse and validate input arguments in the create_element handler.
    const ElementSchema = z.object({
      type: z.enum(Object.values(EXCALIDRAW_ELEMENT_TYPES) as [ExcalidrawElementType, ...ExcalidrawElementType[]]),
      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.string().optional(),
      groupIds: z.array(z.string()).optional(),
      locked: z.boolean().optional()
    });
  • Helper function called by the handler to perform the actual canvas sync for element creation via POST to /api/elements.
    async function createElementOnCanvas(elementData: ServerElement): Promise<ServerElement | null> {
      const result = await syncToCanvas('create', elementData);
      return result?.element || elementData;
    }
  • Helper function used in handler to convert 'text' property to Excalidraw-compatible 'label' format for non-text elements.
    function convertTextToLabel(element: ServerElement): ServerElement {
      const { text, ...rest } = element;
      if (text) {
        // For standalone text elements, keep text as direct property
        if (element.type === 'text') {
          return element; // Keep text as direct property
        }
        // For other elements (rectangle, ellipse, diamond), convert to label format
        return {
          ...rest,
          label: { text }
        } as ServerElement;
      }
      return element;
    }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full burden for behavioral disclosure. 'Create' implies a write operation, but it doesn't specify permissions needed, whether the element is saved immediately, if there are rate limits, or what happens on failure. This is inadequate for a mutation tool with zero annotation coverage.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, efficient sentence that gets straight to the point without any wasted words. It's appropriately sized for the tool's basic purpose, though this conciseness comes at the cost of completeness.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a creation tool with 13 parameters, 0% schema coverage, no annotations, and no output schema, the description is severely inadequate. It doesn't explain what an 'Excalidraw element' is, how parameters interact, what values are returned, or error conditions.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters1/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description provides no information about any of the 13 parameters, despite 0% schema description coverage. Parameters like 'type' with an enum or 'roughness' are completely unexplained, leaving the agent to guess their meaning and usage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb ('Create') and resource ('a new Excalidraw element'), making the purpose immediately understandable. However, it doesn't distinguish this tool from its sibling 'update_element' which might also create elements through updates, leaving room for ambiguity.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives like 'update_element' or 'query_elements'. There's no mention of prerequisites, context, or exclusions, leaving the agent to infer usage from the tool name alone.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Related Tools

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

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