feat(ST-707): log tools — implementation, test_result, commit

Three write tools that append StoryLog entries:
- log_implementation: type=IMPLEMENTATION_PLAN
- log_test_result: type=TEST_RESULT, status PASSED|FAILED
- log_commit: type=COMMIT with hash and message

All accept optional metadata in input but skip writing it for now —
the StoryLog.metadata JSONB column lands with Scrum4Me PR #2.
After that PR merges, run sync-schema and add `metadata` to each
prisma.create's data field.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Janpeter Visser 2026-04-26 23:06:50 +02:00
parent e3f9476568
commit c39b337fcc
4 changed files with 138 additions and 1 deletions

View file

@ -0,0 +1,43 @@
import { z } from 'zod'
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
import { prisma } from '../prisma.js'
import { requireWriteAccess } from '../auth.js'
import { userCanAccessStory } from '../access.js'
import { toolError, toolJson, withToolErrors } from '../errors.js'
// metadata is accepted on input but not yet written — schema sync after
// Scrum4Me PR #2 lands adds the StoryLog.metadata JSONB column.
const inputSchema = z.object({
story_id: z.string().min(1),
content: z.string().min(1),
metadata: z.record(z.string(), z.unknown()).optional(),
})
export function registerLogImplementationTool(server: McpServer) {
server.registerTool(
'log_implementation',
{
title: 'Log implementation plan',
description:
'Append an IMPLEMENTATION_PLAN entry to a story log. ' +
'Forbidden for demo accounts.',
inputSchema,
},
async ({ story_id, content }) =>
withToolErrors(async () => {
const auth = await requireWriteAccess()
if (!(await userCanAccessStory(story_id, auth.userId))) {
return toolError(`Story ${story_id} not found or not accessible`)
}
const log = await prisma.storyLog.create({
data: {
story_id,
type: 'IMPLEMENTATION_PLAN',
content,
},
select: { id: true, created_at: true },
})
return toolJson({ id: log.id, created_at: log.created_at })
}),
)
}