diff --git a/README.md b/README.md
index e1ad687..4571628 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,8 @@
A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server for Azure DevOps integration, enabling AI assistants to interact with Azure DevOps Work Items, Git Repositories, Pull Requests, and Pipelines.
+> **Note**: Flow metrics, WIP analysis, and other analytics features were removed. With `ActivatedDate` and `ClosedDate` now exposed on all work item queries, Claude can derive cycle time, lead time, aging, and throughput directly from the data — no pre-built analytics tools needed.
+
---
## Quick Start
@@ -163,40 +165,6 @@ This project implements an MCP server that exposes tools for querying and managi
| `get_build_timeline` | Gets the timeline (stages, jobs, tasks) for a build |
| `query_builds` | Advanced query with multiple combined filters |
-### Analytics Tools
-
-Tools for analyzing delivery performance, identifying bottlenecks, and tracking work health.
-
-| Tool | Description |
-|------|-------------|
-| `get_flow_metrics` | Calculates Lead Time, Cycle Time, and Throughput with statistical analysis |
-| `compare_flow_metrics` | Compares metrics between two periods to identify trends |
-| `get_wip_analysis` | Analyzes Work in Progress by state, area, and person |
-| `get_bottlenecks` | Identifies workflow bottlenecks with severity scores and recommendations |
-| `get_team_workload` | Analyzes workload distribution across team members |
-| `get_aging_report` | Reports aging work items with urgency classification and recommendations |
-
-#### Flow Metrics
-
-- **Lead Time**: Time from work item creation to completion (measures total delivery time)
-- **Cycle Time**: Time from work started to completion (measures active work time)
-- **Throughput**: Number of items completed per period
-
-#### WIP Analysis
-
-- **By State**: Where work is accumulating
-- **By Area**: Which teams/squads are overloaded
-- **By Person**: Who has too many items assigned
-- **Aging Items**: Work that has been stuck too long
-
-#### Aging Report
-
-Items are classified by urgency based on:
-- Priority (P1 items age faster than P4)
-- Time since last update
-- Current state (blocked items are more urgent)
-- Assignment status (unassigned items need attention)
-
---
## Prerequisites
@@ -434,19 +402,6 @@ After configuring the MCP client, you can ask questions like:
- "Show me the timeline of build #123"
- "What builds are currently in progress?"
-### Analytics and Insights
-
-- "What's our average delivery time (lead time)?"
-- "Are we delivering faster or slower than last month?"
-- "Where is work piling up? Show me bottlenecks"
-- "Who on the team is overloaded?"
-- "What items have been stuck for too long?"
-- "Show me aging work items that need attention"
-- "How many items did we complete last week?"
-- "What's our cycle time for bugs vs user stories?"
-- "Is the 'Backend' team overloaded?"
-- "Compare this sprint's throughput to the previous sprint"
-
---
## Troubleshooting
@@ -541,16 +496,13 @@ mcp-azure-devops/
│ │ ├── WorkItemDto.cs # Work item models
│ │ ├── RepositoryDto.cs # Git repository models
│ │ ├── PullRequestDto.cs # Pull request models
-│ │ ├── PipelineDto.cs # Pipeline/build models
-│ │ ├── FlowMetricsDto.cs # Flow metrics models
-│ │ └── WipAnalysisDto.cs # WIP and aging models
+│ │ └── PipelineDto.cs # Pipeline/build models
│ ├── Services/ # Azure DevOps SDK integration
│ ├── Tools/ # MCP tool implementations
│ │ ├── WorkItemTools.cs # Work item operations
│ │ ├── GitTools.cs # Git repository operations
│ │ ├── PullRequestTools.cs # Pull request operations
-│ │ ├── PipelineTools.cs # Pipeline/build operations
-│ │ └── AnalyticsTools.cs # Analytics and metrics
+│ │ └── PipelineTools.cs # Pipeline/build operations
│ ├── Program.cs # Entry point
│ ├── appsettings.json # App settings
│ └── Dockerfile # Container definition
@@ -636,44 +588,6 @@ Build log metadata with Id, Type, Url, LineCount, and timestamps.
#### BuildTimelineRecordDto
Timeline record (stage, job, or task) with Id, ParentId, Type, Name, State, Result, timing information, and error/warning counts.
-### Analytics DTOs
-
-#### FlowMetricsDto
-Flow metrics analysis results including:
-- PeriodStart, PeriodEnd, Throughput (total completed items)
-- LeadTime, CycleTime (MetricStatistics with average, median, percentiles)
-- ThroughputByPeriod (breakdown by day/week)
-- ThroughputByType (breakdown by work item type)
-- Items (optional detailed list)
-
-#### MetricStatistics
-Statistical measures for a metric including Average, Median, Percentile85, Percentile95, Min, Max, StdDev, and Count.
-
-#### WipAnalysisDto
-Work in Progress analysis including:
-- TotalWip, ByState, ByArea, ByPerson, ByType
-- AgingItems (items stuck too long)
-- Insights (auto-generated observations)
-
-#### BottleneckAnalysisDto
-Bottleneck identification results with:
-- Bottlenecks (list ordered by severity)
-- Recommendations (actionable suggestions)
-
-#### BottleneckDto
-Individual bottleneck with Type (State/Person/Area), Location, ItemCount, Severity (1-10), Description, and SampleItemIds.
-
-#### AgingReportDto
-Comprehensive aging analysis including:
-- TotalAgingItems, Summary (statistics)
-- ByUrgency (Critical/High/Medium/Low item IDs)
-- ByState, ByAssignee, ByArea (grouped counts)
-- Items (detailed list with recommendations)
-- Recommendations (overall action items)
-
-#### AgingItemDetailDto
-Detailed aging item with Id, Title, WorkItemType, State, AssignedTo, AreaPath, Priority, DaysSinceUpdate, DaysSinceCreation, Urgency, UrgencyScore, and Recommendation.
-
---
## Development
diff --git a/src/Viamus.Azure.Devops.Mcp.Server/Models/FlowMetricsDto.cs b/src/Viamus.Azure.Devops.Mcp.Server/Models/FlowMetricsDto.cs
deleted file mode 100644
index d3aaaeb..0000000
--- a/src/Viamus.Azure.Devops.Mcp.Server/Models/FlowMetricsDto.cs
+++ /dev/null
@@ -1,170 +0,0 @@
-namespace Viamus.Azure.Devops.Mcp.Server.Models;
-
-///
-/// Flow metrics analysis results.
-///
-public sealed record FlowMetricsDto
-{
- ///
- /// Analysis period start date.
- ///
- public DateTime PeriodStart { get; init; }
-
- ///
- /// Analysis period end date.
- ///
- public DateTime PeriodEnd { get; init; }
-
- ///
- /// Total number of completed work items in the period.
- ///
- public int Throughput { get; init; }
-
- ///
- /// Lead time statistics in days (from creation to completion).
- ///
- public MetricStatistics LeadTime { get; init; } = new();
-
- ///
- /// Cycle time statistics in days (from started to completion).
- ///
- public MetricStatistics CycleTime { get; init; } = new();
-
- ///
- /// Throughput breakdown by period (day/week).
- ///
- public List ThroughputByPeriod { get; init; } = [];
-
- ///
- /// Throughput breakdown by work item type.
- ///
- public Dictionary ThroughputByType { get; init; } = new();
-
- ///
- /// Individual work item flow data for detailed analysis.
- ///
- public List Items { get; init; } = [];
-}
-
-///
-/// Statistical measures for a metric.
-///
-public sealed record MetricStatistics
-{
- ///
- /// Average value.
- ///
- public double Average { get; init; }
-
- ///
- /// Median value (50th percentile).
- ///
- public double Median { get; init; }
-
- ///
- /// 85th percentile value.
- ///
- public double Percentile85 { get; init; }
-
- ///
- /// 95th percentile value.
- ///
- public double Percentile95 { get; init; }
-
- ///
- /// Minimum value.
- ///
- public double Min { get; init; }
-
- ///
- /// Maximum value.
- ///
- public double Max { get; init; }
-
- ///
- /// Standard deviation.
- ///
- public double StdDev { get; init; }
-
- ///
- /// Number of items in the sample.
- ///
- public int Count { get; init; }
-}
-
-///
-/// Throughput data for a specific period.
-///
-public sealed record ThroughputPeriod
-{
- ///
- /// Period start date.
- ///
- public DateTime PeriodStart { get; init; }
-
- ///
- /// Period end date.
- ///
- public DateTime PeriodEnd { get; init; }
-
- ///
- /// Number of items completed in this period.
- ///
- public int Count { get; init; }
-}
-
-///
-/// Flow data for a single work item.
-///
-public sealed record WorkItemFlowDataDto
-{
- ///
- /// Work item ID.
- ///
- public int Id { get; init; }
-
- ///
- /// Work item title.
- ///
- public string? Title { get; init; }
-
- ///
- /// Work item type (Bug, Task, User Story, etc.).
- ///
- public string? WorkItemType { get; init; }
-
- ///
- /// Date the work item was created.
- ///
- public DateTime? CreatedDate { get; init; }
-
- ///
- /// Date the work item was started (entered In Progress or equivalent).
- ///
- public DateTime? StartedDate { get; init; }
-
- ///
- /// Date the work item was completed.
- ///
- public DateTime? CompletedDate { get; init; }
-
- ///
- /// Lead time in days (created to completed).
- ///
- public double? LeadTimeDays { get; init; }
-
- ///
- /// Cycle time in days (started to completed).
- ///
- public double? CycleTimeDays { get; init; }
-
- ///
- /// Area path of the work item.
- ///
- public string? AreaPath { get; init; }
-
- ///
- /// Iteration path of the work item.
- ///
- public string? IterationPath { get; init; }
-}
diff --git a/src/Viamus.Azure.Devops.Mcp.Server/Models/WipAnalysisDto.cs b/src/Viamus.Azure.Devops.Mcp.Server/Models/WipAnalysisDto.cs
deleted file mode 100644
index 5308ac9..0000000
--- a/src/Viamus.Azure.Devops.Mcp.Server/Models/WipAnalysisDto.cs
+++ /dev/null
@@ -1,463 +0,0 @@
-namespace Viamus.Azure.Devops.Mcp.Server.Models;
-
-///
-/// Work in Progress (WIP) analysis results.
-///
-public sealed record WipAnalysisDto
-{
- ///
- /// Analysis timestamp.
- ///
- public DateTime AnalysisDate { get; init; } = DateTime.UtcNow;
-
- ///
- /// Total number of items in progress (not completed).
- ///
- public int TotalWip { get; init; }
-
- ///
- /// WIP breakdown by state.
- ///
- public List ByState { get; init; } = [];
-
- ///
- /// WIP breakdown by area path (team/squad).
- ///
- public List ByArea { get; init; } = [];
-
- ///
- /// WIP breakdown by assigned person.
- ///
- public List ByPerson { get; init; } = [];
-
- ///
- /// WIP breakdown by work item type.
- ///
- public Dictionary ByType { get; init; } = new();
-
- ///
- /// Items that have been in progress for too long (aging items).
- ///
- public List AgingItems { get; init; } = [];
-
- ///
- /// Summary insights about the WIP status.
- ///
- public List Insights { get; init; } = [];
-}
-
-///
-/// WIP count by state.
-///
-public sealed record WipByStateDto
-{
- ///
- /// State name.
- ///
- public string State { get; init; } = string.Empty;
-
- ///
- /// Number of items in this state.
- ///
- public int Count { get; init; }
-
- ///
- /// Percentage of total WIP.
- ///
- public double Percentage { get; init; }
-
- ///
- /// Average age in days for items in this state.
- ///
- public double AverageAgeDays { get; init; }
-}
-
-///
-/// WIP count by area path (team/squad).
-///
-public sealed record WipByAreaDto
-{
- ///
- /// Area path.
- ///
- public string AreaPath { get; init; } = string.Empty;
-
- ///
- /// Number of items in this area.
- ///
- public int Count { get; init; }
-
- ///
- /// Number of unique assignees in this area.
- ///
- public int UniqueAssignees { get; init; }
-
- ///
- /// Average items per person in this area.
- ///
- public double ItemsPerPerson { get; init; }
-
- ///
- /// Whether this area appears overloaded (high items per person).
- ///
- public bool IsOverloaded { get; init; }
-}
-
-///
-/// WIP count by person.
-///
-public sealed record WipByPersonDto
-{
- ///
- /// Person's display name.
- ///
- public string AssignedTo { get; init; } = string.Empty;
-
- ///
- /// Number of items assigned to this person.
- ///
- public int Count { get; init; }
-
- ///
- /// Breakdown by state for this person.
- ///
- public Dictionary ByState { get; init; } = new();
-
- ///
- /// Whether this person appears overloaded.
- ///
- public bool IsOverloaded { get; init; }
-
- ///
- /// Oldest item age in days assigned to this person.
- ///
- public double OldestItemAgeDays { get; init; }
-}
-
-///
-/// Work item that has been in progress for too long.
-///
-public sealed record AgingWorkItemDto
-{
- ///
- /// Work item ID.
- ///
- public int Id { get; init; }
-
- ///
- /// Work item title.
- ///
- public string? Title { get; init; }
-
- ///
- /// Work item type.
- ///
- public string? WorkItemType { get; init; }
-
- ///
- /// Current state.
- ///
- public string? State { get; init; }
-
- ///
- /// Person assigned to this item.
- ///
- public string? AssignedTo { get; init; }
-
- ///
- /// Area path.
- ///
- public string? AreaPath { get; init; }
-
- ///
- /// Date when the item entered current state.
- ///
- public DateTime? StateChangedDate { get; init; }
-
- ///
- /// Days in current state.
- ///
- public double DaysInState { get; init; }
-
- ///
- /// Days since creation.
- ///
- public double DaysSinceCreation { get; init; }
-
- ///
- /// Priority of the item.
- ///
- public string? Priority { get; init; }
-
- ///
- /// Reason for aging classification.
- ///
- public string AgingReason { get; init; } = string.Empty;
-}
-
-///
-/// Bottleneck analysis results.
-///
-public sealed record BottleneckAnalysisDto
-{
- ///
- /// Analysis timestamp.
- ///
- public DateTime AnalysisDate { get; init; } = DateTime.UtcNow;
-
- ///
- /// Identified bottlenecks ordered by severity.
- ///
- public List Bottlenecks { get; init; } = [];
-
- ///
- /// Recommendations for addressing bottlenecks.
- ///
- public List Recommendations { get; init; } = [];
-}
-
-///
-/// A single bottleneck in the flow.
-///
-public sealed record BottleneckDto
-{
- ///
- /// Type of bottleneck (State, Person, Area, Type).
- ///
- public string Type { get; init; } = string.Empty;
-
- ///
- /// Name/identifier of the bottleneck location.
- ///
- public string Location { get; init; } = string.Empty;
-
- ///
- /// Number of items blocked/waiting.
- ///
- public int ItemCount { get; init; }
-
- ///
- /// Severity score (1-10).
- ///
- public int Severity { get; init; }
-
- ///
- /// Description of the bottleneck.
- ///
- public string Description { get; init; } = string.Empty;
-
- ///
- /// Sample work item IDs affected.
- ///
- public List SampleItemIds { get; init; } = [];
-}
-
-///
-/// Aging report analysis results.
-///
-public sealed record AgingReportDto
-{
- ///
- /// Analysis timestamp.
- ///
- public DateTime AnalysisDate { get; init; } = DateTime.UtcNow;
-
- ///
- /// Total number of aging items.
- ///
- public int TotalAgingItems { get; init; }
-
- ///
- /// Summary statistics about aging.
- ///
- public AgingSummaryDto Summary { get; init; } = new();
-
- ///
- /// Items grouped by urgency level.
- ///
- public AgingByUrgencyDto ByUrgency { get; init; } = new();
-
- ///
- /// Aging items grouped by state.
- ///
- public List ByState { get; init; } = [];
-
- ///
- /// Aging items grouped by assignee.
- ///
- public List ByAssignee { get; init; } = [];
-
- ///
- /// Aging items grouped by area.
- ///
- public List ByArea { get; init; } = [];
-
- ///
- /// Detailed list of aging items with recommendations.
- ///
- public List Items { get; init; } = [];
-
- ///
- /// Overall recommendations for addressing aging work.
- ///
- public List Recommendations { get; init; } = [];
-}
-
-///
-/// Summary statistics for aging analysis.
-///
-public sealed record AgingSummaryDto
-{
- ///
- /// Average age of all aging items in days.
- ///
- public double AverageAgeDays { get; init; }
-
- ///
- /// Median age in days.
- ///
- public double MedianAgeDays { get; init; }
-
- ///
- /// Maximum age in days.
- ///
- public double MaxAgeDays { get; init; }
-
- ///
- /// Percentage of total WIP that is aging.
- ///
- public double PercentageOfWip { get; init; }
-
- ///
- /// States with most aging items.
- ///
- public string TopAgingState { get; init; } = string.Empty;
-
- ///
- /// Person with most aging items.
- ///
- public string TopAgingAssignee { get; init; } = string.Empty;
-}
-
-///
-/// Aging items grouped by urgency level.
-///
-public sealed record AgingByUrgencyDto
-{
- ///
- /// Critical items (highest priority, very old).
- ///
- public List Critical { get; init; } = [];
-
- ///
- /// High urgency items.
- ///
- public List High { get; init; } = [];
-
- ///
- /// Medium urgency items.
- ///
- public List Medium { get; init; } = [];
-
- ///
- /// Low urgency items.
- ///
- public List Low { get; init; } = [];
-}
-
-///
-/// Aging statistics for a group (state, person, area).
-///
-public sealed record AgingByGroupDto
-{
- ///
- /// Group name (state name, person name, or area path).
- ///
- public string Name { get; init; } = string.Empty;
-
- ///
- /// Number of aging items in this group.
- ///
- public int Count { get; init; }
-
- ///
- /// Average age in days for this group.
- ///
- public double AverageAgeDays { get; init; }
-
- ///
- /// Oldest item age in this group.
- ///
- public double MaxAgeDays { get; init; }
-
- ///
- /// List of work item IDs in this group.
- ///
- public List ItemIds { get; init; } = [];
-}
-
-///
-/// Detailed aging item with recommendation.
-///
-public sealed record AgingItemDetailDto
-{
- ///
- /// Work item ID.
- ///
- public int Id { get; init; }
-
- ///
- /// Work item title.
- ///
- public string? Title { get; init; }
-
- ///
- /// Work item type.
- ///
- public string? WorkItemType { get; init; }
-
- ///
- /// Current state.
- ///
- public string? State { get; init; }
-
- ///
- /// Assigned person.
- ///
- public string? AssignedTo { get; init; }
-
- ///
- /// Area path.
- ///
- public string? AreaPath { get; init; }
-
- ///
- /// Priority (1=highest).
- ///
- public string? Priority { get; init; }
-
- ///
- /// Days since last update.
- ///
- public double DaysSinceUpdate { get; init; }
-
- ///
- /// Days since creation.
- ///
- public double DaysSinceCreation { get; init; }
-
- ///
- /// Urgency classification (Critical, High, Medium, Low).
- ///
- public string Urgency { get; init; } = string.Empty;
-
- ///
- /// Urgency score (1-10, higher is more urgent).
- ///
- public int UrgencyScore { get; init; }
-
- ///
- /// Specific recommendation for this item.
- ///
- public string Recommendation { get; init; } = string.Empty;
-}
diff --git a/src/Viamus.Azure.Devops.Mcp.Server/Models/WorkItemDto.cs b/src/Viamus.Azure.Devops.Mcp.Server/Models/WorkItemDto.cs
index 56338a0..03c5d5b 100644
--- a/src/Viamus.Azure.Devops.Mcp.Server/Models/WorkItemDto.cs
+++ b/src/Viamus.Azure.Devops.Mcp.Server/Models/WorkItemDto.cs
@@ -17,6 +17,8 @@ public sealed record WorkItemDto
public string? Severity { get; init; }
public DateTime? CreatedDate { get; init; }
public DateTime? ChangedDate { get; init; }
+ public DateTime? ActivatedDate { get; init; }
+ public DateTime? ClosedDate { get; init; }
public string? CreatedBy { get; init; }
public string? ChangedBy { get; init; }
public string? Reason { get; init; }
diff --git a/src/Viamus.Azure.Devops.Mcp.Server/Models/WorkItemSummaryDto.cs b/src/Viamus.Azure.Devops.Mcp.Server/Models/WorkItemSummaryDto.cs
index ba9a8c5..7a6f8ed 100644
--- a/src/Viamus.Azure.Devops.Mcp.Server/Models/WorkItemSummaryDto.cs
+++ b/src/Viamus.Azure.Devops.Mcp.Server/Models/WorkItemSummaryDto.cs
@@ -13,5 +13,7 @@ public sealed record WorkItemSummaryDto
public string? AssignedTo { get; init; }
public string? Priority { get; init; }
public DateTime? ChangedDate { get; init; }
+ public DateTime? ActivatedDate { get; init; }
+ public DateTime? ClosedDate { get; init; }
public int? ParentId { get; init; }
}
diff --git a/src/Viamus.Azure.Devops.Mcp.Server/Services/AzureDevOpsService.cs b/src/Viamus.Azure.Devops.Mcp.Server/Services/AzureDevOpsService.cs
index c13ef83..38b9704 100644
--- a/src/Viamus.Azure.Devops.Mcp.Server/Services/AzureDevOpsService.cs
+++ b/src/Viamus.Azure.Devops.Mcp.Server/Services/AzureDevOpsService.cs
@@ -39,6 +39,8 @@ public sealed class AzureDevOpsService : IAzureDevOpsService, IDisposable
"Microsoft.VSTS.Common.Severity",
"System.CreatedDate",
"System.ChangedDate",
+ "Microsoft.VSTS.Common.ActivatedDate",
+ "Microsoft.VSTS.Common.ClosedDate",
"System.CreatedBy",
"System.ChangedBy",
"System.Reason",
@@ -54,6 +56,8 @@ public sealed class AzureDevOpsService : IAzureDevOpsService, IDisposable
"System.AssignedTo",
"Microsoft.VSTS.Common.Priority",
"System.ChangedDate",
+ "Microsoft.VSTS.Common.ActivatedDate",
+ "Microsoft.VSTS.Common.ClosedDate",
"System.Parent"
];
@@ -294,6 +298,8 @@ private static WorkItemSummaryDto MapToSummaryDto(WorkItem workItem)
AssignedTo = GetIdentityFieldValue(fields, "System.AssignedTo"),
Priority = GetFieldValue