Skip to main content

10 - Project Management Servers: Scrum and Agile

MCP servers for project management: scrum-board, agile-metrics, time-tracking, project-economics and retrospective-manager.

What do you think about this article?

At a Glance

MCP servers for project management: scrum-board, agile-metrics, time-tracking, project-economics and retrospective-manager.

Overview: Five MCP Servers for Agile Project Management

Agile project management is one of the most complex domains in software development: it requires coordinating sprints, tasks, performance metrics, time tracking, budgets, and retrospectives. In the Tech-MCP suite, these aspects are managed by five specialized MCP servers that collaborate through the EventBus, forming an integrated project management ecosystem.

In this article, we will analyze each server in detail: its tools with Zod schemas, published and subscribed events, and the collaboration flow that binds them into a cohesive system.

The Five PM Servers of the MCP Suite

Server Role Tools Storage
scrum-board Central Scrum hub 7 SQLite (3 tables)
agile-metrics Analytics and forecasts 4 Stateless
time-tracking Time tracking 4 SQLite (2 tables)
project-economics Budget and costs 4 SQLite (2 tables)
retrospective-manager Agile retrospectives 5 SQLite (3 tables)

1. Scrum Board Server: The Central Hub

The scrum-board server is the operational heart of the entire MCP Suite for project management. It manages sprints, user stories, and tasks following the Scrum methodology, serving as the hub through which most collaborative workflows pass. Virtually every other PM server interacts with scrum-board, either directly or through the events it publishes.


                    +---------------------------+
                    |     SCRUM-BOARD SERVER    |
                    |       CENTRAL HUB         |
                    +---------------------------+
                   /     |       |        |      \
                  /      |       |        |       \
                 v       v       v        v        v
          +-------+ +-------+ +------+ +-------+ +-------+
          |agile  | |time   | |retro | |standup| |project|
          |metrics| |track. | |mgr   | |notes  | |econ.  |
          +-------+ +-------+ +------+ +-------+ +-------+
    

Scrum-board Server Tools

The scrum-board exposes 7 tools covering the entire Scrum lifecycle:

Tool Table: scrum-board

Tool Description Key Parameters
create-sprint Creates a new sprint name (string), startDate (string), endDate (string), goals (string[])
get-sprint Retrieves sprint details sprintId (number)
create-story Creates a new user story title, description, acceptanceCriteria (string[]), storyPoints (number), priority, sprintId (opt.)
create-task Creates a task for a story title, description, storyId (number), assignee (opt.)
update-task-status Updates a task's status taskId (number), status (enum: todo | in_progress | in_review | done | blocked)
sprint-board Kanban view of the sprint sprintId (number, optional; default: active sprint)
get-backlog Stories not assigned to a sprint None

Zod Schema: create-sprint

Every tool defines its parameters through Zod schemas for automatic input validation:


// Tool: create-sprint
const CreateSprintSchema = z.object({
  name: z.string().describe("Sprint name"),
  startDate: z.string().describe("Start date ISO (YYYY-MM-DD)"),
  endDate: z.string().describe("End date ISO (YYYY-MM-DD)"),
  goals: z.array(z.string()).describe("Sprint goals")
});
    

Zod Schema: update-task-status


// Tool: update-task-status
const UpdateTaskStatusSchema = z.object({
  taskId: z.number().describe("ID of the task to update"),
  status: z.enum(["todo", "in_progress", "in_review", "done", "blocked"])
    .describe("New task status in the Kanban flow")
});
    

Task Kanban Flow

Every task status change follows the standard Kanban flow. From any state, it is possible to transition to blocked:


  +-------+     +-------------+     +-----------+     +------+
  | todo  | --> | in_progress | --> | in_review | --> | done |
  +-------+     +-------------+     +-----------+     +------+
      |               |                   |
      +-------+-------+-------------------+
              |
              v
          +--------+
          | blocked|
          +--------+
    

ScrumStore Database: Three SQLite Tables

The ScrumStore manages three interconnected tables via foreign keys:


