@excalimate/mcp-server 0.1.0 → 0.3.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/README.md +176 -16
- package/dist/checkpoint-store.d.ts +1 -0
- package/dist/checkpoint-store.d.ts.map +1 -1
- package/dist/checkpoint-store.js +23 -2
- package/dist/checkpoint-store.js.map +1 -1
- package/dist/httpServer.d.ts +4 -0
- package/dist/httpServer.d.ts.map +1 -0
- package/dist/httpServer.js +199 -0
- package/dist/httpServer.js.map +1 -0
- package/dist/index.d.ts +0 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +35 -177
- package/dist/index.js.map +1 -1
- package/dist/server/animationTools.d.ts +9 -0
- package/dist/server/animationTools.d.ts.map +1 -0
- package/dist/server/animationTools.js +254 -0
- package/dist/server/animationTools.js.map +1 -0
- package/dist/server/checkpointTools.d.ts +5 -0
- package/dist/server/checkpointTools.d.ts.map +1 -0
- package/dist/server/checkpointTools.js +22 -0
- package/dist/server/checkpointTools.js.map +1 -0
- package/dist/server/elementNormalizer.d.ts +3 -0
- package/dist/server/elementNormalizer.d.ts.map +1 -0
- package/dist/server/elementNormalizer.js +52 -0
- package/dist/server/elementNormalizer.js.map +1 -0
- package/dist/server/geometry.d.ts +24 -0
- package/dist/server/geometry.d.ts.map +1 -0
- package/dist/server/geometry.js +102 -0
- package/dist/server/geometry.js.map +1 -0
- package/dist/server/queryTools.d.ts +28 -0
- package/dist/server/queryTools.d.ts.map +1 -0
- package/dist/server/queryTools.js +107 -0
- package/dist/server/queryTools.js.map +1 -0
- package/dist/server/referenceText.d.ts +3 -0
- package/dist/server/referenceText.d.ts.map +1 -0
- package/dist/server/referenceText.js +268 -0
- package/dist/server/referenceText.js.map +1 -0
- package/dist/server/sceneTools.d.ts +4 -0
- package/dist/server/sceneTools.d.ts.map +1 -0
- package/dist/server/sceneTools.js +86 -0
- package/dist/server/sceneTools.js.map +1 -0
- package/dist/server/shareTools.d.ts +11 -0
- package/dist/server/shareTools.d.ts.map +1 -0
- package/dist/server/shareTools.js +81 -0
- package/dist/server/shareTools.js.map +1 -0
- package/dist/server/stateContext.d.ts +21 -0
- package/dist/server/stateContext.d.ts.map +1 -0
- package/dist/server/stateContext.js +85 -0
- package/dist/server/stateContext.js.map +1 -0
- package/dist/server.d.ts +5 -10
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +24 -891
- package/dist/server.js.map +1 -1
- package/dist/shareRoutes.d.ts +4 -0
- package/dist/shareRoutes.d.ts.map +1 -0
- package/dist/shareRoutes.js +44 -0
- package/dist/shareRoutes.js.map +1 -0
- package/dist/stdioServer.d.ts +3 -0
- package/dist/stdioServer.d.ts.map +1 -0
- package/dist/stdioServer.js +5 -0
- package/dist/stdioServer.js.map +1 -0
- package/package.json +6 -2
- package/SKILL.md +0 -110
- package/references/REFERENCE.md +0 -192
package/README.md
CHANGED
|
@@ -2,47 +2,199 @@
|
|
|
2
2
|
|
|
3
3
|
Excalimate MCP server for creating Excalidraw designs and animating them with keyframes. Designed for AI agent integration (Claude Desktop, Copilot CLI, etc.).
|
|
4
4
|
|
|
5
|
+
**Pair with [excalimate.com](https://excalimate.com) for real-time live preview** — the AI creates and animates, you watch it happen in your browser.
|
|
6
|
+
|
|
7
|
+
## Getting Started with excalimate.com
|
|
8
|
+
|
|
9
|
+
The fastest way to use Excalimate with AI is to combine the deployed web app with this npm package. No cloning, no building — just install and go.
|
|
10
|
+
|
|
11
|
+
### Step 1: Start the MCP server
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npx @excalimate/mcp-server
|
|
15
|
+
# → Listening on http://localhost:3001/mcp
|
|
16
|
+
# → Live preview SSE at http://localhost:3001/live
|
|
17
|
+
|
|
18
|
+
# Custom port:
|
|
19
|
+
npx @excalimate/mcp-server --port 4000
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Port priority: CLI arg (`--port` / `-p`) > `PORT` env var > default `3001`.
|
|
23
|
+
Also supports `--port=4000` syntax.
|
|
24
|
+
|
|
25
|
+
Or install globally:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install -g @excalimate/mcp-server
|
|
29
|
+
excalimate-mcp
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Step 2: Open the web app
|
|
33
|
+
|
|
34
|
+
Go to [excalimate.com](https://excalimate.com) in your browser and click **📡 Live** in the toolbar. The app connects to `localhost:3001` automatically.
|
|
35
|
+
|
|
36
|
+
You can configure the MCP server URL in **File → Preferences**. The app persists this setting in localStorage, shows connection progress (progress bar + notifications), provides smart error dialogs, and warns about HTTPS→HTTP mixed-content connections.
|
|
37
|
+
|
|
38
|
+
### Step 3: Connect your AI
|
|
39
|
+
|
|
40
|
+
Point your AI tool to `http://localhost:3001/mcp` as an MCP server. Then ask it to create a diagram and animate it — you'll see elements appear and animate in your browser in real-time.
|
|
41
|
+
|
|
42
|
+
**That's it.** The AI draws and animates, you see it live, and you can edit alongside it.
|
|
43
|
+
|
|
5
44
|
## Features
|
|
6
45
|
|
|
7
|
-
- **
|
|
46
|
+
- **23 tools** for scene creation, animation, camera control, export, checkpointing, and sharing
|
|
8
47
|
- **Dual transport**: stdio (Claude Desktop) + Streamable HTTP (cloud deployment)
|
|
48
|
+
- **Live preview**: Real-time updates in [excalimate.com](https://excalimate.com) via SSE
|
|
9
49
|
- **Sequence reveal**: Staggered element reveal animations in one tool call
|
|
10
50
|
- **Camera animation**: Pan/zoom keyframes for cinematic effects
|
|
11
51
|
- **Checkpoint persistence**: Save/load complete scene + animation state
|
|
52
|
+
- **Runtime versioning**: Server version is read from `package.json`
|
|
53
|
+
|
|
54
|
+
## Installation & Usage
|
|
12
55
|
|
|
13
|
-
|
|
56
|
+
### HTTP mode (recommended — enables live preview)
|
|
14
57
|
|
|
15
58
|
```bash
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
npm install
|
|
59
|
+
npx @excalimate/mcp-server
|
|
60
|
+
# → http://localhost:3001/mcp
|
|
19
61
|
|
|
20
|
-
#
|
|
21
|
-
|
|
62
|
+
# Custom port:
|
|
63
|
+
npx @excalimate/mcp-server -p 4000
|
|
64
|
+
```
|
|
22
65
|
|
|
23
|
-
|
|
24
|
-
node dist/index.js --stdio
|
|
66
|
+
Open [excalimate.com](https://excalimate.com) and click **📡 Live**, then configure your AI tool below.
|
|
25
67
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
68
|
+
### Configure your AI tool
|
|
69
|
+
|
|
70
|
+
<details>
|
|
71
|
+
<summary><strong>VS Code (GitHub Copilot) — ✅ live preview</strong></summary>
|
|
72
|
+
|
|
73
|
+
Add to your VS Code MCP config (`.vscode/mcp.json` or user-level `mcp.json`):
|
|
74
|
+
|
|
75
|
+
**HTTP mode (recommended — live preview works):**
|
|
76
|
+
|
|
77
|
+
```jsonc
|
|
78
|
+
{
|
|
79
|
+
"servers": {
|
|
80
|
+
"excalimate": {
|
|
81
|
+
"type": "http",
|
|
82
|
+
"url": "http://localhost:3001/mcp"
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
29
86
|
```
|
|
30
87
|
|
|
31
|
-
|
|
88
|
+
Start the MCP server first (`npx @excalimate/mcp-server`), open [excalimate.com](https://excalimate.com), click **📡 Live**, then ask Copilot to create a diagram. You'll see it appear in real-time.
|
|
32
89
|
|
|
33
|
-
|
|
90
|
+
**stdio mode (no live preview):**
|
|
91
|
+
|
|
92
|
+
```jsonc
|
|
93
|
+
{
|
|
94
|
+
"servers": {
|
|
95
|
+
"excalimate": {
|
|
96
|
+
"type": "stdio",
|
|
97
|
+
"command": "npx",
|
|
98
|
+
"args": ["@excalimate/mcp-server", "--stdio"]
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
</details>
|
|
105
|
+
|
|
106
|
+
<details>
|
|
107
|
+
<summary><strong>Claude Desktop — stdio only (no live preview)</strong></summary>
|
|
108
|
+
|
|
109
|
+
Add to your `claude_desktop_config.json`:
|
|
34
110
|
|
|
35
111
|
```json
|
|
36
112
|
{
|
|
37
113
|
"mcpServers": {
|
|
38
114
|
"excalimate": {
|
|
39
|
-
"command": "
|
|
40
|
-
"args": ["/
|
|
115
|
+
"command": "npx",
|
|
116
|
+
"args": ["@excalimate/mcp-server", "--stdio"]
|
|
41
117
|
}
|
|
42
118
|
}
|
|
43
119
|
}
|
|
44
120
|
```
|
|
45
121
|
|
|
122
|
+
Claude Desktop uses stdio transport, so there's no live preview. The AI creates scenes and animations, then use `save_checkpoint` to save state and load it in [excalimate.com](https://excalimate.com) via the **MCP** button in the toolbar.
|
|
123
|
+
|
|
124
|
+
</details>
|
|
125
|
+
|
|
126
|
+
<details>
|
|
127
|
+
<summary><strong>Claude Code (CLI) — ✅ live preview</strong></summary>
|
|
128
|
+
|
|
129
|
+
Claude Code supports HTTP MCP servers. Start the server first, then add it:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
npx @excalimate/mcp-server &
|
|
133
|
+
claude mcp add excalimate http://localhost:3001/mcp
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Open [excalimate.com](https://excalimate.com) and click **📡 Live** — you'll see the AI's changes in real-time.
|
|
137
|
+
|
|
138
|
+
</details>
|
|
139
|
+
|
|
140
|
+
<details>
|
|
141
|
+
<summary><strong>Cursor — ✅ live preview</strong></summary>
|
|
142
|
+
|
|
143
|
+
In Cursor settings, go to **MCP Servers** and add:
|
|
144
|
+
|
|
145
|
+
- **Name:** `excalimate`
|
|
146
|
+
- **Type:** `http`
|
|
147
|
+
- **URL:** `http://localhost:3001/mcp`
|
|
148
|
+
|
|
149
|
+
Start the MCP server (`npx @excalimate/mcp-server`), open [excalimate.com](https://excalimate.com), click **📡 Live**, then use Cursor's agent to create diagrams with live preview.
|
|
150
|
+
|
|
151
|
+
</details>
|
|
152
|
+
|
|
153
|
+
<details>
|
|
154
|
+
<summary><strong>Windsurf — ✅ live preview</strong></summary>
|
|
155
|
+
|
|
156
|
+
Add to your Windsurf MCP config:
|
|
157
|
+
|
|
158
|
+
```json
|
|
159
|
+
{
|
|
160
|
+
"mcpServers": {
|
|
161
|
+
"excalimate": {
|
|
162
|
+
"serverUrl": "http://localhost:3001/mcp"
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Start the MCP server, open [excalimate.com](https://excalimate.com), click **📡 Live**, and use Cascade to create animated diagrams in real-time.
|
|
169
|
+
|
|
170
|
+
</details>
|
|
171
|
+
|
|
172
|
+
<details>
|
|
173
|
+
<summary><strong>Any HTTP-compatible MCP client — ✅ live preview</strong></summary>
|
|
174
|
+
|
|
175
|
+
Point your MCP client to:
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
http://localhost:3001/mcp
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Start the server with `npx @excalimate/mcp-server`, open [excalimate.com](https://excalimate.com), and click **📡 Live**. Any tool that supports Streamable HTTP MCP transport will work with live preview.
|
|
182
|
+
|
|
183
|
+
</details>
|
|
184
|
+
|
|
185
|
+
> **Tip:** HTTP mode (the default) is always preferred — it enables live preview so you can watch the AI build your animation in real-time. stdio mode is only needed for tools that don't support HTTP transport (like Claude Desktop).
|
|
186
|
+
|
|
187
|
+
### From source (for development)
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
cd mcp-server
|
|
191
|
+
npm install
|
|
192
|
+
npm run build
|
|
193
|
+
node dist/index.js # HTTP mode
|
|
194
|
+
node dist/index.js --port 4000
|
|
195
|
+
node dist/index.js --stdio # stdio mode
|
|
196
|
+
```
|
|
197
|
+
|
|
46
198
|
## Tools
|
|
47
199
|
|
|
48
200
|
### Scene Tools
|
|
@@ -84,6 +236,13 @@ Add to `claude_desktop_config.json`:
|
|
|
84
236
|
| `items_visible_in_camera` | Report visibility of items at a given time |
|
|
85
237
|
| `animations_of_item` | Describe all animations of an element |
|
|
86
238
|
|
|
239
|
+
### Sharing Tools
|
|
240
|
+
| Tool | Description |
|
|
241
|
+
|------|-------------|
|
|
242
|
+
| `share_project` | Create E2E encrypted share URL for the current project |
|
|
243
|
+
|
|
244
|
+
`share_project` accepts `{ baseUrl?: string }` and defaults to `https://excalimate.com`, returning URLs like `https://excalimate.com/#share=ID,KEY`.
|
|
245
|
+
|
|
87
246
|
### Checkpoint Tools
|
|
88
247
|
| Tool | Description |
|
|
89
248
|
|------|-------------|
|
|
@@ -105,4 +264,5 @@ Add to `claude_desktop_config.json`:
|
|
|
105
264
|
}
|
|
106
265
|
4. set_clip_range {0, 5000} → Set 5-second export window
|
|
107
266
|
5. save_checkpoint {id: "demo"} → Save for web app preview
|
|
267
|
+
or share_project {baseUrl: "https://excalimate.com"} → Generate E2E encrypted share URL
|
|
108
268
|
```
|
|
@@ -13,6 +13,7 @@ export declare class FileCheckpointStore implements CheckpointStore {
|
|
|
13
13
|
save(id: string, data: ServerState): Promise<void>;
|
|
14
14
|
load(id: string): Promise<ServerState | null>;
|
|
15
15
|
list(): Promise<string[]>;
|
|
16
|
+
private _pruning;
|
|
16
17
|
private prune;
|
|
17
18
|
}
|
|
18
19
|
export declare class MemoryCheckpointStore implements CheckpointStore {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkpoint-store.d.ts","sourceRoot":"","sources":["../src/checkpoint-store.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAW9C,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC9C,IAAI,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CAC3B;AAED,qBAAa,mBAAoB,YAAW,eAAe;IACzD,OAAO,CAAC,GAAG,CAAS;;IAOd,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAclD,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAc7C,IAAI,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"checkpoint-store.d.ts","sourceRoot":"","sources":["../src/checkpoint-store.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAW9C,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC9C,IAAI,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CAC3B;AAED,qBAAa,mBAAoB,YAAW,eAAe;IACzD,OAAO,CAAC,GAAG,CAAS;;IAOd,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAclD,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAc7C,IAAI,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAS/B,OAAO,CAAC,QAAQ,CAAS;YAEX,KAAK;CAiCpB;AAED,qBAAa,qBAAsB,YAAW,eAAe;IAC3D,OAAO,CAAC,KAAK,CAA6B;IAEpC,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAWlD,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAO7C,IAAI,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;CAGhC"}
|
package/dist/checkpoint-store.js
CHANGED
|
@@ -53,7 +53,12 @@ export class FileCheckpointStore {
|
|
|
53
53
|
return [];
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
|
+
_pruning = false;
|
|
56
57
|
async prune() {
|
|
58
|
+
// Serialize prune operations to avoid concurrent filesystem races
|
|
59
|
+
if (this._pruning)
|
|
60
|
+
return;
|
|
61
|
+
this._pruning = true;
|
|
57
62
|
try {
|
|
58
63
|
const entries = await fs.promises.readdir(this.dir);
|
|
59
64
|
const jsonFiles = entries.filter(f => f.endsWith('.json'));
|
|
@@ -65,9 +70,25 @@ export class FileCheckpointStore {
|
|
|
65
70
|
})));
|
|
66
71
|
stats.sort((a, b) => a.mtime - b.mtime);
|
|
67
72
|
const toRemove = stats.slice(0, stats.length - MAX_CHECKPOINTS);
|
|
68
|
-
await Promise.all(toRemove.map(
|
|
73
|
+
await Promise.all(toRemove.map(async (f) => {
|
|
74
|
+
try {
|
|
75
|
+
await fs.promises.unlink(path.join(this.dir, f.name));
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
const code = err.code;
|
|
79
|
+
// ENOENT is expected (concurrent delete) — log anything else
|
|
80
|
+
if (code !== 'ENOENT') {
|
|
81
|
+
console.warn(`[checkpoint] Failed to prune ${f.name}:`, err);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}));
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
console.warn('[checkpoint] Prune scan failed:', err);
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
this._pruning = false;
|
|
69
91
|
}
|
|
70
|
-
catch { /* best-effort */ }
|
|
71
92
|
}
|
|
72
93
|
}
|
|
73
94
|
export class MemoryCheckpointStore {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkpoint-store.js","sourceRoot":"","sources":["../src/checkpoint-store.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"checkpoint-store.js","sourceRoot":"","sources":["../src/checkpoint-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { Response } from 'express';
|
|
3
|
+
export declare function startHTTPServer(factoryWithSSE: (sseClients: Set<Response>, broadcastSSE: (data: string) => void, port: number) => McpServer, portOverride?: number): Promise<void>;
|
|
4
|
+
//# sourceMappingURL=httpServer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"httpServer.d.ts","sourceRoot":"","sources":["../src/httpServer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAOzE,OAAO,KAAK,EAAW,QAAQ,EAAE,MAAM,SAAS,CAAC;AAwCjD,wBAAsB,eAAe,CACnC,cAAc,EAAE,CAAC,UAAU,EAAE,GAAG,CAAC,QAAQ,CAAC,EAAE,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,EAAE,IAAI,EAAE,MAAM,KAAK,SAAS,EAC5G,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CAoLf"}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
2
|
+
import cors from 'cors';
|
|
3
|
+
import crypto from 'node:crypto';
|
|
4
|
+
import express from 'express';
|
|
5
|
+
import helmet from 'helmet';
|
|
6
|
+
import rateLimit from 'express-rate-limit';
|
|
7
|
+
import { getSharedState } from './server.js';
|
|
8
|
+
import { registerShareRoutes } from './shareRoutes.js';
|
|
9
|
+
function getCorsOrigin() {
|
|
10
|
+
const raw = process.env.CORS_ORIGIN;
|
|
11
|
+
// No CORS origin configured: allow local dev + production domains
|
|
12
|
+
if (!raw || !raw.trim()) {
|
|
13
|
+
return ['http://localhost:5173', 'https://excalimate.com', 'https://www.excalimate.com'];
|
|
14
|
+
}
|
|
15
|
+
const origins = raw
|
|
16
|
+
.split(',')
|
|
17
|
+
.map((o) => o.trim())
|
|
18
|
+
.filter((o) => o.length > 0);
|
|
19
|
+
if (origins.length === 0) {
|
|
20
|
+
return ['http://localhost:5173', 'https://excalimate.com', 'https://www.excalimate.com'];
|
|
21
|
+
}
|
|
22
|
+
if (origins.length === 1) {
|
|
23
|
+
return origins[0];
|
|
24
|
+
}
|
|
25
|
+
// Multiple allowed origins: validate incoming origin against the list
|
|
26
|
+
return (origin, callback) => {
|
|
27
|
+
// Allow requests without an Origin header (e.g., same-origin or non-browser clients)
|
|
28
|
+
if (!origin) {
|
|
29
|
+
return callback(null, true);
|
|
30
|
+
}
|
|
31
|
+
if (origins.includes(origin)) {
|
|
32
|
+
return callback(null, true);
|
|
33
|
+
}
|
|
34
|
+
return callback(new Error('Not allowed by CORS'), false);
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export async function startHTTPServer(factoryWithSSE, portOverride) {
|
|
38
|
+
const port = portOverride ?? parseInt(process.env.PORT ?? '3001', 10);
|
|
39
|
+
const app = express();
|
|
40
|
+
app.use(helmet()); // Security headers
|
|
41
|
+
app.use(cors({
|
|
42
|
+
origin: getCorsOrigin(),
|
|
43
|
+
}));
|
|
44
|
+
// Rate limiting
|
|
45
|
+
const limiter = rateLimit({
|
|
46
|
+
windowMs: 60 * 1000, // 1 minute
|
|
47
|
+
max: 200, // 200 requests per minute
|
|
48
|
+
standardHeaders: true,
|
|
49
|
+
legacyHeaders: false,
|
|
50
|
+
});
|
|
51
|
+
app.use(limiter);
|
|
52
|
+
// Stricter rate limit for share uploads
|
|
53
|
+
const shareLimiter = rateLimit({
|
|
54
|
+
windowMs: 60 * 1000,
|
|
55
|
+
max: 10, // 10 shares per minute
|
|
56
|
+
standardHeaders: true,
|
|
57
|
+
legacyHeaders: false,
|
|
58
|
+
});
|
|
59
|
+
const jsonMiddleware = express.json();
|
|
60
|
+
// Parse JSON only for non-share routes (share uses raw binary)
|
|
61
|
+
app.use((req, res, next) => {
|
|
62
|
+
if (req.path === '/share' && req.method === 'POST') {
|
|
63
|
+
next();
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
jsonMiddleware(req, res, next);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
// SSE clients for live state broadcasting
|
|
70
|
+
const sseClients = new Set();
|
|
71
|
+
/** Safely broadcast to all SSE clients, removing dead ones on failure. */
|
|
72
|
+
function broadcastSSE(data) {
|
|
73
|
+
for (const client of sseClients) {
|
|
74
|
+
try {
|
|
75
|
+
client.write(`data: ${data}\n\n`);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
sseClients.delete(client);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Factory that wires SSE broadcasting
|
|
83
|
+
const factory = () => factoryWithSSE(sseClients, broadcastSSE, port);
|
|
84
|
+
// Session map: keep server + transport alive across requests
|
|
85
|
+
const sessions = new Map();
|
|
86
|
+
// Periodically clean up stale sessions (no activity for 30 minutes)
|
|
87
|
+
const SESSION_TTL_MS = 30 * 60 * 1000;
|
|
88
|
+
const sessionCleanupTimer = setInterval(() => {
|
|
89
|
+
const now = Date.now();
|
|
90
|
+
for (const [sid, session] of sessions) {
|
|
91
|
+
if (now - session.lastActivity > SESSION_TTL_MS) {
|
|
92
|
+
sessions.delete(sid);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}, 60 * 1000);
|
|
96
|
+
sessionCleanupTimer.unref();
|
|
97
|
+
app.all('/mcp', async (req, res) => {
|
|
98
|
+
const sessionId = req.headers['mcp-session-id'];
|
|
99
|
+
// Route to existing session
|
|
100
|
+
if (sessionId && sessions.has(sessionId)) {
|
|
101
|
+
const session = sessions.get(sessionId);
|
|
102
|
+
session.lastActivity = Date.now();
|
|
103
|
+
try {
|
|
104
|
+
await session.transport.handleRequest(req, res, req.body);
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
console.error('MCP session error:', error);
|
|
108
|
+
if (!res.headersSent) {
|
|
109
|
+
res.status(500).json({
|
|
110
|
+
jsonrpc: '2.0',
|
|
111
|
+
error: { code: -32603, message: 'Internal server error' },
|
|
112
|
+
id: null,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
// New session
|
|
119
|
+
const server = factory();
|
|
120
|
+
const transport = new StreamableHTTPServerTransport({
|
|
121
|
+
sessionIdGenerator: () => crypto.randomUUID(),
|
|
122
|
+
});
|
|
123
|
+
transport.onclose = () => {
|
|
124
|
+
const sid = transport.sessionId;
|
|
125
|
+
if (sid)
|
|
126
|
+
sessions.delete(sid);
|
|
127
|
+
// Don't call server.close() here — it would call transport.close()
|
|
128
|
+
// again, causing infinite recursion. The SDK handles cleanup internally.
|
|
129
|
+
};
|
|
130
|
+
try {
|
|
131
|
+
await server.connect(transport);
|
|
132
|
+
await transport.handleRequest(req, res, req.body);
|
|
133
|
+
// Store session after first successful request (session ID is now set)
|
|
134
|
+
const sid = transport.sessionId;
|
|
135
|
+
if (sid) {
|
|
136
|
+
sessions.set(sid, { server, transport, lastActivity: Date.now() });
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
console.error('MCP error:', error);
|
|
141
|
+
if (!res.headersSent) {
|
|
142
|
+
res.status(500).json({
|
|
143
|
+
jsonrpc: '2.0',
|
|
144
|
+
error: { code: -32603, message: 'Internal server error' },
|
|
145
|
+
id: null,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
// SSE endpoint — web app connects here to receive live state updates
|
|
151
|
+
app.get('/live', (req, res) => {
|
|
152
|
+
res.writeHead(200, {
|
|
153
|
+
'Content-Type': 'text/event-stream',
|
|
154
|
+
'Cache-Control': 'no-cache',
|
|
155
|
+
Connection: 'keep-alive',
|
|
156
|
+
'Access-Control-Allow-Origin': '*',
|
|
157
|
+
});
|
|
158
|
+
res.write('data: {"type":"connected"}\n\n');
|
|
159
|
+
sseClients.add(res);
|
|
160
|
+
req.on('close', () => sseClients.delete(res));
|
|
161
|
+
});
|
|
162
|
+
// Current state endpoint
|
|
163
|
+
app.get('/state', (_req, res) => {
|
|
164
|
+
res.json(getSharedState());
|
|
165
|
+
});
|
|
166
|
+
// ── E2E Encrypted Sharing ──────────────────────────────────────
|
|
167
|
+
// The server only stores encrypted blobs. It never sees the encryption key.
|
|
168
|
+
registerShareRoutes(app, shareLimiter);
|
|
169
|
+
const httpServer = app.listen(port, () => {
|
|
170
|
+
console.log(`Excalimate MCP server listening on http://localhost:${port}/mcp`);
|
|
171
|
+
console.log(`Live preview SSE at http://localhost:${port}/live`);
|
|
172
|
+
});
|
|
173
|
+
let shuttingDown = false;
|
|
174
|
+
const shutdown = async () => {
|
|
175
|
+
if (shuttingDown)
|
|
176
|
+
return;
|
|
177
|
+
shuttingDown = true;
|
|
178
|
+
console.log('\nGraceful shutdown started...');
|
|
179
|
+
// 1. Stop accepting new connections
|
|
180
|
+
httpServer.close();
|
|
181
|
+
// 2. Stop the session cleanup timer
|
|
182
|
+
clearInterval(sessionCleanupTimer);
|
|
183
|
+
// 3. Close all SSE clients
|
|
184
|
+
for (const client of sseClients) {
|
|
185
|
+
try {
|
|
186
|
+
client.end();
|
|
187
|
+
}
|
|
188
|
+
catch { /* best-effort */ }
|
|
189
|
+
}
|
|
190
|
+
sseClients.clear();
|
|
191
|
+
// 4. Clear MCP sessions
|
|
192
|
+
sessions.clear();
|
|
193
|
+
console.log('Shutdown complete.');
|
|
194
|
+
process.exit(0);
|
|
195
|
+
};
|
|
196
|
+
process.on('SIGINT', shutdown);
|
|
197
|
+
process.on('SIGTERM', shutdown);
|
|
198
|
+
}
|
|
199
|
+
//# sourceMappingURL=httpServer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"httpServer.js","sourceRoot":"","sources":["../src/httpServer.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|