indra_db_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/README.md +225 -0
- package/package.json +52 -0
- package/src/index.ts +529 -0
- package/src/indra-client.ts +488 -0
- package/src/types.ts +263 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,529 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* indra_db MCP Server
|
|
3
|
+
*
|
|
4
|
+
* A Model Context Protocol server that provides tools for managing a
|
|
5
|
+
* content-addressed graph database of thoughts. Perfect for:
|
|
6
|
+
*
|
|
7
|
+
* - Externalizing your reasoning process
|
|
8
|
+
* - Building evolving knowledge graphs
|
|
9
|
+
* - Tracking how understanding changes over time
|
|
10
|
+
* - Creating branching paths of exploration
|
|
11
|
+
* - Finding semantic connections between ideas
|
|
12
|
+
*
|
|
13
|
+
* Think of it as version-controlled thinking - git for your mind.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
17
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
18
|
+
import { z } from "zod";
|
|
19
|
+
import { IndraClient } from "./indra-client.js";
|
|
20
|
+
import { EdgeTypes, IndraError } from "./types.js";
|
|
21
|
+
|
|
22
|
+
// ============================================================================
|
|
23
|
+
// Server Setup
|
|
24
|
+
// ============================================================================
|
|
25
|
+
|
|
26
|
+
const server = new McpServer({
|
|
27
|
+
name: "indra_db",
|
|
28
|
+
version: "0.1.0",
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const client = new IndraClient({
|
|
32
|
+
autoCommit: false, // We'll handle commits explicitly for better control
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// ============================================================================
|
|
36
|
+
// Helper: Format responses for LLM consumption
|
|
37
|
+
// ============================================================================
|
|
38
|
+
|
|
39
|
+
function formatSuccess(data: unknown, context?: string): { content: Array<{ type: "text"; text: string }> } {
|
|
40
|
+
const response = context
|
|
41
|
+
? `${context}\n\n${JSON.stringify(data, null, 2)}`
|
|
42
|
+
: JSON.stringify(data, null, 2);
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
content: [{ type: "text", text: response }],
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function formatError(error: unknown): { content: Array<{ type: "text"; text: string }>; isError: true } {
|
|
50
|
+
if (error instanceof IndraError) {
|
|
51
|
+
return {
|
|
52
|
+
content: [{
|
|
53
|
+
type: "text",
|
|
54
|
+
text: `Error: ${error.message}\n\nDetails:\n${error.stderr}\n\nCommand: ${error.command.join(" ")}`,
|
|
55
|
+
}],
|
|
56
|
+
isError: true,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
content: [{
|
|
62
|
+
type: "text",
|
|
63
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
64
|
+
}],
|
|
65
|
+
isError: true,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ============================================================================
|
|
70
|
+
// THOUGHT TOOLS - Capture and evolve ideas
|
|
71
|
+
// ============================================================================
|
|
72
|
+
|
|
73
|
+
server.tool(
|
|
74
|
+
"remember",
|
|
75
|
+
`🧠 CAPTURE A THOUGHT - Crystallize an idea, insight, or realization into the knowledge graph.
|
|
76
|
+
|
|
77
|
+
Use this when you:
|
|
78
|
+
- Have an insight worth preserving
|
|
79
|
+
- Want to externalize part of your reasoning
|
|
80
|
+
- Need to create a reference point for later
|
|
81
|
+
- Are building understanding incrementally
|
|
82
|
+
|
|
83
|
+
The thought will be embedded for semantic search, allowing you to find it later
|
|
84
|
+
by meaning rather than exact words. Each thought becomes a node that can be
|
|
85
|
+
connected to others, forming a web of understanding.
|
|
86
|
+
|
|
87
|
+
This is how you think out loud - make your reasoning visible and traceable.`,
|
|
88
|
+
{
|
|
89
|
+
content: z.string().describe("The thought to capture - be specific and self-contained"),
|
|
90
|
+
id: z.string().optional().describe("Optional memorable identifier (e.g., 'key-insight-about-X'). Auto-generated if not provided."),
|
|
91
|
+
},
|
|
92
|
+
async ({ content, id }) => {
|
|
93
|
+
try {
|
|
94
|
+
const thought = await client.createThought(content, { id });
|
|
95
|
+
await client.commit(`Remember: ${id || thought.id}`);
|
|
96
|
+
return formatSuccess(thought, `✅ Thought captured and committed. ID: "${thought.id}"`);
|
|
97
|
+
} catch (error) {
|
|
98
|
+
return formatError(error);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
server.tool(
|
|
104
|
+
"recall",
|
|
105
|
+
`🔍 RETRIEVE A THOUGHT - Fetch a specific thought by its identifier.
|
|
106
|
+
|
|
107
|
+
Use this when you:
|
|
108
|
+
- Need to review a previous insight
|
|
109
|
+
- Want to check what you recorded earlier
|
|
110
|
+
- Are building on a specific prior thought
|
|
111
|
+
- Need exact content for a connection
|
|
112
|
+
|
|
113
|
+
Returns the full thought including its content and metadata.`,
|
|
114
|
+
{
|
|
115
|
+
id: z.string().describe("The identifier of the thought to retrieve"),
|
|
116
|
+
},
|
|
117
|
+
async ({ id }) => {
|
|
118
|
+
try {
|
|
119
|
+
const thought = await client.getThought(id);
|
|
120
|
+
return formatSuccess(thought, `📖 Retrieved thought "${id}":`);
|
|
121
|
+
} catch (error) {
|
|
122
|
+
return formatError(error);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
server.tool(
|
|
128
|
+
"revise",
|
|
129
|
+
`✏️ REVISE A THOUGHT - Update your understanding while preserving history.
|
|
130
|
+
|
|
131
|
+
Use this when:
|
|
132
|
+
- Your understanding has evolved
|
|
133
|
+
- You need to correct or refine an idea
|
|
134
|
+
- New information changes a previous insight
|
|
135
|
+
- You want to improve how something is expressed
|
|
136
|
+
|
|
137
|
+
Unlike editing a document, this creates a new version. The old understanding
|
|
138
|
+
is preserved in history - you can always see how your thinking evolved.
|
|
139
|
+
This is the heart of versioned thinking.`,
|
|
140
|
+
{
|
|
141
|
+
id: z.string().describe("The thought to revise"),
|
|
142
|
+
content: z.string().describe("The new, revised content"),
|
|
143
|
+
},
|
|
144
|
+
async ({ id, content }) => {
|
|
145
|
+
try {
|
|
146
|
+
const thought = await client.updateThought(id, content);
|
|
147
|
+
await client.commit(`Revise: ${id}`);
|
|
148
|
+
return formatSuccess(thought, `✅ Thought revised. The previous version is preserved in history.`);
|
|
149
|
+
} catch (error) {
|
|
150
|
+
return formatError(error);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
server.tool(
|
|
156
|
+
"forget",
|
|
157
|
+
`🗑️ FORGET A THOUGHT - Remove a thought from the current state.
|
|
158
|
+
|
|
159
|
+
Use sparingly. The thought remains in history and can be recovered by:
|
|
160
|
+
- Viewing commit history
|
|
161
|
+
- Branching from a previous state
|
|
162
|
+
- Using diff to see what was removed
|
|
163
|
+
|
|
164
|
+
This isn't true deletion - it's more like archiving. Version control means
|
|
165
|
+
nothing is ever truly lost.`,
|
|
166
|
+
{
|
|
167
|
+
id: z.string().describe("The thought to forget"),
|
|
168
|
+
},
|
|
169
|
+
async ({ id }) => {
|
|
170
|
+
try {
|
|
171
|
+
await client.deleteThought(id);
|
|
172
|
+
await client.commit(`Forget: ${id}`);
|
|
173
|
+
return formatSuccess({ forgotten: id }, `✅ Thought "${id}" removed from current state. It remains in history.`);
|
|
174
|
+
} catch (error) {
|
|
175
|
+
return formatError(error);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
server.tool(
|
|
181
|
+
"list_thoughts",
|
|
182
|
+
`📋 LIST ALL THOUGHTS - See everything currently in the knowledge graph.
|
|
183
|
+
|
|
184
|
+
Use this to:
|
|
185
|
+
- Get an overview of what's been captured
|
|
186
|
+
- Find thoughts to connect
|
|
187
|
+
- Review the current state of understanding
|
|
188
|
+
- Plan what connections to make
|
|
189
|
+
|
|
190
|
+
Returns all thoughts with their IDs and content.`,
|
|
191
|
+
{},
|
|
192
|
+
async () => {
|
|
193
|
+
try {
|
|
194
|
+
const result = await client.listThoughts();
|
|
195
|
+
return formatSuccess(result, `📋 ${result.count} thought(s) in the knowledge graph:`);
|
|
196
|
+
} catch (error) {
|
|
197
|
+
return formatError(error);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
// ============================================================================
|
|
203
|
+
// RELATIONSHIP TOOLS - Build the web of understanding
|
|
204
|
+
// ============================================================================
|
|
205
|
+
|
|
206
|
+
server.tool(
|
|
207
|
+
"connect",
|
|
208
|
+
`🔗 CONNECT THOUGHTS - Create a typed relationship between two ideas.
|
|
209
|
+
|
|
210
|
+
This is where the graph comes alive. Connections reveal structure in your thinking.
|
|
211
|
+
|
|
212
|
+
Relationship types (use what fits, or create your own):
|
|
213
|
+
- "supports" → This thought provides evidence for another
|
|
214
|
+
- "contradicts" → This thought conflicts with another
|
|
215
|
+
- "derives_from" → This thought evolved from another
|
|
216
|
+
- "part_of" → This thought is a component of a larger idea
|
|
217
|
+
- "causes" → This thought leads to another
|
|
218
|
+
- "precedes" → This thought comes before another temporally
|
|
219
|
+
- "similar_to" → These thoughts express related ideas
|
|
220
|
+
- "relates_to" → General connection (when type is unclear)
|
|
221
|
+
|
|
222
|
+
The web of connections IS your understanding made visible.`,
|
|
223
|
+
{
|
|
224
|
+
from: z.string().describe("Source thought ID - the starting point of the relationship"),
|
|
225
|
+
to: z.string().describe("Target thought ID - what the source connects to"),
|
|
226
|
+
relationship: z.string().default("relates_to").describe("Type of relationship (see description for built-in types)"),
|
|
227
|
+
strength: z.number().min(0).max(1).optional().describe("Optional weight 0.0-1.0 indicating relationship strength"),
|
|
228
|
+
},
|
|
229
|
+
async ({ from, to, relationship, strength }) => {
|
|
230
|
+
try {
|
|
231
|
+
const edge = await client.relate(from, to, relationship, { weight: strength });
|
|
232
|
+
await client.commit(`Connect: ${from} --[${relationship}]--> ${to}`);
|
|
233
|
+
return formatSuccess(edge, `✅ Connected: "${from}" --[${relationship}]--> "${to}"`);
|
|
234
|
+
} catch (error) {
|
|
235
|
+
return formatError(error);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
);
|
|
239
|
+
|
|
240
|
+
server.tool(
|
|
241
|
+
"disconnect",
|
|
242
|
+
`✂️ DISCONNECT THOUGHTS - Remove a relationship between thoughts.
|
|
243
|
+
|
|
244
|
+
Use when:
|
|
245
|
+
- A connection no longer makes sense
|
|
246
|
+
- You're restructuring your understanding
|
|
247
|
+
- A relationship was created in error
|
|
248
|
+
|
|
249
|
+
The thoughts themselves remain - only the connection is removed.`,
|
|
250
|
+
{
|
|
251
|
+
from: z.string().describe("Source thought ID"),
|
|
252
|
+
to: z.string().describe("Target thought ID"),
|
|
253
|
+
relationship: z.string().optional().describe("Specific relationship type to remove (removes all if not specified)"),
|
|
254
|
+
},
|
|
255
|
+
async ({ from, to, relationship }) => {
|
|
256
|
+
try {
|
|
257
|
+
await client.unrelate(from, to, relationship);
|
|
258
|
+
await client.commit(`Disconnect: ${from} from ${to}`);
|
|
259
|
+
return formatSuccess(
|
|
260
|
+
{ disconnected: { from, to, relationship } },
|
|
261
|
+
`✅ Disconnected "${from}" from "${to}"`
|
|
262
|
+
);
|
|
263
|
+
} catch (error) {
|
|
264
|
+
return formatError(error);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
server.tool(
|
|
270
|
+
"explore",
|
|
271
|
+
`🌐 EXPLORE CONNECTIONS - See what's connected to a thought.
|
|
272
|
+
|
|
273
|
+
This is how you traverse the knowledge graph. From any thought, see:
|
|
274
|
+
- What it connects TO (outgoing)
|
|
275
|
+
- What connects to IT (incoming)
|
|
276
|
+
- Or both directions
|
|
277
|
+
|
|
278
|
+
Each neighbor comes with the edge that connects them, showing the
|
|
279
|
+
relationship type and strength. Use this to follow chains of reasoning,
|
|
280
|
+
find related concepts, or understand context.`,
|
|
281
|
+
{
|
|
282
|
+
thought_id: z.string().describe("The thought to explore from"),
|
|
283
|
+
direction: z.enum(["outgoing", "incoming", "both"]).default("both")
|
|
284
|
+
.describe("Which connections to follow"),
|
|
285
|
+
},
|
|
286
|
+
async ({ thought_id, direction }) => {
|
|
287
|
+
try {
|
|
288
|
+
const result = await client.getNeighbors(thought_id, direction);
|
|
289
|
+
const directionEmoji = direction === "outgoing" ? "→" : direction === "incoming" ? "←" : "↔";
|
|
290
|
+
return formatSuccess(result, `🌐 Connections from "${thought_id}" (${directionEmoji} ${direction}):`);
|
|
291
|
+
} catch (error) {
|
|
292
|
+
return formatError(error);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
// ============================================================================
|
|
298
|
+
// SEARCH TOOLS - Find by meaning
|
|
299
|
+
// ============================================================================
|
|
300
|
+
|
|
301
|
+
server.tool(
|
|
302
|
+
"search",
|
|
303
|
+
`🔮 SEMANTIC SEARCH - Find thoughts by meaning, not just keywords.
|
|
304
|
+
|
|
305
|
+
This is powerful: describe what you're looking for conceptually, and find
|
|
306
|
+
thoughts that match semantically. The embeddings capture meaning, so:
|
|
307
|
+
|
|
308
|
+
- "initial hypothesis" might find "my first theory about X"
|
|
309
|
+
- "things that went wrong" might find "problems encountered"
|
|
310
|
+
- "key decisions" might find "we chose to..."
|
|
311
|
+
|
|
312
|
+
Use this to:
|
|
313
|
+
- Rediscover relevant prior thinking
|
|
314
|
+
- Find thoughts to connect
|
|
315
|
+
- Check if you've already captured something similar
|
|
316
|
+
- Surface related ideas you may have forgotten
|
|
317
|
+
|
|
318
|
+
Higher scores = more semantically similar.`,
|
|
319
|
+
{
|
|
320
|
+
query: z.string().describe("What you're looking for - describe the meaning/concept"),
|
|
321
|
+
limit: z.number().min(1).max(100).default(10).describe("Maximum results to return"),
|
|
322
|
+
},
|
|
323
|
+
async ({ query, limit }) => {
|
|
324
|
+
try {
|
|
325
|
+
const result = await client.search(query, limit);
|
|
326
|
+
return formatSuccess(result, `🔮 Found ${result.count} thought(s) matching "${query}":`);
|
|
327
|
+
} catch (error) {
|
|
328
|
+
return formatError(error);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
);
|
|
332
|
+
|
|
333
|
+
// ============================================================================
|
|
334
|
+
// VERSION CONTROL TOOLS - Track the evolution of understanding
|
|
335
|
+
// ============================================================================
|
|
336
|
+
|
|
337
|
+
server.tool(
|
|
338
|
+
"checkpoint",
|
|
339
|
+
`💾 CHECKPOINT - Commit current state with a meaningful message.
|
|
340
|
+
|
|
341
|
+
Like git commit, but for thoughts. Creates a snapshot you can return to.
|
|
342
|
+
|
|
343
|
+
Good checkpoint messages describe WHY, not just what:
|
|
344
|
+
- "Completed initial analysis of problem space"
|
|
345
|
+
- "Refined hypothesis after finding contradicting evidence"
|
|
346
|
+
- "Branching to explore alternative approach"
|
|
347
|
+
|
|
348
|
+
Checkpoints let you see how understanding evolved over time.`,
|
|
349
|
+
{
|
|
350
|
+
message: z.string().describe("What this checkpoint represents - focus on the WHY"),
|
|
351
|
+
},
|
|
352
|
+
async ({ message }) => {
|
|
353
|
+
try {
|
|
354
|
+
const result = await client.commit(message);
|
|
355
|
+
return formatSuccess(result, `💾 Checkpoint created: "${message}"`);
|
|
356
|
+
} catch (error) {
|
|
357
|
+
return formatError(error);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
);
|
|
361
|
+
|
|
362
|
+
server.tool(
|
|
363
|
+
"history",
|
|
364
|
+
`📜 VIEW HISTORY - See how understanding has evolved.
|
|
365
|
+
|
|
366
|
+
Returns the commit log showing each checkpoint. This is the trajectory
|
|
367
|
+
of your thinking - not just where you are, but how you got here.
|
|
368
|
+
|
|
369
|
+
Use this to:
|
|
370
|
+
- Review the evolution of understanding
|
|
371
|
+
- Find a point to branch from
|
|
372
|
+
- Understand context of current state
|
|
373
|
+
- Track decision points`,
|
|
374
|
+
{
|
|
375
|
+
limit: z.number().min(1).max(100).optional().describe("Maximum commits to show"),
|
|
376
|
+
},
|
|
377
|
+
async ({ limit }) => {
|
|
378
|
+
try {
|
|
379
|
+
const result = await client.log(limit);
|
|
380
|
+
return formatSuccess(result, `📜 Commit history for branch "${result.branch}":`);
|
|
381
|
+
} catch (error) {
|
|
382
|
+
return formatError(error);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
);
|
|
386
|
+
|
|
387
|
+
server.tool(
|
|
388
|
+
"branch",
|
|
389
|
+
`🌿 CREATE BRANCH - Start a new line of exploration.
|
|
390
|
+
|
|
391
|
+
Branches let you explore alternatives without losing your main line of thought.
|
|
392
|
+
Like git branches, they're cheap and fast.
|
|
393
|
+
|
|
394
|
+
Use this when:
|
|
395
|
+
- You want to explore a "what if" scenario
|
|
396
|
+
- Testing a hypothesis that might not pan out
|
|
397
|
+
- Trying an alternative approach
|
|
398
|
+
- Saving current state before major changes
|
|
399
|
+
|
|
400
|
+
You can always come back to main, or merge insights later.`,
|
|
401
|
+
{
|
|
402
|
+
name: z.string().describe("Name for the new branch (e.g., 'explore-alternative', 'hypothesis-b')"),
|
|
403
|
+
},
|
|
404
|
+
async ({ name }) => {
|
|
405
|
+
try {
|
|
406
|
+
const branch = await client.createBranch(name);
|
|
407
|
+
return formatSuccess(branch, `🌿 Branch "${name}" created. Use 'switch_branch' to explore it.`);
|
|
408
|
+
} catch (error) {
|
|
409
|
+
return formatError(error);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
);
|
|
413
|
+
|
|
414
|
+
server.tool(
|
|
415
|
+
"switch_branch",
|
|
416
|
+
`🔀 SWITCH BRANCH - Move to a different line of thinking.
|
|
417
|
+
|
|
418
|
+
Changes which branch you're working on. All thoughts and connections
|
|
419
|
+
reflect that branch's state.
|
|
420
|
+
|
|
421
|
+
Use this to:
|
|
422
|
+
- Return to main after exploring
|
|
423
|
+
- Switch between different approaches
|
|
424
|
+
- Compare different lines of reasoning`,
|
|
425
|
+
{
|
|
426
|
+
name: z.string().describe("Branch name to switch to"),
|
|
427
|
+
},
|
|
428
|
+
async ({ name }) => {
|
|
429
|
+
try {
|
|
430
|
+
await client.checkout(name);
|
|
431
|
+
return formatSuccess({ branch: name }, `🔀 Switched to branch "${name}"`);
|
|
432
|
+
} catch (error) {
|
|
433
|
+
return formatError(error);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
);
|
|
437
|
+
|
|
438
|
+
server.tool(
|
|
439
|
+
"list_branches",
|
|
440
|
+
`🌳 LIST BRANCHES - See all lines of exploration.
|
|
441
|
+
|
|
442
|
+
Shows all branches and which one is currently active.
|
|
443
|
+
Each branch is an independent line of thought that can evolve separately.`,
|
|
444
|
+
{},
|
|
445
|
+
async () => {
|
|
446
|
+
try {
|
|
447
|
+
const result = await client.listBranches();
|
|
448
|
+
return formatSuccess(result, `🌳 Branches (current: "${result.current}"):`);
|
|
449
|
+
} catch (error) {
|
|
450
|
+
return formatError(error);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
);
|
|
454
|
+
|
|
455
|
+
server.tool(
|
|
456
|
+
"compare",
|
|
457
|
+
`🔍 COMPARE - See what changed between states.
|
|
458
|
+
|
|
459
|
+
Shows differences between commits or branches:
|
|
460
|
+
- Thoughts added, removed, modified
|
|
461
|
+
- Connections added or removed
|
|
462
|
+
|
|
463
|
+
Use this to:
|
|
464
|
+
- Understand how thinking evolved
|
|
465
|
+
- See what a branch explored
|
|
466
|
+
- Review changes before merging ideas`,
|
|
467
|
+
{
|
|
468
|
+
from: z.string().optional().describe("Starting commit/branch (defaults to parent)"),
|
|
469
|
+
to: z.string().optional().describe("Ending commit/branch (defaults to HEAD)"),
|
|
470
|
+
},
|
|
471
|
+
async ({ from, to }) => {
|
|
472
|
+
try {
|
|
473
|
+
const result = await client.diff(from, to);
|
|
474
|
+
return formatSuccess(result, `🔍 Diff${from ? ` from ${from}` : ""}${to ? ` to ${to}` : ""}:`);
|
|
475
|
+
} catch (error) {
|
|
476
|
+
return formatError(error);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
);
|
|
480
|
+
|
|
481
|
+
server.tool(
|
|
482
|
+
"status",
|
|
483
|
+
`📊 STATUS - Get current database state overview.
|
|
484
|
+
|
|
485
|
+
Shows:
|
|
486
|
+
- Current branch
|
|
487
|
+
- Number of thoughts and connections
|
|
488
|
+
- Uncommitted changes
|
|
489
|
+
- Database location
|
|
490
|
+
|
|
491
|
+
Use this to orient yourself - where am I in the knowledge graph?`,
|
|
492
|
+
{},
|
|
493
|
+
async () => {
|
|
494
|
+
try {
|
|
495
|
+
const result = await client.status();
|
|
496
|
+
return formatSuccess(result, `📊 Database status:`);
|
|
497
|
+
} catch (error) {
|
|
498
|
+
return formatError(error);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
);
|
|
502
|
+
|
|
503
|
+
// ============================================================================
|
|
504
|
+
// Server Startup
|
|
505
|
+
// ============================================================================
|
|
506
|
+
|
|
507
|
+
async function main() {
|
|
508
|
+
const transport = new StdioServerTransport();
|
|
509
|
+
|
|
510
|
+
console.error(`[indra_db_mcp] Starting server...`);
|
|
511
|
+
console.error(`[indra_db_mcp] Database path: ${client.getDatabasePath()}`);
|
|
512
|
+
|
|
513
|
+
// Initialize the client (ensures binary exists, creates DB if needed)
|
|
514
|
+
try {
|
|
515
|
+
await client.init();
|
|
516
|
+
console.error(`[indra_db_mcp] Database initialized successfully`);
|
|
517
|
+
} catch (error) {
|
|
518
|
+
console.error(`[indra_db_mcp] Warning: ${error}`);
|
|
519
|
+
// Continue anyway - errors will be reported when tools are called
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
await server.connect(transport);
|
|
523
|
+
console.error(`[indra_db_mcp] Server connected and ready`);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
main().catch((error) => {
|
|
527
|
+
console.error(`[indra_db_mcp] Fatal error:`, error);
|
|
528
|
+
process.exit(1);
|
|
529
|
+
});
|