+------------------+       +-------------------+       +------------------+
|     sprints      |       |      stories      |       |      tasks       |
+------------------+       +-------------------+       +------------------+
| id (PK)          |<------| sprintId (FK)     |       | id (PK)          |
| name             |       | id (PK)           |<------| storyId (FK, NN) |
| startDate        |       | title             |       | sprintId (FK)    |
| endDate          |       | description       |       | title            |
| goals (JSON)     |       | acceptanceCriteria|       | description      |
| status           |       | storyPoints       |       | status           |
| createdAt        |       | priority          |       | assignee         |
+------------------+       | status            |       | createdAt        |
                            | createdAt         |       | updatedAt        |
                            +-------------------+       +------------------+
    

Sprint Board: Kanban View

The sprint-board tool generates a complete Kanban view, organizing tasks into columns. If no sprintId is specified, it automatically retrieves the sprint with active status:


+--------------------------------------------------------------------+
|                   Sprint Board: Sprint 14                          |
+--------------------------------------------------------------------+
| TODO          | IN PROGRESS   | IN REVIEW     | DONE    | BLOCKED  |
|---------------|---------------|---------------|---------|----------|
| Task: Setup   | Task: Login   | Task: Test    | Task:   | Task:    |
|   OAuth       |   form UI     |   OAuth flow  |  DB     |  Deploy  |
|               |               |               | schema  |  (needs  |
| Task: 2FA     | Task: Token   |               |         |  infra)  |
|   research    |   refresh     |               |         |          |
+--------------------------------------------------------------------+
    

Events Published by scrum-board

The scrum-board is the primary event producer of the PM suite. Every critical operation generates an event that triggers chain reactions in other servers:

Scrum-board Events

Event Payload Emitted by
scrum:sprint-started { sprintId, name, startDate, endDate } create-sprint
scrum:task-updated { taskId, status, previousStatus, storyId, sprintId } update-task-status
scrum:sprint-completed { sprintId, name, completedPoints } Sprint closure
scrum:story-completed { storyId, storyPoints, sprintId } Story completion

Events Subscribed by scrum-board

The scrum-board is also one of the few servers that receives events from other servers, creating a bidirectional feedback loop:

Subscription: retro:action-item-created

When the retrospective-manager generates action items from a retrospective, it publishes retro:action-item-created. The scrum-board receives it and automatically creates a task in the backlog, closing the continuous improvement loop.

Example: Complete Sprint Workflow


// 1. Create the sprint
{ "tool": "create-sprint",
  "arguments": {
    "name": "Sprint 14 - Authentication",
    "startDate": "2025-02-03",
    "endDate": "2025-02-14",
    "goals": ["Implement OAuth login", "Add 2FA"]
  } }

// 2. Create a user story
{ "tool": "create-story",
  "arguments": {
    "title": "Google OAuth Login",
    "description": "As a user I want to authenticate with Google",
    "acceptanceCriteria": ["Redirect to Google", "Token saved", "Session active"],
    "storyPoints": 8,
    "priority": "high",
    "sprintId": 1
  } }

// 3. Create tasks for the story
{ "tool": "create-task",
  "arguments": {
    "title": "Configure OAuth credentials",
    "description": "Setup on Google Cloud Console",
    "storyId": 1,
    "assignee": "mario"
  } }

// 4. Update task status
{ "tool": "update-task-status",
  "arguments": { "taskId": 1, "status": "in_progress" } }

// 5. View the board
{ "tool": "sprint-board", "arguments": { "sprintId": 1 } }
    

2. Agile Metrics Server: Analytics and Forecasts

The agile-metrics server provides analytical tools for measuring and predicting team performance. It calculates velocity, generates burndown data, analyzes cycle time, and produces completion forecasts based on Monte Carlo simulations.

A fundamental characteristic is that the server is completely stateless: it has no database or internal store. It receives data as input (typically from the scrum-board) and returns pure calculations.

Tool Table: agile-metrics

Tool Description Key Parameters
calculate-velocity Average velocity with trend analysis sprints (array of { name, completedPoints, totalPoints })
generate-burndown Burndown chart data totalPoints, sprintDays, dailyCompleted (number[])
calculate-cycle-time Cycle time statistics tasks (array of { taskId, startDate, endDate })
forecast-completion Monte Carlo forecast remainingPoints, velocityHistory (number[]), sprintLengthDays

