Skip to main content
Glama

MCP draw.io server

mcp-drawio-server is a local MCP server that turns a relational schema into an editable entity-relationship diagram in draw.io. It can reflect a live database, parse SQL DDL, read a YAML or JSON schema specification, or reopen an existing uncompressed .drawio file. It also exposes granular tools for changing tables, columns, relations, and layout before saving the diagram.

The schema model is the source of truth. Every save regenerates the complete mxGraph document instead of patching XML cells in place.

Relations use deterministic, obstacle-aware orthogonal routing. Each endpoint gets a private port, crowded hubs fan out into separate lanes, recursive relations loop outside their table, and persistent waypoints keep the route stable when the file is reopened. Adjacent hub ports keep a visible pitch, terminal stubs cannot backtrack over themselves, and arc jumps make the remaining crossings explicit. Crow's-foot markers include nullable-FK optionality (0..1, 0..N, 1, and N).

Requirements and installation

  • Python 3.14 or newer

  • uv

  • draw.io Desktop is optional for generation, but required for interactive viewing and the final compatibility check

Install the locked environment:

git clone https://github.com/marcelovillanuevam-code/MCP-Draw.IO.git
cd MCP-Draw.IO
uv sync --locked

Run the stdio server directly while developing:

uv run --locked --no-sync mcp-drawio-server

The server communicates over standard input and output, so it normally appears to wait silently when started by hand.

Related MCP server: drawio-mcp-server

Register with Claude Code

Register it as a user-scoped utility so it is available in every project. Use absolute paths because Claude starts the command directly rather than through an interactive shell.

claude mcp add --transport stdio --scope user drawio -- \
  /absolute/path/to/uv run \
  --project /absolute/path/to/MCP-Draw.IO \
  --locked --no-sync \
  mcp-drawio-server

uv run --project selects this project's environment without changing the server process's working directory. This matters because relative output paths normally resolve from the Claude project that launched the server. Do not replace it with uv --directory, which changes the working directory to this repository.

Confirm the registration, then start a new Claude Code session:

claude mcp get drawio
claude mcp list

Use --scope local instead if the server should be available only in the current Claude project.

Configuration and output paths

The only server setting is optional:

MCP_DRAWIO_OUTPUT_DIR=/absolute/path/to/diagrams

It is the base directory for relative .drawio save and open paths. If it is unset, the process working directory is used. Absolute paths always take precedence, and a missing .drawio extension is added automatically. The server creates missing parent directories when it saves.

The project does not load .env files itself; .env.example documents the variable for shells, process managers, or MCP client configuration. To pin a single output directory in Claude Code, add the environment setting when registering the server:

claude mcp add --transport stdio \
  -e MCP_DRAWIO_OUTPUT_DIR=/absolute/path/to/diagrams \
  --scope user drawio -- \
  /absolute/path/to/uv run \
  --project /absolute/path/to/MCP-Draw.IO \
  --locked --no-sync \
  mcp-drawio-server

Named diagrams live only in the server process. Save important work before the session ends, and use open_diagram to restore it in a later session.

Input formats

Live database

load_database_schema uses SQLAlchemy reflection. It supports a named schema and include/exclude table filters. SQLite works without an extra package; other engines require a DBAPI driver.

Database

Example URL

Driver command

SQLite

sqlite:////absolute/path/store.db

Built in

PostgreSQL

postgresql+psycopg://user:password@host/database

uv add "psycopg[binary]"

MySQL/MariaDB

mysql+pymysql://user:password@host/database

uv add pymysql

Other SQLAlchemy dialects may work after their driver is installed, but are not part of the base environment. Run driver installation commands from the project root so pyproject.toml and uv.lock stay in sync.

SQL DDL

load_ddl_schema accepts SQL text or a file path. Pass a sqlglot dialect such as postgres, mysql, sqlite, or tsql when the syntax is dialect-specific. Only CREATE TABLE statements contribute to the diagram; unrelated statements are skipped. Foreign keys to tables outside a partial DDL input are omitted. Constraints must appear inside CREATE TABLE; dump-style ALTER TABLE ... ADD CONSTRAINT statements and standalone CREATE UNIQUE INDEX statements are not currently imported by the DDL parser.

YAML or JSON specification

load_spec_schema accepts text or a file path. JSON is parsed as a subset of YAML. Both expanded objects and concise column/relation forms are supported:

name: shop
tables:
  customer:
    columns:
      - "customer_id: INTEGER pk"
      - "email: VARCHAR(255) not null unique"
  orders:
    columns:
      - "order_id: INTEGER pk"
      - "customer_id: INTEGER required"
relations:
  - orders.customer_id -> customer.customer_id

Column shorthand recognizes pk/primary key, unique/uq, not null/ not_null/notnull/required, and null/nullable. A <table>_id column may infer a relation to a matching table with a single-column primary key when no explicit relation exists.

Composite unique keys use the expanded table form and participate in cardinality inference:

tables:
  enrollment:
    columns:
      - "student_id: INTEGER"
      - "course_id: INTEGER"
    unique_keys:
      - [student_id, course_id]

draw.io XML

open_diagram reads uncompressed .drawio or .xml mxGraph documents. Generated files use draw.io's native table, table-row, and ERD edge shapes.

MCP tools

The server exposes 16 tools. A loader creates a named diagram or replaces the schema of an existing diagram with that name.

Tool

Purpose

load_database_schema(url, diagram, schema=None, include_tables=None, exclude_tables=None)

Reflect selected tables from a live database.

load_ddl_schema(diagram, ddl=None, path=None, dialect=None)

Load CREATE TABLE statements from inline DDL or one file.

load_spec_schema(diagram, spec=None, path=None)

