81 lines
2.5 KiB
TypeScript
81 lines
2.5 KiB
TypeScript
/**
|
|
* 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<FlowsDoc>(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<FlowsDoc>(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),
|
|
}],
|
|
};
|
|
},
|
|
);
|
|
}
|