Zod Schema: calculate-velocity


const CalculateVelocitySchema = z.object({
  sprints: z.array(z.object({
    name: z.string(),
    completedPoints: z.number(),
    totalPoints: z.number()
  })).describe("Sprint list with completed and total points")
});
    

Zod Schema: forecast-completion


const ForecastCompletionSchema = z.object({
  remainingPoints: z.number().describe("Remaining points to complete"),
  velocityHistory: z.array(z.number())
    .describe("Velocity history from recent sprints"),
  sprintLengthDays: z.number()
    .describe("Sprint duration in days")
});
    

Monte Carlo Simulation

The forecast-completion tool runs 1000 simulations to predict when the remaining work will be completed, accounting for historical velocity variability:


  Monte Carlo Algorithm:
  +-------------------------------------------------------+
  | For each simulation (1..1000):                        |
  |   remainingWork = remainingPoints                     |
  |   sprints = 0                                         |
  |   while remainingWork > 0:                            |
  |     velocity = random(velocityHistory)                |
  |     remainingWork -= velocity                         |
  |     sprints++                                         |
  |   record(sprints * sprintLengthDays)                  |
  +-------------------------------------------------------+
  | Sort results                                          |
  | p50 = result at the 50th percentile                   |
  | p85 = result at the 85th percentile                   |
  | p95 = result at the 95th percentile                   |
  +-------------------------------------------------------+
    

The output provides three confidence levels:


{
  "remainingPoints": 50,
  "simulations": 1000,
  "forecast": {
    "p50": { "sprints": 2, "days": 28, "date": "2025-03-14" },
    "p85": { "sprints": 3, "days": 42, "date": "2025-03-28" },
    "p95": { "sprints": 3, "days": 42, "date": "2025-03-28" }
  },
  "confidence": "85% probability of completion within 42 days"
}
    

Burndown Chart: Ideal vs Actual

The generate-burndown tool compares the ideal line with actual progress, indicating for each day whether progress is on-track, behind, or ahead:


  Points
  40 |*
     | *  .
  30 |  *   .
     |   *     .    * <-- actual (behind schedule)
  20 |    *       .
     |     *         .    *
  10 |      *           .     *
     |       *              .    *
   0 |--------*------------------.--*-----> Days
     1  2  3  4  5  6  7  8  9 10

     * = ideal line     . = actual progress
    

Cycle Time: Detailed Statistics

The calculate-cycle-time tool analyzes task completion times:

Cycle Time Metrics

Metric Description
average Arithmetic mean of cycle time
median Median value (p50)
p95 95th percentile
min Minimum completion time
max Maximum completion time

Events Subscribed by agile-metrics

Agile-metrics is a pure data consumer. It publishes no events, but subscribes to scrum-board events to react to changes in the current sprint:

  • scrum:sprint-completed → trigger for velocity recalculation and end-of-sprint report
  • scrum:task-updated → real-time burndown data update
  • scrum:story-completed → completed points update for velocity tracking

3. Time Tracking Server: Time Management

The time-tracking server manages tracking of time worked on tasks, with support for live timers and manual logging. It maintains persistent state via SQLite with two tables: one for time entries and one for active timers.

The server implements double-start protection: it is not possible to have more than one active timer simultaneously for the same user.

Tool Table: time-tracking

Tool Description Key Parameters
start-timer Starts a timer for a task taskId (string), description (opt.), userId (opt.)
stop-timer Stops the active timer userId (opt.)
log-time Manual time logging taskId, durationMinutes (number), description (opt.), date (opt.)
get-timesheet Timesheet filtered by dates userId (opt.), startDate (opt.), endDate (opt.)

Zod Schema: start-timer and log-time


const StartTimerSchema = z.object({
  taskId: z.string().describe("ID of the task to track"),
  description: z.string().optional()
    .describe("Activity description"),
  userId: z.string().optional()
    .describe("User ID (default: 'default')")
});

const LogTimeSchema = z.object({
  taskId: z.string().describe("Task ID"),
  durationMinutes: z.number()
    .describe("Duration in minutes"),
  description: z.string().optional(),
  date: z.string().optional()
    .describe("ISO date (YYYY-MM-DD)"),
  userId: z.string().optional()
});
    

