@classcad/mcp 0.2.1 → 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 (73) hide show
  1. package/README.md +128 -87
  2. package/dist/app/SOURCE.txt +4 -0
  3. package/dist/app/assets/index-54a14bc0.css +8 -0
  4. package/dist/app/assets/index-c650c783.js +11257 -0
  5. package/dist/app/assets/troika-three-text.esm-188d86b5.js +220 -0
  6. package/dist/app/favicon.svg +98 -0
  7. package/dist/app/index.html +19 -0
  8. package/dist/app/manifest.json +14 -0
  9. package/dist/auth.d.ts +8 -0
  10. package/dist/auth.js +49 -10
  11. package/dist/auth.js.map +1 -1
  12. package/dist/backend.d.ts +8 -0
  13. package/dist/backend.js +39 -0
  14. package/dist/backend.js.map +1 -0
  15. package/dist/client.d.ts +48 -11
  16. package/dist/client.js +152 -167
  17. package/dist/client.js.map +1 -1
  18. package/dist/daemon.d.ts +0 -2
  19. package/dist/daemon.js +77 -62
  20. package/dist/daemon.js.map +1 -1
  21. package/dist/engine/key.d.ts +29 -0
  22. package/dist/engine/key.js +145 -0
  23. package/dist/engine/key.js.map +1 -0
  24. package/dist/engine/wasm-worker.js +7 -7
  25. package/dist/engine/wasm-worker.js.map +1 -1
  26. package/dist/engine/wasm.d.ts +16 -14
  27. package/dist/engine/wasm.js +22 -30
  28. package/dist/engine/wasm.js.map +1 -1
  29. package/dist/mcp-server.d.ts +4 -4
  30. package/dist/mcp-server.js +72 -28
  31. package/dist/mcp-server.js.map +1 -1
  32. package/dist/queue.js +1 -1
  33. package/dist/queue.js.map +1 -1
  34. package/dist/server.js +69 -36
  35. package/dist/server.js.map +1 -1
  36. package/dist/share/hub.d.ts +70 -0
  37. package/dist/share/hub.js +494 -0
  38. package/dist/share/hub.js.map +1 -0
  39. package/dist/share/protocol.d.ts +87 -0
  40. package/dist/share/protocol.js +54 -0
  41. package/dist/share/protocol.js.map +1 -0
  42. package/dist/share/relay.d.ts +45 -0
  43. package/dist/share/relay.js +230 -0
  44. package/dist/share/relay.js.map +1 -0
  45. package/dist/share/server.d.ts +27 -0
  46. package/dist/share/server.js +399 -0
  47. package/dist/share/server.js.map +1 -0
  48. package/dist/share/session.d.ts +120 -0
  49. package/dist/share/session.js +336 -0
  50. package/dist/share/session.js.map +1 -0
  51. package/dist/tools/auth.js +1 -1
  52. package/dist/tools/auth.js.map +1 -1
  53. package/dist/tools/docs.js +3 -2
  54. package/dist/tools/docs.js.map +1 -1
  55. package/dist/tools/lifecycle.js +36 -9
  56. package/dist/tools/lifecycle.js.map +1 -1
  57. package/dist/tools/share.d.ts +18 -0
  58. package/dist/tools/share.js +277 -0
  59. package/dist/tools/share.js.map +1 -0
  60. package/dist/tools/viewer.d.ts +1 -1
  61. package/dist/tools/viewer.js +11 -6
  62. package/dist/tools/viewer.js.map +1 -1
  63. package/dist/viewer-page/viewer.js +19 -2
  64. package/package.json +4 -3
  65. package/dist/bridge/protocol.d.ts +0 -87
  66. package/dist/bridge/protocol.js +0 -14
  67. package/dist/bridge/protocol.js.map +0 -1
  68. package/dist/bridge/server.d.ts +0 -35
  69. package/dist/bridge/server.js +0 -236
  70. package/dist/bridge/server.js.map +0 -1
  71. package/dist/tools/bridge.d.ts +0 -4
  72. package/dist/tools/bridge.js +0 -115
  73. package/dist/tools/bridge.js.map +0 -1
