mindgraph-mcp 0.13.3 → 0.13.5

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.
Files changed (3) hide show
  1. package/dist/cli.js +237 -212
  2. package/dist/index.js +217 -202
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -1486,9 +1486,13 @@ var init_tools = __esm({
1486
1486
 
1487
1487
  // src/generated-tools.ts
1488
1488
  async function getGeneratedTools(client2) {
1489
- if (cache && Date.now() - cache.fetchedAt < CACHE_TTL_MS) {
1489
+ const now = Date.now();
1490
+ if (cache && now - cache.fetchedAt < CACHE_TTL_MS) {
1490
1491
  return { tools: cache.tools, byName: cache.byName };
1491
1492
  }
1493
+ if (now < retryNotBefore) {
1494
+ return cache ? { tools: cache.tools, byName: cache.byName } : EMPTY;
1495
+ }
1492
1496
  try {
1493
1497
  const c = client2;
1494
1498
  if (typeof c.listOntologyTools !== "function") {
@@ -1512,11 +1516,12 @@ async function getGeneratedTools(client2) {
1512
1516
  });
1513
1517
  }
1514
1518
  cache = { tools, byName, fetchedAt: Date.now() };
1519
+ retryNotBefore = 0;
1515
1520
  return { tools, byName };
1516
1521
  } catch (error) {
1517
1522
  if (error instanceof DuplicateGeneratedToolError) throw error;
1518
- cache = { tools: [], byName: /* @__PURE__ */ new Map(), fetchedAt: Date.now() };
1519
- return { tools: cache.tools, byName: cache.byName };
1523
+ retryNotBefore = Date.now() + FAILURE_COOLDOWN_MS;
1524
+ return cache ? { tools: cache.tools, byName: cache.byName } : EMPTY;
1520
1525
  }
1521
1526
  }
1522
1527
  async function handleGeneratedTool(client2, desc, args) {
@@ -1586,11 +1591,14 @@ async function handleGeneratedTool(client2, desc, args) {
1586
1591
  "structured ontology tools require a graph-aware version of the mindgraph SDK"
1587
1592
  );
1588
1593
  }
1589
- return ok2(await ontologyClient.queryDomainStructured({
1590
- ...args,
1594
+ const request = {
1591
1595
  schema_id: desc.schema_id,
1592
1596
  select
1593
- }));
1597
+ };
1598
+ for (const field of STRUCTURED_QUERY_PASSTHROUGH) {
1599
+ if (args[field] !== void 0) request[field] = args[field];
1600
+ }
1601
+ return ok2(await ontologyClient.queryDomainStructured(request));
1594
1602
  }
1595
1603
  default:
1596
1604
  return err2(`unknown generated tool mapping: ${desc.maps_to}`);
@@ -1599,7 +1607,7 @@ async function handleGeneratedTool(client2, desc, args) {
1599
1607
  return err2(e instanceof Error ? e.message : String(e));
1600
1608
  }
1601
1609
  }
1602
- var ok2, err2, CACHE_TTL_MS, cache, DuplicateGeneratedToolError;
1610
+ var ok2, err2, CACHE_TTL_MS, FAILURE_COOLDOWN_MS, cache, retryNotBefore, EMPTY, DuplicateGeneratedToolError, STRUCTURED_QUERY_PASSTHROUGH;
1603
1611
  var init_generated_tools = __esm({
1604
1612
  "src/generated-tools.ts"() {
1605
1613
  "use strict";
@@ -1611,13 +1619,33 @@ var init_generated_tools = __esm({
1611
1619
  isError: true
1612
1620
  });
1613
1621
  CACHE_TTL_MS = 5 * 60 * 1e3;
1622
+ FAILURE_COOLDOWN_MS = 15 * 1e3;
1614
1623
  cache = null;
1624
+ retryNotBefore = 0;
1625
+ EMPTY = {
1626
+ tools: [],
1627
+ byName: /* @__PURE__ */ new Map()
1628
+ };
1615
1629
  DuplicateGeneratedToolError = class extends Error {
1616
1630
  };
1631
+ STRUCTURED_QUERY_PASSTHROUGH = [
1632
+ "anchor",
1633
+ "path",
1634
+ "where",
1635
+ "include",
1636
+ "page",
1637
+ "aggregate"
1638
+ ];
1617
1639
  }
1618
1640
  });
1619
1641
 
1620
1642
  // src/governance.ts
