Skip to main content
Glama

diagrams-mcp-server

Technical Preview (V1 Preview, v0.7.0) — local-first MCP server for PlantUML and Mermaid diagrams: manage, render, and share them, check them against your codebase, and draft new ones from your code.

CI Node.js TypeScript MCP PlantUML Mermaid License: MIT

An MCP (Model Context Protocol) server that gives AI coding agents structured access to your project's PlantUML and Mermaid architecture diagrams. It can list, read, create, update, and delete diagrams, render and export them, check them against the codebase, diff two versions, and draft new diagrams from code or from starter skeletons — all locally, with no accounts and no network calls unless you explicitly opt in.

Works with any MCP-compatible client over stdio: Claude Code, Codex (Desktop & CLI), Antigravity (IDE, 2.0 & CLI), OpenCode (Desktop & CLI), Cursor, and VS Code. See Client setup below.

Why this exists

I built this after running into the same problem while using AI to work on software design. The diagram was in one place, the code was in another, and I kept having to paste context into the conversation. After a few rounds, it became hard to tell whether the diagram still described the project. I wanted a small local MCP server that could keep the diagram in the project, let the agent read it, and check it against the code when needed.

diagrams-mcp-server keeps diagrams in the project next to the code so an agent can read and check them in the same workflow. It uses the standard stdio MCP transport and does not require client-specific server code.

Related MCP server: scryer-mcp

Features

Twelve tools in four groups. The read-only drafting tools (diagrams_generate, diagrams_generate_sequence, diagrams_template, diagrams_export) never write: they return source text and you save it yourself with diagrams_create.

Manage diagrams

Tool

What it does

diagrams_list

List all PlantUML/Mermaid diagrams in the project, with extracted titles and explicit offset/limit pagination

diagrams_get

Read the raw source of a diagram, in full or as an explicit offset/max_chars window

diagrams_create

Create a new diagram file (refuses to overwrite)

diagrams_update

Replace an existing diagram's content

diagrams_delete

Delete a diagram (explicit, marked destructiveHint)

Render and share

Tool

What it does

diagrams_render

Render a diagram to SVG/PNG

diagrams_export

Package a stored diagram and its rendered SVG into one self-contained HTML file — fully offline, no external resources, nothing written to disk

Check and compare

Tool

What it does

diagrams_check_consistency

Compare class/interface/component names in a diagram against your actual codebase and flag anything that looks outdated

diagrams_diff

Compare two diagram sources — two stored files, or a stored file against inline text — and report added, removed, and renamed entity names

Draft new diagrams

Tool

What it does

diagrams_generate

Draft a PlantUML or Mermaid class diagram from a slice of your codebase, returning source text to review and then save with diagrams_create

diagrams_generate_sequence

Draft a PlantUML or Mermaid sequence diagram from the message-call patterns in a slice of your codebase, returning source text to review and then save with diagrams_create

diagrams_template

Instantiate a minimal, always-valid starter skeleton (class, sequence, or C4-context) in PlantUML or Mermaid — one declaration per entity, nothing inferred, nothing written

Tool notes

diagrams_check_consistency It reads entity names from class/interface/enum/component declarations, aliases, namespaces, packages, sequence participants, message calls such as charge(card), C4 blocks, and subgraph groupings. It then searches source files for matching identifiers, using declaration patterns for JavaScript/TypeScript, Python, PHP, and Java, and whole-word matching elsewhere. It helps detect common drift, such as a renamed or removed class or a component that has not been implemented. Structured output includes extracted, matched, and unmatched entities, per-entity file evidence, analyzer tiers, and an explicit heuristic confidence warning. The scan limits are listed under Consistency scan limits.

diagrams_generate

diagrams_generate is the generative flip side of that check: it reads the same declarations from a file or directory under your project root and drafts a class diagram from them — one box per declared name, plus extends/implements edges when the TypeScript compiler can evidence them. It is read-only and never writes: the source text comes back in the response, and nothing lands in diagrams/ until you save it with an explicit diagrams_create call. It is a heuristic (name extraction, not full type modeling): member lists, generics, namespace nesting, and cross-file inheritance through re-exports are out of scope, and a scope without TypeScript-family files yields entities with no relations and a dialect_note saying why. Every result is labeled confidence: "heuristic" with a heuristic_warning, and every cap reports itself in-band (entities_capped / entities_available / relations_capped / truncated), so a capped draft is never mistaken for a complete one. The generation limits are listed under Generation limits.

diagrams_generate_sequence

diagrams_generate_sequence drafts the other half of the picture: not the boxes, but the conversation between them. It reads the message-call patterns in a file or directory under your project root — one participant per scanned file, named by module — and emits ordered from -> to : message lines from the caller-to-callee edges the consistency checker's call graph already extracts. Static call-site order is not runtime order, and every result says so: a call inside a callback, promise, or listener is counted in deferred_count and excluded from the messages, because its real position in the conversation is unknowable from source. Participant mapping is declared-identifier equality only — a callee that no file in the scope declares is listed in unresolved_callees rather than attached to an invented participant, because which class owns a method is a type question and out of scope. Like diagrams_generate it is read-only and never writes — nothing lands in diagrams/ until you save it with an explicit diagrams_create call — and every result is labeled confidence: "heuristic" with a heuristic_warning, with every cap reporting itself in-band (participants_capped / messages_capped / *_available / *_limit / truncated). The sequence limits are listed under Sequence limits.

diagrams_diff

diagrams_diff answers the review-time question that follows an edit: what changed between two versions of the same diagram? Each side supplies exactly one of a stored path or inline text, so unstaged edits can be compared without a round trip, and the two sides may even use different dialects — each is read with its own syntax. It reports added / removed / renamed entity names, the unchanged list, and the sequence-side participants_* / calls_* fields ([], never absent, for class diagrams). Rename detection pairs a removed name with an added one only when the two are identical once lowercased and stripped of separators — the same shared normalizer the consistency checker uses to match names against code — so a genuine rename with a different spelling stays a plain add plus a remove, and every pair carries confidence: "heuristic". It compares declared names only: member lists, layout, and style are out of scope, and it never patches or merges — it reports, and you edit. Like the other read-only tools it touches nothing on disk; a malformed request is rejected before any file is read.

diagrams_template

diagrams_template is the blank-page tool that precedes all of them: give it a kind, a dialect, and the entity names, and it hands back a minimal skeleton that already clears every syntax gate. Boilerplate is where missing @startuml/@enduml boundaries and wrong starter keywords enter the repo, so one capped, deterministic emitter removes that failure mode: the six skeletons (class, sequence, C4-context × PlantUML, Mermaid) are fixed tables in source, and identical inputs yield byte-identical source in every process. It is pure — no filesystem, no code scanning, no heuristics, no state — so unlike diagrams_generate there is no confidence field and nothing to be uncertain about: it emits one declaration line per entity plus a TODO hint pointing at where the diagram grows, and nothing more. Member bodies, relations, and styling stay yours to write after the save. The PlantUML C4-context skeleton stays self-contained with plain rectangles, because real C4 shapes need the C4-PlantUML stdlib and this local-first server never fetches it; the Mermaid skeleton uses native C4Context. Nothing is ever written: the source comes back in the response, and nothing lands in diagrams/ until you save it with an explicit diagrams_create call. The template limits are listed under Template limits.

diagrams_export

