Adds the 4 new MCP-tools for the Scrum4Me M12 Idea-entity flow + extends
3 existing tools to handle the new ClaudeJobKind discriminator.
New tools:
- get_idea_context: full idea + product + open questions + recent logs
- update_idea_grill_md: save grill-result + status → GRILLED + IdeaLog
- update_idea_plan_md: server-side yaml parser validates frontmatter;
ok → PLAN_READY, fail → PLAN_FAILED + line-info errors
- log_idea_decision: DECISION/NOTE entries on the timeline
Extended tools:
- ask_user_question: xor schema (story_id | idea_id); idea-questions are
user-private with productId derived from idea.product_id
- wait_for_job: returns \`kind\` discriminator; IDEA_* payloads include
idea + prompt_text (from src/prompts/idea/) and skip worktree creation
- update_job_status: failed on IDEA_* auto-transitions idea-status to
GRILL_FAILED / PLAN_FAILED + IdeaLog{JOB_EVENT}; auto-PR + worktree-
cleanup skipped for idea-jobs
Other changes:
- Health version now read dynamically from package.json (was hardcoded
'0.1.0' which caused deploy-sync confusion)
- Schema synced to Scrum4Me M12 (Idea + IdeaLog + enums + ClaudeJob/
Question nullable-FKs + check-constraints + pg_notify-trigger update)
- New @scrum4me-mcp/lib/idea-plan-parser duplicates Scrum4Me's parser
(drift detected by vendor schema-watchdog)
- Embedded grill+make-plan prompts copied to src/prompts/idea/
- New userOwnsIdea access helper
Tests: 153/153 green; tsc + build clean.
Migration: requires Scrum4Me M12 migration (20260504172747_add_ideas_and_grill_jobs)
applied on the target DB. See vendor/scrum4me/docs/runbooks/mcp-integration.md
for the updated batch-loop with kind-switch.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
113 lines
5.2 KiB
JavaScript
113 lines
5.2 KiB
JavaScript
#!/usr/bin/env node
|
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
|
import { registerHealthTool } from './tools/health.js'
|
|
import { registerListProductsTool } from './tools/list-products.js'
|
|
import { registerGetClaudeContextTool } from './tools/get-claude-context.js'
|
|
import { registerUpdateTaskStatusTool } from './tools/update-task-status.js'
|
|
import { registerUpdateTaskPlanTool } from './tools/update-task-plan.js'
|
|
import { registerLogImplementationTool } from './tools/log-implementation.js'
|
|
import { registerLogTestResultTool } from './tools/log-test-result.js'
|
|
import { registerLogCommitTool } from './tools/log-commit.js'
|
|
import { registerCreateTodoTool } from './tools/create-todo.js'
|
|
import { registerCreatePbiTool } from './tools/create-pbi.js'
|
|
import { registerCreateStoryTool } from './tools/create-story.js'
|
|
import { registerCreateTaskTool } from './tools/create-task.js'
|
|
import { registerAskUserQuestionTool } from './tools/ask-user-question.js'
|
|
import { registerGetQuestionAnswerTool } from './tools/get-question-answer.js'
|
|
import { registerListOpenQuestionsTool } from './tools/list-open-questions.js'
|
|
import { registerCancelQuestionTool } from './tools/cancel-question.js'
|
|
import { registerWaitForJobTool } from './tools/wait-for-job.js'
|
|
import { registerUpdateJobStatusTool } from './tools/update-job-status.js'
|
|
import { registerVerifyTaskAgainstPlanTool } from './tools/verify-task-against-plan.js'
|
|
import { registerCleanupMyWorktreesTool } from './tools/cleanup-my-worktrees.js'
|
|
import { registerCheckQueueEmptyTool } from './tools/check-queue-empty.js'
|
|
import { registerSetPbiPrTool } from './tools/set-pbi-pr.js'
|
|
import { registerMarkPbiPrMergedTool } from './tools/mark-pbi-pr-merged.js'
|
|
import { registerGetIdeaContextTool } from './tools/get-idea-context.js'
|
|
import { registerUpdateIdeaGrillMdTool } from './tools/update-idea-grill-md.js'
|
|
import { registerUpdateIdeaPlanMdTool } from './tools/update-idea-plan-md.js'
|
|
import { registerLogIdeaDecisionTool } from './tools/log-idea-decision.js'
|
|
import { registerImplementNextStoryPrompt } from './prompts/implement-next-story.js'
|
|
import { getAuth } from './auth.js'
|
|
import { registerWorker } from './presence/worker.js'
|
|
import { startHeartbeat } from './presence/heartbeat.js'
|
|
import { registerShutdownHandlers } from './presence/shutdown.js'
|
|
|
|
import { readFileSync } from 'node:fs'
|
|
import { dirname, join } from 'node:path'
|
|
import { fileURLToPath } from 'node:url'
|
|
|
|
// Read version dynamically from package.json — voorheen hardcoded en
|
|
// veroorzaakte sync-issues bij deployment. Lees op module-load.
|
|
function readPkgVersion(): string {
|
|
try {
|
|
const here = dirname(fileURLToPath(import.meta.url))
|
|
const pkgPath = join(here, '..', 'package.json')
|
|
return (JSON.parse(readFileSync(pkgPath, 'utf8')) as { version?: string }).version ?? '0.0.0'
|
|
} catch {
|
|
return '0.0.0'
|
|
}
|
|
}
|
|
const VERSION = readPkgVersion()
|
|
|
|
async function main() {
|
|
const server = new McpServer(
|
|
{ name: 'scrum4me-mcp', version: VERSION },
|
|
{
|
|
instructions:
|
|
'Scrum4Me dev-flow tools: read product/sprint/story context, update tasks, log activity. ' +
|
|
'Always call get_claude_context before starting work to fetch the next story.',
|
|
},
|
|
)
|
|
|
|
registerHealthTool(server)
|
|
registerListProductsTool(server)
|
|
registerGetClaudeContextTool(server)
|
|
registerUpdateTaskStatusTool(server)
|
|
registerUpdateTaskPlanTool(server)
|
|
registerLogImplementationTool(server)
|
|
registerLogTestResultTool(server)
|
|
registerLogCommitTool(server)
|
|
registerCreateTodoTool(server)
|
|
registerCreatePbiTool(server)
|
|
registerCreateStoryTool(server)
|
|
registerCreateTaskTool(server)
|
|
registerAskUserQuestionTool(server)
|
|
registerGetQuestionAnswerTool(server)
|
|
registerListOpenQuestionsTool(server)
|
|
registerCancelQuestionTool(server)
|
|
registerWaitForJobTool(server)
|
|
registerUpdateJobStatusTool(server)
|
|
registerVerifyTaskAgainstPlanTool(server)
|
|
registerCleanupMyWorktreesTool(server)
|
|
registerCheckQueueEmptyTool(server)
|
|
registerSetPbiPrTool(server)
|
|
registerMarkPbiPrMergedTool(server)
|
|
// M12: idee-job tools
|
|
registerGetIdeaContextTool(server)
|
|
registerUpdateIdeaGrillMdTool(server)
|
|
registerUpdateIdeaPlanMdTool(server)
|
|
registerLogIdeaDecisionTool(server)
|
|
registerImplementNextStoryPrompt(server)
|
|
|
|
// Presence bootstrap MUST run before server.connect — the stdio transport
|
|
// can stall the await on incoming messages, so anything after server.connect
|
|
// may never execute reliably. Registering the worker + starting the
|
|
// heartbeat first guarantees the UI sees the agent as soon as the process
|
|
// is up, regardless of when the MCP client sends its first request.
|
|
const auth = await getAuth()
|
|
await registerWorker({ userId: auth.userId, tokenId: auth.tokenId })
|
|
const { stop: stopHeartbeat } = startHeartbeat({ userId: auth.userId, tokenId: auth.tokenId })
|
|
registerShutdownHandlers({ userId: auth.userId, tokenId: auth.tokenId, stopHeartbeat })
|
|
|
|
const transport = new StdioServerTransport()
|
|
await server.connect(transport)
|
|
|
|
console.error(`scrum4me-mcp ${VERSION} running on stdio`)
|
|
}
|
|
|
|
main().catch((err) => {
|
|
console.error('Fatal error in scrum4me-mcp:', err)
|
|
process.exit(1)
|
|
})
|