Timer Flow

The start-timer flow includes double-start protection. The stop-timer automatically calculates the duration and creates a time entry:


  start-timer(taskId: "TASK-42")
       |
       v
  Check: does an active timer exist for userId?
       |
       +--[YES]--> Error: "Active timer for TASK-15. Stop it first."
       |
       +--[NO]--> Create record in active_timers
                   startTime = new Date().toISOString()

  stop-timer()
       |
       v
  Find active timer for userId
       |
       +--[NOT FOUND]--> Error: "No active timer found"
       |
       +--[FOUND]
            |
            v
       endTime = now()
       durationMinutes = Math.round((endMs - startMs) / 60000)
            |
            v
       INSERT INTO time_entries --> DELETE FROM active_timers
            |
            v
       Publish time:entry-logged
    

TimeStore Database

The TimeStore manages two SQLite tables:

  • active_timers: currently running timers (id, taskId, userId, startTime, description)
  • time_entries: completed entries (id, taskId, userId, startTime, endTime, durationMinutes, description, date)

Time-tracking Events

Published Event: time:entry-logged

Every time a timer is stopped or time is manually logged, the server publishes the time:entry-logged event with payload:


{
  "taskId": "TASK-42",
  "userId": "mario",
  "durationMinutes": 45,
  "date": "2025-02-07"
}
      

This event is intercepted by project-economics to convert time into cost and update the project budget.

4. Project Economics Server: Budget and Costs

The project-economics server manages project budgets and costs, providing visibility on spending, category breakdown, and budget exhaustion forecasts. It includes an automatic alert system that publishes an event when budget usage reaches or exceeds 80%.

Tool Table: project-economics

Tool Description Key Parameters
set-budget Defines a project budget projectName, totalBudget (number), currency (default: 'EUR')
log-cost Records a cost projectName, category, amount (number), description, taskId (opt.)
get-budget-status Complete budget status projectName
forecast-budget Budget exhaustion forecast projectName

Zod Schema: log-cost


const LogCostSchema = z.object({
  projectName: z.string().describe("Project name"),
  category: z.string().describe("Spending category (e.g. development, infra, testing)"),
  amount: z.number().describe("Amount in budget currency"),
  description: z.string().describe("Cost description"),
  date: z.string().optional().describe("ISO date of the cost"),
  taskId: z.string().optional().describe("Associated task ID")
});
    

Budget Forecast Algorithm

The forecast-budget tool calculates the daily burn rate and estimates when the budget will be exhausted:


  Forecast algorithm:
  +---------------------------------------------------+
  | 1. Find first and last cost date                  |
  | 2. daysTracked = (lastDate - firstDate) + 1       |
  | 3. dailyBurnRate = totalSpent / daysTracked       |
  | 4. estimatedDaysRemaining = remaining / burnRate  |
  | 5. runOutDate = today + daysRemaining             |
  +---------------------------------------------------+
    

Budget Status with Breakdown

The get-budget-status tool returns a complete budget view with a breakdown by spending category:


{
  "projectName": "MCP Suite v2",
  "totalBudget": 50000,
  "currency": "EUR",
  "totalSpent": 38500,
  "remaining": 11500,
  "percentageUsed": 77.0,
  "breakdown": [
    { "category": "development", "total": 25000 },
    { "category": "infrastructure", "total": 8500 },
    { "category": "testing", "total": 3000 },
    { "category": "design", "total": 2000 }
  ]
}
    

Project-economics Events

Automatic Alert System

Event Payload Condition
economics:cost-updated { projectName, category, amount, totalSpent } Always (on every log-cost)
economics:budget-alert { projectName, percentageUsed, remaining, totalBudget } When percentageUsed >= 80%

Budget Alert Flow


  log-cost("MCP Suite v2", "development", 5000, ...)
       |
       v
  Calculate percentageUsed = totalSpent / totalBudget * 100
       |
       v
  percentageUsed = 82%  --> >= 80%?
       |
       +--[YES]--> Publish economics:budget-alert
       |           { projectName: "MCP Suite v2",
       |             percentageUsed: 82,
       |             remaining: 9000,
       |             totalBudget: 50000 }
       |
       +--[NO]--> Only economics:cost-updated
    