diagrams_export is the sharing tool that closes the loop: package a stored diagram and its rendered SVG into one self-contained HTML file that opens anywhere, inside or outside the repo. It is packaging of two artifacts the server already produces — the stored source and the locally rendered SVG — so it adds no dependency (the HTML is string concatenation) and no new write surface: the tool never writes a file, the HTML comes back as text, and you decide where it lands. The artifact carries nothing external at all: no src/href URLs, no @import, no script, no web font — inline styles are the only styling, and the SVG is inlined as live markup rather than a base64 image, so it stays selectable and survives a strict content-security policy. The diagram's POSIX relative_path is the only path in the document. With include_source (the default), the source is embedded in a collapsible block built on the native <details> element, which needs no JavaScript; set it to false for a leaner file. Rendering follows diagrams_render exactly, including its CLI requirements and opt-in remote fallback, and rendered_with reports which path produced the image (local-plantuml / remote-plantuml / mmdc). A bundle larger than the byte cap is refused outright rather than cut down — truncated is always false, because a half-rendered artifact is worse than none. The export limits are listed under Export limits.

Pagination and source windows

Pagination is explicit and opt-in — the server never pages or truncates on its own.

diagrams_list accepts optional offset (non-negative integer, default 0) and limit (integer 1–500). Omitting both returns every match. The response always includes count (items in this page), total (matches before paging), the effective offset/limit, and has_more (whether items after this page remain). An offset past the end returns an empty page with has_more: false, not an error. Example: first diagrams_list({ "type_filter": "all", "limit": 10 }), then diagrams_list({ "type_filter": "all", "offset": 10, "limit": 10 }) while has_more is true.

diagrams_get accepts optional offset (zero-based character offset, default 0) and max_chars (integer 1–100000). Omitting both returns the full source. The response always includes is_partial, the effective offset, total_chars, returned_chars, and has_more; the text block always equals the returned content, so a window is never silently truncated. An offset past the end of the source returns an isError result instead of an empty string. Example: diagrams_get({ "relative_path": "models/big.puml", "offset": 0, "max_chars": 2000 }), then repeat with offset: 2000.

Requirements

  • Node.js 18+ for running the server (runtime engines: >=18 — the compiled dist/ output, npm test, and npm start work on Node 18)

  • Node.js >=20.19 for the development toolchain (npm ci, npm run lint, npm run format:check, npm run build) — the ESLint 10 toolchain does not run on older Node versions

  • (Optional, for diagrams_render) @mermaid-js/mermaid-cli for Mermaid rendering: npm install -g @mermaid-js/mermaid-cli

  • (Optional, for diagrams_render) A local plantuml CLI for offline PlantUML rendering. Without it, rendering fails with an actionable error unless remote rendering is explicitly enabled with ALLOW_REMOTE_PLANTUML=true, in which case it falls back to the public plantuml.com server over HTTPS. DISABLE_REMOTE_PLANTUML=true always disables the fallback, even when the allow flag is set.

Installation

You need Node.js 18+ — that is the only requirement. No accounts, no API keys, no separate services.

1. Get the package (pick one way)

Option A — no install (fastest way to try it)

npx diagrams-mcp-server --help

npx fetches the package on first use and caches it. Nothing is installed permanently, so this is the simplest way to try the server. The trade-off: the first run needs internet access, and MCP clients start the server fresh on every session — for daily use, prefer Option B.

npm install -g diagrams-mcp-server
diagrams-mcp-server --help   # prints the help text and exits 0

This puts a diagrams-mcp-server command on your PATH so any MCP client can launch it. To update later, just rerun the same command.

Option C — project dependency (pin a version per project)

cd /path/to/your/project
npm install diagrams-mcp-server
npx diagrams-mcp-server --help

Use this when different projects should use different server versions.

2. Connect it to your client

Installing the package alone is not enough: your MCP client also needs a diagrams entry telling it how to launch the server. The one-command setup writes that entry for you — no hand-editing JSON:

npx diagrams-mcp-server setup            # interactive: pick client, then scope
npx diagrams-mcp-server setup --client codex --yes   # non-interactive
npx diagrams-mcp-server setup --client cursor --scope project --yes   # pin this project

Setup asks for the client first, then the scope (each skippable with a flag):

  • Global (Recommended): writes a clean entry with no PROJECT_ROOT — the server attaches to whatever directory the client launches it from. Best when you work across many projects.

  • Project-specific: asks for the project root and bakes it in ("env": { "PROJECT_ROOT": "..." } for file-based clients, --env PROJECT_ROOT=... for claude/codex mcp add). Best when one config should always point at one project.

For file-based clients (Cursor, VS Code, Antigravity) this merges the entry into the client's config file. For Claude Code and Codex it runs their mcp add command; if that CLI is not installed, setup prints the exact command to run yourself. For OpenCode it prints the command to run. Restart file-based clients afterwards so they pick it up.

Setup opens with a version banner and runs pre-flight checks automatically: it warns when the claude or codex CLI is missing (printing the manual command instead), validates a project-scoped path (offering to create it), and ends with a summary of the client, scope, touched config, and status. Interactive prompts use arrow-key pickers (↑↓ + Enter, Esc cancels) and Yes/No toggles; manual commands appear in boxed cards, and status output is color-highlighted (plain text when piped or when NO_COLOR is set). Every prompt is skipped when the matching flag is passed.

3. Verify it works

Restart your client, then ask your agent: "List my diagrams." It should call diagrams_list — an empty list on a fresh project means everything is wired up correctly.

From source (contributors)

git clone https://github.com/mohammad-emad-dev/diagrams-mcp-server.git
cd diagrams-mcp-server
npm ci
npm run build
npm test

npm test runs the full suite from dist/ — unit, golden, and live-stdio integration tests that spawn the real server — so always build first. Before opening a PR, run all four gates: npm run build, npm test, npm run lint, npm run format:check (the last two need Node >=20.19).

Where the files live

  • Global install (npm install -g diagrams-mcp-server): the package lands in the global node_modules (run npm root -g to find yours — e.g. C:\Users\<you>\AppData\Roaming\npm\node_modules on Windows, /usr/local/lib/node_modules on macOS/Linux) with launch shims on your PATH, so diagrams-mcp-server runs from anywhere.

  • Project dependency (npm install diagrams-mcp-server inside a project): the same payload under <project>/node_modules/diagrams-mcp-server/, with the binary linked at <project>/node_modules/.bin/diagrams-mcp-server.

  • npx diagrams-mcp-server: uses the global install if present, else the local one, else downloads and caches it — no manual file handling needed.

All three run the same entry point (dist/index.js), so MCP clients can use whichever path fits: the global shim, the project's .bin binary, or node <path>/dist/index.js directly.

Lint and formatting

npm run lint          # ESLint over src/ (TypeScript recommended rules, zero warnings allowed)
npm run format:check  # Prettier check over src/ (100-col, double quotes, semicolons, trailing commas)

Both run in CI (.github/workflows/ci.yml, Node 20.x/22.x matrix) before the build. They cover source and test files under src/ only — dist/, node_modules/, graphify-out/, and packed tarballs are excluded via eslint.config.mjs and .prettierignore. These two commands require the development toolchain (Node >=20.19); the server runtime itself still supports Node >=18. .gitattributes pins all text files to LF, so Windows and Linux checkouts produce identical line endings and the format check gives the same result on every platform.

Local tarball install without publishing

To install and run this Technical Preview from a local package file, create a tarball and install it in a separate consumer project:

npm pack   # runs the prepack build and writes diagrams-mcp-server-0.7.0.tgz
cd /path/to/your/project
npm init -y                       # if the consumer project has no package.json yet
npm install /path/to/diagrams-mcp-server-0.7.0.tgz
npx diagrams-mcp-server --help    # resolves the local install, exits 0

