trackmcp
Back to directory
Cam10001110101

obsidian-jsoncanvas

View on GitHub

JSON Canvas MCP Server

14 stars HTMLOthers Updated Jun 22, 2026

Documentation

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`.

    `edges` (optional array of edge objects).

    • 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).

      `remove_node_ids` (cascades connected edges), `add_edges`, `update_edges`, `remove_edge_ids`.

        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/`:

        bash
        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)

        bash
        docker build -t mcp/jsoncanvas .

        Add to your `claude_desktop_config.json`:

        json
        {
          "mcpServers": {
            "jsoncanvas": {
              "command": "docker",
              "args": ["run", "-i", "--rm", "-v", "canvas-data:/data", "mcp/jsoncanvas"],
              "env": { "OUTPUT_PATH": "/data/output" }
            }
          }
        }

        uv (stdio)

        json
        {
          "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:

        bash
        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
        # Install uv: https://docs.astral.sh/uv/getting-started/installation/
        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:

        bash
        make example      # writes example.canvas to OUTPUT_PATH (default ./output)

        Library example

        The `jsoncanvas` package can also be used directly:

        python
        from jsoncanvas import Canvas, TextNode, Edge
        
        title = TextNode(id="title", x=100, y=100, width=400, height=100,
                         text="# Hello Canvas", color="#4285F4")
        info = TextNode(id="info", x=600, y=100, width=300, height=100,
                        text="More information here", color="2")  # preset color
        
        canvas = Canvas()
        canvas.add_node(title)
        canvas.add_node(info)
        canvas.add_edge(Edge(id="edge1", from_node="title", to_node="info",
                             from_side="right", to_side="left", label="Connection"))
        
        import json
        print(json.dumps(canvas.to_dict(), indent=2))

        License

        MIT. See LICENSE.

        Frequently asked questions

        What is obsidian-jsoncanvas?

        obsidian-jsoncanvas is JSON Canvas MCP Server

        How do I install obsidian-jsoncanvas?

        Open the GitHub repository and follow its README. Most MCP servers are added to your client's MCP config, then called by your agent.

        Is obsidian-jsoncanvas open source?

        Yes — it is hosted on GitHub at https://github.com/Cam10001110101/obsidian-jsoncanvas and has 14 stars.

        Related MCP tools

        Run your own MCP server? See who uses it and what to fix.

        Measure it with TrackMCP