slate

slate

Enables AI agents to read and write to an iPad whiteboard via MCP, including structured elements, handwritten text, and image rendering.

Category
访问服务器

README

Slate

Una whiteboard sull'iPad che gli agenti AI possono leggere e scrivere via MCP.

Disegni e scrivi a mano con la Pencil, aggiungi note e riquadri. Dall'altra parte un agente (Claude Code o qualsiasi client MCP) legge la board come struttura — elementi, testo, posizioni, frecce — e come immagine, così capisce anche quello che è stato scritto a mano. E può rispondere scrivendo sulla board.

Tutto gira sul tuo Mac. Nessun servizio esterno, nessun dato che esce dalla rete.

Prima di adottarlo: il codice di Slate è MIT, ma il canvas è l'SDK di tldraw, che non è open source e limita l'uso gratuito agli ambienti di sviluppo. Per un deployment di produzione serve una licenza tldraw. Dettagli nella sezione Licenza — leggila prima di costruirci sopra.

Come è fatto

iPad Safari (PWA tldraw)  ─┐
                           ├─ WebSocket sync ─►  board-server (Node 22+)
Mac browser (stessa PWA)  ─┘                     • @tldraw/sync-core
                                                  • SQLite (un file per board)
                                                  • render PNG headless + OCR
                                                          ▲
Claude Code / altri agent ── stdio MCP ──►  slate-mcp ────┘

Lo stato vive sul server, non sull'iPad: la board resta leggibile anche a tablet spento.

Cartella Cosa fa
apps/board-server Sync tldraw, persistenza, API, render, OCR
apps/board-web La PWA installabile sull'iPad
apps/slate-mcp Il server MCP che parla agli agenti
tools/ocr Binario Swift che usa Apple Vision per la scrittura a mano

Prerequisiti

  • Node ≥ 22.12 — richiesto da tldraw 5. Il .node-version punta a 26. Se la tua shell è su Node 20 (default per altri progetti), usa /opt/homebrew/bin/node o fnm use 26.
  • Google Chrome — usato in headless per il render. Nessun browser da scaricare.
  • Xcode command line tools — solo per compilare il binario OCR.

Setup

npm install
npm run build

# OCR della scrittura a mano (opzionale ma consigliato)
cd tools/ocr && swiftc -O -o slate-ocr main.swift && cd -

Avvio

npm run dev:server     # in sviluppo

Oppure come servizio, così parte da solo al login:

./scripts/install-service.sh

All'avvio il server stampa i link di pairing:

[slate] pair a device:  http://192.168.1.x:4501/?token=…      ← LAN
[slate] pair a device:  http://100.x.x.x:4501/?token=…        ← Tailscale

Collegare l'iPad

  1. Apri uno dei link di pairing su Safari. Il token viene salvato e tolto dall'URL.
  2. Condividi → Aggiungi a Home. Si apre a schermo intero, senza barre.
  3. Fuori casa serve Tailscale sull'iPad (usa il link 100.x). In LAN non serve.

Il firewall di macOS blocca tutto

Se l'iPad non si collega ma da Mac funziona, è quasi certamente il firewall: autorizza il binario node reale (non il symlink).

NODE_REAL=$(readlink -f /opt/homebrew/bin/node)
sudo /usr/libexec/ApplicationFirewall/socketfilterfw --add "$NODE_REAL"
sudo /usr/libexec/ApplicationFirewall/socketfilterfw --unblockapp "$NODE_REAL"

Va rifatto dopo ogni aggiornamento di Node: Homebrew installa in un path versionato (/opt/homebrew/Cellar/node/26.4.0/bin/node) e l'autorizzazione è legata a quel path esatto.

Collegare l'agente

claude mcp add slate -- /opt/homebrew/bin/node ~/GitHub/mcp/slate/apps/slate-mcp/dist/index.js