This installs only the published payload (dist/ runtime files, README.md, LICENSE) — no tests, fixtures, or local configs — and changes nothing outside the consumer project (no global packages and no registry publish). The package file is local, but npm may still download the package dependencies from the registry during installation. Point any stdio MCP client at the installed binary (node_modules/.bin/diagrams-mcp-server) the same way as dist/index.js in Client setup.

Uninstallation

Uninstalling has two independent parts: disconnecting the server from your client, and removing the package. Do either or both.

1. Disconnect it from your client

Delete the diagrams entry from your client's configuration and restart the client:

Client

What to remove

Cursor

the "diagrams" block in ~/.cursor/mcp.json or .cursor/mcp.json

VS Code

the "diagrams" block in .vscode/mcp.json

Antigravity

the "diagrams" block in ~/.gemini/config/mcp_config.json (or .agents/mcp_config.json)

Claude Code

run claude mcp remove diagrams

Codex

the [mcp_servers.diagrams] section in ~/.codex/config.toml

OpenCode

the "diagrams" block in opencode.jsonc

2. Remove the package

Match how you installed it:

npm uninstall -g diagrams-mcp-server   # global install (Option B)
npm uninstall diagrams-mcp-server      # project dependency (Option C, run inside the project)

If you only ever used npx (Option A), there is nothing to uninstall — optionally clear the download cache with npx clear-npx-cache.

What stays behind

Uninstalling never touches your diagram files: the diagrams/ folder in your project is your own work and is left exactly as it is. Delete it manually only if you want the diagrams gone too.

Client setup

diagrams-mcp-server speaks plain stdio MCP, so it works with any MCP-compatible client. Setup instructions for each below.

All examples assume you built the server at /absolute/path/to/diagrams-mcp-server and want it attached to a project at /absolute/path/to/your/project. Replace both paths with your own. If you installed from the registry, use the global install path or your project's node_modules/.bin/diagrams-mcp-server instead of a build directory (see Where the files live).

Claude Code

claude mcp add diagrams -- node /absolute/path/to/diagrams-mcp-server/dist/index.js

Set PROJECT_ROOT in your shell environment, or run Claude Code from within your project directory (it defaults to the current working directory).

Codex (Desktop & CLI)

codex mcp add diagrams -- node /absolute/path/to/diagrams-mcp-server/dist/index.js

Or add directly to ~/.codex/config.toml:

[mcp_servers.diagrams]
command = "node"
args = ["/absolute/path/to/diagrams-mcp-server/dist/index.js"]
env = { PROJECT_ROOT = "/absolute/path/to/your/project" }

Antigravity (IDE, 2.0 & CLI)

Antigravity IDE, Antigravity 2.0, and Antigravity CLI share one config file: ~/.gemini/config/mcp_config.json (or .agents/mcp_config.json for project scope). Add:

{
  "mcpServers": {
    "diagrams": {
      "command": "node",
      "args": ["/absolute/path/to/diagrams-mcp-server/dist/index.js"],
      "env": {
        "PROJECT_ROOT": "/absolute/path/to/your/project"
      }
    }
  }
}

You can also add it from the IDE: Agent panel → ⋯ menu → MCP Servers → Manage MCP Servers → View raw config, then paste the same block.

OpenCode (Desktop & CLI)

opencode mcp add

When prompted, choose Local as the server type and enter:

node /absolute/path/to/diagrams-mcp-server/dist/index.js

Or edit opencode.jsonc directly:

{
  "mcp": {
    "diagrams": {
      "type": "local",
      "command": ["node", "/absolute/path/to/diagrams-mcp-server/dist/index.js"],
      "environment": {
        "PROJECT_ROOT": "/absolute/path/to/your/project"
      }
    }
  }
}

Cursor (Desktop & CLI)

Add to ~/.cursor/mcp.json (global) or .cursor/mcp.json (project-scoped):

{
  "mcpServers": {
    "diagrams": {
      "command": "node",
      "args": ["/absolute/path/to/diagrams-mcp-server/dist/index.js"],
      "env": {
        "PROJECT_ROOT": "/absolute/path/to/your/project"
      }
    }
  }
}

VS Code (with GitHub Copilot)

Add to .vscode/mcp.json in your workspace:

{
  "servers": {
    "diagrams": {
      "command": "node",
      "args": ["/absolute/path/to/diagrams-mcp-server/dist/index.js"],
      "env": {
        "PROJECT_ROOT": "${workspaceFolder}"
      }
    }
  }
}

Or via the command palette: MCP: Add Server → Command (stdio), then enter the same command and args.

Configuration

Environment variable

Default

Description

PROJECT_ROOT

current working directory

Root of the codebase this server is attached to (used by diagrams_check_consistency)

DIAGRAMS_DIR

diagrams

Where diagram files live, relative to PROJECT_ROOT unless absolute

PLANTUML_SERVER_URL

https://www.plantuml.com/plantuml

Override the public PlantUML rendering fallback (e.g. to point at a self-hosted instance)

ALLOW_REMOTE_PLANTUML

unset (remote fallback disabled)

Set to exactly true to allow the remote PlantUML server fallback when no local plantuml CLI is installed. Any other value keeps remote rendering disabled. Mermaid is always local-only and unaffected

DISABLE_REMOTE_PLANTUML

unset

Set to exactly true to never use the remote PlantUML server, even when ALLOW_REMOTE_PLANTUML=true is set. PlantUML rendering then requires a local plantuml CLI. Mermaid is always local-only and unaffected

Consistency scan limits

Every diagrams_check_consistency run observes these caps:

Limit

Value

How you see it

Files scanned

5,000 source files

the result reports truncated, scan_limit, files_scanned, and scan_warning so a capped scan is never mistaken for a complete one — when truncated is true, unmatched results may be incomplete

Per-file size

1,000,000 bytes

larger files (usually generated bundles) are skipped silently

Evidence per entity

10 matched files

matched_files is capped; matched_file_count still reports the full count

Concurrent file reads

32

bounds open handles while the scan runs

Generation limits

Every diagrams_generate run observes these caps. max_entities (1–60, default 30) bounds the emitted declarations; the limits below are the hard ceilings:

Limit

Value

How you see it

Emitted entities

60 declarations

entities_available reports the total found and entities_capped is true when any were dropped; entity_limit reports the applied cap

Emitted relations

60 edges

relations_available reports the total evidenced and relations_capped is true when any were dropped by the cap or by an entity the cap removed — a diagram never references a box it does not declare

Files scanned

5,000 source files

the result reports truncated, scan_limit, files_scanned, and scan_warning so a capped scan is never mistaken for a complete one — when truncated is true, generated entities may be incomplete

Per-file size

1,000,000 bytes

larger files (usually generated bundles) are skipped

Concurrent file reads

32

bounds open handles while the scan runs

When the TypeScript compiler is not installed (published installs have no typescript dependency), the tool degrades openly instead of failing: entities still come from declaration patterns, relations is empty, and dialect_note says relations are unavailable.

Sequence limits

Every diagrams_generate_sequence run observes these caps. max_participants (1–20, default 8) bounds the declared participants and max_messages (1–50, default 20) bounds the emitted messages; the limits below are the hard ceilings:

Limit

Value

How you see it

Declared participants

20 participants

participants_available reports the total found and participants_capped is true when any were dropped; participant_limit reports the applied cap

