Skip to main content
Glama

plan-viz-mcp

License: MIT Node.js CI

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 build

Chromium 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/list

npm 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

plan

Inline plan text, the current selection, or the full contents of a named .txt / .sql fixture

format

.png (default) or .excalidraw

path

Output .png or .excalidraw file. Inferred from the path extension when format is omitted

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:package

Build 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 chromium from 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 .png using 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 tool
visualizeVisualize a DataFusion execution planA
Read-onlyIdempotent

Convert raw DataFusion physical plan or EXPLAIN / EXPLAIN ANALYZE output into an editable Excalidraw scene or PNG image. Does not execute SQL.

ParametersJSON Schema
NameRequiredDescriptionDefault
planYes
formatYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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. 1 tool updatev0.1.0
    • First observedvisualize

TDQS

A4.4/5.0

Scored across 1 tool

Disambiguation5/5

With only one tool, there is no possibility of confusion between tools. The tool's purpose is clearly distinct and singular.

Naming Consistency5/5

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.

Tool Count3/5

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.

Completeness5/5

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

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    Converts 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.
    3
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    Generate 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.
    28
    3
    MIT