JSON Canvas MCP Server

Um servidor para criar, modificar, validar e exportar arquivos JSON Canvas, um formato para dados de canvas infinito.

Documentação

JSON Canvas MCP Server

Um servidor Model Context Protocol (MCP) para trabalhar com arquivos JSON Canvas — o formato aberto de tela infinita usado pelo Obsidian. Ele permite que um cliente MCP crie, valide, leia e liste arquivos .canvas.

Construído sobre o SDK Python oficial mcp (>=1.27), que negocia a revisão do protocolo MCP 2025-11-25. Executa via stdio por padrão e opcionalmente sobre o transporte Streamable HTTP.

Hosts que suportam a extensão de UI MCP Apps renderizam um visualizador de canvas interativo inline ao ler ou criar um canvas — uma pré-visualização com pan/zoom, no estilo do Obsidian, dos nós e arestas. Clientes somente texto não são afetados e continuam recebendo o canvas como saída texto/estruturada.

Componentes

Ferramentas

  • create_canvas — Cria um canvas a partir de nodes (e edges opcional) e o grava em um arquivo .canvas com prefixo de data em OUTPUT_PATH.
    • Entrada: nodes (matriz de objetos de nó JSON Canvas), filename (string, sem extensão), edges (matriz opcional de objetos de aresta).
    • Retorna (estruturado): { path, node_count, edge_count }.
  • validate_canvas — Valida dados de canvas contra a especificação JSON Canvas 1.0.
    • Entrada: canvas (objeto com nodes e edges opcionais).
    • Retorna (estruturado): { valid, error }.
  • read_canvas — Lê um arquivo .canvas armazenado e retorna seus nós e arestas.
    • Entrada: filename (string, com ou sem a extensão .canvas).
    • Retorna (estruturado): { nodes, edges } (também renderizado pelo visualizador de canvas; o fallback de texto é o JSON do canvas).
  • list_canvases — Lista os arquivos .canvas disponíveis em OUTPUT_PATH.
    • Retorna: matriz de nomes de arquivo.
  • edit_canvas — Adiciona, atualiza e/ou remove nós e arestas em um canvas armazenado em uma única gravação atômica (uma operação com falha deixa o arquivo inalterado).
    • Entrada: filename, além de add_nodes opcional, update_nodes (parcial, deve incluir id), remove_node_ids (propaga para arestas conectadas), add_edges, update_edges, remove_edge_ids.
    • Retorna (estruturado): { path, node_count, edge_count, canvas } — o canvas atualizado, para que hosts com capacidade de UI o re-renderizem inline.
  • export_canvas — Exporta um canvas armazenado para outro formato.
    • Entrada: filename, format (markdown | svg).
    • Retorna (estruturado): { format, mime_type, content }. Markdown é um esboço ordenado por arestas; SVG é uma imagem vetorial autônoma (apenas linhas de título de nó — SVG simples não pode renderizar Markdown).
  • search_canvases — Pesquisa de substring sem diferenciar maiúsculas/minúsculas nos canvases armazenados.
    • Entrada: query, filename opcional para limitar a um canvas.
    • Retorna (estruturado): { matches: [{ filename, kind, id, field, snippet }] }.

create_canvas, read_canvas e edit_canvas estão vinculados ao visualizador de canvas via _meta.ui.resourceUri, para que hosts com capacidade de UI renderizem o resultado inline.

Objetos de nó usam a forma JSON Canvas: id, type (text | file | link | group), x, y, width, height, color opcional, além de campos específicos de tipo (text, file/subpath, url, label/background/backgroundStyle). Objetos de aresta usam id, fromNode, toNode e fromSide/toSide/fromEnd/toEnd/color/label opcionais.

Recursos

  • canvas://schema — JSON Schema para validar arquivos de canvas.
  • canvas://examples/basic — Um canvas de exemplo simples (dois nós de texto unidos por uma aresta).
  • ui://canvas/viewer.html — O visualizador de canvas interativo (UI MCP Apps), servido com tipo MIME text/html;profile=mcp-app. Referenciado por create_canvas e read_canvas.

Visualizador de canvas interativo (UI MCP Apps)

O visualizador é um único pacote HTML autônomo construído a partir do código-fonte ui/ com Vite e o cliente oficial @modelcontextprotocol/ext-apps. Ele renderiza nós (com markdown, cores e grupos) e arestas (lados, setas, rótulos) em uma visualização com pan/zoom, tematizada pelas variáveis CSS do host.

O pacote construído é commitado em jsoncanvas/_ui/viewer.html e incluído no pacote, então executar o servidor requer apenas Python. Reconstrua-o após alterar ui/:

make build-ui     # cd ui && npm install && npm run build  (requires Node.js)

Para pré-visualizar o renderizador de forma autônoma (sem host MCP), execute cd ui && npm run dev e abra /preview.html.

Uso com Claude Desktop

Docker (stdio)

docker build -t mcp/jsoncanvas .

Adicione ao seu 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" }
    }
  }
}

Transporte Streamable HTTP

Para servir via Streamable HTTP em vez de stdio:

mcp-server-jsoncanvas --transport streamable-http --host 127.0.0.1 --port 8000

O endpoint MCP é então http://127.0.0.1:8000/mcp. O transporte vincula-se a localhost e, conforme a especificação 2025-11-25, valida o cabeçalho Origin com proteção contra DNS-rebinding habilitada (apenas Origins de localhost por padrão). Para aceitar conexões de fora do host (por exemplo, ao executar o contêiner com HTTP), vincule --host 0.0.0.0 e configure seus Origins permitidos de acordo.

Hosts MCP baseados em navegador (o tipo que renderiza o visualizador de canvas) conectam-se entre origens e devem ler o cabeçalho de resposta mcp-session-id, então o transporte Streamable HTTP serve cabeçalhos CORS permissivos. Restrinja as origens permitidas com MCP_CORS_ORIGINS (separadas por vírgula; padrão *).

Nota de segurança. O transporte HTTP é não autenticado — qualquer pessoa que alcance a porta pode ler e gravar arquivos .canvas em OUTPUT_PATH. O servidor é destinado ao uso local; mantenha-o vinculado a 127.0.0.1 (o padrão). A proteção DNS-rebinding/Origin é fixada em Origins e Hosts de localhost na inicialização, então vincular --host 0.0.0.0 expõe a porta na rede, mas ainda rejeita cabeçalhos Host/Origin de não-localhost — para expô-lo remotamente com segurança, coloque um proxy reverso autenticador na frente em vez de publicá-lo diretamente, e defina MCP_CORS_ORIGINS para as origens específicas em que você confia (nunca *).

Configuração

Variáveis de ambiente:

  • OUTPUT_PATH — Diretório onde os arquivos .canvas são gravados/lidos (padrão ./output).
  • MCP_TRANSPORT — stdio (padrão) ou streamable-http.
  • MCP_HOST / MCP_PORT — Host/porta para o transporte Streamable HTTP (padrão 127.0.0.1:8000).
  • MCP_CORS_ORIGINS — Origens CORS permitidas, separadas por vírgula, para o transporte HTTP (padrão *).

Desenvolvimento

# 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

Execute o exemplo de biblioteca incluído:

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

Exemplo de biblioteca

O pacote jsoncanvas também pode ser usado diretamente:

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

Licença

MIT. Consulte LICENSE.