Turn a description of a process into a BPMN 2.0 diagram that opens cleanly in Bizagi Modeler.
An MCP server that generates, reads, audits and previews BPMN 2.0 diagrams — and drives the Bizagi Modeler desktop app on Windows.
Generated from a 60-line JSON spec. Every coordinate above was computed, not placed by hand.
Bizagi Modeler has no scripting API. The one integration path it does support is the open BPMN 2.0 XML format, through its Export / Import tab.
But there is a catch that makes naive generation useless: Bizagi imports the coordinates written in the file verbatim. It does not lay out a diagram for you. Emit a structurally perfect BPMN file without geometry and it opens as a pile of boxes stacked on the origin.
So the hard part of this server is not the XML. It is the layout.
| Tool | What it does |
|---|---|
get_spec_reference |
The spec format: every node type, field and rule |
create_process |
Description → a .bpmn file ready to import, coordinates computed |
update_process |
Edit an existing .bpmn (add/change/remove nodes and flows), re-laid out |
read_process |
Parse a .bpmn → structured JSON, a readable walk-through, or an editable spec |
list_processes |
Scan a folder and summarise each BPMN file |
validate_process |
Audit against BPMN 2.0 rules and modelling conventions, with a fix for each finding |
render_preview |
Render to SVG — check the result without opening Bizagi |
export_documentation |
Process documentation as Markdown (outline + audit) |
bizagi_status |
Whether Bizagi Modeler can be driven from here |
bizagi_open |
Launch Bizagi Modeler, optionally with a file |
bizagi_import_bpmn |
Drive Export / Import ▸ BPMN, and verify that it landed |
bizagi_export_bpmn |
Drive Export ▸ BPMN for the open diagram |
The first eight are pure Python and run on any OS, with or without Bizagi installed.
Only the four bizagi_* tools need Windows.
A lane-aware layered layout, in the order it runs:
- Break cycles so the graph can be layered at all
- Longest-path layering → each node's horizontal column
- Barycenter ordering per (column, lane) → fewer crossing lines
- Adaptive lane heights, sized to the tallest cell each band holds
- Reserved strips — a bypass band along the top of any lane carrying a column-skipping branch, and a channel strip at the bottom for loop-backs
- Orthogonal routing that goes around obstacles rather than through them
- Label separation as a final pass
These are not aspirations. Each one is a test that fails when the rule is removed:
- No two shapes overlap
- No edge is drawn through a shape that is not its own endpoint
- Every element sits inside its pool
- Message flows run in the empty corridor between pools, never horizontally through one
- Each message flow gets its own line in that corridor, and the corridor is sized from how many flows cross it — so their labels do not stack
- Loop-backs each get their own channel in a strip reserved while lanes are sized
- A branch that skips columns detours inside its own lane, over the activities it skips
- A gateway's branches leave from visibly different points, so a two-way split does not read as a single arrow
- Boundary-event flows leave downwards, never back up through the host activity
- Annotations and data stores sit beside what they describe — or, when they have no association, inside the pool they declare rather than off the canvas
- No label is written over another label or over a shape
A few decisions that are easy to get wrong:
- A label is as wide as its text. Reserving a flat box for every label makes collisions between the long ones invisible to anything that measures the reserved box.
- Reserved space must be held out of centring. Grow a lane to make room for a channel and then centre the shapes in it, and half the new space is handed back as padding above — the channel ends up too thin to use.
- A detour belongs in the gaps between shapes, not around all of them. Routing over or under everything lands the line outside the pool, and the verticals that reach it then cross every lane on the way.
- A data store can be associated with many activities but sits beside one. Placing it once per association leaves holes in the lanes where the earlier placements were.
pip install -e .For the Windows desktop tools:
pip install -e ".[desktop]"Python ≥ 3.10.
claude_desktop_config.json (Windows: %APPDATA%\Claude\claude_desktop_config.json):
{
"mcpServers": {
"bizagi-modeler": {
"command": "bizagi-mcp",
"env": {
"BIZAGI_MCP_ROOT": "C:\\Users\\you\\Documents\\Bizagi"
}
}
}
}If bizagi-mcp is not on PATH:
{
"mcpServers": {
"bizagi-modeler": {
"command": "python",
"args": ["-m", "bizagi_mcp.server"],
"env": { "BIZAGI_MCP_ROOT": "C:\\Users\\you\\Documents\\Bizagi" }
}
}
}For Claude Code: claude mcp add bizagi-modeler -- bizagi-mcp
| Variable | What it does |
|---|---|
BIZAGI_MCP_ROOT |
Confine every file read and write to this folder. Strongly recommended. |
BIZAGI_MODELER_PATH |
Full path to BizagiModeler.exe or BizAgiMC.exe when it is not found automatically |
"Model a leave request: the employee submits it, the manager approves or rejects it, HR records the outcome. Save it to
D:\Processes\leave.bpmn."
Then in Bizagi Modeler: Export / Import ▸ Import ▸ BPMN.
Export from Bizagi first (Export / Import ▸ Export ▸ BPMN), then:
"Read
D:\Processes\purchasing.bpmn, walk me through it, and tell me what is wrong with it."
See examples/purchase_request.json (the spec), .bpmn (generated) and .svg (preview).
Structure (BPMN001–BPMN020, severity error / warning)
Missing start or end events · unreachable elements · dead ends · sequence flows crossing pools · message flows inside one pool · gateways branching without conditions · event-based gateway targets · implicit split and merge · boundary events on non-activities · duplicate ids · a default flow that also carries a condition · one-in-one-out gateways.
Conventions (BP001–BP017, severity warning / info)
Activity naming (verb + object) · gateways not phrased as questions · unlabelled branches · documentation coverage · pools without lanes · empty lanes · diagram size · duplicate names · pools that never exchange messages.
Every finding names the offending element and the concrete step to fix it.
bizagi_open is the dependable path: Modeler takes a file as a command line argument,
so no menu has to be driven.
bizagi_import_bpmn drives the ribbon, and is honest about it:
- It claims the foreground and verifies it got there. Windows refuses
SetForegroundWindowto a process that does not own the foreground, andset_focus()returns as if it worked — clicking on regardless sends a real mouse click into whatever the user is working in. - It counts diagram tabs before and after, and reports
imported: true/falsefrom that evidence rather than from hope. - Both counts are taken with the window raised, because a window that is behind can hand back an incomplete accessibility tree.
Import cannot run while the machine is used for something else. Three routes were tested against Modeler 4.3.0.008 and all three are closed:
| Route | Result |
|---|---|
UI Automation Invoke pattern |
Ribbon tabs expose no patterns at all |
PostMessage mouse messages |
Ignored, across every candidate window handle |
BizAgiMC.exe file.bpmn |
Exits 0 without importing anything |
The ribbon only responds to real mouse input on a focused window. For unattended runs, give Bizagi its own Windows session or VM. If you want that recorded so nobody retries it: this table is the record.
- Paths are fully resolved (
~,.., symlinks) before being checked, then confined toBIZAGI_MCP_ROOTwhen it is set - XML parsing goes through
defusedxmlwhen available (XXE, billion laughs) - Files are never overwritten without
overwrite=true - Bizagi is launched with an argument list and no shell, so a filename can never become a command
- Every error comes back as data (
{"ok": false, ...}), never a traceback
pip install -e ".[dev]"
pytest -q72 tests: spec normalisation, XSD element ordering, BPMNDI completeness, every layout guarantee listed above, label collisions, round-trips, each validation rule, path traversal, ribbon button selection, foreground verification, and the error contract of every tool.
.bpmis not read. It is Bizagi's proprietary format; export to BPMN first.list_processesstill lists.bpmfiles and flags them.- Desktop control is Windows-only and needs
pywinauto. - Diagrams are generated one level deep. A sub-process appears as a collapsed shape; its contents are not generated.
- Layout tidiness is guaranteed for the geometry written to the file. Bizagi places node names by its own rules, which the diagram interchange section does not control.
MIT — see LICENSE.
