Table of contents
uml-mcp
uml-mcp is a Model Context Protocol server that lets an AI assistant draw diagrams. The assistant writes diagram source (PlantUML, Mermaid, D2, Graphviz, C4, BPMN …), calls one of the server’s tools, and gets back an image, a link to the rendered file and a link to an editable playground. In clients that support MCP Apps, the diagram opens in a viewer inside the chat. It is published on PyPI as uml-mcp (version 1.4.0 in pyproject.toml), runs as a hosted endpoint on Vercel, and can be self-hosted with Docker or Helm.
1. Demo
The recording comes from the repository (docs/assets/mcp-app-demo.mp4). One generate_uml_batch call returns four diagrams as tabs in the MCP App viewer; the user switches tabs, then re-renders one diagram in another format.
Clients without MCP Apps get the same result as an inline image plus links, which is what most chat clients show:

2. Use cases
MCP server that lets AI assistants turn diagram source or a description into a rendered diagram inside the chat.
- Render one diagram
- MCP client (AI chat)Kroki / PlantUML
generate_uml takes a diagram_type, the source code, a format and an optional theme, renders through Kroki (KROKI_SERVER, https://kroki.io by default) and returns the file, its URL and a playground link.
- Validate diagram source
- MCP client (AI chat)
validate_uml checks the type, format and basic structure locally without rendering, so the assistant can fix the source before calling a renderer.
- Render a batch of diagrams
- MCP client (AI chat)Kroki / PlantUML
generate_uml_batch renders several items with bounded concurrency and stable ordering, up to the batch_max_items setting.
- Edit in the chat viewer
- DeveloperMCP client (AI chat)
In clients that support MCP Apps, results open in ui://uml-mcp/diagram-viewer, where the user can zoom, edit the source, change theme or format and export SVG, PNG, HTML or PDF.
- Self-host the server
- DeveloperKroki / PlantUML
uv tool install uml-mcp && uml-mcp setup installs it locally; docker-compose.yml starts the server on port 8000 with Kroki containers and an opt-in PlantUML fallback profile, and deploy/helm/uml-mcp targets Kubernetes.
2.1. Scenario: Draw a login sequence from Cursor
- Add the hosted endpoint https://uml-mcp.vercel.app/mcp to the MCP config, as in .cursor/mcp.json.
- Ask the assistant: "Draw a sequence diagram of a user logging in through an API gateway."
- The assistant calls list_diagram_types, writes Mermaid or PlantUML source and checks it with validate_uml.
- It calls generate_uml_image; the server renders through Kroki and returns an inline PNG with render and playground links.
- Open the playground link or the MCP App viewer to edit the source and export SVG.
Files readREADME.mdpyproject.tomldocker-compose.yml.cursor/mcp.jsonmcp_core/tools/diagram_tools.pymcp_core/apps/diagram_viewer.pymcp_core/core/config.py
3. Overview
The server exposes five tools, plus resources (uml://types, uml://examples, uml://templates), prompts and skill files that teach the assistant each notation.
| Tool | What it does |
|---|---|
generate_uml | Render one diagram; returns url, playground, display_markdown, and the bytes as base64 when they are fetched |
generate_uml_image | The same, returned as MCP ImageContent for inline display (PNG by default) |
validate_uml | Check source before rendering, with errors that say how to fix it |
list_diagram_types | The live catalog of types and their output formats |
generate_uml_batch | Several diagrams in one call (MCP_BATCH_MAX_ITEMS, 20 by default) |
The README counts 46 diagram types: 37 rendered by Kroki and 9 by four bundled plugins (D3 force and cloud diagrams with real logos, stack diagrams, archify-style architecture, workflow and sequence diagrams, and 2D/3D LLM layer maps).
4. What happens on a tool call
generate_uml in mcp_core/tools/diagram_tools.py is a thin wrapper; the work is in generate_from_request (mcp_core/core/diagram_service.py) and run_diagram_pipeline (mcp_core/core/diagram_rendering.py).
sequenceDiagram
participant AI as Assistant (MCP client)
participant Tool as generate_uml
participant Svc as generate_from_request
participant Cache as Render cache
participant Pipe as run_diagram_pipeline
participant K as Kroki
participant FB as PlantUML server / mermaid.ink
AI->>Tool: diagram_type, code, output_format, theme, scale
Tool->>Tool: resolve_diagram_type (exact key, else suggestions or a picker)
Tool->>Svc: DiagramRequest
Svc->>Svc: GenerateUMLInput validation, type in catalog?
Svc->>Cache: SHA-256 key of type, code, format, theme, scale, renderer
alt cache hit
Cache-->>AI: stored result, cache_hit = true
else miss
Svc->>Pipe: render
alt plugin type
Pipe->>Pipe: render_with_plugin
else Kroki type
Pipe->>K: GET /{type}/{format}/{deflate+base64url source}
K-->>Pipe: SVG or PNG
opt Kroki fails and fallback is on
Pipe->>FB: same source
end
end
Pipe-->>Svc: result + attempts + render_ms
Svc->>Svc: flatten SVG labels, rasterize if PNG was asked for an SVG-only type, build display_markdown
Svc->>Cache: store
Svc-->>AI: url, playground, image, display_markdown
end
Step by step:
- Type.
mrtr.resolve_diagram_typelower-cases the key and accepts it if it is in the catalog. Otherwise, if the client supports form elicitation, the server asks the user to pick from up to eight close matches (difflib, cutoff 0.45); if not, it returns an error with those suggestions. The theme goes through the same treatment. - Validation.
GenerateUMLInput(Pydantic) checks the arguments; source is limited toMCP_MAX_CODE_LENGTH, 500,000 characters by default. An unknown type returnsUNSUPPORTED_DIAGRAM_TYPEwith a pointer touml://types. - Format. If the client asks for PNG or JPEG and the type only renders SVG, the service renders SVG and rasterizes it afterwards.
- Cache. Calls that do not write a file are cached in memory. The key is the SHA-256 of a JSON object holding the type, the trimmed source, format, theme, scale and renderer identity. Defaults: 300 seconds, 128 entries, 32 MiB (
MCP_RENDER_CACHE_*). - Render. Plugin types (
plugin:backend) render locally. Everything else goes to Kroki: the source is compressed with zlib at level 9, base64url-encoded and put in the URL{kroki}/{type}/{format}/{encoded}, which is also the link returned to the user. - Fallback. If Kroki fails, PlantUML-family sources are retried on the PlantUML server and Mermaid on mermaid.ink. Mermaid has a fail-fast Kroki deadline of 8 seconds, and a circuit breaker skips Kroki’s Mermaid engine for 60 seconds after repeated failures. Fallback is off by default on Vercel and with a local Kroki, where the public services would be the wrong target.
- Answer. HTML-backed labels in SVG (
foreignObject) are converted to plain SVG text so the file renders anywhere,display_markdownis built for chat, and every result carriesattempts,fallback_usedandrender_ms, so a failure says which backend failed and why.
5. Operations
uml-mcp admin opens a web console on http://127.0.0.1:8765/admin (on a deployed server, /admin): setup, settings, activity, live logs, metrics, rate limits, tools and plugins, clients and quality checks. Locally, changes need a one-time setup token; with enterprise sign-in (Entra ID) the console is read-only unless writes are enabled in the settings.

docs/assets/admin/desktop-overview.png): health, traffic and a setup checklist.
6. Getting started
Use the hosted server in any MCP client:
"uml-mcp": {
"transport": "http",
"url": "https://uml-mcp.vercel.app/mcp"
}
Or install it locally and let the setup command write the client configuration:
uv tool install uml-mcp && uml-mcp setup
Then ask the assistant for a diagram, for example “Draw a sequence diagram of a user logging in through an API gateway.” The repository has ready-made configurations for Cursor (.cursor/mcp.json), VS Code (.vscode/mcp.json), Codex, Claude Desktop and Open WebUI, and docs/installation.md covers Docker, Helm and running from source.
7. Repository guide
server.py,app.py: stdio and HTTP entry points;server.pyresolves the MCP object lazily so importing it prints nothing on stdout, which carries the stdio protocol.mcp_core/tools/: the tool functions, their schemas, elicitation helpers (mrtr.py), batch progress notifications and export.mcp_core/core/: catalog, validation, rendering pipeline, render cache, SVG rasterizing, themes and configuration.mcp_core/plugins/,examples/plugins/: the plugin loader and the four bundled plugins (D3, stack diagram, archify, LLM visualizer).mcp_core/apps/: the MCP App viewer (ui://uml-mcp/diagram-viewer) and SVG sanitizing.mcp_core/admin/,mcp_core/auth/,mcp_core/observability/: admin console, SSO and metrics.tools/kroki/: the Kroki client, URL encoding, playground links and per-language helpers.deploy/helm/,Dockerfile,docker-compose*.yml,vercel.json: deployment.tests/: 127 entries, unit and integration tests with MCP and HTTP rigs.
8. Limits
- Kroki-backed types depend on a reachable Kroki instance, and because the source travels in the URL, very large diagrams produce very long links.
- The render cache is per process and in memory, so it is not shared between serverless instances.
- The fallbacks send diagram source to third-party services (PlantUML server, mermaid.ink) when enabled; set
MCP_DIAGRAM_FALLBACK=falseif the source is private. - MCP Apps support varies by client; other clients only get the image and links.
9. Sources
- GitHub repository
- Documentation
- PyPI package
mcp_core/tools/diagram_tools.pymcp_core/core/diagram_service.pymcp_core/core/diagram_rendering.pymcp_core/core/render_cache.pytools/kroki/kroki.py- Companion article
10. CI/CD pipeline
11 GitHub Actions workflows, 26 jobs. Each box is a job; double-bordered boxes publish or deploy, and arrows follow needs.
Mermaid Pipeline flow
flowchart LR
subgraph wf0["Build Package"]
direction LR
wf0_build[["build<br/>ubuntu-latest"]]
end
subgraph wf1["UML-MCP CD Pipeline"]
direction LR
wf1_prepare["prepare<br/>ubuntu-latest"]
wf1_build["build<br/>reuses build.yml"]
wf1_deploy["deploy<br/>reuses deploy.yml"]
end
subgraph wf2["UML-MCP CI Pipeline"]
direction LR
wf2_lint["lint<br/>ubuntu-latest"]
wf2_test[["test<br/>ubuntu-latest"]]
wf2_public_kroki["public-kroki<br/>ubuntu-latest"]
wf2_helm[["helm<br/>ubuntu-latest"]]
wf2_frontend["frontend<br/>ubuntu-latest"]
wf2_build["build<br/>reuses build.yml"]
end
subgraph wf3["Deploy (Vercel conformance + Smithery publi…"]
direction LR
wf3_test_and_publish[["test-and-publish<br/>ubuntu-latest"]]
end
subgraph wf4["Deploy docs"]
direction LR
wf4_build[["build<br/>ubuntu-latest"]]
wf4_deploy[["deploy<br/>ubuntu-latest"]]
end
subgraph wf5["MCP 2026 Conformance"]
direction LR
wf5_protocol_conformance[["protocol-conformance<br/>ubuntu-latest"]]
end
t0(["manual run · called by a workflow"])
t1(["push · release · manual run"])
t2(["manual run · push · pull request"])
t3(["called by a workflow · manual run"])
t4(["push · manual run"])
t5(["manual run · pull request"])
d0[("GitHub Pages")]
t0 --> wf0_build
t1 --> wf1_prepare
wf1_prepare --> wf1_build
wf1_build --> wf1_deploy
t2 --> wf2_lint
t2 --> wf2_test
t2 --> wf2_public_kroki
t2 --> wf2_helm
t2 --> wf2_frontend
t2 --> wf2_build
t3 --> wf3_test_and_publish
t4 --> wf4_build
wf4_build --> wf4_deploy
wf4_deploy -.-> d0
t5 --> wf5_protocol_conformance
| Workflow | Triggers | Jobs | Publishes to |
|---|---|---|---|
Build Package.github/workflows/build.yml | manual run, called by a workflow |
| — |
UML-MCP CD Pipeline.github/workflows/cd.yml | push, release, manual run |
| — |
UML-MCP CI Pipeline.github/workflows/ci.yml | manual run, push, pull request |
| — |
Deploy (Vercel conformance + Smithery publish).github/workflows/deploy.yml | called by a workflow, manual run |
| — |
Deploy docs.github/workflows/docs.yml | push, manual run |
| GitHub Pages |
MCP 2026 Conformance.github/workflows/mcp-2026-conformance.yml | manual run, pull request |
| — |
MCP Rig.github/workflows/mcp-rig.yml | manual run, push, pull request |
| — |
Build MCPB Bundle.github/workflows/mcpb.yml | manual run, called by a workflow |
| — |
3 more workflows are not shown.
Generated from the source at commit ebaeac6.
11. Deployment diagram
Mermaid Deployment diagram
flowchart LR
repo[("GitHub repository")]
ci[["GitHub Actions<br/>11 workflows"]]
image["Docker image<br/>FROM python:3.15-slim"]
pub_GitHub_Pages[("GitHub Pages")]
pub_PyPI[("PyPI")]
host_Vercel("Vercel<br/>vercel.json")
host_Kubernetes_manifests("Kubernetes<br/>deploy/helm/uml-mcp/")
host_MkDocs_site("Documentation site (MkDocs)<br/>mkdocs.yml")
subgraph compose["Docker Compose"]
svc_uml_mcp["uml-mcp"]
svc_kroki["kroki"]
svc_mermaid["mermaid"]
svc_blockdiag["blockdiag"]
svc_bpmn["bpmn"]
svc_excalidraw["excalidraw"]
svc_plantuml_server["plantuml-server"]
svc_mermaid_ink["mermaid-ink"]
end
repo -->|"push or pull request"| ci
ci -->|"docker build"| image
ci -->|"publishes"| pub_GitHub_Pages
ci -->|"publishes"| pub_PyPI
ci -.->|"configured"| host_Vercel
ci -.->|"configured"| host_Kubernetes_manifests
ci -.->|"configured"| host_MkDocs_site
image -->|"docker compose up"| compose
12. External dependencies
82 declared packages (43 runtime, 39 development) in pyproject.toml, frontend/package.json, examples/plugins/uml-mcp-plugin-d3/pyproject.toml.
Package table 80 / 82
| Package | Version | Scope | Purpose | Registry |
|---|---|---|---|---|
fastapi | >=0.141.1,<0.200.0 | runtime | Web framework | pypi.org |
uvicorn | >=0.54,<0.55 | runtime | Application server | pypi.org |
pydantic | >=2.14.0,<3 | runtime | Data validation | pypi.org |
pydantic-core | >=2.50.0,<3 | runtime | Data validation | pypi.org |
rich | ==15.0.0 | runtime | Command line | pypi.org |
typer | ==0.27.3 | runtime | Command line | pypi.org |
tqdm | >=4.66.0,<5 | runtime | Command line | pypi.org |
python-multipart | ==0.0.32 | runtime | A streaming multipart parser for Python | pypi.org |
python-dotenv | ==1.2.4 | runtime | Configuration | pypi.org |
starlette | >=1.6.0,<2.0.0 | runtime | Web framework | pypi.org |
jinja2 | >=3.1.2,<4 | runtime | Templates | pypi.org |
aiofiles | >=25,<26 | runtime | File support for asyncio. | pypi.org |
requests | >=2.34.2,<3 | runtime | HTTP client | pypi.org |
click | ==8.5.0 | runtime | Command line | pypi.org |
charset-normalizer | ==3.5.2 | runtime | The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet. | pypi.org |
python-dateutil | >=3,<4 | runtime | Extensions to the standard Python datetime module | pypi.org |
graphviz | >=0.21,<0.22 | runtime | Simple Python interface for Graphviz | pypi.org |
pillow | >=13,<14 | runtime | Graphics, imaging and 3D | pypi.org |
fastmcp-slim | ==4.1.3 | runtime | Model Context Protocol | pypi.org |
mcp | >=2.0.0,<3.0.0 | runtime | Model Context Protocol | pypi.org |
pyjwt | >=2.10.0,<3 | runtime | Authentication and security | pypi.org |
cryptography | >=44.0.0,<51 | runtime | Authentication and security | pypi.org |
pyyaml | >=6.0.2,<7 | runtime | Configuration | pypi.org |
resvg-py | >=0.5.0,<1 | runtime | — | pypi.org |
opentelemetry-sdk | >=1.30.0,<2 | development | Logging and observability | pypi.org |
opentelemetry-exporter-otlp-proto-http | >=1.30.0,<2 | development | Logging and observability | pypi.org |
tomli | >=2.4.1,<3 | development | Configuration | pypi.org |
pre-commit | >=4.6.0 | development | Linting and formatting | pypi.org |
pytest | >=9.1.1,<10 | development | Testing | pypi.org |
pytest-cov | >=7.1.0,<8 | development | Testing | pypi.org |
ruff | >=0.15.15 | development | Linting and formatting | pypi.org |
ty | >=0.0.69 | development | An extremely fast Python type checker, written in Rust. | pypi.org |
pytest-asyncio | >=1.4.0,<2 | development | Testing | pypi.org |
mypy | >=2.0.0,<3 | development | Linting and formatting | pypi.org |
mkdocs | >=1.6.0 | development | Project documentation with Markdown. | pypi.org |
mkdocs-material | >=9.7.6 | development | Documentation that simply works | pypi.org |
pymdown-extensions | >=11.0 | development | Extension pack for Python Markdown. | pypi.org |
mkdocs-git-revision-date-localized-plugin | >=1.5.3 | development | Mkdocs plugin that enables displaying the localized date of the last git modification of a markdown file. | pypi.org |
mkdocs-minify-plugin | >=0.8.0 | development | An MkDocs plugin to minify HTML, JS or CSS files prior to being written to disk | pypi.org |
mkdocs-glightbox | >=0.4.0 | development | MkDocs plugin supports image lightbox with GLightbox. | pypi.org |
mkdocstrings | >=0.30.0 | development | Automatic documentation from sources, for MkDocs. | pypi.org |
axe-playwright-python | >=0.1.4 | development | Testing | pypi.org |
playwright | >=1.55.0,<2 | development | Testing | pypi.org |
@radix-ui/react-dialog | ^1.1.23 | runtime | — | npmjs.com |
@radix-ui/react-dropdown-menu | ^2.1.24 | runtime | — | npmjs.com |
@radix-ui/react-label | ^2.1.15 | runtime | — | npmjs.com |
@radix-ui/react-select | ^2.3.7 | runtime | — | npmjs.com |
@radix-ui/react-separator | ^1.1.15 | runtime | — | npmjs.com |
@radix-ui/react-slot | ^1.3.3 | runtime | — | npmjs.com |
@radix-ui/react-switch | ^1.3.7 | runtime | — | npmjs.com |
@radix-ui/react-tabs | ^1.1.21 | runtime | — | npmjs.com |
@radix-ui/react-tooltip | ^1.2.16 | runtime | — | npmjs.com |
class-variance-authority | ^0.7.1 | runtime | Class Variance Authority 🧬 | npmjs.com |
clsx | ^2.1.1 | runtime | A tiny (239B) utility for constructing className strings conditionally. | npmjs.com |
lucide-react | ^1.48.0 | runtime | A Lucide icon library package for React applications. | npmjs.com |
react | ^19.3.0 | runtime | User interface | npmjs.com |
react-dom | ^19.3.0 | runtime | User interface | npmjs.com |
react-router-dom | ^7.18.4 | runtime | User interface | npmjs.com |
recharts | ^3.10.1 | runtime | Charts | npmjs.com |
sonner | ^2.0.8 | runtime | An opinionated toast component for React. | npmjs.com |
tailwind-merge | ^3.7.0 | runtime | User interface | npmjs.com |
@eslint/js | ^10.0.1 | development | Linting and formatting | npmjs.com |
@tailwindcss/vite | ^4.3.3 | development | User interface | npmjs.com |
@testing-library/jest-dom | ^7.0.1 | development | Testing | npmjs.com |
@testing-library/react | ^16.3.3 | development | Testing | npmjs.com |
@testing-library/user-event | ^14.6.7 | development | Testing | npmjs.com |
@types/node | ^26.6.2 | development | Type checking | npmjs.com |
@types/react | ^19.3.0 | development | Type checking | npmjs.com |
@types/react-dom | ^19.3.0 | development | Type checking | npmjs.com |
@vitejs/plugin-react | ^6.1.1 | development | The default Vite plugin for React projects | npmjs.com |
eslint | ^10.11.0 | development | Linting and formatting | npmjs.com |
eslint-plugin-react-hooks | ^7.1.1 | development | Linting and formatting | npmjs.com |
globals | ^17.12.0 | development | Global identifiers from different JavaScript environments | npmjs.com |
jsdom | ^30.1.1 | development | A JavaScript implementation of many web standards | npmjs.com |
tailwindcss | ^4.3.3 | development | User interface | npmjs.com |
tw-animate-css | ^1.4.0 | development | TailwindCSS v4.0 compatible replacement for tailwindcss-animate. | npmjs.com |
typescript | ^6.0.3 | development | Type checking | npmjs.com |
typescript-7 | npm:typescript@^7.0.2 | development | — | npmjs.com |
typescript-eslint | ^8.70.1 | development | Linting and formatting | npmjs.com |
vite | ^8.3.1 | development | Build tooling | npmjs.com |
2 more packages are listed in the manifests.
13. Glossary
Repository
The versioned source files, configuration, and history of a project.
README
The repository’s entry document, usually covering its purpose and initial setup.
Dependency
A library, tool, or service that another component needs to build or run.
API
An interface through which software components exchange requests and results. An API does not have to use HTTP.
HTTP
A request-and-response protocol used by browsers and web services. A method, path, headers, and optional body describe a request.
Session
State kept across related requests, often to track a signed-in user. Authentication and permission checks remain separate concerns.
Container
An isolated process environment created from an image. Persistent data needs storage outside the container’s disposable filesystem.
Docker Compose
A configuration format and tool for starting related containers, networks, and volumes. Startup order alone does not guarantee service readiness.
Published port
A host port mapped to a service’s container port. Publishing a port can expose that service beyond its container network.
CLI
A text interface in which commands and arguments select operations. Exit codes let scripts detect success or failure.
Build
The steps that turn source files and dependencies into a runnable program or distributable artifact.
Continuous integration
Automated checks that run when source changes, such as building, testing, and linting. Passing checks cover only what those checks exercise.
MCP
Model Context Protocol: a protocol through which an AI client discovers and calls tools and reads resources from a server.
Mermaid
A text-based diagram language. Nodes and connections describe a model; the diagram itself does not execute the project.
GPU
A processor designed for parallel workloads, including graphics rendering and many numerical operations.
Mesh
A surface represented by vertices and connected elements, often triangles. Its geometry is distinct from its material or texture.
Backend
An implementation behind a shared interface. Depending on context, it can mean a server-side service or a graphics, input, or storage implementation.
14. References
- antoinebou12. (2026, November 5). uml-mcp. [Software repository] github.com.
- antoinebou12. (2026, November 5). uml-mcp: README. [Repository documentation] github.com.
- antoinebou12. (2026, November 5). server.py. [Source file] github.com.
- antoinebou12. (2026, November 5). mcp_core/core/server.py. [Source file] github.com.
- antoinebou12. (2026, November 5). README.md. [Source file] github.com.
- Boucher, A. (2026, September 2). uml-mcp — UML diagrams from chat via MCP. [Project article] antoineboucher.info.
- Boucher, A. (2026, October 23). uml-mcp: From an MCP tool call to a diagram. [Project article] antoineboucher.info.
- Boucher, A. (2026, September 2). uml-mcp. [Project article] antoineboucher.info.
Sources without a publication date show the date they were last checked, November 5, 2026. File links retain the inspected revision where available.