Events Subscribed by project-economics

  • time:entry-logged (from time-tracking) → converts logged time into cost and adds it to the project
  • scrum:sprint-completed (from scrum-board) → trigger for end-of-sprint report with cost analysis

5. Retrospective Manager Server: Agile Retrospectives

The retrospective-manager server manages the complete agile retrospective cycle: from creating a session with a specific format, to collecting feedback by category, to voting, and finally to the automatic generation of action items from the most voted themes.

It supports three standard formats of retrospective:

Supported Retrospective Formats

Format Categories
mad-sad-glad mad, sad, glad
4Ls liked, learned, lacked, longed-for
start-stop-continue start, stop, continue

Tool Table: retrospective-manager

Tool Description Key Parameters
create-retro Creates a retrospective format (enum), sprintId (opt.)
add-retro-item Adds feedback (with category validation) retroId, category, content, authorId (opt.)
vote-retro-item Adds a vote to an item itemId (number)
generate-action-items Generates action items from top voted retroId, topN (default: 3)
get-retro Complete retrospective retroId (number)

Zod Schema: create-retro and add-retro-item


const CreateRetroSchema = z.object({
  format: z.enum(["mad-sad-glad", "4ls", "start-stop-continue"])
    .describe("Retrospective format"),
  sprintId: z.string().optional()
    .describe("Associated sprint ID")
});

const AddRetroItemSchema = z.object({
  retroId: z.number().describe("Retrospective ID"),
  category: z.string()
    .describe("Category (validated against retro format)"),
  content: z.string().describe("Feedback content"),
  authorId: z.string().optional()
    .describe("Feedback author")
});
    

Category Validation

The server validates the category by checking that it is consistent with the retrospective format. If the category is invalid, it returns an error:


  add-retro-item(retroId: 1, category: "happy", content: "...")
       |
       v
  Check retro #1 format = "mad-sad-glad"
  Valid categories: ["mad", "sad", "glad"]
  "happy" is NOT valid
       |
       v
  Error: 'Invalid category "happy" for format "mad-sad-glad".
          Valid categories: mad, sad, glad'
    

Action Item Generation

The generate-action-items tool selects the top-N most voted items and generates an action item for each, publishing the retro:action-item-created event:


  Top 3 voted --> Action Items:
  1. [mad] Deploy too slow (8 votes)
  2. [sad] Missing documentation (6 votes)
  3. [glad] Code review improves quality (5 votes)
       |
       v
  For each action item:
    Publish retro:action-item-created
    { retroId, actionItemId, description, assignee }
       |
       v
  scrum-board receives --> creates task in backlog
    

RetroStore Database: Three SQLite Tables

  • retros: retrospective sessions (id, sprintId, format, status)
  • retro_items: team feedback (id, retroId, category, content, votes, authorId)
  • action_items: concrete actions (id, retroId, description, assignee, dueDate, status)

Bidirectional Flow with scrum-board

Feedback Loop: Sprint → Retro → Backlog

  1. Sprint completes → scrum-board publishes scrum:sprint-completed
  2. The retrospective-manager receives the event and automatically creates a retrospective
  3. The team adds items and votes
  4. Generated action items are published as retro:action-item-created
  5. The scrum-board receives the event and creates tasks in the backlog

This cycle closes the continuous improvement loop: every retrospective generates concrete actions that enter the Scrum workflow as backlog tasks.

Collaboration Flow: How the 5 PM Servers Interact

The real value of these five servers emerges from their EventBus-driven collaboration. No server operates in isolation: every published event triggers chain reactions that create an integrated and automated project management flow.

Complete PM Event Map

Event Producer Consumers
scrum:sprint-started scrum-board agile-metrics, retrospective-manager
scrum:task-updated scrum-board agile-metrics, time-tracking, project-economics
scrum:sprint-completed scrum-board agile-metrics, retrospective-manager, project-economics
scrum:story-completed scrum-board agile-metrics
time:entry-logged time-tracking project-economics
economics:budget-alert project-economics (future: standup-notes)
economics:cost-updated project-economics (logging and audit)
retro:action-item-created retrospective-manager scrum-board

