langgraph-spec-toolkit
Use this MCP server to build and manage LangGraph projects by editing a structured YAML spec, with validation and deterministic Python code generation.
init_project: scaffold a new project with spec.yaml, nodes.py, and init.py, plus optional initial state fields.
add_node / add_edge: add or update nodes and simple/conditional edges; entry point is handled automatically.
remove_node / remove_edge: delete nodes and edges, with cascading cleanup for edges touching a removed node.
set_state_schema: replace the graph's state schema wholesale.
apply_changes: batch multiple mutating operations atomically in one round trip.
get_spec: fetch the full current spec read-only.
validate_graph: check for unreachable nodes, missing paths to END, dangling conditions, duplicate/typo'd ids, and unsafe identifiers.
render_python: deterministically generate idiomatic LangGraph graph.py from the spec, blocking on validation errors.
Enables building LangGraph projects by editing a structured YAML spec, with tools for scaffolding projects, managing nodes, edges, and state schema, validating graph topology, and rendering deterministic Python code.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@langgraph-spec-toolkitInitialize a new LangGraph project and add a node named 'greet'."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
langgraph-spec-toolkit
An MCP server + Claude skill for building LangGraph projects by editing a structured YAML spec — not by regenerating Python from scratch on every turn.
edit spec.yaml (via MCP tools) → validate_graph → render_python → graph.pyGraph topology — nodes, edges, state schema, checkpointer — is data, not
prose. An LLM agent should be able to add a node or rewire an edge with one
small, targeted tool call, not re-emit 150 lines of Python and hope nothing
upstream broke. spec.yaml is the source of truth; graph.py is a
deterministic, regenerable build artifact you never hand-edit.
Quick look

