@letpeoplework/lighthouse-mcp-core 1.5.0 → 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: {
@@ -252,6 +277,62 @@ var toolDefinitions = [
252
277
  additionalProperties: false
253
278
  }
254
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
+ },
255
336
  {
256
337
  name: "lighthouse_portfolio_metrics_throughput",
257
338
  description: "Get throughput run-chart data for a portfolio by ID, optionally filtered by start and end dates.",
@@ -610,6 +691,30 @@ var getThroughputFilterView = (argumentsPayload) => {
610
691
  const view = argumentsPayload.view;
611
692
  return view === "raw" || view === "filtered" ? view : void 0;
612
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
+ };
613
718
  var getApplyFilterOverride = (argumentsPayload) => {
614
719
  if (!isObjectRecord(argumentsPayload)) {
615
720
  return void 0;
@@ -677,6 +782,46 @@ var toolInputSchemas = {
677
782
  startDate: isoDateStringSchema.optional(),
678
783
  endDate: isoDateStringSchema.optional()
679
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
+ }),
680
825
  lighthouse_team_metrics_workItemAge: import_zod.z.object({
681
826
  id: import_zod.z.number().int(),
682
827
  startDate: isoDateStringSchema.optional(),
@@ -991,6 +1136,88 @@ var createMcpCoreRuntime = (dependencies) => ({
991
1136
  `portfolio metrics: ${result.error.category} (${result.error.reason})`
992
1137
  );
993
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
+ }
994
1221
  if (name === "lighthouse_team_metrics_cumulativeStateTime") {
995
1222
  const id = getNumericId(argumentsPayload);
996
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_blockedCountHistory" | "lighthouse_portfolio_metrics_blockedCountHistory" | "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";
@@ -262,6 +262,58 @@ type McpRuntimeClient = {
262
262
  readonly reason: string;
263
263
  };
264
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
+ }>;
265
317
  readonly getTeamCumulativeStateTime: (id: number, range?: {
266
318
  readonly startDate: string;
267
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_blockedCountHistory" | "lighthouse_portfolio_metrics_blockedCountHistory" | "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";
@@ -262,6 +262,58 @@ type McpRuntimeClient = {
262
262
  readonly reason: string;
263
263
  };
264
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
+ }>;
265
317
  readonly getTeamCumulativeStateTime: (id: number, range?: {
266
318
  readonly startDate: string;
267
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: {
@@ -226,6 +251,62 @@ var toolDefinitions = [
226
251
  additionalProperties: false
227
252
  }
228
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
+ },
229
310
  {
230
311
  name: "lighthouse_portfolio_metrics_throughput",
231
312
  description: "Get throughput run-chart data for a portfolio by ID, optionally filtered by start and end dates.",
@@ -584,6 +665,30 @@ var getThroughputFilterView = (argumentsPayload) => {
584
665
  const view = argumentsPayload.view;
585
666
  return view === "raw" || view === "filtered" ? view : void 0;
586
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
+ };
587
692
  var getApplyFilterOverride = (argumentsPayload) => {
588
693
  if (!isObjectRecord(argumentsPayload)) {
589
694
  return void 0;
@@ -651,6 +756,46 @@ var toolInputSchemas = {
651
756
  startDate: isoDateStringSchema.optional(),
652
757
  endDate: isoDateStringSchema.optional()
653
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
+ }),
654
799
  lighthouse_team_metrics_workItemAge: z.object({
655
800
  id: z.number().int(),
656
801
  startDate: isoDateStringSchema.optional(),
@@ -965,6 +1110,88 @@ var createMcpCoreRuntime = (dependencies) => ({
965
1110
  `portfolio metrics: ${result.error.category} (${result.error.reason})`
966
1111
  );
967
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
+ }
968
1195
  if (name === "lighthouse_team_metrics_cumulativeStateTime") {
969
1196
  const id = getNumericId(argumentsPayload);
970
1197
  if (id === null) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letpeoplework/lighthouse-mcp-core",
3
- "version": "1.5.0",
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.6.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",