plan-viz
Generates editable Excalidraw diagrams from DataFusion physical execution plans, returning .excalidraw scene JSON that can be opened in Excalidraw.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@plan-vizTurn this DataFusion EXPLAIN output into a PNG diagram."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
plan-viz-mcp
Convert DataFusion physical execution plans into editable Excalidraw diagrams or PNG images using one MCP tool: visualize.
The server uses the public convertPlanToExcalidraw API from plan-viz. It accepts raw indented physical plans and DataFusion EXPLAIN / EXPLAIN ANALYZE tables. It does not execute SQL, connect to a database, or save submitted plans or generated results to disk.
Install from source
Use Node.js 24 LTS (Node 22.13+ is also supported).
npm ci
npx playwright install chromium
npm run buildChromium is needed only for .png. JSON output works without a browser. On Linux, use npx playwright install --with-deps chromium if browser system libraries are missing. Browser installation downloads executables; subsequent visualization runs use bundled assets and fonts without external network access.
Related MCP server: Vizdown-MCP
stdio
The published v0.1.0 tarball is the default Cursor configuration. Add it to .cursor/mcp.json or an MCP host's server settings. Ensure the host's node executable is a supported version; use an absolute path to Node if necessary.
{
"mcpServers": {
"plan-viz": {
"command": "npx",
"args": [
"-y",
"https://github.com/NGA-TRAN/plan_viz_mcp/releases/download/v0.1.0/plan-viz-mcp-0.1.0.tgz"
]
}
}
}After npm publication, npx -y plan-viz-mcp is equivalent. For a local checkout, build first (npm run build) and point the host at dist/stdio.js:
{
"mcpServers": {
"plan-viz": {
"command": "node",
"args": ["/absolute/path/to/plan_viz_mcp_codex/dist/stdio.js"]
}
}
}For transport inspection, run:
npx @modelcontextprotocol/inspector node dist/stdio.js
# Noninteractive discovery:
npx @modelcontextprotocol/inspector --cli node dist/stdio.js --method tools/listnpm start is convenient for manual execution. Configure hosts to launch node dist/stdio.js directly so npm's own script banners cannot pollute the protocol stream. Server diagnostics go to stderr.
Cursor command: /visualize
This repo ships a project command at .cursor/commands/visualize.md. After the plan-viz MCP server is configured and enabled (Customize → MCP, or reload the window), type /visualize in Cursor Agent chat.
The command reads a DataFusion physical plan, calls the MCP visualize tool, and writes the result to a workspace file. It accepts:
Input | Meaning |
| Inline plan text, the current selection, or the full contents of a named |
|
|
| Output |
If path is omitted, the command writes a kebab-case PNG named from the request (a query or plan-file basename, or the top operators, for example projection-filter-datasource.png) and reports that path. Do not treat a plan fixture as the output path.
/visualize example_1.png
ProjectionExec: expr=[id, name, age]
FilterExec: age > 18
DataSourceExec: file_groups={1 groups: [[data.parquet]]}/visualize format=.excalidraw tests/fixtures/sample-plan.ts example_1.excalidraw/visualize path/to/plan.txt/visualize tests/join.sql example_join.png/visualize
ProjectionExec: expr=[id, name, age]
FilterExec: age > 18
DataSourceExec: file_groups={1 groups: [[data.parquet]]}The first and last examples write example_1.png and projection-filter-datasource.png respectively. Open .excalidraw results in Excalidraw or plan-visualizer.
Streamable HTTP
npm run start:http
# http://127.0.0.1:3333/mcp
# Optional: PORT=4444 npm run start:http{
"mcpServers": {
"plan-viz": {
"url": "http://127.0.0.1:3333/mcp"
}
}
}If the host requires an explicit transport type:
{
"mcpServers": {
"plan-viz": {
"type": "http",
"url": "http://127.0.0.1:3333/mcp"
}
}
}The server binds to 127.0.0.1 and accepts POST requests only at /mcp. It permits Host values 127.0.0.1:<port> and localhost:<port>. An Origin, if present, must be the corresponding http:// origin on that same port. Native MCP clients may omit Origin. There is no public deployment or authentication mode in this release; do not expose this endpoint through a public proxy.
Tool examples
Both plan and format are required. Formats are exactly .excalidraw and .png. These JSON objects are the arguments to an SDK client's callTool method, not complete JSON-RPC wire messages. Let the SDK supply protocol metadata and envelopes.
The shared sample, also used by tests, is:
ProjectionExec: expr=[id, name, age]
FilterExec: age > 18
DataSourceExec: file_groups={1 groups: [[data.parquet]]}1. Editable Excalidraw scene
{
"name": "visualize",
"arguments": {
"plan": "ProjectionExec: expr=[id, name, age]\n FilterExec: age > 18\n DataSourceExec: file_groups={1 groups: [[data.parquet]]}",
"format": ".excalidraw"
}
}The successful result has isError: false, a text block containing the complete, pretty-printed scene JSON, and:
{ "format": ".excalidraw", "mimeType": "application/json" }in structuredContent. Parse the text with JSON.parse; the result has type: "excalidraw" and a nonempty elements array. The host can save the returned text as a .excalidraw file for editing. The server itself performs no result-file writes.
2. PNG image
{
"name": "visualize",
"arguments": {
"plan": "ProjectionExec: expr=[id, name, age]\n FilterExec: age > 18\n DataSourceExec: file_groups={1 groups: [[data.parquet]]}",
"format": ".png"
}
}The successful result contains an image block with type: "image", mimeType: "image/png", and base64 bytes in data. Its structuredContent is:
{ "format": ".png", "mimeType": "image/png" }The decoded bytes are a complete PNG (signature 89 50 4E 47 0D 0A 1A 0A). Image display and downloading depend on the host UI. This is an export of the same Excalidraw scene, not a separate layout implementation.
3. Validation error
{
"name": "visualize",
"arguments": { "plan": " ", "format": ".png" }
}A blank plan, absent format, or unsupported format returns a tool result with isError: true, explanatory text, and no image. Converter and renderer failures also return safe tool errors. Malformed protocol messages and HTTP rejections retain their protocol/HTTP error semantics.
4. EXPLAIN table
The same tool accepts table output with a physical_plan row:
+-------------------+--------------------------------------------------------------------+
| plan_type | plan |
+-------------------+--------------------------------------------------------------------+
| physical_plan | ProjectionExec: expr=[id, name, age] |
| | FilterExec: age > 18 |
| | DataSourceExec: file_groups={1 groups: [[data.parquet]]} |
+-------------------+--------------------------------------------------------------------+Pass the entire table as plan with either format. EXPLAIN ANALYZE tables using Plan with Metrics are also supported. Fixtures in tests/fixtures/plans.ts generate both variants from the shared sample. Preserve the indentation in the plan column.
Limits and lifecycle
Resource | Limit |
Plan text | 512 KiB, measured as UTF-8 bytes |
HTTP body / stdio input buffer | 4 MiB |
Serialized tool result | 8 MiB, including base64 expansion |
Conversion | One active worker, four queued jobs, 5 seconds including queue wait |
Worker heap | 128 MiB old-generation heap |
PNG rendering | One active export, four queued jobs, 30 seconds including queue wait |
PNG dimensions | 16 megapixels; maximum 16384 pixels per side |
Large conversions run in terminable workers to keep the server responsive. PNG requests lazily start one Chromium process and use a fresh context for each export. Cancellation, timeouts, and shutdown release workers and browser contexts; a subsequent request can restart a crashed browser. No plan/result cache is retained. Chromium may create temporary runtime profiles managed by Playwright.
A resource-limit error never returns a partial image. Request .excalidraw when the image dimensions are too large, or submit a smaller plan when conversion or result size limits are reached. Operator support and interpretation come from plan-viz; accepting text does not validate SQL semantics.
Development and verification
npm run typecheck
npm run lint
npm run format:check
npm run build
npm test
npm run test:png
npm run test:packageBuild before running tests: process/worker tests exercise compiled files. npm test uses fake images and does not launch Chromium. test:png requires Chromium and fails instead of skipping when unavailable. It checks real image pixels, bundled fonts, offline rendering, both transports, crash recovery, and cancellation. CI runs fast tests on Node 22 and 24 and browser/package tests on Node 24.
test:package packs the build, installs it with production dependencies into a fresh temporary directory, and exercises both formats over stdio and HTTP outside the source tree. It prints the retained package artifact location. This command may access npm but never publishes anything.
The implementation uses MCP SDK 2.0.0 and its built-in compatibility path for 2025-era clients. Automated tests cover pinned 2026-07-28 and legacy client connections. See verification.md for the checks actually run and remaining host/UI limitations.
Troubleshooting
Chromium could not start: run
npx playwright install chromiumfrom the source checkout or installed package directory, using its pinned Playwright version. A restricted OS/container sandbox may also block browser launch.Unsupported Node engine: select Node 24 for both installation and the MCP host's configured executable. Shell version managers and desktop applications can resolve different Node installations.
HTTP 403: use the exact loopback URL and allowed Host/Origin values; public domains and unrelated browser origins are rejected.
Renderer busy / timeout: wait for the active request or reduce the plan size.
JSON works but no image appears: verify
.pngusing Inspector; the host must support MCP image content.
Architecture and rationale are in docs/implementation-plan.md. The original reference is retained in docs/plan.md.
Contributing
See CONTRIBUTING.md. Please follow the code of conduct. Security reports go through SECURITY.md, not public issues.
Changelog
Notable changes are listed in CHANGELOG.md.
License
MIT. See LICENSE.
Available Tools
1 toolvisualizeVisualize a DataFusion execution planARead-onlyIdempotent
Convert raw DataFusion physical plan or EXPLAIN / EXPLAIN ANALYZE output into an editable Excalidraw scene or PNG image. Does not execute SQL.
| Name | Required | Description | Default |
|---|---|---|---|
| plan | Yes | ||
| format | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark the tool as read-only, idempotent, and non-destructive. The description adds a crucial behavioral note—'Does not execute SQL'—which assures the agent that invoking this tool has no side effects beyond producing a visualization. This goes beyond the annotations and adds valuable context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, well-structured sentence that front-loads the primary purpose and adds the critical 'Does not execute SQL' clause at the end. There is zero filler, making it efficient and easy to parse.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity (2 parameters, no nested objects), the description covers the essential behavior and parameters. The output schema is present, so return values don't need description. The only minor gap is a lack of mention of potential errors or size limits, but these are secondary for a read-only conversion tool. Overall, it is sufficiently complete for an agent to use correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 0% schema description coverage, the description carries the burden of explaining parameters. It does this well: 'plan' is described as 'raw DataFusion physical plan or EXPLAIN / EXPLAIN ANALYZE output' and 'format' is implied by the output types ('.excalidraw' or '.png'). The description provides enough meaning for an agent to understand what to pass, even though it doesn't enumerate valid format values explicitly (the schema enumerates them).
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states a specific verb ('Convert') and resource ('raw DataFusion physical plan or EXPLAIN / EXPLAIN ANALYZE output') and specifies the output types ('editable Excalidraw scene or PNG image'). This is unambiguous and leaves no doubt about the tool's function, even without siblings to differentiate from.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear context: it is used to visualize DataFusion plans into images. It also includes an explicit exclusion ('Does not execute SQL'), which tells the agent when not to use it (if SQL execution is needed). There are no sibling tools to compare, but the usage context is well-stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
1 tool update
v0.1.0- First observed
visualize
TDQS
Scored across 1 tool
With only one tool, there is no possibility of confusion between tools. The tool's purpose is clearly distinct and singular.
The single tool name 'visualize' is consistent and follows a clear verb-based pattern. There are no other tools to conflict with, so naming consistency is trivially maintained.
The server has only one tool, which feels thin for a typical MCP server. However, given its narrow purpose of plan visualization, the count is borderline but not unreasonable.
The tool fully covers the server's stated purpose of converting DataFusion plans into visual formats. There are no obvious gaps in the domain of plan visualization.
Maintenance
Related MCP Connectors
Create, validate, edit, export (markdown/svg/png/mermaid), and search JSON Canvas files.
Generate, edit, and export data-architecture diagrams from your AI. Column lineage, PNG in chat.
Render, verify, describe, and safely edit Mermaid diagrams through MCP.
Generate cloud architecture diagrams, flowcharts, and sequence diagrams.
Related MCP Servers
- AlicenseAqualityCmaintenanceEnables AI agents to programmatically generate, edit, and view Excalidraw diagrams with real-time browser synchronization. It provides a suite of tools for adding shapes, text, and arrows to diagrams through natural language interactions.112,455 npm100MIT
- AlicenseAqualityDmaintenanceConverts Markdown files into professional diagrams such as flowcharts, mind maps, and architecture diagrams using Mermaid.js and custom SVG renderers. It enables users to list, render, and export visualizations in multiple formats including SVG, PNG, and PDF.3MIT
- AlicenseNot gradedqualityDmaintenanceConverts Mermaid diagrams into Excalidraw diagrams, serves them locally, and opens the result in your browser.29 npm3MIT
- AlicenseAqualityCmaintenanceGenerate 25+ types of hand-drawn Excalidraw diagrams - flowcharts, sequence, architecture, mind maps, ER, UML, kanban, bar/line/radar charts - from structured input with Sugiyama auto-layout and CJK support. Reads and modifies .excalidraw files, exports SVG. Python, local, no API keys required.283MIT