graph.do 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.
@@ -0,0 +1,647 @@
1
+ // src/types.ts
2
+ import { z } from "zod";
3
+ var EntitySchema = z.object({
4
+ name: z.string().describe("Unique identifier for the entity"),
5
+ entityType: z.string().describe("Type classification of the entity"),
6
+ observations: z.array(z.string()).describe("Array of atomic facts about the entity")
7
+ });
8
+ var RelationSchema = z.object({
9
+ from: z.string().describe("Source entity name"),
10
+ to: z.string().describe("Target entity name"),
11
+ relationType: z.string().describe("Type of relationship (active voice)")
12
+ });
13
+ var KnowledgeGraphSchema = z.object({
14
+ entities: z.array(EntitySchema),
15
+ relations: z.array(RelationSchema)
16
+ });
17
+ var CreateEntitiesInputSchema = z.object({
18
+ entities: z.array(EntitySchema).describe("Array of entities to create")
19
+ });
20
+ var CreateRelationsInputSchema = z.object({
21
+ relations: z.array(RelationSchema).describe("Array of relations to create")
22
+ });
23
+ var AddObservationsInputSchema = z.object({
24
+ observations: z.array(
25
+ z.object({
26
+ entityName: z.string().describe("Name of the entity to add observations to"),
27
+ contents: z.array(z.string()).describe("Array of observations to add")
28
+ })
29
+ ).describe("Array of observation additions")
30
+ });
31
+ var DeleteEntitiesInputSchema = z.object({
32
+ entityNames: z.array(z.string()).describe("Array of entity names to delete")
33
+ });
34
+ var DeleteObservationsInputSchema = z.object({
35
+ deletions: z.array(
36
+ z.object({
37
+ entityName: z.string().describe("Name of the entity"),
38
+ observations: z.array(z.string()).describe("Observations to remove")
39
+ })
40
+ ).describe("Array of observation deletions")
41
+ });
42
+ var DeleteRelationsInputSchema = z.object({
43
+ relations: z.array(RelationSchema).describe("Array of relations to delete")
44
+ });
45
+ var SearchNodesInputSchema = z.object({
46
+ query: z.string().describe("Search query to match against entity names, types, and observations")
47
+ });
48
+ var OpenNodesInputSchema = z.object({
49
+ names: z.array(z.string()).describe("Array of entity names to retrieve")
50
+ });
51
+
52
+ // src/mcp/server.ts
53
+ var McpErrorCode = {
54
+ PARSE_ERROR: -32700,
55
+ INVALID_REQUEST: -32600,
56
+ METHOD_NOT_FOUND: -32601,
57
+ INVALID_PARAMS: -32602,
58
+ INTERNAL_ERROR: -32603
59
+ };
60
+ function createGraphMcpServer(config) {
61
+ const { name = "graph.do", version = "0.1.0", graphManager } = config;
62
+ const tools = [
63
+ {
64
+ name: "create_entities",
65
+ description: "Create multiple new entities in the knowledge graph. Entities are nodes with a unique name, type, and observations.",
66
+ inputSchema: {
67
+ type: "object",
68
+ properties: {
69
+ entities: {
70
+ type: "array",
71
+ items: {
72
+ type: "object",
73
+ properties: {
74
+ name: { type: "string", description: "Unique identifier for the entity" },
75
+ entityType: { type: "string", description: "Type classification of the entity" },
76
+ observations: {
77
+ type: "array",
78
+ items: { type: "string" },
79
+ description: "Array of atomic facts about the entity"
80
+ }
81
+ },
82
+ required: ["name", "entityType", "observations"]
83
+ },
84
+ description: "Array of entities to create"
85
+ }
86
+ },
87
+ required: ["entities"]
88
+ }
89
+ },
90
+ {
91
+ name: "create_relations",
92
+ description: "Create multiple new relations between entities. Relations are directed edges with a type.",
93
+ inputSchema: {
94
+ type: "object",
95
+ properties: {
96
+ relations: {
97
+ type: "array",
98
+ items: {
99
+ type: "object",
100
+ properties: {
101
+ from: { type: "string", description: "Source entity name" },
102
+ to: { type: "string", description: "Target entity name" },
103
+ relationType: {
104
+ type: "string",
105
+ description: "Type of relationship (active voice)"
106
+ }
107
+ },
108
+ required: ["from", "to", "relationType"]
109
+ },
110
+ description: "Array of relations to create"
111
+ }
112
+ },
113
+ required: ["relations"]
114
+ }
115
+ },
116
+ {
117
+ name: "add_observations",
118
+ description: "Add new observations to existing entities. Observations are atomic facts about an entity.",
119
+ inputSchema: {
120
+ type: "object",
121
+ properties: {
122
+ observations: {
123
+ type: "array",
124
+ items: {
125
+ type: "object",
126
+ properties: {
127
+ entityName: {
128
+ type: "string",
129
+ description: "Name of the entity to add observations to"
130
+ },
131
+ contents: {
132
+ type: "array",
133
+ items: { type: "string" },
134
+ description: "Array of observations to add"
135
+ }
136
+ },
137
+ required: ["entityName", "contents"]
138
+ },
139
+ description: "Array of observation additions"
140
+ }
141
+ },
142
+ required: ["observations"]
143
+ }
144
+ },
145
+ {
146
+ name: "delete_entities",
147
+ description: "Delete multiple entities and their relations from the knowledge graph by name.",
148
+ inputSchema: {
149
+ type: "object",
150
+ properties: {
151
+ entityNames: {
152
+ type: "array",
153
+ items: { type: "string" },
154
+ description: "Array of entity names to delete"
155
+ }
156
+ },
157
+ required: ["entityNames"]
158
+ }
159
+ },
160
+ {
161
+ name: "delete_observations",
162
+ description: "Delete specific observations from entities.",
163
+ inputSchema: {
164
+ type: "object",
165
+ properties: {
166
+ deletions: {
167
+ type: "array",
168
+ items: {
169
+ type: "object",
170
+ properties: {
171
+ entityName: { type: "string", description: "Name of the entity" },
172
+ observations: {
173
+ type: "array",
174
+ items: { type: "string" },
175
+ description: "Observations to remove"
176
+ }
177
+ },
178
+ required: ["entityName", "observations"]
179
+ },
180
+ description: "Array of observation deletions"
181
+ }
182
+ },
183
+ required: ["deletions"]
184
+ }
185
+ },
186
+ {
187
+ name: "delete_relations",
188
+ description: "Delete specific relations from the knowledge graph.",
189
+ inputSchema: {
190
+ type: "object",
191
+ properties: {
192
+ relations: {
193
+ type: "array",
194
+ items: {
195
+ type: "object",
196
+ properties: {
197
+ from: { type: "string", description: "Source entity name" },
198
+ to: { type: "string", description: "Target entity name" },
199
+ relationType: { type: "string", description: "Type of relationship" }
200
+ },
201
+ required: ["from", "to", "relationType"]
202
+ },
203
+ description: "Array of relations to delete"
204
+ }
205
+ },
206
+ required: ["relations"]
207
+ }
208
+ },
209
+ {
210
+ name: "read_graph",
211
+ description: "Read the entire knowledge graph including all entities and relations.",
212
+ inputSchema: {
213
+ type: "object",
214
+ properties: {}
215
+ }
216
+ },
217
+ {
218
+ name: "search_nodes",
219
+ description: "Search for nodes in the knowledge graph by matching names, types, or observations.",
220
+ inputSchema: {
221
+ type: "object",
222
+ properties: {
223
+ query: {
224
+ type: "string",
225
+ description: "Search query to match against entity names, types, and observations"
226
+ }
227
+ },
228
+ required: ["query"]
229
+ }
230
+ },
231
+ {
232
+ name: "open_nodes",
233
+ description: "Open specific nodes by name and retrieve them with their inter-relations.",
234
+ inputSchema: {
235
+ type: "object",
236
+ properties: {
237
+ names: {
238
+ type: "array",
239
+ items: { type: "string" },
240
+ description: "Array of entity names to retrieve"
241
+ }
242
+ },
243
+ required: ["names"]
244
+ }
245
+ }
246
+ ];
247
+ const toolHandlers = {
248
+ create_entities: async (input) => {
249
+ const { entities } = CreateEntitiesInputSchema.parse(input);
250
+ const created = await graphManager.createEntities(entities);
251
+ return formatGraphResponse(created, `Created ${created.length} entities`);
252
+ },
253
+ create_relations: async (input) => {
254
+ const { relations } = CreateRelationsInputSchema.parse(input);
255
+ const created = await graphManager.createRelations(relations);
256
+ return formatGraphResponse(created, `Created ${created.length} relations`);
257
+ },
258
+ add_observations: async (input) => {
259
+ const { observations } = AddObservationsInputSchema.parse(input);
260
+ const results = await graphManager.addObservations(observations);
261
+ return formatGraphResponse(results, "Observations added");
262
+ },
263
+ delete_entities: async (input) => {
264
+ const { entityNames } = DeleteEntitiesInputSchema.parse(input);
265
+ const result = await graphManager.deleteEntities(entityNames);
266
+ return {
267
+ content: [{ type: "text", text: result.message }]
268
+ };
269
+ },
270
+ delete_observations: async (input) => {
271
+ const { deletions } = DeleteObservationsInputSchema.parse(input);
272
+ const result = await graphManager.deleteObservations(deletions);
273
+ return {
274
+ content: [{ type: "text", text: result.message }]
275
+ };
276
+ },
277
+ delete_relations: async (input) => {
278
+ const { relations } = DeleteRelationsInputSchema.parse(input);
279
+ const result = await graphManager.deleteRelations(relations);
280
+ return {
281
+ content: [{ type: "text", text: result.message }]
282
+ };
283
+ },
284
+ read_graph: async () => {
285
+ const graph = await graphManager.readGraph();
286
+ return formatGraphResponse(graph, `Graph contains ${graph.entities.length} entities and ${graph.relations.length} relations`);
287
+ },
288
+ search_nodes: async (input) => {
289
+ const { query } = SearchNodesInputSchema.parse(input);
290
+ const graph = await graphManager.searchNodes(query);
291
+ return formatGraphResponse(graph, `Found ${graph.entities.length} matching entities`);
292
+ },
293
+ open_nodes: async (input) => {
294
+ const { names } = OpenNodesInputSchema.parse(input);
295
+ const graph = await graphManager.openNodes(names);
296
+ return formatGraphResponse(graph, `Opened ${graph.entities.length} entities`);
297
+ }
298
+ };
299
+ function formatGraphResponse(data, summary) {
300
+ return {
301
+ content: [
302
+ { type: "text", text: summary },
303
+ {
304
+ type: "resource",
305
+ resource: {
306
+ uri: "graph://result",
307
+ mimeType: "application/json",
308
+ text: JSON.stringify(data, null, 2)
309
+ }
310
+ }
311
+ ]
312
+ };
313
+ }
314
+ async function handleRequest(request) {
315
+ const { id, method, params } = request;
316
+ try {
317
+ switch (method) {
318
+ case "initialize":
319
+ return {
320
+ jsonrpc: "2.0",
321
+ id,
322
+ result: {
323
+ protocolVersion: "2024-11-05",
324
+ capabilities: {
325
+ tools: {}
326
+ },
327
+ serverInfo: {
328
+ name,
329
+ version
330
+ }
331
+ }
332
+ };
333
+ case "notifications/initialized":
334
+ return { jsonrpc: "2.0", id, result: {} };
335
+ case "tools/list":
336
+ return {
337
+ jsonrpc: "2.0",
338
+ id,
339
+ result: { tools }
340
+ };
341
+ case "tools/call": {
342
+ const toolName = params?.name;
343
+ const toolInput = params?.arguments ?? {};
344
+ const handler = toolHandlers[toolName];
345
+ if (!handler) {
346
+ return {
347
+ jsonrpc: "2.0",
348
+ id,
349
+ error: {
350
+ code: McpErrorCode.METHOD_NOT_FOUND,
351
+ message: `Unknown tool: ${toolName}`
352
+ }
353
+ };
354
+ }
355
+ try {
356
+ const result = await handler(toolInput);
357
+ return { jsonrpc: "2.0", id, result };
358
+ } catch (err) {
359
+ const error = err instanceof Error ? err : new Error(String(err));
360
+ return {
361
+ jsonrpc: "2.0",
362
+ id,
363
+ result: {
364
+ content: [{ type: "text", text: `Error: ${error.message}` }],
365
+ isError: true
366
+ }
367
+ };
368
+ }
369
+ }
370
+ case "ping":
371
+ return { jsonrpc: "2.0", id, result: {} };
372
+ default:
373
+ return {
374
+ jsonrpc: "2.0",
375
+ id,
376
+ error: {
377
+ code: McpErrorCode.METHOD_NOT_FOUND,
378
+ message: `Unknown method: ${method}`
379
+ }
380
+ };
381
+ }
382
+ } catch (err) {
383
+ const error = err instanceof Error ? err : new Error(String(err));
384
+ return {
385
+ jsonrpc: "2.0",
386
+ id,
387
+ error: {
388
+ code: McpErrorCode.INTERNAL_ERROR,
389
+ message: error.message
390
+ }
391
+ };
392
+ }
393
+ }
394
+ return {
395
+ name,
396
+ version,
397
+ tools,
398
+ handleRequest,
399
+ graphManager
400
+ };
401
+ }
402
+
403
+ // src/mcp/stdio-transport.ts
404
+ async function runStdioTransport(server) {
405
+ const stdin = process.stdin;
406
+ const stdout = process.stdout;
407
+ const stderr = process.stderr;
408
+ stdin.setEncoding("utf8");
409
+ let buffer = "";
410
+ stderr.write(`${server.name} v${server.version} MCP server started (stdio)
411
+ `);
412
+ stdin.on("data", async (chunk) => {
413
+ buffer += chunk;
414
+ while (true) {
415
+ const newlineIndex = buffer.indexOf("\n");
416
+ if (newlineIndex === -1) break;
417
+ const line = buffer.slice(0, newlineIndex).trim();
418
+ buffer = buffer.slice(newlineIndex + 1);
419
+ if (!line) continue;
420
+ try {
421
+ const request = JSON.parse(line);
422
+ const response = await server.handleRequest(request);
423
+ stdout.write(JSON.stringify(response) + "\n");
424
+ } catch (err) {
425
+ const error = err instanceof Error ? err : new Error(String(err));
426
+ const errorResponse = {
427
+ jsonrpc: "2.0",
428
+ id: 0,
429
+ error: {
430
+ code: -32700,
431
+ message: `Parse error: ${error.message}`
432
+ }
433
+ };
434
+ stdout.write(JSON.stringify(errorResponse) + "\n");
435
+ }
436
+ }
437
+ });
438
+ stdin.on("end", () => {
439
+ stderr.write("stdin closed, shutting down\n");
440
+ process.exit(0);
441
+ });
442
+ stdin.on("error", (err) => {
443
+ stderr.write(`stdin error: ${err.message}
444
+ `);
445
+ process.exit(1);
446
+ });
447
+ await new Promise(() => {
448
+ });
449
+ }
450
+ function createStdioClient(server) {
451
+ let requestId = 0;
452
+ async function call(method, params) {
453
+ const request = {
454
+ jsonrpc: "2.0",
455
+ id: ++requestId,
456
+ method,
457
+ params
458
+ };
459
+ const response = await server.handleRequest(request);
460
+ if (response.error) {
461
+ throw new Error(`MCP Error ${response.error.code}: ${response.error.message}`);
462
+ }
463
+ return response.result;
464
+ }
465
+ return {
466
+ initialize: () => call("initialize"),
467
+ listTools: () => call("tools/list"),
468
+ callTool: (name, args) => call("tools/call", { name, arguments: args }),
469
+ ping: () => call("ping")
470
+ };
471
+ }
472
+
473
+ // src/mcp/http-transport.ts
474
+ function createHttpTransport(config) {
475
+ const { server } = config;
476
+ async function handleRequest(request) {
477
+ const url = new URL(request.url);
478
+ const corsHeaders = {
479
+ "Access-Control-Allow-Origin": "*",
480
+ "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
481
+ "Access-Control-Allow-Headers": "Content-Type"
482
+ };
483
+ if (request.method === "OPTIONS") {
484
+ return new Response(null, { status: 204, headers: corsHeaders });
485
+ }
486
+ if (request.method === "GET" && (url.pathname === "/mcp" || url.pathname === "/mcp/")) {
487
+ const initResponse = await server.handleRequest({
488
+ jsonrpc: "2.0",
489
+ id: "info",
490
+ method: "initialize"
491
+ });
492
+ return new Response(JSON.stringify(initResponse.result, null, 2), {
493
+ headers: {
494
+ "Content-Type": "application/json",
495
+ ...corsHeaders
496
+ }
497
+ });
498
+ }
499
+ if (request.method === "GET" && url.pathname === "/mcp/tools") {
500
+ const toolsResponse = await server.handleRequest({
501
+ jsonrpc: "2.0",
502
+ id: "tools",
503
+ method: "tools/list"
504
+ });
505
+ return new Response(JSON.stringify(toolsResponse.result, null, 2), {
506
+ headers: {
507
+ "Content-Type": "application/json",
508
+ ...corsHeaders
509
+ }
510
+ });
511
+ }
512
+ if (request.method === "POST" && (url.pathname === "/mcp" || url.pathname === "/mcp/")) {
513
+ try {
514
+ const body = await request.json();
515
+ if (Array.isArray(body)) {
516
+ const responses = await Promise.all(
517
+ body.map((req) => server.handleRequest(req))
518
+ );
519
+ return new Response(JSON.stringify(responses), {
520
+ headers: {
521
+ "Content-Type": "application/json",
522
+ ...corsHeaders
523
+ }
524
+ });
525
+ }
526
+ const response = await server.handleRequest(body);
527
+ return new Response(JSON.stringify(response), {
528
+ headers: {
529
+ "Content-Type": "application/json",
530
+ ...corsHeaders
531
+ }
532
+ });
533
+ } catch (err) {
534
+ const error = err instanceof Error ? err : new Error(String(err));
535
+ const errorResponse = {
536
+ jsonrpc: "2.0",
537
+ id: 0,
538
+ error: {
539
+ code: -32700,
540
+ message: `Parse error: ${error.message}`
541
+ }
542
+ };
543
+ return new Response(JSON.stringify(errorResponse), {
544
+ status: 400,
545
+ headers: {
546
+ "Content-Type": "application/json",
547
+ ...corsHeaders
548
+ }
549
+ });
550
+ }
551
+ }
552
+ const toolMatch = url.pathname.match(/^\/mcp\/tools\/([^/]+)$/);
553
+ if (request.method === "POST" && toolMatch) {
554
+ const toolName = toolMatch[1];
555
+ try {
556
+ const args = request.headers.get("content-length") !== "0" ? await request.json() : {};
557
+ const response = await server.handleRequest({
558
+ jsonrpc: "2.0",
559
+ id: "tool-call",
560
+ method: "tools/call",
561
+ params: { name: toolName, arguments: args }
562
+ });
563
+ return new Response(JSON.stringify(response.result ?? response.error), {
564
+ status: response.error ? 400 : 200,
565
+ headers: {
566
+ "Content-Type": "application/json",
567
+ ...corsHeaders
568
+ }
569
+ });
570
+ } catch (err) {
571
+ const error = err instanceof Error ? err : new Error(String(err));
572
+ return new Response(
573
+ JSON.stringify({
574
+ content: [{ type: "text", text: `Error: ${error.message}` }],
575
+ isError: true
576
+ }),
577
+ {
578
+ status: 400,
579
+ headers: {
580
+ "Content-Type": "application/json",
581
+ ...corsHeaders
582
+ }
583
+ }
584
+ );
585
+ }
586
+ }
587
+ return new Response("Not Found", { status: 404, headers: corsHeaders });
588
+ }
589
+ return { handleRequest };
590
+ }
591
+ function createSseTransport(config) {
592
+ const { server } = config;
593
+ function handleSse(request) {
594
+ const encoder = new TextEncoder();
595
+ const stream = new ReadableStream({
596
+ async start(controller) {
597
+ controller.enqueue(
598
+ encoder.encode(`data: ${JSON.stringify({ type: "connected", server: server.name })}
599
+
600
+ `)
601
+ );
602
+ const pingInterval = setInterval(() => {
603
+ try {
604
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify({ type: "ping" })}
605
+
606
+ `));
607
+ } catch {
608
+ clearInterval(pingInterval);
609
+ }
610
+ }, 3e4);
611
+ request.signal.addEventListener("abort", () => {
612
+ clearInterval(pingInterval);
613
+ controller.close();
614
+ });
615
+ }
616
+ });
617
+ return new Response(stream, {
618
+ headers: {
619
+ "Content-Type": "text/event-stream",
620
+ "Cache-Control": "no-cache",
621
+ Connection: "keep-alive",
622
+ "Access-Control-Allow-Origin": "*"
623
+ }
624
+ });
625
+ }
626
+ return { handleSse };
627
+ }
628
+
629
+ export {
630
+ EntitySchema,
631
+ RelationSchema,
632
+ KnowledgeGraphSchema,
633
+ CreateEntitiesInputSchema,
634
+ CreateRelationsInputSchema,
635
+ AddObservationsInputSchema,
636
+ DeleteEntitiesInputSchema,
637
+ DeleteObservationsInputSchema,
638
+ DeleteRelationsInputSchema,
639
+ SearchNodesInputSchema,
640
+ OpenNodesInputSchema,
641
+ createGraphMcpServer,
642
+ runStdioTransport,
643
+ createStdioClient,
644
+ createHttpTransport,
645
+ createSseTransport
646
+ };
647
+ //# sourceMappingURL=chunk-SOVFPCTE.js.map