@excalimate/mcp-server 0.2.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.
Files changed (62) hide show
  1. package/README.md +22 -1
  2. package/dist/checkpoint-store.d.ts +1 -0
  3. package/dist/checkpoint-store.d.ts.map +1 -1
  4. package/dist/checkpoint-store.js +23 -2
  5. package/dist/checkpoint-store.js.map +1 -1
  6. package/dist/httpServer.d.ts +4 -0
  7. package/dist/httpServer.d.ts.map +1 -0
  8. package/dist/httpServer.js +199 -0
  9. package/dist/httpServer.js.map +1 -0
  10. package/dist/index.d.ts +0 -7
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +23 -199
  13. package/dist/index.js.map +1 -1
  14. package/dist/server/animationTools.d.ts +9 -0
  15. package/dist/server/animationTools.d.ts.map +1 -0
  16. package/dist/server/animationTools.js +254 -0
  17. package/dist/server/animationTools.js.map +1 -0
  18. package/dist/server/checkpointTools.d.ts +5 -0
  19. package/dist/server/checkpointTools.d.ts.map +1 -0
  20. package/dist/server/checkpointTools.js +22 -0
  21. package/dist/server/checkpointTools.js.map +1 -0
  22. package/dist/server/elementNormalizer.d.ts +3 -0
  23. package/dist/server/elementNormalizer.d.ts.map +1 -0
  24. package/dist/server/elementNormalizer.js +52 -0
  25. package/dist/server/elementNormalizer.js.map +1 -0
  26. package/dist/server/geometry.d.ts +24 -0
  27. package/dist/server/geometry.d.ts.map +1 -0
  28. package/dist/server/geometry.js +102 -0
  29. package/dist/server/geometry.js.map +1 -0
  30. package/dist/server/queryTools.d.ts +28 -0
  31. package/dist/server/queryTools.d.ts.map +1 -0
  32. package/dist/server/queryTools.js +107 -0
  33. package/dist/server/queryTools.js.map +1 -0
  34. package/dist/server/referenceText.d.ts +3 -0
  35. package/dist/server/referenceText.d.ts.map +1 -0
  36. package/dist/server/referenceText.js +268 -0
  37. package/dist/server/referenceText.js.map +1 -0
  38. package/dist/server/sceneTools.d.ts +4 -0
  39. package/dist/server/sceneTools.d.ts.map +1 -0
  40. package/dist/server/sceneTools.js +86 -0
  41. package/dist/server/sceneTools.js.map +1 -0
  42. package/dist/server/shareTools.d.ts +11 -0
  43. package/dist/server/shareTools.d.ts.map +1 -0
  44. package/dist/server/shareTools.js +81 -0
  45. package/dist/server/shareTools.js.map +1 -0
  46. package/dist/server/stateContext.d.ts +21 -0
  47. package/dist/server/stateContext.d.ts.map +1 -0
  48. package/dist/server/stateContext.js +85 -0
  49. package/dist/server/stateContext.js.map +1 -0
  50. package/dist/server.d.ts +5 -10
  51. package/dist/server.d.ts.map +1 -1
  52. package/dist/server.js +24 -907
  53. package/dist/server.js.map +1 -1
  54. package/dist/shareRoutes.d.ts +4 -0
  55. package/dist/shareRoutes.d.ts.map +1 -0
  56. package/dist/shareRoutes.js +44 -0
  57. package/dist/shareRoutes.js.map +1 -0
  58. package/dist/stdioServer.d.ts +3 -0
  59. package/dist/stdioServer.d.ts.map +1 -0
  60. package/dist/stdioServer.js +5 -0
  61. package/dist/stdioServer.js.map +1 -0
  62. package/package.json +3 -2
