JSON Canvas
About
Provides tools for creating, modifying, and validating infinite canvas data structures, supporting all node types and edge connections, with a RESTful API for canvas operations and export capabilities.
Details
- Author
- cam10001110101
- Repository
- Cam10001110101/obsidian-jsoncanvas
- GitHub stars
- 3
- Downloads
- 311
- License
- MIT License
- Categories
- Productivity, Other, AI, Design, Developer Tools, File Management, Frontend, Infrastructure, API, Knowledge Base
Jump to
- Five tools: create_canvas, validate_canvas, read_canvas, list_canvases, edit_canvas, export_canvas, search_canvases
- Interactive canvas viewer (MCP Apps UI) for UI-capable hosts
- Export canvases to Markdown (edge-ordered outline) or SVG (vector image)
- Atomic edit operations (add/update/remove nodes and edges)
- Case-insensitive substring search across stored canvases
Setting up with Highlight
This MCP is not yet compatible with Highlight’s one-click setup. However, you can still use it with Highlight by following these steps:
- Download and install Highlight from highlightai.com/download
- Navigate to the plugins tab and select "Add Custom Plugin"
-
Configure the plugin with the settings below
Plugin Name
JSON CanvasCommand (node, npx, python, etc.)uvArguments-
Argument 1
--directory -
Argument 2
/path/to/jsoncanvas -
Argument 3
run -
Argument 4
mcp-server-jsoncanvas
Environment-
OUTPUT_PATH
./output
Please refer to the README for specific instructions on how to obtain API keys or other required environment variables.
-
Argument 1
- Enable "Start Automatically" if you want the plugin to start when Highlight launches
From the repository
Environment variables:
- OUTPUT_PATH — Directory where .canvas files are written/read (default ./output).
- MCP_TRANSPORT — stdio (default) or streamable-http.
- MCP_HOST / MCP_PORT — Host/port for the Streamable HTTP transport (default 127.0.0.1:8000).
- MCP_CORS_ORIGINS — Comma-separated allowed CORS origins for the HTTP transport (default *).
make setup # uv venv && uv sync --extra dev
make build-ui # rebuild the canvas viewer bundle (requires Node.js)
make test # run the test suite
make lint # ruff check + format check
make audit # scan dependencies for known vulnerabilities (pip-audit)
make run # run the server over stdio
Run the bundled library example:
bashmake example # writes example.canvas to OUTPUT_PATH (default ./output)
```
create_canvas
Create a canvas from nodes (and optional edges) and write it to a date-prefixed .canvas file under OUTPUT_PATH. Input: nodes (array of JSON Canvas node objects), filename (string, no extension), edges (optional array of edge objects). Returns (structured): { path, node_count, edge_count }.
validate_canvas
Validate canvas data against the JSON Canvas 1.0 specification. Input: canvas (object with optional nodes and edges). Returns (structured): { valid, error }.
read_canvas
Read a stored .canvas file and return its nodes and edges. Input: filename (string, with or without the .canvas extension). Returns (structured): { nodes, edges }.
list_canvases
List the .canvas files available in OUTPUT_PATH. Returns: array of filenames.
edit_canvas
Add, update, and/or remove nodes and edges on a stored canvas in one atomic write (a failed operation leaves the file unchanged). Input: filename, plus optional add_nodes, update_nodes (partial, must include id), remove_node_ids (cascades connected edges), add_edges, update_edges, remove_edge_ids. Returns (structured): { path, node_count, edge_count, canvas }.
export_canvas
Export a stored canvas to another format. Input: filename, format (markdown | svg). Returns (structured): { format, mime_type, content }.
search_canvases
Case-insensitive substring search across stored canvases. Input: query, optional filename to scope to one canvas. Returns (structured): { matches: [{ filename, kind, id, field, snippet }] }.
- create_canvas — Create a canvas from nodes (and optional edges) and write it to a
date-prefixed .canvas file under OUTPUT_PATH.
- Input: nodes (array of JSON Canvas node objects), filename (string, no extension),
edges (optional array of edge objects).
- Returns (structured): { path, node_count, edge_count }.
- validate_canvas — Validate canvas data against the JSON Canvas 1.0 specification.
- Input: canvas (object with optional nodes and edges).
- Returns (structured): { valid, error }.
- read_canvas — Read a stored .canvas file and return its nodes and edges.
- Input: filename (string, with or without the .canvas extension).
- Returns (structured): { nodes, edges } (also rendered by the canvas viewer; text
fallback is the canvas JSON).
- list_canvases — List the .canvas files available in OUTPUT_PATH.
- Returns: array of filenames.
- edit_canvas — Add, update, and/or remove nodes and edges on a stored canvas in one
atomic write (a failed operation leaves the file unchanged).
- Input: filename, plus optional add_nodes, update_nodes (partial, must include id),
remove_node_ids (cascades connected edges), add_edges, update_edges, remove_edge_ids.
- Returns (structured): { path, node_count, edge_count, canvas } — the updated canvas, so
UI-capable hosts re-render it inline.
- export_canvas — Export a stored canvas to another format.
- Input: filename, format (markdown | svg).
- Returns (structured): { format, mime_type, content }. Markdown is an edge-ordered outline;
SVG is a standalone vector image (node title lines only — plain SVG can't render Markdown).
- search_canvases — Case-insensitive substring search across stored canvases.
- Input: query, optional filename to scope to one canvas.
- Returns (structured): { matches: [{ filename, kind, id, field, snippet }] }.
create_canvas, read_canvas, and edit_canvas are linked to the canvas viewer via
_meta.ui.resourceUri, so UI-capable hosts render the result inline.
Node objects use the JSON Canvas shape: id, type (text | file | link | group),
x, y, width, height, optional color, plus type-specific fields (text, file/subpath,
url, label/background/backgroundStyle). Edge objects use id, fromNode, toNode, and
optional fromSide/toSide/fromEnd/toEnd/color/label.
Claude Desktop / Cursor
Paste into your MCP client config file to install this server.
{
"mcpServers": {
"json canvas": {
"env": {
"OUTPUT_PATH": "./output"
},
"args": [
"--directory",
"/path/to/jsoncanvas",
"run",
"mcp-server-jsoncanvas"
],
"command": "uv"
}
}
}
Linux
{
"env": {
"OUTPUT_PATH": "./output"
},
"args": [
"--directory",
"/path/to/jsoncanvas",
"run",
"mcp-server-jsoncanvas"
],
"command": "uv"
}
Macos
{
"env": {
"OUTPUT_PATH": "./output"
},
"args": [
"--directory",
"/path/to/jsoncanvas",
"run",
"mcp-server-jsoncanvas"
],
"command": "uv"
}
Windows
{
"env": {
"OUTPUT_PATH": "./output"
},
"args": [
"/c",
"uv",
"--directory",
"/path/to/jsoncanvas",
"run",
"mcp-server-jsoncanvas"
],
"command": "cmd"
}
JSON Canvas MCP Server
A Model Context Protocol (MCP) server for working with
JSON Canvas files — the open infinite-canvas format used
by Obsidian. It lets an MCP client create, validate,
read, and list .canvas files.
Built on the official mcp Python SDK (>=1.27), which negotiates the 2025-11-25 MCP
protocol revision. Runs over stdio by default and optionally over the Streamable HTTP
transport.
Hosts that support the MCP Apps UI extension render an
interactive canvas viewer inline when you read or create a canvas — a pan/zoom,
Obsidian-style preview of the nodes and edges. Text-only clients are unaffected and keep
receiving the canvas as text/structured output.
Components
Tools
- create_canvas — Create a canvas from nodes (and optional edges) and write it to a
date-prefixed .canvas file under OUTPUT_PATH.
- Input: nodes (array of JSON Canvas node objects), filename (string, no extension),
edges (optional array of edge objects).
- Returns (structured): { path, node_count, edge_count }.
- validate_canvas — Validate canvas data against the JSON Canvas 1.0 specification.
- Input: canvas (object with optional nodes and edges).
- Returns (structured): { valid, error }.
- read_canvas — Read a stored .canvas file and return its nodes and edges.
- Input: filename (string, with or without the .canvas extension).
- Returns (structured): { nodes, edges } (also rendered by the canvas viewer; text
fallback is the canvas JSON).
- list_canvases — List the .canvas files available in OUTPUT_PATH.
- Returns: array of filenames.
- edit_canvas — Add, update, and/or remove nodes and edges on a stored canvas in one
atomic write (a failed operation leaves the file unchanged).
- Input: filename, plus optional add_nodes, update_nodes (partial, must include id),
remove_node_ids (cascades connected edges), add_edges, update_edges, remove_edge_ids.
- Returns (structured): { path, node_count, edge_count, canvas } — the updated canvas, so
UI-capable hosts re-render it inline.
- export_canvas — Export a stored canvas to another format.
- Input: filename, format (markdown | svg).
- Returns (structured): { format, mime_type, content }. Markdown is an edge-ordered outline;
SVG is a standalone vector image (node title lines only — plain SVG can't render Markdown).
- search_canvases — Case-insensitive substring search across stored canvases.
- Input: query, optional filename to scope to one canvas.
- Returns (structured): { matches: [{ filename, kind, id, field, snippet }] }.
create_canvas, read_canvas, and edit_canvas are linked to the canvas viewer via
_meta.ui.resourceUri, so UI-capable hosts render the result inline.
Node objects use the JSON Canvas shape: id, type (text | file | link | group),
x, y, width, height, optional color, plus type-specific fields (text, file/subpath,
url, label/background/backgroundStyle). Edge objects use id, fromNode, toNode, and
optional fromSide/toSide/fromEnd/toEnd/color/label.
Resources
- canvas://schema — JSON Schema for validating canvas files.
- canvas://examples/basic — A simple example canvas (two text nodes joined by an edge).
- ui://canvas/viewer.html — The interactive canvas viewer (MCP Apps UI), served with MIME
type text/html;profile=mcp-app. Referenced by create_canvas and read_canvas.
Interactive canvas viewer (MCP Apps UI)
The viewer is a single self-contained HTML bundle built from the ui/ source with Vite
and the official @modelcontextprotocol/ext-apps
client. It renders nodes (with markdown, colors, and groups) and edges (sides, arrows, labels)
in a pan/zoom view, themed via the host's CSS variables.
The built bundle is committed at jsoncanvas/_ui/viewer.html and ships in the package, so
running the server needs only Python. Rebuild it after changing ui/:
make build-ui # cd ui && npm install && npm run build (requires Node.js)
To preview the renderer standalone (no MCP host), run cd ui && npm run dev and open
/preview.html.
Usage with Claude Desktop
Docker (stdio)
docker build -t mcp/jsoncanvas .
Add to your claude_desktop_config.json:
{
"mcpServers": {
"jsoncanvas": {
"command": "docker",
"args": ["run", "-i", "--rm", "-v", "canvas-data:/data", "mcp/jsoncanvas"],
"env": { "OUTPUT_PATH": "/data/output" }
}
}
}
uv (stdio)
{
"mcpServers": {
"jsoncanvas": {
"command": "uv",
"args": ["--directory", "/path/to/jsoncanvas", "run", "mcp-server-jsoncanvas"],
"env": { "OUTPUT_PATH": "./output" }
}
}
}
Streamable HTTP transport
To serve over Streamable HTTP instead of stdio:
mcp-server-jsoncanvas --transport streamable-http --host 127.0.0.1 --port 8000
The MCP endpoint is then http://127.0.0.1:8000/mcp. The transport binds to localhost and, per
the 2025-11-25 spec, validates the Origin header with DNS-rebinding protection enabled
(localhost Origins only by default). To accept connections from outside the host (e.g. when
running the container with HTTP), bind --host 0.0.0.0 and configure your allowed Origins
accordingly.
Browser-based MCP hosts (the kind that render the canvas viewer) connect cross-origin and must
read the mcp-session-id response header, so the Streamable HTTP transport serves permissive
CORS headers. Restrict the allowed origins with MCP_CORS_ORIGINS (comma-separated; default
).
> Security note. The HTTP transport is unauthenticated — anyone who can reach the port
> can read and write .canvas files under OUTPUT_PATH. The server is intended for local use;
> keep it bound to 127.0.0.1 (the default). DNS-rebinding/Origin protection is fixed to
> localhost Origins and Hosts at startup, so binding --host 0.0.0.0 exposes the port on the
> network but still rejects non-localhost Host/Origin headers — to safely expose it remotely,
> front it with an authenticating reverse proxy rather than publishing it directly, and set
> MCP_CORS_ORIGINS to the specific origins you trust (never ).
Configuration
Environment variables:
- OUTPUT_PATH — Directory where .canvas files are written/read (default ./output).
- MCP_TRANSPORT — stdio (default) or streamable-http.
- MCP_HOST / MCP_PORT — Host/port for the Streamable HTTP transport (default 127.0.0.1:8000).
- MCP_CORS_ORIGINS — Comma-separated allowed CORS origins for the HTTP transport (default *).
Development
```bash
Sign in to leave a review
Use Google, GitHub, or an email account so ratings stay tied to real people.
No reviews posted yet.





