/** * MCP tools for rFlows (financial modeling & budget allocation). * * Tools: rflows_list_flows, rflows_get_budget */ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { z } from "zod"; import type { SyncServer } from "../local-first/sync-server"; import { flowsDocId } from "../../modules/rflows/schemas"; import type { FlowsDoc } from "../../modules/rflows/schemas"; import { resolveAccess, accessDeniedResponse } from "./_auth"; export function registerFlowsTools(server: McpServer, syncServer: SyncServer) { server.tool( "rflows_list_flows", "List canvas flows (financial models) in a space", { space: z.string().describe("Space slug"), token: z.string().optional().describe("JWT auth token"), }, async ({ space, token }) => { const access = await resolveAccess(token, space, false); if (!access.allowed) return accessDeniedResponse(access.reason!); const doc = syncServer.getDoc(flowsDocId(space)); if (!doc) return { content: [{ type: "text", text: JSON.stringify({ error: "No flows data found" }) }] }; const flows = Object.values(doc.canvasFlows || {}).map(f => ({ id: f.id, name: f.name, nodeCount: f.nodes?.length ?? 0, createdBy: f.createdBy, createdAt: f.createdAt, updatedAt: f.updatedAt, })); const mortgageCount = Object.keys(doc.mortgagePositions || {}).length; const reinvestmentCount = Object.keys(doc.reinvestmentPositions || {}).length; return { content: [{ type: "text", text: JSON.stringify({ flows, activeFlowId: doc.activeFlowId, mortgagePositionCount: mortgageCount, reinvestmentPositionCount: reinvestmentCount, budgetTotalAmount: doc.budgetTotalAmount, }, null, 2), }], }; }, ); server.tool( "rflows_get_budget", "Get budget segments and participant allocations", { space: z.string().describe("Space slug"), token: z.string().optional().describe("JWT auth token"), }, async ({ space, token }) => { const access = await resolveAccess(token, space, false); if (!access.allowed) return accessDeniedResponse(access.reason!); const doc = syncServer.getDoc(flowsDocId(space)); if (!doc) return { content: [{ type: "text", text: JSON.stringify({ error: "No flows data found" }) }] }; return { content: [{ type: "text", text: JSON.stringify({ totalAmount: doc.budgetTotalAmount, segments: doc.budgetSegments, allocations: doc.budgetAllocations, }, null, 2), }], }; }, ); }