Emitted messages

50 messages

messages_available reports the total found and messages_capped is true when any were dropped by the cap or by a participant the cap removed — a message is never sent to a box the diagram does not declare; message_limit reports the applied cap

Deferred call sites

Counted, never sequenced

deferred_count reports how many calls sit inside a callback, promise, or listener; they are excluded from messages because their runtime position is unknowable from source

Unresolved callees

Reported, never guessed

unresolved_callees lists callees no participant in the scope declares, instead of inventing a participant for them

Files scanned

5,000 source files

the result reports truncated, scan_limit, files_scanned, and scan_warning so a capped scan is never mistaken for a complete one — when truncated is true, generated messages may be incomplete

Per-file size

1,000,000 bytes

larger files (usually generated bundles) are skipped

Concurrent file reads

32

bounds open handles while the scan runs

When the TypeScript compiler is not installed (published installs have no typescript dependency), the tool degrades the same open way instead of failing: declared operations and call edges still come from the heuristic extractors, so participants and messages are still emitted.

Diff scope

diagrams_diff reports, and never silently drops a change — but it deliberately compares less than a differencing tool can:

Compared

Not compared

Declared class/interface/enum/component names, aliases, namespaces, participants, and message calls

Member lists, attributes, and method signatures

Added, removed, and renamed names (renames paired by the shared name normalizer)

Layout, position, ordering, styling, and theme

Sequence participants and message calls, per dialect

Cross-file or cross-diagram references and resolved types

The tool has no caps of its own: both sides are already bounded by the two sources being compared, so every added, removed, and renamed name is reported in full. It reads nothing outside the diagrams root, and input-shape errors (a side given both or neither of its path and content, or inline content in no recognized dialect) are reported before any file is opened.

Template limits

Every diagrams_template call observes these caps. There is no max_* argument to raise or lower — a skeleton is fixed scaffolding, so the ceilings below are the only shape it comes in:

Limit

Value

How you see it

Entities per skeleton

20 names (1–20)

entities_included reports the count actually emitted, in the order given

Entity name length

60 characters

each name is emitted bare as a class, participant, or C4 alias, so this is the length that has to stay a legal identifier

Title length

200 characters

a longer title is rejected rather than truncated; whitespace-only is rejected rather than emitting an empty title line

Template kinds

3 (class, sequence, c4_context)

the set is fixed in source, so a fourth kind is a schema change, not a value to pass in

Every name must match /^[A-Za-z_][A-Za-z0-9_]*$/ and no two may repeat — a duplicate would emit two declarations of the same box, so the second occurrence is rejected at its own index. A rejection comes back with isError: true and names the offending input; the emitted source always passes the same syntax gate diagrams_create applies, so a skeleton can be saved as-is.

Export limits

Every diagrams_export run observes this cap on the finished HTML document:

Limit

Value

How you see it

Bundle size

5,000,000 bytes

a larger bundle is refused with isError: true naming the diagram and the ceiling; truncated is always false, so no partial file is ever returned or saved

The SVG inside the bundle is bounded by what the renderer produced, and the renderer's own limits still apply on the way there. include_source is a boolean, not a size argument: the source block is either embedded in full or omitted, because a cut-off source next to a complete diagram would mislead a reader.

Example

diagrams/
└── models/
    └── user-class.puml

Ask your agent:

"Is the user-class diagram still accurate compared to the code?"

The agent calls diagrams_check_consistency, which reports:

1 of 2 entities in 'models/user-class.puml' were NOT found in the codebase:
- Order: 'Order' appears in the diagram but no matching identifier was
  found in the scanned codebase. It may be renamed, removed, or not yet
  implemented.

Project layout

src/
├── index.ts                       # Server entry point (stdio transport)
├── context.ts                     # Resolves PROJECT_ROOT / DIAGRAMS_DIR once at startup
├── constants.ts                   # Shared constants
├── types.ts                       # Shared TypeScript types
├── setup/                         # Guided client-setup wizard (scopes, pre-flight checks)
│   ├── index.ts                   # runSetup orchestrator
│   ├── clients.ts                 # Supported clients, arg parsing, config writers
│   ├── prompts.ts                 # Interactive pickers and confirmations
│   └── terminal.ts                # Banner, boxes, color
├── services/
│   ├── diagramStore.ts            # Safe filesystem CRUD (path-traversal protected)
│   ├── diagramValidator.ts        # PlantUML/Mermaid syntax checks and dialect detection
│   ├── nameNormalize.ts           # Shared lenient name normalizer (checker + diff)
│   ├── renderer.ts                # Mermaid/PlantUML -> SVG/PNG rendering
│   ├── scopeResolve.ts            # Bounds read-only tool scopes to PROJECT_ROOT
│   ├── consistencyChecker/        # Diagram <-> code drift detection
│   │   ├── index.ts               # checkConsistency orchestration (scan, match, report)
│   │   ├── entities.ts            # Entity names from diagram source
│   │   ├── codeAnalysis.ts        # Per-language declaration patterns
│   │   ├── scanning.ts            # Filesystem walk with scan limits
│   │   ├── sequence/              # Call-graph edges, participant mapping, message ordering
│   │   │   ├── callGraph.ts / operationIndex.ts / participantMapping.ts
│   │   │   ├── sequenceEntities.ts / sequenceMatch.ts / sequenceOrder.ts
│   │   │   └── sequenceGoldens.test.ts / sequenceOrderGoldens.test.ts
│   │   └── ts/                    # Optional TypeScript AST path (dynamic import only — never a static import, so published installs run without the compiler)
│   │       ├── tsParse.ts         # Compiler availability probe
│   │       ├── tsSymbols.ts       # Declared symbols + heritage collection
│   │       ├── tsIndex.ts / tsHeritage.ts  # Index and extends/implements edges
│   ├── diff/                      # diagrams_diff comparison
│   │   └── diffDiagram.ts         # Pure added/removed/renamed + sequence fields
│   ├── export/                    # diagrams_export bundle builder (pure, no filesystem)
│   │   ├── htmlBundle.ts          # One self-contained HTML string from SVG + source
│   │   └── exportGoldens.test.ts  # Exact wrapper structure locked per variant
│   ├── generate/                  # diagrams_generate entity collection and emitters
│   │   ├── collectEntities.ts     # Scan a scope into ordered entities + relations
│   │   ├── emitters.ts            # Pure PlantUML/Mermaid class-diagram emitters
│   │   ├── sequence.ts            # diagrams_generate_sequence orchestration (participants, messages, caps)
│   │   ├── sequenceEmitters.ts    # Pure PlantUML/Mermaid sequence emitters
│   │   └── scopeFiles.ts          # Scope walking shared by both generators
│   └── templates/                 # diagrams_template skeleton tables (no filesystem, no state)
│       ├── skeletons.ts           # Six pure emitters: kind x dialect
│       └── templateGoldens.test.ts # Exact emitted source per (template, format)
├── tools/                         # One MCP tool adapter per file (12 tools) + shared toolError/toolOutput
└── integration/
    └── mcpServer.test.ts          # End-to-end server surface tests

Tests live next to the source they cover (*.test.ts), compile to dist/, and run from there — npm test uses the file list in package.json, so new test files need adding there.

