@letpeoplework/lighthouse-mcp-core 1.4.1 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -65,6 +65,31 @@ var throughputFilterViewProperty = {
65
65
  description: `Forecast-filter view (Lighthouse v26.5.24.10+). "filtered" applies the team's exclusion rule to throughput. Omit or "raw" returns unfiltered data.`
66
66
  }
67
67
  };
68
+ var percentilesOverTimeProperties = {
69
+ metricType: {
70
+ type: "string",
71
+ enum: ["CycleTime", "WorkItemAge"],
72
+ description: 'Percentile family to read. Defaults to "CycleTime" when omitted.'
73
+ },
74
+ horizon: {
75
+ type: "number",
76
+ description: "Cycle-time horizon in days (30, 60 or 90). Ignored for WorkItemAge, which is always as-of-today and has no horizon dimension."
77
+ }
78
+ };
79
+ var processBehaviorOverTimeProperties = {
80
+ metricType: {
81
+ type: "string",
82
+ enum: [
83
+ "Throughput",
84
+ "WorkItemAge",
85
+ "Wip",
86
+ "CycleTime",
87
+ "Arrivals",
88
+ "FeatureSize"
89
+ ],
90
+ description: 'Process-behaviour family to read. Defaults to "Throughput" when omitted. "FeatureSize" is portfolio-only \u2014 a team never records it and returns an empty series.'
91
+ }
92
+ };
68
93
  var cumulativeStateProperty = {
69
94
  state: {
70
95
  type: "string",
@@ -202,7 +227,7 @@ var toolDefinitions = [
202
227
  },
203
228
  {
204
229
  name: "lighthouse_team_metrics_workItemAgePercentiles",
205
- description: "Get work-item age percentiles for a team by ID, optionally filtered by start and end dates.",
230
+ description: "Get work-item age percentiles for a team by ID, optionally filtered by start and end dates. Ages are measured as of the last day of the selected range, not as of today \u2014 a historical range reports how old the items were at the end of that period, so do not present the result as the team's current ages unless the range ends today.",
206
231
  inputSchema: {
207
232
  type: "object",
208
233
  properties: {
@@ -215,7 +240,7 @@ var toolDefinitions = [
215
240
  },
216
241
  {
217
242
  name: "lighthouse_portfolio_metrics_workItemAgePercentiles",
218
- description: "Get work-item age percentiles for a portfolio by ID, optionally filtered by start and end dates.",
243
+ description: "Get work-item age percentiles for a portfolio by ID, optionally filtered by start and end dates. Ages are measured as of the last day of the selected range, not as of today \u2014 a historical range reports how old the items were at the end of that period, so do not present the result as the portfolio's current ages unless the range ends today.",
219
244
  inputSchema: {
220
245
  type: "object",
221
246
  properties: {
@@ -226,6 +251,88 @@ var toolDefinitions = [
226
251
  additionalProperties: false
227
252
  }
228
253
  },
254
+ {
255
+ name: "lighthouse_team_metrics_blockedCountHistory",
256
+ description: "Get the blocked-items-over-time trend for a team by ID: how many work items were blocked on each captured day, optionally filtered by start and end dates. To see what is blocked right now and for how long, read the team's current WIP \u2014 each item carries isBlocked and, when blocked, a blockedSince timestamp.",
257
+ inputSchema: {
258
+ type: "object",
259
+ properties: {
260
+ ...idInputSchema.properties,
261
+ ...dateRangeProperties
262
+ },
263
+ required: ["id"],
264
+ additionalProperties: false
265
+ }
266
+ },
267
+ {
268
+ name: "lighthouse_portfolio_metrics_blockedCountHistory",
269
+ description: "Get the blocked-items-over-time trend for a portfolio by ID: how many work items were blocked on each captured day, optionally filtered by start and end dates. To see what is blocked right now and for how long, read the portfolio's current WIP \u2014 each item carries isBlocked and, when blocked, a blockedSince timestamp.",
270
+ inputSchema: {
271
+ type: "object",
272
+ properties: {
273
+ ...idInputSchema.properties,
274
+ ...dateRangeProperties
275
+ },
276
+ required: ["id"],
277
+ additionalProperties: false
278
+ }
279
+ },
280
+ {
281
+ name: "lighthouse_team_metrics_percentilesOverTime",
282
+ description: "Get the percentiles-over-time trend for a team by ID: the p50/p70/p85/p95 quartet recorded on each captured day, optionally filtered by start and end dates. Recording is forward-only \u2014 Lighthouse never backfills days it did not observe, so a recently upgraded server returns an empty series until it has recorded some. Use metricType to pick the family and horizon to pick the cycle-time window.",
283
+ inputSchema: {
284
+ type: "object",
285
+ properties: {
286
+ ...idInputSchema.properties,
287
+ ...dateRangeProperties,
288
+ ...percentilesOverTimeProperties
289
+ },
290
+ required: ["id"],
291
+ additionalProperties: false
292
+ }
293
+ },
294
+ {
295
+ name: "lighthouse_portfolio_metrics_percentilesOverTime",
296
+ description: "Get the percentiles-over-time trend for a portfolio by ID: the p50/p70/p85/p95 quartet recorded on each captured day, optionally filtered by start and end dates. Recording is forward-only \u2014 Lighthouse never backfills days it did not observe, so a recently upgraded server returns an empty series until it has recorded some. Use metricType to pick the family and horizon to pick the cycle-time window.",
297
+ inputSchema: {
298
+ type: "object",
299
+ properties: {
300
+ ...idInputSchema.properties,
301
+ ...dateRangeProperties,
302
+ ...percentilesOverTimeProperties
303
+ },
304
+ required: ["id"],
305
+ additionalProperties: false
306
+ }
307
+ },
308
+ {
309
+ name: "lighthouse_team_metrics_processBehaviorOverTime",
310
+ description: "Get the process-behaviour-limits-over-time trend for a team by ID: the upper limit, average and lower limit (UNPL/Average/LNPL) recorded on each captured day, optionally filtered by start and end dates. Recording is forward-only, and days without a usable baseline are absent rather than zeroed \u2014 an empty series means nothing was recorded, never a process pinned at zero.",
311
+ inputSchema: {
312
+ type: "object",
313
+ properties: {
314
+ ...idInputSchema.properties,
315
+ ...dateRangeProperties,
316
+ ...processBehaviorOverTimeProperties
317
+ },
318
+ required: ["id"],
319
+ additionalProperties: false
320
+ }
321
+ },
322
+ {
323
+ name: "lighthouse_portfolio_metrics_processBehaviorOverTime",
324
+ description: "Get the process-behaviour-limits-over-time trend for a portfolio by ID: the upper limit, average and lower limit (UNPL/Average/LNPL) recorded on each captured day, optionally filtered by start and end dates. Recording is forward-only, and days without a usable baseline are absent rather than zeroed \u2014 an empty series means nothing was recorded, never a process pinned at zero. FeatureSize is available here and not on teams.",
325
+ inputSchema: {
326
+ type: "object",
327
+ properties: {
328
+ ...idInputSchema.properties,
329
+ ...dateRangeProperties,
330
+ ...processBehaviorOverTimeProperties
331
+ },
332
+ required: ["id"],
333
+ additionalProperties: false
334
+ }
335
+ },
229
336
  {
230
337
  name: "lighthouse_portfolio_metrics_throughput",
231
338
  description: "Get throughput run-chart data for a portfolio by ID, optionally filtered by start and end dates.",
@@ -584,6 +691,30 @@ var getThroughputFilterView = (argumentsPayload) => {
584
691
  const view = argumentsPayload.view;
585
692
  return view === "raw" || view === "filtered" ? view : void 0;
586
693
  };
694
+ var percentilesOverTimeMetricTypes = ["CycleTime", "WorkItemAge"];
695
+ var getPercentilesOverTimeMetricType = (argumentsPayload) => {
696
+ const raw = getStringArgument(argumentsPayload, "metricType");
697
+ return percentilesOverTimeMetricTypes.find((candidate) => candidate === raw);
698
+ };
699
+ var processBehaviorMetricTypes = [
700
+ "Throughput",
701
+ "WorkItemAge",
702
+ "Wip",
703
+ "CycleTime",
704
+ "Arrivals",
705
+ "FeatureSize"
706
+ ];
707
+ var getProcessBehaviorMetricType = (argumentsPayload) => {
708
+ const raw = getStringArgument(argumentsPayload, "metricType");
709
+ return processBehaviorMetricTypes.find((candidate) => candidate === raw);
710
+ };
711
+ var getHorizonArgument = (argumentsPayload) => {
712
+ if (!isObjectRecord(argumentsPayload)) {
713
+ return void 0;
714
+ }
715
+ const horizon = argumentsPayload.horizon;
716
+ return typeof horizon === "number" && Number.isInteger(horizon) ? horizon : void 0;
717
+ };
587
718
  var getApplyFilterOverride = (argumentsPayload) => {
588
719
  if (!isObjectRecord(argumentsPayload)) {
589
720
  return void 0;
@@ -641,6 +772,56 @@ var toolInputSchemas = {
641
772
  startDate: isoDateStringSchema.optional(),
642
773
  endDate: isoDateStringSchema.optional()
643
774
  }),
775
+ lighthouse_team_metrics_blockedCountHistory: import_zod.z.object({
776
+ id: import_zod.z.number().int(),
777
+ startDate: isoDateStringSchema.optional(),
778
+ endDate: isoDateStringSchema.optional()
779
+ }),
780
+ lighthouse_portfolio_metrics_blockedCountHistory: import_zod.z.object({
781
+ id: import_zod.z.number().int(),
782
+ startDate: isoDateStringSchema.optional(),
783
+ endDate: isoDateStringSchema.optional()
784
+ }),
785
+ lighthouse_team_metrics_percentilesOverTime: import_zod.z.object({
786
+ id: import_zod.z.number().int(),
787
+ startDate: isoDateStringSchema.optional(),
788
+ endDate: isoDateStringSchema.optional(),
789
+ metricType: import_zod.z.enum(["CycleTime", "WorkItemAge"]).optional(),
790
+ horizon: import_zod.z.number().int().optional()
791
+ }),
792
+ lighthouse_portfolio_metrics_percentilesOverTime: import_zod.z.object({
793
+ id: import_zod.z.number().int(),
794
+ startDate: isoDateStringSchema.optional(),
795
+ endDate: isoDateStringSchema.optional(),
796
+ metricType: import_zod.z.enum(["CycleTime", "WorkItemAge"]).optional(),
797
+ horizon: import_zod.z.number().int().optional()
798
+ }),
799
+ lighthouse_team_metrics_processBehaviorOverTime: import_zod.z.object({
800
+ id: import_zod.z.number().int(),
801
+ startDate: isoDateStringSchema.optional(),
802
+ endDate: isoDateStringSchema.optional(),
803
+ metricType: import_zod.z.enum([
804
+ "Throughput",
805
+ "WorkItemAge",
806
+ "Wip",
807
+ "CycleTime",
808
+ "Arrivals",
809
+ "FeatureSize"
810
+ ]).optional()
811
+ }),
812
+ lighthouse_portfolio_metrics_processBehaviorOverTime: import_zod.z.object({
813
+ id: import_zod.z.number().int(),
814
+ startDate: isoDateStringSchema.optional(),
815
+ endDate: isoDateStringSchema.optional(),
816
+ metricType: import_zod.z.enum([
817
+ "Throughput",
818
+ "WorkItemAge",
819
+ "Wip",
820
+ "CycleTime",
821
+ "Arrivals",
822
+ "FeatureSize"
823
+ ]).optional()
824
+ }),
644
825
  lighthouse_team_metrics_workItemAge: import_zod.z.object({
645
826
  id: import_zod.z.number().int(),
646
827
  startDate: isoDateStringSchema.optional(),
@@ -923,6 +1104,120 @@ var createMcpCoreRuntime = (dependencies) => ({
923
1104
  `portfolio metrics: ${result.error.category} (${result.error.reason})`
924
1105
  );
925
1106
  }
1107
+ if (name === "lighthouse_team_metrics_blockedCountHistory") {
1108
+ const id = getNumericId(argumentsPayload);
1109
+ if (id === null) {
1110
+ return getErrorToolResult("team metrics: invalid id");
1111
+ }
1112
+ const range = getDateRange(argumentsPayload);
1113
+ const result = await client.getTeamBlockedCountHistory(id, range);
1114
+ if (result.ok) {
1115
+ return getSuccessToolResult(
1116
+ `team blockedCountHistory: ${encodePayload(result.value)}`
1117
+ );
1118
+ }
1119
+ return getErrorToolResult(
1120
+ `team metrics: ${result.error.category} (${result.error.reason})`
1121
+ );
1122
+ }
1123
+ if (name === "lighthouse_portfolio_metrics_blockedCountHistory") {
1124
+ const id = getNumericId(argumentsPayload);
1125
+ if (id === null) {
1126
+ return getErrorToolResult("portfolio metrics: invalid id");
1127
+ }
1128
+ const range = getDateRange(argumentsPayload);
1129
+ const result = await client.getPortfolioBlockedCountHistory(id, range);
1130
+ if (result.ok) {
1131
+ return getSuccessToolResult(
1132
+ `portfolio blockedCountHistory: ${encodePayload(result.value)}`
1133
+ );
1134
+ }
1135
+ return getErrorToolResult(
1136
+ `portfolio metrics: ${result.error.category} (${result.error.reason})`
1137
+ );
1138
+ }
1139
+ if (name === "lighthouse_team_metrics_percentilesOverTime") {
1140
+ const id = getNumericId(argumentsPayload);
1141
+ if (id === null) {
1142
+ return getErrorToolResult("team metrics: invalid id");
1143
+ }
1144
+ const range = getDateRange(argumentsPayload);
1145
+ const result = await client.getTeamPercentilesOverTime(
1146
+ id,
1147
+ range,
1148
+ getPercentilesOverTimeMetricType(argumentsPayload),
1149
+ getHorizonArgument(argumentsPayload)
1150
+ );
1151
+ if (result.ok) {
1152
+ return getSuccessToolResult(
1153
+ `team percentilesOverTime: ${encodePayload(result.value)}`
1154
+ );
1155
+ }
1156
+ return getErrorToolResult(
1157
+ `team metrics: ${result.error.category} (${result.error.reason})`
1158
+ );
1159
+ }
1160
+ if (name === "lighthouse_portfolio_metrics_percentilesOverTime") {
1161
+ const id = getNumericId(argumentsPayload);
1162
+ if (id === null) {
1163
+ return getErrorToolResult("portfolio metrics: invalid id");
1164
+ }
1165
+ const range = getDateRange(argumentsPayload);
1166
+ const result = await client.getPortfolioPercentilesOverTime(
1167
+ id,
1168
+ range,
1169
+ getPercentilesOverTimeMetricType(argumentsPayload),
1170
+ getHorizonArgument(argumentsPayload)
1171
+ );
1172
+ if (result.ok) {
1173
+ return getSuccessToolResult(
1174
+ `portfolio percentilesOverTime: ${encodePayload(result.value)}`
1175
+ );
1176
+ }
1177
+ return getErrorToolResult(
1178
+ `portfolio metrics: ${result.error.category} (${result.error.reason})`
1179
+ );
1180
+ }
1181
+ if (name === "lighthouse_team_metrics_processBehaviorOverTime") {
1182
+ const id = getNumericId(argumentsPayload);
1183
+ if (id === null) {
1184
+ return getErrorToolResult("team metrics: invalid id");
1185
+ }
1186
+ const range = getDateRange(argumentsPayload);
1187
+ const result = await client.getTeamProcessBehaviorOverTime(
1188
+ id,
1189
+ range,
1190
+ getProcessBehaviorMetricType(argumentsPayload)
1191
+ );
1192
+ if (result.ok) {
1193
+ return getSuccessToolResult(
1194
+ `team processBehaviorOverTime: ${encodePayload(result.value)}`
1195
+ );
1196
+ }
1197
+ return getErrorToolResult(
1198
+ `team metrics: ${result.error.category} (${result.error.reason})`
1199
+ );
1200
+ }
1201
+ if (name === "lighthouse_portfolio_metrics_processBehaviorOverTime") {
1202
+ const id = getNumericId(argumentsPayload);
1203
+ if (id === null) {
1204
+ return getErrorToolResult("portfolio metrics: invalid id");
1205
+ }
1206
+ const range = getDateRange(argumentsPayload);
1207
+ const result = await client.getPortfolioProcessBehaviorOverTime(
1208
+ id,
1209
+ range,
1210
+ getProcessBehaviorMetricType(argumentsPayload)
1211
+ );
1212
+ if (result.ok) {
1213
+ return getSuccessToolResult(
1214
+ `portfolio processBehaviorOverTime: ${encodePayload(result.value)}`
1215
+ );
1216
+ }
1217
+ return getErrorToolResult(
1218
+ `portfolio metrics: ${result.error.category} (${result.error.reason})`
1219
+ );
1220
+ }
926
1221
  if (name === "lighthouse_team_metrics_cumulativeStateTime") {
927
1222
  const id = getNumericId(argumentsPayload);
928
1223
  if (id === null) {
package/dist/index.d.cts CHANGED
@@ -15,7 +15,7 @@ type McpToolResult = {
15
15
  readonly content: readonly McpToolContent[];
16
16
  };
17
17
  type McpToolDefinition = {
18
- readonly name: "lighthouse_health_check" | "lighthouse_version_get" | "lighthouse_worktracking_list" | "lighthouse_worktracking_get" | "lighthouse_team_list" | "lighthouse_team_get" | "lighthouse_team_refresh" | "lighthouse_portfolio_list" | "lighthouse_portfolio_get" | "lighthouse_portfolio_refresh" | "lighthouse_team_metrics_throughput" | "lighthouse_team_metrics_cycleTimePercentiles" | "lighthouse_team_metrics_workItemAgePercentiles" | "lighthouse_portfolio_metrics_workItemAgePercentiles" | "lighthouse_team_metrics_workItemAge" | "lighthouse_team_metrics_totalWorkItemAge" | "lighthouse_portfolio_metrics_throughput" | "lighthouse_portfolio_metrics_workItemAge" | "lighthouse_portfolio_metrics_totalWorkItemAge" | "lighthouse_team_metrics_cumulativeStateTime" | "lighthouse_team_metrics_cumulativeStateTimeItems" | "lighthouse_team_metrics_cumulativeStateTimeCandidates" | "lighthouse_portfolio_metrics_cumulativeStateTime" | "lighthouse_portfolio_metrics_cumulativeStateTimeItems" | "lighthouse_portfolio_metrics_cumulativeStateTimeCandidates" | "lighthouse_feature_get" | "lighthouse_feature_workitems" | "lighthouse_delivery_list" | "lighthouse_blackout_list" | "lighthouse_blackout_create" | "lighthouse_blackout_update" | "lighthouse_blackout_delete" | "lighthouse_forecast_manual" | "lighthouse_forecast_backtest";
18
+ readonly name: "lighthouse_health_check" | "lighthouse_version_get" | "lighthouse_worktracking_list" | "lighthouse_worktracking_get" | "lighthouse_team_list" | "lighthouse_team_get" | "lighthouse_team_refresh" | "lighthouse_portfolio_list" | "lighthouse_portfolio_get" | "lighthouse_portfolio_refresh" | "lighthouse_team_metrics_throughput" | "lighthouse_team_metrics_cycleTimePercentiles" | "lighthouse_team_metrics_workItemAgePercentiles" | "lighthouse_portfolio_metrics_workItemAgePercentiles" | "lighthouse_team_metrics_workItemAge" | "lighthouse_team_metrics_totalWorkItemAge" | "lighthouse_portfolio_metrics_throughput" | "lighthouse_portfolio_metrics_workItemAge" | "lighthouse_portfolio_metrics_totalWorkItemAge" | "lighthouse_team_metrics_blockedCountHistory" | "lighthouse_portfolio_metrics_blockedCountHistory" | "lighthouse_team_metrics_percentilesOverTime" | "lighthouse_portfolio_metrics_percentilesOverTime" | "lighthouse_team_metrics_processBehaviorOverTime" | "lighthouse_portfolio_metrics_processBehaviorOverTime" | "lighthouse_team_metrics_cumulativeStateTime" | "lighthouse_team_metrics_cumulativeStateTimeItems" | "lighthouse_team_metrics_cumulativeStateTimeCandidates" | "lighthouse_portfolio_metrics_cumulativeStateTime" | "lighthouse_portfolio_metrics_cumulativeStateTimeItems" | "lighthouse_portfolio_metrics_cumulativeStateTimeCandidates" | "lighthouse_feature_get" | "lighthouse_feature_workitems" | "lighthouse_delivery_list" | "lighthouse_blackout_list" | "lighthouse_blackout_create" | "lighthouse_blackout_update" | "lighthouse_blackout_delete" | "lighthouse_forecast_manual" | "lighthouse_forecast_backtest";
19
19
  readonly description: string;
20
20
  readonly inputSchema: {
21
21
  readonly type: "object";
@@ -236,6 +236,84 @@ type McpRuntimeClient = {
236
236
  readonly reason: string;
237
237
  };
238
238
  }>;
239
+ readonly getTeamBlockedCountHistory: (id: number, range?: {
240
+ readonly startDate: string;
241
+ readonly endDate: string;
242
+ }) => Promise<{
243
+ readonly ok: true;
244
+ readonly value: readonly unknown[];
245
+ } | {
246
+ readonly ok: false;
247
+ readonly error: {
248
+ readonly category: string;
249
+ readonly reason: string;
250
+ };
251
+ }>;
252
+ readonly getPortfolioBlockedCountHistory: (id: number, range?: {
253
+ readonly startDate: string;
254
+ readonly endDate: string;
255
+ }) => Promise<{
256
+ readonly ok: true;
257
+ readonly value: readonly unknown[];
258
+ } | {
259
+ readonly ok: false;
260
+ readonly error: {
261
+ readonly category: string;
262
+ readonly reason: string;
263
+ };
264
+ }>;
265
+ readonly getTeamPercentilesOverTime: (id: number, range?: {
266
+ readonly startDate: string;
267
+ readonly endDate: string;
268
+ }, metricType?: "CycleTime" | "WorkItemAge", horizon?: number) => Promise<{
269
+ readonly ok: true;
270
+ readonly value: readonly unknown[];
271
+ } | {
272
+ readonly ok: false;
273
+ readonly error: {
274
+ readonly category: string;
275
+ readonly reason: string;
276
+ };
277
+ }>;
278
+ readonly getPortfolioPercentilesOverTime: (id: number, range?: {
279
+ readonly startDate: string;
280
+ readonly endDate: string;
281
+ }, metricType?: "CycleTime" | "WorkItemAge", horizon?: number) => Promise<{
282
+ readonly ok: true;
283
+ readonly value: readonly unknown[];
284
+ } | {
285
+ readonly ok: false;
286
+ readonly error: {
287
+ readonly category: string;
288
+ readonly reason: string;
289
+ };
290
+ }>;
291
+ readonly getTeamProcessBehaviorOverTime: (id: number, range?: {
292
+ readonly startDate: string;
293
+ readonly endDate: string;
294
+ }, metricType?: "Throughput" | "WorkItemAge" | "Wip" | "CycleTime" | "Arrivals" | "FeatureSize") => Promise<{
295
+ readonly ok: true;
296
+ readonly value: readonly unknown[];
297
+ } | {
298
+ readonly ok: false;
299
+ readonly error: {
300
+ readonly category: string;
301
+ readonly reason: string;
302
+ };
303
+ }>;
304
+ readonly getPortfolioProcessBehaviorOverTime: (id: number, range?: {
305
+ readonly startDate: string;
306
+ readonly endDate: string;
307
+ }, metricType?: "Throughput" | "WorkItemAge" | "Wip" | "CycleTime" | "Arrivals" | "FeatureSize") => Promise<{
308
+ readonly ok: true;
309
+ readonly value: readonly unknown[];
310
+ } | {
311
+ readonly ok: false;
312
+ readonly error: {
313
+ readonly category: string;
314
+ readonly reason: string;
315
+ };
316
+ }>;
239
317
  readonly getTeamCumulativeStateTime: (id: number, range?: {
240
318
  readonly startDate: string;
241
319
  readonly endDate: string;
package/dist/index.d.ts CHANGED
@@ -15,7 +15,7 @@ type McpToolResult = {
15
15
  readonly content: readonly McpToolContent[];
16
16
  };
17
17
  type McpToolDefinition = {
18
- readonly name: "lighthouse_health_check" | "lighthouse_version_get" | "lighthouse_worktracking_list" | "lighthouse_worktracking_get" | "lighthouse_team_list" | "lighthouse_team_get" | "lighthouse_team_refresh" | "lighthouse_portfolio_list" | "lighthouse_portfolio_get" | "lighthouse_portfolio_refresh" | "lighthouse_team_metrics_throughput" | "lighthouse_team_metrics_cycleTimePercentiles" | "lighthouse_team_metrics_workItemAgePercentiles" | "lighthouse_portfolio_metrics_workItemAgePercentiles" | "lighthouse_team_metrics_workItemAge" | "lighthouse_team_metrics_totalWorkItemAge" | "lighthouse_portfolio_metrics_throughput" | "lighthouse_portfolio_metrics_workItemAge" | "lighthouse_portfolio_metrics_totalWorkItemAge" | "lighthouse_team_metrics_cumulativeStateTime" | "lighthouse_team_metrics_cumulativeStateTimeItems" | "lighthouse_team_metrics_cumulativeStateTimeCandidates" | "lighthouse_portfolio_metrics_cumulativeStateTime" | "lighthouse_portfolio_metrics_cumulativeStateTimeItems" | "lighthouse_portfolio_metrics_cumulativeStateTimeCandidates" | "lighthouse_feature_get" | "lighthouse_feature_workitems" | "lighthouse_delivery_list" | "lighthouse_blackout_list" | "lighthouse_blackout_create" | "lighthouse_blackout_update" | "lighthouse_blackout_delete" | "lighthouse_forecast_manual" | "lighthouse_forecast_backtest";
18
+ readonly name: "lighthouse_health_check" | "lighthouse_version_get" | "lighthouse_worktracking_list" | "lighthouse_worktracking_get" | "lighthouse_team_list" | "lighthouse_team_get" | "lighthouse_team_refresh" | "lighthouse_portfolio_list" | "lighthouse_portfolio_get" | "lighthouse_portfolio_refresh" | "lighthouse_team_metrics_throughput" | "lighthouse_team_metrics_cycleTimePercentiles" | "lighthouse_team_metrics_workItemAgePercentiles" | "lighthouse_portfolio_metrics_workItemAgePercentiles" | "lighthouse_team_metrics_workItemAge" | "lighthouse_team_metrics_totalWorkItemAge" | "lighthouse_portfolio_metrics_throughput" | "lighthouse_portfolio_metrics_workItemAge" | "lighthouse_portfolio_metrics_totalWorkItemAge" | "lighthouse_team_metrics_blockedCountHistory" | "lighthouse_portfolio_metrics_blockedCountHistory" | "lighthouse_team_metrics_percentilesOverTime" | "lighthouse_portfolio_metrics_percentilesOverTime" | "lighthouse_team_metrics_processBehaviorOverTime" | "lighthouse_portfolio_metrics_processBehaviorOverTime" | "lighthouse_team_metrics_cumulativeStateTime" | "lighthouse_team_metrics_cumulativeStateTimeItems" | "lighthouse_team_metrics_cumulativeStateTimeCandidates" | "lighthouse_portfolio_metrics_cumulativeStateTime" | "lighthouse_portfolio_metrics_cumulativeStateTimeItems" | "lighthouse_portfolio_metrics_cumulativeStateTimeCandidates" | "lighthouse_feature_get" | "lighthouse_feature_workitems" | "lighthouse_delivery_list" | "lighthouse_blackout_list" | "lighthouse_blackout_create" | "lighthouse_blackout_update" | "lighthouse_blackout_delete" | "lighthouse_forecast_manual" | "lighthouse_forecast_backtest";
19
19
  readonly description: string;
20
20
  readonly inputSchema: {
21
21
  readonly type: "object";
@@ -236,6 +236,84 @@ type McpRuntimeClient = {
236
236
  readonly reason: string;
237
237
  };
238
238
  }>;
239
+ readonly getTeamBlockedCountHistory: (id: number, range?: {
240
+ readonly startDate: string;
241
+ readonly endDate: string;
242
+ }) => Promise<{
243
+ readonly ok: true;
244
+ readonly value: readonly unknown[];
245
+ } | {
246
+ readonly ok: false;
247
+ readonly error: {
248
+ readonly category: string;
249
+ readonly reason: string;
250
+ };
251
+ }>;
252
+ readonly getPortfolioBlockedCountHistory: (id: number, range?: {
253
+ readonly startDate: string;
254
+ readonly endDate: string;
255
+ }) => Promise<{
256
+ readonly ok: true;
257
+ readonly value: readonly unknown[];
258
+ } | {
259
+ readonly ok: false;
260
+ readonly error: {
261
+ readonly category: string;
262
+ readonly reason: string;
263
+ };
264
+ }>;
265
+ readonly getTeamPercentilesOverTime: (id: number, range?: {
266
+ readonly startDate: string;
267
+ readonly endDate: string;
268
+ }, metricType?: "CycleTime" | "WorkItemAge", horizon?: number) => Promise<{
269
+ readonly ok: true;
270
+ readonly value: readonly unknown[];
271
+ } | {
272
+ readonly ok: false;
273
+ readonly error: {
274
+ readonly category: string;
275
+ readonly reason: string;
276
+ };
277
+ }>;
278
+ readonly getPortfolioPercentilesOverTime: (id: number, range?: {
279
+ readonly startDate: string;
280
+ readonly endDate: string;
281
+ }, metricType?: "CycleTime" | "WorkItemAge", horizon?: number) => Promise<{
282
+ readonly ok: true;
283
+ readonly value: readonly unknown[];
284
+ } | {
285
+ readonly ok: false;
286
+ readonly error: {
287
+ readonly category: string;
288
+ readonly reason: string;
289
+ };
290
+ }>;
291
+ readonly getTeamProcessBehaviorOverTime: (id: number, range?: {
292
+ readonly startDate: string;
293
+ readonly endDate: string;
294
+ }, metricType?: "Throughput" | "WorkItemAge" | "Wip" | "CycleTime" | "Arrivals" | "FeatureSize") => Promise<{
295
+ readonly ok: true;
296
+ readonly value: readonly unknown[];
297
+ } | {
298
+ readonly ok: false;
299
+ readonly error: {
300
+ readonly category: string;
301
+ readonly reason: string;
302
+ };
303
+ }>;
304
+ readonly getPortfolioProcessBehaviorOverTime: (id: number, range?: {
305
+ readonly startDate: string;
306
+ readonly endDate: string;
307
+ }, metricType?: "Throughput" | "WorkItemAge" | "Wip" | "CycleTime" | "Arrivals" | "FeatureSize") => Promise<{
308
+ readonly ok: true;
309
+ readonly value: readonly unknown[];
310
+ } | {
311
+ readonly ok: false;
312
+ readonly error: {
313
+ readonly category: string;
314
+ readonly reason: string;
315
+ };
316
+ }>;
239
317
  readonly getTeamCumulativeStateTime: (id: number, range?: {
240
318
  readonly startDate: string;
241
319
  readonly endDate: string;
package/dist/index.js CHANGED
@@ -39,6 +39,31 @@ var throughputFilterViewProperty = {
39
39
  description: `Forecast-filter view (Lighthouse v26.5.24.10+). "filtered" applies the team's exclusion rule to throughput. Omit or "raw" returns unfiltered data.`
40
40
  }
41
41
  };
42
+ var percentilesOverTimeProperties = {
43
+ metricType: {
44
+ type: "string",
45
+ enum: ["CycleTime", "WorkItemAge"],
46
+ description: 'Percentile family to read. Defaults to "CycleTime" when omitted.'
47
+ },
48
+ horizon: {
49
+ type: "number",
50
+ description: "Cycle-time horizon in days (30, 60 or 90). Ignored for WorkItemAge, which is always as-of-today and has no horizon dimension."
51
+ }
52
+ };
53
+ var processBehaviorOverTimeProperties = {
54
+ metricType: {
55
+ type: "string",
56
+ enum: [
57
+ "Throughput",
58
+ "WorkItemAge",
59
+ "Wip",
60
+ "CycleTime",
61
+ "Arrivals",
62
+ "FeatureSize"
63
+ ],
64
+ description: 'Process-behaviour family to read. Defaults to "Throughput" when omitted. "FeatureSize" is portfolio-only \u2014 a team never records it and returns an empty series.'
65
+ }
66
+ };
42
67
  var cumulativeStateProperty = {
43
68
  state: {
44
69
  type: "string",
@@ -176,7 +201,7 @@ var toolDefinitions = [
176
201
  },
177
202
  {
178
203
  name: "lighthouse_team_metrics_workItemAgePercentiles",
179
- description: "Get work-item age percentiles for a team by ID, optionally filtered by start and end dates.",
204
+ description: "Get work-item age percentiles for a team by ID, optionally filtered by start and end dates. Ages are measured as of the last day of the selected range, not as of today \u2014 a historical range reports how old the items were at the end of that period, so do not present the result as the team's current ages unless the range ends today.",
180
205
  inputSchema: {
181
206
  type: "object",
182
207
  properties: {
@@ -189,7 +214,7 @@ var toolDefinitions = [
189
214
  },
190
215
  {
191
216
  name: "lighthouse_portfolio_metrics_workItemAgePercentiles",
192
- description: "Get work-item age percentiles for a portfolio by ID, optionally filtered by start and end dates.",
217
+ description: "Get work-item age percentiles for a portfolio by ID, optionally filtered by start and end dates. Ages are measured as of the last day of the selected range, not as of today \u2014 a historical range reports how old the items were at the end of that period, so do not present the result as the portfolio's current ages unless the range ends today.",
193
218
  inputSchema: {
194
219
  type: "object",
195
220
  properties: {
@@ -200,6 +225,88 @@ var toolDefinitions = [
200
225
  additionalProperties: false
201
226
  }
202
227
  },
228
+ {
229
+ name: "lighthouse_team_metrics_blockedCountHistory",
230
+ description: "Get the blocked-items-over-time trend for a team by ID: how many work items were blocked on each captured day, optionally filtered by start and end dates. To see what is blocked right now and for how long, read the team's current WIP \u2014 each item carries isBlocked and, when blocked, a blockedSince timestamp.",
231
+ inputSchema: {
232
+ type: "object",
233
+ properties: {
234
+ ...idInputSchema.properties,
235
+ ...dateRangeProperties
236
+ },
237
+ required: ["id"],
238
+ additionalProperties: false
239
+ }
240
+ },
241
+ {
242
+ name: "lighthouse_portfolio_metrics_blockedCountHistory",
243
+ description: "Get the blocked-items-over-time trend for a portfolio by ID: how many work items were blocked on each captured day, optionally filtered by start and end dates. To see what is blocked right now and for how long, read the portfolio's current WIP \u2014 each item carries isBlocked and, when blocked, a blockedSince timestamp.",
244
+ inputSchema: {
245
+ type: "object",
246
+ properties: {
247
+ ...idInputSchema.properties,
248
+ ...dateRangeProperties
249
+ },
250
+ required: ["id"],
251
+ additionalProperties: false
252
+ }
253
+ },
254
+ {
255
+ name: "lighthouse_team_metrics_percentilesOverTime",
256
+ description: "Get the percentiles-over-time trend for a team by ID: the p50/p70/p85/p95 quartet recorded on each captured day, optionally filtered by start and end dates. Recording is forward-only \u2014 Lighthouse never backfills days it did not observe, so a recently upgraded server returns an empty series until it has recorded some. Use metricType to pick the family and horizon to pick the cycle-time window.",
257
+ inputSchema: {
258
+ type: "object",
259
+ properties: {
260
+ ...idInputSchema.properties,
261
+ ...dateRangeProperties,
262
+ ...percentilesOverTimeProperties
263
+ },
264
+ required: ["id"],
265
+ additionalProperties: false
266
+ }
267
+ },
268
+ {
269
+ name: "lighthouse_portfolio_metrics_percentilesOverTime",
270
+ description: "Get the percentiles-over-time trend for a portfolio by ID: the p50/p70/p85/p95 quartet recorded on each captured day, optionally filtered by start and end dates. Recording is forward-only \u2014 Lighthouse never backfills days it did not observe, so a recently upgraded server returns an empty series until it has recorded some. Use metricType to pick the family and horizon to pick the cycle-time window.",
271
+ inputSchema: {
272
+ type: "object",
273
+ properties: {
274
+ ...idInputSchema.properties,
275
+ ...dateRangeProperties,
276
+ ...percentilesOverTimeProperties
277
+ },
278
+ required: ["id"],
279
+ additionalProperties: false
280
+ }
281
+ },
282
+ {
283
+ name: "lighthouse_team_metrics_processBehaviorOverTime",
284
+ description: "Get the process-behaviour-limits-over-time trend for a team by ID: the upper limit, average and lower limit (UNPL/Average/LNPL) recorded on each captured day, optionally filtered by start and end dates. Recording is forward-only, and days without a usable baseline are absent rather than zeroed \u2014 an empty series means nothing was recorded, never a process pinned at zero.",
285
+ inputSchema: {
286
+ type: "object",
287
+ properties: {
288
+ ...idInputSchema.properties,
289
+ ...dateRangeProperties,
290
+ ...processBehaviorOverTimeProperties
291
+ },
292
+ required: ["id"],
293
+ additionalProperties: false
294
+ }
295
+ },
296
+ {
297
+ name: "lighthouse_portfolio_metrics_processBehaviorOverTime",
298
+ description: "Get the process-behaviour-limits-over-time trend for a portfolio by ID: the upper limit, average and lower limit (UNPL/Average/LNPL) recorded on each captured day, optionally filtered by start and end dates. Recording is forward-only, and days without a usable baseline are absent rather than zeroed \u2014 an empty series means nothing was recorded, never a process pinned at zero. FeatureSize is available here and not on teams.",
299
+ inputSchema: {
300
+ type: "object",
301
+ properties: {
302
+ ...idInputSchema.properties,
303
+ ...dateRangeProperties,
304
+ ...processBehaviorOverTimeProperties
305
+ },
306
+ required: ["id"],
307
+ additionalProperties: false
308
+ }
309
+ },
203
310
  {
204
311
  name: "lighthouse_portfolio_metrics_throughput",
205
312
  description: "Get throughput run-chart data for a portfolio by ID, optionally filtered by start and end dates.",
@@ -558,6 +665,30 @@ var getThroughputFilterView = (argumentsPayload) => {
558
665
  const view = argumentsPayload.view;
559
666
  return view === "raw" || view === "filtered" ? view : void 0;
560
667
  };
668
+ var percentilesOverTimeMetricTypes = ["CycleTime", "WorkItemAge"];
669
+ var getPercentilesOverTimeMetricType = (argumentsPayload) => {
670
+ const raw = getStringArgument(argumentsPayload, "metricType");
671
+ return percentilesOverTimeMetricTypes.find((candidate) => candidate === raw);
672
+ };
673
+ var processBehaviorMetricTypes = [
674
+ "Throughput",
675
+ "WorkItemAge",
676
+ "Wip",
677
+ "CycleTime",
678
+ "Arrivals",
679
+ "FeatureSize"
680
+ ];
681
+ var getProcessBehaviorMetricType = (argumentsPayload) => {
682
+ const raw = getStringArgument(argumentsPayload, "metricType");
683
+ return processBehaviorMetricTypes.find((candidate) => candidate === raw);
684
+ };
685
+ var getHorizonArgument = (argumentsPayload) => {
686
+ if (!isObjectRecord(argumentsPayload)) {
687
+ return void 0;
688
+ }
689
+ const horizon = argumentsPayload.horizon;
690
+ return typeof horizon === "number" && Number.isInteger(horizon) ? horizon : void 0;
691
+ };
561
692
  var getApplyFilterOverride = (argumentsPayload) => {
562
693
  if (!isObjectRecord(argumentsPayload)) {
563
694
  return void 0;
@@ -615,6 +746,56 @@ var toolInputSchemas = {
615
746
  startDate: isoDateStringSchema.optional(),
616
747
  endDate: isoDateStringSchema.optional()
617
748
  }),
749
+ lighthouse_team_metrics_blockedCountHistory: z.object({
750
+ id: z.number().int(),
751
+ startDate: isoDateStringSchema.optional(),
752
+ endDate: isoDateStringSchema.optional()
753
+ }),
754
+ lighthouse_portfolio_metrics_blockedCountHistory: z.object({
755
+ id: z.number().int(),
756
+ startDate: isoDateStringSchema.optional(),
757
+ endDate: isoDateStringSchema.optional()
758
+ }),
759
+ lighthouse_team_metrics_percentilesOverTime: z.object({
760
+ id: z.number().int(),
761
+ startDate: isoDateStringSchema.optional(),
762
+ endDate: isoDateStringSchema.optional(),
763
+ metricType: z.enum(["CycleTime", "WorkItemAge"]).optional(),
764
+ horizon: z.number().int().optional()
765
+ }),
766
+ lighthouse_portfolio_metrics_percentilesOverTime: z.object({
767
+ id: z.number().int(),
768
+ startDate: isoDateStringSchema.optional(),
769
+ endDate: isoDateStringSchema.optional(),
770
+ metricType: z.enum(["CycleTime", "WorkItemAge"]).optional(),
771
+ horizon: z.number().int().optional()
772
+ }),
773
+ lighthouse_team_metrics_processBehaviorOverTime: z.object({
774
+ id: z.number().int(),
775
+ startDate: isoDateStringSchema.optional(),
776
+ endDate: isoDateStringSchema.optional(),
777
+ metricType: z.enum([
778
+ "Throughput",
779
+ "WorkItemAge",
780
+ "Wip",
781
+ "CycleTime",
782
+ "Arrivals",
783
+ "FeatureSize"
784
+ ]).optional()
785
+ }),
786
+ lighthouse_portfolio_metrics_processBehaviorOverTime: z.object({
787
+ id: z.number().int(),
788
+ startDate: isoDateStringSchema.optional(),
789
+ endDate: isoDateStringSchema.optional(),
790
+ metricType: z.enum([
791
+ "Throughput",
792
+ "WorkItemAge",
793
+ "Wip",
794
+ "CycleTime",
795
+ "Arrivals",
796
+ "FeatureSize"
797
+ ]).optional()
798
+ }),
618
799
  lighthouse_team_metrics_workItemAge: z.object({
619
800
  id: z.number().int(),
620
801
  startDate: isoDateStringSchema.optional(),
@@ -897,6 +1078,120 @@ var createMcpCoreRuntime = (dependencies) => ({
897
1078
  `portfolio metrics: ${result.error.category} (${result.error.reason})`
898
1079
  );
899
1080
  }
1081
+ if (name === "lighthouse_team_metrics_blockedCountHistory") {
1082
+ const id = getNumericId(argumentsPayload);
1083
+ if (id === null) {
1084
+ return getErrorToolResult("team metrics: invalid id");
1085
+ }
1086
+ const range = getDateRange(argumentsPayload);
1087
+ const result = await client.getTeamBlockedCountHistory(id, range);
1088
+ if (result.ok) {
1089
+ return getSuccessToolResult(
1090
+ `team blockedCountHistory: ${encodePayload(result.value)}`
1091
+ );
1092
+ }
1093
+ return getErrorToolResult(
1094
+ `team metrics: ${result.error.category} (${result.error.reason})`
1095
+ );
1096
+ }
1097
+ if (name === "lighthouse_portfolio_metrics_blockedCountHistory") {
1098
+ const id = getNumericId(argumentsPayload);
1099
+ if (id === null) {
1100
+ return getErrorToolResult("portfolio metrics: invalid id");
1101
+ }
1102
+ const range = getDateRange(argumentsPayload);
1103
+ const result = await client.getPortfolioBlockedCountHistory(id, range);
1104
+ if (result.ok) {
1105
+ return getSuccessToolResult(
1106
+ `portfolio blockedCountHistory: ${encodePayload(result.value)}`
1107
+ );
1108
+ }
1109
+ return getErrorToolResult(
1110
+ `portfolio metrics: ${result.error.category} (${result.error.reason})`
1111
+ );
1112
+ }
1113
+ if (name === "lighthouse_team_metrics_percentilesOverTime") {
1114
+ const id = getNumericId(argumentsPayload);
1115
+ if (id === null) {
1116
+ return getErrorToolResult("team metrics: invalid id");
1117
+ }
1118
+ const range = getDateRange(argumentsPayload);
1119
+ const result = await client.getTeamPercentilesOverTime(
1120
+ id,
1121
+ range,
1122
+ getPercentilesOverTimeMetricType(argumentsPayload),
1123
+ getHorizonArgument(argumentsPayload)
1124
+ );
1125
+ if (result.ok) {
1126
+ return getSuccessToolResult(
1127
+ `team percentilesOverTime: ${encodePayload(result.value)}`
1128
+ );
1129
+ }
1130
+ return getErrorToolResult(
1131
+ `team metrics: ${result.error.category} (${result.error.reason})`
1132
+ );
1133
+ }
1134
+ if (name === "lighthouse_portfolio_metrics_percentilesOverTime") {
1135
+ const id = getNumericId(argumentsPayload);
1136
+ if (id === null) {
1137
+ return getErrorToolResult("portfolio metrics: invalid id");
1138
+ }
1139
+ const range = getDateRange(argumentsPayload);
1140
+ const result = await client.getPortfolioPercentilesOverTime(
1141
+ id,
1142
+ range,
1143
+ getPercentilesOverTimeMetricType(argumentsPayload),
1144
+ getHorizonArgument(argumentsPayload)
1145
+ );
1146
+ if (result.ok) {
1147
+ return getSuccessToolResult(
1148
+ `portfolio percentilesOverTime: ${encodePayload(result.value)}`
1149
+ );
1150
+ }
1151
+ return getErrorToolResult(
1152
+ `portfolio metrics: ${result.error.category} (${result.error.reason})`
1153
+ );
1154
+ }
1155
+ if (name === "lighthouse_team_metrics_processBehaviorOverTime") {
1156
+ const id = getNumericId(argumentsPayload);
1157
+ if (id === null) {
1158
+ return getErrorToolResult("team metrics: invalid id");
1159
+ }
1160
+ const range = getDateRange(argumentsPayload);
1161
+ const result = await client.getTeamProcessBehaviorOverTime(
1162
+ id,
1163
+ range,
1164
+ getProcessBehaviorMetricType(argumentsPayload)
1165
+ );
1166
+ if (result.ok) {
1167
+ return getSuccessToolResult(
1168
+ `team processBehaviorOverTime: ${encodePayload(result.value)}`
1169
+ );
1170
+ }
1171
+ return getErrorToolResult(
1172
+ `team metrics: ${result.error.category} (${result.error.reason})`
1173
+ );
1174
+ }
1175
+ if (name === "lighthouse_portfolio_metrics_processBehaviorOverTime") {
1176
+ const id = getNumericId(argumentsPayload);
1177
+ if (id === null) {
1178
+ return getErrorToolResult("portfolio metrics: invalid id");
1179
+ }
1180
+ const range = getDateRange(argumentsPayload);
1181
+ const result = await client.getPortfolioProcessBehaviorOverTime(
1182
+ id,
1183
+ range,
1184
+ getProcessBehaviorMetricType(argumentsPayload)
1185
+ );
1186
+ if (result.ok) {
1187
+ return getSuccessToolResult(
1188
+ `portfolio processBehaviorOverTime: ${encodePayload(result.value)}`
1189
+ );
1190
+ }
1191
+ return getErrorToolResult(
1192
+ `portfolio metrics: ${result.error.category} (${result.error.reason})`
1193
+ );
1194
+ }
900
1195
  if (name === "lighthouse_team_metrics_cumulativeStateTime") {
901
1196
  const id = getNumericId(argumentsPayload);
902
1197
  if (id === null) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letpeoplework/lighthouse-mcp-core",
3
- "version": "1.4.1",
3
+ "version": "1.6.0",
4
4
  "description": "Shared MCP semantics for Lighthouse",
5
5
  "repository": "https://github.com/LetPeopleWork/lighthouse-clients",
6
6
  "type": "module",
@@ -26,7 +26,7 @@
26
26
  "@modelcontextprotocol/sdk": "^1.26.0",
27
27
  "@toon-format/toon": "^2.1.0",
28
28
  "zod": "^3.24.1",
29
- "@letpeoplework/lighthouse-client": "1.5.0"
29
+ "@letpeoplework/lighthouse-client": "1.7.0"
30
30
  },
31
31
  "scripts": {
32
32
  "build": "tsup src/index.ts --format esm,cjs --dts --clean",