L'MCP parla al server via loopback, che è sempre autorizzato: nessun token da configurare finché server e agente stanno sulla stessa macchina. Se li separi, passa SLATE_SERVER e SLATE_TOKEN.

Tool disponibili

Tool Cosa fa
list_boards Elenca le board, dalla più recente
read_board Struttura: elementi, testo, posizioni, gruppi, frecce, + OCR della scrittura
render_board Restituisce la board come immagine PNG
search_board Cerca testo, incluso quello scritto a mano
create_board Crea una board vuota
add_note Aggiunge una sticky note (posizionata da sola per non sovrapporsi)
add_image Carica un'immagine da file e la posiziona sulla board (PNG, JPEG, GIF, WebP)
update_note Cambia il testo di un elemento mantenendo stile e posizione
delete_shapes Elimina elementi

Eliminare una board non è esposto come tool: si fa via DELETE /api/boards/:id. Un agente può cancellare elementi, non board intere.

Quanto è affidabile l'OCR

Poco, ed è per questo che render_board esiste. Su scrittura a mano reale Apple Vision prende circa 3 parole su 4: abbastanza per cercare ("in che board avevo scritto FLUSSO?"), non abbastanza per fidarsi del testo riconosciuto.

Per capire davvero cosa c'è su una board disegnata, l'agente deve guardare l'immagine. read_board lo dice esplicitamente nel proprio output.

Misurato su una board di prova (scripts/ocr-scale-test.mjs confronta le varianti):

