@neat.is/mcp 0.9.8-dev.20260828 → 0.9.8

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.cjs CHANGED
@@ -742,6 +742,60 @@ async function getIncidentHistory(client2, input) {
742
742
  });
743
743
  }, `Node ${input.nodeId} not found in the graph.`);
744
744
  }
745
+ async function getIncidentCard(client2, input) {
746
+ return withMissingNodeFallback(
747
+ client2,
748
+ input.project,
749
+ async () => {
750
+ const qs = input.errorId ? `?errorId=${encodeURIComponent(input.errorId)}` : "";
751
+ const card = await client2.get(
752
+ projectPath(input.project, `/graph/incident-card/${encodeURIComponent(input.nodeId)}${qs}`)
753
+ );
754
+ const lines = [];
755
+ lines.push(` incident ${card.id} [${card.incidentKind}] at ${card.at}`);
756
+ lines.push(` ${card.message}`);
757
+ if (card.locus) {
758
+ const l = card.locus;
759
+ lines.push(
760
+ ` locus: ${l.symbol ? `${l.symbol} ` : ""}${l.file}${l.lineStart ? `:${l.lineStart}` : ""} [${l.provenance}]`
761
+ );
762
+ } else {
763
+ lines.push(" locus: none recovered \u2014 service grain");
764
+ }
765
+ if (card.rootCause) {
766
+ const rc = card.rootCause;
767
+ lines.push(
768
+ ` root cause: ${rc.node}${rc.classification ? ` (${rc.classification})` : ""} \u2014 ${rc.reason} [confidence ${rc.confidence.toFixed(2)}]`
769
+ );
770
+ lines.push(` chain: ${rc.chain.map((h) => `${h.node} [${h.provenance}]`).join(" \u2192 ")}`);
771
+ if (rc.fix) lines.push(` fix: ${rc.fix}`);
772
+ } else {
773
+ lines.push(" root cause: none reachable");
774
+ }
775
+ if (card.blastRadius) {
776
+ lines.push(
777
+ ` blast radius: ${card.blastRadius.totalAffected} node(s); nearest ${card.blastRadius.nearest.map((n) => n.node).join(", ")}`
778
+ );
779
+ }
780
+ if (card.policies && card.policies.length > 0) {
781
+ lines.push(
782
+ ` policies: ${card.policies.map((p) => `[${p.severity}] ${p.policyName}`).join("; ")}`
783
+ );
784
+ }
785
+ if (card.divergence && card.divergence.length > 0) {
786
+ lines.push(
787
+ ` divergence: ${card.divergence.map((d) => `${d.type} (${d.summary})`).join("; ")}`
788
+ );
789
+ }
790
+ return formatToolResponse({
791
+ summary: card.headline,
792
+ block: lines.join("\n"),
793
+ provenance: import_types.Provenance.OBSERVED
794
+ });
795
+ },
796
+ `No incident card available for ${input.nodeId}.`
797
+ );
798
+ }
745
799
  async function semanticSearch(client2, input) {
746
800
  try {
747
801
  const result = await client2.get(
@@ -1298,6 +1352,16 @@ registerTool(
1298
1352
  },
1299
1353
  async (input) => getIncidentHistory(client, { ...input, project: projectFor(input) })
1300
1354
  );
1355
+ registerTool(
1356
+ "get_incident_card",
1357
+ "One self-sufficient work order for an incident on a node (ADR-221): the incident fused with its root-cause chain, blast radius, governing policies, and node divergence \u2014 each claim provenance-stamped, so you can act without grepping. Give a node id (a service, file, or symbol); omit errorId for the node's most-recent incident, or pass errorId to pin one.",
1358
+ {
1359
+ nodeId: import_zod.z.string().describe("Graph node id the incident is on (service/file/symbol)"),
1360
+ errorId: import_zod.z.string().optional().describe("Pin a specific incident by its id; omit for the most recent"),
1361
+ project: projectField
1362
+ },
1363
+ async (input) => getIncidentCard(client, { ...input, project: projectFor(input) })
1364
+ );
1301
1365
  registerTool(
1302
1366
  "semantic_search",
1303
1367
  "Search nodes by natural-language query. Uses embedding vectors when an embedder is available (Ollama nomic-embed-text \u2192 in-process MiniLM \u2192 substring fallback) \u2014 phrase the query the way you would describe what you want.",