mindgraph-mcp 0.11.0 → 0.13.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/cli.js +173 -7
- package/dist/index.js +165 -6
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -1483,6 +1483,11 @@ async function getGeneratedTools(client2) {
|
|
|
1483
1483
|
const byName = /* @__PURE__ */ new Map();
|
|
1484
1484
|
const tools = [];
|
|
1485
1485
|
for (const d of resp.tools ?? []) {
|
|
1486
|
+
if (byName.has(d.name)) {
|
|
1487
|
+
throw new DuplicateGeneratedToolError(
|
|
1488
|
+
`duplicate generated ontology tool name: ${d.name}`
|
|
1489
|
+
);
|
|
1490
|
+
}
|
|
1486
1491
|
byName.set(d.name, d);
|
|
1487
1492
|
tools.push({
|
|
1488
1493
|
name: d.name,
|
|
@@ -1492,22 +1497,26 @@ async function getGeneratedTools(client2) {
|
|
|
1492
1497
|
}
|
|
1493
1498
|
cache = { tools, byName, fetchedAt: Date.now() };
|
|
1494
1499
|
return { tools, byName };
|
|
1495
|
-
} catch {
|
|
1500
|
+
} catch (error) {
|
|
1501
|
+
if (error instanceof DuplicateGeneratedToolError) throw error;
|
|
1496
1502
|
cache = { tools: [], byName: /* @__PURE__ */ new Map(), fetchedAt: Date.now() };
|
|
1497
1503
|
return { tools: cache.tools, byName: cache.byName };
|
|
1498
1504
|
}
|
|
1499
1505
|
}
|
|
1500
1506
|
async function handleGeneratedTool(client2, desc, args) {
|
|
1501
1507
|
try {
|
|
1508
|
+
const ontologyClient = client2;
|
|
1502
1509
|
switch (desc.maps_to) {
|
|
1503
1510
|
case "search": {
|
|
1504
1511
|
const query = args.query;
|
|
1505
1512
|
if (!query) return err2(`query is required for ${desc.name}`);
|
|
1506
1513
|
const limit = typeof args.limit === "number" ? args.limit : void 0;
|
|
1514
|
+
const filters = Array.isArray(args.filters) ? args.filters : void 0;
|
|
1507
1515
|
return ok2(
|
|
1508
|
-
await
|
|
1516
|
+
await ontologyClient.searchDomainObjects(query, {
|
|
1509
1517
|
schema_id: desc.schema_id,
|
|
1510
1518
|
object_types: [desc.object_type],
|
|
1519
|
+
filters,
|
|
1511
1520
|
limit
|
|
1512
1521
|
})
|
|
1513
1522
|
);
|
|
@@ -1515,13 +1524,57 @@ async function handleGeneratedTool(client2, desc, args) {
|
|
|
1515
1524
|
case "object": {
|
|
1516
1525
|
const uid = args.uid;
|
|
1517
1526
|
if (!uid) return err2(`uid is required for ${desc.name}`);
|
|
1518
|
-
return ok2(await
|
|
1527
|
+
return ok2(await ontologyClient.getDomainObject(uid, {
|
|
1528
|
+
schema_id: desc.schema_id,
|
|
1529
|
+
object_type: desc.object_type
|
|
1530
|
+
}));
|
|
1519
1531
|
}
|
|
1520
1532
|
case "object_context": {
|
|
1521
1533
|
const uid = args.uid;
|
|
1522
1534
|
if (!uid) return err2(`uid is required for ${desc.name}`);
|
|
1523
1535
|
const depth = typeof args.depth === "number" ? args.depth : void 0;
|
|
1524
|
-
return ok2(await
|
|
1536
|
+
return ok2(await ontologyClient.getDomainObjectContext(uid, depth, {
|
|
1537
|
+
schema_id: desc.schema_id,
|
|
1538
|
+
object_type: desc.object_type
|
|
1539
|
+
}));
|
|
1540
|
+
}
|
|
1541
|
+
case "related": {
|
|
1542
|
+
const uid = args.uid;
|
|
1543
|
+
if (!uid) return err2(`uid is required for ${desc.name}`);
|
|
1544
|
+
if (!desc.relation || !desc.entry_role || !desc.far_type) {
|
|
1545
|
+
return err2(`invalid related descriptor: ${desc.name}`);
|
|
1546
|
+
}
|
|
1547
|
+
if (!ontologyClient.queryRelatedDomainObjects) {
|
|
1548
|
+
return err2(
|
|
1549
|
+
"related ontology tools require a graph-aware version of the mindgraph SDK"
|
|
1550
|
+
);
|
|
1551
|
+
}
|
|
1552
|
+
return ok2(await ontologyClient.queryRelatedDomainObjects({
|
|
1553
|
+
schema_id: desc.schema_id,
|
|
1554
|
+
entry_type: desc.object_type,
|
|
1555
|
+
uid,
|
|
1556
|
+
relation: desc.relation,
|
|
1557
|
+
entry_role: desc.entry_role,
|
|
1558
|
+
far_type: desc.far_type,
|
|
1559
|
+
where: Array.isArray(args.where) ? args.where : void 0,
|
|
1560
|
+
include_provenance: args.include_provenance === true,
|
|
1561
|
+
limit: typeof args.limit === "number" ? args.limit : void 0,
|
|
1562
|
+
offset: typeof args.offset === "number" ? args.offset : void 0
|
|
1563
|
+
}));
|
|
1564
|
+
}
|
|
1565
|
+
case "structured_query": {
|
|
1566
|
+
const select = args.select;
|
|
1567
|
+
if (!select) return err2(`select is required for ${desc.name}`);
|
|
1568
|
+
if (!ontologyClient.queryDomainStructured) {
|
|
1569
|
+
return err2(
|
|
1570
|
+
"structured ontology tools require a graph-aware version of the mindgraph SDK"
|
|
1571
|
+
);
|
|
1572
|
+
}
|
|
1573
|
+
return ok2(await ontologyClient.queryDomainStructured({
|
|
1574
|
+
...args,
|
|
1575
|
+
schema_id: desc.schema_id,
|
|
1576
|
+
select
|
|
1577
|
+
}));
|
|
1525
1578
|
}
|
|
1526
1579
|
default:
|
|
1527
1580
|
return err2(`unknown generated tool mapping: ${desc.maps_to}`);
|
|
@@ -1530,7 +1583,7 @@ async function handleGeneratedTool(client2, desc, args) {
|
|
|
1530
1583
|
return err2(e instanceof Error ? e.message : String(e));
|
|
1531
1584
|
}
|
|
1532
1585
|
}
|
|
1533
|
-
var ok2, err2, CACHE_TTL_MS, cache;
|
|
1586
|
+
var ok2, err2, CACHE_TTL_MS, cache, DuplicateGeneratedToolError;
|
|
1534
1587
|
var init_generated_tools = __esm({
|
|
1535
1588
|
"src/generated-tools.ts"() {
|
|
1536
1589
|
"use strict";
|
|
@@ -1543,6 +1596,101 @@ var init_generated_tools = __esm({
|
|
|
1543
1596
|
});
|
|
1544
1597
|
CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
1545
1598
|
cache = null;
|
|
1599
|
+
DuplicateGeneratedToolError = class extends Error {
|
|
1600
|
+
};
|
|
1601
|
+
}
|
|
1602
|
+
});
|
|
1603
|
+
|
|
1604
|
+
// src/governance.ts
|
|
1605
|
+
function headers(apiKey, orgId) {
|
|
1606
|
+
const value = {
|
|
1607
|
+
authorization: `Bearer ${apiKey}`,
|
|
1608
|
+
"content-type": "application/json"
|
|
1609
|
+
};
|
|
1610
|
+
if (orgId) value["x-mindgraph-org"] = orgId;
|
|
1611
|
+
return value;
|
|
1612
|
+
}
|
|
1613
|
+
function unsupportedResponse(status, body) {
|
|
1614
|
+
if (status === 404 || status === 405) return true;
|
|
1615
|
+
if (status !== 400) return false;
|
|
1616
|
+
const lower = body.toLowerCase();
|
|
1617
|
+
return lower.includes("unknown governance action") || lower.includes("unknown action") || lower.includes("invalid_governance_action");
|
|
1618
|
+
}
|
|
1619
|
+
async function checkMcpGovernance(toolName, args, config) {
|
|
1620
|
+
if (config.disabled || capability === "unsupported") return { allowed: true };
|
|
1621
|
+
const fetchImpl = config.fetchImpl ?? fetch;
|
|
1622
|
+
let response;
|
|
1623
|
+
let body;
|
|
1624
|
+
try {
|
|
1625
|
+
response = await fetchImpl(`${config.baseUrl.replace(/\/$/, "")}/agent/governance`, {
|
|
1626
|
+
method: "POST",
|
|
1627
|
+
headers: headers(config.apiKey, config.orgId),
|
|
1628
|
+
body: JSON.stringify({
|
|
1629
|
+
action: "check",
|
|
1630
|
+
act: "tool_invoke",
|
|
1631
|
+
agent_id: String(args.agent_id || config.agentId),
|
|
1632
|
+
target: { tool_name: toolName },
|
|
1633
|
+
context: { adapter: "mindgraph-mcp" },
|
|
1634
|
+
tier: "checkpoint"
|
|
1635
|
+
})
|
|
1636
|
+
});
|
|
1637
|
+
body = await response.text();
|
|
1638
|
+
} catch (error) {
|
|
1639
|
+
return {
|
|
1640
|
+
allowed: false,
|
|
1641
|
+
message: `MindGraph governance could not establish permission: ${error instanceof Error ? error.message : String(error)}`
|
|
1642
|
+
};
|
|
1643
|
+
}
|
|
1644
|
+
if (!response.ok) {
|
|
1645
|
+
if (capability === "unknown" && unsupportedResponse(response.status, body)) {
|
|
1646
|
+
capability = "unsupported";
|
|
1647
|
+
return { allowed: true };
|
|
1648
|
+
}
|
|
1649
|
+
return {
|
|
1650
|
+
allowed: false,
|
|
1651
|
+
message: `MindGraph governance check failed (${response.status})`
|
|
1652
|
+
};
|
|
1653
|
+
}
|
|
1654
|
+
capability = "supported";
|
|
1655
|
+
let decision;
|
|
1656
|
+
try {
|
|
1657
|
+
decision = JSON.parse(body);
|
|
1658
|
+
} catch {
|
|
1659
|
+
return { allowed: false, message: "MindGraph governance returned an invalid decision" };
|
|
1660
|
+
}
|
|
1661
|
+
const obligations = Array.isArray(decision.obligations) ? decision.obligations : [];
|
|
1662
|
+
const unknownDuty = obligations.find((obligation) => {
|
|
1663
|
+
if (!obligation || typeof obligation !== "object") return true;
|
|
1664
|
+
const duty = obligation.duty;
|
|
1665
|
+
return typeof duty !== "string" || !KNOWN_DUTIES.has(duty);
|
|
1666
|
+
});
|
|
1667
|
+
if (unknownDuty) {
|
|
1668
|
+
return {
|
|
1669
|
+
allowed: false,
|
|
1670
|
+
decision: String(decision.decision || "conditional"),
|
|
1671
|
+
message: "MindGraph governance returned an obligation this adapter cannot safely enforce"
|
|
1672
|
+
};
|
|
1673
|
+
}
|
|
1674
|
+
const verdict = String(decision.decision || "deny");
|
|
1675
|
+
if (verdict === "permit") return { allowed: true };
|
|
1676
|
+
const fired = Array.isArray(decision.fired_policies) ? decision.fired_policies : [];
|
|
1677
|
+
const first = fired[0];
|
|
1678
|
+
const policy = first && typeof first.name === "string" ? first.name : void 0;
|
|
1679
|
+
const approvalUid = typeof decision.approval_uid === "string" ? decision.approval_uid : void 0;
|
|
1680
|
+
return {
|
|
1681
|
+
allowed: false,
|
|
1682
|
+
decision: verdict,
|
|
1683
|
+
approval_uid: approvalUid,
|
|
1684
|
+
policy,
|
|
1685
|
+
message: verdict === "conditional" ? `Approval is required${policy ? ` by policy ${policy}` : ""}${approvalUid ? ` (approval ${approvalUid})` : ""}` : `Denied by MindGraph governance${policy ? ` policy ${policy}` : ""}`
|
|
1686
|
+
};
|
|
1687
|
+
}
|
|
1688
|
+
var capability, KNOWN_DUTIES;
|
|
1689
|
+
var init_governance = __esm({
|
|
1690
|
+
"src/governance.ts"() {
|
|
1691
|
+
"use strict";
|
|
1692
|
+
capability = "unknown";
|
|
1693
|
+
KNOWN_DUTIES = /* @__PURE__ */ new Set(["log", "require_approval"]);
|
|
1546
1694
|
}
|
|
1547
1695
|
});
|
|
1548
1696
|
|
|
@@ -1565,6 +1713,7 @@ var init_src = __esm({
|
|
|
1565
1713
|
import_mindgraph = require("mindgraph");
|
|
1566
1714
|
init_tools();
|
|
1567
1715
|
init_generated_tools();
|
|
1716
|
+
init_governance();
|
|
1568
1717
|
API_KEY = process.env.MINDGRAPH_API_KEY;
|
|
1569
1718
|
BASE_URL = process.env.MINDGRAPH_BASE_URL || "https://api.mindgraph.cloud";
|
|
1570
1719
|
AGENT_ID = process.env.MINDGRAPH_AGENT_ID || "mcp";
|
|
@@ -1578,7 +1727,11 @@ var init_src = __esm({
|
|
|
1578
1727
|
client = new import_mindgraph.MindGraph({
|
|
1579
1728
|
baseUrl: BASE_URL,
|
|
1580
1729
|
apiKey: API_KEY,
|
|
1581
|
-
orgId: ORG_ID
|
|
1730
|
+
orgId: ORG_ID,
|
|
1731
|
+
// Available in the companion mindgraph SDK from the D6 telemetry batch.
|
|
1732
|
+
// Cast keeps this repository buildable during the cross-package release
|
|
1733
|
+
// window where npm may still resolve the preceding SDK declaration file.
|
|
1734
|
+
telemetrySurface: "mcp"
|
|
1582
1735
|
});
|
|
1583
1736
|
INSTRUCTIONS = `You have access to a persistent knowledge graph via MindGraph (7 tools).
|
|
1584
1737
|
|
|
@@ -1658,7 +1811,7 @@ Capture knowledge when the user shares something worth remembering:
|
|
|
1658
1811
|
server = new import_server.Server(
|
|
1659
1812
|
{
|
|
1660
1813
|
name: "mindgraph",
|
|
1661
|
-
version: "0.
|
|
1814
|
+
version: "0.12.0"
|
|
1662
1815
|
},
|
|
1663
1816
|
{
|
|
1664
1817
|
capabilities: {
|
|
@@ -1679,6 +1832,19 @@ Capture knowledge when the user shares something worth remembering:
|
|
|
1679
1832
|
if (!toolArgs.agent_id) {
|
|
1680
1833
|
toolArgs.agent_id = AGENT_ID;
|
|
1681
1834
|
}
|
|
1835
|
+
const governance = await checkMcpGovernance(name, toolArgs, {
|
|
1836
|
+
baseUrl: BASE_URL,
|
|
1837
|
+
apiKey: API_KEY,
|
|
1838
|
+
orgId: ORG_ID,
|
|
1839
|
+
agentId: AGENT_ID,
|
|
1840
|
+
disabled: process.env.MINDGRAPH_GOVERNANCE === "off"
|
|
1841
|
+
});
|
|
1842
|
+
if (!governance.allowed) {
|
|
1843
|
+
return {
|
|
1844
|
+
content: [{ type: "text", text: JSON.stringify({ error: governance.message, ...governance }) }],
|
|
1845
|
+
isError: true
|
|
1846
|
+
};
|
|
1847
|
+
}
|
|
1682
1848
|
const generated = await getGeneratedTools(client);
|
|
1683
1849
|
const desc = generated.byName.get(name);
|
|
1684
1850
|
if (desc) {
|
package/dist/index.js
CHANGED
|
@@ -1452,6 +1452,8 @@ var err2 = (message) => ({
|
|
|
1452
1452
|
});
|
|
1453
1453
|
var CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
1454
1454
|
var cache = null;
|
|
1455
|
+
var DuplicateGeneratedToolError = class extends Error {
|
|
1456
|
+
};
|
|
1455
1457
|
async function getGeneratedTools(client2) {
|
|
1456
1458
|
if (cache && Date.now() - cache.fetchedAt < CACHE_TTL_MS) {
|
|
1457
1459
|
return { tools: cache.tools, byName: cache.byName };
|
|
@@ -1466,6 +1468,11 @@ async function getGeneratedTools(client2) {
|
|
|
1466
1468
|
const byName = /* @__PURE__ */ new Map();
|
|
1467
1469
|
const tools = [];
|
|
1468
1470
|
for (const d of resp.tools ?? []) {
|
|
1471
|
+
if (byName.has(d.name)) {
|
|
1472
|
+
throw new DuplicateGeneratedToolError(
|
|
1473
|
+
`duplicate generated ontology tool name: ${d.name}`
|
|
1474
|
+
);
|
|
1475
|
+
}
|
|
1469
1476
|
byName.set(d.name, d);
|
|
1470
1477
|
tools.push({
|
|
1471
1478
|
name: d.name,
|
|
@@ -1475,22 +1482,26 @@ async function getGeneratedTools(client2) {
|
|
|
1475
1482
|
}
|
|
1476
1483
|
cache = { tools, byName, fetchedAt: Date.now() };
|
|
1477
1484
|
return { tools, byName };
|
|
1478
|
-
} catch {
|
|
1485
|
+
} catch (error) {
|
|
1486
|
+
if (error instanceof DuplicateGeneratedToolError) throw error;
|
|
1479
1487
|
cache = { tools: [], byName: /* @__PURE__ */ new Map(), fetchedAt: Date.now() };
|
|
1480
1488
|
return { tools: cache.tools, byName: cache.byName };
|
|
1481
1489
|
}
|
|
1482
1490
|
}
|
|
1483
1491
|
async function handleGeneratedTool(client2, desc, args) {
|
|
1484
1492
|
try {
|
|
1493
|
+
const ontologyClient = client2;
|
|
1485
1494
|
switch (desc.maps_to) {
|
|
1486
1495
|
case "search": {
|
|
1487
1496
|
const query = args.query;
|
|
1488
1497
|
if (!query) return err2(`query is required for ${desc.name}`);
|
|
1489
1498
|
const limit = typeof args.limit === "number" ? args.limit : void 0;
|
|
1499
|
+
const filters = Array.isArray(args.filters) ? args.filters : void 0;
|
|
1490
1500
|
return ok2(
|
|
1491
|
-
await
|
|
1501
|
+
await ontologyClient.searchDomainObjects(query, {
|
|
1492
1502
|
schema_id: desc.schema_id,
|
|
1493
1503
|
object_types: [desc.object_type],
|
|
1504
|
+
filters,
|
|
1494
1505
|
limit
|
|
1495
1506
|
})
|
|
1496
1507
|
);
|
|
@@ -1498,13 +1509,57 @@ async function handleGeneratedTool(client2, desc, args) {
|
|
|
1498
1509
|
case "object": {
|
|
1499
1510
|
const uid = args.uid;
|
|
1500
1511
|
if (!uid) return err2(`uid is required for ${desc.name}`);
|
|
1501
|
-
return ok2(await
|
|
1512
|
+
return ok2(await ontologyClient.getDomainObject(uid, {
|
|
1513
|
+
schema_id: desc.schema_id,
|
|
1514
|
+
object_type: desc.object_type
|
|
1515
|
+
}));
|
|
1502
1516
|
}
|
|
1503
1517
|
case "object_context": {
|
|
1504
1518
|
const uid = args.uid;
|
|
1505
1519
|
if (!uid) return err2(`uid is required for ${desc.name}`);
|
|
1506
1520
|
const depth = typeof args.depth === "number" ? args.depth : void 0;
|
|
1507
|
-
return ok2(await
|
|
1521
|
+
return ok2(await ontologyClient.getDomainObjectContext(uid, depth, {
|
|
1522
|
+
schema_id: desc.schema_id,
|
|
1523
|
+
object_type: desc.object_type
|
|
1524
|
+
}));
|
|
1525
|
+
}
|
|
1526
|
+
case "related": {
|
|
1527
|
+
const uid = args.uid;
|
|
1528
|
+
if (!uid) return err2(`uid is required for ${desc.name}`);
|
|
1529
|
+
if (!desc.relation || !desc.entry_role || !desc.far_type) {
|
|
1530
|
+
return err2(`invalid related descriptor: ${desc.name}`);
|
|
1531
|
+
}
|
|
1532
|
+
if (!ontologyClient.queryRelatedDomainObjects) {
|
|
1533
|
+
return err2(
|
|
1534
|
+
"related ontology tools require a graph-aware version of the mindgraph SDK"
|
|
1535
|
+
);
|
|
1536
|
+
}
|
|
1537
|
+
return ok2(await ontologyClient.queryRelatedDomainObjects({
|
|
1538
|
+
schema_id: desc.schema_id,
|
|
1539
|
+
entry_type: desc.object_type,
|
|
1540
|
+
uid,
|
|
1541
|
+
relation: desc.relation,
|
|
1542
|
+
entry_role: desc.entry_role,
|
|
1543
|
+
far_type: desc.far_type,
|
|
1544
|
+
where: Array.isArray(args.where) ? args.where : void 0,
|
|
1545
|
+
include_provenance: args.include_provenance === true,
|
|
1546
|
+
limit: typeof args.limit === "number" ? args.limit : void 0,
|
|
1547
|
+
offset: typeof args.offset === "number" ? args.offset : void 0
|
|
1548
|
+
}));
|
|
1549
|
+
}
|
|
1550
|
+
case "structured_query": {
|
|
1551
|
+
const select = args.select;
|
|
1552
|
+
if (!select) return err2(`select is required for ${desc.name}`);
|
|
1553
|
+
if (!ontologyClient.queryDomainStructured) {
|
|
1554
|
+
return err2(
|
|
1555
|
+
"structured ontology tools require a graph-aware version of the mindgraph SDK"
|
|
1556
|
+
);
|
|
1557
|
+
}
|
|
1558
|
+
return ok2(await ontologyClient.queryDomainStructured({
|
|
1559
|
+
...args,
|
|
1560
|
+
schema_id: desc.schema_id,
|
|
1561
|
+
select
|
|
1562
|
+
}));
|
|
1508
1563
|
}
|
|
1509
1564
|
default:
|
|
1510
1565
|
return err2(`unknown generated tool mapping: ${desc.maps_to}`);
|
|
@@ -1514,6 +1569,93 @@ async function handleGeneratedTool(client2, desc, args) {
|
|
|
1514
1569
|
}
|
|
1515
1570
|
}
|
|
1516
1571
|
|
|
1572
|
+
// src/governance.ts
|
|
1573
|
+
var capability = "unknown";
|
|
1574
|
+
var KNOWN_DUTIES = /* @__PURE__ */ new Set(["log", "require_approval"]);
|
|
1575
|
+
function headers(apiKey, orgId) {
|
|
1576
|
+
const value = {
|
|
1577
|
+
authorization: `Bearer ${apiKey}`,
|
|
1578
|
+
"content-type": "application/json"
|
|
1579
|
+
};
|
|
1580
|
+
if (orgId) value["x-mindgraph-org"] = orgId;
|
|
1581
|
+
return value;
|
|
1582
|
+
}
|
|
1583
|
+
function unsupportedResponse(status, body) {
|
|
1584
|
+
if (status === 404 || status === 405) return true;
|
|
1585
|
+
if (status !== 400) return false;
|
|
1586
|
+
const lower = body.toLowerCase();
|
|
1587
|
+
return lower.includes("unknown governance action") || lower.includes("unknown action") || lower.includes("invalid_governance_action");
|
|
1588
|
+
}
|
|
1589
|
+
async function checkMcpGovernance(toolName, args, config) {
|
|
1590
|
+
if (config.disabled || capability === "unsupported") return { allowed: true };
|
|
1591
|
+
const fetchImpl = config.fetchImpl ?? fetch;
|
|
1592
|
+
let response;
|
|
1593
|
+
let body;
|
|
1594
|
+
try {
|
|
1595
|
+
response = await fetchImpl(`${config.baseUrl.replace(/\/$/, "")}/agent/governance`, {
|
|
1596
|
+
method: "POST",
|
|
1597
|
+
headers: headers(config.apiKey, config.orgId),
|
|
1598
|
+
body: JSON.stringify({
|
|
1599
|
+
action: "check",
|
|
1600
|
+
act: "tool_invoke",
|
|
1601
|
+
agent_id: String(args.agent_id || config.agentId),
|
|
1602
|
+
target: { tool_name: toolName },
|
|
1603
|
+
context: { adapter: "mindgraph-mcp" },
|
|
1604
|
+
tier: "checkpoint"
|
|
1605
|
+
})
|
|
1606
|
+
});
|
|
1607
|
+
body = await response.text();
|
|
1608
|
+
} catch (error) {
|
|
1609
|
+
return {
|
|
1610
|
+
allowed: false,
|
|
1611
|
+
message: `MindGraph governance could not establish permission: ${error instanceof Error ? error.message : String(error)}`
|
|
1612
|
+
};
|
|
1613
|
+
}
|
|
1614
|
+
if (!response.ok) {
|
|
1615
|
+
if (capability === "unknown" && unsupportedResponse(response.status, body)) {
|
|
1616
|
+
capability = "unsupported";
|
|
1617
|
+
return { allowed: true };
|
|
1618
|
+
}
|
|
1619
|
+
return {
|
|
1620
|
+
allowed: false,
|
|
1621
|
+
message: `MindGraph governance check failed (${response.status})`
|
|
1622
|
+
};
|
|
1623
|
+
}
|
|
1624
|
+
capability = "supported";
|
|
1625
|
+
let decision;
|
|
1626
|
+
try {
|
|
1627
|
+
decision = JSON.parse(body);
|
|
1628
|
+
} catch {
|
|
1629
|
+
return { allowed: false, message: "MindGraph governance returned an invalid decision" };
|
|
1630
|
+
}
|
|
1631
|
+
const obligations = Array.isArray(decision.obligations) ? decision.obligations : [];
|
|
1632
|
+
const unknownDuty = obligations.find((obligation) => {
|
|
1633
|
+
if (!obligation || typeof obligation !== "object") return true;
|
|
1634
|
+
const duty = obligation.duty;
|
|
1635
|
+
return typeof duty !== "string" || !KNOWN_DUTIES.has(duty);
|
|
1636
|
+
});
|
|
1637
|
+
if (unknownDuty) {
|
|
1638
|
+
return {
|
|
1639
|
+
allowed: false,
|
|
1640
|
+
decision: String(decision.decision || "conditional"),
|
|
1641
|
+
message: "MindGraph governance returned an obligation this adapter cannot safely enforce"
|
|
1642
|
+
};
|
|
1643
|
+
}
|
|
1644
|
+
const verdict = String(decision.decision || "deny");
|
|
1645
|
+
if (verdict === "permit") return { allowed: true };
|
|
1646
|
+
const fired = Array.isArray(decision.fired_policies) ? decision.fired_policies : [];
|
|
1647
|
+
const first = fired[0];
|
|
1648
|
+
const policy = first && typeof first.name === "string" ? first.name : void 0;
|
|
1649
|
+
const approvalUid = typeof decision.approval_uid === "string" ? decision.approval_uid : void 0;
|
|
1650
|
+
return {
|
|
1651
|
+
allowed: false,
|
|
1652
|
+
decision: verdict,
|
|
1653
|
+
approval_uid: approvalUid,
|
|
1654
|
+
policy,
|
|
1655
|
+
message: verdict === "conditional" ? `Approval is required${policy ? ` by policy ${policy}` : ""}${approvalUid ? ` (approval ${approvalUid})` : ""}` : `Denied by MindGraph governance${policy ? ` policy ${policy}` : ""}`
|
|
1656
|
+
};
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1517
1659
|
// src/index.ts
|
|
1518
1660
|
var API_KEY = process.env.MINDGRAPH_API_KEY;
|
|
1519
1661
|
var BASE_URL = process.env.MINDGRAPH_BASE_URL || "https://api.mindgraph.cloud";
|
|
@@ -1528,7 +1670,11 @@ if (!API_KEY) {
|
|
|
1528
1670
|
var client = new import_mindgraph.MindGraph({
|
|
1529
1671
|
baseUrl: BASE_URL,
|
|
1530
1672
|
apiKey: API_KEY,
|
|
1531
|
-
orgId: ORG_ID
|
|
1673
|
+
orgId: ORG_ID,
|
|
1674
|
+
// Available in the companion mindgraph SDK from the D6 telemetry batch.
|
|
1675
|
+
// Cast keeps this repository buildable during the cross-package release
|
|
1676
|
+
// window where npm may still resolve the preceding SDK declaration file.
|
|
1677
|
+
telemetrySurface: "mcp"
|
|
1532
1678
|
});
|
|
1533
1679
|
var INSTRUCTIONS = `You have access to a persistent knowledge graph via MindGraph (7 tools).
|
|
1534
1680
|
|
|
@@ -1608,7 +1754,7 @@ Capture knowledge when the user shares something worth remembering:
|
|
|
1608
1754
|
var server = new import_server.Server(
|
|
1609
1755
|
{
|
|
1610
1756
|
name: "mindgraph",
|
|
1611
|
-
version: "0.
|
|
1757
|
+
version: "0.12.0"
|
|
1612
1758
|
},
|
|
1613
1759
|
{
|
|
1614
1760
|
capabilities: {
|
|
@@ -1629,6 +1775,19 @@ server.setRequestHandler(import_types.CallToolRequestSchema, async (request) =>
|
|
|
1629
1775
|
if (!toolArgs.agent_id) {
|
|
1630
1776
|
toolArgs.agent_id = AGENT_ID;
|
|
1631
1777
|
}
|
|
1778
|
+
const governance = await checkMcpGovernance(name, toolArgs, {
|
|
1779
|
+
baseUrl: BASE_URL,
|
|
1780
|
+
apiKey: API_KEY,
|
|
1781
|
+
orgId: ORG_ID,
|
|
1782
|
+
agentId: AGENT_ID,
|
|
1783
|
+
disabled: process.env.MINDGRAPH_GOVERNANCE === "off"
|
|
1784
|
+
});
|
|
1785
|
+
if (!governance.allowed) {
|
|
1786
|
+
return {
|
|
1787
|
+
content: [{ type: "text", text: JSON.stringify({ error: governance.message, ...governance }) }],
|
|
1788
|
+
isError: true
|
|
1789
|
+
};
|
|
1790
|
+
}
|
|
1632
1791
|
const generated = await getGeneratedTools(client);
|
|
1633
1792
|
const desc = generated.byName.get(name);
|
|
1634
1793
|
if (desc) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mindgraph-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "MCP server for MindGraph — connect Claude Desktop, Claude Code, and any MCP client to your knowledge graph",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"license": "MIT",
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
35
|
-
"mindgraph": "^0.
|
|
35
|
+
"mindgraph": "^0.13.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@types/node": "^22.0.0",
|