Security notes

  • All file operations are restricted to the configured diagrams directory; attempts to read/write outside it (e.g. via ../..) are rejected. Windows-style \ separators work as path separators on every platform, so ..\.. traversal is rejected on Linux too.

  • diagrams_check_consistency, diagrams_generate, and diagrams_generate_sequence only read your codebase — they never modify code or diagrams. Both generators resolve their scope against PROJECT_ROOT and refuse (without reading anything) any path that would land outside it; their output is source text you save yourself with diagrams_create.

  • diagrams_diff is read-only too: stored sides are read through the same traversal-protected store as diagrams_get, inline sides never touch the filesystem at all, and input-shape errors are reported before any file is opened. Errors and logs never include diagram source, only the names being reported.

  • diagrams_template touches no filesystem at all — no project root, no diagrams directory, no state between calls. It is pure source text in and out, so there is nothing to restrict and nothing to leak; the entity names you pass are the only thing it echoes back.

  • diagrams_export reads one diagram through the same traversal-protected store as diagrams_get and returns the bundle as text — it writes nothing, so the store's extension allow-list never opens to .html. The artifact is built to be shared: it contains no external resource of any kind (no src/href URLs, no @import, no script, no font), and the only path it carries is the diagram's POSIX relative_path. Remote PlantUML rendering, when you opt into it, sends diagram source to the configured server; that is the renderer's existing path, unchanged.

  • No credentials or external accounts are required for any tool. diagrams_render for PlantUML never leaves the machine unless remote rendering is explicitly enabled with ALLOW_REMOTE_PLANTUML=true — and never when DISABLE_REMOTE_PLANTUML=true is set, which takes precedence. Mermaid rendering never leaves the machine.

  • Local renderer processes run with a timeout and bounded stdout/stderr capture (1,000,000 characters per stream, enforced while collecting). A renderer that exceeds the cap or its timeout budget is stopped: its output pipes are closed and the process is killed, and rendering fails with an actionable error that never includes captured output, paths, or environment values. On timeout, the error is delivered immediately rather than waiting for a descendant process that inherited the renderer's output pipes (for example through the Windows cmd.exe shim chain) to release them.

Roadmap

Shipped in v0.7.0 (see RELEASE_NOTES.md):

  • TypeScript AST path for consistency checking — stricter matching plus extends/implements edges when the compiler is available, open heuristic fallback when it is not

  • Sequence diagrams both ways: diagrams_generate_sequence drafts them from call-graph edges, and the checker compares message ordering (callbacks deferred, never sequenced)

  • Diagram diffing (diagrams_diff), starter skeletons (diagrams_template), and self-contained HTML export (diagrams_export)

Still open:

  • Code-from-diagram scaffolding: generate a class skeleton from a diagram (the reverse of diagrams_generate)

  • AST-backed precision for more languages, as demand dictates

  • Export hardening follow-up: allowlist SVG sanitizer for bundled markup (tracked in docs/next-features.md)

Contributions and issues welcome.

License

MIT — see LICENSE.

Available Tools

7 tools
diagrams_check_consistencyCheck Diagram-to-Code ConsistencyA
Read-onlyIdempotent

Compare class/interface/component names mentioned in a PlantUML or Mermaid diagram against identifiers that actually exist in the codebase, to catch documentation drift.

This is a heuristic, text-based check (not a full semantic/AST analysis): it extracts entity names from class/interface/enum/component declarations in the diagram, then searches source files under the project root for a matching identifier as a whole word. It flags names that appear in the diagram but were not found anywhere in the scanned code — a signal the diagram may be outdated, or the code was renamed/removed/not yet built.

This tool does NOT modify the diagram or the code. It only reports findings; the caller (agent or human) decides what to do about them.

Args:

  • relative_path (string): Path to the diagram to check, relative to the diagrams root

