pi-tldraw 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +222 -0
- package/bridge/app-bridge-entry.js +6 -0
- package/mcp-app/LICENSE.md +9 -0
- package/mcp-app/PI_TLDRAW_PROVENANCE.json +32 -0
- package/mcp-app/README.md +129 -0
- package/mcp-app/dev-tunnel.sh +51 -0
- package/mcp-app/dist/editor-api.json +8493 -0
- package/mcp-app/dist/mcp-app.html +643 -0
- package/mcp-app/dist/method-map.json +915 -0
- package/mcp-app/package.json +42 -0
- package/mcp-app/plugins/tldraw-mcp/.cursor-plugin/plugin.json +10 -0
- package/mcp-app/plugins/tldraw-mcp/assets/logo.svg +3 -0
- package/mcp-app/plugins/tldraw-mcp/mcp.json +8 -0
- package/mcp-app/scripts/extract-editor-api.ts +1374 -0
- package/mcp-app/server.json +21 -0
- package/mcp-app/src/logger.ts +45 -0
- package/mcp-app/src/register-tools.ts +368 -0
- package/mcp-app/src/shared/generated-data.ts +160 -0
- package/mcp-app/src/shared/pending-requests.ts +69 -0
- package/mcp-app/src/shared/types.ts +76 -0
- package/mcp-app/src/shared/utils.ts +132 -0
- package/mcp-app/src/tools/exec.ts +120 -0
- package/mcp-app/src/tools/loadCachedCanvasWidgetHtml.ts +16 -0
- package/mcp-app/src/tools/search.ts +150 -0
- package/mcp-app/src/widget/app-context.tsx +29 -0
- package/mcp-app/src/widget/dev-log.tsx +70 -0
- package/mcp-app/src/widget/exec-helpers.ts +232 -0
- package/mcp-app/src/widget/export-tldr.ts +35 -0
- package/mcp-app/src/widget/focused/defaults.ts +141 -0
- package/mcp-app/src/widget/focused/focused-editor-proxy.ts +434 -0
- package/mcp-app/src/widget/focused/format.ts +366 -0
- package/mcp-app/src/widget/focused/to-focused.ts +258 -0
- package/mcp-app/src/widget/focused/to-tldraw.ts +570 -0
- package/mcp-app/src/widget/image-guard.tsx +106 -0
- package/mcp-app/src/widget/index.html +33 -0
- package/mcp-app/src/widget/mcp-app.css +113 -0
- package/mcp-app/src/widget/mcp-app.tsx +857 -0
- package/mcp-app/src/widget/persistence.ts +337 -0
- package/mcp-app/src/widget/snapshot.ts +157 -0
- package/mcp-app/src/worker.ts +305 -0
- package/mcp-app/tsconfig.json +23 -0
- package/mcp-app/vite.config.ts +13 -0
- package/mcp-app/wrangler.toml +45 -0
- package/mcp-app-source.json +36 -0
- package/package.json +90 -0
- package/patches/tldraw-mcp-app/001-pi-runtime.patch +35 -0
- package/scripts/assemble-mcp-app.mjs +193 -0
- package/scripts/build-bridge.mjs +74 -0
- package/scripts/e2e-mcp.mjs +69 -0
- package/scripts/e2e-packaged-mcp-app.mjs +79 -0
- package/scripts/run-mcp-app-dev.mjs +44 -0
- package/scripts/verify-bundle.mjs +41 -0
- package/scripts/verify-mcp-app-source.mjs +51 -0
- package/scripts/verify-mcp-app.mjs +38 -0
- package/scripts/verify-package-files.mjs +50 -0
- package/src/canvas/export.ts +164 -0
- package/src/canvas/state.ts +117 -0
- package/src/canvas/workflow.ts +105 -0
- package/src/commands/tldraw-command.ts +48 -0
- package/src/diagram/guidance.ts +44 -0
- package/src/host/local-host.ts +289 -0
- package/src/index.ts +762 -0
- package/src/mcp/client.ts +126 -0
- package/src/mcp/response.ts +74 -0
- package/src/semantic/layer.ts +309 -0
- package/src/server/server-manager.ts +153 -0
- package/src/store/export-store.ts +33 -0
- package/src/store/project-store.ts +251 -0
- package/src/ui/tldraw-status.ts +88 -0
- package/static/app-bridge-bundle.js +18114 -0
- package/static/app-bridge-bundle.meta.json +164 -0
- package/static/host.html +390 -0
- package/tsconfig.json +13 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Zbigniew Siwiec
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# pi-tldraw
|
|
2
|
+
|
|
3
|
+
A Pi extension that opens a local tldraw MCP canvas, lets the agent inspect/edit it, and persists canvas snapshots per project folder.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
From npm:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pi install npm:pi-tldraw
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Pinned:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pi install npm:pi-tldraw@0.1.0
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Before the npm package is published, you can install from GitHub after a repo/tag exists:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pi install git:github.com/<github-owner>/pi-tldraw@v0.1.0
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Or quick-run a local checkout without installing:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pi -e .
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Runtime requirement: tldraw MCP app
|
|
32
|
+
|
|
33
|
+
The extension talks to a tldraw MCP server at:
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
http://127.0.0.1:8787/mcp
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
If that endpoint is not reachable and the endpoint is local, the extension tries to auto-start a local tldraw MCP app. Auto-start uses:
|
|
40
|
+
|
|
41
|
+
1. `TLDRAW_MCP_APP_DIR`, if set.
|
|
42
|
+
2. `./mcp-app` at the package root, if present in the installed package.
|
|
43
|
+
|
|
44
|
+
For a development checkout of tldraw:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
export TLDRAW_MCP_APP_DIR=/path/to/tldraw/apps/mcp-app
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
If you prefer to run the MCP server yourself, start it separately and disable auto-start:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
export TLDRAW_MCP_AUTO_START=false
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The browser-side MCP Apps bridge is different: it is built from source in this repository and shipped as `static/app-bridge-bundle.js`.
|
|
57
|
+
|
|
58
|
+
## Extension shape
|
|
59
|
+
|
|
60
|
+
This is a testable Pi extension package:
|
|
61
|
+
|
|
62
|
+
```text
|
|
63
|
+
pi-tldraw/
|
|
64
|
+
├── src/
|
|
65
|
+
│ ├── index.ts # Pi extension entry point / registration shell
|
|
66
|
+
│ ├── canvas/ # pure canvas state helpers + workflows
|
|
67
|
+
│ ├── commands/ # pure slash-command parsing
|
|
68
|
+
│ ├── host/ # local browser host adapter
|
|
69
|
+
│ ├── mcp/ # MCP HTTP client + response parsing
|
|
70
|
+
│ ├── semantic/ # pure canvas semantic rendering layer
|
|
71
|
+
│ ├── server/ # local MCP server lifecycle adapter
|
|
72
|
+
│ ├── store/ # project snapshot persistence
|
|
73
|
+
│ └── ui/ # Pi status widget adapter
|
|
74
|
+
├── test/ # pure helper/workflow/unit tests
|
|
75
|
+
├── bridge/ # source for the browser-side MCP Apps bridge bundle
|
|
76
|
+
├── scripts/ # reproducible build / verification / local e2e helpers
|
|
77
|
+
├── static/app-bridge-bundle.js
|
|
78
|
+
├── static/app-bridge-bundle.meta.json
|
|
79
|
+
├── static/host.html
|
|
80
|
+
├── mcp-app/ # packaged tldraw MCP app runtime when release assembly provides it
|
|
81
|
+
├── package.json # Pi package metadata
|
|
82
|
+
└── tsconfig.json
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Pi discovers the extension via:
|
|
86
|
+
|
|
87
|
+
```json
|
|
88
|
+
{
|
|
89
|
+
"pi": {
|
|
90
|
+
"extensions": ["./src/index.ts"]
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Build and release contract
|
|
96
|
+
|
|
97
|
+
- Users installing from npm should receive prebuilt browser assets; they should not compile the bridge during `pi install`.
|
|
98
|
+
- Maintainers build the bridge in CI from the source under `bridge/` before publishing.
|
|
99
|
+
- The npm tarball includes both source (`bridge/`, `scripts/`) and the generated artifact (`static/app-bridge-bundle.js`, `static/app-bridge-bundle.meta.json`).
|
|
100
|
+
- Git installs work from tagged commits because the generated static artifact is committed and verified by CI.
|
|
101
|
+
- The runtime contract remains the same: the extension auto-starts a local `mcp-app/` when the release package contains it, or uses `TLDRAW_MCP_APP_DIR` / a manually started server.
|
|
102
|
+
|
|
103
|
+
## Normal UX
|
|
104
|
+
|
|
105
|
+
Start or restore the current project canvas:
|
|
106
|
+
|
|
107
|
+
```text
|
|
108
|
+
/tldraw open
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Then work in the browser canvas. Edits are autosaved into the current project folder:
|
|
112
|
+
|
|
113
|
+
```text
|
|
114
|
+
.pi/tldraw-canvases/index.json
|
|
115
|
+
.pi/tldraw-canvases/<canvasId>.json
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
You should not need a manual save during normal use.
|
|
119
|
+
|
|
120
|
+
## Useful commands
|
|
121
|
+
|
|
122
|
+
```text
|
|
123
|
+
/tldraw open [canvasId] # Open/restore canvas; creates one if needed
|
|
124
|
+
/tldraw host # Show host/server/autosave diagnostics
|
|
125
|
+
/tldraw canvases # List saved project canvases
|
|
126
|
+
/tldraw current # Show current project canvas id
|
|
127
|
+
/tldraw restart # Restart local MCP app server
|
|
128
|
+
/tldraw save # Manual checkpoint; refuses unsafe blank overwrite
|
|
129
|
+
/tldraw save! # Force manual empty overwrite
|
|
130
|
+
/tldraw reset # Reset MCP HTTP session
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Agent tools
|
|
134
|
+
|
|
135
|
+
- `tldraw_canvas_open` — open/restore the local browser canvas host.
|
|
136
|
+
- `tldraw_diagram_tips` — get minimalist drawing guidance before creating or revising a diagram.
|
|
137
|
+
- `tldraw_canvas_export` — export the current selection or whole canvas as a PNG/SVG image for visual feedback.
|
|
138
|
+
- `tldraw_canvas_scene` — compact semantic canvas view; falls back to saved snapshots.
|
|
139
|
+
- `tldraw_canvas_state` — inspect live canvas state and optionally save it.
|
|
140
|
+
- `tldraw_canvas_exec` — execute JavaScript against the live tldraw editor.
|
|
141
|
+
- `tldraw_search` — inspect the tldraw Editor API via the MCP search tool.
|
|
142
|
+
- `tldraw_status` — check MCP server tools/resources.
|
|
143
|
+
|
|
144
|
+
## Persistence model
|
|
145
|
+
|
|
146
|
+
The durable source of truth is project-local JSON:
|
|
147
|
+
|
|
148
|
+
```text
|
|
149
|
+
<project>/.pi/tldraw-canvases/<canvasId>.json
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
The MCP server checkpoint store is treated as transient runtime state. If the browser port, MCP session, or Wrangler state changes, `/tldraw open` restores from the project snapshot.
|
|
153
|
+
|
|
154
|
+
Safety rules:
|
|
155
|
+
|
|
156
|
+
- Autosave and manual save refuse to overwrite a non-empty saved snapshot with an empty live canvas.
|
|
157
|
+
- Forced empty overwrite is available with `/tldraw save!`.
|
|
158
|
+
- Previous snapshots are copied to `.pi/tldraw-canvases/history/<canvasId>/` before overwrite.
|
|
159
|
+
|
|
160
|
+
## Development
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
npm install
|
|
164
|
+
npm run build # builds static/app-bridge-bundle.js from bridge/app-bridge-entry.js
|
|
165
|
+
npm run check
|
|
166
|
+
npm run pack:dry
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
The bridge bundle is intentionally prebuilt for users, but maintainers build it from source with `npm run build:bridge`. CI rebuilds it and fails if the committed artifact drifts from source.
|
|
170
|
+
|
|
171
|
+
The packaged MCP app is assembled from a built tldraw checkout and records OSS provenance in `mcp-app/PI_TLDRAW_PROVENANCE.json`:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
# source checkout must already have apps/mcp-app/dist/* built
|
|
175
|
+
export TLDRAW_MCP_APP_SOURCE_DIR=/path/to/tldraw/apps/mcp-app
|
|
176
|
+
npm run assemble:mcp-app
|
|
177
|
+
npm run verify:mcp-app
|
|
178
|
+
npm run verify:mcp-app-source
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
The source contract is declared in `mcp-app-source.json`: upstream tldraw repo, pinned commit, app path, build commands, and patch files under `patches/tldraw-mcp-app/`. The current packaged app is traceable to that pinned source plus `patches/tldraw-mcp-app/001-pi-runtime.patch`.
|
|
182
|
+
|
|
183
|
+
The packaged `mcp-app/` keeps the same runtime contract as before (`cd mcp-app && yarn dev`) but uses prebuilt `dist/` assets so users do not rebuild tldraw during install/startup.
|
|
184
|
+
|
|
185
|
+
For maintainers who want to rebuild from the pinned upstream source directly:
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
npm run assemble:mcp-app:pinned
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
This clones the pinned tldraw commit, applies declared patches, runs the manifest build commands, and assembles `mcp-app/`.
|
|
192
|
+
|
|
193
|
+
Release checklist:
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
npm ci
|
|
197
|
+
export TLDRAW_MCP_APP_SOURCE_DIR=/path/to/tldraw/apps/mcp-app
|
|
198
|
+
npm run assemble:mcp-app
|
|
199
|
+
npm run verify:mcp-app-source
|
|
200
|
+
npm run build
|
|
201
|
+
npm run check
|
|
202
|
+
npm run e2e:packaged-mcp-app
|
|
203
|
+
npm run pack:dry
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
GitHub Actions runs the same build/check path before publishing with npm provenance.
|
|
207
|
+
|
|
208
|
+
To smoke-test against a running tldraw MCP server:
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
# optional: defaults to http://127.0.0.1:8787/mcp
|
|
212
|
+
export TLDRAW_MCP_URL=http://127.0.0.1:8787/mcp
|
|
213
|
+
npm run e2e:mcp
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
To smoke-test the packaged MCP app itself on a temporary port:
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
npm run e2e:packaged-mcp-app
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Keep logic that does not need Pi APIs in separate modules, such as `src/store/project-store.ts`, so it can be unit-tested without mocking Pi.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { AppBridge, PostMessageTransport } from '@modelcontextprotocol/ext-apps/app-bridge'
|
|
2
|
+
|
|
3
|
+
// Browser host entry point for Pi's local tldraw iframe host.
|
|
4
|
+
// Keep this intentionally small: the build step owns bundling MCP Apps bridge
|
|
5
|
+
// dependencies into static/app-bridge-bundle.js for zero-build installs.
|
|
6
|
+
globalThis.McpAppsBridge = { AppBridge, PostMessageTransport }
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 tldraw Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"artifact": "mcp-app/",
|
|
3
|
+
"builder": "scripts/assemble-mcp-app.mjs",
|
|
4
|
+
"source": {
|
|
5
|
+
"mode": "local",
|
|
6
|
+
"repo": "https://github.com/tldraw/tldraw.git",
|
|
7
|
+
"commit": "4b0cfc539e074217e1e248461afa596fc7d02040",
|
|
8
|
+
"appPath": "apps/mcp-app",
|
|
9
|
+
"patches": [
|
|
10
|
+
{
|
|
11
|
+
"path": "patches/tldraw-mcp-app/001-pi-runtime.patch",
|
|
12
|
+
"sha256": "6bb0b7b7e9a2b9379bfe13800e4407c346b307e3e241d3c4ffe2f1876d1af894"
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
"build": [
|
|
16
|
+
{
|
|
17
|
+
"cwd": ".",
|
|
18
|
+
"command": "yarn install --immutable"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"cwd": "apps/mcp-app",
|
|
22
|
+
"command": "yarn build"
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"sourceGitCommit": "4b0cfc539e074217e1e248461afa596fc7d02040"
|
|
26
|
+
},
|
|
27
|
+
"dist": {
|
|
28
|
+
"mcp-app.html": "24af4cfaef84460f172dec501803960bf161f2faeab9c5eff8c6b0b3ace83c67",
|
|
29
|
+
"editor-api.json": "7298c0069c700f4b5db94a31ab3fbf742a64dc97442cf93f63616ab029153620",
|
|
30
|
+
"method-map.json": "e060b2860d245d07bddd9f2ad41398dd733328eba48234058854ac03f1bb828e"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# tldraw MCP app
|
|
2
|
+
|
|
3
|
+
This is the tldraw MCP app. It exposes an interactive tldraw canvas to AI agents via the [Model Context Protocol app specification](https://github.com/modelcontextprotocol/ext-apps/), so you can work in tldraw with agents in any MCP client that supports the MCP app spec.
|
|
4
|
+
|
|
5
|
+
## Architecture
|
|
6
|
+
|
|
7
|
+
The app has two parts: a **server** and a **widget**.
|
|
8
|
+
|
|
9
|
+
### Server
|
|
10
|
+
|
|
11
|
+
The server runs in Cloudflare Workers via `src/worker.ts`, using a Durable Object (`TldrawMCP`) backed by SQLite for persistent checkpoint storage.
|
|
12
|
+
|
|
13
|
+
It exposes:
|
|
14
|
+
|
|
15
|
+
- `search` — query the extracted Editor API spec in a sandboxed dynamic worker
|
|
16
|
+
- `exec` — execute JavaScript against the live editor in the widget via a pending-request callback bridge
|
|
17
|
+
- `_exec_callback` — app-only tool the widget calls to resolve a pending `exec` request
|
|
18
|
+
- `save_checkpoint` / `read_checkpoint` — app-only tools used by the widget for checkpoint persistence
|
|
19
|
+
|
|
20
|
+
### Widget
|
|
21
|
+
|
|
22
|
+
The widget is a React app (`src/widget/mcp-app.tsx`) that renders a full tldraw canvas inside the MCP host's iframe.
|
|
23
|
+
|
|
24
|
+
When the AI calls `exec`, the server creates a pending request and the widget picks it up, runs the code through a focused editor proxy (`src/widget/focused/`) that translates between an AI-friendly shape format (simple string IDs, flat `_type` shapes) and tldraw's internal `TLShape`/`TLShapeId` types, then calls `_exec_callback` to resolve the pending request with the result. Canvas state is checkpointed to the Durable Object's SQLite database and to the browser's local storage.
|
|
25
|
+
|
|
26
|
+
## Developing
|
|
27
|
+
|
|
28
|
+
### Prerequisites
|
|
29
|
+
|
|
30
|
+
The widget build depends on generated files (`editor-api.json`, `method-map.json`) that are extracted from the editor's TypeScript declarations. Before you can develop or build the mcp-app, you need to build the core packages first:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# from the repo root
|
|
34
|
+
yarn build
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
This produces the `.tsbuild/` output that `yarn extract-api` reads from. The `build` and `dev` scripts run `extract-api` automatically, so you don't need to call it separately.
|
|
38
|
+
|
|
39
|
+
### Package scripts
|
|
40
|
+
|
|
41
|
+
Run all commands from `apps/mcp-app`.
|
|
42
|
+
|
|
43
|
+
| Command | What it does |
|
|
44
|
+
| ----------------- | -------------------------------------------------------------------------------------------------- |
|
|
45
|
+
| `yarn build` | Build the widget HTML |
|
|
46
|
+
| `yarn dev` | Build widget + start local Cloudflare worker (HTTP MCP on `localhost:8787`) |
|
|
47
|
+
| `yarn dev:tunnel` | Build widget + start a Cloudflare tunnel + local worker with `WORKER_ORIGIN` set to the tunnel URL |
|
|
48
|
+
| `yarn deploy` | Build widget + deploy the Cloudflare worker to production |
|
|
49
|
+
|
|
50
|
+
`yarn dev:tunnel` requires the `cloudflared` CLI to be installed on your machine.
|
|
51
|
+
|
|
52
|
+
The worker defaults to production-safe behavior in `wrangler.toml`, including setting `MCP_IS_DEV="false"`. Local HTTP dev scripts override that with `MCP_IS_DEV=true` so local Claude/ChatGPT connectors suppress `ui.domain` while production deployments keep it enabled.
|
|
53
|
+
|
|
54
|
+
### Cursor setup
|
|
55
|
+
|
|
56
|
+
Add these two servers in `~/.cursor/mcp.json`:
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"mcpServers": {
|
|
61
|
+
"tldraw": {
|
|
62
|
+
"transport": "http",
|
|
63
|
+
"url": "https://tldraw-mcp-app.tldraw.workers.dev/mcp"
|
|
64
|
+
},
|
|
65
|
+
"tldraw-local": {
|
|
66
|
+
"command": "npx",
|
|
67
|
+
"args": ["-y", "mcp-remote", "http://127.0.0.1:8787/mcp"]
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Claude Desktop local setup
|
|
74
|
+
|
|
75
|
+
For local Claude Desktop development, use `claude_desktop_config.json` with the local HTTP server:
|
|
76
|
+
|
|
77
|
+
```json
|
|
78
|
+
{
|
|
79
|
+
"mcpServers": {
|
|
80
|
+
"tldraw-local": {
|
|
81
|
+
"command": "npx",
|
|
82
|
+
"args": ["-y", "mcp-remote", "http://127.0.0.1:8787/mcp"]
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Claude Desktop remote setup
|
|
89
|
+
|
|
90
|
+
If you'd like to try the remote MCP server in Claude Desktop, use the in-app connector flow rather than adding the production URL to `claude_desktop_config.json`.
|
|
91
|
+
|
|
92
|
+
1. Open Claude Desktop
|
|
93
|
+
2. In the sidebar, go to **Customize**
|
|
94
|
+
3. Open **Connectors**
|
|
95
|
+
4. Click the button to add a connector, then choose **Add custom connector**
|
|
96
|
+
5. Give it a name such as `tldraw`
|
|
97
|
+
6. Paste `https://tldraw-mcp-app.tldraw.workers.dev/mcp` as the server URL
|
|
98
|
+
|
|
99
|
+
The **Add custom connector** option is not available on the free plan, so you may need Max or another paid plan.
|
|
100
|
+
|
|
101
|
+
If you need Notion access in Claude Desktop, use the Notion MCP connector for that separately.
|
|
102
|
+
|
|
103
|
+
### ChatGPT local dev
|
|
104
|
+
|
|
105
|
+
ChatGPT requires an HTTPS origin, so you need a Cloudflare tunnel. You must be an admin of your OpenAI org/workspace to do local dev.
|
|
106
|
+
|
|
107
|
+
1. Run `yarn dev:tunnel` in `apps/mcp-app`
|
|
108
|
+
2. It prints a `https://...trycloudflare.com` tunnel URL
|
|
109
|
+
3. In ChatGPT web (not the desktop app), go to **Apps** and add your app using that tunnel URL
|
|
110
|
+
4. You can then test in both ChatGPT web and the desktop or mobile apps
|
|
111
|
+
|
|
112
|
+
`dev:tunnel` automatically wires `WORKER_ORIGIN` to the tunnel URL and sets `MCP_IS_DEV=true` for the local worker.
|
|
113
|
+
|
|
114
|
+
### Iteration loop
|
|
115
|
+
|
|
116
|
+
1. Make code changes in `apps/mcp-app`
|
|
117
|
+
2. Run the relevant script (`dev` or `dev:tunnel`)
|
|
118
|
+
3. Disconnect and reconnect the MCP server in your client (or reload the page/app)
|
|
119
|
+
4. When making widget changes, make sure to rebuild, either by running `yarn build` or rerunning any of the dev scripts.
|
|
120
|
+
|
|
121
|
+
Reconnecting the server after changes is the most reliable way to pick up new code, especially when the widget HTML changes.
|
|
122
|
+
|
|
123
|
+
## Contact
|
|
124
|
+
|
|
125
|
+
Find us on Twitter/X at [@tldraw](https://twitter.com/tldraw).
|
|
126
|
+
|
|
127
|
+
## Community
|
|
128
|
+
|
|
129
|
+
Have questions, comments or feedback? [Join our discord](https://discord.tldraw.com/?utm_source=github&utm_medium=readme&utm_campaign=sociallink). For the latest news and release notes, visit [tldraw.dev](https://tldraw.dev).
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Starts a cloudflared tunnel + wrangler dev with the tunnel URL as WORKER_ORIGIN.
|
|
3
|
+
# Usage: ./dev-tunnel.sh
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
|
|
6
|
+
PORT="${PORT:-8787}"
|
|
7
|
+
LOGFILE=$(mktemp)
|
|
8
|
+
|
|
9
|
+
# Build widget first
|
|
10
|
+
echo "Building widget..."
|
|
11
|
+
yarn build:widget
|
|
12
|
+
|
|
13
|
+
# Start cloudflared in background, capture the tunnel URL from stderr
|
|
14
|
+
cloudflared tunnel --url "http://localhost:$PORT" 2>"$LOGFILE" &
|
|
15
|
+
CF_PID=$!
|
|
16
|
+
|
|
17
|
+
cleanup() {
|
|
18
|
+
echo "Stopping cloudflared (pid $CF_PID)..."
|
|
19
|
+
kill "$CF_PID" 2>/dev/null || true
|
|
20
|
+
rm -f "$LOGFILE"
|
|
21
|
+
}
|
|
22
|
+
trap cleanup EXIT
|
|
23
|
+
|
|
24
|
+
# Wait for cloudflared to print the tunnel URL
|
|
25
|
+
echo "Waiting for tunnel URL..."
|
|
26
|
+
TUNNEL_URL=""
|
|
27
|
+
for i in $(seq 1 30); do
|
|
28
|
+
TUNNEL_URL=$(grep -o 'https://[a-z0-9-]*\.trycloudflare\.com' "$LOGFILE" | head -1 || true)
|
|
29
|
+
if [ -n "$TUNNEL_URL" ]; then
|
|
30
|
+
break
|
|
31
|
+
fi
|
|
32
|
+
sleep 1
|
|
33
|
+
done
|
|
34
|
+
|
|
35
|
+
if [ -z "$TUNNEL_URL" ]; then
|
|
36
|
+
echo "ERROR: Failed to get tunnel URL after 30s. cloudflared log:"
|
|
37
|
+
cat "$LOGFILE"
|
|
38
|
+
exit 1
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
echo ""
|
|
42
|
+
echo "==================================="
|
|
43
|
+
echo "Tunnel URL: $TUNNEL_URL"
|
|
44
|
+
echo "==================================="
|
|
45
|
+
echo ""
|
|
46
|
+
echo "Update claude_desktop_config.json to use:"
|
|
47
|
+
echo " \"args\": [\"-y\", \"mcp-remote\", \"$TUNNEL_URL/mcp\"]"
|
|
48
|
+
echo ""
|
|
49
|
+
|
|
50
|
+
# Start wrangler with the tunnel URL as WORKER_ORIGIN in dev mode
|
|
51
|
+
exec wrangler dev --port "$PORT" --var "WORKER_ORIGIN:$TUNNEL_URL" --var "MCP_IS_DEV:true"
|