@ysdk/mcp 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/dist/index.js ADDED
@@ -0,0 +1,480 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import { WebSocket } from "ws";
5
+
6
+ // src/room.ts
7
+ import * as Y from "yjs";
8
+ import { WebsocketProvider } from "y-websocket";
9
+ function createRoom(wsUrl2, roomName, params2 = {}) {
10
+ const doc = new Y.Doc();
11
+ const provider = new WebsocketProvider(wsUrl2, roomName, doc, {
12
+ params: params2,
13
+ maxBackoffTime: 3e4
14
+ });
15
+ const awareness = provider.awareness;
16
+ awareness.setLocalStateField("user", {
17
+ name: "Claude (MCP)",
18
+ isMCP: true
19
+ });
20
+ const waitForSync = new Promise((resolve) => {
21
+ if (provider.synced) {
22
+ resolve();
23
+ } else {
24
+ const onSync = (synced) => {
25
+ if (synced) {
26
+ provider.off("sync", onSync);
27
+ resolve();
28
+ }
29
+ };
30
+ provider.on("sync", onSync);
31
+ }
32
+ });
33
+ return { doc, awareness, provider, waitForSync };
34
+ }
35
+
36
+ // src/server.ts
37
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
38
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
39
+ import {
40
+ CallToolRequestSchema,
41
+ ListToolsRequestSchema,
42
+ ListResourcesRequestSchema,
43
+ ReadResourceRequestSchema
44
+ } from "@modelcontextprotocol/sdk/types.js";
45
+
46
+ // src/tools.ts
47
+ import * as Y2 from "yjs";
48
+ var TOOLS = [
49
+ // --- Shared Map (Y.Map keyed 'ysdk') ---
50
+ {
51
+ name: "shared_get",
52
+ description: "Read a value from the shared state map. This is the same data useShared() reads in the React app.",
53
+ inputSchema: {
54
+ type: "object",
55
+ properties: { key: { type: "string", description: "The key to read" } },
56
+ required: ["key"]
57
+ }
58
+ },
59
+ {
60
+ name: "shared_set",
61
+ description: "Write a value to the shared state map. All connected clients (React app) see the change immediately via useShared().",
62
+ inputSchema: {
63
+ type: "object",
64
+ properties: {
65
+ key: { type: "string", description: "The key to set" },
66
+ value: { description: "The value (any JSON type: string, number, boolean, object, array, null)" }
67
+ },
68
+ required: ["key", "value"]
69
+ }
70
+ },
71
+ {
72
+ name: "shared_delete",
73
+ description: "Delete a key from the shared state map.",
74
+ inputSchema: {
75
+ type: "object",
76
+ properties: { key: { type: "string", description: "The key to delete" } },
77
+ required: ["key"]
78
+ }
79
+ },
80
+ {
81
+ name: "shared_keys",
82
+ description: "List all keys in the shared state map.",
83
+ inputSchema: { type: "object", properties: {} }
84
+ },
85
+ // --- Shared Arrays ---
86
+ {
87
+ name: "array_get",
88
+ description: "Read the contents of a shared array. This is the same data useSharedArray() reads.",
89
+ inputSchema: {
90
+ type: "object",
91
+ properties: { key: { type: "string", description: "Array name" } },
92
+ required: ["key"]
93
+ }
94
+ },
95
+ {
96
+ name: "array_push",
97
+ description: "Push items to the end of a shared array. Connected clients see the update via useSharedArray().",
98
+ inputSchema: {
99
+ type: "object",
100
+ properties: {
101
+ key: { type: "string", description: "Array name" },
102
+ items: { type: "array", description: "Items to push (array of any JSON values)" }
103
+ },
104
+ required: ["key", "items"]
105
+ }
106
+ },
107
+ {
108
+ name: "array_insert",
109
+ description: "Insert items at a position in a shared array.",
110
+ inputSchema: {
111
+ type: "object",
112
+ properties: {
113
+ key: { type: "string", description: "Array name" },
114
+ index: { type: "number", description: "Position to insert at (0-based)" },
115
+ items: { type: "array", description: "Items to insert" }
116
+ },
117
+ required: ["key", "index", "items"]
118
+ }
119
+ },
120
+ {
121
+ name: "array_delete",
122
+ description: "Delete items from a shared array.",
123
+ inputSchema: {
124
+ type: "object",
125
+ properties: {
126
+ key: { type: "string", description: "Array name" },
127
+ index: { type: "number", description: "Start index (0-based)" },
128
+ count: { type: "number", description: "Number of items to delete (default: 1)" }
129
+ },
130
+ required: ["key", "index"]
131
+ }
132
+ },
133
+ {
134
+ name: "array_clear",
135
+ description: "Remove all items from a shared array.",
136
+ inputSchema: {
137
+ type: "object",
138
+ properties: { key: { type: "string", description: "Array name" } },
139
+ required: ["key"]
140
+ }
141
+ },
142
+ // --- Shared Text ---
143
+ {
144
+ name: "text_get",
145
+ description: "Read the contents of a shared text. This is the same data useSharedText() reads.",
146
+ inputSchema: {
147
+ type: "object",
148
+ properties: { key: { type: "string", description: "Text name" } },
149
+ required: ["key"]
150
+ }
151
+ },
152
+ {
153
+ name: "text_set",
154
+ description: "Replace the entire content of a shared text. Connected clients see the update via useSharedText().",
155
+ inputSchema: {
156
+ type: "object",
157
+ properties: {
158
+ key: { type: "string", description: "Text name" },
159
+ value: { type: "string", description: "New text content" }
160
+ },
161
+ required: ["key", "value"]
162
+ }
163
+ },
164
+ {
165
+ name: "text_insert",
166
+ description: "Insert content at a position in a shared text.",
167
+ inputSchema: {
168
+ type: "object",
169
+ properties: {
170
+ key: { type: "string", description: "Text name" },
171
+ index: { type: "number", description: "Position to insert at (0-based character index)" },
172
+ content: { type: "string", description: "Text to insert" }
173
+ },
174
+ required: ["key", "index", "content"]
175
+ }
176
+ },
177
+ {
178
+ name: "text_delete",
179
+ description: "Delete a range of characters from a shared text.",
180
+ inputSchema: {
181
+ type: "object",
182
+ properties: {
183
+ key: { type: "string", description: "Text name" },
184
+ index: { type: "number", description: "Start position (0-based)" },
185
+ length: { type: "number", description: "Number of characters to delete" }
186
+ },
187
+ required: ["key", "index", "length"]
188
+ }
189
+ },
190
+ // --- Presence ---
191
+ {
192
+ name: "presence_list",
193
+ description: "List all connected users and their presence state.",
194
+ inputSchema: { type: "object", properties: {} }
195
+ },
196
+ // --- Broadcast ---
197
+ {
198
+ name: "broadcast",
199
+ description: "Send an ephemeral message to all connected clients. Received via useBroadcast() in the React app. Not persisted.",
200
+ inputSchema: {
201
+ type: "object",
202
+ properties: {
203
+ channel: { type: "string", description: "Channel name (matches useBroadcast channel)" },
204
+ data: { description: "Message payload (any JSON value)" }
205
+ },
206
+ required: ["channel", "data"]
207
+ }
208
+ },
209
+ // --- Room Info ---
210
+ {
211
+ name: "room_info",
212
+ description: "Get room metadata: connection status, sync status, connected client count, document size.",
213
+ inputSchema: { type: "object", properties: {} }
214
+ },
215
+ // --- Document Snapshot ---
216
+ {
217
+ name: "document_snapshot",
218
+ description: "Get a full snapshot of all shared data in the document (maps, arrays, texts).",
219
+ inputSchema: { type: "object", properties: {} }
220
+ }
221
+ ];
222
+ function handleTool(name, args, doc, awareness, provider) {
223
+ if (name.startsWith("shared_")) {
224
+ const map = doc.getMap("ysdk");
225
+ switch (name) {
226
+ case "shared_get": {
227
+ const value = map.get(args.key);
228
+ return ok(value !== void 0 ? JSON.stringify(value, null, 2) : "undefined (key not set)");
229
+ }
230
+ case "shared_set":
231
+ map.set(args.key, args.value);
232
+ return ok(`Set "${args.key}" = ${JSON.stringify(args.value)}`);
233
+ case "shared_delete":
234
+ map.delete(args.key);
235
+ return ok(`Deleted "${args.key}"`);
236
+ case "shared_keys":
237
+ return ok(JSON.stringify(Array.from(map.keys())));
238
+ }
239
+ }
240
+ if (name.startsWith("array_")) {
241
+ const arr = doc.getArray(args.key);
242
+ switch (name) {
243
+ case "array_get":
244
+ return ok(JSON.stringify(arr.toArray(), null, 2));
245
+ case "array_push":
246
+ arr.push(args.items);
247
+ return ok(`Pushed ${args.items.length} item(s). Length: ${arr.length}`);
248
+ case "array_insert":
249
+ arr.insert(args.index, args.items);
250
+ return ok(`Inserted ${args.items.length} item(s) at index ${args.index}. Length: ${arr.length}`);
251
+ case "array_delete": {
252
+ const count = args.count ?? 1;
253
+ arr.delete(args.index, count);
254
+ return ok(`Deleted ${count} item(s) at index ${args.index}. Length: ${arr.length}`);
255
+ }
256
+ case "array_clear":
257
+ if (arr.length > 0) arr.delete(0, arr.length);
258
+ return ok(`Array "${args.key}" cleared.`);
259
+ }
260
+ }
261
+ if (name.startsWith("text_")) {
262
+ const text = doc.getText(args.key);
263
+ switch (name) {
264
+ case "text_get":
265
+ return ok(text.toString() || "(empty)");
266
+ case "text_set":
267
+ doc.transact(() => {
268
+ text.delete(0, text.length);
269
+ text.insert(0, args.value);
270
+ });
271
+ return ok(`Text "${args.key}" set (${args.value.length} chars)`);
272
+ case "text_insert":
273
+ text.insert(args.index, args.content);
274
+ return ok(`Inserted at index ${args.index} in "${args.key}"`);
275
+ case "text_delete":
276
+ text.delete(args.index, args.length);
277
+ return ok(`Deleted ${args.length} chars at index ${args.index} in "${args.key}"`);
278
+ }
279
+ }
280
+ if (name === "presence_list") {
281
+ const peers = [];
282
+ awareness.getStates().forEach((state, clientId) => {
283
+ if (state.user) {
284
+ peers.push({
285
+ clientId,
286
+ isLocal: clientId === awareness.clientID,
287
+ ...state.user
288
+ });
289
+ }
290
+ });
291
+ return ok(JSON.stringify(peers, null, 2));
292
+ }
293
+ if (name === "broadcast") {
294
+ awareness.setLocalStateField(`_bc:${args.channel}`, {
295
+ data: args.data,
296
+ ts: Date.now()
297
+ });
298
+ return ok(`Broadcast sent on channel "${args.channel}"`);
299
+ }
300
+ if (name === "room_info") {
301
+ const stateSize = Y2.encodeStateAsUpdate(doc).length;
302
+ const connectedClients = awareness.getStates().size;
303
+ return ok(JSON.stringify({
304
+ connected: provider.wsconnected,
305
+ synced: provider.synced,
306
+ connectedClients,
307
+ documentSizeBytes: stateSize,
308
+ room: provider.roomname
309
+ }, null, 2));
310
+ }
311
+ if (name === "document_snapshot") {
312
+ return ok(JSON.stringify(getDocSnapshot(doc), null, 2));
313
+ }
314
+ return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
315
+ }
316
+ function ok(text) {
317
+ return { content: [{ type: "text", text }] };
318
+ }
319
+ function getDocSnapshot(doc) {
320
+ const snapshot = {};
321
+ const sharedMap = doc.getMap("ysdk");
322
+ if (sharedMap.size > 0) {
323
+ snapshot.shared = {};
324
+ sharedMap.forEach((value, key) => {
325
+ snapshot.shared[key] = value;
326
+ });
327
+ }
328
+ doc.share.forEach((type, name) => {
329
+ if (name === "ysdk") return;
330
+ if (type instanceof Y2.Array) {
331
+ if (!snapshot.arrays) snapshot.arrays = {};
332
+ snapshot.arrays[name] = type.toArray();
333
+ } else if (type instanceof Y2.Text) {
334
+ if (!snapshot.texts) snapshot.texts = {};
335
+ snapshot.texts[name] = type.toString();
336
+ } else if (type instanceof Y2.Map) {
337
+ if (!snapshot.maps) snapshot.maps = {};
338
+ const mapData = {};
339
+ type.forEach((v, k) => {
340
+ mapData[k] = v;
341
+ });
342
+ snapshot.maps[name] = mapData;
343
+ }
344
+ });
345
+ return snapshot;
346
+ }
347
+
348
+ // src/resources.ts
349
+ var RESOURCES = [
350
+ {
351
+ uri: "ysdk://document",
352
+ name: "Document State",
353
+ description: "Full state of all shared data (maps, arrays, texts)",
354
+ mimeType: "application/json"
355
+ },
356
+ {
357
+ uri: "ysdk://presence",
358
+ name: "Presence",
359
+ description: "Currently connected users and their presence state",
360
+ mimeType: "application/json"
361
+ }
362
+ ];
363
+ function handleReadResource(uri, doc, awareness) {
364
+ switch (uri) {
365
+ case "ysdk://document": {
366
+ return {
367
+ contents: [{
368
+ uri,
369
+ mimeType: "application/json",
370
+ text: JSON.stringify(getDocSnapshot(doc), null, 2)
371
+ }]
372
+ };
373
+ }
374
+ case "ysdk://presence": {
375
+ const peers = [];
376
+ awareness.getStates().forEach((state, clientId) => {
377
+ peers.push({
378
+ clientId,
379
+ isLocal: clientId === awareness.clientID,
380
+ ...state
381
+ });
382
+ });
383
+ return {
384
+ contents: [{
385
+ uri,
386
+ mimeType: "application/json",
387
+ text: JSON.stringify(peers, null, 2)
388
+ }]
389
+ };
390
+ }
391
+ default:
392
+ throw new Error(`Unknown resource: ${uri}`);
393
+ }
394
+ }
395
+
396
+ // src/server.ts
397
+ function createServer(doc, awareness, provider) {
398
+ const server2 = new Server(
399
+ { name: "@ysdk/mcp", version: "0.1.0" },
400
+ { capabilities: { tools: {}, resources: {} } }
401
+ );
402
+ server2.setRequestHandler(ListToolsRequestSchema, async () => ({
403
+ tools: TOOLS
404
+ }));
405
+ server2.setRequestHandler(CallToolRequestSchema, async (request) => {
406
+ const { name, arguments: args } = request.params;
407
+ try {
408
+ return handleTool(name, args || {}, doc, awareness, provider);
409
+ } catch (err) {
410
+ return {
411
+ content: [{ type: "text", text: `Error: ${err.message}` }],
412
+ isError: true
413
+ };
414
+ }
415
+ });
416
+ server2.setRequestHandler(ListResourcesRequestSchema, async () => ({
417
+ resources: RESOURCES
418
+ }));
419
+ server2.setRequestHandler(ReadResourceRequestSchema, async (request) => {
420
+ return handleReadResource(request.params.uri, doc, awareness);
421
+ });
422
+ return {
423
+ async start() {
424
+ const transport = new StdioServerTransport();
425
+ await server2.connect(transport);
426
+ }
427
+ };
428
+ }
429
+
430
+ // src/index.ts
431
+ globalThis.WebSocket = WebSocket;
432
+ var room = process.env.YSDK_ROOM;
433
+ var apiKey = process.env.YSDK_API_KEY;
434
+ var urlOverride = process.env.YSDK_URL;
435
+ if (!room) {
436
+ process.stderr.write("Error: YSDK_ROOM environment variable is required.\n\n");
437
+ process.stderr.write("Usage in .mcp.json:\n");
438
+ process.stderr.write(JSON.stringify({
439
+ mcpServers: {
440
+ ysdk: {
441
+ command: "npx",
442
+ args: ["@ysdk/mcp"],
443
+ env: { YSDK_ROOM: "my-room", YSDK_API_KEY: "ysdk_live_..." }
444
+ }
445
+ }
446
+ }, null, 2));
447
+ process.stderr.write("\n");
448
+ process.exit(1);
449
+ }
450
+ var wsUrl;
451
+ var params = {};
452
+ if (urlOverride) {
453
+ wsUrl = urlOverride;
454
+ } else if (apiKey) {
455
+ wsUrl = "wss://sync.elvenvtt.com/ysdk";
456
+ params = { apiKey };
457
+ } else {
458
+ wsUrl = "ws://localhost:1234";
459
+ }
460
+ process.stderr.write(`[@ysdk/mcp] Connecting to ${wsUrl} room="${room}"${apiKey ? " (cloud)" : urlOverride ? " (custom)" : " (local)"}...
461
+ `);
462
+ var connection = createRoom(wsUrl, room, params);
463
+ var server = createServer(connection.doc, connection.awareness, connection.provider);
464
+ connection.waitForSync.then(() => {
465
+ process.stderr.write(`[@ysdk/mcp] Synced. Ready.
466
+ `);
467
+ });
468
+ var cleanup = () => {
469
+ connection.provider.destroy();
470
+ connection.doc.destroy();
471
+ process.exit(0);
472
+ };
473
+ process.on("SIGINT", cleanup);
474
+ process.on("SIGTERM", cleanup);
475
+ server.start().catch((err) => {
476
+ process.stderr.write(`[@ysdk/mcp] Fatal: ${err.message}
477
+ `);
478
+ process.exit(1);
479
+ });
480
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/room.ts","../src/server.ts","../src/tools.ts","../src/resources.ts"],"sourcesContent":["// WebSocket polyfill for Node.js - MUST be set before importing y-websocket\r\nimport { WebSocket } from 'ws';\r\n// @ts-ignore\r\nglobalThis.WebSocket = WebSocket;\r\n\r\nimport { createRoom } from './room.js';\r\nimport { createServer } from './server.js';\r\n\r\nconst room = process.env.YSDK_ROOM;\r\nconst apiKey = process.env.YSDK_API_KEY;\r\nconst urlOverride = process.env.YSDK_URL;\r\n\r\nif (!room) {\r\n process.stderr.write('Error: YSDK_ROOM environment variable is required.\\n\\n');\r\n process.stderr.write('Usage in .mcp.json:\\n');\r\n process.stderr.write(JSON.stringify({\r\n mcpServers: {\r\n ysdk: {\r\n command: 'npx',\r\n args: ['@ysdk/mcp'],\r\n env: { YSDK_ROOM: 'my-room', YSDK_API_KEY: 'ysdk_live_...' },\r\n },\r\n },\r\n }, null, 2));\r\n process.stderr.write('\\n');\r\n process.exit(1);\r\n}\r\n\r\n// Determine connection mode\r\nlet wsUrl: string;\r\nlet params: Record<string, string> = {};\r\n\r\nif (urlOverride) {\r\n wsUrl = urlOverride;\r\n} else if (apiKey) {\r\n wsUrl = 'wss://sync.elvenvtt.com/ysdk';\r\n params = { apiKey };\r\n} else {\r\n wsUrl = 'ws://localhost:1234';\r\n}\r\n\r\nprocess.stderr.write(`[@ysdk/mcp] Connecting to ${wsUrl} room=\"${room}\"${apiKey ? ' (cloud)' : urlOverride ? ' (custom)' : ' (local)'}...\\n`);\r\n\r\nconst connection = createRoom(wsUrl, room, params);\r\nconst server = createServer(connection.doc, connection.awareness, connection.provider);\r\n\r\n// Wait for initial sync before accepting tool calls\r\nconnection.waitForSync.then(() => {\r\n process.stderr.write(`[@ysdk/mcp] Synced. Ready.\\n`);\r\n});\r\n\r\n// Clean shutdown\r\nconst cleanup = () => {\r\n connection.provider.destroy();\r\n connection.doc.destroy();\r\n process.exit(0);\r\n};\r\nprocess.on('SIGINT', cleanup);\r\nprocess.on('SIGTERM', cleanup);\r\n\r\n// Start MCP server on stdio\r\nserver.start().catch((err) => {\r\n process.stderr.write(`[@ysdk/mcp] Fatal: ${err.message}\\n`);\r\n process.exit(1);\r\n});\r\n","import * as Y from 'yjs';\r\nimport { WebsocketProvider } from 'y-websocket';\r\n\r\nexport interface RoomConnection {\r\n doc: Y.Doc;\r\n awareness: any;\r\n provider: WebsocketProvider;\r\n waitForSync: Promise<void>;\r\n}\r\n\r\nexport function createRoom(wsUrl: string, roomName: string, params: Record<string, string> = {}): RoomConnection {\r\n const doc = new Y.Doc();\r\n const provider = new WebsocketProvider(wsUrl, roomName, doc, {\r\n params,\r\n maxBackoffTime: 30000,\r\n } as any);\r\n\r\n const awareness = provider.awareness;\r\n\r\n // Identify as MCP server in presence\r\n awareness.setLocalStateField('user', {\r\n name: 'Claude (MCP)',\r\n isMCP: true,\r\n });\r\n\r\n const waitForSync = new Promise<void>((resolve) => {\r\n if (provider.synced) {\r\n resolve();\r\n } else {\r\n const onSync = (synced: boolean) => {\r\n if (synced) {\r\n provider.off('sync', onSync);\r\n resolve();\r\n }\r\n };\r\n provider.on('sync', onSync);\r\n }\r\n });\r\n\r\n return { doc, awareness, provider, waitForSync };\r\n}\r\n","import { Server } from '@modelcontextprotocol/sdk/server/index.js';\r\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\r\nimport {\r\n CallToolRequestSchema,\r\n ListToolsRequestSchema,\r\n ListResourcesRequestSchema,\r\n ReadResourceRequestSchema,\r\n} from '@modelcontextprotocol/sdk/types.js';\r\nimport type * as Y from 'yjs';\r\nimport { TOOLS, handleTool } from './tools.js';\r\nimport { RESOURCES, handleReadResource } from './resources.js';\r\n\r\nexport function createServer(doc: Y.Doc, awareness: any, provider: any) {\r\n const server = new Server(\r\n { name: '@ysdk/mcp', version: '0.1.0' },\r\n { capabilities: { tools: {}, resources: {} } }\r\n );\r\n\r\n server.setRequestHandler(ListToolsRequestSchema, async () => ({\r\n tools: TOOLS,\r\n }));\r\n\r\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\r\n const { name, arguments: args } = request.params;\r\n try {\r\n return handleTool(name, args || {}, doc, awareness, provider);\r\n } catch (err: any) {\r\n return {\r\n content: [{ type: 'text' as const, text: `Error: ${err.message}` }],\r\n isError: true,\r\n };\r\n }\r\n });\r\n\r\n server.setRequestHandler(ListResourcesRequestSchema, async () => ({\r\n resources: RESOURCES,\r\n }));\r\n\r\n server.setRequestHandler(ReadResourceRequestSchema, async (request) => {\r\n return handleReadResource(request.params.uri, doc, awareness);\r\n });\r\n\r\n return {\r\n async start() {\r\n const transport = new StdioServerTransport();\r\n await server.connect(transport);\r\n },\r\n };\r\n}\r\n","import * as Y from 'yjs';\r\n\r\n// ==================== Tool Definitions ====================\r\n\r\nexport const TOOLS = [\r\n // --- Shared Map (Y.Map keyed 'ysdk') ---\r\n {\r\n name: 'shared_get',\r\n description: 'Read a value from the shared state map. This is the same data useShared() reads in the React app.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: { key: { type: 'string', description: 'The key to read' } },\r\n required: ['key'],\r\n },\r\n },\r\n {\r\n name: 'shared_set',\r\n description: 'Write a value to the shared state map. All connected clients (React app) see the change immediately via useShared().',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n key: { type: 'string', description: 'The key to set' },\r\n value: { description: 'The value (any JSON type: string, number, boolean, object, array, null)' },\r\n },\r\n required: ['key', 'value'],\r\n },\r\n },\r\n {\r\n name: 'shared_delete',\r\n description: 'Delete a key from the shared state map.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: { key: { type: 'string', description: 'The key to delete' } },\r\n required: ['key'],\r\n },\r\n },\r\n {\r\n name: 'shared_keys',\r\n description: 'List all keys in the shared state map.',\r\n inputSchema: { type: 'object' as const, properties: {} },\r\n },\r\n\r\n // --- Shared Arrays ---\r\n {\r\n name: 'array_get',\r\n description: 'Read the contents of a shared array. This is the same data useSharedArray() reads.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: { key: { type: 'string', description: 'Array name' } },\r\n required: ['key'],\r\n },\r\n },\r\n {\r\n name: 'array_push',\r\n description: 'Push items to the end of a shared array. Connected clients see the update via useSharedArray().',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n key: { type: 'string', description: 'Array name' },\r\n items: { type: 'array', description: 'Items to push (array of any JSON values)' },\r\n },\r\n required: ['key', 'items'],\r\n },\r\n },\r\n {\r\n name: 'array_insert',\r\n description: 'Insert items at a position in a shared array.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n key: { type: 'string', description: 'Array name' },\r\n index: { type: 'number', description: 'Position to insert at (0-based)' },\r\n items: { type: 'array', description: 'Items to insert' },\r\n },\r\n required: ['key', 'index', 'items'],\r\n },\r\n },\r\n {\r\n name: 'array_delete',\r\n description: 'Delete items from a shared array.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n key: { type: 'string', description: 'Array name' },\r\n index: { type: 'number', description: 'Start index (0-based)' },\r\n count: { type: 'number', description: 'Number of items to delete (default: 1)' },\r\n },\r\n required: ['key', 'index'],\r\n },\r\n },\r\n {\r\n name: 'array_clear',\r\n description: 'Remove all items from a shared array.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: { key: { type: 'string', description: 'Array name' } },\r\n required: ['key'],\r\n },\r\n },\r\n\r\n // --- Shared Text ---\r\n {\r\n name: 'text_get',\r\n description: 'Read the contents of a shared text. This is the same data useSharedText() reads.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: { key: { type: 'string', description: 'Text name' } },\r\n required: ['key'],\r\n },\r\n },\r\n {\r\n name: 'text_set',\r\n description: 'Replace the entire content of a shared text. Connected clients see the update via useSharedText().',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n key: { type: 'string', description: 'Text name' },\r\n value: { type: 'string', description: 'New text content' },\r\n },\r\n required: ['key', 'value'],\r\n },\r\n },\r\n {\r\n name: 'text_insert',\r\n description: 'Insert content at a position in a shared text.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n key: { type: 'string', description: 'Text name' },\r\n index: { type: 'number', description: 'Position to insert at (0-based character index)' },\r\n content: { type: 'string', description: 'Text to insert' },\r\n },\r\n required: ['key', 'index', 'content'],\r\n },\r\n },\r\n {\r\n name: 'text_delete',\r\n description: 'Delete a range of characters from a shared text.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n key: { type: 'string', description: 'Text name' },\r\n index: { type: 'number', description: 'Start position (0-based)' },\r\n length: { type: 'number', description: 'Number of characters to delete' },\r\n },\r\n required: ['key', 'index', 'length'],\r\n },\r\n },\r\n\r\n // --- Presence ---\r\n {\r\n name: 'presence_list',\r\n description: 'List all connected users and their presence state.',\r\n inputSchema: { type: 'object' as const, properties: {} },\r\n },\r\n\r\n // --- Broadcast ---\r\n {\r\n name: 'broadcast',\r\n description: 'Send an ephemeral message to all connected clients. Received via useBroadcast() in the React app. Not persisted.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n channel: { type: 'string', description: 'Channel name (matches useBroadcast channel)' },\r\n data: { description: 'Message payload (any JSON value)' },\r\n },\r\n required: ['channel', 'data'],\r\n },\r\n },\r\n\r\n // --- Room Info ---\r\n {\r\n name: 'room_info',\r\n description: 'Get room metadata: connection status, sync status, connected client count, document size.',\r\n inputSchema: { type: 'object' as const, properties: {} },\r\n },\r\n\r\n // --- Document Snapshot ---\r\n {\r\n name: 'document_snapshot',\r\n description: 'Get a full snapshot of all shared data in the document (maps, arrays, texts).',\r\n inputSchema: { type: 'object' as const, properties: {} },\r\n },\r\n];\r\n\r\n// ==================== Tool Handlers ====================\r\n\r\nexport function handleTool(name: string, args: any, doc: Y.Doc, awareness: any, provider: any) {\r\n // --- Shared Map ---\r\n if (name.startsWith('shared_')) {\r\n const map = doc.getMap('ysdk');\r\n switch (name) {\r\n case 'shared_get': {\r\n const value = map.get(args.key);\r\n return ok(value !== undefined ? JSON.stringify(value, null, 2) : 'undefined (key not set)');\r\n }\r\n case 'shared_set':\r\n map.set(args.key, args.value);\r\n return ok(`Set \"${args.key}\" = ${JSON.stringify(args.value)}`);\r\n case 'shared_delete':\r\n map.delete(args.key);\r\n return ok(`Deleted \"${args.key}\"`);\r\n case 'shared_keys':\r\n return ok(JSON.stringify(Array.from(map.keys())));\r\n }\r\n }\r\n\r\n // --- Arrays ---\r\n if (name.startsWith('array_')) {\r\n const arr = doc.getArray(args.key);\r\n switch (name) {\r\n case 'array_get':\r\n return ok(JSON.stringify(arr.toArray(), null, 2));\r\n case 'array_push':\r\n arr.push(args.items);\r\n return ok(`Pushed ${args.items.length} item(s). Length: ${arr.length}`);\r\n case 'array_insert':\r\n arr.insert(args.index, args.items);\r\n return ok(`Inserted ${args.items.length} item(s) at index ${args.index}. Length: ${arr.length}`);\r\n case 'array_delete': {\r\n const count = args.count ?? 1;\r\n arr.delete(args.index, count);\r\n return ok(`Deleted ${count} item(s) at index ${args.index}. Length: ${arr.length}`);\r\n }\r\n case 'array_clear':\r\n if (arr.length > 0) arr.delete(0, arr.length);\r\n return ok(`Array \"${args.key}\" cleared.`);\r\n }\r\n }\r\n\r\n // --- Text ---\r\n if (name.startsWith('text_')) {\r\n const text = doc.getText(args.key);\r\n switch (name) {\r\n case 'text_get':\r\n return ok(text.toString() || '(empty)');\r\n case 'text_set':\r\n doc.transact(() => {\r\n text.delete(0, text.length);\r\n text.insert(0, args.value);\r\n });\r\n return ok(`Text \"${args.key}\" set (${args.value.length} chars)`);\r\n case 'text_insert':\r\n text.insert(args.index, args.content);\r\n return ok(`Inserted at index ${args.index} in \"${args.key}\"`);\r\n case 'text_delete':\r\n text.delete(args.index, args.length);\r\n return ok(`Deleted ${args.length} chars at index ${args.index} in \"${args.key}\"`);\r\n }\r\n }\r\n\r\n // --- Presence ---\r\n if (name === 'presence_list') {\r\n const peers: any[] = [];\r\n awareness.getStates().forEach((state: any, clientId: number) => {\r\n if (state.user) {\r\n peers.push({\r\n clientId,\r\n isLocal: clientId === awareness.clientID,\r\n ...state.user,\r\n });\r\n }\r\n });\r\n return ok(JSON.stringify(peers, null, 2));\r\n }\r\n\r\n // --- Broadcast ---\r\n if (name === 'broadcast') {\r\n awareness.setLocalStateField(`_bc:${args.channel}`, {\r\n data: args.data,\r\n ts: Date.now(),\r\n });\r\n return ok(`Broadcast sent on channel \"${args.channel}\"`);\r\n }\r\n\r\n // --- Room Info ---\r\n if (name === 'room_info') {\r\n const stateSize = Y.encodeStateAsUpdate(doc).length;\r\n const connectedClients = awareness.getStates().size;\r\n return ok(JSON.stringify({\r\n connected: provider.wsconnected,\r\n synced: provider.synced,\r\n connectedClients,\r\n documentSizeBytes: stateSize,\r\n room: provider.roomname,\r\n }, null, 2));\r\n }\r\n\r\n // --- Document Snapshot ---\r\n if (name === 'document_snapshot') {\r\n return ok(JSON.stringify(getDocSnapshot(doc), null, 2));\r\n }\r\n\r\n return { content: [{ type: 'text' as const, text: `Unknown tool: ${name}` }], isError: true };\r\n}\r\n\r\nfunction ok(text: string) {\r\n return { content: [{ type: 'text' as const, text }] };\r\n}\r\n\r\nexport function getDocSnapshot(doc: Y.Doc): any {\r\n const snapshot: any = {};\r\n\r\n // Shared map (the 'ysdk' map used by useShared)\r\n const sharedMap = doc.getMap('ysdk');\r\n if (sharedMap.size > 0) {\r\n snapshot.shared = {};\r\n sharedMap.forEach((value: any, key: string) => {\r\n snapshot.shared[key] = value;\r\n });\r\n }\r\n\r\n // Discover all other shared types\r\n doc.share.forEach((type: any, name: string) => {\r\n if (name === 'ysdk') return; // already captured above\r\n if (type instanceof Y.Array) {\r\n if (!snapshot.arrays) snapshot.arrays = {};\r\n snapshot.arrays[name] = type.toArray();\r\n } else if (type instanceof Y.Text) {\r\n if (!snapshot.texts) snapshot.texts = {};\r\n snapshot.texts[name] = type.toString();\r\n } else if (type instanceof Y.Map) {\r\n if (!snapshot.maps) snapshot.maps = {};\r\n const mapData: Record<string, any> = {};\r\n type.forEach((v: any, k: string) => { mapData[k] = v; });\r\n snapshot.maps[name] = mapData;\r\n }\r\n });\r\n\r\n return snapshot;\r\n}\r\n","import * as Y from 'yjs';\r\nimport { getDocSnapshot } from './tools.js';\r\n\r\nexport const RESOURCES = [\r\n {\r\n uri: 'ysdk://document',\r\n name: 'Document State',\r\n description: 'Full state of all shared data (maps, arrays, texts)',\r\n mimeType: 'application/json',\r\n },\r\n {\r\n uri: 'ysdk://presence',\r\n name: 'Presence',\r\n description: 'Currently connected users and their presence state',\r\n mimeType: 'application/json',\r\n },\r\n];\r\n\r\nexport function handleReadResource(uri: string, doc: Y.Doc, awareness: any) {\r\n switch (uri) {\r\n case 'ysdk://document': {\r\n return {\r\n contents: [{\r\n uri,\r\n mimeType: 'application/json',\r\n text: JSON.stringify(getDocSnapshot(doc), null, 2),\r\n }],\r\n };\r\n }\r\n case 'ysdk://presence': {\r\n const peers: any[] = [];\r\n awareness.getStates().forEach((state: any, clientId: number) => {\r\n peers.push({\r\n clientId,\r\n isLocal: clientId === awareness.clientID,\r\n ...state,\r\n });\r\n });\r\n return {\r\n contents: [{\r\n uri,\r\n mimeType: 'application/json',\r\n text: JSON.stringify(peers, null, 2),\r\n }],\r\n };\r\n }\r\n default:\r\n throw new Error(`Unknown resource: ${uri}`);\r\n }\r\n}\r\n"],"mappings":"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","names":["wsUrl","params","Y","server"]}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@ysdk/mcp",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for YSDK rooms. Lets Claude read and write collaborative state.",
5
+ "type": "module",
6
+ "bin": {
7
+ "ysdk-mcp": "./dist/index.js"
8
+ },
9
+ "main": "dist/index.js",
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsup",
15
+ "dev": "tsup --watch"
16
+ },
17
+ "dependencies": {
18
+ "@modelcontextprotocol/sdk": "^1.12.0",
19
+ "yjs": "^13.6.0",
20
+ "y-websocket": "^2.0.0",
21
+ "y-protocols": "^1.0.0",
22
+ "ws": "^8.18.0"
23
+ },
24
+ "devDependencies": {
25
+ "@types/ws": "^8.0.0",
26
+ "tsup": "^8.0.0",
27
+ "typescript": "^5.0.0"
28
+ },
29
+ "license": "MIT",
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "https://github.com/aoatkinson/ysdk"
33
+ },
34
+ "keywords": [
35
+ "yjs",
36
+ "crdt",
37
+ "mcp",
38
+ "claude",
39
+ "ai",
40
+ "collaborative",
41
+ "multiplayer"
42
+ ]
43
+ }