@letpeoplework/lighthouse-mcp-core 1.1.0 → 1.3.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,12 +65,59 @@ 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 cumulativeStateProperty = {
69
+ state: {
70
+ type: "string",
71
+ description: "Workflow state name to drill into (must match a bar's state from the cumulativeStateTime response)."
72
+ }
73
+ };
74
+ var itemIdsProperty = {
75
+ itemIds: {
76
+ type: "array",
77
+ items: { type: "integer" },
78
+ description: "Optional work-item IDs to narrow the computation to a selected subset; omit for all in-scope items."
79
+ }
80
+ };
68
81
  var forecastFilterOverrideProperty = {
69
82
  applyFilterOverride: {
70
83
  type: "boolean",
71
84
  description: "Override the team's forecast-filter setting (Lighthouse v26.5.24.10+). true = apply the team filter; false = skip the filter (raw); omit = respect the team setting."
72
85
  }
73
86
  };
87
+ var recurringBlackoutRuleProperties = {
88
+ weekdays: {
89
+ type: "array",
90
+ items: {
91
+ type: "string",
92
+ enum: [
93
+ "Sunday",
94
+ "Monday",
95
+ "Tuesday",
96
+ "Wednesday",
97
+ "Thursday",
98
+ "Friday",
99
+ "Saturday"
100
+ ]
101
+ },
102
+ description: "Weekdays the rule applies to."
103
+ },
104
+ intervalWeeks: {
105
+ type: "integer",
106
+ description: "Repeat every N weeks (1 = every week)."
107
+ },
108
+ start: {
109
+ type: "string",
110
+ description: "Rule start date in ISO format (YYYY-MM-DD)."
111
+ },
112
+ end: {
113
+ type: ["string", "null"],
114
+ description: "Optional end date in ISO format (YYYY-MM-DD), or null for an open end."
115
+ },
116
+ description: {
117
+ type: "string",
118
+ description: "Human-readable description of the rule."
119
+ }
120
+ };
74
121
  var toolDefinitions = [
75
122
  {
76
123
  name: "lighthouse_health_check",
@@ -248,6 +295,41 @@ var toolDefinitions = [
248
295
  description: "List deliveries for a portfolio by portfolio ID.",
249
296
  inputSchema: idInputSchema
250
297
  },
298
+ {
299
+ name: "lighthouse_blackout_list",
300
+ description: "List the recurring blackout rules (recurring non-working days excluded from forecasts). Requires Lighthouse newer than v26.5.29.5.",
301
+ inputSchema: emptyInputSchema
302
+ },
303
+ {
304
+ name: "lighthouse_blackout_create",
305
+ description: "Create a recurring blackout rule (weekdays + every-N-weeks interval + start date + optional open end). Premium, system-admin only. Requires Lighthouse newer than v26.5.29.5.",
306
+ inputSchema: {
307
+ type: "object",
308
+ properties: {
309
+ ...recurringBlackoutRuleProperties
310
+ },
311
+ required: ["weekdays", "intervalWeeks", "start", "description"],
312
+ additionalProperties: false
313
+ }
314
+ },
315
+ {
316
+ name: "lighthouse_blackout_update",
317
+ description: "Update a recurring blackout rule by ID. Premium, system-admin only. Requires Lighthouse newer than v26.5.29.5.",
318
+ inputSchema: {
319
+ type: "object",
320
+ properties: {
321
+ ...idInputSchema.properties,
322
+ ...recurringBlackoutRuleProperties
323
+ },
324
+ required: ["id", "weekdays", "intervalWeeks", "start", "description"],
325
+ additionalProperties: false
326
+ }
327
+ },
328
+ {
329
+ name: "lighthouse_blackout_delete",
330
+ description: "Delete a recurring blackout rule by ID. Premium, system-admin only. Requires Lighthouse newer than v26.5.29.5.",
331
+ inputSchema: idInputSchema
332
+ },
251
333
  {
252
334
  name: "lighthouse_forecast_manual",
253
335
  description: "Run a manual forecast for a team by ID with optional remaining items and target date. Pass applyFilterOverride=true to apply the team's forecast filter, false to skip it, or omit to respect the team setting (Lighthouse v26.5.24.10+). The response includes filterApplied (boolean) and excludedSummary (string) when a filter was applied.",
@@ -303,6 +385,90 @@ var toolDefinitions = [
303
385
  ],
304
386
  additionalProperties: false
305
387
  }
388
+ },
389
+ {
390
+ name: "lighthouse_team_metrics_cumulativeStateTime",
391
+ description: "Get cumulative time-per-state bar data for a team by ID: one entry per Doing-category workflow state with total/completed/ongoing contribution days and item counts. Optionally filter by date range and a subset of work-item IDs.",
392
+ inputSchema: {
393
+ type: "object",
394
+ properties: {
395
+ ...idInputSchema.properties,
396
+ ...dateRangeProperties,
397
+ ...itemIdsProperty
398
+ },
399
+ required: ["id"],
400
+ additionalProperties: false
401
+ }
402
+ },
403
+ {
404
+ name: "lighthouse_team_metrics_cumulativeStateTimeItems",
405
+ description: "Get the per-item drill-down for ONE state of a team's cumulative time-per-state chart: the work items that contributed to that state, with days contributed. Requires the state name.",
406
+ inputSchema: {
407
+ type: "object",
408
+ properties: {
409
+ ...idInputSchema.properties,
410
+ ...cumulativeStateProperty,
411
+ ...dateRangeProperties,
412
+ ...itemIdsProperty
413
+ },
414
+ required: ["id", "state"],
415
+ additionalProperties: false
416
+ }
417
+ },
418
+ {
419
+ name: "lighthouse_team_metrics_cumulativeStateTimeCandidates",
420
+ description: "List the work items selectable in a team's cumulative time-per-state item picker for the window (the in-scope candidate set). Search keys are referenceId and title.",
421
+ inputSchema: {
422
+ type: "object",
423
+ properties: {
424
+ ...idInputSchema.properties,
425
+ ...dateRangeProperties
426
+ },
427
+ required: ["id"],
428
+ additionalProperties: false
429
+ }
430
+ },
431
+ {
432
+ name: "lighthouse_portfolio_metrics_cumulativeStateTime",
433
+ description: "Get cumulative time-per-state bar data for a portfolio by ID: one entry per Doing-category workflow state with total/completed/ongoing contribution days and item counts. Optionally filter by date range and a subset of work-item IDs.",
434
+ inputSchema: {
435
+ type: "object",
436
+ properties: {
437
+ ...idInputSchema.properties,
438
+ ...dateRangeProperties,
439
+ ...itemIdsProperty
440
+ },
441
+ required: ["id"],
442
+ additionalProperties: false
443
+ }
444
+ },
445
+ {
446
+ name: "lighthouse_portfolio_metrics_cumulativeStateTimeItems",
447
+ description: "Get the per-item drill-down for ONE state of a portfolio's cumulative time-per-state chart: the work items that contributed to that state, with days contributed. Requires the state name.",
448
+ inputSchema: {
449
+ type: "object",
450
+ properties: {
451
+ ...idInputSchema.properties,
452
+ ...cumulativeStateProperty,
453
+ ...dateRangeProperties,
454
+ ...itemIdsProperty
455
+ },
456
+ required: ["id", "state"],
457
+ additionalProperties: false
458
+ }
459
+ },
460
+ {
461
+ name: "lighthouse_portfolio_metrics_cumulativeStateTimeCandidates",
462
+ description: "List the work items selectable in a portfolio's cumulative time-per-state item picker for the window (the in-scope candidate set). Search keys are referenceId and title.",
463
+ inputSchema: {
464
+ type: "object",
465
+ properties: {
466
+ ...idInputSchema.properties,
467
+ ...dateRangeProperties
468
+ },
469
+ required: ["id"],
470
+ additionalProperties: false
471
+ }
306
472
  }
307
473
  ];