@@ -0,0 +1,81 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /**
3
+ * MCP tool: share_project
4
+ *
5
+ * Creates an E2E encrypted share URL containing the complete project state.
6
+ * Uses AES-256-GCM encryption — the key is returned to the AI in the URL
7
+ * hash fragment and never stored on the server.
8
+ */
9
+ import crypto from 'node:crypto';
10
+ import { z } from 'zod';
11
+ import { promisify } from 'node:util';
12
+ import { gzip } from 'node:zlib';
13
+ const gzipAsync = promisify(gzip);
14
+ /**
15
+ * Encrypt data with AES-256-GCM.
16
+ * Returns: [IV (12 bytes)] [ciphertext + GCM auth tag]
17
+ */
18
+ function encrypt(plaintext) {
19
+ const key = crypto.randomBytes(32); // 256-bit key
20
+ const iv = crypto.randomBytes(12); // 96-bit IV for GCM
21
+ const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
22
+ const enc = Buffer.concat([cipher.update(plaintext), cipher.final()]);
23
+ const tag = cipher.getAuthTag(); // 16 bytes
24
+ // Layout: [IV (12)] [ciphertext] [GCM tag (16)]
25
+ const result = Buffer.concat([iv, enc, tag]);
26
+ // Export key as base64url (no padding) for shortest URL
27
+ const keyBase64url = key.toString('base64url');
28
+ return { encrypted: result, keyBase64url };
29
+ }
30
+ export function registerShareTools(server, ctx, serverPort) {
31
+ server.tool('share_project', 'Create an E2E encrypted share URL for the current project. The URL contains the encryption key in the hash fragment (never sent to the server). Returns the shareable URL.', {
32
+ baseUrl: z.string().optional().describe('Base URL for the share link (default: https://excalimate.com)'),
33
+ }, async ({ baseUrl }) => {
34
+ const state = ctx.getState();
35
+ if (!state.scene.elements || state.scene.elements.length === 0) {
36
+ return { content: [{ type: 'text', text: 'Error: No elements in the scene. Create a scene first.' }] };
37
+ }
38
+ try {
39
+ // Build the full project payload
40
+ const payload = JSON.stringify({
41
+ scene: state.scene,
42
+ timeline: state.timeline,
43
+ clipStart: state.clipStart,
44
+ clipEnd: state.clipEnd,
45
+ cameraFrame: state.cameraFrame,
46
+ });
47
+ // Compress + encrypt
48
+ const compressed = await gzipAsync(Buffer.from(payload, 'utf-8'));
49
+ const { encrypted, keyBase64url } = encrypt(compressed);
50
+ // Upload to the local share endpoint
51
+ const shareUrl = `http://localhost:${serverPort}/share`;
52
+ const response = await fetch(shareUrl, {
53
+ method: 'POST',
54
+ headers: { 'Content-Type': 'application/octet-stream' },
55
+ body: new Uint8Array(encrypted),
56
+ });
57
+ if (!response.ok) {
58
+ const err = await response.text();
59
+ return { content: [{ type: 'text', text: `Error uploading share: ${err}` }] };
60
+ }
61
+ const { id } = await response.json();
62
+ // Build the shareable URL — key in hash fragment (never sent to server)
63
+ const appBase = baseUrl ?? 'https://excalimate.com';
64
+ const fullUrl = `${appBase}/#share=${id},${keyBase64url}`;
65
+ return {
66
+ content: [{
67
+ type: 'text',
68
+ text: `Share URL created:\n${fullUrl}\n\n` +
69
+ `Elements: ${state.scene.elements.length}, ` +
70
+ `Tracks: ${state.timeline.tracks.length}, ` +
71
+ `Encrypted size: ${(encrypted.length / 1024).toFixed(1)} KB\n\n` +
72
+ `The encryption key is in the URL hash — the server only stores an encrypted blob it cannot read.`,
73
+ }],
74
+ };
75
+ }
76
+ catch (e) {
77
+ return { content: [{ type: 'text', text: `Error creating share: ${e}` }] };
78
+ }
79
+ });
80
+ }
81
+ //# sourceMappingURL=shareTools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shareTools.js","sourceRoot":"","sources":["../../src/server/shareTools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { ServerState } from '../types.js';
3
+ export type StateChangeListener = (delta: Partial<ServerState>) => void;
4
+ export declare function getSharedState(): ServerState;
5
+ export interface StateContext {
6
+ getState: () => ServerState;
7
+ updateState: (newState: ServerState) => void;
8
+ emitChange: () => void;
9
+ /** Mark a state area as dirty for delta broadcasting. */
10
+ markDirty: (area: 'scene' | 'timeline' | 'clip' | 'cameraFrame' | 'all') => void;
11
+ mutatingTool: (name: string, description: string, schema: any, handler: (args: any) => Promise<{
12
+ content: {
13
+ type: 'text';
14
+ text: string;
15
+ }[];
16
+ }>,
17
+ /** Which state areas this tool modifies (for delta broadcasting). Defaults to 'all'. */
18
+ dirtyAreas?: Array<'scene' | 'timeline' | 'clip' | 'cameraFrame'>) => void;
19
+ }
20
+ export declare function createStateContext(serverId: string, server: McpServer, onStateChange?: StateChangeListener): StateContext;
21
+ //# sourceMappingURL=stateContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stateContext.d.ts","sourceRoot":"","sources":["../../src/server/stateContext.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,MAAM,mBAAmB,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;AAKxE,wBAAgB,cAAc,IAAI,WAAW,CAAyB;AAEtE,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,WAAW,CAAC;IAC5B,WAAW,EAAE,CAAC,QAAQ,EAAE,WAAW,KAAK,IAAI,CAAC;IAC7C,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,yDAAyD;IACzD,SAAS,EAAE,CAAC,IAAI,EAAE,OAAO,GAAG,UAAU,GAAG,MAAM,GAAG,aAAa,GAAG,KAAK,KAAK,IAAI,CAAC;IACjF,YAAY,EAAE,CACZ,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,GAAG,EACX,OAAO,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC;QAAE,OAAO,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,EAAE,CAAA;KAAE,CAAC;IAC9E,wFAAwF;IACxF,UAAU,CAAC,EAAE,KAAK,CAAC,OAAO,GAAG,UAAU,GAAG,MAAM,GAAG,aAAa,CAAC,KAC9D,IAAI,CAAC;CACX;AAED,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,SAAS,EACjB,aAAa,CAAC,EAAE,mBAAmB,GAClC,YAAY,CAgFd"}
@@ -0,0 +1,85 @@
1
+ import { createDefaultState } from '../state.js';
2
+ let _activeState = createDefaultState();
3
+ let _activeServerId = null;
4
+ export function getSharedState() { return _activeState; }
5
+ export function createStateContext(serverId, server, onStateChange) {
6
+ if (_activeServerId !== null) {
7
+ console.warn(`[excalimate] New server ${serverId} replacing active server ${_activeServerId}. ` +
8
+ 'Concurrent MCP sessions share the same state (single-tenant design).');
9
+ }
10
+ _activeServerId = serverId;
11
+ // ── Delta broadcasting with debounce ───────────────────────────
12
+ // Track which top-level state areas are dirty via flags set by tools.
13
+ // When the debounced emit fires, only serialize and broadcast the
14
+ // dirty fields. This avoids serializing the entire scene+timeline
15
+ // on every keyframe addition.
16
+ let _emitTimer = null;
17
+ const _dirty = { scene: false, timeline: false, clip: false, cameraFrame: false };
18
+ /** Mark a state area as dirty so it's included in the next broadcast. */
19
+ function markDirty(area) {
20
+ if (area === 'all') {
21
+ _dirty.scene = _dirty.timeline = _dirty.clip = _dirty.cameraFrame = true;
22
+ }
23
+ else {
24
+ _dirty[area] = true;
25
+ }
26
+ }
27
+ const emitChange = () => {
28
+ // Default: mark everything dirty (tools that don't specify get full broadcast).
29
+ // Specific tools can call markDirty() before emitChange() for fine-grained deltas.
30
+ if (!_dirty.scene && !_dirty.timeline && !_dirty.clip && !_dirty.cameraFrame) {
31
+ markDirty('all');
32
+ }
33
+ if (_emitTimer)
34
+ clearTimeout(_emitTimer);
35
+ _emitTimer = setTimeout(() => {
36
+ _emitTimer = null;
37
+ try {
38
+ if (!onStateChange)
39
+ return;
40
+ const delta = {};
41
+ if (_dirty.scene)
42
+ delta.scene = _activeState.scene;
43
+ if (_dirty.timeline)
44
+ delta.timeline = _activeState.timeline;
45
+ if (_dirty.clip) {
46
+ delta.clipStart = _activeState.clipStart;
47
+ delta.clipEnd = _activeState.clipEnd;
48
+ }
49
+ if (_dirty.cameraFrame)
50
+ delta.cameraFrame = _activeState.cameraFrame;
51
+ // Reset dirty flags
52
+ _dirty.scene = _dirty.timeline = _dirty.clip = _dirty.cameraFrame = false;
53
+ if (Object.keys(delta).length === 0)
54
+ return;
55
+ onStateChange(delta);
56
+ }
57
+ catch (err) {
58
+ console.error('emitChange failed:', err);
59
+ }
60
+ }, 50);
61
+ };
62
+ server.__getState = () => _activeState;
63
+ const updateState = (newState) => {
64
+ _activeState = newState;
65
+ };
66
+ const mutatingTool = (name, description, schema, handler, dirtyAreas) => {
67
+ server.tool(name, description, schema, async (args) => {
68
+ const result = await handler(args);
69
+ if (dirtyAreas) {
70
+ for (const area of dirtyAreas)
71
+ markDirty(area);
72
+ }
73
+ emitChange();
74
+ return result;
75
+ });
76
+ };
77
+ return {
78
+ getState: () => _activeState,
79
+ updateState,
80
+ emitChange,
81
+ markDirty,
82
+ mutatingTool,
83
+ };
84
+ }
85
+ //# sourceMappingURL=stateContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stateContext.js","sourceRoot":"","sources":["../../src/server/stateContext.ts"],"names":[],"mappings":"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"}
package/dist/server.d.ts CHANGED
@@ -1,13 +1,8 @@
1
- /**
2
- * Excalimate MCP Server
3
- *
4
- * Provides tools for creating Excalidraw scenes, animating them with keyframes,
5
- * and exporting the results. Designed for AI agent integration via MCP.
6
- */
7
1
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
8
2
  import type { CheckpointStore } from './checkpoint-store.js';
