// progression-pipeline-list — every active sale-agreed deal with a stall flag. // The across-pipeline read the morning round and chase-progression open with. // Read-only. import { z } from "zod"; import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { lifelineTool } from "../../../../../../../platform/lib/mcp-lifeline/dist/index.js"; import { getSession } from "../lib/neo4j.js"; import { listPipeline, DEFAULT_STALLED_THRESHOLD_DAYS } from "../lib/chain-graph.js"; export function registerPipelineList(server: McpServer, accountId: string): void { lifelineTool( server, "progression-pipeline-list", "List every active sale-agreed deal with days since the last milestone movement and a stall flag. Use to open the morning round or chase-progression across the whole pipeline. Read-only.", { stalledThresholdDays: z .number() .int() .positive() .optional() .describe(`Days with no movement before a deal is flagged stalled (default ${DEFAULT_STALLED_THRESHOLD_DAYS}).`), }, async (params: Record) => { const { stalledThresholdDays } = params as { stalledThresholdDays?: number }; const session = getSession(); try { const rows = await listPipeline( session, accountId, Date.now(), stalledThresholdDays ?? DEFAULT_STALLED_THRESHOLD_DAYS, ); const stalled = rows.filter((r) => r.stalled).length; console.error(`[progression] op=pipeline-list active=${rows.length} stalled=${stalled}`); return { content: [ { type: "text" as const, text: JSON.stringify({ ok: true, active: rows.length, stalled, rows }, null, 2) }, ], }; } catch (err) { const msg = err instanceof Error ? err.message : String(err); return { content: [{ type: "text" as const, text: `Error: ${msg}` }], isError: true }; } finally { await session.close(); } }, ); }