308
474
  var encodePayload = (value) => {
@@ -354,6 +520,26 @@ var getDateRange = (argumentsPayload) => {
354
520
  }
355
521
  return void 0;
356
522
  };
523
+ var getStringArgument = (argumentsPayload, key) => {
524
+ if (!isObjectRecord(argumentsPayload)) {
525
+ return void 0;
526
+ }
527
+ const value = argumentsPayload[key];
528
+ return typeof value === "string" ? value : void 0;
529
+ };
530
+ var getItemIdsArgument = (argumentsPayload) => {
531
+ if (!isObjectRecord(argumentsPayload)) {
532
+ return void 0;
533
+ }
534
+ const value = argumentsPayload.itemIds;
535
+ if (!Array.isArray(value)) {
536
+ return void 0;
537
+ }
538
+ const ids = value.filter(
539
+ (entry) => typeof entry === "number" && Number.isInteger(entry)
540
+ );
541
+ return ids.length > 0 ? ids : void 0;
542
+ };
357
543
  var getThroughputFilterView = (argumentsPayload) => {
358
544
  if (!isObjectRecord(argumentsPayload)) {
359
545
  return void 0;
@@ -369,6 +555,22 @@ var getApplyFilterOverride = (argumentsPayload) => {
369
555
  return typeof value === "boolean" ? value : void 0;
370
556
  };
371
557
  var isoDateStringSchema = import_zod.z.string().regex(/^\d{4}-\d{2}-\d{2}$/u, "Expected ISO date in YYYY-MM-DD format.");
558
+ var weekdaySchema = import_zod.z.enum([
559
+ "Sunday",
560
+ "Monday",
561
+ "Tuesday",
562
+ "Wednesday",
563
+ "Thursday",
564
+ "Friday",
565
+ "Saturday"
566
+ ]);
567
+ var recurringBlackoutRuleInputSchema = import_zod.z.object({
568
+ weekdays: import_zod.z.array(weekdaySchema),
569
+ intervalWeeks: import_zod.z.number().int(),
570
+ start: isoDateStringSchema,
571
+ end: isoDateStringSchema.nullable().optional(),
572
+ description: import_zod.z.string()
573
+ });
372
574
  var toolInputSchemas = {
373
575
  lighthouse_health_check: import_zod.z.object({}),
374
576
  lighthouse_version_get: import_zod.z.object({}),
@@ -416,12 +618,54 @@ var toolInputSchemas = {
416
618
  startDate: isoDateStringSchema.optional(),
417
619
  endDate: isoDateStringSchema.optional()
418
620
  }),
621
+ lighthouse_team_metrics_cumulativeStateTime: import_zod.z.object({
622
+ id: import_zod.z.number().int(),
623
+ startDate: isoDateStringSchema.optional(),
624
+ endDate: isoDateStringSchema.optional(),
625
+ itemIds: import_zod.z.array(import_zod.z.number().int()).optional()
626
+ }),
627
+ lighthouse_team_metrics_cumulativeStateTimeItems: import_zod.z.object({
628
+ id: import_zod.z.number().int(),
629
+ state: import_zod.z.string(),
630
+ startDate: isoDateStringSchema.optional(),
631
+ endDate: isoDateStringSchema.optional(),
632
+ itemIds: import_zod.z.array(import_zod.z.number().int()).optional()
633
+ }),
634
+ lighthouse_team_metrics_cumulativeStateTimeCandidates: import_zod.z.object({
635
+ id: import_zod.z.number().int(),
636
+ startDate: isoDateStringSchema.optional(),
637
+ endDate: isoDateStringSchema.optional()
638
+ }),
639
+ lighthouse_portfolio_metrics_cumulativeStateTime: import_zod.z.object({
640
+ id: import_zod.z.number().int(),
641
+ startDate: isoDateStringSchema.optional(),
642
+ endDate: isoDateStringSchema.optional(),
643
+ itemIds: import_zod.z.array(import_zod.z.number().int()).optional()
644
+ }),
645
+ lighthouse_portfolio_metrics_cumulativeStateTimeItems: import_zod.z.object({
646
+ id: import_zod.z.number().int(),
647
+ state: import_zod.z.string(),
648
+ startDate: isoDateStringSchema.optional(),
649
+ endDate: isoDateStringSchema.optional(),
650
+ itemIds: import_zod.z.array(import_zod.z.number().int()).optional()
651
+ }),
652
+ lighthouse_portfolio_metrics_cumulativeStateTimeCandidates: import_zod.z.object({
653
+ id: import_zod.z.number().int(),
654
+ startDate: isoDateStringSchema.optional(),
655
+ endDate: isoDateStringSchema.optional()
656
+ }),
419
657
  lighthouse_feature_get: import_zod.z.object({
420
658
  ids: import_zod.z.array(import_zod.z.number().int()).optional(),
421
659
  refs: import_zod.z.array(import_zod.z.string()).optional()
422
660
  }),
423
661
  lighthouse_feature_workitems: import_zod.z.object({ id: import_zod.z.number().int() }),
424
662
  lighthouse_delivery_list: import_zod.z.object({ id: import_zod.z.number().int() }),
663
+ lighthouse_blackout_list: import_zod.z.object({}),
664
+ lighthouse_blackout_create: recurringBlackoutRuleInputSchema,
665
+ lighthouse_blackout_update: recurringBlackoutRuleInputSchema.extend({
666
+ id: import_zod.z.number().int()
667
+ }),
668
+ lighthouse_blackout_delete: import_zod.z.object({ id: import_zod.z.number().int() }),
425
669
  lighthouse_forecast_manual: import_zod.z.object({
426
670
  id: import_zod.z.number().int(),
427
671
  remainingItems: import_zod.z.number().int().optional(),
@@ -437,7 +681,7 @@ var toolInputSchemas = {
437
681
  applyFilterOverride: import_zod.z.boolean().optional()
438
682
  })
439
683
  };
440
- var isReadOnlyTool = (toolName) => !toolName.endsWith("_refresh");
684
+ var isReadOnlyTool = (toolName) => !(toolName.endsWith("_refresh") || toolName.endsWith("_create") || toolName.endsWith("_update") || toolName.endsWith("_delete"));
441
685
  var createMcpCoreRuntime = (dependencies) => ({
442
686
  listTools: () => toolDefinitions,
443
687
  callTool: async (name, argumentsPayload) => {
@@ -594,6 +838,128 @@ var createMcpCoreRuntime = (dependencies) => ({
594
838
  `team metrics: ${result.error.category} (${result.error.reason})`
595
839
  );
596
840
  }
841
+ if (name === "lighthouse_team_metrics_cumulativeStateTime") {
842
+ const id = getNumericId(argumentsPayload);
843
+ if (id === null) {
844
+ return getErrorToolResult("team metrics: invalid id");
845
+ }
846
+ const result = await client.getTeamCumulativeStateTime(
847
+ id,
848
+ getDateRange(argumentsPayload),
849
+ getItemIdsArgument(argumentsPayload)
850
+ );
851
+ if (result.ok) {
852
+ return getSuccessToolResult(
853
+ `team cumulativeStateTime: ${encodePayload(result.value)}`
854
+ );
855
+ }
856
+ return getErrorToolResult(
857
+ `team metrics: ${result.error.category} (${result.error.reason})`
858
+ );
859
+ }
860
+ if (name === "lighthouse_team_metrics_cumulativeStateTimeItems") {
861
+ const id = getNumericId(argumentsPayload);
862
+ if (id === null) {
863
+ return getErrorToolResult("team metrics: invalid id");
864
+ }
865
+ const state = getStringArgument(argumentsPayload, "state");
866
+ if (state === void 0) {
867
+ return getErrorToolResult("team metrics: missing state");
868
+ }
869
+ const result = await client.getTeamCumulativeStateTimeItems(
870
+ id,
871
+ state,
872
+ getDateRange(argumentsPayload),
873
+ getItemIdsArgument(argumentsPayload)
874
+ );
875
+ if (result.ok) {
876
+ return getSuccessToolResult(
877
+ `team cumulativeStateTimeItems: ${encodePayload(result.value)}`
878
+ );
879
+ }
880
+ return getErrorToolResult(
881
+ `team metrics: ${result.error.category} (${result.error.reason})`
882
+ );
883
+ }
884
+ if (name === "lighthouse_team_metrics_cumulativeStateTimeCandidates") {
885
+ const id = getNumericId(argumentsPayload);
886
+ if (id === null) {
887
+ return getErrorToolResult("team metrics: invalid id");
888
+ }
889
+ const result = await client.getTeamCumulativeStateTimeCandidates(
890
+ id,
891
+ getDateRange(argumentsPayload)
892
+ );
893
+ if (result.ok) {
894
+ return getSuccessToolResult(
895
+ `team cumulativeStateTimeCandidates: ${encodePayload(result.value)}`
896
+ );
897
+ }
898
+ return getErrorToolResult(
899
+ `team metrics: ${result.error.category} (${result.error.reason})`
900
+ );
901
+ }
902
+ if (name === "lighthouse_portfolio_metrics_cumulativeStateTime") {
903
+ const id = getNumericId(argumentsPayload);
904
+ if (id === null) {
905
+ return getErrorToolResult("portfolio metrics: invalid id");
906
+ }
907
+ const result = await client.getPortfolioCumulativeStateTime(
908
+ id,
909
+ getDateRange(argumentsPayload),
910
+ getItemIdsArgument(argumentsPayload)
911
+ );
912
+ if (result.ok) {
913
+ return getSuccessToolResult(
914
+ `portfolio cumulativeStateTime: ${encodePayload(result.value)}`
915
+ );
916
+ }
917
+ return getErrorToolResult(
918
+ `portfolio metrics: ${result.error.category} (${result.error.reason})`
919
+ );
920
+ }
921
+ if (name === "lighthouse_portfolio_metrics_cumulativeStateTimeItems") {
922
+ const id = getNumericId(argumentsPayload);
923
+ if (id === null) {
924
+ return getErrorToolResult("portfolio metrics: invalid id");
925
+ }
926
+ const state = getStringArgument(argumentsPayload, "state");
927
+ if (state === void 0) {
928
+ return getErrorToolResult("portfolio metrics: missing state");
929
+ }
930
+ const result = await client.getPortfolioCumulativeStateTimeItems(
931
+ id,
932
+ state,
933
+ getDateRange(argumentsPayload),
934
+ getItemIdsArgument(argumentsPayload)
935
+ );
936
+ if (result.ok) {
937
+ return getSuccessToolResult(
938
+ `portfolio cumulativeStateTimeItems: ${encodePayload(result.value)}`
939
+ );
940
+ }
941
+ return getErrorToolResult(
942
+ `portfolio metrics: ${result.error.category} (${result.error.reason})`
943
+ );
944
+ }
945
+ if (name === "lighthouse_portfolio_metrics_cumulativeStateTimeCandidates") {
946
+ const id = getNumericId(argumentsPayload);
947
+ if (id === null) {
948
+ return getErrorToolResult("portfolio metrics: invalid id");
949
+ }
950
+ const result = await client.getPortfolioCumulativeStateTimeCandidates(
951
+ id,
952
+ getDateRange(argumentsPayload)
953
+ );
954
+ if (result.ok) {
955
+ return getSuccessToolResult(
956
+ `portfolio cumulativeStateTimeCandidates: ${encodePayload(result.value)}`
957
+ );
958
+ }
959
+ return getErrorToolResult(
960
+ `portfolio metrics: ${result.error.category} (${result.error.reason})`
961
+ );
962
+ }
597
963
  if (name === "lighthouse_portfolio_metrics_throughput") {
598
964
  const id = getNumericId(argumentsPayload);
599
965
  if (id === null) {
@@ -743,6 +1109,59 @@ var createMcpCoreRuntime = (dependencies) => ({
743
1109
  `delivery: ${result.error.category} (${result.error.reason})`
744
1110
  );
745
1111
  }
1112
+ if (name === "lighthouse_blackout_list") {
1113
+ const result = await client.getRecurringBlackoutRules();
1114
+ if (result.ok) {
1115
+ return getSuccessToolResult(
1116
+ `recurringBlackoutRules: ${encodePayload(result.value)}`
1117
+ );
1118
+ }
1119
+ return getErrorToolResult(
1120
+ `blackout: ${result.error.category} (${result.error.reason})`
1121
+ );
1122
+ }
1123
+ if (name === "lighthouse_blackout_create") {
1124
+ const payload = isObjectRecord(argumentsPayload) ? argumentsPayload : {};
1125
+ const result = await client.createRecurringBlackoutRule(payload);
1126
+ if (result.ok) {
1127
+ return getSuccessToolResult(
1128
+ `recurringBlackoutRule: ${encodePayload(result.value)}`
1129
+ );
1130
+ }
1131
+ return getErrorToolResult(
1132
+ `blackout: ${result.error.category} (${result.error.reason})`
1133
+ );
1134
+ }
1135
+ if (name === "lighthouse_blackout_update") {
1136
+ const id = getNumericId(argumentsPayload);
1137
+ if (id === null) {
1138
+ return getErrorToolResult("blackout: invalid id (rule id required)");
1139
+ }
1140
+ const payload = isObjectRecord(argumentsPayload) ? argumentsPayload : {};
1141
+ const { id: _ignoredId, ...rulePayload } = payload;
1142
+ const result = await client.updateRecurringBlackoutRule(id, rulePayload);
1143
+ if (result.ok) {
1144
+ return getSuccessToolResult(
1145
+ `recurringBlackoutRule: ${encodePayload(result.value)}`
1146
+ );
1147
+ }
1148
+ return getErrorToolResult(
1149
+ `blackout: ${result.error.category} (${result.error.reason})`
1150
+ );
1151
+ }
1152
+ if (name === "lighthouse_blackout_delete") {
1153
+ const id = getNumericId(argumentsPayload);
1154
+ if (id === null) {
1155
+ return getErrorToolResult("blackout: invalid id (rule id required)");
1156
+ }
1157
+ const result = await client.deleteRecurringBlackoutRule(id);
1158
+ if (result.ok) {
1159
+ return getSuccessToolResult(`recurringBlackoutRule deleted: ${id}`);
1160
+ }
1161
+ return getErrorToolResult(
1162
+ `blackout: ${result.error.category} (${result.error.reason})`
1163
+ );
1164
+ }
746
1165
  if (name === "lighthouse_forecast_manual") {
747
1166
  const id = getNumericId(argumentsPayload);
748
1167
  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_workItemAge" | "lighthouse_team_metrics_totalWorkItemAge" | "lighthouse_portfolio_metrics_throughput" | "lighthouse_portfolio_metrics_workItemAge" | "lighthouse_portfolio_metrics_totalWorkItemAge" | "lighthouse_feature_get" | "lighthouse_feature_workitems" | "lighthouse_delivery_list" | "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_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";
19
19
  readonly description: string;
20
20
  readonly inputSchema: {
21
21
  readonly type: "object";
@@ -26,7 +26,7 @@ type McpToolDefinition = {
26
26
  };
27
27
  type McpRuntimeClient = {
28
28
  readonly checkConnectivity: () => Promise<{
29
- readonly category: "success" | "unreachable" | "misconfigured" | "unauthorized" | "dependency-failure" | "unexpected";
29
+ readonly category: "success" | "unreachable" | "misconfigured" | "unauthorized" | "dependency-failure" | "concurrency-conflict" | "unexpected";
30
30
  readonly reason?: string;
31
31
  }>;
32
32
  readonly getVersion: () => Promise<{
@@ -210,6 +210,84 @@ type McpRuntimeClient = {
210
210
  readonly reason: string;
211
211
  };
212
212
  }>;
213
+ readonly getTeamCumulativeStateTime: (id: number, range?: {
214
+ readonly startDate: string;
215
+ readonly endDate: string;
216
+ }, itemIds?: readonly number[]) => Promise<{
217
+ readonly ok: true;
218
+ readonly value: unknown;
219
+ } | {
220
+ readonly ok: false;
221
+ readonly error: {
222
+ readonly category: string;
223
+ readonly reason: string;
224
+ };
225
+ }>;
226
+ readonly getTeamCumulativeStateTimeItems: (id: number, state: string, range?: {
227
+ readonly startDate: string;
228
+ readonly endDate: string;
229
+ }, itemIds?: readonly number[]) => Promise<{
230
+ readonly ok: true;
231
+ readonly value: unknown;
232
+ } | {
233
+ readonly ok: false;
234
+ readonly error: {
235
+ readonly category: string;
236
+ readonly reason: string;
237
+ };
238
+ }>;
239
+ readonly getTeamCumulativeStateTimeCandidates: (id: number, range?: {
240
+ readonly startDate: string;
241
+ readonly endDate: string;
242
+ }) => Promise<{
243
+ readonly ok: true;
244
+ readonly value: unknown;
245
+ } | {
246
+ readonly ok: false;
247
+ readonly error: {
248
+ readonly category: string;
249
+ readonly reason: string;
250
+ };
251
+ }>;
252
+ readonly getPortfolioCumulativeStateTime: (id: number, range?: {
253
+ readonly startDate: string;
254
+ readonly endDate: string;
255
+ }, itemIds?: readonly number[]) => Promise<{
256
+ readonly ok: true;
257
+ readonly value: unknown;
258
+ } | {
259
+ readonly ok: false;
260
+ readonly error: {
261
+ readonly category: string;
262
+ readonly reason: string;
263
+ };
264
+ }>;
265
+ readonly getPortfolioCumulativeStateTimeItems: (id: number, state: string, range?: {
266
+ readonly startDate: string;
267
+ readonly endDate: string;
268
+ }, itemIds?: readonly number[]) => Promise<{
269
+ readonly ok: true;
270
+ readonly value: unknown;
271
+ } | {
272
+ readonly ok: false;
273
+ readonly error: {
274
+ readonly category: string;
275
+ readonly reason: string;
276
+ };
277
+ }>;
278
+ readonly getPortfolioCumulativeStateTimeCandidates: (id: number, range?: {
279
+ readonly startDate: string;
280
+ readonly endDate: string;
281
+ }) => Promise<{
282
+ readonly ok: true;
283
+ readonly value: unknown;
284
+ } | {
285
+ readonly ok: false;
286
+ readonly error: {
287
+ readonly category: string;
288
+ readonly reason: string;
289
+ };
290
+ }>;
213
291
  readonly getFeaturesByIds: (ids: readonly number[]) => Promise<{
214
292
  readonly ok: true;
215
293
  readonly value: readonly unknown[];
@@ -280,6 +358,46 @@ type McpRuntimeClient = {
280
358
  readonly reason: string;
281
359
  };
282
360
  }>;
361
+ readonly getRecurringBlackoutRules: () => Promise<{
362
+ readonly ok: true;
363
+ readonly value: readonly unknown[];
364
+ } | {
365
+ readonly ok: false;
366
+ readonly error: {
367
+ readonly category: string;
368
+ readonly reason: string;
369
+ };
370
+ }>;
371
+ readonly createRecurringBlackoutRule: (payload: Readonly<Record<string, unknown>>) => Promise<{
372
+ readonly ok: true;
373
+ readonly value: unknown;
374
+ } | {
375
+ readonly ok: false;
376
+ readonly error: {
377
+ readonly category: string;
378
+ readonly reason: string;
379
+ };
380
+ }>;
381
+ readonly updateRecurringBlackoutRule: (id: number, payload: Readonly<Record<string, unknown>>) => Promise<{
382
+ readonly ok: true;
383
+ readonly value: unknown;
384
+ } | {
385
+ readonly ok: false;
386
+ readonly error: {
387
+ readonly category: string;
388
+ readonly reason: string;
389
+ };
390
+ }>;
391
+ readonly deleteRecurringBlackoutRule: (id: number) => Promise<{
392
+ readonly ok: true;
393
+ readonly value: undefined;
394
+ } | {
395
+ readonly ok: false;
396
+ readonly error: {
397
+ readonly category: string;
398
+ readonly reason: string;
399
+ };
400
+ }>;
283
401
  readonly runManualForecast: (teamId: number, payload: {
284
402
  readonly remainingItems?: number;
285
403
  readonly targetDate?: 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_workItemAge" | "lighthouse_team_metrics_totalWorkItemAge" | "lighthouse_portfolio_metrics_throughput" | "lighthouse_portfolio_metrics_workItemAge" | "lighthouse_portfolio_metrics_totalWorkItemAge" | "lighthouse_feature_get" | "lighthouse_feature_workitems" | "lighthouse_delivery_list" | "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_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";
19
19
  readonly description: string;
20
20
  readonly inputSchema: {
21
21
  readonly type: "object";
@@ -26,7 +26,7 @@ type McpToolDefinition = {
26
26
  };
27
27
  type McpRuntimeClient = {
28
28
  readonly checkConnectivity: () => Promise<{
29
- readonly category: "success" | "unreachable" | "misconfigured" | "unauthorized" | "dependency-failure" | "unexpected";
29
+ readonly category: "success" | "unreachable" | "misconfigured" | "unauthorized" | "dependency-failure" | "concurrency-conflict" | "unexpected";
30
30
  readonly reason?: string;
31
31
  }>;
32
32
  readonly getVersion: () => Promise<{
@@ -210,6 +210,84 @@ type McpRuntimeClient = {
210
210
  readonly reason: string;
211
211
  };
212
212
  }>;
213
+ readonly getTeamCumulativeStateTime: (id: number, range?: {
214
+ readonly startDate: string;
215
+ readonly endDate: string;
216
+ }, itemIds?: readonly number[]) => Promise<{
217
+ readonly ok: true;
218
+ readonly value: unknown;
219
+ } | {
220
+ readonly ok: false;
221
+ readonly error: {
222
+ readonly category: string;
223
+ readonly reason: string;
224
+ };
225
+ }>;
226
+ readonly getTeamCumulativeStateTimeItems: (id: number, state: string, range?: {
227
+ readonly startDate: string;
228
+ readonly endDate: string;
229
+ }, itemIds?: readonly number[]) => Promise<{
230
+ readonly ok: true;
231
+ readonly value: unknown;
232
+ } | {
233
+ readonly ok: false;
234
+ readonly error: {
235
+ readonly category: string;
236
+ readonly reason: string;
237
+ };
238
+ }>;
239
+ readonly getTeamCumulativeStateTimeCandidates: (id: number, range?: {
240
+ readonly startDate: string;
241
+ readonly endDate: string;
242
+ }) => Promise<{
243
+ readonly ok: true;
244
+ readonly value: unknown;
245
+ } | {
246
+ readonly ok: false;
247
+ readonly error: {
248
+ readonly category: string;
249
+ readonly reason: string;
250
+ };
251
+ }>;
252
+ readonly getPortfolioCumulativeStateTime: (id: number, range?: {
253
+ readonly startDate: string;
254
+ readonly endDate: string;
255
+ }, itemIds?: readonly number[]) => Promise<{
256
+ readonly ok: true;
257
+ readonly value: unknown;
258
+ } | {
259
+ readonly ok: false;
260
+ readonly error: {
261
+ readonly category: string;
262
+ readonly reason: string;
263
+ };
264
+ }>;
265
+ readonly getPortfolioCumulativeStateTimeItems: (id: number, state: string, range?: {
266
+ readonly startDate: string;
267
+ readonly endDate: string;
268
+ }, itemIds?: readonly number[]) => Promise<{
269
+ readonly ok: true;
270
+ readonly value: unknown;
271
+ } | {
272
+ readonly ok: false;
273
+ readonly error: {
274
+ readonly category: string;
275
+ readonly reason: string;
276
+ };
277
+ }>;
278
+ readonly getPortfolioCumulativeStateTimeCandidates: (id: number, range?: {
279
+ readonly startDate: string;
280
+ readonly endDate: string;
281
+ }) => Promise<{
282
+ readonly ok: true;
283
+ readonly value: unknown;
284
+ } | {
285
+ readonly ok: false;
286
+ readonly error: {
287
+ readonly category: string;
288
+ readonly reason: string;
289
+ };
290
+ }>;
213
291
  readonly getFeaturesByIds: (ids: readonly number[]) => Promise<{
214
292
  readonly ok: true;
215
293
  readonly value: readonly unknown[];
@@ -280,6 +358,46 @@ type McpRuntimeClient = {
280
358
  readonly reason: string;
281
359
  };
282
360
  }>;
361
+ readonly getRecurringBlackoutRules: () => Promise<{
362
+ readonly ok: true;
363
+ readonly value: readonly unknown[];
364
+ } | {
365
+ readonly ok: false;
366
+ readonly error: {
367
+ readonly category: string;
368
+ readonly reason: string;
369
+ };
370
+ }>;
371
+ readonly createRecurringBlackoutRule: (payload: Readonly<Record<string, unknown>>) => Promise<{
372
+ readonly ok: true;
373
+ readonly value: unknown;
374
+ } | {
375
+ readonly ok: false;
376
+ readonly error: {
377
+ readonly category: string;
378
+ readonly reason: string;
379
+ };
380
+ }>;
381
+ readonly updateRecurringBlackoutRule: (id: number, payload: Readonly<Record<string, unknown>>) => Promise<{
382
+ readonly ok: true;
383
+ readonly value: unknown;
384
+ } | {
385
+ readonly ok: false;
386
+ readonly error: {
387
+ readonly category: string;
388
+ readonly reason: string;
389
+ };
390
+ }>;
391
+ readonly deleteRecurringBlackoutRule: (id: number) => Promise<{
392
+ readonly ok: true;
393
+ readonly value: undefined;
394
+ } | {
395
+ readonly ok: false;
396
+ readonly error: {
397
+ readonly category: string;
398
+ readonly reason: string;
399
+ };
400
+ }>;
283
401
  readonly runManualForecast: (teamId: number, payload: {
284
402
  readonly remainingItems?: number;
285
403
  readonly targetDate?: string;
package/dist/index.js CHANGED
@@ -39,12 +39,59 @@ 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 cumulativeStateProperty = {
43
+ state: {
44
+ type: "string",
45
+ description: "Workflow state name to drill into (must match a bar's state from the cumulativeStateTime response)."
46
+ }
47
+ };
48
+ var itemIdsProperty = {
49
+ itemIds: {
50
+ type: "array",
51
+ items: { type: "integer" },
52
+ description: "Optional work-item IDs to narrow the computation to a selected subset; omit for all in-scope items."
53
+ }
54
+ };
42
55
  var forecastFilterOverrideProperty = {
43
56
  applyFilterOverride: {
44
57
  type: "boolean",
45
58
  description: "Override the team's forecast-filter setting (Lighthouse v26.5.24.10+). true = apply the team filter; false = skip the filter (raw); omit = respect the team setting."
46
59
  }
47
60
  };
61
+ var recurringBlackoutRuleProperties = {
62
+ weekdays: {
63
+ type: "array",
64
+ items: {
65
+ type: "string",
66
+ enum: [
67
+ "Sunday",
68
+ "Monday",
69
+ "Tuesday",
70
+ "Wednesday",
71
+ "Thursday",
72
+ "Friday",
73
+ "Saturday"
74
+ ]
75
+ },
76
+ description: "Weekdays the rule applies to."
77
+ },
78
+ intervalWeeks: {
79
+ type: "integer",
80
+ description: "Repeat every N weeks (1 = every week)."
81
+ },
82
+ start: {
83
+ type: "string",
84
+ description: "Rule start date in ISO format (YYYY-MM-DD)."
85
+ },
86
+ end: {
87
+ type: ["string", "null"],
88
+ description: "Optional end date in ISO format (YYYY-MM-DD), or null for an open end."
89
+ },
90
+ description: {
91
+ type: "string",
92
+ description: "Human-readable description of the rule."
93
+ }
94
+ };
48
95
  var toolDefinitions = [
49
96
  {
50
97
  name: "lighthouse_health_check",
@@ -222,6 +269,41 @@ var toolDefinitions = [
222
269
  description: "List deliveries for a portfolio by portfolio ID.",
223
270
  inputSchema: idInputSchema
224
271
  },
272
+ {
273
+ name: "lighthouse_blackout_list",
274
+ description: "List the recurring blackout rules (recurring non-working days excluded from forecasts). Requires Lighthouse newer than v26.5.29.5.",
275
+ inputSchema: emptyInputSchema
276
+ },
277
+ {
278
+ name: "lighthouse_blackout_create",
279
+ description: "Create a recurring blackout rule (weekdays + every-N-weeks interval + start date + optional open end). Premium, system-admin only. Requires Lighthouse newer than v26.5.29.5.",
280
+ inputSchema: {
281
+ type: "object",
282
+ properties: {
283
+ ...recurringBlackoutRuleProperties
284
+ },
285
+ required: ["weekdays", "intervalWeeks", "start", "description"],
286
+ additionalProperties: false
287
+ }
288
+ },
289
+ {
290
+ name: "lighthouse_blackout_update",
291
+ description: "Update a recurring blackout rule by ID. Premium, system-admin only. Requires Lighthouse newer than v26.5.29.5.",
292
+ inputSchema: {
293
+ type: "object",
294
+ properties: {
295
+ ...idInputSchema.properties,
296
+ ...recurringBlackoutRuleProperties
297
+ },
298
+ required: ["id", "weekdays", "intervalWeeks", "start", "description"],
299
+ additionalProperties: false
300
+ }
301
+ },
302
+ {
303
+ name: "lighthouse_blackout_delete",
304
+ description: "Delete a recurring blackout rule by ID. Premium, system-admin only. Requires Lighthouse newer than v26.5.29.5.",
305
+ inputSchema: idInputSchema
306
+ },
225
307
  {
226
308
  name: "lighthouse_forecast_manual",
227
309
  description: "Run a manual forecast for a team by ID with optional remaining items and target date. Pass applyFilterOverride=true to apply the team's forecast filter, false to skip it, or omit to respect the team setting (Lighthouse v26.5.24.10+). The response includes filterApplied (boolean) and excludedSummary (string) when a filter was applied.",
@@ -277,6 +359,90 @@ var toolDefinitions = [
277
359
  ],
278
360
  additionalProperties: false
279
361
  }
362
+ },
363
+ {
364
+ name: "lighthouse_team_metrics_cumulativeStateTime",
365
+ description: "Get cumulative time-per-state bar data for a team by ID: one entry per Doing-category workflow state with total/completed/ongoing contribution days and item counts. Optionally filter by date range and a subset of work-item IDs.",
366
+ inputSchema: {
367
+ type: "object",
368
+ properties: {
369
+ ...idInputSchema.properties,
370
+ ...dateRangeProperties,
371
+ ...itemIdsProperty
372
+ },
373
+ required: ["id"],
374
+ additionalProperties: false
375
+ }
376
+ },
377
+ {
378
+ name: "lighthouse_team_metrics_cumulativeStateTimeItems",
379
+ description: "Get the per-item drill-down for ONE state of a team's cumulative time-per-state chart: the work items that contributed to that state, with days contributed. Requires the state name.",
380
+ inputSchema: {
381
+ type: "object",
382
+ properties: {
383
+ ...idInputSchema.properties,
384
+ ...cumulativeStateProperty,
385
+ ...dateRangeProperties,
386
+ ...itemIdsProperty
387
+ },
388
+ required: ["id", "state"],
389
+ additionalProperties: false
390
+ }
391
+ },
392
+ {
393
+ name: "lighthouse_team_metrics_cumulativeStateTimeCandidates",
394
+ description: "List the work items selectable in a team's cumulative time-per-state item picker for the window (the in-scope candidate set). Search keys are referenceId and title.",
395
+ inputSchema: {
396
+ type: "object",
397
+ properties: {
398
+ ...idInputSchema.properties,
399
+ ...dateRangeProperties
400
+ },
401
+ required: ["id"],
402
+ additionalProperties: false
403
+ }
404
+ },
405
+ {
406
+ name: "lighthouse_portfolio_metrics_cumulativeStateTime",
407
+ description: "Get cumulative time-per-state bar data for a portfolio by ID: one entry per Doing-category workflow state with total/completed/ongoing contribution days and item counts. Optionally filter by date range and a subset of work-item IDs.",
408
+ inputSchema: {
409
+ type: "object",
410
+ properties: {
411
+ ...idInputSchema.properties,
412
+ ...dateRangeProperties,
413
+ ...itemIdsProperty
414
+ },
415
+ required: ["id"],
416
+ additionalProperties: false
417
+ }
418
+ },
419
+ {
420
+ name: "lighthouse_portfolio_metrics_cumulativeStateTimeItems",
421
+ description: "Get the per-item drill-down for ONE state of a portfolio's cumulative time-per-state chart: the work items that contributed to that state, with days contributed. Requires the state name.",
422
+ inputSchema: {
423
+ type: "object",
424
+ properties: {
425
+ ...idInputSchema.properties,
426
+ ...cumulativeStateProperty,
427
+ ...dateRangeProperties,
428
+ ...itemIdsProperty
429
+ },
430
+ required: ["id", "state"],
431
+ additionalProperties: false
432
+ }
433
+ },
434
+ {
435
+ name: "lighthouse_portfolio_metrics_cumulativeStateTimeCandidates",
436
+ description: "List the work items selectable in a portfolio's cumulative time-per-state item picker for the window (the in-scope candidate set). Search keys are referenceId and title.",
437
+ inputSchema: {
438
+ type: "object",
439
+ properties: {
440
+ ...idInputSchema.properties,
441
+ ...dateRangeProperties
442
+ },
443
+ required: ["id"],
444
+ additionalProperties: false
445
+ }
280
446
  }
281
447
  ];
282
448
  var encodePayload = (value) => {
@@ -328,6 +494,26 @@ var getDateRange = (argumentsPayload) => {
328
494
  }
329
495
  return void 0;
330
496
  };
497
+ var getStringArgument = (argumentsPayload, key) => {
498
+ if (!isObjectRecord(argumentsPayload)) {
499
+ return void 0;
500
+ }
501
+ const value = argumentsPayload[key];
502
+ return typeof value === "string" ? value : void 0;
503
+ };
504
+ var getItemIdsArgument = (argumentsPayload) => {
505
+ if (!isObjectRecord(argumentsPayload)) {
506
+ return void 0;
507
+ }
508
+ const value = argumentsPayload.itemIds;
509
+ if (!Array.isArray(value)) {
510
+ return void 0;
511
+ }
512
+ const ids = value.filter(
513
+ (entry) => typeof entry === "number" && Number.isInteger(entry)
514
+ );
515
+ return ids.length > 0 ? ids : void 0;
516
+ };
331
517
  var getThroughputFilterView = (argumentsPayload) => {
332
518
  if (!isObjectRecord(argumentsPayload)) {
333
519
  return void 0;
@@ -343,6 +529,22 @@ var getApplyFilterOverride = (argumentsPayload) => {
343
529
  return typeof value === "boolean" ? value : void 0;
344
530
  };
345
531
  var isoDateStringSchema = z.string().regex(/^\d{4}-\d{2}-\d{2}$/u, "Expected ISO date in YYYY-MM-DD format.");
532
+ var weekdaySchema = z.enum([
533
+ "Sunday",
534
+ "Monday",
535
+ "Tuesday",
536
+ "Wednesday",
537
+ "Thursday",
538
+ "Friday",
539
+ "Saturday"
540
+ ]);
541
+ var recurringBlackoutRuleInputSchema = z.object({
542
+ weekdays: z.array(weekdaySchema),
543
+ intervalWeeks: z.number().int(),
544
+ start: isoDateStringSchema,
545
+ end: isoDateStringSchema.nullable().optional(),
546
+ description: z.string()
547
+ });
346
548
  var toolInputSchemas = {
347
549
  lighthouse_health_check: z.object({}),
348
550
  lighthouse_version_get: z.object({}),
@@ -390,12 +592,54 @@ var toolInputSchemas = {
390
592
  startDate: isoDateStringSchema.optional(),
391
593
  endDate: isoDateStringSchema.optional()
392
594
  }),
595
+ lighthouse_team_metrics_cumulativeStateTime: z.object({
596
+ id: z.number().int(),
597
+ startDate: isoDateStringSchema.optional(),
598
+ endDate: isoDateStringSchema.optional(),
599
+ itemIds: z.array(z.number().int()).optional()
600
+ }),
601
+ lighthouse_team_metrics_cumulativeStateTimeItems: z.object({
602
+ id: z.number().int(),
603
+ state: z.string(),
604
+ startDate: isoDateStringSchema.optional(),
605
+ endDate: isoDateStringSchema.optional(),
606
+ itemIds: z.array(z.number().int()).optional()
607
+ }),
608
+ lighthouse_team_metrics_cumulativeStateTimeCandidates: z.object({
609
+ id: z.number().int(),
610
+ startDate: isoDateStringSchema.optional(),
611
+ endDate: isoDateStringSchema.optional()
612
+ }),
613
+ lighthouse_portfolio_metrics_cumulativeStateTime: z.object({
614
+ id: z.number().int(),
615
+ startDate: isoDateStringSchema.optional(),
616
+ endDate: isoDateStringSchema.optional(),
617
+ itemIds: z.array(z.number().int()).optional()
618
+ }),
619
+ lighthouse_portfolio_metrics_cumulativeStateTimeItems: z.object({
620
+ id: z.number().int(),
621
+ state: z.string(),
622
+ startDate: isoDateStringSchema.optional(),
623
+ endDate: isoDateStringSchema.optional(),
624
+ itemIds: z.array(z.number().int()).optional()
625
+ }),
626
+ lighthouse_portfolio_metrics_cumulativeStateTimeCandidates: z.object({
627
+ id: z.number().int(),
628
+ startDate: isoDateStringSchema.optional(),
629
+ endDate: isoDateStringSchema.optional()
630
+ }),
393
631
  lighthouse_feature_get: z.object({
394
632
  ids: z.array(z.number().int()).optional(),
395
633
  refs: z.array(z.string()).optional()
396
634
  }),
397
635
  lighthouse_feature_workitems: z.object({ id: z.number().int() }),
398
636
  lighthouse_delivery_list: z.object({ id: z.number().int() }),
637
+ lighthouse_blackout_list: z.object({}),
638
+ lighthouse_blackout_create: recurringBlackoutRuleInputSchema,
639
+ lighthouse_blackout_update: recurringBlackoutRuleInputSchema.extend({
640
+ id: z.number().int()
641
+ }),
642
+ lighthouse_blackout_delete: z.object({ id: z.number().int() }),
399
643
  lighthouse_forecast_manual: z.object({
400
644
  id: z.number().int(),
401
645
  remainingItems: z.number().int().optional(),
@@ -411,7 +655,7 @@ var toolInputSchemas = {
411
655
  applyFilterOverride: z.boolean().optional()
412
656
  })
413
657
  };
414
- var isReadOnlyTool = (toolName) => !toolName.endsWith("_refresh");
658
+ var isReadOnlyTool = (toolName) => !(toolName.endsWith("_refresh") || toolName.endsWith("_create") || toolName.endsWith("_update") || toolName.endsWith("_delete"));
415
659
  var createMcpCoreRuntime = (dependencies) => ({
416
660
  listTools: () => toolDefinitions,
417
661
  callTool: async (name, argumentsPayload) => {
@@ -568,6 +812,128 @@ var createMcpCoreRuntime = (dependencies) => ({
568
812
  `team metrics: ${result.error.category} (${result.error.reason})`
569
813
  );
570
814
  }
815
+ if (name === "lighthouse_team_metrics_cumulativeStateTime") {
816
+ const id = getNumericId(argumentsPayload);
817
+ if (id === null) {
818
+ return getErrorToolResult("team metrics: invalid id");
819
+ }
820
+ const result = await client.getTeamCumulativeStateTime(
821
+ id,
822
+ getDateRange(argumentsPayload),
823
+ getItemIdsArgument(argumentsPayload)
824
+ );
825
+ if (result.ok) {
826
+ return getSuccessToolResult(
827
+ `team cumulativeStateTime: ${encodePayload(result.value)}`
828
+ );
829
+ }
830
+ return getErrorToolResult(
831
+ `team metrics: ${result.error.category} (${result.error.reason})`
832
+ );
833
+ }
834
+ if (name === "lighthouse_team_metrics_cumulativeStateTimeItems") {
835
+ const id = getNumericId(argumentsPayload);
836
+ if (id === null) {
837
+ return getErrorToolResult("team metrics: invalid id");
838
+ }
839
+ const state = getStringArgument(argumentsPayload, "state");
840
+ if (state === void 0) {
841
+ return getErrorToolResult("team metrics: missing state");
842
+ }
843
+ const result = await client.getTeamCumulativeStateTimeItems(
844
+ id,
845
+ state,
846
+ getDateRange(argumentsPayload),
847
+ getItemIdsArgument(argumentsPayload)
848
+ );
849
+ if (result.ok) {
850
+ return getSuccessToolResult(
851
+ `team cumulativeStateTimeItems: ${encodePayload(result.value)}`
852
+ );
853
+ }
854
+ return getErrorToolResult(
855
+ `team metrics: ${result.error.category} (${result.error.reason})`
856
+ );
857
+ }
858
+ if (name === "lighthouse_team_metrics_cumulativeStateTimeCandidates") {
859
+ const id = getNumericId(argumentsPayload);
860
+ if (id === null) {
861
+ return getErrorToolResult("team metrics: invalid id");
862
+ }
863
+ const result = await client.getTeamCumulativeStateTimeCandidates(
864
+ id,
865
+ getDateRange(argumentsPayload)
866
+ );
867
+ if (result.ok) {
868
+ return getSuccessToolResult(
869
+ `team cumulativeStateTimeCandidates: ${encodePayload(result.value)}`
870
+ );
871
+ }
872
+ return getErrorToolResult(
873
+ `team metrics: ${result.error.category} (${result.error.reason})`
874
+ );
875
+ }
876
+ if (name === "lighthouse_portfolio_metrics_cumulativeStateTime") {
877
+ const id = getNumericId(argumentsPayload);
878
+ if (id === null) {
879
+ return getErrorToolResult("portfolio metrics: invalid id");
880
+ }
881
+ const result = await client.getPortfolioCumulativeStateTime(
882
+ id,
883
+ getDateRange(argumentsPayload),
884
+ getItemIdsArgument(argumentsPayload)
885
+ );
886
+ if (result.ok) {
887
+ return getSuccessToolResult(
888
+ `portfolio cumulativeStateTime: ${encodePayload(result.value)}`
889
+ );
890
+ }
891
+ return getErrorToolResult(
892
+ `portfolio metrics: ${result.error.category} (${result.error.reason})`
893
+ );
894
+ }
895
+ if (name === "lighthouse_portfolio_metrics_cumulativeStateTimeItems") {
896
+ const id = getNumericId(argumentsPayload);
897
+ if (id === null) {
898
+ return getErrorToolResult("portfolio metrics: invalid id");
899
+ }
900
+ const state = getStringArgument(argumentsPayload, "state");
901
+ if (state === void 0) {
902
+ return getErrorToolResult("portfolio metrics: missing state");
903
+ }
904
+ const result = await client.getPortfolioCumulativeStateTimeItems(
905
+ id,
906
+ state,
907
+ getDateRange(argumentsPayload),
908
+ getItemIdsArgument(argumentsPayload)
909
+ );
910
+ if (result.ok) {
911
+ return getSuccessToolResult(
912
+ `portfolio cumulativeStateTimeItems: ${encodePayload(result.value)}`
913
+ );
914
+ }
915
+ return getErrorToolResult(
916
+ `portfolio metrics: ${result.error.category} (${result.error.reason})`
917
+ );
918
+ }
919
+ if (name === "lighthouse_portfolio_metrics_cumulativeStateTimeCandidates") {
920
+ const id = getNumericId(argumentsPayload);
921
+ if (id === null) {
922
+ return getErrorToolResult("portfolio metrics: invalid id");
923
+ }
924
+ const result = await client.getPortfolioCumulativeStateTimeCandidates(
925
+ id,
926
+ getDateRange(argumentsPayload)
927
+ );
928
+ if (result.ok) {
929
+ return getSuccessToolResult(
930
+ `portfolio cumulativeStateTimeCandidates: ${encodePayload(result.value)}`
931
+ );
932
+ }
933
+ return getErrorToolResult(
934
+ `portfolio metrics: ${result.error.category} (${result.error.reason})`
935
+ );
936
+ }
571
937
  if (name === "lighthouse_portfolio_metrics_throughput") {
572
938
  const id = getNumericId(argumentsPayload);
573
939
  if (id === null) {
@@ -717,6 +1083,59 @@ var createMcpCoreRuntime = (dependencies) => ({
717
1083
  `delivery: ${result.error.category} (${result.error.reason})`
718
1084
  );
719
1085
  }
1086
+ if (name === "lighthouse_blackout_list") {
1087
+ const result = await client.getRecurringBlackoutRules();
1088
+ if (result.ok) {
1089
+ return getSuccessToolResult(
1090
+ `recurringBlackoutRules: ${encodePayload(result.value)}`
1091
+ );
1092
+ }
1093
+ return getErrorToolResult(
1094
+ `blackout: ${result.error.category} (${result.error.reason})`
1095
+ );
1096
+ }
1097
+ if (name === "lighthouse_blackout_create") {
1098
+ const payload = isObjectRecord(argumentsPayload) ? argumentsPayload : {};
1099
+ const result = await client.createRecurringBlackoutRule(payload);
1100
+ if (result.ok) {
1101
+ return getSuccessToolResult(
1102
+ `recurringBlackoutRule: ${encodePayload(result.value)}`
1103
+ );
1104
+ }
1105
+ return getErrorToolResult(
1106
+ `blackout: ${result.error.category} (${result.error.reason})`
1107
+ );
1108
+ }
1109
+ if (name === "lighthouse_blackout_update") {
1110
+ const id = getNumericId(argumentsPayload);
1111
+ if (id === null) {
1112
+ return getErrorToolResult("blackout: invalid id (rule id required)");
1113
+ }
1114
+ const payload = isObjectRecord(argumentsPayload) ? argumentsPayload : {};
1115
+ const { id: _ignoredId, ...rulePayload } = payload;
1116
+ const result = await client.updateRecurringBlackoutRule(id, rulePayload);
1117
+ if (result.ok) {
1118
+ return getSuccessToolResult(
1119
+ `recurringBlackoutRule: ${encodePayload(result.value)}`
1120
+ );
1121
+ }
1122
+ return getErrorToolResult(
1123
+ `blackout: ${result.error.category} (${result.error.reason})`
1124
+ );
1125
+ }
1126
+ if (name === "lighthouse_blackout_delete") {
1127
+ const id = getNumericId(argumentsPayload);
1128
+ if (id === null) {
1129
+ return getErrorToolResult("blackout: invalid id (rule id required)");
1130
+ }
1131
+ const result = await client.deleteRecurringBlackoutRule(id);
1132
+ if (result.ok) {
1133
+ return getSuccessToolResult(`recurringBlackoutRule deleted: ${id}`);
1134
+ }
1135
+ return getErrorToolResult(
1136
+ `blackout: ${result.error.category} (${result.error.reason})`
1137
+ );
1138
+ }
720
1139
  if (name === "lighthouse_forecast_manual") {
721
1140
  const id = getNumericId(argumentsPayload);
722
1141
  if (id === null) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letpeoplework/lighthouse-mcp-core",
3
- "version": "1.1.0",
3
+ "version": "1.3.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.1.0"
29
+ "@letpeoplework/lighthouse-client": "1.3.0"
30
30
  },
31
31
  "scripts": {
32
32
  "build": "tsup src/index.ts --format esm,cjs --dts --clean",