82 lines
2.8 KiB
TypeScript
82 lines
2.8 KiB
TypeScript
/**
|
|
* MCP tools for rGov (modular governance decision circuits).
|
|
* rGov shapes live in the space's main canvas document, not a separate Automerge doc.
|
|
*
|
|
* Tools: rgov_list_circuits, rgov_get_circuit
|
|
*/
|
|
|
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
import { z } from "zod";
|
|
import { getDocumentData } from "../community-store";
|
|
import { resolveAccess, accessDeniedResponse } from "./_auth";
|
|
|
|
const GOV_TYPES = [
|
|
"folk-gov-binary", "folk-gov-threshold", "folk-gov-knob",
|
|
"folk-gov-project", "folk-gov-amendment",
|
|
"folk-gov-quadratic", "folk-gov-conviction", "folk-gov-multisig",
|
|
"folk-gov-sankey",
|
|
];
|
|
|
|
export function registerGovTools(server: McpServer) {
|
|
server.tool(
|
|
"rgov_list_circuits",
|
|
"List governance circuit shapes on the space canvas",
|
|
{
|
|
space: z.string().describe("Space slug"),
|
|
token: z.string().optional().describe("JWT auth token"),
|
|
type: z.string().optional().describe("Filter by gov shape type (e.g. folk-gov-project, folk-gov-threshold)"),
|
|
},
|
|
async ({ space, token, type }) => {
|
|
const access = await resolveAccess(token, space, false);
|
|
if (!access.allowed) return accessDeniedResponse(access.reason!);
|
|
|
|
const docData = getDocumentData(space);
|
|
if (!docData?.shapes) return { content: [{ type: "text" as const, text: JSON.stringify({ shapes: [] }) }] };
|
|
|
|
let govShapes = Object.values(docData.shapes)
|
|
.filter((s: any) => !s.forgotten && GOV_TYPES.includes(s.type));
|
|
|
|
if (type) govShapes = govShapes.filter((s: any) => s.type === type);
|
|
|
|
const summary = govShapes.map((s: any) => ({
|
|
id: s.id, type: s.type, title: s.title,
|
|
status: s.status, x: s.x, y: s.y,
|
|
}));
|
|
|
|
return { content: [{ type: "text" as const, text: JSON.stringify(summary, null, 2) }] };
|
|
},
|
|
);
|
|
|
|
server.tool(
|
|
"rgov_get_circuit",
|
|
"Get full details of a governance shape by ID",
|
|
{
|
|
space: z.string().describe("Space slug"),
|
|
token: z.string().optional().describe("JWT auth token"),
|
|
shape_id: z.string().describe("Shape ID"),
|
|
},
|
|
async ({ space, token, shape_id }) => {
|
|
const access = await resolveAccess(token, space, false);
|
|
if (!access.allowed) return accessDeniedResponse(access.reason!);
|
|
|
|
const docData = getDocumentData(space);
|
|
const shape = docData?.shapes?.[shape_id] as any;
|
|
if (!shape || !GOV_TYPES.includes(shape.type)) {
|
|
return { content: [{ type: "text" as const, text: JSON.stringify({ error: "Gov shape not found" }) }] };
|
|
}
|
|
|
|
// Find arrows connected to this shape
|
|
const arrows = Object.values(docData!.shapes)
|
|
.filter((s: any) => s.type === "folk-arrow" && (s.sourceId === shape_id || s.targetId === shape_id))
|
|
.map((a: any) => ({ id: a.id, sourceId: a.sourceId, targetId: a.targetId }));
|
|
|
|
return {
|
|
content: [{
|
|
type: "text" as const,
|
|
text: JSON.stringify({ shape, connectedArrows: arrows }, null, 2),
|
|
}],
|
|
};
|
|
},
|
|
);
|
|
}
|