mcp-drawio-server
Turns relational schemas into editable entity-relationship diagrams in draw.io, supporting live databases, SQL DDL, YAML/JSON specs, and existing .drawio files, with tools for managing tables, columns, and relations.
README
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.
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-metadataJSON 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, andUmarkers 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_diagramcan reopen.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。