Submatter/apps/mcp-server/src/tools/create-brief.ts

77 lines
2.3 KiB
TypeScript
Raw Normal View History

import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import { briefObjectContentSchema } from "@tasks/shared/convoy-lifecycle";
import { db } from "../db.js";
import { objects } from "../schema.js";
import { loadConvoyProject } from "../lib/convoy-objects.js";
import { resolveWorkspaceHandle } from "../lib/resolve-workspace.js";
import { toolCatch, toolErr, toolOk } from "./tool-result.js";
const createBriefInputSchema = z.object({
workspace: z.string().min(1),
convoyId: z.string().uuid(),
briefNumber: z.number().int().positive(),
title: z.string().min(1).max(500),
files: z.array(z.string()).default([]),
sliceDependencies: z.array(z.number().int().positive()).default([]),
acceptance: z.string().optional(),
bodyMarkdown: z.string().optional(),
});
export function registerCreateBriefTool(mcp: McpServer): void {
mcp.registerTool(
"create_brief",
{
description:
"Create an implementer brief as a task object child of a convoy project.",
inputSchema: createBriefInputSchema,
},
async (args) => {
try {
const input = createBriefInputSchema.parse(args);
const ws = await resolveWorkspaceHandle(input.workspace);
const convoy = await loadConvoyProject(input.convoyId, ws.id);
if (!convoy) {
return toolErr(`Convoy ${input.convoyId} not found in workspace ${ws.slug}`);
}
const content = briefObjectContentSchema.parse({
briefNumber: input.briefNumber,
files: input.files,
sliceDependencies: input.sliceDependencies,
acceptance: input.acceptance,
});
const [created] = await db
.insert(objects)
.values({
type: "task",
title: input.title,
parentId: convoy.id,
workspaceId: ws.id,
description: input.bodyMarkdown ?? input.acceptance ?? null,
status: "ready",
content,
sortOrder: input.briefNumber,
})
.returning();
if (!created) {
return toolErr("Failed to create brief");
}
return toolOk({
workspace: { id: ws.id, slug: ws.slug, name: ws.name },
convoyId: convoy.id,
brief: created,
});
} catch (e) {
return toolCatch(e);
}
},
);
}