Load an inline YAML/JSON specification or one file.

open_diagram(path, diagram=None)

Open an existing uncompressed draw.io document.

list_diagrams()

List the diagrams currently held in memory.

describe_diagram(diagram)

Summarize tables, primary keys, and relations.

add_table(diagram, table, columns)

Add a table; columns is a list of column shorthand strings.

remove_table(diagram, table)

Remove a table and relations that touch it.

add_column(diagram, table, column)

Add one column from shorthand.

remove_column(diagram, table, column)

Remove a column and invalidated relations.

add_relation(diagram, source, target, cardinality=None, name=None)

Add a relation between endpoints such as orders.customer_id and customer.customer_id.

remove_relation(diagram, source, target)

Remove the relation matching the two endpoints.

move_table(diagram, table, x, y)

Set a table's draw.io coordinates.

relayout_diagram(diagram)

Recompute the complete automatic layout.

save_diagram(diagram, path=None)

Regenerate and save .drawio XML; omit path after the first save.

export_spec(diagram, format="yaml")

Return the current schema as YAML or JSON.

Composite endpoints use parentheses, for example order_line.(order_id,line_no). Explicit cardinalities are one-to-one, one-to-many, and many-to-many; when omitted, the server infers cardinality from keys where possible.

The MCP server produces .drawio/.xml and YAML/JSON text. It does not export PNG, SVG, or PDF itself; use draw.io Desktop or its CLI for those formats.

Security

  • Treat a database URL as a secret. Do not commit it, paste it into issue reports, or store it in .env.example; MCP tool calls and client logs may retain arguments.

  • Percent-encode reserved characters in usernames and passwords, and quote a URL when passing it through a shell. Prefer short-lived credentials so an accidentally retained URL has limited value.

  • Use a dedicated, least-privilege, read-only database account and encrypted transport for remote databases. Reflection reads metadata, but the database still receives a real connection from this process.

  • Schema names, table names, column names, and comments returned by reflection become available to the MCP client and model. Do not introspect sensitive production metadata unless that disclosure is acceptable.

  • File tools can read or write any path permitted to the server process. There is no built-in path allowlist, so use a restricted OS account or container when processing untrusted requests.

  • DDL and YAML/JSON inputs are parsed locally and are not executed against a database.

Round-trip limitations

  • Compressed draw.io documents cannot be opened. In draw.io Desktop, use File > Properties, clear Compressed, and save again.

  • Multi-page files are rejected rather than silently dropping pages. Save the ERD page as a separate uncompressed file before calling open_diagram.

  • Generated files contain a hidden mcp-schema-metadata JSON cell. The server prefers its canonical schema on reopen, while current visible table geometry wins over stale coordinates in the hidden payload.

  • Manual edits to visible table shapes do not update the hidden metadata. Moves and resizes are recovered from visible geometry, but manually renamed columns, added rows, or new relations can be ignored the next time the MCP server opens the file. Make structural changes through the MCP tools.

  • Manually edited edge ports and waypoints are intentionally regenerated from the schema and current table positions on the next save. Table geometry is preserved; route geometry is deterministic rather than a round-trip input.

  • A foreign or metadata-free draw.io document is parsed from its visible native table shapes on a best-effort basis. Names, types, common key markers, and row-anchored relations can be recovered. A table-to-table edge without MCP endpoint attributes is skipped because its columns cannot be inferred safely. Comments, arbitrary styling, some constraint details, and complex edge semantics may be lost. The next save regenerates the document in the server's standard style.

  • The router separates shared lanes and avoids table interiors, but a dense ERD can still contain line crossings. Crossings use arc jumps, and relation labels have opaque backgrounds. Labels can be dragged in draw.io when final presentation polish matters.

Tests

Run the full suite from any directory:

uv run --project /absolute/path/to/MCP-Draw.IO \
  --locked --no-sync pytest

The suite should cover all input sources, composite-primary-key cardinality, granular tools, save/open behavior, and draw.io round-trips both with and without embedded metadata.

The real stdio subprocess test is opt-in because restricted sandboxes can block AnyIO worker threads used by the SDK transport:

MCP_STDIO_INTEGRATION=1 uv run --locked --no-sync \
  pytest tests/test_stdio.py

Desktop validation

XML parsing and server round-trip tests do not prove that draw.io Desktop lays out and edits every native shape correctly. Before a release, generate a representative ERD containing PK, FK, combined PF, unique, nullable, one-to-one, one-to-many, and composite-key cases.

First exercise the real Desktop renderer non-interactively:

drawio --export --format png --border 20 \
  --output validation.png validation.drawio

On Windows PowerShell, replace drawio with the full path to draw.io.exe. Then open validation.drawio in the desktop application and confirm:

  • table headers and rows render without clipping or overlap;

  • PK, FK, PF, and U markers are visible;

  • ERD endpoints and cardinality markers are correct;

  • single-column relations attach to their column rows;

  • every relationship can be traced independently from endpoint to endpoint;

  • parallel relationships use separate ports and lanes rather than sharing a segment;

  • recursive relationships loop outside the table;

  • crossings have visible arc jumps and no route crosses a table interior;

  • tables can be selected, moved, resized, collapsed, and expanded;

  • the hidden metadata cell is not visible; and

  • saving with compression disabled produces a file open_diagram can reopen.

Install Server
F
license - not found
A
quality
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • Create diagrams in chat, rendered as live interactive draw.io diagrams. 10,000+ searchable shapes.

  • Generate cloud architecture diagrams, flowcharts, and sequence diagrams.

  • Generate dynamic Mermaid diagrams and charts with AI assistance. Customize styles and export diagr…

View all MCP Connectors

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/marcelovillanuevam-code/MCP-Draw.IO'

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