@@ -1,236 +0,0 @@
1
- // bridge/server.ts — WebSocket listener for CC apps to opt into.
2
- //
3
- // Apps connect outbound to ws://127.0.0.1:9096/bridge (default) and send an
4
- // `announce` with a share token. The MCP keeps a registry of these
5
- // connections keyed by clientId and indexed by token. Two uses:
6
- // • kind 'invite' — app-state bridge (selection) next to a server session
7
- // the MCP joined with the same token.
8
- // • kind 'bridge' — the engine transport itself for in-app (WASM) engines:
9
- // client.ts relays every engine command through `engine.execute`.
10
- import { WebSocketServer } from 'ws';
11
- import { PROTOCOL_VERSION } from './protocol.js';
12
- const REQUEST_TIMEOUT = 60_000; // app-side picks can be long
13
- export async function startBridgeServer(opts = {}) {
14
- const listen = opts.listen ?? 'ws://127.0.0.1:9096/bridge';
15
- const url = new URL(listen);
16
- // Bind ONE address family explicitly. 'localhost' resolves to ::1 or
17
- // 127.0.0.1 depending on the platform, so two processes could both hold
18
- // "localhost:9096" and apps would land on either — the reason the MCP
19
- // runs as a single daemon in the first place.
20
- const host = (url.hostname || '127.0.0.1') === 'localhost' ? '127.0.0.1' : url.hostname;
21
- const port = Number(url.port || '9096');
22
- const path = url.pathname || '/bridge';
23
- const wss = new WebSocketServer({ host, port, path });
24
- const connections = new Map(); // clientId → conn
25
- const selectionListeners = new Map();
26
- // Resolvers waiting for a token to be announced (waitFor).
27
- const waiters = new Map();
28
- wss.on('connection', (socket) => {
29
- let conn = null;
30
- const pending = new Map();
31
- const closeListeners = new Set();
32
- const sendRaw = (env) => {
33
- try {
34
- socket.send(JSON.stringify(env));
35
- }
36
- catch (err) {
37
- // socket may already be closing; safe to ignore
38
- }
39
- };
40
- let nextId = 1;
41
- const request = (method, params) => {
42
- const id = nextId++;
43
- return new Promise((resolve, reject) => {
44
- const timer = setTimeout(() => {
45
- if (pending.has(id)) {
46
- pending.delete(id);
47
- reject(new Error(`bridge request timeout (${REQUEST_TIMEOUT}ms): ${method}`));
48
- }
49
- }, REQUEST_TIMEOUT);
50
- pending.set(id, { resolve: resolve, reject, timer });
51
- sendRaw({ type: 'request', id, method, params });
52
- });
53
- };
54
- socket.on('message', (data) => {
55
- let env;
56
- try {
57
- env = JSON.parse(data.toString());
58
- }
59
- catch {
60
- return;
61
- }
62
- if (env.type === 'announce') {
63
- const a = env;
64
- if (conn)
65
- return; // ignore re-announce on the same socket
66
- // Token: current apps send `token` + `kind`; the modeler used to send
67
- // its Drogon invite as `invite`, older builds a `sessionId`.
68
- const token = a.token ?? a.invite ?? a.sessionId;
69
- if (!token)
70
- return;
71
- const kind = a.kind ?? 'invite';
72
- conn = {
73
- clientId: a.clientId,
74
- token,
75
- kind,
76
- sessionId: token,
77
- drawingId: a.drawingId,
78
- app: a.app,
79
- appVersion: a.appVersion,
80
- capabilities: a.capabilities,
81
- protocolVersion: a.protocolVersion,
82
- announcedAt: Date.now(),
83
- request,
84
- onClose: (cb) => {
85
- closeListeners.add(cb);
86
- return () => {
87
- closeListeners.delete(cb);
88
- };
89
- },
90
- cachedSelection: null,
91
- socket,
92
- };
93
- connections.set(a.clientId, conn);
94
- opts.log?.(`app ${a.clientId} (${a.app}) announced token ${token} [${a.kind ?? 'bridge'}]; ${connections.size} app(s)`);
95
- const waiting = waiters.get(token);
96
- if (waiting) {
97
- waiters.delete(token);
98
- for (const resolve of waiting)
99
- resolve(conn);
100
- }
101
- return;
102
- }
103
- if (env.type === 'response') {
104
- const r = env;
105
- const p = pending.get(r.id);
106
- if (!p)
107
- return;
108
- pending.delete(r.id);
109
- if (p.timer)
110
- clearTimeout(p.timer);
111
- if (r.error) {
112
- p.reject(new Error(`${r.error.code}: ${r.error.message}`));
113
- }
114
- else {
115
- p.resolve(r.result);
116
- }
117
- return;
118
- }
119
- if (env.type === 'event' && conn) {
120
- const e = env;
121
- if (e.channel === 'selection.changed') {
122
- const payload = (e.payload ?? {});
123
- const items = payload.items ?? [];
124
- conn.cachedSelection = items;
125
- const subs = selectionListeners.get(conn.sessionId);
126
- if (subs)
127
- for (const cb of subs)
128
- try {
129
- cb(items);
130
- }
131
- catch { }
132
- }
133
- return;
134
- }
135
- });
136
- socket.on('close', () => {
137
- // reject any in-flight requests
138
- for (const [, p] of pending) {
139
- try {
140
- p.reject(new Error('bridge socket closed'));
141
- }
142
- catch { }
143
- if (p.timer)
144
- clearTimeout(p.timer);
145
- }
146
- pending.clear();
147
- if (conn) {
148
- connections.delete(conn.clientId);
149
- opts.log?.(`app ${conn.clientId} (${conn.app}) gone (token ${conn.token}); ${connections.size} app(s)`);
150
- }
151
- for (const cb of closeListeners)
152
- try {
153
- cb();
154
- }
155
- catch { }
156
- closeListeners.clear();
157
- });
158
- socket.on('error', () => { });
159
- });
160
- // wait for listening, but don't block other startup if the port is busy —
161
- // surface the error to the caller.
162
- await new Promise((resolve, reject) => {
163
- wss.once('listening', () => resolve());
164
- wss.once('error', (err) => reject(err));
165
- });
166
- return {
167
- url: `ws://${host}:${port}${path}`,
168
- list: (token) => {
169
- const all = [...connections.values()];
170
- return token ? all.filter(c => c.token === token) : all;
171
- },
172
- pick: (token, clientId) => {
173
- if (clientId)
174
- return connections.get(clientId) ?? null;
175
- const matches = [...connections.values()].filter(c => c.token === token);
176
- if (matches.length === 0)
177
- return null;
178
- // most recently announced wins
179
- matches.sort((a, b) => b.announcedAt - a.announcedAt);
180
- return matches[0];
181
- },
182
- waitFor: (token, timeoutMs = 5_000) => {
183
- const now = [...connections.values()].filter(c => c.token === token).sort((a, b) => b.announcedAt - a.announcedAt)[0];
184
- if (now)
185
- return Promise.resolve(now);
186
- return new Promise(resolve => {
187
- let set = waiters.get(token);
188
- if (!set) {
189
- set = new Set();
190
- waiters.set(token, set);
191
- }
192
- const target = set;
193
- const cb = (c) => {
194
- clearTimeout(timer);
195
- resolve(c);
196
- };
197
- const timer = setTimeout(() => {
198
- target.delete(cb);
199
- if (target.size === 0)
200
- waiters.delete(token);
201
- resolve(null);
202
- }, timeoutMs);
203
- target.add(cb);
204
- });
205
- },
206
- onSelectionChanged: (sessionId, cb) => {
207
- let set = selectionListeners.get(sessionId);
208
- if (!set) {
209
- set = new Set();
210
- selectionListeners.set(sessionId, set);
211
- }
212
- set.add(cb);
213
- return () => {
214
- const s = selectionListeners.get(sessionId);
215
- if (!s)
216
- return;
217
- s.delete(cb);
218
- if (s.size === 0)
219
- selectionListeners.delete(sessionId);
220
- };
221
- },
222
- close: async () => {
223
- for (const [, conn] of connections) {
224
- try {
225
- conn.socket.close();
226
- }
227
- catch { }
228
- }
229
- connections.clear();
230
- await new Promise((resolve) => wss.close(() => resolve()));
231
- },
232
- };
233
- }
234
- // re-export PROTOCOL_VERSION for callers that want to log compat info
235
- export { PROTOCOL_VERSION };
236
- //# sourceMappingURL=server.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/bridge/server.ts"],"names":[],"mappings":"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"}
@@ -1,4 +0,0 @@
1
- import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
- import type { Client } from '../client.js';
3
- import type { BridgeRegistry } from '../bridge/server.js';
4
- export declare function registerBridgeTools(server: McpServer, client: Client, registry: BridgeRegistry): void;
@@ -1,115 +0,0 @@
1
- // Bridge tools: route requests to a CC app's bridge connection.
2
- //
3
- // All tools are scoped by the share token the cc MCP is currently attached
4
- // with (use_session: an invite for a server session, or a bridge token for
5
- // an in-app engine). If no app has connected a bridge for that token, tools
6
- // return a clean "no bridge connected" error and the user can keep using the
7
- // rest of the cc MCP unaffected.
8
- import { z } from 'zod';
9
- function noBridgeError(sessionId) {
10
- return {
11
- isError: true,
12
- content: [{
13
- type: 'text',
14
- text: JSON.stringify({
15
- ok: false,
16
- error: 'no bridge connected',
17
- sessionId,
18
- hint: sessionId
19
- ? `No CC app has registered a bridge for token "${sessionId}". Create the share in the app (Session Management) and start the app with the bridge enabled (e.g. ?mcpBridge=on).`
20
- : 'No shared session is attached. Call use_session with the app\'s share link first, then try again.',
21
- }),
22
- }],
23
- };
24
- }
25
- function pickConn(client, registry, clientId) {
26
- // The token the MCP joined with (invite or bridge) selects the app.
27
- const sid = client.shareToken;
28
- if (!sid)
29
- return { conn: null, sid: null };
30
- return { conn: registry.pick(sid, clientId), sid };
31
- }
32
- export function registerBridgeTools(server, client, registry) {
33
- server.registerTool('bridge.list_clients', {
34
- title: 'List bridge clients',
35
- description: 'List CC apps that have opened a bridge connection for the share token the MCP is attached with (use_session with an app share link; both ?invite= and ?bridge= links). Returns connection metadata and capabilities (engine.execute = the app hosts the engine). Empty list = no bridge available; the cc MCP still works for ClassCAD-only operations.',
36
- inputSchema: {},
37
- }, async () => {
38
- const sid = client.shareToken;
39
- const clients = registry.list(sid ?? undefined).map(c => ({
40
- clientId: c.clientId,
41
- token: c.token,
42
- kind: c.kind,
43
- drawingId: c.drawingId,
44
- app: c.app,
45
- appVersion: c.appVersion,
46
- capabilities: c.capabilities,
47
- protocolVersion: c.protocolVersion,
48
- announcedAt: c.announcedAt,
49
- }));
50
- return {
51
- content: [{
52
- type: 'text',
53
- text: JSON.stringify({ shareToken: sid, transport: client.transport, count: clients.length, clients, bridgeUrl: registry.url }),
54
- }],
55
- };
56
- });
57
- server.registerTool('bridge.get_selection', {
58
- title: 'Get app selection',
59
- description: 'Return the currently selected entities in the connected CC app. Each entity carries both a high-level kind/position/normal AND the raw {containerId, graphicId, prodRefId} triplet — pass `raw.graphicId` straight into ClassCAD APIs like v1.sketch.create({planeId: ...}).\n\n' +
60
- 'STALENESS WARNING — the `raw.containerId` reflects the part\'s brep container at the time of the pick. Once any feature mutation (fillet, chamfer, boolean, extrusion, ...) creates a new solid, the part\'s active container id rotates (it tracks `inspect(partId).solids[0]`). Reusing an older containerId in bridge.set_selection round-trips fine but mis-renders: the viewer highlights the wrong graphic or nothing. After any mutation, re-fetch via `inspect(partId).solids[0]` instead of trusting an older raw triplet.',
61
- inputSchema: {
62
- clientId: z.string().optional()
63
- .describe('Specific bridge client id (from bridge.list_clients). Omit to use the most recently announced client for the session.'),
64
- cached: z.boolean().optional()
65
- .describe('If true, return the cached selection (updated by push events). If false (default), round-trip to the app.'),
66
- },
67
- }, async ({ clientId, cached }) => {
68
- const { conn, sid } = pickConn(client, registry, clientId);
69
- if (!conn)
70
- return noBridgeError(sid);
71
- try {
72
- const items = cached && conn.cachedSelection
73
- ? conn.cachedSelection
74
- : await conn.request('selection.get');
75
- return { content: [{ type: 'text', text: JSON.stringify({ ok: true, count: items.length, items }) }] };
76
- }
77
- catch (err) {
78
- const msg = err instanceof Error ? err.message : String(err);
79
- return { isError: true, content: [{ type: 'text', text: JSON.stringify({ ok: false, error: msg }) }] };
80
- }
81
- });
82
- server.registerTool('bridge.set_selection', {
83
- title: 'Set app selection',
84
- description: "Set the CC app's current selection. Each item is the raw {containerId, graphicId, prodRefId} triplet. The app highlights these entities in its UI.\n\n" +
85
- 'CRITICAL — `containerId` must be the part\'s **current** brep container id, i.e. `inspect(partId).solids[0]` at call time. Each feature that creates a new solid (fillet, chamfer, boolean, extrusion, ...) rotates the part\'s `solids[0]` to a new id, and the bridge\'s canonical containerId rotates with it. Do NOT copy `containerId` from an earlier bridge.get_selection / bridge.pick if any feature has run since — old containerIds round-trip without error but mis-render in the viewer (the bridge accepts the triplet, but graphicIds created by later features do not exist in the old container, and the viewer either highlights the wrong graphic or nothing).\n\n' +
86
- 'Construction recipe from API state alone:\n' +
87
- ' • containerId = `inspect(partId).solids[0]` (re-fetch every time, do not cache across mutations)\n' +
88
- ' • graphicId = brep element id (from `getBrepGeometryByIndex` / `getGeometryIds`)\n' +
89
- ' • prodRefId = the value echoed by a recent bridge.get_selection / bridge.pick on the same part (this differs from the part id when the part is instanced through an assembly — copy it from a pick rather than guessing).',
90
- inputSchema: {
91
- items: z.array(z.object({
92
- containerId: z.number(),
93
- graphicId: z.number(),
94
- prodRefId: z.number(),
95
- })).describe('Entities to select.'),
96
- replace: z.boolean().optional()
97
- .describe('If true (default), replace current selection. If false, add to it.'),
98
- clientId: z.string().optional(),
99
- },
100
- }, async ({ items, replace, clientId }) => {
101
- const { conn, sid } = pickConn(client, registry, clientId);
102
- if (!conn)
103
- return noBridgeError(sid);
104
- try {
105
- const params = { items, replace: replace !== false };
106
- await conn.request('selection.set', params);
107
- return { content: [{ type: 'text', text: JSON.stringify({ ok: true, count: items.length }) }] };
108
- }
109
- catch (err) {
110
- const msg = err instanceof Error ? err.message : String(err);
111
- return { isError: true, content: [{ type: 'text', text: JSON.stringify({ ok: false, error: msg }) }] };
112
- }
113
- });
114
- }
115
- //# sourceMappingURL=bridge.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../../src/tools/bridge.ts"],"names":[],"mappings":"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"}