agent-ecosystem/mcp-server/src/tools/workSyncTools.ts

86 lines
3 KiB
TypeScript

import type { FastMCP } from 'fastmcp';
import { z } from 'zod';
import { getController } from '../controller';
import { jsonTextContent } from '../utils/format';
import { assertConfiguredTeam } from '../utils/teamConfig';
const controlContextSchema = {
teamName: z.string().min(1),
claudeDir: z.string().min(1).optional(),
controlUrl: z.string().optional(),
waitTimeoutMs: z.number().int().min(1000).max(600000).optional(),
};
const reportStateSchema = z.enum(['still_working', 'blocked', 'caught_up']);
export function registerWorkSyncTools(server: Pick<FastMCP, 'addTool'>) {
server.addTool({
name: 'member_work_sync_status',
description:
'Read your current actionable-work agenda and agendaFingerprint before reporting whether you are still working, blocked, or caught up.',
parameters: z.object({
...controlContextSchema,
memberName: z.string().min(1).optional(),
from: z.string().min(1).optional(),
}),
execute: async ({ teamName, claudeDir, controlUrl, waitTimeoutMs, memberName, from }) => {
assertConfiguredTeam(teamName, claudeDir);
return jsonTextContent(
await getController(teamName, claudeDir).workSync.memberWorkSyncStatus({
...(memberName ? { memberName } : {}),
...(from ? { from } : {}),
...(controlUrl ? { controlUrl } : {}),
...(waitTimeoutMs ? { waitTimeoutMs } : {}),
})
);
},
});
server.addTool({
name: 'member_work_sync_report',
description:
'Report your validated work-sync state for the current agendaFingerprint. This never completes tasks. Use still_working while actively continuing, blocked only when the board has blocker evidence, and caught_up only when the status agenda is empty.',
parameters: z.object({
...controlContextSchema,
memberName: z.string().min(1).optional(),
from: z.string().min(1).optional(),
state: reportStateSchema,
agendaFingerprint: z.string().min(1),
reportToken: z.string().min(1),
taskIds: z.array(z.string().min(1)).optional(),
note: z.string().optional(),
leaseTtlMs: z.number().int().min(60000).max(3600000).optional(),
}),
execute: async ({
teamName,
claudeDir,
controlUrl,
waitTimeoutMs,
memberName,
from,
state,
agendaFingerprint,
reportToken,
taskIds,
note,
leaseTtlMs,
}) => {
assertConfiguredTeam(teamName, claudeDir);
return jsonTextContent(
await getController(teamName, claudeDir).workSync.memberWorkSyncReport({
...(memberName ? { memberName } : {}),
...(from ? { from } : {}),
state,
agendaFingerprint,
reportToken,
...(taskIds ? { taskIds } : {}),
...(note ? { note } : {}),
...(leaseTtlMs ? { leaseTtlMs } : {}),
...(controlUrl ? { controlUrl } : {}),
...(waitTimeoutMs ? { waitTimeoutMs } : {}),
})
);
},
});
}