Collaboration Diagram


  +------------------+
  |   SCRUM-BOARD    |  (CENTRAL HUB)
  |   7 tools        |
  +--------+---------+
           |
           | scrum:sprint-started
           | scrum:task-updated
           | scrum:sprint-completed
           | scrum:story-completed
           |
     +-----+-----+-----+------------------+
     |           |     |                  |
     v           v     v                  v
+----------+ +------+ +---------------+ +----+
|agile-    | |time- | |retrospective- | |... |
|metrics   | |track.| |manager        | |    |
|4 tools   | |4 tool| |5 tools        | |    |
|stateless | |      | |               | |    |
+----------+ +--+---+ +------+--------+ +----+
                |             |
                | time:       | retro:action-
                | entry-      | item-created
                | logged      |
                v             v
          +----------+  +------------------+
          |project-  |  |  SCRUM-BOARD     |
          |economics |  |  (receives and   |
          |4 tools   |  |   creates tasks) |
          +----+-----+  +------------------+
               |
               | economics:budget-alert
               | economics:cost-updated
               v
          (alerts and audit)
    

Integrated Scenario: Complete Sprint with All Servers

Here is an example of how all five servers collaborate during a sprint lifecycle:

  1. Planning: the AI invokes create-sprint on the scrum-board. The scrum:sprint-started event notifies agile-metrics (new velocity) and retrospective-manager (context for future retro).
  2. Execution: developers update task statuses with update-task-status. The scrum:task-updated event triggers burndown recalculation in agile-metrics and time-tracking can automatically start/stop timers.
  3. Time tracking: on stop-timer, time-tracking publishes time:entry-logged. Project-economics receives the event and converts time to cost, updating the budget.
  4. Budget alert: if spending exceeds 80% of the budget, project-economics publishes economics:budget-alert to notify the team.
  5. Sprint closure: on sprint completion, agile-metrics recalculates velocity and forecasts, while retrospective-manager automatically creates a retrospective.
  6. Retrospective: the team adds feedback, votes, and generates action items. The retro:action-item-created event creates tasks in the scrum-board backlog, ready for the next sprint.

Internal Architecture of PM Servers

All five PM servers follow the same standardized architectural structure, sharing patterns and conventions from the @mcp-suite/core package:


server-name/
  src/
    index.ts          --> entry point
    server.ts         --> createXxxServer(), registers tools and collaboration
    services/
      xxx-store.ts    --> SQLite Store (persistent data management)
    tools/
      tool-name.ts    --> individual tool handler with Zod schema
    collaboration.ts  --> setupCollaborationHandlers(eventBus, store)
    

The collaboration.ts pattern is particularly important: it is the file that manages event subscription and publication on the EventBus, making each server's collaboration contract with the rest of the suite explicit.

Shared Package Dependencies

The PM servers use three shared packages from the MCP Suite:

  • @mcp-suite/core: base for MCP server creation, tool registration, lifecycle management
  • @mcp-suite/event-bus: typed event system for inter-server communication
  • @mcp-suite/database: SQLite wrapper with automatic migrations (used by 4 of 5 servers; agile-metrics is stateless)

Conclusions

The five project management servers of the MCP Suite demonstrate how the MCP protocol can support complex and truly collaborative workflows. The scrum-board as the central hub, agile-metrics for predictive analytics with Monte Carlo, time-tracking for time management, project-economics for cost control, and retrospective-manager for continuous improvement form a complete agile management ecosystem.

The key pattern is event-driven collaboration: each server publishes events that trigger actions in others, creating automation chains that reduce manual work and keep the entire system synchronized. The retrospective-backlog cycle is a perfect example of how MCP servers can close feedback loops in a fully automated way.

In the next article, we will explore the advanced servers of the suite: incident-manager, decision-log, access-policy, quality-gate, workflow-orchestrator, insight-engine, and more, discovering how to handle even more complex scenarios with evolved architectural patterns.

The complete code for all project management servers is available in the Tech-MCP GitHub repository.

Commenti

Caricamento commenti...

Sign in to comment

Discuss this article in the community

Join the Telegram group to discuss with other developers, ask questions and share your experiences.

Did you like this article?

Explore other content on the blog or discover my projects