Returns: JSON with schema: { "diagram_path": string, "entities_found": number, // total entity names extracted from the diagram "entities_matched": number, // how many were found somewhere in the code "entities_unmatched": number, // how many were NOT found (potential drift) "files_scanned": number, // how many source files were searched "searched_directory": string, // absolute path of the code root that was scanned "truncated": boolean, // true when the 5,000-file scan cap was reached; unmatched results may be incomplete "scan_limit": number, // maximum source files collected during the scan "scan_warning": string | null, // human-readable warning when truncated, otherwise null "entities": string[], // extracted entity names, in extraction order "matched_entities": string[], // extracted entities found in the code "unmatched_entities": string[],// extracted entities NOT found (potential drift) "analyzers": { // scanned file extensions per analyzer tier "reliable": string[], // per-language declaration patterns (JS/TS, Python, PHP, Java) "experimental": string[], // generic heuristic path (C#, Go, Ruby, Kotlin, Rust) "generic": string[] // other scanned extensions, heuristic path only }, "confidence": "heuristic", // results are evidence, never a definitive verdict "heuristic_warning": string, // human-readable limits of the heuristic "evidence": [ // per-entity evidence, same order as "entities" { "name": string, "matched": boolean, "analyzers": ("reliable" | "experimental" | "generic")[], "matched_files": string[], // POSIX paths relative to searched_directory (capped) "matched_file_count": number } ], "issues": [ { "name": string, // the unmatched entity name "issue": string, // human-readable explanation "severity": "warning" | "info" } ] }

Examples:

  • Use when: "Is this class diagram still accurate compared to the code?" -> relative_path="models/user-class.puml"

  • Use when: Reviewing a PR that touches architecture, to check the UML docs weren't left behind

  • Don't use when: The diagram has no class/interface/component declarations (e.g. a pure sequence diagram) — entities_found will be 0, which is expected, not an error

Error Handling:

  • Returns "Error: No diagram found at ''" if the diagram file doesn't exist

  • An empty "issues" array with entities_found=0 means no checkable entities were found in the diagram, not that everything matched

  • Unexpected internal failures return a generic "Error: Unexpected internal error ..." with isError:true and are logged to stderr without source, paths, or secrets

ParametersJSON Schema
NameRequiredDescriptionDefault
relative_pathYesPath to the diagram to check, relative to the diagrams root.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false; the description reinforces this by stating 'This tool does NOT modify the diagram or the code.' Beyond that, it discloses the heuristic, text-based nature, the 5,000-file scan cap, truncation behavior, confidence level, and the distinction between reliable/experimental/generic analyzers. This exceeds what annotations alone convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is lengthy, but it is well-structured with clear sections (overview, args, returns, examples, error handling) and front-loads the purpose and key non-modifying constraint. Every section adds value, though the inline return schema is verbose. Slightly overlong but organized enough to earn a 4.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description is exceptionally complete for a heuristic check tool: it covers the return schema in detail, error handling, edge cases (entities_found=0, truncation), and the confidence level. Despite having no output schema annotation, the description fully specifies the expected JSON structure and all relevant failure modes, leaving no ambiguity for an agent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the only parameter (relative_path) is already described as 'Path to the diagram to check, relative to the diagrams root.' The description adds example paths and clarifies the root relative interpretation, but these are marginal additions beyond the schema. The baseline of 3 applies since the schema carries the semantic load.

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 the tool compares entity names in diagrams against code identifiers to catch documentation drift. It names the specific resource (PlantUML/Mermaid diagrams vs codebase) and distinguishes itself from sibling tools like diagrams_get or diagrams_render by focusing on consistency checking, not creation, retrieval, or rendering.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit when-to-use scenarios ('Is this class diagram still accurate?', PR review) and a concrete don't-use condition (pure sequence diagram with no declarations, where entities_found=0 is expected). Also clarifies that an empty issues array with entities_found=0 means no checkable entities, not a pass, preventing misinterpretation.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

diagrams_createCreate New DiagramA

Create a new PlantUML or Mermaid diagram file under the diagrams root.

The diagram type is inferred from the file extension in relative_path:

  • .puml or .plantuml -> PlantUML

  • .mmd or .mermaid -> Mermaid

This tool refuses to overwrite an existing file — use diagrams_update for that. Intermediate directories in relative_path are created automatically.

Performs a basic, dependency-free syntax check before writing (not full validation): PlantUML must include @startuml/@enduml boundaries; Mermaid must start with a known diagram declaration. Clearly invalid or empty sources are rejected without creating a file.

Args:

  • relative_path (string): Path for the new file, relative to the diagrams root, with a recognized extension

  • content (string): Full diagram source text

Returns: JSON with schema: { "relative_path": string, "created": true }

Examples:

  • Use when: "Create a class diagram for the User model" -> relative_path="models/user-class.puml", content="@startuml\nclass User {\n +id: int\n}\n@enduml"

  • Don't use when: The file already exists and you want to change it (use diagrams_update instead)

Error Handling:

  • Returns "Error: ... already exists" if a file already exists at relative_path

  • Returns "Error: ... does not have a recognized diagram extension" if the extension isn't one of .puml/.plantuml/.mmd/.mermaid

  • Returns "Error: Invalid PlantUML diagram (basic check): ..." if PlantUML source is empty or missing @startuml/@enduml boundaries

  • Returns "Error: Invalid Mermaid diagram (basic check): ..." if Mermaid source is empty or has no recognized diagram declaration

  • Returns "Error: Refused to access path outside the diagrams root" if relative_path attempts to escape the diagrams directory

  • Unexpected internal failures return a generic "Error: Unexpected internal error ..." with isError:true and are logged to stderr without source, paths, or secrets

ParametersJSON Schema
NameRequiredDescriptionDefault
contentYesFull PlantUML or Mermaid source text for the diagram.
relative_pathYesPath for the new diagram, relative to the diagrams root, including extension (.puml, .plantuml, .mmd, or .mermaid). E.g. 'system/order-flow.puml'.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only indicate non-readOnly, non-idempotent, non-destructive behavior. The description goes far beyond this by disclosing that it refuses to overwrite, creates intermediate directories automatically, performs a basic non-validating syntax check, rejects invalid/empty sources without creating files, prevents path escape, and logs unexpected errors safely without leaking secrets.

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 well structured: purpose first, then extension rules, overwrite policy, validation behavior, arg definitions, return shape, examples, and error handling. It is long but every section earns its place and the most decision-relevant information is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a creation tool with no output schema, the description fully compensates by specifying the exact return JSON structure, listing all expected error messages, and providing concrete usage examples. An agent has everything needed to invoke it correctly and anticipate failure modes.

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?

The input schema already describes both parameters fully (100% coverage). The description adds value by clarifying the extension-to-type mapping, the meaning of a recognized extension, automatic creation of intermediate directories, and the syntax-check behavior, which give the agent practical context for constructing valid parameter values.

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 states a specific verb ('Create'), a specific resource ('PlantUML or Mermaid diagram file under the diagrams root'), and the inference rule from the file extension. It clearly distinguishes this tool from diagrams_update by explicitly saying it refuses to overwrite existing files.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit usage context: use for creating new diagrams, and explicitly says not to use it when the file exists and needs changing, naming diagrams_update as the alternative. The included examples of when and when not to use it make the decision easy for an agent.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

diagrams_deleteDelete DiagramA
Destructive

Delete a single PlantUML or Mermaid diagram file from the diagrams root.

This is destructive and cannot be undone — the file is removed from disk. To replace content instead, use diagrams_update. To remove then recreate with different content, delete first, then use diagrams_create.

Args:

  • relative_path (string): Path to the diagram relative to the diagrams root, as returned by diagrams_list

Returns: JSON with schema: { "relative_path": string, "deleted": true }

Examples:

  • Use when: "Remove the outdated order-flow diagram" -> relative_path="system/order-flow.puml"

  • Don't use when: You want to change the diagram content but keep the file (use diagrams_update)

Error Handling:

  • Returns "Error: No diagram found at ''" if the file doesn't exist

  • Returns "Error: Refused to access path outside the diagrams root" if relative_path attempts to escape the diagrams directory (e.g. via '../..')

  • Unexpected internal failures return a generic "Error: Unexpected internal error ..." with isError:true and are logged to stderr without source, paths, or secrets

ParametersJSON Schema
NameRequiredDescriptionDefault
relative_pathYesPath to the diagram to delete, relative to the diagrams root (e.g. 'system/order-flow.puml'). Get this from diagrams_list.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the destructiveHint=true annotation, the description discloses that deletion is physical and irreversible ('file is removed from disk'), details error responses for missing files and path traversal attempts ('Refused to access path outside the diagrams root'), and clarifies how internal failures are logged without leaking sensitive data. This is rich behavioral context that annotations alone do not provide.

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 longer than average, but every section earns its place: purpose, destructiveness warning, alternatives, args, return shape, examples, and error handling. The most critical facts (destructive, irreversible) are front-loaded, and the structured sections make the content easy for an agent to parse.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive one-parameter tool with no structured output schema, the description is fully complete. It includes the return JSON shape, all relevant error cases, path safety constraints, and sibling-tool alternatives, so an agent has everything needed to invoke it correctly and predict consequences.

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?

Schema coverage is 100%, so the baseline is 3; the description's Args section largely repeats the schema. However, the error-handling section and examples add meaning beyond the schema by clarifying that paths must come from diagrams_list and that escaping the diagrams root is refused, giving the agent a better model of valid and invalid inputs.

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 opens with a specific verb and resource: 'Delete a single PlantUML or Mermaid diagram file from the diagrams root.' It clearly distinguishes the tool from siblings by explicitly naming diagrams_update and diagrams_create as alternatives for different goals, so an agent can select it correctly without opening schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit when-to-use and when-not-to-use guidance: replace content -> use diagrams_update; remove and recreate -> delete then create. It also provides concrete examples ('Remove the outdated order-flow diagram') and a 'Don't use when' clause, making the decision boundary unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

diagrams_getGet Diagram SourceA
Read-onlyIdempotent

Retrieve the raw source text of a single PlantUML or Mermaid diagram, in full or as an explicit character window.

Args:

  • relative_path (string): Path to the diagram relative to the diagrams root, as returned by diagrams_list

  • offset (number, optional): Zero-based character offset where the returned window starts (default: 0)

  • max_chars (number, optional): Maximum characters to return from offset (1-100000). Omit to return the full source

Returns: JSON with schema: { "relative_path": string, "type": "plantuml" | "mermaid", "content": string, // full source, or the requested [offset, offset+max_chars) window "is_partial": boolean, // true when content is a window rather than the full source "offset": number, // effective character offset of this window "total_chars": number, // full source length in characters "returned_chars": number,// length of the returned content "has_more": boolean // true when source after this window remains }

The text block always equals structuredContent.content. Content is never silently truncated: omitting offset/max_chars returns everything, and requesting a window is always reported via is_partial/has_more.

Examples:

  • Use when: "Show me the order-flow diagram" -> relative_path="system/order-flow.puml"

  • Use when: "Read the first 2000 characters of the big diagram" -> relative_path="...", offset=0, max_chars=2000, then offset=2000 for the next window

  • Don't use when: You need to list what diagrams exist first (use diagrams_list)

Error Handling:

  • Returns "Error: No diagram found at ''" if the file doesn't exist

  • Returns "Error: Refused to access path outside the diagrams root" if relative_path attempts to escape the diagrams directory (e.g. via '../..')

  • Returns "Error: Invalid source window: ..." if offset/max_chars are negative, non-integer, or max_chars is outside 1-100000

  • Returns "Error: offset is out of range ..." if offset points past the end of the source

  • Unexpected internal failures return a generic "Error: Unexpected internal error ..." with isError:true and are logged to stderr without source, paths, or secrets

ParametersJSON Schema
NameRequiredDescriptionDefault
offsetNoZero-based character offset into the diagram source where the returned window starts (default: 0).
max_charsNoMaximum characters to return starting at offset (1-100000). Omit to return the full source.
relative_pathYesPath to the diagram, relative to the diagrams root (e.g. 'system/order-flow.puml'). Get this from diagrams_list.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, destructiveHint=false. The description adds substantial behavioral detail beyond this: it explains the windowing behavior with is_partial/has_more flags, guarantees no silent truncation, and provides a comprehensive error-handling list (file not found, path escape, invalid window, out-of-range offset). This far exceeds annotation coverage and fully discloses behavior.

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?

While long, the description is modularly structured with clear sections (Args, Returns, Examples, Error Handling) and front-loads the core purpose. Every sentence serves a purpose—there is no fluff or repetition. The length is justified by the tool's windowing and error complexity, and the structure makes it easy to scan.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite lacking an output schema, the description provides a full inline JSON return schema with all fields explained. It covers error cases, examples, and parameter usage. For a tool with this complexity (character windows, partial returns), the description leaves nothing an agent needs to call it correctly; it is complete.

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?

Schema description coverage is 100%, so the baseline is 3. The description reinforces each parameter and adds usage nuance: it explains that omitting offset/max_chars returns the full source, demonstrates a windowing example (offset=0, max_chars=2000, then offset=2000), and clarifies the zero-based offset. This goes beyond the schema's basic type/range descriptions, though it does not introduce entirely new semantics.

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 opens with a precise verb+resource statement: 'Retrieve the raw source text of a single PlantUML or Mermaid diagram, in full or as an explicit character window.' It clearly distinguishes itself from siblings, explicitly noting the alternative diagrams_list for listing diagrams. No ambiguity about what this tool does.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The Examples section explicitly states 'Use when' scenarios (e.g., 'Show me the order-flow diagram') and 'Don't use when' (e.g., when needing to list diagrams first, use diagrams_list). It also instructs that relative_path should come from diagrams_list, giving clear routing to the correct sibling.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

diagrams_listList Architecture DiagramsA
Read-onlyIdempotent

List all PlantUML and Mermaid diagram files stored under the project's diagrams directory.

This tool scans the configured diagrams root recursively and returns every file with a recognized diagram extension (.puml, .plantuml, .mmd, .mermaid). It does NOT create, modify, or render diagrams — read-only.

Args:

  • type_filter ('plantuml' | 'mermaid' | 'all'): Restrict results to one diagram type (default: 'all')

  • offset (number, optional): Zero-based number of matching diagrams to skip (default: 0)

  • limit (number, optional): Maximum diagrams to return (1-500). Omit to return every remaining match

Returns: JSON with schema: { "diagrams_root": string, // absolute path being scanned "count": number, // number of diagrams in this page "total": number, // number of diagrams matching type_filter, before paging "offset": number, // effective offset of this page "limit": number, // effective limit of this page (requested limit, or remaining count when omitted) "has_more": boolean, // true when diagrams after this page remain "diagrams": [ { "relative_path": string, // path to use with diagrams_get / diagrams_update "type": "plantuml" | "mermaid", "title": string | null, // best-effort extracted title "size_bytes": number, "modified_at": string // ISO 8601 timestamp } ] }

Pagination is explicit: omitting offset/limit returns every match with has_more=false. Nothing is ever silently dropped — has_more tells the caller when to request the next page with offset=<offset+count>.

Examples:

  • Use when: "What diagrams exist for this project?" -> type_filter="all"

  • Use when: "Show me all the Mermaid diagrams" -> type_filter="mermaid"

  • Use when: "List diagrams ten at a time" -> limit=10, then offset=10 for the next page

  • Don't use when: You already know the exact path and just need its content (use diagrams_get instead)

Error Handling:

  • Returns an empty "diagrams" array if the diagrams directory doesn't exist yet or is empty (this is not an error)

  • Returns an empty page (count 0, has_more=false) when offset is past the end of the matches

  • Returns "Error: Invalid pagination: ..." if offset is negative/non-integer or limit is outside 1-500

  • Unexpected internal failures return a generic "Error: Unexpected internal error ..." with isError:true and are logged to stderr without source, paths, or secrets

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum number of diagrams to return (1-500). Omit to return every remaining match.
offsetNoZero-based number of matching diagrams to skip before the returned page (default: 0).
type_filterNoRestrict results to a single diagram type, or 'all' for both.all

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already indicate readOnly, idempotent, and non-destructive behavior, and the description adds substantial context: recursive scanning, no create/modify/render side effects, explicit pagination semantics, empty-directory behavior, out-of-range offset behavior, and error message shapes. There is no contradiction with the annotations.

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 long but well-structured and front-loaded with the core purpose. Every section (args, return schema, pagination, examples, error handling) earns its place since there is no output schema or separate documentation to carry that information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description fully specifies the return JSON structure, pagination flags, field meanings, and error behavior. It also covers the main sibling-tool distinction and edge cases like empty directories and invalid offsets, making it complete for an agent to invoke 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?

The input schema has 100% description coverage, so the baseline is 3. The description adds value beyond the schema by explaining the pagination contract (has_more, offset=offset+count, nothing silently dropped) and giving concrete examples for using limit and offset together. It somewhat restates the schema defaults, which prevents a higher score.

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 names a specific verb and resource: it scans the diagrams directory and lists PlantUML/Mermaid files. It also explicitly differentiates itself from siblings by stating it does NOT create, modify, or render diagrams, and by referring to diagrams_get when the exact path is already known.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives concrete 'Use when' examples for all filters and pagination scenarios, and a 'Don't use when' case naming diagrams_get as the alternative. This is explicit routing guidance that leaves no ambiguity about when to select this tool over siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

diagrams_renderRender Diagram to ImageA
Read-onlyIdempotent

Render a PlantUML or Mermaid diagram to an image (SVG or PNG) and return it as base64-encoded image content.

Rendering requirements:

  • Mermaid: requires the 'mmdc' CLI (install with: npm install -g @mermaid-js/mermaid-cli). No fallback exists.

  • PlantUML: uses a local 'plantuml' CLI if installed. Without one, rendering fails unless remote rendering is explicitly enabled with ALLOW_REMOTE_PLANTUML=true, in which case it falls back to the configured PlantUML rendering server over HTTPS (requires internet access; sends diagram source to that server). DISABLE_REMOTE_PLANTUML=true always disables the fallback, even when the allow flag is set.

Args:

  • relative_path (string): Path to the diagram, relative to the diagrams root

  • format ('svg' | 'png'): Output image format (default: 'svg')

Returns: An image content block (base64-encoded), plus a JSON summary: { "relative_path": string, "format": "svg" | "png", "rendered": true }

Examples:

  • Use when: "Show me what the order-flow diagram looks like" -> relative_path="system/order-flow.puml", format="svg"

  • Don't use when: You just need the raw source text (use diagrams_get instead, it's much cheaper)

Error Handling:

  • Returns "Error: No diagram found at ''" if the file doesn't exist

  • Returns "Error: Mermaid rendering requires the 'mmdc' CLI..." if rendering a Mermaid diagram without mmdc installed

  • Returns "Error: PlantUML rendering requires a local 'plantuml' CLI..." when no local CLI is installed and remote rendering is not explicitly enabled (set ALLOW_REMOTE_PLANTUML=true to opt in)

  • Returns "Error: PlantUML rendering server responded with ..." if both local and remote PlantUML rendering fail

  • Unexpected internal failures return a generic "Error: Unexpected internal error ..." with isError:true and are logged to stderr without source, paths, or secrets

ParametersJSON Schema
NameRequiredDescriptionDefault
formatNoOutput image format (default: 'svg').svg
relative_pathYesPath to the diagram to render, relative to the diagrams root.

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, destructiveHint=false. The description adds extensive behavioral context beyond these: exact rendering dependencies, remote fallback conditions with environment flags (ALLOW_REMOTE_PLANTUML, DISABLE_REMOTE_PLANTUML), detailed error messages, and a security note about logging without source/paths/secrets. This is rich, non-redundant transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is longer than average, but every section (rendering requirements, args, returns, examples, error handling) carries necessary information for a tool with complex dependencies and failure modes. It is well-structured with headings and front-loaded purpose. A small amount of redundancy exists (error messages are verbose), but overall it is efficient.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a rendering tool with two distinct renderers, fallback behaviors, and CLI dependencies, this description leaves nothing unstated. It covers prerequisites, flags, error cases, output format (base64 + JSON summary), and security/privacy concerns. Without an output schema, the description fully compensates by explaining the return structure. 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?

Schema coverage is 100% and both parameters already have clear descriptions. The description reinforces relative_path's meaning (relative to diagrams root) and format's default, but more importantly adds example parameter values ('system/order-flow.puml', 'svg') that disambiguate real usage. It slightly exceeds the baseline by providing usage examples.

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 opens with a specific verb-resource pair: 'Render a PlantUML or Mermaid diagram to an image (SVG or PNG)' and clarifies the output is base64 content. It clearly distinguishes from siblings by stating when not to use it (use diagrams_get for raw source), which is explicit sibling differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides concrete when-to-use ('Show me what the order-flow diagram looks like') and when-not-to-use conditions (raw source -> use diagrams_get). Additionally details prerequisites (mmdc CLI, plantuml CLI), fallback flags, and even names the preferred alternative (diagrams_get) – no ambiguity left.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

diagrams_updateUpdate Existing DiagramA
DestructiveIdempotent

Replace the full content of an existing PlantUML or Mermaid diagram file.

This performs a full-content replace, not a partial edit — pass the complete new diagram source. To create a new diagram, use diagrams_create (or set create_if_missing=true here).

Performs a basic, dependency-free syntax check before writing (not full validation): PlantUML must include @startuml/@enduml boundaries; Mermaid must start with a known diagram declaration. Clearly invalid or empty sources are rejected without overwriting the existing file.

Args:

  • relative_path (string): Path to the diagram, relative to the diagrams root

  • content (string): Full new diagram source text

  • create_if_missing (boolean): Create the file instead of erroring if it doesn't exist (default: false)

Returns: JSON with schema: { "relative_path": string, "updated": true }

Examples:

  • Use when: "Add a new field to the User class diagram" -> read current content with diagrams_get first, then call diagrams_update with the modified full content

  • Don't use when: The file doesn't exist yet and you don't want auto-creation (use diagrams_create)

Error Handling:

  • Returns "Error: No diagram found at ''" if the file doesn't exist and create_if_missing is false

  • Returns "Error: ... does not have a recognized diagram extension" if the extension isn't recognized

  • Returns "Error: Invalid PlantUML diagram (basic check): ..." if PlantUML source is empty or missing @startuml/@enduml boundaries (original file left unchanged)

  • Returns "Error: Invalid Mermaid diagram (basic check): ..." if Mermaid source is empty or has no recognized diagram declaration (original file left unchanged)

  • Returns "Error: Refused to access path outside the diagrams root" if relative_path attempts to escape the diagrams directory

  • Unexpected internal failures return a generic "Error: Unexpected internal error ..." with isError:true and are logged to stderr without source, paths, or secrets

ParametersJSON Schema
NameRequiredDescriptionDefault
contentYesNew full PlantUML or Mermaid source text that replaces the existing content.
relative_pathYesPath to the existing diagram, relative to the diagrams root.
create_if_missingNoIf true and no diagram exists at relative_path, create it instead of failing (default: false).

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds substantial behavior beyond the annotations: it discloses the pre-write syntax check, clarifies it is not full validation, states rejection conditions, and assures the original file is left unchanged on invalid input. This complements destructiveHint=true and idempotentHint=true without contradicting them.

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 long but well-structured with labeled sections, and the core behavior is front-loaded in the first paragraph. Every sentence serves a purpose, including the detailed error-handling list, which is practically useful for agents.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with no output schema, the description is complete: it specifies the return shape, error cases, validation behavior, file-overwrite semantics, and sibling alternatives. An agent has enough information to invoke the tool correctly and anticipate failures.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3 even though the description mostly restates the parameter meanings. It does add mild context (e.g., 'pass the complete new diagram source' and create_if_missing behavior), but it does not uncover anything fundamentally beyond the schema.

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 states a specific verb ('Replace') and resource ('existing PlantUML or Mermaid diagram file'), and explicitly clarifies it is a full-content replace rather than a partial edit. It differentiates itself from diagrams_create by naming the sibling tool and the create_if_missing alternative.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage guidance is explicit: it says when to use this tool, when not to, and names alternatives. The 'Use when' and 'Don't use when' examples directly instruct agents to read current content with diagrams_get first and to prefer diagrams_create for new files unless auto-creation is desired.

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. 7 tool updatesv0.1.0
    • First observeddiagrams_check_consistency
    • First observeddiagrams_create
    • First observeddiagrams_delete
    • First observeddiagrams_get
    • First observeddiagrams_list
    • First observeddiagrams_render
    • First observeddiagrams_update

TDQS

A4.8/5.0

Scored across 7 tools

Disambiguation5/5

Each tool has a distinct action: list, create, get, update, delete, check consistency, and render. There is no overlap or ambiguity in their purposes; agents can easily select the correct tool.

Naming Consistency5/5

All tools follow a consistent diagrams_<verb> pattern (diagrams_list, diagrams_create, diagrams_get, etc.). The naming is uniform and predictable, making it easy to infer functionality from the name.

Tool Count5/5

With 7 tools, the set is well-scoped for a diagram management server: CRUD operations plus a consistency check and rendering. Each tool serves a necessary function without redundancy.

Completeness5/5

The toolset provides complete lifecycle coverage: list, create, read, update, delete, plus useful extras like consistency checking and rendering. There are no obvious gaps for the stated domain of managing PlantUML/Mermaid diagrams.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables generating cloud architecture diagrams, flowcharts, sequence diagrams, and more using three rendering engines: mingrammer/diagrams, Mermaid, and PlantUML.
    3
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI agents to read, modify, and build from architecture models, keeping the model as the source of truth for intent and synchronized with code.
    38 npm
    115
    BSD 3-Clause
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables LLMs to draw interactive diagrams (architecture, sequence, class) inside the editor, with clickable nodes that jump to source code.
    6
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI agents to create, read, update, and delete Draw.io diagrams, allowing automated generation of architectural diagrams, flowcharts, and visual documentation.
    72 npm
    MIT