Four tool calls, zero hand-written Python for the graph wiring itself.
(Regenerate with vhs .github/assets/demo.tape — see that file for a
vhs 0.12.0 bug you may need to work around.)
$ uv run python .github/assets/demo.py
1) init_project - scaffold spec.yaml, nodes.py
2) apply_changes - nodes + edges wired in one round trip
3) validate_graph - catch problems before any code is emitted
ok=True issues=0
4) render_python - deterministic codegen, no LLM involved
wrote demo_graph/graph.py
$ cat demo_graph/graph.py
"""Auto-generated by langgraph-spec-toolkit — DO NOT EDIT BY HAND.
Regenerate with the `render_python` MCP tool after changing spec.yaml.
Source spec: demo_graph
"""
from langgraph.graph import StateGraph, START, END
from typing import TypedDict
from . import nodes
class GraphState(TypedDict):
pass
def build_graph():
workflow = StateGraph(GraphState)
workflow.add_node('greet', nodes.greet)
workflow.add_node('respond', nodes.respond)
workflow.add_edge(START, 'greet')
workflow.add_edge('greet', 'respond')
workflow.add_edge('respond', END)
return workflow.compile()Related MCP server: Oplink
Table of contents
Why
Real-world cost. Measured on a real Claude Code session's
/costoutput (not a synthetic estimate), in a fresh session with no prior history: building a small 2-node graph from scratch cost $0.1267 hand-writinggraph.pydirectly, vs. $0.1291 through this toolkit's MCP tools (usingapply_changesto wire nodes/edges in one call) — roughly at parity for this small, from-scratch case, which is close to the toolkit's least favorable scenario since there's no existing complexity yet for hand-written regeneration to be expensive.Error rate. Free-form Python regeneration risks silently dropping an edge, mistyping a state key, or producing an unreachable node. A structured spec can be validated before any code is emitted.
Diffability.
spec.yamlchanges are small, reviewable diffs. A regenerated file's diff is often the whole file.
Installation
Requires Python 3.11+ and uv (which provides
uvx).
Via uvx (recommended — no clone, no local install; uvx fetches
langgraph-spec-toolkit
from PyPI and runs it on demand):
{
"mcpServers": {
"langgraph-spec-toolkit": {
"command": "uvx",
"args": ["langgraph-spec-toolkit"]
}
}
}From source (if you're developing on the toolkit itself):
git clone <this-repo>
cd langgraph-spec-toolkit
uv sync{
"mcpServers": {
"langgraph-spec-toolkit": {
"command": "uv",
"args": ["run", "--directory", "/path/to/langgraph-spec-toolkit", "python", "-m", "mcp_server.server"]
}
}
}Runtime dependencies are intentionally minimal: mcp, jinja2, pyyaml.
render_python's output imports langgraph (and langchain-core, if
your state uses message types) — those are dependencies of the project
you're generating, not of this toolkit.
Usage
Either config above starts the MCP server (it speaks MCP over stdio) the moment your client connects — there's no separate "run the server" step to do by hand. If you want to smoke-test it directly:
uv run python -m mcp_server.server # from a source checkout
uvx langgraph-spec-toolkit # from PyPIThen drive it through the tools below — or point Claude at skill/SKILL.md
and let it drive itself. A typical session:
init_project(project_dir="my_graph", name="my_graph")
apply_changes(project_dir="my_graph", operations=[
{"op": "add_node", "id": "start"},
{"op": "add_node", "id": "respond"},
{"op": "add_edge", "from_": "start", "to": "respond"},
{"op": "add_edge", "from_": "respond", "to": "END"},
])
validate_graph(project_dir="my_graph") # -> ok: true
render_python(project_dir="my_graph") # -> writes my_graph/graph.py...then write start/respond in my_graph/nodes.py and you have a
runnable graph.
The spec format
spec.yaml:
name: simple_chatbot
entry_point: greet
state:
- name: messages
type: list[BaseMessage]
reducer: add_messages
default: []
nodes:
- id: greet
type: python
config:
function: greet # callable in nodes.py; defaults to the node id
- id: chatbot
type: python
config:
function: chatbot
- id: tools
type: python
config:
function: call_tools
edges:
- from: greet
to: chatbot
- from: chatbot
condition: route_after_chatbot # router fn in nodes.py
paths:
continue: tools
end: END
- from: tools
to: chatbot
checkpointer:
type: none # none | memory | sqlite | postgresNode and router bodies are not generated — render_python only owns
topology, state, and wiring. You write the callables in the project's
nodes.py, named to match config.function / condition. This keeps
codegen deterministic: the same spec always renders to the same Python, and
business logic never gets silently rewritten on a regen.
type on a state field is a raw Python type expression. A handful of
common symbols — BaseMessage, AnyMessage, HumanMessage, AIMessage,
SystemMessage, ToolMessage, ChatMessage, plus Any / Optional /
Sequence / Union / Literal from typing — are recognized by name and
auto-imported in the rendered file. reducer similarly recognizes
add_messages and add / operator.add as built-ins; anything else is
assumed to be a function you define in reducers.py.
MCP tools
Tool | Purpose |
| Scaffold |
| Add/update a node. The first node added becomes |
| Add a simple ( |
| Remove a node; cascades to delete edges touching it. |
| Remove edge(s) from a source, optionally to one target. |
| Replace the state schema wholesale. |
| Apply several |
| Read-only fetch of the full current spec. |
| Run static checks; returns |
| Emit |
Note: edges use the parameter name
from_, notfrom— the latter is a reserved word in Python. It still round-trips through thefrom:key inspec.yaml.
Note: the mutating tools (
add_node,add_edge,remove_node,remove_edge,set_state_schema,apply_changes) return a compactsummary(node/edge/state counts, entry point, checkpointer type) rather than the full spec — echoing the whole graph back on every small edit would grow with graph size and quietly erode the token savings this toolkit exists for. Callget_specwhen you actually need the full picture.
Prefer
apply_changesover separate calls whenever wiring more than one node/edge at once (e.g. a whole tool-calling loop) — it's the same edit, one round trip instead of several. See Why for the measured real-world cost. Each operation is a dict with an"op"key plus that operation's normal arguments, e.g.{"op": "add_node", "id": "tools", "config": {...}}— see the tool's own description for the full list.entry_pointis set automatically (the first node added, orentry_point: trueon a lateradd_nodeop) — don't add an edge from"START"yourself, even though renderedgraph.pycontains one; that edge is derived fromentry_point, not wired as a spec edge.
Validation
validate_graph checks for:
Unreachable nodes — no path from
entry_point.Missing path to
END— a node that can never terminate the graph.Dangling conditions — a conditional edge with no
paths, or apathstarget that isn't a real node id (orEND).State/id typos — duplicate node ids, duplicate state field names, an
entry_pointthat doesn't match any node id, an unknown checkpointer type.Unsafe identifiers —
config.function, a conditional edge'scondition, a state field'sname, and a non-builtinreducerare all spliced into the generated Python unquoted (e.g.nodes.<function>), so each must be a valid Python identifier; a state field'stypemust at least parse as a Python expression. This is a correctness and safety check — it's the boundary that keeps a bad spec value from becoming arbitrary code ingraph.py.
render_python refuses to emit code while validation errors are present;
warnings (like an unreachable node) don't block rendering.
Example
examples/simple_chatbot has a spec with a
message-reducer state field, a linear edge, and a conditional tool-call
loop, plus the generated graph.py — diff the two to see exactly what
codegen does. It's been exercised end-to-end against a real langgraph +
langchain-core install to confirm the generated wiring executes, not just
that it parses.
Development
uv sync
uv run python -m mcp_server.server # smoke-test the server starts
uv run pytest # run the test suite
uv run ruff check . # lintThe test suite (tests/) covers spec.py (dataclasses, YAML round-trips),
validator/ (every check, including the identifier/injection-safety ones),
renderer/ (codegen against the committed example, plus each reducer/
checkpointer variant), every MCP tool's run() function, and MCP tool
registration itself. New tools or spec fields should come with tests in
the matching file.
CI (.github/workflows/ci.yml) runs lint and the test suite (on Python
3.11 and 3.12) on every push and pull request against main.
Releasing
Publishing to PyPI (.github/workflows/publish.yml) uses
Trusted Publishing — no API
token is stored in this repo. One-time setup (maintainers only):
On pypi.org, add a trusted publisher for this project: owner
mkrishna-gs, repolanggraph-spec-toolkit, workflowpublish.yml, environmentpypi. (If the project doesn't exist on PyPI yet, PyPI supports adding a trusted publisher for a not-yet-published project name — it claims the name on first publish.)In this repo's GitHub settings, create an environment named
pypi(optionally with required reviewers, for an extra manual gate before every publish).
After that, cutting a release is the whole process:
Bump
versioninpyproject.toml.Tag and push, then publish a GitHub Release from that tag (or use
gh release create).publish.ymlbuilds the sdist/wheel and publishes them automatically.
Contributing
Issues and pull requests are welcome — see
CONTRIBUTING.md for the project layout, dev setup, and
the checklist to run through before opening a PR.
License
Available Tools
10 toolsadd_edgeA
Add an edge between nodes.
Simple edge: set to (a node id, or "END").
Conditional edge: set condition (the name of a router function in
nodes.py) and paths (a mapping of the router's return value to a
target node id or "END").
| Name | Required | Description | Default |
|---|---|---|---|
| to | No | ||
| from_ | Yes | ||
| paths | No | ||
| condition | No | ||
| project_dir | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description must carry the full burden. It mentions conditions and paths but does not disclose what happens when invalid inputs are given, whether edges can overwrite existing ones, or any validation behavior. It also doesn't mention the return value or side effects.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and well-structured: an introductory sentence followed by bullet-like lines for each edge type. Every sentence adds value, and the most important information (how to specify each type) is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has an output schema, but the description doesn't mention what the tool returns, which might be important for agents. It also lacks behavioral details like validation or error handling. Given the complexity of conditional edges, the description covers the main usage but misses edge cases and side effects.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With schema description coverage at 0%, the description must compensate for all parameters. It does explain 'to', 'condition', and 'paths' in context (e.g., 'to' is a node id or END), but it does not explain 'project_dir' and 'from_' at all. The description adds value for some parameters but leaves others undocumented.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool adds an edge between nodes and distinguishes between simple and conditional edges, which is a specific verb and resource. However, it does not explicitly contrast with siblings like remove_edge, but the purpose is clear enough.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear guidance on when to use simple vs conditional edges, explaining the required parameters for each case. It does not explicitly mention alternatives, but the context is sufficient for an agent to decide which parameters to set.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
add_nodeB
Add or update a node. config['function'] names the callable in nodes.py (defaults to the node id if omitted).
The first node added to a project becomes the entry point automatically; pass entry_point=True to (re)designate a later node instead.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | ||
| type | No | python | |
| config | No | ||
| entry_point | No | ||
| project_dir | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden. It discloses two important behaviors: config['function'] defaults to node id, and the first node auto-becomes entry point. However, it does not disclose whether 'update' overwrites existing config, whether it validates the callable exists, or any side effects on edges.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loads the primary action, then explains the two non-obvious behaviors. Every sentence earns its place, though the entry-point rule could be more concise.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has an output schema and 5 parameters, but no annotations. The description covers the most subtle behaviors (config function resolution and entry point designation) but omits update semantics, error conditions, and relationship to project initialization. Adequate for basic use, incomplete for edge cases.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It explains config['function'] and entry_point semantics, but leaves id, type, and project_dir meanings to the schema. The description adds value for two of five parameters, which is partial compensation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a clear verb+resource ('Add or update a node') and explains the key config['function'] behavior, which distinguishes it from graph-structure tools like add_edge/remove_node. It doesn't explicitly contrast with siblings, but the resource and behavior are specific enough to be identifiable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage context: it is for adding/updating nodes, and the entry-point rule tells when to use entry_point=True. However, it does not explicitly state when to prefer alternatives like remove_node or validate_graph, nor does it mention prerequisites like project initialization.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
apply_changesA
Apply several spec edits in one call instead of one add_node/add_edge/... call each.
Prefer this over separate calls whenever wiring more than one node/edge at once (e.g. adding a whole tool-calling loop) — it's the same edit, one round trip instead of several.
operations is a list, applied in order against one loaded spec and
saved once at the end. Nothing is written if any operation is invalid
(bad op name, missing required field, dangling reference) — the whole
batch is atomic. Each entry is a dict with an "op" key plus that
operation's normal arguments:
{"op": "add_node", "id": "tools", "config": {"function": "call_tools"}} {"op": "add_edge", "from_": "chatbot", "condition": "route", "paths": {"continue": "tools", "end": "END"}} {"op": "add_edge", "from_": "tools", "to": "chatbot"} {"op": "remove_node", "id": "..."} {"op": "remove_edge", "from_": "...", "to": "..."} {"op": "set_state_schema", "fields": [...]}
entry_point is set automatically (the first node added, or pass entry_point=true on a later add_node op) — don't add an edge from "START" yourself, even though rendered graph.py contains one; that edge is derived from entry_point, not wired as a spec edge.
Returns a compact summary (counts), like the other mutating tools — call get_spec if you need the full picture afterward.
| Name | Required | Description | Default |
|---|---|---|---|
| operations | Yes | ||
| project_dir | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, this description carries the full behavioral burden. It discloses atomicity ('Nothing is written if any operation is invalid'), ordering ('applied in order'), persistence ('saved once at the end'), automatic entry_point derivation, and the compact summary return. This is a thorough behavioral contract for a mutating batch tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is moderately long but every sentence carries instructional weight: usage guidance, atomicity, operation format, entry_point caveat, and return behavior. The front-loaded purpose and clean example block make it easy to scan, with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (multi-operation batching with atomic semantics) and an existing output schema, the description covers all necessary operational details: operation set, ordering, atomicity, entry_point handling, and post-call guidance. An agent can invoke it correctly and predict its side effects without needing additional information.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, but the description compensates richly for the `operations` parameter with a full format spec and concrete examples for add_node, add_edge, remove_node, remove_edge, and set_state_schema. However, `project_dir` is never explained beyond its name in the schema, leaving a small gap in an otherwise strong parameter narrative.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Apply several spec edits in one call' and explicitly contrasts with individual add_node/add_edge calls, naming the sibling tools it replaces. This makes the batch-mutation purpose unmistakable and differentiates it from the single-edit siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a clear when-to-use rule ('whenever wiring more than one node/edge at once') and mentions the alternative of separate calls. It also explains when not to fabricate a START edge, and routes to get_spec for full results, leaving no ambiguity about selection or follow-up.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_specA
Read-only fetch of the full current spec.
Mutating tools (add_node, add_edge, remove_node, remove_edge, set_state_schema) return a compact summary (counts), not the full spec, to keep per-edit response cost flat as the graph grows. Call this when you actually need the whole picture.
| Name | Required | Description | Default |
|---|---|---|---|
| project_dir | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It clearly declares the operation is read-only, explains that the return is the full spec rather than a summary, and gives the design rationale about per-edit response cost. It does not discuss error conditions or permissions, but the core behavioral traits are well covered.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core purpose and then adds a tightly relevant paragraph explaining the contrast with mutating tools. Every sentence earns its place, and there is no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple one-parameter read-only tool with an output schema available, the description covers the main behavioral context: what it retrieves, when to call it, and how it differs from siblings. The missing parameter documentation is a minor gap given the self-explanatory project_dir name, but the tool is otherwise fully understandable.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, and the description does not mention project_dir at all. The parameter name and title ('Project Dir') give some minimal hint, but the description fails to compensate for the absence of schema documentation, such as what the path should point to or any required format.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: "Read-only fetch of the full current spec." It also distinguishes itself from sibling mutating tools by noting they return compact summaries, making it clear this tool provides the complete graph state.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly states when to use this tool: "Call this when you actually need the whole picture." It also explains that mutating tools (add_node, add_edge, remove_node, remove_edge, set_state_schema) return only counts, which tells the agent when those alternatives are more appropriate.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
init_projectA
Create a new spec-driven LangGraph project: spec.yaml, nodes.py stub, init.py.
project_dir: directory to create/use (created if missing; error if a spec.yaml already exists there). name: project/graph name, stored in spec.yaml. state_fields: optional initial state fields, each {name, type, reducer?, default?}.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | ||
| project_dir | Yes | ||
| state_fields | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It explains that project_dir is created if missing, errors if spec.yaml already exists, and details how name and state_fields are used. It does not mention whether other files are overwritten or permissions required, but the error condition on spec.yaml suggests safe creation. This is reasonably transparent for a scaffold tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loaded with the core purpose, followed by parameter explanations. Each sentence carries necessary information—creation artifacts, error condition, and parameter details. It is slightly verbose in the parameter block but remains efficient and well-structured.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an initialization tool with an output schema (not shown), the description covers all necessary aspects: purpose, parameters, error behavior, and file outputs. It does not mention what the return value looks like, but since an output schema exists, that is acceptable. It could be more explicit about side effects (e.g., creating directories) but overall it is complete for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema has 0% description coverage, so the description must fully compensate. It does: each parameter (project_dir, name, state_fields) is explained with its role, constraints, and expected structure (e.g., state_fields items have name, type, reducer?, default?). This adds meaning far beyond the bare schema titles.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool creates a new spec-driven LangGraph project and enumerates the artifacts it generates (spec.yaml, nodes.py stub, __init__.py). This distinguishes it from sibling tools that modify or inspect an existing project, so an agent can immediately recognize it as the setup/initialization tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage for new projects by noting that an error occurs if spec.yaml already exists, which effectively warns against reuse. However, it does not explicitly state when to prefer this tool over siblings (e.g., 'use for initial scaffolding') or mention any alternatives. The error condition provides partial guidance but the exclusion logic is left implicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
remove_edgeA
Remove edge(s) from a source node. Omit to to remove all edges from that source.
| Name | Required | Description | Default |
|---|---|---|---|
| to | No | ||
| from_ | Yes | ||
| project_dir | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden of behavioral disclosure. It reveals a key behavioral nuance: omitting `to` removes all edges from the source, which is not obvious from the schema alone. However, it does not mention error handling, side effects, or what happens if the edge or node does not exist.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is extremely concise: two sentences with zero filler. The primary action is front-loaded, and the optional behavior is stated immediately after, making it easy for an agent to parse quickly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple mutation tool, the description covers the core behavior and the optional parameter's effect. The output schema exists, so return values are not needed. The only gap is the unaddressed `project_dir` parameter and edge-case behavior, but these are minor for this tool's complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It explicitly explains the `to` parameter (optional, and omission removes all edges), and `from_` is clearly implied as the source node. However, `project_dir` is not explained, leaving its purpose unclear despite being required.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action: 'Remove edge(s) from a source node.' It specifies the verb (remove), the resource (edge), and the context (source node), distinguishing it from sibling tools like remove_node and add_edge without ambiguity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides a usage hint for the `to` parameter ('Omit `to` to remove all edges'), but it does not explicitly state when to use this tool versus alternatives like remove_node or add_edge. The usage is implied by the name and description rather than directly addressed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
remove_nodeA
Remove a node, cascading to delete any edges that touch it.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | ||
| project_dir | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the behavioral disclosure burden. It meaningfully discloses that the operation is destructive to edges as well as the node, which is the most important side-effect. It does not discuss failure behavior or irreversibility, but the core cascading behavior is clearly stated.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single sentence, front-loaded with the primary action and immediately followed by the critical side-effect. Every word earns its place; there is no filler or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple two-parameter tool with an output schema, the core semantics are covered. However, the description leaves project_dir's role and the node-identification semantics implicit, and it does not state what happens if the node does not exist. This is acceptable but not fully complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, and the description adds no meaning to either parameter. 'id' and 'project_dir' are only explained by their names, so an agent must infer that 'id' identifies the node and 'project_dir' locates the containing project. The description should have compensated for the missing parameter docs.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action ('Remove a node') and the key side-effect (cascading deletion of edges). It is clearly distinguishable from sibling tools like remove_edge, since it targets a node and explicitly handles edge cleanup.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied rather than explicit: the 'cascading' phrase suggests this is the right tool when both a node and its touching edges should be removed, versus remove_edge for edges alone. No explicit when-to-use or when-not-to-use guidance is provided, but the context is inferable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
render_pythonA
Render the current spec into idiomatic LangGraph Python (graph.py by default).
Deterministic Jinja2 templating — no LLM involved, same spec always produces the same code. Blocks if the spec has validation errors (warnings still allow rendering).
| Name | Required | Description | Default |
|---|---|---|---|
| output_path | No | ||
| project_dir | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden and does add meaningful behavioral context: deterministic Jinja2 templating, no LLM involvement, and error-blocking versus warning-tolerant rendering. It does not explicitly describe file overwriting or other side effects, but the default output path and rendering behavior are clearly disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three short, meaningful sentences with the core purpose front-loaded. The second sentence about determinism and validation behavior earns its place and adds no fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return-value documentation is not required. However, for a tool with no annotations that appears to write files, the description does not state how project_dir and output_path interact or whether an existing graph.py is overwritten. It covers validation behavior well but lacks full file-handling context.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate for undocumented parameters. It only clarifies the output_path default via 'graph.py by default' and leaves project_dir and custom output_path behavior largely unexplained. This is partial compensation at best.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states a specific action and resource: rendering the current spec into idiomatic LangGraph Python, defaulting to graph.py. This distinguishes it from sibling tools like get_spec and validate_graph, which inspect or validate rather than generate code.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies the tool should be used after the spec is valid, since it blocks on validation errors, but it never explicitly says when to use it or when to prefer a sibling tool. No alternatives or exclusions are named.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_state_schemaA
Replace the graph's state schema wholesale.
Each field: {name, type, reducer?, default?}. type is a raw Python
type expression (e.g. "str", "list[str]"); reducer names a reducer
function (e.g. "add_messages", or a custom name defined in reducers.py).
| Name | Required | Description | Default |
|---|---|---|---|
| fields | Yes | ||
| project_dir | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full disclosure burden. It does convey the destructive nature ('replace wholesale') and documents the field contract ({name, type, reducer?, default?}) plus the type/reducer syntax. However, it omits error behavior (e.g., invalid Python type expressions), validation of the schema, and side effects on nodes referencing old fields. The documented field structure adds genuine value, but coverage is incomplete.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences with the core purpose front-loaded in the first sentence and supporting field details in the following two. No filler or redundant phrasing; each sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return-value documentation is not required. The description covers the input contract for 'fields' but lacks error-condition disclosure and side-effect context (what happens to existing nodes or references after a wholesale schema swap). For a schema-replacement mutation, this is a meaningful gap, though the tool has only two parameters and moderate complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate, and it does substantially for 'fields' by defining each sub-field's shape and the exact syntax of 'type' and 'reducer' with examples. However, 'project_dir' receives zero explanation—no hint that it is the project path or how it is used. The main parameter is richly documented, but one of the two required parameters is ignored.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb+resource+scope: 'Replace the graph's state schema wholesale.' This clearly distinguishes it from sibling tools like add_node/add_edge (which mutate graph structure) and init_project (project setup). The 'wholesale' qualifier precisely conveys full replacement, making the purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description states what the tool does but gives no guidance on when to choose it over alternatives, and never names a sibling or an exclusion condition. There is no mention of when incremental updates would be preferable or when this wholesale replacement is appropriate. Usage context is entirely implied by the purpose.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
validate_graphA
Check the spec for unreachable nodes, missing paths to END, dangling conditions/edges, and duplicate/typo'd ids. Returns ok=False if any errors (as opposed to warnings) are found.
| Name | Required | Description | Default |
|---|---|---|---|
| project_dir | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description must carry the burden of behavioral disclosure. It explains that the tool returns ok=False if errors are found, and distinguishes errors from warnings, which is useful. However, it doesn't specify what 'errors' vs 'warnings' mean in this context, nor does it explain whether the tool performs any side effects (likely none, but it's not stated). Since it's a validation tool, it's presumably read-only, but that's implicit, not explicit.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences, with the first sentence defining the purpose and the second detailing the return behavior. It's concise, front-loaded with the action and scope, and every phrase adds value. No redundant information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is a validation function with a single simple parameter and an output schema (which likely describes the return structure). Given its complexity, the description covers the core functionality (what is validated, what the result means). It doesn't provide examples or elaborate on warning vs error categories, but for a validation tool, this is reasonably complete. The output schema exists, so return details are structured elsewhere.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema has 0% description coverage for the only parameter 'project_dir', so the description must compensate. The description does not explain 'project_dir' beyond its name, but the name is self-explanatory (the directory containing the spec). Given the parameter's simplicity, the missing explicit description is a minor gap. Still, the description doesn't add any additional meaning beyond the schema, but the schema itself is minimal, so the baseline is 4 due to low coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states a specific verb ('validate') and resource ('the spec'), and lists the specific error types it checks for (unreachable nodes, missing paths to END, dangling conditions/edges, duplicate/typo'd ids). This distinguishes it from sibling tools like get_spec or init_project, though it doesn't explicitly name a sibling.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use it (when you need to validate the spec for errors), but it doesn't explicitly state when to use it versus alternatives or when not to use it. It also doesn't mention typical triggers like 'after making changes' or 'before rendering'. The context is clear enough but lacks explicit routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
1 tool update
v0.2.0- Added
apply_changes
9 tool updates
v0.1.0- First observed
add_edge - First observed
add_node - First observed
get_spec - First observed
init_project - First observed
remove_edge - First observed
remove_node - First observed
render_python - First observed
set_state_schema - First observed
validate_graph
TDQS
Scored across 10 tools
Each tool targets a distinct operation: adding/removing nodes and edges, setting schema, fetching the spec, validating, rendering, initializing, and batch-applying changes. Even apply_changes is clearly scoped as a batch wrapper with explicit op names, so no tool is easily confused with another.
All tool names follow a consistent snake_case verb_noun pattern: add_node, remove_edge, set_state_schema, get_spec, validate_graph, render_python, init_project, apply_changes. There are no style deviations or vague verbs.
Ten tools is well-scoped for a LangGraph spec toolkit. Each tool covers a necessary piece of the workflow without redundancy, and the count supports both simple edits and batching without feeling bloated.
The toolkit covers the full graph-building lifecycle: project creation, node and edge CRUD, state schema management, validation, rendering to Python, and full-spec inspection. The batch apply_changes tool also fills the practical gap of multi-edit workflows.
Maintenance
Related MCP Connectors
Render, verify, describe, and safely edit Mermaid diagrams through MCP.
- typeshipOAuthdev.typeship
Generate a typed SDK, CLI, and MCP server from any OpenAPI or GraphQL spec, and keep them current.
Create and manage Mermaid.js flowcharts and diagrams with AI agents via MCP.
Create, browse, remix, collaborate on, and run durable AI workflow nodes from MCP hosts.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables orchestration of MCP tool calls through declarative YAML-defined directed graphs with data transformation, conditional routing, and observable execution flows.57 npm22MIT
- AlicenseNot gradedqualityCmaintenanceEnables creating no-code agent workflows by combining multiple MCP servers into unified YAML-defined tools. Supports parameterized prompts and scripted steps, exposing a single MCP endpoint that orchestrates external servers like Chrome DevTools and shadcn.10MIT
- AlicenseNot gradedqualityBmaintenanceEnables multi-model leader-worker agent orchestration, workflow execution, and deterministic validation via structured MCP tools.5 npmApache 2.0
- AlicenseAqualityAmaintenanceA local, auditable multi-model workflow engine that lets you define YAML graphs for orchestrating LLM agents across vendors, with MCP tools for validation, dry-runs, execution, and human approval, all fully observable in a local web interface.83Apache 2.0