Variante Risultato
scale 1.5, corretto CIAO QUESTO E ON / TEST / ALUSSO 1 / FLUSSO?
scale 2, corretto (default) CIAO QUESTO E ON / TEST / FLUSSO 1 / Autor
scale 3, corretto CIAO QUEDO E ON / TEST / FLUSSO 1 / {LUSSO?
qualsiasi scala, --raw sempre uguale o peggio

Due cose controintuitive emerse dai dati:

  • Alzare la risoluzione non migliora linearmente. A scale 3 la scrittura viene letta peggio che a 2 in alcuni punti: i tratti spessi iniziano a fondersi. Regola con SLATE_OCR_SCALE, non dare per scontato che più alto sia meglio.
  • La correzione linguistica conviene tenerla accesa, anche se spinge verso parole di dizionario (è lei a trasformare FLUSSO2 in Autor). Disattivarla con --raw peggiora tutto il resto. Se la tua board è fatta solo di sigle, riprova la misura: il compromesso può ribaltarsi.

Sicurezza

Un solo modello di accesso per tutte le superfici remote — API, sync e upload. Loopback è sempre autorizzato (è così che entra l'MCP); tutto il resto richiede il token, che viene generato al primo avvio e salvato in ~/.slate/token (0600).

Non esiste una modalità "senza token": lasciare aperto il sync proteggendo solo l'API sarebbe inutile, perché chi raggiunge il socket di sync ha già accesso completo in lettura e scrittura a ogni board.

Le immagini sotto /media/ si leggono senza token: tldraw le carica con <img src>, che non può portare un header, e mettere il token nell'URL lo farebbe finire dentro i documenti esportati. I nomi contengono un UUID, quindi non sono indovinabili.

Per restringere l'ascolto alla sola tailnet:

SLATE_HOST=100.x.x.x npm run dev:server   # il tuo indirizzo Tailscale

Variabili d'ambiente

Variabile Default Note
SLATE_HOST 0.0.0.0 Metti l'IP Tailscale per non esporre in LAN
SLATE_PORT 4501
SLATE_DATA_DIR ~/.slate Board, asset, token
SLATE_TOKEN generato Sovrascrive quello salvato
SLATE_CHROME_PATH Chrome in /Applications Per il render
SLATE_OCR_BIN tools/ocr/slate-ocr
SLATE_OCR_SCALE 2 Risoluzione del render passato a Vision
SLATE_SERVER http://127.0.0.1:4501 Lato MCP

Trappole già incontrate

Cose che costano un pomeriggio se le scopri da solo.

  • fontSizeAdjustment: 0 rende il testo invisibile. La nota si salva, si rilegge correttamente dai dati, e sull'iPad appare vuota. Il valore giusto è null ("ricalcola"). Se scrivi record a mano, non copiare uno 0 da un esempio vecchio.
  • /assets è di Vite. Le immagini delle board stanno sotto /media perché la build della PWA emette i suoi bundle in /assets: una rotta sovrapposta se li mangia e l'app resta senza JavaScript, fallendo in modo silenzioso.
  • Il testo è ProseMirror, non stringa. props.richText vuole un documento; una stringa viene rifiutata dallo schema.
  • I tratti sono path base64. tldraw 5 non espone un encoder, quindi non si può fabbricare un tratto a mano libera da script — solo disegnandolo. Per lo stesso motivo la dimensione di un tratto non è calcolabile dal record: la sanno solo il renderer e l'endpoint OCR, che la misurano in un editor vivo.
  • Non elencare i tratti uno per uno. Una pagina scritta a mano sono decine o centinaia di draw: elencarli produce un muro di righe identiche che seppellisce tutto il resto. read_board li conta e mostra il testo riconosciuto.
  • Le note non crescono da sole. Una sticky è un riquadro fisso 200×200 e il testo che eccede viene tagliato nel render, pur restando integro nei dati: l'API lo rilegge intero mentre sull'iPad la nota appare mozzata. add_note stima growY dalla lunghezza del testo; il client ricalcola l'altezza esatta alla prima modifica.
  • Il posizionamento automatico ha bisogno delle misure vere. Siccome i tratti dichiarano dimensione zero, su una board disegnata il calcolo del bordo destro cade dove inizia il primo tratto e la nota finisce sopra il disegno. Per questo add_note interroga /api/boards/:id/bounds quando trova inchiostro.
  • I record scritti vengono validati. Il server rifiuta con 400 quello che non passa lo schema tldraw, invece di far crashare il canvas sull'iPad più tardi.
  • La licenza tldraw non è open source. Vedi la sezione qui sotto: incide su cosa puoi farci, non solo sul watermark.

Licenza

Il codice di Slate è MIT (vedi LICENSE): usalo, modificalo, ridistribuiscilo come vuoi.

Ma il canvas no. Slate è costruito sull'SDK di tldraw, che non è open source e ha una licenza propria. Vale la pena leggerla prima di adottare Slate, perché è più restrittiva di quanto il watermark lasci intuire:

  • L'uso gratuito è limitato ai Development Environment. La licenza definisce Production come «any production deployment of the Software that operates on servers, cloud platforms, web applications, or where the software is used to provide functionality to end users».
  • Per un deployment di produzione serve una licenza commerciale o un trial.
  • La redistribuzione è ammessa solo come componente di un'altra applicazione, mai standalone, e con copia verbatim della licenza tldraw.

In pratica: un'istanza personale self-hosted sul proprio Mac sta in una zona grigia che solo tldraw può chiarire; qualsiasi cosa somigli a un servizio per altri utenti quasi certamente richiede una licenza. Se il vincolo non ti va bene, la strada è sostituire il canvas con un'alternativa realmente libera — Excalidraw è MIT — tenendo il resto di Slate, che dal canvas dipende solo attraverso il layer di sync e il renderer.

Questa è lettura del testo della licenza, non consulenza legale. Per un uso serio chiedi a tldraw (sales@tldraw.com) o a un avvocato. Il quadro completo delle dipendenze e delle loro licenze è in NOTICE.md.

Sviluppo

npm run dev:server                    # server con reload
npm run dev:web                       # PWA su :4500, proxy verso il server
node scripts/seed-demo.mjs demo       # riempie una board di prova
node scripts/test-mcp.mjs demo        # esercita l'MCP su stdio
node scripts/make-icons.mjs           # rigenera le icone della PWA

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选