9
- import type { ServerState } from './types.js';
10
- export type StateChangeListener = (state: ServerState) => void;
11
- export declare function getSharedState(): ServerState;
12
- export declare function createServer(store: CheckpointStore, onStateChange?: StateChangeListener): McpServer;
3
+ import { getSharedState } from './server/stateContext.js';
4
+ import type { StateChangeListener } from './server/stateContext.js';
5
+ export { getSharedState };
6
+ export type { StateChangeListener } from './server/stateContext.js';
7
+ export declare function createServer(store: CheckpointStore, onStateChange?: StateChangeListener, serverPort?: number): McpServer;
13
8
  //# sourceMappingURL=server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AACA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGpE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D,OAAO,KAAK,EAAE,WAAW,EAAkD,MAAM,YAAY,CAAC;AAG9F,MAAM,MAAM,mBAAmB,GAAG,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;AAK/D,wBAAgB,cAAc,IAAI,WAAW,CAAyB;AAEtE,wBAAgB,YAAY,CAC1B,KAAK,EAAE,eAAe,EACtB,aAAa,CAAC,EAAE,mBAAmB,GAClC,SAAS,CAswBX"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGpE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAa7D,OAAO,EAAsB,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC9E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,OAAO,EAAE,cAAc,EAAE,CAAC;AAC1B,YAAY,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,wBAAgB,YAAY,CAC1B,KAAK,EAAE,eAAe,EACtB,aAAa,CAAC,EAAE,mBAAmB,EACnC,UAAU,GAAE,MAAa,GACxB,SAAS,CAyBX"}