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/cli.js CHANGED
@@ -2123,13 +2123,13 @@ var init_code_tool = __esm({
2123
2123
  init_error_detail();
2124
2124
  init_codegraph();
2125
2125
  ok = (data) => ({
2126
- content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
2126
+ content: [{ type: "text", text: JSON.stringify(data) }]
2127
2127
  });
2128
2128
  err = (code, message, details) => ({
2129
2129
  content: [
2130
2130
  {
2131
2131
  type: "text",
2132
- text: JSON.stringify({ error: message, code, details }, null, 2)
2132
+ text: JSON.stringify({ error: message, code, details })
2133
2133
  }
2134
2134
  ],
2135
2135
  isError: true
@@ -2335,7 +2335,7 @@ var init_sync_tool = __esm({
2335
2335
  init_codegraph();
2336
2336
  init_error_detail();
2337
2337
  ok2 = (data) => ({
2338
- content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
2338
+ content: [{ type: "text", text: JSON.stringify(data) }]
2339
2339
  });
2340
2340
  err2 = (code, message) => ({
2341
2341
  content: [{ type: "text", text: JSON.stringify({ code, error: message }) }],
@@ -2431,12 +2431,23 @@ function clip(value, max, state) {
2431
2431
  }
2432
2432
  function isNodeShaped(value) {
2433
2433
  const node = obj(value);
2434
- return Boolean(node && str(node.uid) && (str(node.label) || str(node.node_type)));
2434
+ return Boolean(
2435
+ node && str(node.uid) && (str(node.label) || str(node.node_type) || obj(node.node_type))
2436
+ );
2437
+ }
2438
+ function nodeDisplayType(node) {
2439
+ const props = obj(node.props);
2440
+ const plain = str(node.node_type);
2441
+ 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";
2442
+ }
2443
+ function nodeFields(node) {
2444
+ const props = obj(node.props);
2445
+ return obj(props?.fields) ?? obj(obj(props?.data)?.fields);
2435
2446
  }
2436
2447
  function unwrapSearchResult(value) {
2437
2448
  if (isNodeShaped(value)) return value;
2438
2449
  const wrapper = obj(value);
2439
- const inner = obj(wrapper?.node);
2450
+ const inner = obj(wrapper?.node) ?? obj(wrapper?.object);
2440
2451
  if (inner && isNodeShaped(inner)) {
2441
2452
  const score = num(wrapper.score);
2442
2453
  return score !== void 0 ? { ...inner, retrieval_score: score } : inner;
@@ -2474,7 +2485,7 @@ function sourceTag(node) {
2474
2485
  return `from: ${title}${extra}`;
2475
2486
  }
2476
2487
  function layer7Fields(node, state) {
2477
- const fields = obj(obj(node.props)?.fields);
2488
+ const fields = nodeFields(node);
2478
2489
  if (!fields) return void 0;
2479
2490
  const pairs = Object.entries(fields).filter(([, value]) => value !== null && value !== void 0 && value !== "").map(([key, value]) => `${key}: ${Array.isArray(value) ? value.join(", ") : String(value)}`);
2480
2491
  if (pairs.length === 0) return void 0;
@@ -2486,7 +2497,7 @@ function nodeSummaryText(node, state) {
2486
2497
  }
2487
2498
  function nodeLines(node, state) {
2488
2499
  const label = clip(node.label, LABEL_MAX, state) || "(unlabeled)";
2489
- const type = str(node.node_type) || "Node";
2500
+ const type = nodeDisplayType(node);
2490
2501
  const confidence = num(node.confidence);
2491
2502
  const score = num(node.retrieval_score);
2492
2503
  const parenthetical = [
@@ -2505,19 +2516,19 @@ function nodeLines(node, state) {
2505
2516
  if (source) lines.push(` - ${source}`);
2506
2517
  const believers = Array.isArray(node.believed_by) ? node.believed_by : [];
2507
2518
  if (believers.length > 0) {
2508
- const rendered = believers.slice(0, 3).map((raw) => {
2519
+ const rendered2 = believers.slice(0, 3).map((raw) => {
2509
2520
  const believer = obj(raw);
2510
2521
  const conf = num(believer?.confidence);
2511
2522
  return `${str(believer?.agent_label) || "?"}${conf !== void 0 ? ` (${conf})` : ""}`;
2512
2523
  }).join(", ");
2513
- lines.push(` - believed by: ${rendered}`);
2524
+ lines.push(` - believed by: ${rendered2}`);
2514
2525
  }
2515
2526
  return lines.join("\n");
2516
2527
  }
2517
2528
  function groupedNodeSections(nodes, state, headingPrefix = "") {
2518
2529
  const groups = /* @__PURE__ */ new Map();
2519
2530
  for (const node of nodes) {
2520
- const type = str(node.node_type) || "Node";
2531
+ const type = nodeDisplayType(node);
2521
2532
  const group = groups.get(type) ?? [];
2522
2533
  group.push(node);
2523
2534
  groups.set(type, group);
@@ -2533,7 +2544,7 @@ function groupedNodeSections(nodes, state, headingPrefix = "") {
2533
2544
  }
2534
2545
  return sections;
2535
2546
  }
2536
- function relationshipItems(edges, labelByUid, state) {
2547
+ function relationshipItems(edges, labelByUid, state, options) {
2537
2548
  const lines = [];
2538
2549
  for (const raw of edges) {
2539
2550
  const edge = obj(raw);
@@ -2543,8 +2554,8 @@ function relationshipItems(edges, labelByUid, state) {
2543
2554
  const to = str(edge.to_uid);
2544
2555
  if (CURATION_EDGE_TYPES.has(type)) continue;
2545
2556
  if (!from || !to || from === to) continue;
2546
- const fromLabel = labelByUid.get(from);
2547
- const toLabel = labelByUid.get(to);
2557
+ const fromLabel = labelByUid.get(from) ?? (options?.fallbackToUid ? `[${from}]` : void 0);
2558
+ const toLabel = labelByUid.get(to) ?? (options?.fallbackToUid ? `[${to}]` : void 0);
2548
2559
  if (!fromLabel || !toLabel) continue;
2549
2560
  lines.push(`- ${fromLabel} \u2014${type}\u2192 ${toLabel}`);
2550
2561
  }
@@ -2587,8 +2598,8 @@ function assemble(header, sections, state) {
2587
2598
  sectionUsed += marker.length + 1;
2588
2599
  }
2589
2600
  lines.push(
2590
- section.items.length === 0 ? section.heading : `${section.heading}
2591
- ${kept.join("\n")}`
2601
+ section.items.length === 0 ? section.heading : section.heading ? `${section.heading}
2602
+ ${kept.join("\n")}` : kept.join("\n")
2592
2603
  );
2593
2604
  used += headingCost + sectionUsed;
2594
2605
  }
@@ -2751,7 +2762,157 @@ function renderTraversal(response) {
2751
2762
  }
2752
2763
  return assemble("# Graph traversal", sections, state);
2753
2764
  }
2754
- var LABEL_MAX, SUMMARY_MAX, QUOTE_MAX, ARTICLE_MAX, CHUNK_MAX, RELATIONSHIP_MAX, RENDER_CHAR_BUDGET, CURATION_EDGE_TYPES, INFRA_NODE_TYPES;
2765
+ function neighborLine(value) {
2766
+ const node = obj(value);
2767
+ if (!node) return void 0;
2768
+ const label = str(node.label) || "(unlabeled)";
2769
+ const uid = str(node.uid);
2770
+ const type = str(node.node_type);
2771
+ return `- ${label}${uid ? ` [${uid}]` : ""}${type ? ` (${type})` : ""}`;
2772
+ }
2773
+ function renderOntologyAnswer(response) {
2774
+ const payload = obj(response);
2775
+ if (!payload) return void 0;
2776
+ const objects = Array.isArray(payload.objects) ? payload.objects.filter(isNodeShaped) : isNodeShaped(payload.object) ? [payload.object] : [];
2777
+ const cognitive = obj(payload.cognitive_context);
2778
+ const provenance = Array.isArray(payload.provenance) ? payload.provenance : [];
2779
+ const hasQuerySignature = Array.isArray(payload.objects) || obj(payload.confidence) !== void 0;
2780
+ const cognitiveEmpty = !cognitive || Object.values(cognitive).every((v) => !Array.isArray(v) || v.length === 0);
2781
+ if (objects.length === 0 && cognitiveEmpty && provenance.length === 0) {
2782
+ return hasQuerySignature ? "No matching domain objects." : void 0;
2783
+ }
2784
+ const state = { bounded: false };
2785
+ const sections = [];
2786
+ if (objects.length > 0) {
2787
+ sections.push(...groupedNodeSections(objects, state));
2788
+ }
2789
+ const labelByUid = /* @__PURE__ */ new Map();
2790
+ for (const node of objects) labelByUid.set(str(node.uid), str(node.label) || "?");
2791
+ const graph = obj(payload.graph);
2792
+ for (const raw of Array.isArray(graph?.nodes) ? graph.nodes : []) {
2793
+ const node = obj(raw);
2794
+ const uid = str(node?.uid);
2795
+ if (uid && !labelByUid.has(uid)) labelByUid.set(uid, str(node?.label) || "?");
2796
+ }
2797
+ if (cognitive) {
2798
+ for (const rawNodes of Object.values(cognitive)) {
2799
+ if (!Array.isArray(rawNodes)) continue;
2800
+ for (const raw of rawNodes) {
2801
+ const node = obj(raw);
2802
+ const uid = str(node?.uid);
2803
+ if (uid && !labelByUid.has(uid)) labelByUid.set(uid, str(node?.label) || "?");
2804
+ }
2805
+ }
2806
+ }
2807
+ const relations = Array.isArray(payload.relations) ? payload.relations : [];
2808
+ const relationLines = relationshipItems(relations, labelByUid, state, { fallbackToUid: true });
2809
+ if (relationLines.length > 0) {
2810
+ sections.push({ heading: "## Relations", items: relationLines });
2811
+ }
2812
+ if (cognitive) {
2813
+ for (const [category, rawNodes] of Object.entries(cognitive)) {
2814
+ if (!Array.isArray(rawNodes) || rawNodes.length === 0) continue;
2815
+ const items = rawNodes.map(neighborLine).filter((line) => Boolean(line));
2816
+ if (items.length > 0) {
2817
+ sections.push({ heading: `### Cognitive context \u2014 ${category}`, items });
2818
+ }
2819
+ }
2820
+ }
2821
+ if (provenance.length > 0) {
2822
+ const items = provenance.map((raw) => obj(raw)).filter((entry) => Boolean(entry)).map((entry) => {
2823
+ const span = clip(entry.text_span, QUOTE_MAX, state) || "";
2824
+ const by = str(entry.ingested_by_name);
2825
+ const suffix = `${by ? ` (ingested by ${by})` : ""} [source ${str(entry.source_uid) || "?"}]`;
2826
+ return str(entry.span_kind) === "anchor" ? `- "${span}"${suffix}` : `- context: ${span}${suffix}`;
2827
+ });
2828
+ sections.push({ heading: "## Sources", items });
2829
+ }
2830
+ const confidence = num(obj(payload.confidence)?.overall);
2831
+ const notes = [];
2832
+ if (confidence !== void 0) notes.push(`overall confidence ${confidence}`);
2833
+ if (payload.has_more === true) notes.push("more results exist (has_more)");
2834
+ if (payload.seed_cap_hit === true) notes.push("seed cap hit \u2014 narrow the query for a complete set");
2835
+ if (notes.length > 0) sections.push({ heading: `Note: ${notes.join("; ")}.`, items: [] });
2836
+ return assemble(
2837
+ `# Ontology results (${objects.length} object${objects.length === 1 ? "" : "s"})`,
2838
+ sections,
2839
+ state
2840
+ );
2841
+ }
2842
+ function renderObjectList(response, title) {
2843
+ const payload = obj(response);
2844
+ if (!payload) return void 0;
2845
+ const rawItems = Array.isArray(payload.items) ? payload.items : Array.isArray(payload.rows) && payload.rows.some((row) => unwrapSearchResult(row)) ? payload.rows : void 0;
2846
+ const items = (rawItems ?? []).map(unwrapSearchResult).filter((node) => Boolean(node));
2847
+ if (items.length === 0) {
2848
+ return rawItems ? `# ${title} (0 results)` : void 0;
2849
+ }
2850
+ const state = { bounded: false };
2851
+ const sections = groupedNodeSections(items, state);
2852
+ const total = num(payload.total_count);
2853
+ const truncations = Array.isArray(payload.truncation_reasons) ? payload.truncation_reasons.filter((reason) => typeof reason === "string") : [];
2854
+ const notes = [];
2855
+ if (payload.has_more === true) notes.push("more results exist");
2856
+ if (truncations.length > 0) notes.push(`truncated: ${truncations.join(", ")}`);
2857
+ if (notes.length > 0) sections.push({ heading: `Note: ${notes.join("; ")}.`, items: [] });
2858
+ const count = total !== void 0 && total !== items.length ? `${items.length} of ${total}` : `${items.length}`;
2859
+ return assemble(`# ${title} (${count})`, sections, state);
2860
+ }
2861
+ function renderJobs(response) {
2862
+ const jobs = Array.isArray(response) ? response : obj(response)?.jobs;
2863
+ if (!Array.isArray(jobs)) return void 0;
2864
+ if (jobs.length === 0) return "No ingestion jobs.";
2865
+ const state = { bounded: false };
2866
+ const sorted = jobs.map((raw) => obj(raw)).filter((job) => Boolean(job)).sort((a, b) => (num(b.created_at) ?? 0) - (num(a.created_at) ?? 0));
2867
+ const shown = sorted.slice(0, JOBS_RENDER_MAX);
2868
+ if (shown.length < sorted.length) state.bounded = true;
2869
+ const items = shown.map((job) => {
2870
+ const progress = obj(job.progress);
2871
+ const done = num(progress?.processed_chunks);
2872
+ const totalChunks = num(progress?.total_chunks);
2873
+ const bits = [
2874
+ str(job.status) || "?",
2875
+ done !== void 0 && totalChunks !== void 0 ? `${done}/${totalChunks} chunks` : void 0,
2876
+ num(progress?.nodes_created) !== void 0 ? `${num(progress?.nodes_created)} nodes` : void 0,
2877
+ num(job.queue_position) !== void 0 ? `queue #${num(job.queue_position)}` : void 0,
2878
+ str(job.error) ? `error: ${clip(job.error, 160, state)}` : void 0
2879
+ ].filter(Boolean);
2880
+ return `- [${str(job.id) || "?"}] ${clip(job.title, 120, state) || "(untitled)"} \u2014 ${bits.join(", ")}`;
2881
+ });
2882
+ return assemble(
2883
+ `# Ingestion jobs (${shown.length}${shown.length < sorted.length ? ` of ${sorted.length}` : ""})`,
2884
+ [{ heading: "", items }],
2885
+ state
2886
+ );
2887
+ }
2888
+ function renderSignals(response) {
2889
+ const payload = obj(response);
2890
+ if (!payload) return void 0;
2891
+ const state = { bounded: false };
2892
+ const sections = [];
2893
+ for (const [key, value] of Object.entries(payload)) {
2894
+ if (!Array.isArray(value) || value.length === 0) continue;
2895
+ const items = value.map((raw) => obj(raw)).filter((item) => Boolean(item)).map((item) => {
2896
+ const fromLabel = str(item.from_label);
2897
+ const toLabel = str(item.to_label);
2898
+ const anyLabelKey = Object.keys(item).find(
2899
+ (k) => k.endsWith("_label") && str(item[k])
2900
+ );
2901
+ 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)";
2902
+ const uid = str(item.uid) ?? str(item.target_uid);
2903
+ const numbers = Object.entries(item).filter(([, v]) => typeof v === "number").slice(0, 4).map(([k, v]) => `${k} ${Math.round(v * 100) / 100}`);
2904
+ const lists = Object.entries(item).filter(([, v]) => Array.isArray(v) && v.length > 0).slice(0, 2).map(([k, v]) => `${k}: ${v.length}`);
2905
+ const meta = [...numbers, ...lists].join(", ");
2906
+ return `- ${clip(label, 160, state)}${uid && uid !== label ? ` [${uid}]` : ""}${meta ? ` (${meta})` : ""}`;
2907
+ });
2908
+ if (items.length > 0) {
2909
+ sections.push({ heading: `## ${key.replace(/_/g, " ")}`, items });
2910
+ }
2911
+ }
2912
+ if (sections.length === 0) return void 0;
2913
+ return assemble("# Synthesis signals", sections, state);
2914
+ }
2915
+ var LABEL_MAX, SUMMARY_MAX, QUOTE_MAX, ARTICLE_MAX, CHUNK_MAX, RELATIONSHIP_MAX, RENDER_CHAR_BUDGET, CURATION_EDGE_TYPES, INFRA_NODE_TYPES, JOBS_RENDER_MAX;
2755
2916
  var init_render = __esm({
2756
2917
  "src/render.ts"() {
2757
2918
  "use strict";
@@ -2764,6 +2925,7 @@ var init_render = __esm({
2764
2925
  RENDER_CHAR_BUDGET = 24e3;
2765
2926
  CURATION_EDGE_TYPES = /* @__PURE__ */ new Set(["POSSIBLE_DUPLICATE", "PossibleDuplicate"]);
2766
2927
  INFRA_NODE_TYPES = /* @__PURE__ */ new Set(["Chunk", "Document", "Article"]);
2928
+ JOBS_RENDER_MAX = 20;
2767
2929
  }
2768
2930
  });
2769
2931
 
@@ -2776,9 +2938,14 @@ function toolsForProfile(profile = process.env.MINDGRAPH_PROFILE || "general") {
2776
2938
  }
2777
2939
  function ok3(data) {
2778
2940
  return {
2779
- content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
2941
+ content: [{ type: "text", text: JSON.stringify(data) }]
2780
2942
  };
2781
2943
  }
2944
+ function renderedResult(format, raw, render) {
2945
+ if (format === "json") return ok3(raw);
2946
+ const text = render(raw);
2947
+ return text !== void 0 ? { content: [{ type: "text", text }] } : ok3(raw);
2948
+ }
2782
2949
  function err3(message) {
2783
2950
  return {
2784
2951
  content: [{ type: "text", text: JSON.stringify({ error: message }) }],
@@ -3390,15 +3557,11 @@ async function handleRetrieve(client2, args) {
3390
3557
  max_cost,
3391
3558
  agent_id
3392
3559
  } = args;
3393
- const rendered = (raw, render) => {
3394
- if (format === "json") return ok3(raw);
3395
- const text = render(raw);
3396
- return text !== void 0 ? { content: [{ type: "text", text }] } : ok3(raw);
3397
- };
3560
+ const rendered2 = (raw, render) => renderedResult(format, raw, render);
3398
3561
  switch (action) {
3399
3562
  case "context":
3400
3563
  if (!query) return err3("query is required for context retrieval");
3401
- return rendered(
3564
+ return rendered2(
3402
3565
  await client2.retrieveContext({
3403
3566
  query,
3404
3567
  node_limit: limit,
@@ -3423,7 +3586,7 @@ async function handleRetrieve(client2, args) {
3423
3586
  );
3424
3587
  case "text":
3425
3588
  if (!query) return err3("query is required for text search");
3426
- return rendered(
3589
+ return rendered2(
3427
3590
  await client2.retrieve({
3428
3591
  action: "text",
3429
3592
  query,
@@ -3437,7 +3600,7 @@ async function handleRetrieve(client2, args) {
3437
3600
  );
3438
3601
  case "semantic":
3439
3602
  if (!query) return err3("query is required for semantic search");
3440
- return rendered(
3603
+ return rendered2(
3441
3604
  await client2.retrieve({
3442
3605
  action: "semantic",
3443
3606
  query,
@@ -3451,7 +3614,7 @@ async function handleRetrieve(client2, args) {
3451
3614
  );
3452
3615
  case "hybrid":
3453
3616
  if (!query) return err3("query is required for hybrid search");
3454
- return rendered(
3617
+ return rendered2(
3455
3618
  await client2.retrieve({
3456
3619
  action: "hybrid",
3457
3620
  query,
@@ -3473,7 +3636,7 @@ async function handleRetrieve(client2, args) {
3473
3636
  case "weak_claims":
3474
3637
  case "pending_approvals":
3475
3638
  case "unresolved_contradictions":
3476
- return rendered(
3639
+ return rendered2(
3477
3640
  await client2.retrieve({
3478
3641
  action,
3479
3642
  limit,
@@ -3483,7 +3646,7 @@ async function handleRetrieve(client2, args) {
3483
3646
  (raw) => renderNodeList(raw, action.replace(/_/g, " "), limit)
3484
3647
  );
3485
3648
  case "stale_derivations":
3486
- return rendered(
3649
+ return rendered2(
3487
3650
  await client2.retrieve({
3488
3651
  action: "stale_derivations",
3489
3652
  limit,
@@ -3492,7 +3655,7 @@ async function handleRetrieve(client2, args) {
3492
3655
  (raw) => renderNodeList(raw, "stale derivations", limit)
3493
3656
  );
3494
3657
  case "preferences":
3495
- return rendered(
3658
+ return rendered2(
3496
3659
  await client2.retrieve({
3497
3660
  action: "preferences",
3498
3661
  ...query ? { query, k: limit } : {},
@@ -3503,7 +3666,7 @@ async function handleRetrieve(client2, args) {
3503
3666
  );
3504
3667
  case "layer":
3505
3668
  if (!layer) return err3("layer is required for layer retrieval");
3506
- return rendered(
3669
+ return rendered2(
3507
3670
  await client2.retrieve({
3508
3671
  action: "layer",
3509
3672
  layer,
@@ -3514,7 +3677,7 @@ async function handleRetrieve(client2, args) {
3514
3677
  (raw) => renderNodeList(raw, `Layer: ${layer}`, limit)
3515
3678
  );
3516
3679
  case "recent":
3517
- return rendered(
3680
+ return rendered2(
3518
3681
  await client2.retrieve({
3519
3682
  action: "recent",
3520
3683
  limit,
@@ -3529,7 +3692,7 @@ async function handleRetrieve(client2, args) {
3529
3692
  );
3530
3693
  // Document inventory
3531
3694
  case "document_index":
3532
- return rendered(
3695
+ return rendered2(
3533
3696
  await client2.getNodes({
3534
3697
  node_type: "Document",
3535
3698
  limit: limit ?? 100
@@ -3539,7 +3702,7 @@ async function handleRetrieve(client2, args) {
3539
3702
  // Graph traversal
3540
3703
  case "chain":
3541
3704
  if (!start_uid) return err3("start_uid is required for chain traversal");
3542
- return rendered(
3705
+ return rendered2(
3543
3706
  await client2.traverse({
3544
3707
  action: "chain",
3545
3708
  start_uid,
@@ -3552,7 +3715,7 @@ async function handleRetrieve(client2, args) {
3552
3715
  );
3553
3716
  case "neighborhood":
3554
3717
  if (!start_uid) return err3("start_uid is required for neighborhood traversal");
3555
- return rendered(
3718
+ return rendered2(
3556
3719
  await client2.traverse({
3557
3720
  action: "neighborhood",
3558
3721
  start_uid,
@@ -3568,7 +3731,7 @@ async function handleRetrieve(client2, args) {
3568
3731
  case "path":
3569
3732
  if (!start_uid) return err3("start_uid is required for path traversal");
3570
3733
  if (!end_uid) return err3("end_uid is required for path traversal");
3571
- return rendered(
3734
+ return rendered2(
3572
3735
  await client2.traverse({
3573
3736
  action: "path",
3574
3737
  start_uid,
@@ -3584,7 +3747,7 @@ async function handleRetrieve(client2, args) {
3584
3747
  );
3585
3748
  case "subgraph":
3586
3749
  if (!start_uid) return err3("start_uid is required for subgraph traversal");
3587
- return rendered(
3750
+ return rendered2(
3588
3751
  await client2.traverse({
3589
3752
  action: "subgraph",
3590
3753
  start_uid,
@@ -3600,7 +3763,7 @@ async function handleRetrieve(client2, args) {
3600
3763
  case "top_k_paths":
3601
3764
  if (!start_uid) return err3("start_uid is required for top_k_paths");
3602
3765
  if (!end_uid) return err3("end_uid is required for top_k_paths");
3603
- return rendered(
3766
+ return rendered2(
3604
3767
  await client2.traverse({
3605
3768
  action: "top_k_paths",
3606
3769
  start_uid,
@@ -3637,6 +3800,7 @@ async function handleIngest(client2, args) {
3637
3800
  chunk_size,
3638
3801
  chunk_overlap,
3639
3802
  job_id,
3803
+ format,
3640
3804
  agent_id
3641
3805
  } = args;
3642
3806
  const src = source_uri ?? source;
@@ -3706,19 +3870,21 @@ async function handleIngest(client2, args) {
3706
3870
  if (job_id) {
3707
3871
  return ok3(await client2.getJob(job_id));
3708
3872
  }
3709
- return ok3(await client2.listJobs());
3873
+ return renderedResult(format, await client2.listJobs(), renderJobs);
3710
3874
  default:
3711
3875
  return err3(`Unknown ingest action: ${action}`);
3712
3876
  }
3713
3877
  }
3714
3878
  async function handleSynthesize(client2, args) {
3715
- const { action, project_uid, signals, target_types, job_id } = args;
3879
+ const { action, project_uid, signals, target_types, job_id, format } = args;
3716
3880
  switch (action) {
3717
3881
  case "signals":
3718
3882
  if (!project_uid)
3719
3883
  return err3("project_uid is required for action='signals'");
3720
- return ok3(
3721
- await client2.signals(project_uid, { signals, target_types })
3884
+ return renderedResult(
3885
+ format,
3886
+ await client2.signals(project_uid, { signals, target_types }),
3887
+ renderSignals
3722
3888
  );
3723
3889
  case "run":
3724
3890
  if (!project_uid)
@@ -3752,6 +3918,7 @@ async function handleOntology(client2, args) {
3752
3918
  relation_type,
3753
3919
  fields,
3754
3920
  source_uids,
3921
+ format,
3755
3922
  agent_id
3756
3923
  } = args;
3757
3924
  switch (action) {
@@ -3767,7 +3934,8 @@ async function handleOntology(client2, args) {
3767
3934
  "schema_id is required for action='query' (use action='schemas' to find the active schema)"
3768
3935
  );
3769
3936
  }
3770
- return ok3(
3937
+ return renderedResult(
3938
+ format,
3771
3939
  await client2.queryOntology({
3772
3940
  query,
3773
3941
  schema_id,
@@ -3776,29 +3944,42 @@ async function handleOntology(client2, args) {
3776
3944
  include_sources: include_sources ?? true,
3777
3945
  depth,
3778
3946
  limit
3779
- })
3947
+ }),
3948
+ renderOntologyAnswer
3780
3949
  );
3781
3950
  }
3782
3951
  case "search":
3783
3952
  if (!query) return err3("query is required for action='search'");
3784
- return ok3(
3953
+ return renderedResult(
3954
+ format,
3785
3955
  await client2.searchDomainObjects(query, {
3786
3956
  schema_id,
3787
3957
  object_types,
3788
3958
  limit
3789
- })
3959
+ }),
3960
+ (raw) => renderObjectList(raw, `Domain search: ${query}`)
3790
3961
  );
3791
3962
  case "objects":
3792
3963
  if (!schema_id) return err3("schema_id is required for action='objects'");
3793
- return ok3(
3794
- await client2.listDomainObjects({ schema_id, object_type, limit })
3964
+ return renderedResult(
3965
+ format,
3966
+ await client2.listDomainObjects({ schema_id, object_type, limit }),
3967
+ (raw) => renderObjectList(raw, `Domain objects${object_type ? `: ${object_type}` : ""}`)
3795
3968
  );
3796
3969
  case "object":
3797
3970
  if (!uid) return err3("uid is required for action='object'");
3798
- return ok3(await client2.getDomainObject(uid));
3971
+ return renderedResult(
3972
+ format,
3973
+ await client2.getDomainObject(uid),
3974
+ (raw) => renderNodeList([raw], "Domain object")
3975
+ );
3799
3976
  case "object_context":
3800
3977
  if (!uid) return err3("uid is required for action='object_context'");
3801
- return ok3(await client2.getDomainObjectContext(uid, depth));
3978
+ return renderedResult(
3979
+ format,
3980
+ await client2.getDomainObjectContext(uid, depth),
3981
+ renderOntologyAnswer
3982
+ );
3802
3983
  case "proposals":
3803
3984
  return ok3(
3804
3985
  await client2.listOntologyProposals({
@@ -4665,6 +4846,11 @@ var init_tools = __esm({
4665
4846
  type: "string",
4666
4847
  description: "Job ID to check status (for job_status action)"
4667
4848
  },
4849
+ format: {
4850
+ type: "string",
4851
+ enum: ["text", "json"],
4852
+ description: "job_status without job_id: 'text' (default) renders the 20 most recent jobs; 'json' returns the full raw list."
4853
+ },
4668
4854
  agent_id: {
4669
4855
  type: "string",
4670
4856
  description: "Agent identity"
@@ -4700,6 +4886,11 @@ var init_tools = __esm({
4700
4886
  type: "string",
4701
4887
  description: "Job ID to poll (for action='job_status')"
4702
4888
  },
4889
+ format: {
4890
+ type: "string",
4891
+ enum: ["text", "json"],
4892
+ description: "signals action: 'text' (default) renders signal sections; 'json' returns the raw payload."
4893
+ },
4703
4894
  agent_id: {
4704
4895
  type: "string",
4705
4896
  description: "Agent identity"
@@ -4808,6 +4999,11 @@ var init_tools = __esm({
4808
4999
  items: { type: "string" },
4809
5000
  description: "Chunk/document UIDs to extract from (for action=extract)"
4810
5001
  },
5002
+ format: {
5003
+ type: "string",
5004
+ enum: ["text", "json"],
5005
+ 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."
5006
+ },
4811
5007
  agent_id: {
4812
5008
  type: "string",
4813
5009
  description: "Agent identity"
@@ -4870,10 +5066,21 @@ async function getGeneratedTools(client2) {
4870
5066
  );
4871
5067
  }
4872
5068
  byName.set(d.name, d);
5069
+ const inputSchema = d.maps_to === "structured_query" ? d.input_schema : {
5070
+ ...d.input_schema,
5071
+ properties: {
5072
+ ...d.input_schema.properties,
5073
+ format: {
5074
+ type: "string",
5075
+ enum: ["text", "json"],
5076
+ description: "Output format (default 'text': compact rendered block). Pass 'json' for the raw server response."
5077
+ }
5078
+ }
5079
+ };
4873
5080
  tools.push({
4874
5081
  name: d.name,
4875
5082
  description: d.description,
4876
- inputSchema: d.input_schema
5083
+ inputSchema
4877
5084
  });
4878
5085
  }
4879
5086
  cache = { tools, byName, fetchedAt: Date.now() };
@@ -4894,31 +5101,41 @@ async function handleGeneratedTool(client2, desc, args) {
4894
5101
  if (!query) return err4(`query is required for ${desc.name}`);
4895
5102
  const limit = typeof args.limit === "number" ? args.limit : void 0;
4896
5103
  const filters = Array.isArray(args.filters) ? args.filters : void 0;
4897
- return ok4(
5104
+ return rendered(
5105
+ args.format,
4898
5106
  await ontologyClient.searchDomainObjects(query, {
4899
5107
  schema_id: desc.schema_id,
4900
5108
  object_types: [desc.object_type],
4901
5109
  filters,
4902
5110
  limit
4903
- })
5111
+ }),
5112
+ (raw) => renderObjectList(raw, `${desc.object_type} search: ${query}`)
4904
5113
  );
4905
5114
  }
4906
5115
  case "object": {
4907
5116
  const uid = args.uid;
4908
5117
  if (!uid) return err4(`uid is required for ${desc.name}`);
4909
- return ok4(await ontologyClient.getDomainObject(uid, {
4910
- schema_id: desc.schema_id,
4911
- object_type: desc.object_type
4912
- }));
5118
+ return rendered(
5119
+ args.format,
5120
+ await ontologyClient.getDomainObject(uid, {
5121
+ schema_id: desc.schema_id,
5122
+ object_type: desc.object_type
5123
+ }),
5124
+ (raw) => renderNodeList([raw], desc.object_type)
5125
+ );
4913
5126
  }
4914
5127
  case "object_context": {
4915
5128
  const uid = args.uid;
4916
5129
  if (!uid) return err4(`uid is required for ${desc.name}`);
4917
5130
  const depth = typeof args.depth === "number" ? args.depth : void 0;
4918
- return ok4(await ontologyClient.getDomainObjectContext(uid, depth, {
4919
- schema_id: desc.schema_id,
4920
- object_type: desc.object_type
4921
- }));
5131
+ return rendered(
5132
+ args.format,
5133
+ await ontologyClient.getDomainObjectContext(uid, depth, {
5134
+ schema_id: desc.schema_id,
5135
+ object_type: desc.object_type
5136
+ }),
5137
+ renderOntologyAnswer
5138
+ );
4922
5139
  }
4923
5140
  case "related": {
4924
5141
  const uid = args.uid;
@@ -4931,18 +5148,22 @@ async function handleGeneratedTool(client2, desc, args) {
4931
5148
  "related ontology tools require a graph-aware version of the mindgraph SDK"
4932
5149
  );
4933
5150
  }
4934
- return ok4(await ontologyClient.queryRelatedDomainObjects({
4935
- schema_id: desc.schema_id,
4936
- entry_type: desc.object_type,
4937
- uid,
4938
- relation: desc.relation,
4939
- entry_role: desc.entry_role,
4940
- far_type: desc.far_type,
4941
- where: Array.isArray(args.where) ? args.where : void 0,
4942
- include_provenance: args.include_provenance === true,
4943
- limit: typeof args.limit === "number" ? args.limit : void 0,
4944
- offset: typeof args.offset === "number" ? args.offset : void 0
4945
- }));
5151
+ return rendered(
5152
+ args.format,
5153
+ await ontologyClient.queryRelatedDomainObjects({
5154
+ schema_id: desc.schema_id,
5155
+ entry_type: desc.object_type,
5156
+ uid,
5157
+ relation: desc.relation,
5158
+ entry_role: desc.entry_role,
5159
+ far_type: desc.far_type,
5160
+ where: Array.isArray(args.where) ? args.where : void 0,
5161
+ include_provenance: args.include_provenance === true,
5162
+ limit: typeof args.limit === "number" ? args.limit : void 0,
5163
+ offset: typeof args.offset === "number" ? args.offset : void 0
5164
+ }),
5165
+ (raw) => renderObjectList(raw, `${desc.far_type} related via ${desc.relation}`)
5166
+ );
4946
5167
  }
4947
5168
  case "structured_query": {
4948
5169
  const select = args.select;
@@ -4968,13 +5189,20 @@ async function handleGeneratedTool(client2, desc, args) {
4968
5189
  return err4(e instanceof Error ? e.message : String(e));
4969
5190
  }
4970
5191
  }
4971
- var ok4, err4, CACHE_TTL_MS, FAILURE_COOLDOWN_MS, cache, retryNotBefore, EMPTY, DuplicateGeneratedToolError, STRUCTURED_QUERY_PASSTHROUGH;
5192
+ var ok4, rendered, err4, CACHE_TTL_MS, FAILURE_COOLDOWN_MS, cache, retryNotBefore, EMPTY, DuplicateGeneratedToolError, STRUCTURED_QUERY_PASSTHROUGH;
4972
5193
  var init_generated_tools = __esm({
4973
5194
  "src/generated-tools.ts"() {
4974
5195
  "use strict";
5196
+ init_render();
4975
5197
  ok4 = (data) => ({
4976
- content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
5198
+ // Compact on purpose — pretty-printing doubled the token cost.
5199
+ content: [{ type: "text", text: JSON.stringify(data) }]
4977
5200
  });
5201
+ rendered = (format, raw, render) => {
5202
+ if (format === "json") return ok4(raw);
5203
+ const text = render(raw);
5204
+ return text !== void 0 ? { content: [{ type: "text", text }] } : ok4(raw);
5205
+ };
4978
5206
  err4 = (message) => ({
4979
5207
  content: [{ type: "text", text: JSON.stringify({ error: message }) }],
4980
5208
  isError: true
@@ -5245,7 +5473,7 @@ var init_governance = __esm({
5245
5473
  // src/resources.ts
5246
5474
  function json(uri, data) {
5247
5475
  return {
5248
- contents: [{ uri, mimeType: "application/json", text: JSON.stringify(data, null, 2) }]
5476
+ contents: [{ uri, mimeType: "application/json", text: JSON.stringify(data) }]
5249
5477
  };
5250
5478
  }
5251
5479
  async function readResource(client2, uri) {
@@ -5359,7 +5587,7 @@ async function main() {
5359
5587
  const transport = new import_stdio.StdioServerTransport();
5360
5588
  await server.connect(transport);
5361
5589
  console.error(
5362
- `MindGraph MCP server v${"0.16.0"} running on stdio (${BASE_URL})`
5590
+ `MindGraph MCP server v${"0.17.0"} running on stdio (${BASE_URL})`
5363
5591
  );
5364
5592
  }
5365
5593
  var import_server, import_stdio, import_types, API_KEY, BASE_URL, AGENT_ID, ORG_ID, PROFILE, HARNESS, client, INSTRUCTIONS, server, GOVERNANCE_CONFIG, PROMPTS;
@@ -5499,7 +5727,7 @@ Capture knowledge when the user shares something worth remembering:
5499
5727
  server = new import_server.Server(
5500
5728
  {
5501
5729
  name: "mindgraph",
5502
- version: "0.16.0"
5730
+ version: "0.17.0"
5503
5731
  },
5504
5732
  {
5505
5733
  capabilities: {
@@ -6064,8 +6292,8 @@ ${knowledgeLines.join("\n")}`);
6064
6292
  );
6065
6293
  }
6066
6294
  if (footer) lines.push(footer);
6067
- const rendered = lines.join("\n");
6068
- return rendered.length <= BRIEF_CHAR_BUDGET ? rendered : `${rendered.slice(0, BRIEF_CHAR_BUDGET - 40)}
6295
+ const rendered2 = lines.join("\n");
6296
+ return rendered2.length <= BRIEF_CHAR_BUDGET ? rendered2 : `${rendered2.slice(0, BRIEF_CHAR_BUDGET - 40)}
6069
6297
  \u2026[bounded work brief truncated]`;
6070
6298
  }
6071
6299
  async function repositoryScopeUids(input, client2, options, agentId) {