mindgraph-mcp 0.16.0 → 0.17.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/index.js CHANGED
@@ -777,13 +777,13 @@ function codeRefIdentityKey(ref) {
777
777
 
778
778
  // src/code-tool.ts
779
779
  var ok = (data) => ({
780
- content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
780
+ content: [{ type: "text", text: JSON.stringify(data) }]
781
781
  });
782
782
  var err = (code, message, details) => ({
783
783
  content: [
784
784
  {
785
785
  type: "text",
786
- text: JSON.stringify({ error: message, code, details }, null, 2)
786
+ text: JSON.stringify({ error: message, code, details })
787
787
  }
788
788
  ],
789
789
  isError: true
@@ -1272,7 +1272,7 @@ var import_node_crypto3 = __toESM(require("crypto"));
1272
1272
  var import_node_fs3 = __toESM(require("fs"));
1273
1273
  var import_node_path3 = __toESM(require("path"));
1274
1274
  var ok2 = (data) => ({
1275
- content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
1275
+ content: [{ type: "text", text: JSON.stringify(data) }]
1276
1276
  });
1277
1277
  var err2 = (code, message) => ({
1278
1278
  content: [{ type: "text", text: JSON.stringify({ code, error: message }) }],
@@ -1502,12 +1502,23 @@ function clip(value, max, state) {
1502
1502
  }
1503
1503
  function isNodeShaped(value) {
1504
1504
  const node = obj(value);
1505
- return Boolean(node && str(node.uid) && (str(node.label) || str(node.node_type)));
1505
+ return Boolean(
1506
+ node && str(node.uid) && (str(node.label) || str(node.node_type) || obj(node.node_type))
1507
+ );
1508
+ }
1509
+ function nodeDisplayType(node) {
1510
+ const props = obj(node.props);
1511
+ const plain = str(node.node_type);
1512
+ return (plain && plain !== "Custom" ? plain : void 0) ?? str(obj(node.node_type)?.Custom) ?? str(props?.object_type) ?? str(props?.type_name) ?? str(obj(props?.data)?.domain_type) ?? plain ?? "Node";
1513
+ }
1514
+ function nodeFields(node) {
1515
+ const props = obj(node.props);
1516
+ return obj(props?.fields) ?? obj(obj(props?.data)?.fields);
1506
1517
  }
1507
1518
  function unwrapSearchResult(value) {
1508
1519
  if (isNodeShaped(value)) return value;
1509
1520
  const wrapper = obj(value);
1510
- const inner = obj(wrapper?.node);
1521
+ const inner = obj(wrapper?.node) ?? obj(wrapper?.object);
1511
1522
  if (inner && isNodeShaped(inner)) {
1512
1523
  const score = num(wrapper.score);
1513
1524
  return score !== void 0 ? { ...inner, retrieval_score: score } : inner;
@@ -1545,7 +1556,7 @@ function sourceTag(node) {
1545
1556
  return `from: ${title}${extra}`;
1546
1557
  }
1547
1558
  function layer7Fields(node, state) {
1548
- const fields = obj(obj(node.props)?.fields);
1559
+ const fields = nodeFields(node);
1549
1560
  if (!fields) return void 0;
1550
1561
  const pairs = Object.entries(fields).filter(([, value]) => value !== null && value !== void 0 && value !== "").map(([key, value]) => `${key}: ${Array.isArray(value) ? value.join(", ") : String(value)}`);
1551
1562
  if (pairs.length === 0) return void 0;
@@ -1557,7 +1568,7 @@ function nodeSummaryText(node, state) {
1557
1568
  }
1558
1569
  function nodeLines(node, state) {
1559
1570
  const label = clip(node.label, LABEL_MAX, state) || "(unlabeled)";
1560
- const type = str(node.node_type) || "Node";
1571
+ const type = nodeDisplayType(node);
1561
1572
  const confidence = num(node.confidence);
1562
1573
  const score = num(node.retrieval_score);
1563
1574
  const parenthetical = [
@@ -1576,19 +1587,19 @@ function nodeLines(node, state) {
1576
1587
  if (source) lines.push(` - ${source}`);
1577
1588
  const believers = Array.isArray(node.believed_by) ? node.believed_by : [];
1578
1589
  if (believers.length > 0) {
1579
- const rendered = believers.slice(0, 3).map((raw) => {
1590
+ const rendered2 = believers.slice(0, 3).map((raw) => {
1580
1591
  const believer = obj(raw);
1581
1592
  const conf = num(believer?.confidence);
1582
1593
  return `${str(believer?.agent_label) || "?"}${conf !== void 0 ? ` (${conf})` : ""}`;
1583
1594
  }).join(", ");
1584
- lines.push(` - believed by: ${rendered}`);
1595
+ lines.push(` - believed by: ${rendered2}`);
1585
1596
  }
1586
1597
  return lines.join("\n");
1587
1598
  }
1588
1599
  function groupedNodeSections(nodes, state, headingPrefix = "") {
1589
1600
  const groups = /* @__PURE__ */ new Map();
1590
1601
  for (const node of nodes) {
1591
- const type = str(node.node_type) || "Node";
1602
+ const type = nodeDisplayType(node);
1592
1603
  const group = groups.get(type) ?? [];
1593
1604
  group.push(node);
1594
1605
  groups.set(type, group);
@@ -1604,7 +1615,7 @@ function groupedNodeSections(nodes, state, headingPrefix = "") {
1604
1615
  }
1605
1616
  return sections;
1606
1617
  }
1607
- function relationshipItems(edges, labelByUid, state) {
1618
+ function relationshipItems(edges, labelByUid, state, options) {
1608
1619
  const lines = [];
1609
1620
  for (const raw of edges) {
1610
1621
  const edge = obj(raw);
@@ -1614,8 +1625,8 @@ function relationshipItems(edges, labelByUid, state) {
1614
1625
  const to = str(edge.to_uid);
1615
1626
  if (CURATION_EDGE_TYPES.has(type)) continue;
1616
1627
  if (!from || !to || from === to) continue;
1617
- const fromLabel = labelByUid.get(from);
1618
- const toLabel = labelByUid.get(to);
1628
+ const fromLabel = labelByUid.get(from) ?? (options?.fallbackToUid ? `[${from}]` : void 0);
1629
+ const toLabel = labelByUid.get(to) ?? (options?.fallbackToUid ? `[${to}]` : void 0);
1619
1630
  if (!fromLabel || !toLabel) continue;
1620
1631
  lines.push(`- ${fromLabel} \u2014${type}\u2192 ${toLabel}`);
1621
1632
  }
@@ -1658,8 +1669,8 @@ function assemble(header, sections, state) {
1658
1669
  sectionUsed += marker.length + 1;
1659
1670
  }
1660
1671
  lines.push(
1661
- section.items.length === 0 ? section.heading : `${section.heading}
1662
- ${kept.join("\n")}`
1672
+ section.items.length === 0 ? section.heading : section.heading ? `${section.heading}
1673
+ ${kept.join("\n")}` : kept.join("\n")
1663
1674
  );
1664
1675
  used += headingCost + sectionUsed;
1665
1676
  }
@@ -1822,6 +1833,157 @@ function renderTraversal(response) {
1822
1833
  }
1823
1834
  return assemble("# Graph traversal", sections, state);
1824
1835
  }
1836
+ function neighborLine(value) {
1837
+ const node = obj(value);
1838
+ if (!node) return void 0;
1839
+ const label = str(node.label) || "(unlabeled)";
1840
+ const uid = str(node.uid);
1841
+ const type = str(node.node_type);
1842
+ return `- ${label}${uid ? ` [${uid}]` : ""}${type ? ` (${type})` : ""}`;
1843
+ }
1844
+ function renderOntologyAnswer(response) {
1845
+ const payload = obj(response);
1846
+ if (!payload) return void 0;
1847
+ const objects = Array.isArray(payload.objects) ? payload.objects.filter(isNodeShaped) : isNodeShaped(payload.object) ? [payload.object] : [];
1848
+ const cognitive = obj(payload.cognitive_context);
1849
+ const provenance = Array.isArray(payload.provenance) ? payload.provenance : [];
1850
+ const hasQuerySignature = Array.isArray(payload.objects) || obj(payload.confidence) !== void 0;
1851
+ const cognitiveEmpty = !cognitive || Object.values(cognitive).every((v) => !Array.isArray(v) || v.length === 0);
1852
+ if (objects.length === 0 && cognitiveEmpty && provenance.length === 0) {
1853
+ return hasQuerySignature ? "No matching domain objects." : void 0;
1854
+ }
1855
+ const state = { bounded: false };
1856
+ const sections = [];
1857
+ if (objects.length > 0) {
1858
+ sections.push(...groupedNodeSections(objects, state));
1859
+ }
1860
+ const labelByUid = /* @__PURE__ */ new Map();
1861
+ for (const node of objects) labelByUid.set(str(node.uid), str(node.label) || "?");
1862
+ const graph = obj(payload.graph);
1863
+ for (const raw of Array.isArray(graph?.nodes) ? graph.nodes : []) {
1864
+ const node = obj(raw);
1865
+ const uid = str(node?.uid);
1866
+ if (uid && !labelByUid.has(uid)) labelByUid.set(uid, str(node?.label) || "?");
1867
+ }
1868
+ if (cognitive) {
1869
+ for (const rawNodes of Object.values(cognitive)) {
1870
+ if (!Array.isArray(rawNodes)) continue;
1871
+ for (const raw of rawNodes) {
1872
+ const node = obj(raw);
1873
+ const uid = str(node?.uid);
1874
+ if (uid && !labelByUid.has(uid)) labelByUid.set(uid, str(node?.label) || "?");
1875
+ }
1876
+ }
1877
+ }
1878
+ const relations = Array.isArray(payload.relations) ? payload.relations : [];
1879
+ const relationLines = relationshipItems(relations, labelByUid, state, { fallbackToUid: true });
1880
+ if (relationLines.length > 0) {
1881
+ sections.push({ heading: "## Relations", items: relationLines });
1882
+ }
1883
+ if (cognitive) {
1884
+ for (const [category, rawNodes] of Object.entries(cognitive)) {
1885
+ if (!Array.isArray(rawNodes) || rawNodes.length === 0) continue;
1886
+ const items = rawNodes.map(neighborLine).filter((line) => Boolean(line));
1887
+ if (items.length > 0) {
1888
+ sections.push({ heading: `### Cognitive context \u2014 ${category}`, items });
1889
+ }
1890
+ }
1891
+ }
1892
+ if (provenance.length > 0) {
1893
+ const items = provenance.map((raw) => obj(raw)).filter((entry) => Boolean(entry)).map((entry) => {
1894
+ const span = clip(entry.text_span, QUOTE_MAX, state) || "";
1895
+ const by = str(entry.ingested_by_name);
1896
+ const suffix = `${by ? ` (ingested by ${by})` : ""} [source ${str(entry.source_uid) || "?"}]`;
1897
+ return str(entry.span_kind) === "anchor" ? `- "${span}"${suffix}` : `- context: ${span}${suffix}`;
1898
+ });
1899
+ sections.push({ heading: "## Sources", items });
1900
+ }
1901
+ const confidence = num(obj(payload.confidence)?.overall);
1902
+ const notes = [];
1903
+ if (confidence !== void 0) notes.push(`overall confidence ${confidence}`);
1904
+ if (payload.has_more === true) notes.push("more results exist (has_more)");
1905
+ if (payload.seed_cap_hit === true) notes.push("seed cap hit \u2014 narrow the query for a complete set");
1906
+ if (notes.length > 0) sections.push({ heading: `Note: ${notes.join("; ")}.`, items: [] });
1907
+ return assemble(
1908
+ `# Ontology results (${objects.length} object${objects.length === 1 ? "" : "s"})`,
1909
+ sections,
1910
+ state
1911
+ );
1912
+ }
1913
+ function renderObjectList(response, title) {
1914
+ const payload = obj(response);
1915
+ if (!payload) return void 0;
1916
+ const rawItems = Array.isArray(payload.items) ? payload.items : Array.isArray(payload.rows) && payload.rows.some((row) => unwrapSearchResult(row)) ? payload.rows : void 0;
1917
+ const items = (rawItems ?? []).map(unwrapSearchResult).filter((node) => Boolean(node));
1918
+ if (items.length === 0) {
1919
+ return rawItems ? `# ${title} (0 results)` : void 0;
1920
+ }
1921
+ const state = { bounded: false };
1922
+ const sections = groupedNodeSections(items, state);
1923
+ const total = num(payload.total_count);
1924
+ const truncations = Array.isArray(payload.truncation_reasons) ? payload.truncation_reasons.filter((reason) => typeof reason === "string") : [];
1925
+ const notes = [];
1926
+ if (payload.has_more === true) notes.push("more results exist");
1927
+ if (truncations.length > 0) notes.push(`truncated: ${truncations.join(", ")}`);
1928
+ if (notes.length > 0) sections.push({ heading: `Note: ${notes.join("; ")}.`, items: [] });
1929
+ const count = total !== void 0 && total !== items.length ? `${items.length} of ${total}` : `${items.length}`;
1930
+ return assemble(`# ${title} (${count})`, sections, state);
1931
+ }
1932
+ var JOBS_RENDER_MAX = 20;
1933
+ function renderJobs(response) {
1934
+ const jobs = Array.isArray(response) ? response : obj(response)?.jobs;
1935
+ if (!Array.isArray(jobs)) return void 0;
1936
+ if (jobs.length === 0) return "No ingestion jobs.";
1937
+ const state = { bounded: false };
1938
+ const sorted = jobs.map((raw) => obj(raw)).filter((job) => Boolean(job)).sort((a, b) => (num(b.created_at) ?? 0) - (num(a.created_at) ?? 0));
1939
+ const shown = sorted.slice(0, JOBS_RENDER_MAX);
1940
+ if (shown.length < sorted.length) state.bounded = true;
1941
+ const items = shown.map((job) => {
1942
+ const progress = obj(job.progress);
1943
+ const done = num(progress?.processed_chunks);
1944
+ const totalChunks = num(progress?.total_chunks);
1945
+ const bits = [
1946
+ str(job.status) || "?",
1947
+ done !== void 0 && totalChunks !== void 0 ? `${done}/${totalChunks} chunks` : void 0,
1948
+ num(progress?.nodes_created) !== void 0 ? `${num(progress?.nodes_created)} nodes` : void 0,
1949
+ num(job.queue_position) !== void 0 ? `queue #${num(job.queue_position)}` : void 0,
1950
+ str(job.error) ? `error: ${clip(job.error, 160, state)}` : void 0
1951
+ ].filter(Boolean);
1952
+ return `- [${str(job.id) || "?"}] ${clip(job.title, 120, state) || "(untitled)"} \u2014 ${bits.join(", ")}`;
1953
+ });
1954
+ return assemble(
1955
+ `# Ingestion jobs (${shown.length}${shown.length < sorted.length ? ` of ${sorted.length}` : ""})`,
1956
+ [{ heading: "", items }],
1957
+ state
1958
+ );
1959
+ }
1960
+ function renderSignals(response) {
1961
+ const payload = obj(response);
1962
+ if (!payload) return void 0;
1963
+ const state = { bounded: false };
1964
+ const sections = [];
1965
+ for (const [key, value] of Object.entries(payload)) {
1966
+ if (!Array.isArray(value) || value.length === 0) continue;
1967
+ const items = value.map((raw) => obj(raw)).filter((item) => Boolean(item)).map((item) => {
1968
+ const fromLabel = str(item.from_label);
1969
+ const toLabel = str(item.to_label);
1970
+ const anyLabelKey = Object.keys(item).find(
1971
+ (k) => k.endsWith("_label") && str(item[k])
1972
+ );
1973
+ const label = str(item.label) ?? str(item.title) ?? str(item.name) ?? (fromLabel && toLabel ? `${fromLabel} \u2194 ${toLabel}` : void 0) ?? (anyLabelKey ? str(item[anyLabelKey]) : void 0) ?? str(item.uid) ?? str(item.target_uid) ?? "(item)";
1974
+ const uid = str(item.uid) ?? str(item.target_uid);
1975
+ const numbers = Object.entries(item).filter(([, v]) => typeof v === "number").slice(0, 4).map(([k, v]) => `${k} ${Math.round(v * 100) / 100}`);
1976
+ const lists = Object.entries(item).filter(([, v]) => Array.isArray(v) && v.length > 0).slice(0, 2).map(([k, v]) => `${k}: ${v.length}`);
1977
+ const meta = [...numbers, ...lists].join(", ");
1978
+ return `- ${clip(label, 160, state)}${uid && uid !== label ? ` [${uid}]` : ""}${meta ? ` (${meta})` : ""}`;
1979
+ });
1980
+ if (items.length > 0) {
1981
+ sections.push({ heading: `## ${key.replace(/_/g, " ")}`, items });
1982
+ }
1983
+ }
1984
+ if (sections.length === 0) return void 0;
1985
+ return assemble("# Synthesis signals", sections, state);
1986
+ }
1825
1987
 
1826
1988
  // src/tools.ts
1827
1989
  var TOOLS = [
@@ -2631,6 +2793,11 @@ var TOOLS = [
2631
2793
  type: "string",
2632
2794
  description: "Job ID to check status (for job_status action)"
2633
2795
  },
2796
+ format: {
2797
+ type: "string",
2798
+ enum: ["text", "json"],
2799
+ description: "job_status without job_id: 'text' (default) renders the 20 most recent jobs; 'json' returns the full raw list."
2800
+ },
2634
2801
  agent_id: {
2635
2802
  type: "string",
2636
2803
  description: "Agent identity"
@@ -2666,6 +2833,11 @@ var TOOLS = [
2666
2833
  type: "string",
2667
2834
  description: "Job ID to poll (for action='job_status')"
2668
2835
  },
2836
+ format: {
2837
+ type: "string",
2838
+ enum: ["text", "json"],
2839
+ description: "signals action: 'text' (default) renders signal sections; 'json' returns the raw payload."
2840
+ },
2669
2841
  agent_id: {
2670
2842
  type: "string",
2671
2843
  description: "Agent identity"
@@ -2774,6 +2946,11 @@ var TOOLS = [
2774
2946
  items: { type: "string" },
2775
2947
  description: "Chunk/document UIDs to extract from (for action=extract)"
2776
2948
  },
2949
+ format: {
2950
+ type: "string",
2951
+ enum: ["text", "json"],
2952
+ description: "Output format for the read actions query/search/objects/object/object_context (default 'text'): a compact rendered block. Pass 'json' for the raw server response."
2953
+ },
2777
2954
  agent_id: {
2778
2955
  type: "string",
2779
2956
  description: "Agent identity"
@@ -2816,9 +2993,14 @@ function toolsForProfile(profile = process.env.MINDGRAPH_PROFILE || "general") {
2816
2993
  }
2817
2994
  function ok3(data) {
2818
2995
  return {
2819
- content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
2996
+ content: [{ type: "text", text: JSON.stringify(data) }]
2820
2997
  };
2821
2998
  }
2999
+ function renderedResult(format, raw, render) {
3000
+ if (format === "json") return ok3(raw);
3001
+ const text = render(raw);
3002
+ return text !== void 0 ? { content: [{ type: "text", text }] } : ok3(raw);
3003
+ }
2822
3004
  function err3(message) {
2823
3005
  return {
2824
3006
  content: [{ type: "text", text: JSON.stringify({ error: message }) }],
@@ -3430,15 +3612,11 @@ async function handleRetrieve(client2, args) {
3430
3612
  max_cost,
3431
3613
  agent_id
3432
3614
  } = args;
3433
- const rendered = (raw, render) => {
3434
- if (format === "json") return ok3(raw);
3435
- const text = render(raw);
3436
- return text !== void 0 ? { content: [{ type: "text", text }] } : ok3(raw);
3437
- };
3615
+ const rendered2 = (raw, render) => renderedResult(format, raw, render);
3438
3616
  switch (action) {
3439
3617
  case "context":
3440
3618
  if (!query) return err3("query is required for context retrieval");
3441
- return rendered(
3619
+ return rendered2(
3442
3620
  await client2.retrieveContext({
3443
3621
  query,
3444
3622
  node_limit: limit,
@@ -3463,7 +3641,7 @@ async function handleRetrieve(client2, args) {
3463
3641
  );
3464
3642
  case "text":
3465
3643
  if (!query) return err3("query is required for text search");
3466
- return rendered(
3644
+ return rendered2(
3467
3645
  await client2.retrieve({
3468
3646
  action: "text",
3469
3647
  query,
@@ -3477,7 +3655,7 @@ async function handleRetrieve(client2, args) {
3477
3655
  );
3478
3656
  case "semantic":
3479
3657
  if (!query) return err3("query is required for semantic search");
3480
- return rendered(
3658
+ return rendered2(
3481
3659
  await client2.retrieve({
3482
3660
  action: "semantic",
3483
3661
  query,
@@ -3491,7 +3669,7 @@ async function handleRetrieve(client2, args) {
3491
3669
  );
3492
3670
  case "hybrid":
3493
3671
  if (!query) return err3("query is required for hybrid search");
3494
- return rendered(
3672
+ return rendered2(
3495
3673
  await client2.retrieve({
3496
3674
  action: "hybrid",
3497
3675
  query,
@@ -3513,7 +3691,7 @@ async function handleRetrieve(client2, args) {
3513
3691
  case "weak_claims":
3514
3692
  case "pending_approvals":
3515
3693
  case "unresolved_contradictions":
3516
- return rendered(
3694
+ return rendered2(
3517
3695
  await client2.retrieve({
3518
3696
  action,
3519
3697
  limit,
@@ -3523,7 +3701,7 @@ async function handleRetrieve(client2, args) {
3523
3701
  (raw) => renderNodeList(raw, action.replace(/_/g, " "), limit)
3524
3702
  );
3525
3703
  case "stale_derivations":
3526
- return rendered(
3704
+ return rendered2(
3527
3705
  await client2.retrieve({
3528
3706
  action: "stale_derivations",
3529
3707
  limit,
@@ -3532,7 +3710,7 @@ async function handleRetrieve(client2, args) {
3532
3710
  (raw) => renderNodeList(raw, "stale derivations", limit)
3533
3711
  );
3534
3712
  case "preferences":
3535
- return rendered(
3713
+ return rendered2(
3536
3714
  await client2.retrieve({
3537
3715
  action: "preferences",
3538
3716
  ...query ? { query, k: limit } : {},
@@ -3543,7 +3721,7 @@ async function handleRetrieve(client2, args) {
3543
3721
  );
3544
3722
  case "layer":
3545
3723
  if (!layer) return err3("layer is required for layer retrieval");
3546
- return rendered(
3724
+ return rendered2(
3547
3725
  await client2.retrieve({
3548
3726
  action: "layer",
3549
3727
  layer,
@@ -3554,7 +3732,7 @@ async function handleRetrieve(client2, args) {
3554
3732
  (raw) => renderNodeList(raw, `Layer: ${layer}`, limit)
3555
3733
  );
3556
3734
  case "recent":
3557
- return rendered(
3735
+ return rendered2(
3558
3736
  await client2.retrieve({
3559
3737
  action: "recent",
3560
3738
  limit,
@@ -3569,7 +3747,7 @@ async function handleRetrieve(client2, args) {
3569
3747
  );
3570
3748
  // Document inventory
3571
3749
  case "document_index":
3572
- return rendered(
3750
+ return rendered2(
3573
3751
  await client2.getNodes({
3574
3752
  node_type: "Document",
3575
3753
  limit: limit ?? 100
@@ -3579,7 +3757,7 @@ async function handleRetrieve(client2, args) {
3579
3757
  // Graph traversal
3580
3758
  case "chain":
3581
3759
  if (!start_uid) return err3("start_uid is required for chain traversal");
3582
- return rendered(
3760
+ return rendered2(
3583
3761
  await client2.traverse({
3584
3762
  action: "chain",
3585
3763
  start_uid,
@@ -3592,7 +3770,7 @@ async function handleRetrieve(client2, args) {
3592
3770
  );
3593
3771
  case "neighborhood":
3594
3772
  if (!start_uid) return err3("start_uid is required for neighborhood traversal");
3595
- return rendered(
3773
+ return rendered2(
3596
3774
  await client2.traverse({
3597
3775
  action: "neighborhood",
3598
3776
  start_uid,
@@ -3608,7 +3786,7 @@ async function handleRetrieve(client2, args) {
3608
3786
  case "path":
3609
3787
  if (!start_uid) return err3("start_uid is required for path traversal");
3610
3788
  if (!end_uid) return err3("end_uid is required for path traversal");
3611
- return rendered(
3789
+ return rendered2(
3612
3790
  await client2.traverse({
3613
3791
  action: "path",
3614
3792
  start_uid,
@@ -3624,7 +3802,7 @@ async function handleRetrieve(client2, args) {
3624
3802
  );
3625
3803
  case "subgraph":
3626
3804
  if (!start_uid) return err3("start_uid is required for subgraph traversal");
3627
- return rendered(
3805
+ return rendered2(
3628
3806
  await client2.traverse({
3629
3807
  action: "subgraph",
3630
3808
  start_uid,
@@ -3640,7 +3818,7 @@ async function handleRetrieve(client2, args) {
3640
3818
  case "top_k_paths":
3641
3819
  if (!start_uid) return err3("start_uid is required for top_k_paths");
3642
3820
  if (!end_uid) return err3("end_uid is required for top_k_paths");
3643
- return rendered(
3821
+ return rendered2(
3644
3822
  await client2.traverse({
3645
3823
  action: "top_k_paths",
3646
3824
  start_uid,
@@ -3677,6 +3855,7 @@ async function handleIngest(client2, args) {
3677
3855
  chunk_size,
3678
3856
  chunk_overlap,
3679
3857
  job_id,
3858
+ format,
3680
3859
  agent_id
3681
3860
  } = args;
3682
3861
  const src = source_uri ?? source;
@@ -3746,19 +3925,21 @@ async function handleIngest(client2, args) {
3746
3925
  if (job_id) {
3747
3926
  return ok3(await client2.getJob(job_id));
3748
3927
  }
3749
- return ok3(await client2.listJobs());
3928
+ return renderedResult(format, await client2.listJobs(), renderJobs);
3750
3929
  default:
3751
3930
  return err3(`Unknown ingest action: ${action}`);
3752
3931
  }
3753
3932
  }
3754
3933
  async function handleSynthesize(client2, args) {
3755
- const { action, project_uid, signals, target_types, job_id } = args;
3934
+ const { action, project_uid, signals, target_types, job_id, format } = args;
3756
3935
  switch (action) {
3757
3936
  case "signals":
3758
3937
  if (!project_uid)
3759
3938
  return err3("project_uid is required for action='signals'");
3760
- return ok3(
3761
- await client2.signals(project_uid, { signals, target_types })
3939
+ return renderedResult(
3940
+ format,
3941
+ await client2.signals(project_uid, { signals, target_types }),
3942
+ renderSignals
3762
3943
  );
3763
3944
  case "run":
3764
3945
  if (!project_uid)
@@ -3792,6 +3973,7 @@ async function handleOntology(client2, args) {
3792
3973
  relation_type,
3793
3974
  fields,
3794
3975
  source_uids,
3976
+ format,
3795
3977
  agent_id
3796
3978
  } = args;
3797
3979
  switch (action) {
@@ -3807,7 +3989,8 @@ async function handleOntology(client2, args) {
3807
3989
  "schema_id is required for action='query' (use action='schemas' to find the active schema)"
3808
3990
  );
3809
3991
  }
3810
- return ok3(
3992
+ return renderedResult(
3993
+ format,
3811
3994
  await client2.queryOntology({
3812
3995
  query,
3813
3996
  schema_id,
@@ -3816,29 +3999,42 @@ async function handleOntology(client2, args) {
3816
3999
  include_sources: include_sources ?? true,
3817
4000
  depth,
3818
4001
  limit
3819
- })
4002
+ }),
4003
+ renderOntologyAnswer
3820
4004
  );
3821
4005
  }
3822
4006
  case "search":
3823
4007
  if (!query) return err3("query is required for action='search'");
3824
- return ok3(
4008
+ return renderedResult(
4009
+ format,
3825
4010
  await client2.searchDomainObjects(query, {
3826
4011
  schema_id,
3827
4012
  object_types,
3828
4013
  limit
3829
- })
4014
+ }),
4015
+ (raw) => renderObjectList(raw, `Domain search: ${query}`)
3830
4016
  );
3831
4017
  case "objects":
3832
4018
  if (!schema_id) return err3("schema_id is required for action='objects'");
3833
- return ok3(
3834
- await client2.listDomainObjects({ schema_id, object_type, limit })
4019
+ return renderedResult(
4020
+ format,
4021
+ await client2.listDomainObjects({ schema_id, object_type, limit }),
4022
+ (raw) => renderObjectList(raw, `Domain objects${object_type ? `: ${object_type}` : ""}`)
3835
4023
  );
3836
4024
  case "object":
3837
4025
  if (!uid) return err3("uid is required for action='object'");
3838
- return ok3(await client2.getDomainObject(uid));
4026
+ return renderedResult(
4027
+ format,
4028
+ await client2.getDomainObject(uid),
4029
+ (raw) => renderNodeList([raw], "Domain object")
4030
+ );
3839
4031
  case "object_context":
3840
4032
  if (!uid) return err3("uid is required for action='object_context'");
3841
- return ok3(await client2.getDomainObjectContext(uid, depth));
4033
+ return renderedResult(
4034
+ format,
4035
+ await client2.getDomainObjectContext(uid, depth),
4036
+ renderOntologyAnswer
4037
+ );
3842
4038
  case "proposals":
3843
4039
  return ok3(
3844
4040
  await client2.listOntologyProposals({
@@ -3892,8 +4088,14 @@ async function handleOntology(client2, args) {
3892
4088
 
3893
4089
  // src/generated-tools.ts
3894
4090
  var ok4 = (data) => ({
3895
- content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
4091
+ // Compact on purpose — pretty-printing doubled the token cost.
4092
+ content: [{ type: "text", text: JSON.stringify(data) }]
3896
4093
  });
4094
+ var rendered = (format, raw, render) => {
4095
+ if (format === "json") return ok4(raw);
4096
+ const text = render(raw);
4097
+ return text !== void 0 ? { content: [{ type: "text", text }] } : ok4(raw);
4098
+ };
3897
4099
  var err4 = (message) => ({
3898
4100
  content: [{ type: "text", text: JSON.stringify({ error: message }) }],
3899
4101
  isError: true
@@ -3932,10 +4134,21 @@ async function getGeneratedTools(client2) {
3932
4134
  );
3933
4135
  }
3934
4136
  byName.set(d.name, d);
4137
+ const inputSchema = d.maps_to === "structured_query" ? d.input_schema : {
4138
+ ...d.input_schema,
4139
+ properties: {
4140
+ ...d.input_schema.properties,
4141
+ format: {
4142
+ type: "string",
4143
+ enum: ["text", "json"],
4144
+ description: "Output format (default 'text': compact rendered block). Pass 'json' for the raw server response."
4145
+ }
4146
+ }
4147
+ };
3935
4148
  tools.push({
3936
4149
  name: d.name,
3937
4150
  description: d.description,
3938
- inputSchema: d.input_schema
4151
+ inputSchema
3939
4152
  });
3940
4153
  }
3941
4154
  cache = { tools, byName, fetchedAt: Date.now() };
@@ -3964,31 +4177,41 @@ async function handleGeneratedTool(client2, desc, args) {
3964
4177
  if (!query) return err4(`query is required for ${desc.name}`);
3965
4178
  const limit = typeof args.limit === "number" ? args.limit : void 0;
3966
4179
  const filters = Array.isArray(args.filters) ? args.filters : void 0;
3967
- return ok4(
4180
+ return rendered(
4181
+ args.format,
3968
4182
  await ontologyClient.searchDomainObjects(query, {
3969
4183
  schema_id: desc.schema_id,
3970
4184
  object_types: [desc.object_type],
3971
4185
  filters,
3972
4186
  limit
3973
- })
4187
+ }),
4188
+ (raw) => renderObjectList(raw, `${desc.object_type} search: ${query}`)
3974
4189
  );
3975
4190
  }
3976
4191
  case "object": {
3977
4192
  const uid = args.uid;
3978
4193
  if (!uid) return err4(`uid is required for ${desc.name}`);
3979
- return ok4(await ontologyClient.getDomainObject(uid, {
3980
- schema_id: desc.schema_id,
3981
- object_type: desc.object_type
3982
- }));
4194
+ return rendered(
4195
+ args.format,
4196
+ await ontologyClient.getDomainObject(uid, {
4197
+ schema_id: desc.schema_id,
4198
+ object_type: desc.object_type
4199
+ }),
4200
+ (raw) => renderNodeList([raw], desc.object_type)
4201
+ );
3983
4202
  }
3984
4203
  case "object_context": {
3985
4204
  const uid = args.uid;
3986
4205
  if (!uid) return err4(`uid is required for ${desc.name}`);
3987
4206
  const depth = typeof args.depth === "number" ? args.depth : void 0;
3988
- return ok4(await ontologyClient.getDomainObjectContext(uid, depth, {
3989
- schema_id: desc.schema_id,
3990
- object_type: desc.object_type
3991
- }));
4207
+ return rendered(
4208
+ args.format,
4209
+ await ontologyClient.getDomainObjectContext(uid, depth, {
4210
+ schema_id: desc.schema_id,
4211
+ object_type: desc.object_type
4212
+ }),
4213
+ renderOntologyAnswer
4214
+ );
3992
4215
  }
3993
4216
  case "related": {
3994
4217
  const uid = args.uid;
@@ -4001,18 +4224,22 @@ async function handleGeneratedTool(client2, desc, args) {
4001
4224
  "related ontology tools require a graph-aware version of the mindgraph SDK"
4002
4225
  );
4003
4226
  }
4004
- return ok4(await ontologyClient.queryRelatedDomainObjects({
4005
- schema_id: desc.schema_id,
4006
- entry_type: desc.object_type,
4007
- uid,
4008
- relation: desc.relation,
4009
- entry_role: desc.entry_role,
4010
- far_type: desc.far_type,
4011
- where: Array.isArray(args.where) ? args.where : void 0,
4012
- include_provenance: args.include_provenance === true,
4013
- limit: typeof args.limit === "number" ? args.limit : void 0,
4014
- offset: typeof args.offset === "number" ? args.offset : void 0
4015
- }));
4227
+ return rendered(
4228
+ args.format,
4229
+ await ontologyClient.queryRelatedDomainObjects({
4230
+ schema_id: desc.schema_id,
4231
+ entry_type: desc.object_type,
4232
+ uid,
4233
+ relation: desc.relation,
4234
+ entry_role: desc.entry_role,
4235
+ far_type: desc.far_type,
4236
+ where: Array.isArray(args.where) ? args.where : void 0,
4237
+ include_provenance: args.include_provenance === true,
4238
+ limit: typeof args.limit === "number" ? args.limit : void 0,
4239
+ offset: typeof args.offset === "number" ? args.offset : void 0
4240
+ }),
4241
+ (raw) => renderObjectList(raw, `${desc.far_type} related via ${desc.relation}`)
4242
+ );
4016
4243
  }
4017
4244
  case "structured_query": {
4018
4245
  const select = args.select;
@@ -4331,7 +4558,7 @@ var RESOURCE_TEMPLATES = [
4331
4558
  var RESOURCE_GOVERNANCE_TOOL = "mindgraph_retrieve";
4332
4559
  function json(uri, data) {
4333
4560
  return {
4334
- contents: [{ uri, mimeType: "application/json", text: JSON.stringify(data, null, 2) }]
4561
+ contents: [{ uri, mimeType: "application/json", text: JSON.stringify(data) }]
4335
4562
  };
4336
4563
  }
4337
4564
  async function readResource(client2, uri) {
@@ -4504,7 +4731,7 @@ if (PROFILE === "coding") {
4504
4731
  var server = new import_server.Server(
4505
4732
  {
4506
4733
  name: "mindgraph",
4507
- version: "0.16.0"
4734
+ version: "0.17.0"
4508
4735
  },
4509
4736
  {
4510
4737
  capabilities: {
@@ -4718,7 +4945,7 @@ async function main() {
4718
4945
  const transport = new import_stdio.StdioServerTransport();
4719
4946
  await server.connect(transport);
4720
4947
  console.error(
4721
- `MindGraph MCP server v${"0.16.0"} running on stdio (${BASE_URL})`
4948
+ `MindGraph MCP server v${"0.17.0"} running on stdio (${BASE_URL})`
4722
4949
  );
4723
4950
  }
4724
4951
  main().catch((error) => {