1643
+ function isTransientStatus(status) {
1644
+ return status === 408 || status === 425 || status === 429 || status >= 500;
1645
+ }
1646
+ function sleep(ms) {
1647
+ return new Promise((resolve) => setTimeout(resolve, ms));
1648
+ }
1621
1649
  function headers(apiKey, orgId) {
1622
1650
  const value = {
1623
1651
  authorization: `Bearer ${apiKey}`,
@@ -1633,41 +1661,81 @@ function unsupportedResponse(status, body) {
1633
1661
  return lower.includes("unknown governance action") || lower.includes("unknown action") || lower.includes("invalid_governance_action");
1634
1662
  }
1635
1663
  async function checkMcpGovernance(toolName, args, config) {
1636
- if (config.disabled || capability === "unsupported") return { allowed: true };
1664
+ if (config.disabled) return { allowed: true };
1665
+ if (capability === "unsupported") {
1666
+ if (Date.now() < unsupportedUntil) return { allowed: true };
1667
+ capability = "unknown";
1668
+ }
1637
1669
  const fetchImpl = config.fetchImpl ?? fetch;
1670
+ const retryDelays = config.retryDelaysMs ?? DEFAULT_RETRY_DELAYS_MS;
1638
1671
  let response;
1639
- let body;
1640
- try {
1641
- response = await fetchImpl(`${config.baseUrl.replace(/\/$/, "")}/agent/governance`, {
1642
- method: "POST",
1643
- headers: headers(config.apiKey, config.orgId),
1644
- body: JSON.stringify({
1645
- action: "check",
1646
- act: "tool_invoke",
1647
- agent_id: String(args.agent_id || config.agentId),
1648
- target: { tool_name: toolName },
1649
- context: { adapter: "mindgraph-mcp" },
1650
- tier: "checkpoint"
1651
- })
1652
- });
1653
- body = await response.text();
1654
- } catch (error) {
1672
+ let body = "";
1673
+ let lastFailure = "";
1674
+ for (let attempt = 0; attempt <= retryDelays.length; attempt++) {
1675
+ try {
1676
+ const candidate = await fetchImpl(
1677
+ `${config.baseUrl.replace(/\/$/, "")}/agent/governance`,
1678
+ {
1679
+ method: "POST",
1680
+ headers: headers(config.apiKey, config.orgId),
1681
+ body: JSON.stringify({
1682
+ action: "check",
1683
+ act: "tool_invoke",
1684
+ agent_id: String(args.agent_id || config.agentId),
1685
+ target: { tool_name: toolName },
1686
+ context: { adapter: "mindgraph-mcp", ...config.context },
1687
+ tier: "checkpoint"
1688
+ })
1689
+ }
1690
+ );
1691
+ const candidateBody = await candidate.text();
1692
+ if (isTransientStatus(candidate.status) && attempt < retryDelays.length) {
1693
+ lastFailure = `HTTP ${candidate.status}`;
1694
+ await sleep(retryDelays[attempt]);
1695
+ continue;
1696
+ }
1697
+ response = candidate;
1698
+ body = candidateBody;
1699
+ break;
1700
+ } catch (error) {
1701
+ lastFailure = error instanceof Error ? error.message : String(error);
1702
+ if (attempt < retryDelays.length) {
1703
+ await sleep(retryDelays[attempt]);
1704
+ continue;
1705
+ }
1706
+ }
1707
+ }
1708
+ if (!response) {
1655
1709
  return {
1656
1710
  allowed: false,
1657
- message: `MindGraph governance could not establish permission: ${error instanceof Error ? error.message : String(error)}`
1711
+ message: `MindGraph governance could not establish permission after ${retryDelays.length + 1} attempts (${lastFailure}). Set MINDGRAPH_GOVERNANCE=off to run this adapter ungoverned.`
1658
1712
  };
1659
1713
  }
1660
1714
  if (!response.ok) {
1661
1715
  if (capability === "unknown" && unsupportedResponse(response.status, body)) {
1662
1716
  capability = "unsupported";
1717
+ unsupportedUntil = Date.now() + UNSUPPORTED_LEASE_MS;
1718
+ if (!unsupportedLogged) {
1719
+ unsupportedLogged = true;
1720
+ console.error(
1721
+ `[mindgraph-mcp] This MindGraph server does not implement the governance checkpoint (HTTP ${response.status}); tool calls proceed ungoverned. Re-probing every ${Math.round(UNSUPPORTED_LEASE_MS / 6e4)} minutes.`
1722
+ );
1723
+ }
1663
1724
  return { allowed: true };
1664
1725
  }
1726
+ if (response.status === 401 || response.status === 403) {
1727
+ return {
1728
+ allowed: false,
1729
+ message: `This credential is not permitted to evaluate MindGraph governance (HTTP ${response.status}). Use a user-scoped API key, or set MINDGRAPH_GOVERNANCE=off to run this adapter ungoverned.`
1730
+ };
1731
+ }
1665
1732
  return {
1666
1733
  allowed: false,
1667
1734
  message: `MindGraph governance check failed (${response.status})`
1668
1735
  };
1669
1736
  }
1670
1737
  capability = "supported";
1738
+ unsupportedLogged = false;
1671
1739
  let decision;
1672
1740
  try {
1673
1741
  decision = JSON.parse(body);
@@ -1701,15 +1769,130 @@ async function checkMcpGovernance(toolName, args, config) {
1701
1769
  message: verdict === "conditional" ? `Approval is required${policy ? ` by policy ${policy}` : ""}${approvalUid ? ` (approval ${approvalUid})` : ""}` : `Denied by MindGraph governance${policy ? ` policy ${policy}` : ""}`
1702
1770
  };
1703
1771
  }
1704
- var capability, KNOWN_DUTIES;
1772
+ var capability, UNSUPPORTED_LEASE_MS, unsupportedUntil, unsupportedLogged, DEFAULT_RETRY_DELAYS_MS, KNOWN_DUTIES;
1705
1773
  var init_governance = __esm({
1706
1774
  "src/governance.ts"() {
1707
1775
  "use strict";
1708
1776
  capability = "unknown";
1777
+ UNSUPPORTED_LEASE_MS = 5 * 60 * 1e3;
1778
+ unsupportedUntil = 0;
1779
+ unsupportedLogged = false;
1780
+ DEFAULT_RETRY_DELAYS_MS = [150, 600];
1709
1781
  KNOWN_DUTIES = /* @__PURE__ */ new Set(["log", "require_approval"]);
1710
1782
  }
1711
1783
  });
1712
1784
 
1785
+ // src/resources.ts
1786
+ function json(uri, data) {
1787
+ return {
1788
+ contents: [{ uri, mimeType: "application/json", text: JSON.stringify(data, null, 2) }]
1789
+ };
1790
+ }
1791
+ async function readResource(client2, uri) {
1792
+ switch (uri) {
1793
+ case "mindgraph://stats":
1794
+ return json(uri, await client2.stats());
1795
+ case "mindgraph://goals":
1796
+ return json(uri, await client2.getGoals());
1797
+ case "mindgraph://questions":
1798
+ return json(uri, await client2.getOpenQuestions());
1799
+ case "mindgraph://contradictions":
1800
+ return json(uri, await client2.getContradictions());
1801
+ case "mindgraph://decisions":
1802
+ return json(uri, await client2.getOpenDecisions());
1803
+ }
1804
+ const nodeMatch = uri.match(/^mindgraph:\/\/node\/(.+)$/);
1805
+ if (nodeMatch) {
1806
+ const uid = decodeURIComponent(nodeMatch[1]);
1807
+ const node = await client2.getNode(uid);
1808
+ const edges = await client2.getEdges({ from_uid: uid });
1809
+ const inEdges = await client2.getEdges({ to_uid: uid });
1810
+ return json(uri, { node, outgoing_edges: edges, incoming_edges: inEdges });
1811
+ }
1812
+ const searchMatch = uri.match(/^mindgraph:\/\/search\/(.+)$/);
1813
+ if (searchMatch) {
1814
+ const query = decodeURIComponent(searchMatch[1]);
1815
+ return json(uri, await client2.search(query, { limit: 20 }));
1816
+ }
1817
+ const layerMatch = uri.match(/^mindgraph:\/\/layer\/(.+)$/);
1818
+ if (layerMatch) {
1819
+ const layer = decodeURIComponent(layerMatch[1]);
1820
+ return json(uri, await client2.getNodes({ layer, limit: 50 }));
1821
+ }
1822
+ throw new Error(`Unknown resource: ${uri}`);
1823
+ }
1824
+ async function readGovernedResource(client2, uri, governanceConfig) {
1825
+ const governance = await checkMcpGovernance(
1826
+ RESOURCE_GOVERNANCE_TOOL,
1827
+ {},
1828
+ { ...governanceConfig, context: { resource_uri: uri } }
1829
+ );
1830
+ if (!governance.allowed) {
1831
+ throw new Error(governance.message);
1832
+ }
1833
+ return readResource(client2, uri);
1834
+ }
1835
+ var RESOURCES, RESOURCE_TEMPLATES, RESOURCE_GOVERNANCE_TOOL;
1836
+ var init_resources = __esm({
1837
+ "src/resources.ts"() {
1838
+ "use strict";
1839
+ init_governance();
1840
+ RESOURCES = [
1841
+ {
1842
+ uri: "mindgraph://stats",
1843
+ name: "Graph Statistics",
1844
+ description: "Current knowledge graph statistics: node counts, edge counts, and layer distribution",
1845
+ mimeType: "application/json"
1846
+ },
1847
+ {
1848
+ uri: "mindgraph://goals",
1849
+ name: "Active Goals",
1850
+ description: "All active goals in the knowledge graph",
1851
+ mimeType: "application/json"
1852
+ },
1853
+ {
1854
+ uri: "mindgraph://questions",
1855
+ name: "Open Questions",
1856
+ description: "All open questions in the knowledge graph",
1857
+ mimeType: "application/json"
1858
+ },
1859
+ {
1860
+ uri: "mindgraph://contradictions",
1861
+ name: "Contradictions",
1862
+ description: "Contradictory claims in the knowledge graph",
1863
+ mimeType: "application/json"
1864
+ },
1865
+ {
1866
+ uri: "mindgraph://decisions",
1867
+ name: "Open Decisions",
1868
+ description: "Unresolved decisions awaiting resolution",
1869
+ mimeType: "application/json"
1870
+ }
1871
+ ];
1872
+ RESOURCE_TEMPLATES = [
1873
+ {
1874
+ uriTemplate: "mindgraph://node/{uid}",
1875
+ name: "Graph Node",
1876
+ description: "Retrieve a specific node by its UID, including all properties, edges, and version history",
1877
+ mimeType: "application/json"
1878
+ },
1879
+ {
1880
+ uriTemplate: "mindgraph://search/{query}",
1881
+ name: "Search Results",
1882
+ description: "BM25 keyword search across all nodes \u2014 pass 1\u20133 discriminating terms (e.g. 'Kissinger NATO'), not natural language sentences",
1883
+ mimeType: "application/json"
1884
+ },
1885
+ {
1886
+ uriTemplate: "mindgraph://layer/{layer}",
1887
+ name: "Layer Nodes",
1888
+ description: "List all nodes in a specific cognitive layer (reality, epistemic, intent, action, memory, agent)",
1889
+ mimeType: "application/json"
1890
+ }
1891
+ ];
1892
+ RESOURCE_GOVERNANCE_TOOL = "mindgraph_retrieve";
1893
+ }
1894
+ });
1895
+
1713
1896
  // src/index.ts
1714
1897
  var src_exports = {};
1715
1898
  async function main() {
@@ -1719,7 +1902,7 @@ async function main() {
1719
1902
  `MindGraph MCP server v0.7.1 running on stdio (${BASE_URL})`
1720
1903
  );
1721
1904
  }
1722
- var import_server, import_stdio, import_types, import_mindgraph, API_KEY, BASE_URL, AGENT_ID, ORG_ID, client, INSTRUCTIONS, server, PROMPTS;
1905
+ var import_server, import_stdio, import_types, import_mindgraph, API_KEY, BASE_URL, AGENT_ID, ORG_ID, client, INSTRUCTIONS, server, GOVERNANCE_CONFIG, PROMPTS;
1723
1906
  var init_src = __esm({
1724
1907
  "src/index.ts"() {
1725
1908
  "use strict";
@@ -1730,6 +1913,7 @@ var init_src = __esm({
1730
1913
  init_tools();
1731
1914
  init_generated_tools();
1732
1915
  init_governance();
1916
+ init_resources();
1733
1917
  API_KEY = process.env.MINDGRAPH_API_KEY;
1734
1918
  BASE_URL = process.env.MINDGRAPH_BASE_URL || "https://api.mindgraph.cloud";
1735
1919
  AGENT_ID = process.env.MINDGRAPH_AGENT_ID || "mcp";
@@ -1827,7 +2011,7 @@ Capture knowledge when the user shares something worth remembering:
1827
2011
  server = new import_server.Server(
1828
2012
  {
1829
2013
  name: "mindgraph",
1830
- version: "0.13.3"
2014
+ version: "0.13.5"
1831
2015
  },
1832
2016
  {
1833
2017
  capabilities: {
@@ -1842,19 +2026,23 @@ Capture knowledge when the user shares something worth remembering:
1842
2026
  const generated = await getGeneratedTools(client);
1843
2027
  return { tools: [...TOOLS, ...generated.tools] };
1844
2028
  });
2029
+ GOVERNANCE_CONFIG = {
2030
+ baseUrl: BASE_URL,
2031
+ apiKey: API_KEY,
2032
+ orgId: ORG_ID,
2033
+ agentId: AGENT_ID,
2034
+ get disabled() {
2035
+ return process.env.MINDGRAPH_GOVERNANCE === "off";
2036
+ }
2037
+ };
1845
2038
  server.setRequestHandler(import_types.CallToolRequestSchema, async (request) => {
1846
2039
  const { name, arguments: args } = request.params;
1847
- const toolArgs = { ...args || {} };
2040
+ const rawArgs = { ...args || {} };
2041
+ const toolArgs = { ...rawArgs };
1848
2042
  if (!toolArgs.agent_id) {
1849
2043
  toolArgs.agent_id = AGENT_ID;
1850
2044
  }
1851
- const governance = await checkMcpGovernance(name, toolArgs, {
1852
- baseUrl: BASE_URL,
1853
- apiKey: API_KEY,
1854
- orgId: ORG_ID,
1855
- agentId: AGENT_ID,
1856
- disabled: process.env.MINDGRAPH_GOVERNANCE === "off"
1857
- });
2045
+ const governance = await checkMcpGovernance(name, toolArgs, GOVERNANCE_CONFIG);
1858
2046
  if (!governance.allowed) {
1859
2047
  return {
1860
2048
  content: [{ type: "text", text: JSON.stringify({ error: governance.message, ...governance }) }],
@@ -1864,7 +2052,7 @@ Capture knowledge when the user shares something worth remembering:
1864
2052
  const generated = await getGeneratedTools(client);
1865
2053
  const desc = generated.byName.get(name);
1866
2054
  if (desc) {
1867
- return handleGeneratedTool(client, desc, toolArgs);
2055
+ return handleGeneratedTool(client, desc, rawArgs);
1868
2056
  }
1869
2057
  return handleTool(client, name, toolArgs);
1870
2058
  });
@@ -2025,178 +2213,13 @@ ${conversation}`
2025
2213
  }
2026
2214
  });
2027
2215
  server.setRequestHandler(import_types.ListResourcesRequestSchema, async () => {
2028
- return {
2029
- resources: [
2030
- {
2031
- uri: "mindgraph://stats",
2032
- name: "Graph Statistics",
2033
- description: "Current knowledge graph statistics: node counts, edge counts, and layer distribution",
2034
- mimeType: "application/json"
2035
- },
2036
- {
2037
- uri: "mindgraph://goals",
2038
- name: "Active Goals",
2039
- description: "All active goals in the knowledge graph",
2040
- mimeType: "application/json"
2041
- },
2042
- {
2043
- uri: "mindgraph://questions",
2044
- name: "Open Questions",
2045
- description: "All open questions in the knowledge graph",
2046
- mimeType: "application/json"
2047
- },
2048
- {
2049
- uri: "mindgraph://contradictions",
2050
- name: "Contradictions",
2051
- description: "Contradictory claims in the knowledge graph",
2052
- mimeType: "application/json"
2053
- },
2054
- {
2055
- uri: "mindgraph://decisions",
2056
- name: "Open Decisions",
2057
- description: "Unresolved decisions awaiting resolution",
2058
- mimeType: "application/json"
2059
- }
2060
- ]
2061
- };
2216
+ return { resources: RESOURCES };
2062
2217
  });
2063
2218
  server.setRequestHandler(import_types.ListResourceTemplatesRequestSchema, async () => {
2064
- return {
2065
- resourceTemplates: [
2066
- {
2067
- uriTemplate: "mindgraph://node/{uid}",
2068
- name: "Graph Node",
2069
- description: "Retrieve a specific node by its UID, including all properties, edges, and version history",
2070
- mimeType: "application/json"
2071
- },
2072
- {
2073
- uriTemplate: "mindgraph://search/{query}",
2074
- name: "Search Results",
2075
- description: "BM25 keyword search across all nodes \u2014 pass 1\u20133 discriminating terms (e.g. 'Kissinger NATO'), not natural language sentences",
2076
- mimeType: "application/json"
2077
- },
2078
- {
2079
- uriTemplate: "mindgraph://layer/{layer}",
2080
- name: "Layer Nodes",
2081
- description: "List all nodes in a specific cognitive layer (reality, epistemic, intent, action, memory, agent)",
2082
- mimeType: "application/json"
2083
- }
2084
- ]
2085
- };
2219
+ return { resourceTemplates: RESOURCE_TEMPLATES };
2086
2220
  });
2087
2221
  server.setRequestHandler(import_types.ReadResourceRequestSchema, async (request) => {
2088
- const { uri } = request.params;
2089
- switch (uri) {
2090
- case "mindgraph://stats": {
2091
- const stats = await client.stats();
2092
- return {
2093
- contents: [
2094
- {
2095
- uri,
2096
- mimeType: "application/json",
2097
- text: JSON.stringify(stats, null, 2)
2098
- }
2099
- ]
2100
- };
2101
- }
2102
- case "mindgraph://goals": {
2103
- const goals = await client.getGoals();
2104
- return {
2105
- contents: [
2106
- {
2107
- uri,
2108
- mimeType: "application/json",
2109
- text: JSON.stringify(goals, null, 2)
2110
- }
2111
- ]
2112
- };
2113
- }
2114
- case "mindgraph://questions": {
2115
- const questions = await client.getOpenQuestions();
2116
- return {
2117
- contents: [
2118
- {
2119
- uri,
2120
- mimeType: "application/json",
2121
- text: JSON.stringify(questions, null, 2)
2122
- }
2123
- ]
2124
- };
2125
- }
2126
- case "mindgraph://contradictions": {
2127
- const contradictions = await client.getContradictions();
2128
- return {
2129
- contents: [
2130
- {
2131
- uri,
2132
- mimeType: "application/json",
2133
- text: JSON.stringify(contradictions, null, 2)
2134
- }
2135
- ]
2136
- };
2137
- }
2138
- case "mindgraph://decisions": {
2139
- const decisions = await client.getOpenDecisions();
2140
- return {
2141
- contents: [
2142
- {
2143
- uri,
2144
- mimeType: "application/json",
2145
- text: JSON.stringify(decisions, null, 2)
2146
- }
2147
- ]
2148
- };
2149
- }
2150
- }
2151
- const nodeMatch = uri.match(/^mindgraph:\/\/node\/(.+)$/);
2152
- if (nodeMatch) {
2153
- const uid = decodeURIComponent(nodeMatch[1]);
2154
- const node = await client.getNode(uid);
2155
- const edges = await client.getEdges({ from_uid: uid });
2156
- const inEdges = await client.getEdges({ to_uid: uid });
2157
- return {
2158
- contents: [
2159
- {
2160
- uri,
2161
- mimeType: "application/json",
2162
- text: JSON.stringify(
2163
- { node, outgoing_edges: edges, incoming_edges: inEdges },
2164
- null,
2165
- 2
2166
- )
2167
- }
2168
- ]
2169
- };
2170
- }
2171
- const searchMatch = uri.match(/^mindgraph:\/\/search\/(.+)$/);
2172
- if (searchMatch) {
2173
- const query = decodeURIComponent(searchMatch[1]);
2174
- const results = await client.search(query, { limit: 20 });
2175
- return {
2176
- contents: [
2177
- {
2178
- uri,
2179
- mimeType: "application/json",
2180
- text: JSON.stringify(results, null, 2)
2181
- }
2182
- ]
2183
- };
2184
- }
2185
- const layerMatch = uri.match(/^mindgraph:\/\/layer\/(.+)$/);
2186
- if (layerMatch) {
2187
- const layer = decodeURIComponent(layerMatch[1]);
2188
- const nodes = await client.getNodes({ layer, limit: 50 });
2189
- return {
2190
- contents: [
2191
- {
2192
- uri,
2193
- mimeType: "application/json",
2194
- text: JSON.stringify(nodes, null, 2)
2195
- }
2196
- ]
2197
- };
2198
- }
2199
- throw new Error(`Unknown resource: ${uri}`);
2222
+ return readGovernedResource(client, request.params.uri, GOVERNANCE_CONFIG);
2200
2223
  });
2201
2224
  main().catch((error) => {
2202
2225
  console.error("Fatal error:", error);
@@ -2283,9 +2306,9 @@ function installClaudeCode(apiKey, baseUrl) {
2283
2306
  envArgs.push("--env", `MINDGRAPH_BASE_URL=${baseUrl}`);
2284
2307
  }
2285
2308
  try {
2286
- (0, import_child_process.execSync)(
2309
+ (0, import_child_process.execFileSync)(
2310
+ "claude",
2287
2311
  [
2288
- "claude",
2289
2312
  "mcp",
2290
2313
  "add",
2291
2314
  "mindgraph",
@@ -2294,7 +2317,7 @@ function installClaudeCode(apiKey, baseUrl) {
2294
2317
  "npx",
2295
2318
  "-y",
2296
2319
  "mindgraph-mcp@latest"
2297
- ].join(" "),
2320
+ ],
2298
2321
  { stdio: "inherit" }
2299
2322
  );
2300
2323
  console.log("Added MindGraph MCP server to Claude Code.");
@@ -2325,7 +2348,9 @@ function uninstallClaudeDesktop() {
2325
2348
  }
2326
2349
  function uninstallClaudeCode() {
2327
2350
  try {
2328
- (0, import_child_process.execSync)("claude mcp remove mindgraph", { stdio: "inherit" });
2351
+ (0, import_child_process.execFileSync)("claude", ["mcp", "remove", "mindgraph"], {
2352
+ stdio: "inherit"
2353
+ });
2329
2354
  console.log("Removed MindGraph MCP server from Claude Code.");
2330
2355
  } catch {
2331
2356
  console.error("Failed to run 'claude mcp remove'.");
@@ -2419,13 +2444,13 @@ function openBrowser(url) {
2419
2444
  try {
2420
2445
  switch (process.platform) {
2421
2446
  case "darwin":
2422
- (0, import_child_process.execSync)(`open "${url}"`);
2447
+ (0, import_child_process.execFileSync)("open", [url]);
2423
2448
  break;
2424
2449
  case "win32":
2425
- (0, import_child_process.execSync)(`start "" "${url}"`);
2450
+ (0, import_child_process.execFileSync)("cmd", ["/c", "start", "", url]);
2426
2451
  break;
2427
2452
  case "linux":
2428
- (0, import_child_process.execSync)(`xdg-open "${url}"`);
2453
+ (0, import_child_process.execFileSync)("xdg-open", [url]);
2429
2454
  break;
2430
2455
  }
2431
2456
  } catch {
package/dist/index.js CHANGED
@@ -1467,13 +1467,23 @@ var err2 = (message) => ({
1467
1467
  isError: true
1468
1468
  });
1469
1469
  var CACHE_TTL_MS = 5 * 60 * 1e3;
1470
+ var FAILURE_COOLDOWN_MS = 15 * 1e3;
1470
1471
  var cache = null;
1472
+ var retryNotBefore = 0;
1473
+ var EMPTY = {
1474
+ tools: [],
1475
+ byName: /* @__PURE__ */ new Map()
1476
+ };
1471
1477
  var DuplicateGeneratedToolError = class extends Error {
1472
1478
  };
1473
1479
  async function getGeneratedTools(client2) {
1474
- if (cache && Date.now() - cache.fetchedAt < CACHE_TTL_MS) {
1480
+ const now = Date.now();
1481
+ if (cache && now - cache.fetchedAt < CACHE_TTL_MS) {
1475
1482
  return { tools: cache.tools, byName: cache.byName };
1476
1483
  }
1484
+ if (now < retryNotBefore) {
1485
+ return cache ? { tools: cache.tools, byName: cache.byName } : EMPTY;
1486
+ }
1477
1487
  try {
1478
1488
  const c = client2;
1479
1489
  if (typeof c.listOntologyTools !== "function") {
@@ -1497,13 +1507,22 @@ async function getGeneratedTools(client2) {
1497
1507
  });
1498
1508
  }
1499
1509
  cache = { tools, byName, fetchedAt: Date.now() };
1510
+ retryNotBefore = 0;
1500
1511
  return { tools, byName };
1501
1512
  } catch (error) {
1502
1513
  if (error instanceof DuplicateGeneratedToolError) throw error;
1503
- cache = { tools: [], byName: /* @__PURE__ */ new Map(), fetchedAt: Date.now() };
1504
- return { tools: cache.tools, byName: cache.byName };
1514
+ retryNotBefore = Date.now() + FAILURE_COOLDOWN_MS;
1515
+ return cache ? { tools: cache.tools, byName: cache.byName } : EMPTY;
1505
1516
  }
1506
1517
  }
1518
+ var STRUCTURED_QUERY_PASSTHROUGH = [
1519
+ "anchor",
1520
+ "path",
1521
+ "where",
1522
+ "include",
1523
+ "page",
1524
+ "aggregate"
1525
+ ];
1507
1526
  async function handleGeneratedTool(client2, desc, args) {
1508
1527
  try {
1509
1528
  const ontologyClient = client2;
@@ -1571,11 +1590,14 @@ async function handleGeneratedTool(client2, desc, args) {
1571
1590
  "structured ontology tools require a graph-aware version of the mindgraph SDK"
1572
1591
  );
1573
1592
  }
1574
- return ok2(await ontologyClient.queryDomainStructured({
1575
- ...args,
1593
+ const request = {
1576
1594
  schema_id: desc.schema_id,
1577
1595
  select
1578
- }));
1596
+ };
1597
+ for (const field of STRUCTURED_QUERY_PASSTHROUGH) {
1598
+ if (args[field] !== void 0) request[field] = args[field];
1599
+ }
1600
+ return ok2(await ontologyClient.queryDomainStructured(request));
1579
1601
  }
1580
1602
  default:
1581
1603
  return err2(`unknown generated tool mapping: ${desc.maps_to}`);
@@ -1587,6 +1609,16 @@ async function handleGeneratedTool(client2, desc, args) {
1587
1609
 
1588
1610
  // src/governance.ts
1589
1611
  var capability = "unknown";
1612
+ var UNSUPPORTED_LEASE_MS = 5 * 60 * 1e3;
1613
+ var unsupportedUntil = 0;
1614
+ var unsupportedLogged = false;
1615
+ var DEFAULT_RETRY_DELAYS_MS = [150, 600];
1616
+ function isTransientStatus(status) {
1617
+ return status === 408 || status === 425 || status === 429 || status >= 500;
1618
+ }
1619
+ function sleep(ms) {
1620
+ return new Promise((resolve) => setTimeout(resolve, ms));
1621
+ }
1590
1622
  var KNOWN_DUTIES = /* @__PURE__ */ new Set(["log", "require_approval"]);
1591
1623
  function headers(apiKey, orgId) {
1592
1624
  const value = {
@@ -1603,41 +1635,81 @@ function unsupportedResponse(status, body) {
1603
1635
  return lower.includes("unknown governance action") || lower.includes("unknown action") || lower.includes("invalid_governance_action");
1604
1636
  }
1605
1637
  async function checkMcpGovernance(toolName, args, config) {
1606
- if (config.disabled || capability === "unsupported") return { allowed: true };
1638
+ if (config.disabled) return { allowed: true };
1639
+ if (capability === "unsupported") {
1640
+ if (Date.now() < unsupportedUntil) return { allowed: true };
1641
+ capability = "unknown";
1642
+ }
1607
1643
  const fetchImpl = config.fetchImpl ?? fetch;
1644
+ const retryDelays = config.retryDelaysMs ?? DEFAULT_RETRY_DELAYS_MS;
1608
1645
  let response;
1609
- let body;
1610
- try {
1611
- response = await fetchImpl(`${config.baseUrl.replace(/\/$/, "")}/agent/governance`, {
1612
- method: "POST",
1613
- headers: headers(config.apiKey, config.orgId),
1614
- body: JSON.stringify({
1615
- action: "check",
1616
- act: "tool_invoke",
1617
- agent_id: String(args.agent_id || config.agentId),
1618
- target: { tool_name: toolName },
1619
- context: { adapter: "mindgraph-mcp" },
1620
- tier: "checkpoint"
1621
- })
1622
- });
1623
- body = await response.text();
1624
- } catch (error) {
1646
+ let body = "";
1647
+ let lastFailure = "";
1648
+ for (let attempt = 0; attempt <= retryDelays.length; attempt++) {
1649
+ try {
1650
+ const candidate = await fetchImpl(
1651
+ `${config.baseUrl.replace(/\/$/, "")}/agent/governance`,
1652
+ {
1653
+ method: "POST",
1654
+ headers: headers(config.apiKey, config.orgId),
1655
+ body: JSON.stringify({
1656
+ action: "check",
1657
+ act: "tool_invoke",
1658
+ agent_id: String(args.agent_id || config.agentId),
1659
+ target: { tool_name: toolName },
1660
+ context: { adapter: "mindgraph-mcp", ...config.context },
1661
+ tier: "checkpoint"
1662
+ })
1663
+ }
1664
+ );
1665
+ const candidateBody = await candidate.text();
1666
+ if (isTransientStatus(candidate.status) && attempt < retryDelays.length) {
1667
+ lastFailure = `HTTP ${candidate.status}`;
1668
+ await sleep(retryDelays[attempt]);
1669
+ continue;
1670
+ }
1671
+ response = candidate;
1672
+ body = candidateBody;
1673
+ break;
1674
+ } catch (error) {
1675
+ lastFailure = error instanceof Error ? error.message : String(error);
1676
+ if (attempt < retryDelays.length) {
1677
+ await sleep(retryDelays[attempt]);
1678
+ continue;
1679
+ }
1680
+ }
1681
+ }
1682
+ if (!response) {
1625
1683
  return {
1626
1684
  allowed: false,
1627
- message: `MindGraph governance could not establish permission: ${error instanceof Error ? error.message : String(error)}`
1685
+ message: `MindGraph governance could not establish permission after ${retryDelays.length + 1} attempts (${lastFailure}). Set MINDGRAPH_GOVERNANCE=off to run this adapter ungoverned.`
1628
1686
  };
1629
1687
  }
1630
1688
  if (!response.ok) {
1631
1689
  if (capability === "unknown" && unsupportedResponse(response.status, body)) {
1632
1690
  capability = "unsupported";
1691
+ unsupportedUntil = Date.now() + UNSUPPORTED_LEASE_MS;
1692
+ if (!unsupportedLogged) {
1693
+ unsupportedLogged = true;
1694
+ console.error(
1695
+ `[mindgraph-mcp] This MindGraph server does not implement the governance checkpoint (HTTP ${response.status}); tool calls proceed ungoverned. Re-probing every ${Math.round(UNSUPPORTED_LEASE_MS / 6e4)} minutes.`
1696
+ );
1697
+ }
1633
1698
  return { allowed: true };
1634
1699
  }
1700
+ if (response.status === 401 || response.status === 403) {
1701
+ return {
1702
+ allowed: false,
1703
+ message: `This credential is not permitted to evaluate MindGraph governance (HTTP ${response.status}). Use a user-scoped API key, or set MINDGRAPH_GOVERNANCE=off to run this adapter ungoverned.`
1704
+ };
1705
+ }
1635
1706
  return {
1636
1707
  allowed: false,
1637
1708
  message: `MindGraph governance check failed (${response.status})`
1638
1709
  };
1639
1710
  }
1640
1711
  capability = "supported";
1712
+ unsupportedLogged = false;
1641
1713
  let decision;
1642
1714
  try {
1643
1715
  decision = JSON.parse(body);
@@ -1672,6 +1744,110 @@ async function checkMcpGovernance(toolName, args, config) {
1672
1744
  };
1673
1745
  }
1674
1746
 
1747
+ // src/resources.ts
1748
+ var RESOURCES = [
1749
+ {
1750
+ uri: "mindgraph://stats",
1751
+ name: "Graph Statistics",
1752
+ description: "Current knowledge graph statistics: node counts, edge counts, and layer distribution",
1753
+ mimeType: "application/json"
1754
+ },
1755
+ {
1756
+ uri: "mindgraph://goals",
1757
+ name: "Active Goals",
1758
+ description: "All active goals in the knowledge graph",
1759
+ mimeType: "application/json"
1760
+ },
1761
+ {
1762
+ uri: "mindgraph://questions",
1763
+ name: "Open Questions",
1764
+ description: "All open questions in the knowledge graph",
1765
+ mimeType: "application/json"
1766
+ },
1767
+ {
1768
+ uri: "mindgraph://contradictions",
1769
+ name: "Contradictions",
1770
+ description: "Contradictory claims in the knowledge graph",
1771
+ mimeType: "application/json"
1772
+ },
1773
+ {
1774
+ uri: "mindgraph://decisions",
1775
+ name: "Open Decisions",
1776
+ description: "Unresolved decisions awaiting resolution",
1777
+ mimeType: "application/json"
1778
+ }
1779
+ ];
1780
+ var RESOURCE_TEMPLATES = [
1781
+ {
1782
+ uriTemplate: "mindgraph://node/{uid}",
1783
+ name: "Graph Node",
1784
+ description: "Retrieve a specific node by its UID, including all properties, edges, and version history",
1785
+ mimeType: "application/json"
1786
+ },
1787
+ {
1788
+ uriTemplate: "mindgraph://search/{query}",
1789
+ name: "Search Results",
1790
+ description: "BM25 keyword search across all nodes \u2014 pass 1\u20133 discriminating terms (e.g. 'Kissinger NATO'), not natural language sentences",
1791
+ mimeType: "application/json"
1792
+ },
1793
+ {
1794
+ uriTemplate: "mindgraph://layer/{layer}",
1795
+ name: "Layer Nodes",
1796
+ description: "List all nodes in a specific cognitive layer (reality, epistemic, intent, action, memory, agent)",
1797
+ mimeType: "application/json"
1798
+ }
1799
+ ];
1800
+ var RESOURCE_GOVERNANCE_TOOL = "mindgraph_retrieve";
1801
+ function json(uri, data) {
1802
+ return {
1803
+ contents: [{ uri, mimeType: "application/json", text: JSON.stringify(data, null, 2) }]
1804
+ };
1805
+ }
1806
+ async function readResource(client2, uri) {
1807
+ switch (uri) {
1808
+ case "mindgraph://stats":
1809
+ return json(uri, await client2.stats());
1810
+ case "mindgraph://goals":
1811
+ return json(uri, await client2.getGoals());
1812
+ case "mindgraph://questions":
1813
+ return json(uri, await client2.getOpenQuestions());
1814
+ case "mindgraph://contradictions":
1815
+ return json(uri, await client2.getContradictions());
1816
+ case "mindgraph://decisions":
1817
+ return json(uri, await client2.getOpenDecisions());
1818
+ }
1819
+ const nodeMatch = uri.match(/^mindgraph:\/\/node\/(.+)$/);
1820
+ if (nodeMatch) {
1821
+ const uid = decodeURIComponent(nodeMatch[1]);
1822
+ const node = await client2.getNode(uid);
1823
+ const edges = await client2.getEdges({ from_uid: uid });
1824
+ const inEdges = await client2.getEdges({ to_uid: uid });
1825
+ return json(uri, { node, outgoing_edges: edges, incoming_edges: inEdges });
1826
+ }
1827
+ const searchMatch = uri.match(/^mindgraph:\/\/search\/(.+)$/);
1828
+ if (searchMatch) {
1829
+ const query = decodeURIComponent(searchMatch[1]);
1830
+ return json(uri, await client2.search(query, { limit: 20 }));
1831
+ }
1832
+ const layerMatch = uri.match(/^mindgraph:\/\/layer\/(.+)$/);
1833
+ if (layerMatch) {
1834
+ const layer = decodeURIComponent(layerMatch[1]);
1835
+ return json(uri, await client2.getNodes({ layer, limit: 50 }));
1836
+ }
1837
+ throw new Error(`Unknown resource: ${uri}`);
1838
+ }
1839
+ async function readGovernedResource(client2, uri, governanceConfig) {
1840
+ const governance = await checkMcpGovernance(
1841
+ RESOURCE_GOVERNANCE_TOOL,
1842
+ {},
1843
+ { ...governanceConfig, context: { resource_uri: uri } }
1844
+ );
1845
+ if (!governance.allowed) {
1846
+ throw new Error(governance.message);
1847
+ }
1848
+ return readResource(client2, uri);
1849
+ }
1850
+
1675
1851
  // src/index.ts
1676
1852
  var API_KEY = process.env.MINDGRAPH_API_KEY;
1677
1853
  var BASE_URL = process.env.MINDGRAPH_BASE_URL || "https://api.mindgraph.cloud";
@@ -1770,7 +1946,7 @@ Capture knowledge when the user shares something worth remembering:
1770
1946
  var server = new import_server.Server(
1771
1947
  {
1772
1948
  name: "mindgraph",
1773
- version: "0.13.3"
1949
+ version: "0.13.5"
1774
1950
  },
1775
1951
  {
1776
1952
  capabilities: {
@@ -1785,19 +1961,23 @@ server.setRequestHandler(import_types.ListToolsRequestSchema, async () => {
1785
1961
  const generated = await getGeneratedTools(client);
1786
1962
  return { tools: [...TOOLS, ...generated.tools] };
1787
1963
  });
1964
+ var GOVERNANCE_CONFIG = {
1965
+ baseUrl: BASE_URL,
1966
+ apiKey: API_KEY,
1967
+ orgId: ORG_ID,
1968
+ agentId: AGENT_ID,
1969
+ get disabled() {
1970
+ return process.env.MINDGRAPH_GOVERNANCE === "off";
1971
+ }
1972
+ };
1788
1973
  server.setRequestHandler(import_types.CallToolRequestSchema, async (request) => {
1789
1974
  const { name, arguments: args } = request.params;
1790
- const toolArgs = { ...args || {} };
1975
+ const rawArgs = { ...args || {} };
1976
+ const toolArgs = { ...rawArgs };
1791
1977
  if (!toolArgs.agent_id) {
1792
1978
  toolArgs.agent_id = AGENT_ID;
1793
1979
  }
1794
- const governance = await checkMcpGovernance(name, toolArgs, {
1795
- baseUrl: BASE_URL,
1796
- apiKey: API_KEY,
1797
- orgId: ORG_ID,
1798
- agentId: AGENT_ID,
1799
- disabled: process.env.MINDGRAPH_GOVERNANCE === "off"
1800
- });
1980
+ const governance = await checkMcpGovernance(name, toolArgs, GOVERNANCE_CONFIG);
1801
1981
  if (!governance.allowed) {
1802
1982
  return {
1803
1983
  content: [{ type: "text", text: JSON.stringify({ error: governance.message, ...governance }) }],
@@ -1807,7 +1987,7 @@ server.setRequestHandler(import_types.CallToolRequestSchema, async (request) =>
1807
1987
  const generated = await getGeneratedTools(client);
1808
1988
  const desc = generated.byName.get(name);
1809
1989
  if (desc) {
1810
- return handleGeneratedTool(client, desc, toolArgs);
1990
+ return handleGeneratedTool(client, desc, rawArgs);
1811
1991
  }
1812
1992
  return handleTool(client, name, toolArgs);
1813
1993
  });
@@ -1968,178 +2148,13 @@ ${conversation}`
1968
2148
  }
1969
2149
  });
1970
2150
  server.setRequestHandler(import_types.ListResourcesRequestSchema, async () => {
1971
- return {
1972
- resources: [
1973
- {
1974
- uri: "mindgraph://stats",
1975
- name: "Graph Statistics",
1976
- description: "Current knowledge graph statistics: node counts, edge counts, and layer distribution",
1977
- mimeType: "application/json"
1978
- },
1979
- {
1980
- uri: "mindgraph://goals",
1981
- name: "Active Goals",
1982
- description: "All active goals in the knowledge graph",
1983
- mimeType: "application/json"
1984
- },
1985
- {
1986
- uri: "mindgraph://questions",
1987
- name: "Open Questions",
1988
- description: "All open questions in the knowledge graph",
1989
- mimeType: "application/json"
1990
- },
1991
- {
1992
- uri: "mindgraph://contradictions",
1993
- name: "Contradictions",
1994
- description: "Contradictory claims in the knowledge graph",
1995
- mimeType: "application/json"
1996
- },
1997
- {
1998
- uri: "mindgraph://decisions",
1999
- name: "Open Decisions",
2000
- description: "Unresolved decisions awaiting resolution",
2001
- mimeType: "application/json"
2002
- }
2003
- ]
2004
- };
2151
+ return { resources: RESOURCES };
2005
2152
  });
2006
2153
  server.setRequestHandler(import_types.ListResourceTemplatesRequestSchema, async () => {
2007
- return {
2008
- resourceTemplates: [
2009
- {
2010
- uriTemplate: "mindgraph://node/{uid}",
2011
- name: "Graph Node",
2012
- description: "Retrieve a specific node by its UID, including all properties, edges, and version history",
2013
- mimeType: "application/json"
2014
- },
2015
- {
2016
- uriTemplate: "mindgraph://search/{query}",
2017
- name: "Search Results",
2018
- description: "BM25 keyword search across all nodes \u2014 pass 1\u20133 discriminating terms (e.g. 'Kissinger NATO'), not natural language sentences",
2019
- mimeType: "application/json"
2020
- },
2021
- {
2022
- uriTemplate: "mindgraph://layer/{layer}",
2023
- name: "Layer Nodes",
2024
- description: "List all nodes in a specific cognitive layer (reality, epistemic, intent, action, memory, agent)",
2025
- mimeType: "application/json"
2026
- }
2027
- ]
2028
- };
2154
+ return { resourceTemplates: RESOURCE_TEMPLATES };
2029
2155
  });
2030
2156
  server.setRequestHandler(import_types.ReadResourceRequestSchema, async (request) => {
2031
- const { uri } = request.params;
2032
- switch (uri) {
2033
- case "mindgraph://stats": {
2034
- const stats = await client.stats();
2035
- return {
2036
- contents: [
2037
- {
2038
- uri,
2039
- mimeType: "application/json",
2040
- text: JSON.stringify(stats, null, 2)
2041
- }
2042
- ]
2043
- };
2044
- }
2045
- case "mindgraph://goals": {
2046
- const goals = await client.getGoals();
2047
- return {
2048
- contents: [
2049
- {
2050
- uri,
2051
- mimeType: "application/json",
2052
- text: JSON.stringify(goals, null, 2)
2053
- }
2054
- ]
2055
- };
2056
- }
2057
- case "mindgraph://questions": {
2058
- const questions = await client.getOpenQuestions();
2059
- return {
2060
- contents: [
2061
- {
2062
- uri,
2063
- mimeType: "application/json",
2064
- text: JSON.stringify(questions, null, 2)
2065
- }
2066
- ]
2067
- };
2068
- }
2069
- case "mindgraph://contradictions": {
2070
- const contradictions = await client.getContradictions();
2071
- return {
2072
- contents: [
2073
- {
2074
- uri,
2075
- mimeType: "application/json",
2076
- text: JSON.stringify(contradictions, null, 2)
2077
- }
2078
- ]
2079
- };
2080
- }
2081
- case "mindgraph://decisions": {
2082
- const decisions = await client.getOpenDecisions();
2083
- return {
2084
- contents: [
2085
- {
2086
- uri,
2087
- mimeType: "application/json",
2088
- text: JSON.stringify(decisions, null, 2)
2089
- }
2090
- ]
2091
- };
2092
- }
2093
- }
2094
- const nodeMatch = uri.match(/^mindgraph:\/\/node\/(.+)$/);
2095
- if (nodeMatch) {
2096
- const uid = decodeURIComponent(nodeMatch[1]);
2097
- const node = await client.getNode(uid);
2098
- const edges = await client.getEdges({ from_uid: uid });
2099
- const inEdges = await client.getEdges({ to_uid: uid });
2100
- return {
2101
- contents: [
2102
- {
2103
- uri,
2104
- mimeType: "application/json",
2105
- text: JSON.stringify(
2106
- { node, outgoing_edges: edges, incoming_edges: inEdges },
2107
- null,
2108
- 2
2109
- )
2110
- }
2111
- ]
2112
- };
2113
- }
2114
- const searchMatch = uri.match(/^mindgraph:\/\/search\/(.+)$/);
2115
- if (searchMatch) {
2116
- const query = decodeURIComponent(searchMatch[1]);
2117
- const results = await client.search(query, { limit: 20 });
2118
- return {
2119
- contents: [
2120
- {
2121
- uri,
2122
- mimeType: "application/json",
2123
- text: JSON.stringify(results, null, 2)
2124
- }
2125
- ]
2126
- };
2127
- }
2128
- const layerMatch = uri.match(/^mindgraph:\/\/layer\/(.+)$/);
2129
- if (layerMatch) {
2130
- const layer = decodeURIComponent(layerMatch[1]);
2131
- const nodes = await client.getNodes({ layer, limit: 50 });
2132
- return {
2133
- contents: [
2134
- {
2135
- uri,
2136
- mimeType: "application/json",
2137
- text: JSON.stringify(nodes, null, 2)
2138
- }
2139
- ]
2140
- };
2141
- }
2142
- throw new Error(`Unknown resource: ${uri}`);
2157
+ return readGovernedResource(client, request.params.uri, GOVERNANCE_CONFIG);
2143
2158
  });
2144
2159
  async function main() {
2145
2160
  const transport = new import_stdio.StdioServerTransport();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mindgraph-mcp",
3
- "version": "0.13.3",
3
+ "version": "0.13.5",
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",