mindgraph-mcp 0.9.0 → 0.10.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/LICENSE +21 -0
- package/README.md +2 -0
- package/dist/cli.js +88 -3
- package/dist/index.js +81 -3
- package/package.json +5 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Shuruheel Ahamed
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -62,6 +62,8 @@ Or drop this into your Claude Desktop config by hand (`~/Library/Application Sup
|
|
|
62
62
|
| `mindgraph_synthesize` | Project-scoped cross-document synthesis — mine signals, spawn Article-generation jobs |
|
|
63
63
|
| `mindgraph_ontology` | Operational Ontology (Layer 7) — typed domain objects, NL queries with provenance, extraction proposal review (approve/reject), object linking |
|
|
64
64
|
|
|
65
|
+
Plus **dynamically generated read tools**: when the tenant's active schema declares object types, the server renders per-type `search_<objs>` / `get_<obj>` / `summarize_<obj>` tools (from the cloud's `GET /v1/ontology/tools` manifest) at session start. `summarize_<obj>` returns the object — whether mapped from a connected SQL database or extracted from documents — *plus* its cognitive context (claims, risks, decisions, evidence).
|
|
66
|
+
|
|
65
67
|
**7 prompt templates** for common workflows:
|
|
66
68
|
|
|
67
69
|
`graph-summary`, `active-goals`, `open-questions`, `review-contradictions`, `knowledge-about`, `daily-briefing`, `capture-conversation`.
|
package/dist/cli.js
CHANGED
|
@@ -1011,7 +1011,7 @@ var init_tools = __esm({
|
|
|
1011
1011
|
},
|
|
1012
1012
|
{
|
|
1013
1013
|
name: "mindgraph_retrieve",
|
|
1014
|
-
description: "Search and explore the knowledge graph. Use 'context' (default) for BM25 keyword retrieval \u2014 returns graph nodes only by default (labels, summaries, types, confidence); set include_chunks=true to also get full source text. Pass 1-3 discriminating keywords, not sentences. GOOD: 'Kissinger NATO'. BAD: 'What is Kissinger\\'s view on NATO?'. Use 'document_index' to list all ingested documents (titles, dates, UIDs) for orientation. Use 'semantic' when keywords return nothing \u2014 conceptual/fuzzy queries. Use 'hybrid' for keyword + semantic. Use 'text' for fast keyword-only. Use 'neighborhood'/'chain'/'path'/'subgraph' for graph traversal. Use 'preferences' for advice or recommendation requests ('suggest a hotel', 'what should I read?') \u2014 it returns the user's stated/learned preferences relevant to the query (pass the topic as 'query'), so your answer reflects what they actually like instead of being generic. Other structured actions ('active_goals', 'open_questions', etc.) only when the user explicitly asks.",
|
|
1014
|
+
description: "Search and explore the knowledge graph. Use 'context' (default) for BM25 keyword retrieval \u2014 returns graph nodes only by default (labels, summaries, types, confidence); set include_chunks=true to also get full source text. Pass 1-3 discriminating keywords, not sentences. GOOD: 'Kissinger NATO'. BAD: 'What is Kissinger\\'s view on NATO?'. Use 'document_index' to list all ingested documents (titles, dates, UIDs) for orientation. Use 'semantic' when keywords return nothing \u2014 conceptual/fuzzy queries. Use 'hybrid' for keyword + semantic. Use 'text' for fast keyword-only. Use 'neighborhood'/'chain'/'path'/'subgraph' for graph traversal \u2014 traversal steps carry path_cost (lower = stronger connection; sum of -ln(edge weight)) and path_confidence (product of edge confidences; a ranking signal, not a calibrated probability) for the returned path, useful for ranking results; they score the path returned, not the best possible path. Use 'preferences' for advice or recommendation requests ('suggest a hotel', 'what should I read?') \u2014 it returns the user's stated/learned preferences relevant to the query (pass the topic as 'query'), so your answer reflects what they actually like instead of being generic. Other structured actions ('active_goals', 'open_questions', etc.) only when the user explicitly asks.",
|
|
1015
1015
|
inputSchema: {
|
|
1016
1016
|
type: "object",
|
|
1017
1017
|
properties: {
|
|
@@ -1311,6 +1311,84 @@ var init_tools = __esm({
|
|
|
1311
1311
|
}
|
|
1312
1312
|
});
|
|
1313
1313
|
|
|
1314
|
+
// src/generated-tools.ts
|
|
1315
|
+
async function getGeneratedTools(client2) {
|
|
1316
|
+
if (cache && Date.now() - cache.fetchedAt < CACHE_TTL_MS) {
|
|
1317
|
+
return { tools: cache.tools, byName: cache.byName };
|
|
1318
|
+
}
|
|
1319
|
+
try {
|
|
1320
|
+
const c = client2;
|
|
1321
|
+
if (typeof c.listOntologyTools !== "function") {
|
|
1322
|
+
cache = { tools: [], byName: /* @__PURE__ */ new Map(), fetchedAt: Date.now() };
|
|
1323
|
+
return { tools: cache.tools, byName: cache.byName };
|
|
1324
|
+
}
|
|
1325
|
+
const resp = await c.listOntologyTools();
|
|
1326
|
+
const byName = /* @__PURE__ */ new Map();
|
|
1327
|
+
const tools = [];
|
|
1328
|
+
for (const d of resp.tools ?? []) {
|
|
1329
|
+
byName.set(d.name, d);
|
|
1330
|
+
tools.push({
|
|
1331
|
+
name: d.name,
|
|
1332
|
+
description: d.description,
|
|
1333
|
+
inputSchema: d.input_schema
|
|
1334
|
+
});
|
|
1335
|
+
}
|
|
1336
|
+
cache = { tools, byName, fetchedAt: Date.now() };
|
|
1337
|
+
return { tools, byName };
|
|
1338
|
+
} catch {
|
|
1339
|
+
cache = { tools: [], byName: /* @__PURE__ */ new Map(), fetchedAt: Date.now() };
|
|
1340
|
+
return { tools: cache.tools, byName: cache.byName };
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
async function handleGeneratedTool(client2, desc, args) {
|
|
1344
|
+
try {
|
|
1345
|
+
switch (desc.maps_to) {
|
|
1346
|
+
case "search": {
|
|
1347
|
+
const query = args.query;
|
|
1348
|
+
if (!query) return err2(`query is required for ${desc.name}`);
|
|
1349
|
+
const limit = typeof args.limit === "number" ? args.limit : void 0;
|
|
1350
|
+
return ok2(
|
|
1351
|
+
await client2.searchDomainObjects(query, {
|
|
1352
|
+
schema_id: desc.schema_id,
|
|
1353
|
+
object_types: [desc.object_type],
|
|
1354
|
+
limit
|
|
1355
|
+
})
|
|
1356
|
+
);
|
|
1357
|
+
}
|
|
1358
|
+
case "object": {
|
|
1359
|
+
const uid = args.uid;
|
|
1360
|
+
if (!uid) return err2(`uid is required for ${desc.name}`);
|
|
1361
|
+
return ok2(await client2.getDomainObject(uid));
|
|
1362
|
+
}
|
|
1363
|
+
case "object_context": {
|
|
1364
|
+
const uid = args.uid;
|
|
1365
|
+
if (!uid) return err2(`uid is required for ${desc.name}`);
|
|
1366
|
+
const depth = typeof args.depth === "number" ? args.depth : void 0;
|
|
1367
|
+
return ok2(await client2.getDomainObjectContext(uid, depth));
|
|
1368
|
+
}
|
|
1369
|
+
default:
|
|
1370
|
+
return err2(`unknown generated tool mapping: ${desc.maps_to}`);
|
|
1371
|
+
}
|
|
1372
|
+
} catch (e) {
|
|
1373
|
+
return err2(e instanceof Error ? e.message : String(e));
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
var ok2, err2, CACHE_TTL_MS, cache;
|
|
1377
|
+
var init_generated_tools = __esm({
|
|
1378
|
+
"src/generated-tools.ts"() {
|
|
1379
|
+
"use strict";
|
|
1380
|
+
ok2 = (data) => ({
|
|
1381
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
|
|
1382
|
+
});
|
|
1383
|
+
err2 = (message) => ({
|
|
1384
|
+
content: [{ type: "text", text: JSON.stringify({ error: message }) }],
|
|
1385
|
+
isError: true
|
|
1386
|
+
});
|
|
1387
|
+
CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
1388
|
+
cache = null;
|
|
1389
|
+
}
|
|
1390
|
+
});
|
|
1391
|
+
|
|
1314
1392
|
// src/index.ts
|
|
1315
1393
|
var src_exports = {};
|
|
1316
1394
|
async function main() {
|
|
@@ -1329,6 +1407,7 @@ var init_src = __esm({
|
|
|
1329
1407
|
import_types = require("@modelcontextprotocol/sdk/types.js");
|
|
1330
1408
|
import_mindgraph = require("mindgraph");
|
|
1331
1409
|
init_tools();
|
|
1410
|
+
init_generated_tools();
|
|
1332
1411
|
API_KEY = process.env.MINDGRAPH_API_KEY;
|
|
1333
1412
|
BASE_URL = process.env.MINDGRAPH_BASE_URL || "https://api.mindgraph.cloud";
|
|
1334
1413
|
AGENT_ID = process.env.MINDGRAPH_AGENT_ID || "mcp";
|
|
@@ -1422,7 +1501,7 @@ Capture knowledge when the user shares something worth remembering:
|
|
|
1422
1501
|
server = new import_server.Server(
|
|
1423
1502
|
{
|
|
1424
1503
|
name: "mindgraph",
|
|
1425
|
-
version: "0.
|
|
1504
|
+
version: "0.9.1"
|
|
1426
1505
|
},
|
|
1427
1506
|
{
|
|
1428
1507
|
capabilities: {
|
|
@@ -1434,7 +1513,8 @@ Capture knowledge when the user shares something worth remembering:
|
|
|
1434
1513
|
}
|
|
1435
1514
|
);
|
|
1436
1515
|
server.setRequestHandler(import_types.ListToolsRequestSchema, async () => {
|
|
1437
|
-
|
|
1516
|
+
const generated = await getGeneratedTools(client);
|
|
1517
|
+
return { tools: [...TOOLS, ...generated.tools] };
|
|
1438
1518
|
});
|
|
1439
1519
|
server.setRequestHandler(import_types.CallToolRequestSchema, async (request) => {
|
|
1440
1520
|
const { name, arguments: args } = request.params;
|
|
@@ -1442,6 +1522,11 @@ Capture knowledge when the user shares something worth remembering:
|
|
|
1442
1522
|
if (!toolArgs.agent_id) {
|
|
1443
1523
|
toolArgs.agent_id = AGENT_ID;
|
|
1444
1524
|
}
|
|
1525
|
+
const generated = await getGeneratedTools(client);
|
|
1526
|
+
const desc = generated.byName.get(name);
|
|
1527
|
+
if (desc) {
|
|
1528
|
+
return handleGeneratedTool(client, desc, toolArgs);
|
|
1529
|
+
}
|
|
1445
1530
|
return handleTool(client, name, toolArgs);
|
|
1446
1531
|
});
|
|
1447
1532
|
PROMPTS = [
|
package/dist/index.js
CHANGED
|
@@ -297,7 +297,7 @@ var TOOLS = [
|
|
|
297
297
|
},
|
|
298
298
|
{
|
|
299
299
|
name: "mindgraph_retrieve",
|
|
300
|
-
description: "Search and explore the knowledge graph. Use 'context' (default) for BM25 keyword retrieval \u2014 returns graph nodes only by default (labels, summaries, types, confidence); set include_chunks=true to also get full source text. Pass 1-3 discriminating keywords, not sentences. GOOD: 'Kissinger NATO'. BAD: 'What is Kissinger\\'s view on NATO?'. Use 'document_index' to list all ingested documents (titles, dates, UIDs) for orientation. Use 'semantic' when keywords return nothing \u2014 conceptual/fuzzy queries. Use 'hybrid' for keyword + semantic. Use 'text' for fast keyword-only. Use 'neighborhood'/'chain'/'path'/'subgraph' for graph traversal. Use 'preferences' for advice or recommendation requests ('suggest a hotel', 'what should I read?') \u2014 it returns the user's stated/learned preferences relevant to the query (pass the topic as 'query'), so your answer reflects what they actually like instead of being generic. Other structured actions ('active_goals', 'open_questions', etc.) only when the user explicitly asks.",
|
|
300
|
+
description: "Search and explore the knowledge graph. Use 'context' (default) for BM25 keyword retrieval \u2014 returns graph nodes only by default (labels, summaries, types, confidence); set include_chunks=true to also get full source text. Pass 1-3 discriminating keywords, not sentences. GOOD: 'Kissinger NATO'. BAD: 'What is Kissinger\\'s view on NATO?'. Use 'document_index' to list all ingested documents (titles, dates, UIDs) for orientation. Use 'semantic' when keywords return nothing \u2014 conceptual/fuzzy queries. Use 'hybrid' for keyword + semantic. Use 'text' for fast keyword-only. Use 'neighborhood'/'chain'/'path'/'subgraph' for graph traversal \u2014 traversal steps carry path_cost (lower = stronger connection; sum of -ln(edge weight)) and path_confidence (product of edge confidences; a ranking signal, not a calibrated probability) for the returned path, useful for ranking results; they score the path returned, not the best possible path. Use 'preferences' for advice or recommendation requests ('suggest a hotel', 'what should I read?') \u2014 it returns the user's stated/learned preferences relevant to the query (pass the topic as 'query'), so your answer reflects what they actually like instead of being generic. Other structured actions ('active_goals', 'open_questions', etc.) only when the user explicitly asks.",
|
|
301
301
|
inputSchema: {
|
|
302
302
|
type: "object",
|
|
303
303
|
properties: {
|
|
@@ -1285,6 +1285,78 @@ async function handleOntology(client2, args) {
|
|
|
1285
1285
|
}
|
|
1286
1286
|
}
|
|
1287
1287
|
|
|
1288
|
+
// src/generated-tools.ts
|
|
1289
|
+
var ok2 = (data) => ({
|
|
1290
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
|
|
1291
|
+
});
|
|
1292
|
+
var err2 = (message) => ({
|
|
1293
|
+
content: [{ type: "text", text: JSON.stringify({ error: message }) }],
|
|
1294
|
+
isError: true
|
|
1295
|
+
});
|
|
1296
|
+
var CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
1297
|
+
var cache = null;
|
|
1298
|
+
async function getGeneratedTools(client2) {
|
|
1299
|
+
if (cache && Date.now() - cache.fetchedAt < CACHE_TTL_MS) {
|
|
1300
|
+
return { tools: cache.tools, byName: cache.byName };
|
|
1301
|
+
}
|
|
1302
|
+
try {
|
|
1303
|
+
const c = client2;
|
|
1304
|
+
if (typeof c.listOntologyTools !== "function") {
|
|
1305
|
+
cache = { tools: [], byName: /* @__PURE__ */ new Map(), fetchedAt: Date.now() };
|
|
1306
|
+
return { tools: cache.tools, byName: cache.byName };
|
|
1307
|
+
}
|
|
1308
|
+
const resp = await c.listOntologyTools();
|
|
1309
|
+
const byName = /* @__PURE__ */ new Map();
|
|
1310
|
+
const tools = [];
|
|
1311
|
+
for (const d of resp.tools ?? []) {
|
|
1312
|
+
byName.set(d.name, d);
|
|
1313
|
+
tools.push({
|
|
1314
|
+
name: d.name,
|
|
1315
|
+
description: d.description,
|
|
1316
|
+
inputSchema: d.input_schema
|
|
1317
|
+
});
|
|
1318
|
+
}
|
|
1319
|
+
cache = { tools, byName, fetchedAt: Date.now() };
|
|
1320
|
+
return { tools, byName };
|
|
1321
|
+
} catch {
|
|
1322
|
+
cache = { tools: [], byName: /* @__PURE__ */ new Map(), fetchedAt: Date.now() };
|
|
1323
|
+
return { tools: cache.tools, byName: cache.byName };
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
async function handleGeneratedTool(client2, desc, args) {
|
|
1327
|
+
try {
|
|
1328
|
+
switch (desc.maps_to) {
|
|
1329
|
+
case "search": {
|
|
1330
|
+
const query = args.query;
|
|
1331
|
+
if (!query) return err2(`query is required for ${desc.name}`);
|
|
1332
|
+
const limit = typeof args.limit === "number" ? args.limit : void 0;
|
|
1333
|
+
return ok2(
|
|
1334
|
+
await client2.searchDomainObjects(query, {
|
|
1335
|
+
schema_id: desc.schema_id,
|
|
1336
|
+
object_types: [desc.object_type],
|
|
1337
|
+
limit
|
|
1338
|
+
})
|
|
1339
|
+
);
|
|
1340
|
+
}
|
|
1341
|
+
case "object": {
|
|
1342
|
+
const uid = args.uid;
|
|
1343
|
+
if (!uid) return err2(`uid is required for ${desc.name}`);
|
|
1344
|
+
return ok2(await client2.getDomainObject(uid));
|
|
1345
|
+
}
|
|
1346
|
+
case "object_context": {
|
|
1347
|
+
const uid = args.uid;
|
|
1348
|
+
if (!uid) return err2(`uid is required for ${desc.name}`);
|
|
1349
|
+
const depth = typeof args.depth === "number" ? args.depth : void 0;
|
|
1350
|
+
return ok2(await client2.getDomainObjectContext(uid, depth));
|
|
1351
|
+
}
|
|
1352
|
+
default:
|
|
1353
|
+
return err2(`unknown generated tool mapping: ${desc.maps_to}`);
|
|
1354
|
+
}
|
|
1355
|
+
} catch (e) {
|
|
1356
|
+
return err2(e instanceof Error ? e.message : String(e));
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1288
1360
|
// src/index.ts
|
|
1289
1361
|
var API_KEY = process.env.MINDGRAPH_API_KEY;
|
|
1290
1362
|
var BASE_URL = process.env.MINDGRAPH_BASE_URL || "https://api.mindgraph.cloud";
|
|
@@ -1379,7 +1451,7 @@ Capture knowledge when the user shares something worth remembering:
|
|
|
1379
1451
|
var server = new import_server.Server(
|
|
1380
1452
|
{
|
|
1381
1453
|
name: "mindgraph",
|
|
1382
|
-
version: "0.
|
|
1454
|
+
version: "0.9.1"
|
|
1383
1455
|
},
|
|
1384
1456
|
{
|
|
1385
1457
|
capabilities: {
|
|
@@ -1391,7 +1463,8 @@ var server = new import_server.Server(
|
|
|
1391
1463
|
}
|
|
1392
1464
|
);
|
|
1393
1465
|
server.setRequestHandler(import_types.ListToolsRequestSchema, async () => {
|
|
1394
|
-
|
|
1466
|
+
const generated = await getGeneratedTools(client);
|
|
1467
|
+
return { tools: [...TOOLS, ...generated.tools] };
|
|
1395
1468
|
});
|
|
1396
1469
|
server.setRequestHandler(import_types.CallToolRequestSchema, async (request) => {
|
|
1397
1470
|
const { name, arguments: args } = request.params;
|
|
@@ -1399,6 +1472,11 @@ server.setRequestHandler(import_types.CallToolRequestSchema, async (request) =>
|
|
|
1399
1472
|
if (!toolArgs.agent_id) {
|
|
1400
1473
|
toolArgs.agent_id = AGENT_ID;
|
|
1401
1474
|
}
|
|
1475
|
+
const generated = await getGeneratedTools(client);
|
|
1476
|
+
const desc = generated.byName.get(name);
|
|
1477
|
+
if (desc) {
|
|
1478
|
+
return handleGeneratedTool(client, desc, toolArgs);
|
|
1479
|
+
}
|
|
1402
1480
|
return handleTool(client, name, toolArgs);
|
|
1403
1481
|
});
|
|
1404
1482
|
var PROMPTS = [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mindgraph-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "MCP server for MindGraph — connect Claude Desktop, Claude Code, and any MCP client to your knowledge graph",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"scripts": {
|
|
14
14
|
"build": "tsup",
|
|
15
15
|
"lint": "tsc --noEmit",
|
|
16
|
+
"test": "vitest run",
|
|
16
17
|
"dev": "tsup --watch"
|
|
17
18
|
},
|
|
18
19
|
"keywords": [
|
|
@@ -27,11 +28,12 @@
|
|
|
27
28
|
"license": "MIT",
|
|
28
29
|
"dependencies": {
|
|
29
30
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
30
|
-
"mindgraph": "^0.
|
|
31
|
+
"mindgraph": "^0.11.0"
|
|
31
32
|
},
|
|
32
33
|
"devDependencies": {
|
|
33
34
|
"@types/node": "^22.0.0",
|
|
34
35
|
"tsup": "^8.0.0",
|
|
35
|
-
"typescript": "^5.7.0"
|
|
36
|
+
"typescript": "^5.7.0",
|
|
37
|
+
"vitest": "^3.0.0"
|
|
36
38
|
}
|
|
37
39
|
}
|