@letpeoplework/lighthouse-mcp-core 1.2.0 → 1.4.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
@@ -84,6 +84,40 @@ var forecastFilterOverrideProperty = {
84
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."
85
85
  }
86
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
+ };
87
121
  var toolDefinitions = [
88
122
  {
89
123
  name: "lighthouse_health_check",
@@ -151,7 +185,37 @@ var toolDefinitions = [
151
185
  },
152
186
  {
153
187
  name: "lighthouse_team_metrics_cycleTimePercentiles",
154
- description: "Get cycle-time percentiles for a team by ID, optionally filtered by start and end dates.",
188
+ description: "Get cycle-time percentiles for a team by ID, optionally filtered by start and end dates. Pass definitionId to get the percentiles for a named cycle time (premium) instead of the default cycle time.",
189
+ inputSchema: {
190
+ type: "object",
191
+ properties: {
192
+ ...idInputSchema.properties,
193
+ ...dateRangeProperties,
194
+ definitionId: {
195
+ type: "number",
196
+ description: "Optional named cycle time definition ID; omit for the default cycle time."
197
+ }
198
+ },
199
+ required: ["id"],
200
+ additionalProperties: false
201
+ }
202
+ },
203
+ {
204
+ name: "lighthouse_team_metrics_workItemAgePercentiles",
205
+ description: "Get work-item age percentiles for a team by ID, optionally filtered by start and end dates.",
206
+ inputSchema: {
207
+ type: "object",
208
+ properties: {
209
+ ...idInputSchema.properties,
210
+ ...dateRangeProperties
211
+ },
212
+ required: ["id"],
213
+ additionalProperties: false
214
+ }
215
+ },
216
+ {
217
+ name: "lighthouse_portfolio_metrics_workItemAgePercentiles",
218
+ description: "Get work-item age percentiles for a portfolio by ID, optionally filtered by start and end dates.",
155
219
  inputSchema: {
156
220
  type: "object",
157
221
  properties: {
@@ -261,6 +325,41 @@ var toolDefinitions = [
261
325
  description: "List deliveries for a portfolio by portfolio ID.",
262
326
  inputSchema: idInputSchema
263
327
  },
328
+ {
329
+ name: "lighthouse_blackout_list",
330
+ description: "List the recurring blackout rules (recurring non-working days excluded from forecasts). Requires Lighthouse newer than v26.5.29.5.",
331
+ inputSchema: emptyInputSchema
332
+ },
333
+ {
334
+ name: "lighthouse_blackout_create",
335
+ 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.",
336
+ inputSchema: {
337
+ type: "object",
338
+ properties: {
339
+ ...recurringBlackoutRuleProperties
340
+ },
341
+ required: ["weekdays", "intervalWeeks", "start", "description"],
342
+ additionalProperties: false
343
+ }
344
+ },
345
+ {
346
+ name: "lighthouse_blackout_update",
347
+ description: "Update a recurring blackout rule by ID. Premium, system-admin only. Requires Lighthouse newer than v26.5.29.5.",
348
+ inputSchema: {
349
+ type: "object",
350
+ properties: {
351
+ ...idInputSchema.properties,
352
+ ...recurringBlackoutRuleProperties
353
+ },
354
+ required: ["id", "weekdays", "intervalWeeks", "start", "description"],
355
+ additionalProperties: false
356
+ }
357
+ },
358
+ {
359
+ name: "lighthouse_blackout_delete",
360
+ description: "Delete a recurring blackout rule by ID. Premium, system-admin only. Requires Lighthouse newer than v26.5.29.5.",
361
+ inputSchema: idInputSchema
362
+ },
264
363
  {
265
364
  name: "lighthouse_forecast_manual",
266
365
  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.",
@@ -437,6 +536,13 @@ var getNumericId = (argumentsPayload) => {
437
536
  }
438
537
  return null;
439
538
  };
539
+ var getDefinitionId = (argumentsPayload) => {
540
+ if (typeof argumentsPayload !== "object" || argumentsPayload === null || Array.isArray(argumentsPayload)) {
541
+ return void 0;
542
+ }
543
+ const value = argumentsPayload.definitionId;
544
+ return typeof value === "number" && Number.isInteger(value) ? value : void 0;
545
+ };
440
546
  var isObjectRecord = (value) => {
441
547
  return typeof value === "object" && value !== null && !Array.isArray(value);
442
548
  };
@@ -486,6 +592,22 @@ var getApplyFilterOverride = (argumentsPayload) => {
486
592
  return typeof value === "boolean" ? value : void 0;
487
593
  };
488
594
  var isoDateStringSchema = import_zod.z.string().regex(/^\d{4}-\d{2}-\d{2}$/u, "Expected ISO date in YYYY-MM-DD format.");
595
+ var weekdaySchema = import_zod.z.enum([
596
+ "Sunday",
597
+ "Monday",
598
+ "Tuesday",
599
+ "Wednesday",
600
+ "Thursday",
601
+ "Friday",
602
+ "Saturday"
603
+ ]);
604
+ var recurringBlackoutRuleInputSchema = import_zod.z.object({
605
+ weekdays: import_zod.z.array(weekdaySchema),
606
+ intervalWeeks: import_zod.z.number().int(),
607
+ start: isoDateStringSchema,
608
+ end: isoDateStringSchema.nullable().optional(),
609
+ description: import_zod.z.string()
610
+ });
489
611
  var toolInputSchemas = {
490
612
  lighthouse_health_check: import_zod.z.object({}),
491
613
  lighthouse_version_get: import_zod.z.object({}),
@@ -504,6 +626,17 @@ var toolInputSchemas = {
504
626
  view: import_zod.z.enum(["raw", "filtered"]).optional()
505
627
  }),
506
628
  lighthouse_team_metrics_cycleTimePercentiles: import_zod.z.object({
629
+ id: import_zod.z.number().int(),
630
+ startDate: isoDateStringSchema.optional(),
631
+ endDate: isoDateStringSchema.optional(),
632
+ definitionId: import_zod.z.number().int().optional()
633
+ }),
634
+ lighthouse_team_metrics_workItemAgePercentiles: import_zod.z.object({
635
+ id: import_zod.z.number().int(),
636
+ startDate: isoDateStringSchema.optional(),
637
+ endDate: isoDateStringSchema.optional()
638
+ }),
639
+ lighthouse_portfolio_metrics_workItemAgePercentiles: import_zod.z.object({
507
640
  id: import_zod.z.number().int(),
508
641
  startDate: isoDateStringSchema.optional(),
509
642
  endDate: isoDateStringSchema.optional()
@@ -575,6 +708,12 @@ var toolInputSchemas = {
575
708
  }),
576
709
  lighthouse_feature_workitems: import_zod.z.object({ id: import_zod.z.number().int() }),
577
710
  lighthouse_delivery_list: import_zod.z.object({ id: import_zod.z.number().int() }),
711
+ lighthouse_blackout_list: import_zod.z.object({}),
712
+ lighthouse_blackout_create: recurringBlackoutRuleInputSchema,
713
+ lighthouse_blackout_update: recurringBlackoutRuleInputSchema.extend({
714
+ id: import_zod.z.number().int()
715
+ }),
716
+ lighthouse_blackout_delete: import_zod.z.object({ id: import_zod.z.number().int() }),
578
717
  lighthouse_forecast_manual: import_zod.z.object({
579
718
  id: import_zod.z.number().int(),
580
719
  remainingItems: import_zod.z.number().int().optional(),
@@ -590,7 +729,7 @@ var toolInputSchemas = {
590
729
  applyFilterOverride: import_zod.z.boolean().optional()
591
730
  })
592
731
  };
593
- var isReadOnlyTool = (toolName) => !toolName.endsWith("_refresh");
732
+ var isReadOnlyTool = (toolName) => !(toolName.endsWith("_refresh") || toolName.endsWith("_create") || toolName.endsWith("_update") || toolName.endsWith("_delete"));
594
733
  var createMcpCoreRuntime = (dependencies) => ({
595
734
  listTools: () => toolDefinitions,
596
735
  callTool: async (name, argumentsPayload) => {
@@ -737,7 +876,12 @@ var createMcpCoreRuntime = (dependencies) => ({
737
876
  return getErrorToolResult("team metrics: invalid id");
738
877
  }
739
878
  const range = getDateRange(argumentsPayload);
740
- const result = await client.getTeamCycleTimePercentiles(id, range);
879
+ const definitionId = getDefinitionId(argumentsPayload);
880
+ const result = await client.getTeamCycleTimePercentiles(
881
+ id,
882
+ range,
883
+ definitionId
884
+ );
741
885
  if (result.ok) {
742
886
  return getSuccessToolResult(
743
887
  `team cycleTimePercentiles: ${encodePayload(result.value)}`
@@ -747,6 +891,38 @@ var createMcpCoreRuntime = (dependencies) => ({
747
891
  `team metrics: ${result.error.category} (${result.error.reason})`
748
892
  );
749
893
  }
894
+ if (name === "lighthouse_team_metrics_workItemAgePercentiles") {
895
+ const id = getNumericId(argumentsPayload);
896
+ if (id === null) {
897
+ return getErrorToolResult("team metrics: invalid id");
898
+ }
899
+ const range = getDateRange(argumentsPayload);
900
+ const result = await client.getTeamWorkItemAgePercentiles(id, range);
901
+ if (result.ok) {
902
+ return getSuccessToolResult(
903
+ `team workItemAgePercentiles: ${encodePayload(result.value)}`
904
+ );
905
+ }
906
+ return getErrorToolResult(
907
+ `team metrics: ${result.error.category} (${result.error.reason})`
908
+ );
909
+ }
910
+ if (name === "lighthouse_portfolio_metrics_workItemAgePercentiles") {
911
+ const id = getNumericId(argumentsPayload);
912
+ if (id === null) {
913
+ return getErrorToolResult("portfolio metrics: invalid id");
914
+ }
915
+ const range = getDateRange(argumentsPayload);
916
+ const result = await client.getPortfolioWorkItemAgePercentiles(id, range);
917
+ if (result.ok) {
918
+ return getSuccessToolResult(
919
+ `portfolio workItemAgePercentiles: ${encodePayload(result.value)}`
920
+ );
921
+ }
922
+ return getErrorToolResult(
923
+ `portfolio metrics: ${result.error.category} (${result.error.reason})`
924
+ );
925
+ }
750
926
  if (name === "lighthouse_team_metrics_cumulativeStateTime") {
751
927
  const id = getNumericId(argumentsPayload);
752
928
  if (id === null) {
@@ -1018,6 +1194,59 @@ var createMcpCoreRuntime = (dependencies) => ({
1018
1194
  `delivery: ${result.error.category} (${result.error.reason})`
1019
1195
  );
1020
1196
  }
1197
+ if (name === "lighthouse_blackout_list") {
1198
+ const result = await client.getRecurringBlackoutRules();
1199
+ if (result.ok) {
1200
+ return getSuccessToolResult(
1201
+ `recurringBlackoutRules: ${encodePayload(result.value)}`
1202
+ );
1203
+ }
1204
+ return getErrorToolResult(
1205
+ `blackout: ${result.error.category} (${result.error.reason})`
1206
+ );
1207
+ }
1208
+ if (name === "lighthouse_blackout_create") {
1209
+ const payload = isObjectRecord(argumentsPayload) ? argumentsPayload : {};
1210
+ const result = await client.createRecurringBlackoutRule(payload);
1211
+ if (result.ok) {
1212
+ return getSuccessToolResult(
1213
+ `recurringBlackoutRule: ${encodePayload(result.value)}`
1214
+ );
1215
+ }
1216
+ return getErrorToolResult(
1217
+ `blackout: ${result.error.category} (${result.error.reason})`
1218
+ );
1219
+ }
1220
+ if (name === "lighthouse_blackout_update") {
1221
+ const id = getNumericId(argumentsPayload);
1222
+ if (id === null) {
1223
+ return getErrorToolResult("blackout: invalid id (rule id required)");
1224
+ }
1225
+ const payload = isObjectRecord(argumentsPayload) ? argumentsPayload : {};
1226
+ const { id: _ignoredId, ...rulePayload } = payload;
1227
+ const result = await client.updateRecurringBlackoutRule(id, rulePayload);
1228
+ if (result.ok) {
1229
+ return getSuccessToolResult(
1230
+ `recurringBlackoutRule: ${encodePayload(result.value)}`
1231
+ );
1232
+ }
1233
+ return getErrorToolResult(
1234
+ `blackout: ${result.error.category} (${result.error.reason})`
1235
+ );
1236
+ }
1237
+ if (name === "lighthouse_blackout_delete") {
1238
+ const id = getNumericId(argumentsPayload);
1239
+ if (id === null) {
1240
+ return getErrorToolResult("blackout: invalid id (rule id required)");
1241
+ }
1242
+ const result = await client.deleteRecurringBlackoutRule(id);
1243
+ if (result.ok) {
1244
+ return getSuccessToolResult(`recurringBlackoutRule deleted: ${id}`);
1245
+ }
1246
+ return getErrorToolResult(
1247
+ `blackout: ${result.error.category} (${result.error.reason})`
1248
+ );
1249
+ }
1021
1250
  if (name === "lighthouse_forecast_manual") {
1022
1251
  const id = getNumericId(argumentsPayload);
1023
1252
  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_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_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_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<{
@@ -135,6 +135,32 @@ type McpRuntimeClient = {
135
135
  readonly getTeamCycleTimePercentiles: (id: number, range?: {
136
136
  readonly startDate: string;
137
137
  readonly endDate: string;
138
+ }, definitionId?: number) => Promise<{
139
+ readonly ok: true;
140
+ readonly value: readonly unknown[];
141
+ } | {
142
+ readonly ok: false;
143
+ readonly error: {
144
+ readonly category: string;
145
+ readonly reason: string;
146
+ };
147
+ }>;
148
+ readonly getTeamWorkItemAgePercentiles: (id: number, range?: {
149
+ readonly startDate: string;
150
+ readonly endDate: string;
151
+ }) => Promise<{
152
+ readonly ok: true;
153
+ readonly value: readonly unknown[];
154
+ } | {
155
+ readonly ok: false;
156
+ readonly error: {
157
+ readonly category: string;
158
+ readonly reason: string;
159
+ };
160
+ }>;
161
+ readonly getPortfolioWorkItemAgePercentiles: (id: number, range?: {
162
+ readonly startDate: string;
163
+ readonly endDate: string;
138
164
  }) => Promise<{
139
165
  readonly ok: true;
140
166
  readonly value: readonly unknown[];
@@ -358,6 +384,46 @@ type McpRuntimeClient = {
358
384
  readonly reason: string;
359
385
  };
360
386
  }>;
387
+ readonly getRecurringBlackoutRules: () => Promise<{
388
+ readonly ok: true;
389
+ readonly value: readonly unknown[];
390
+ } | {
391
+ readonly ok: false;
392
+ readonly error: {
393
+ readonly category: string;
394
+ readonly reason: string;
395
+ };
396
+ }>;
397
+ readonly createRecurringBlackoutRule: (payload: Readonly<Record<string, unknown>>) => Promise<{
398
+ readonly ok: true;
399
+ readonly value: unknown;
400
+ } | {
401
+ readonly ok: false;
402
+ readonly error: {
403
+ readonly category: string;
404
+ readonly reason: string;
405
+ };
406
+ }>;
407
+ readonly updateRecurringBlackoutRule: (id: number, payload: Readonly<Record<string, unknown>>) => Promise<{
408
+ readonly ok: true;
409
+ readonly value: unknown;
410
+ } | {
411
+ readonly ok: false;
412
+ readonly error: {
413
+ readonly category: string;
414
+ readonly reason: string;
415
+ };
416
+ }>;
417
+ readonly deleteRecurringBlackoutRule: (id: number) => Promise<{
418
+ readonly ok: true;
419
+ readonly value: undefined;
420
+ } | {
421
+ readonly ok: false;
422
+ readonly error: {
423
+ readonly category: string;
424
+ readonly reason: string;
425
+ };
426
+ }>;
361
427
  readonly runManualForecast: (teamId: number, payload: {
362
428
  readonly remainingItems?: number;
363
429
  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_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_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_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<{
@@ -135,6 +135,32 @@ type McpRuntimeClient = {
135
135
  readonly getTeamCycleTimePercentiles: (id: number, range?: {
136
136
  readonly startDate: string;
137
137
  readonly endDate: string;
138
+ }, definitionId?: number) => Promise<{
139
+ readonly ok: true;
140
+ readonly value: readonly unknown[];
141
+ } | {
142
+ readonly ok: false;
143
+ readonly error: {
144
+ readonly category: string;
145
+ readonly reason: string;
146
+ };
147
+ }>;
148
+ readonly getTeamWorkItemAgePercentiles: (id: number, range?: {
149
+ readonly startDate: string;
150
+ readonly endDate: string;
151
+ }) => Promise<{
152
+ readonly ok: true;
153
+ readonly value: readonly unknown[];
154
+ } | {
155
+ readonly ok: false;
156
+ readonly error: {
157
+ readonly category: string;
158
+ readonly reason: string;
159
+ };
160
+ }>;
161
+ readonly getPortfolioWorkItemAgePercentiles: (id: number, range?: {
162
+ readonly startDate: string;
163
+ readonly endDate: string;
138
164
  }) => Promise<{
139
165
  readonly ok: true;
140
166
  readonly value: readonly unknown[];
@@ -358,6 +384,46 @@ type McpRuntimeClient = {
358
384
  readonly reason: string;
359
385
  };
360
386
  }>;
387
+ readonly getRecurringBlackoutRules: () => Promise<{
388
+ readonly ok: true;
389
+ readonly value: readonly unknown[];
390
+ } | {
391
+ readonly ok: false;
392
+ readonly error: {
393
+ readonly category: string;
394
+ readonly reason: string;
395
+ };
396
+ }>;
397
+ readonly createRecurringBlackoutRule: (payload: Readonly<Record<string, unknown>>) => Promise<{
398
+ readonly ok: true;
399
+ readonly value: unknown;
400
+ } | {
401
+ readonly ok: false;
402
+ readonly error: {
403
+ readonly category: string;
404
+ readonly reason: string;
405
+ };
406
+ }>;
407
+ readonly updateRecurringBlackoutRule: (id: number, payload: Readonly<Record<string, unknown>>) => Promise<{
408
+ readonly ok: true;
409
+ readonly value: unknown;
410
+ } | {
411
+ readonly ok: false;
412
+ readonly error: {
413
+ readonly category: string;
414
+ readonly reason: string;
415
+ };
416
+ }>;
417
+ readonly deleteRecurringBlackoutRule: (id: number) => Promise<{
418
+ readonly ok: true;
419
+ readonly value: undefined;
420
+ } | {
421
+ readonly ok: false;
422
+ readonly error: {
423
+ readonly category: string;
424
+ readonly reason: string;
425
+ };
426
+ }>;
361
427
  readonly runManualForecast: (teamId: number, payload: {
362
428
  readonly remainingItems?: number;
363
429
  readonly targetDate?: string;
package/dist/index.js CHANGED
@@ -58,6 +58,40 @@ var forecastFilterOverrideProperty = {
58
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."
59
59
  }
60
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
+ };
61
95
  var toolDefinitions = [
62
96
  {
63
97
  name: "lighthouse_health_check",
@@ -125,7 +159,37 @@ var toolDefinitions = [
125
159
  },
126
160
  {
127
161
  name: "lighthouse_team_metrics_cycleTimePercentiles",
128
- description: "Get cycle-time percentiles for a team by ID, optionally filtered by start and end dates.",
162
+ description: "Get cycle-time percentiles for a team by ID, optionally filtered by start and end dates. Pass definitionId to get the percentiles for a named cycle time (premium) instead of the default cycle time.",
163
+ inputSchema: {
164
+ type: "object",
165
+ properties: {
166
+ ...idInputSchema.properties,
167
+ ...dateRangeProperties,
168
+ definitionId: {
169
+ type: "number",
170
+ description: "Optional named cycle time definition ID; omit for the default cycle time."
171
+ }
172
+ },
173
+ required: ["id"],
174
+ additionalProperties: false
175
+ }
176
+ },
177
+ {
178
+ name: "lighthouse_team_metrics_workItemAgePercentiles",
179
+ description: "Get work-item age percentiles for a team by ID, optionally filtered by start and end dates.",
180
+ inputSchema: {
181
+ type: "object",
182
+ properties: {
183
+ ...idInputSchema.properties,
184
+ ...dateRangeProperties
185
+ },
186
+ required: ["id"],
187
+ additionalProperties: false
188
+ }
189
+ },
190
+ {
191
+ name: "lighthouse_portfolio_metrics_workItemAgePercentiles",
192
+ description: "Get work-item age percentiles for a portfolio by ID, optionally filtered by start and end dates.",
129
193
  inputSchema: {
130
194
  type: "object",
131
195
  properties: {
@@ -235,6 +299,41 @@ var toolDefinitions = [
235
299
  description: "List deliveries for a portfolio by portfolio ID.",
236
300
  inputSchema: idInputSchema
237
301
  },
302
+ {
303
+ name: "lighthouse_blackout_list",
304
+ description: "List the recurring blackout rules (recurring non-working days excluded from forecasts). Requires Lighthouse newer than v26.5.29.5.",
305
+ inputSchema: emptyInputSchema
306
+ },
307
+ {
308
+ name: "lighthouse_blackout_create",
309
+ 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.",
310
+ inputSchema: {
311
+ type: "object",
312
+ properties: {
313
+ ...recurringBlackoutRuleProperties
314
+ },
315
+ required: ["weekdays", "intervalWeeks", "start", "description"],
316
+ additionalProperties: false
317
+ }
318
+ },
319
+ {
320
+ name: "lighthouse_blackout_update",
321
+ description: "Update a recurring blackout rule by ID. Premium, system-admin only. Requires Lighthouse newer than v26.5.29.5.",
322
+ inputSchema: {
323
+ type: "object",
324
+ properties: {
325
+ ...idInputSchema.properties,
326
+ ...recurringBlackoutRuleProperties
327
+ },
328
+ required: ["id", "weekdays", "intervalWeeks", "start", "description"],
329
+ additionalProperties: false
330
+ }
331
+ },
332
+ {
333
+ name: "lighthouse_blackout_delete",
334
+ description: "Delete a recurring blackout rule by ID. Premium, system-admin only. Requires Lighthouse newer than v26.5.29.5.",
335
+ inputSchema: idInputSchema
336
+ },
238
337
  {
239
338
  name: "lighthouse_forecast_manual",
240
339
  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.",
@@ -411,6 +510,13 @@ var getNumericId = (argumentsPayload) => {
411
510
  }
412
511
  return null;
413
512
  };
513
+ var getDefinitionId = (argumentsPayload) => {
514
+ if (typeof argumentsPayload !== "object" || argumentsPayload === null || Array.isArray(argumentsPayload)) {
515
+ return void 0;
516
+ }
517
+ const value = argumentsPayload.definitionId;
518
+ return typeof value === "number" && Number.isInteger(value) ? value : void 0;
519
+ };
414
520
  var isObjectRecord = (value) => {
415
521
  return typeof value === "object" && value !== null && !Array.isArray(value);
416
522
  };
@@ -460,6 +566,22 @@ var getApplyFilterOverride = (argumentsPayload) => {
460
566
  return typeof value === "boolean" ? value : void 0;
461
567
  };
462
568
  var isoDateStringSchema = z.string().regex(/^\d{4}-\d{2}-\d{2}$/u, "Expected ISO date in YYYY-MM-DD format.");
569
+ var weekdaySchema = z.enum([
570
+ "Sunday",
571
+ "Monday",
572
+ "Tuesday",
573
+ "Wednesday",
574
+ "Thursday",
575
+ "Friday",
576
+ "Saturday"
577
+ ]);
578
+ var recurringBlackoutRuleInputSchema = z.object({
579
+ weekdays: z.array(weekdaySchema),
580
+ intervalWeeks: z.number().int(),
581
+ start: isoDateStringSchema,
582
+ end: isoDateStringSchema.nullable().optional(),
583
+ description: z.string()
584
+ });
463
585
  var toolInputSchemas = {
464
586
  lighthouse_health_check: z.object({}),
465
587
  lighthouse_version_get: z.object({}),
@@ -478,6 +600,17 @@ var toolInputSchemas = {
478
600
  view: z.enum(["raw", "filtered"]).optional()
479
601
  }),
480
602
  lighthouse_team_metrics_cycleTimePercentiles: z.object({
603
+ id: z.number().int(),
604
+ startDate: isoDateStringSchema.optional(),
605
+ endDate: isoDateStringSchema.optional(),
606
+ definitionId: z.number().int().optional()
607
+ }),
608
+ lighthouse_team_metrics_workItemAgePercentiles: z.object({
609
+ id: z.number().int(),
610
+ startDate: isoDateStringSchema.optional(),
611
+ endDate: isoDateStringSchema.optional()
612
+ }),
613
+ lighthouse_portfolio_metrics_workItemAgePercentiles: z.object({
481
614
  id: z.number().int(),
482
615
  startDate: isoDateStringSchema.optional(),
483
616
  endDate: isoDateStringSchema.optional()
@@ -549,6 +682,12 @@ var toolInputSchemas = {
549
682
  }),
550
683
  lighthouse_feature_workitems: z.object({ id: z.number().int() }),
551
684
  lighthouse_delivery_list: z.object({ id: z.number().int() }),
685
+ lighthouse_blackout_list: z.object({}),
686
+ lighthouse_blackout_create: recurringBlackoutRuleInputSchema,
687
+ lighthouse_blackout_update: recurringBlackoutRuleInputSchema.extend({
688
+ id: z.number().int()
689
+ }),
690
+ lighthouse_blackout_delete: z.object({ id: z.number().int() }),
552
691
  lighthouse_forecast_manual: z.object({
553
692
  id: z.number().int(),
554
693
  remainingItems: z.number().int().optional(),
@@ -564,7 +703,7 @@ var toolInputSchemas = {
564
703
  applyFilterOverride: z.boolean().optional()
565
704
  })
566
705
  };
567
- var isReadOnlyTool = (toolName) => !toolName.endsWith("_refresh");
706
+ var isReadOnlyTool = (toolName) => !(toolName.endsWith("_refresh") || toolName.endsWith("_create") || toolName.endsWith("_update") || toolName.endsWith("_delete"));
568
707
  var createMcpCoreRuntime = (dependencies) => ({
569
708
  listTools: () => toolDefinitions,
570
709
  callTool: async (name, argumentsPayload) => {
@@ -711,7 +850,12 @@ var createMcpCoreRuntime = (dependencies) => ({
711
850
  return getErrorToolResult("team metrics: invalid id");
712
851
  }
713
852
  const range = getDateRange(argumentsPayload);
714
- const result = await client.getTeamCycleTimePercentiles(id, range);
853
+ const definitionId = getDefinitionId(argumentsPayload);
854
+ const result = await client.getTeamCycleTimePercentiles(
855
+ id,
856
+ range,
857
+ definitionId
858
+ );
715
859
  if (result.ok) {
716
860
  return getSuccessToolResult(
717
861
  `team cycleTimePercentiles: ${encodePayload(result.value)}`
@@ -721,6 +865,38 @@ var createMcpCoreRuntime = (dependencies) => ({
721
865
  `team metrics: ${result.error.category} (${result.error.reason})`
722
866
  );
723
867
  }
868
+ if (name === "lighthouse_team_metrics_workItemAgePercentiles") {
869
+ const id = getNumericId(argumentsPayload);
870
+ if (id === null) {
871
+ return getErrorToolResult("team metrics: invalid id");
872
+ }
873
+ const range = getDateRange(argumentsPayload);
874
+ const result = await client.getTeamWorkItemAgePercentiles(id, range);
875
+ if (result.ok) {
876
+ return getSuccessToolResult(
877
+ `team workItemAgePercentiles: ${encodePayload(result.value)}`
878
+ );
879
+ }
880
+ return getErrorToolResult(
881
+ `team metrics: ${result.error.category} (${result.error.reason})`
882
+ );
883
+ }
884
+ if (name === "lighthouse_portfolio_metrics_workItemAgePercentiles") {
885
+ const id = getNumericId(argumentsPayload);
886
+ if (id === null) {
887
+ return getErrorToolResult("portfolio metrics: invalid id");
888
+ }
889
+ const range = getDateRange(argumentsPayload);
890
+ const result = await client.getPortfolioWorkItemAgePercentiles(id, range);
891
+ if (result.ok) {
892
+ return getSuccessToolResult(
893
+ `portfolio workItemAgePercentiles: ${encodePayload(result.value)}`
894
+ );
895
+ }
896
+ return getErrorToolResult(
897
+ `portfolio metrics: ${result.error.category} (${result.error.reason})`
898
+ );
899
+ }
724
900
  if (name === "lighthouse_team_metrics_cumulativeStateTime") {
725
901
  const id = getNumericId(argumentsPayload);
726
902
  if (id === null) {
@@ -992,6 +1168,59 @@ var createMcpCoreRuntime = (dependencies) => ({
992
1168
  `delivery: ${result.error.category} (${result.error.reason})`
993
1169
  );
994
1170
  }
1171
+ if (name === "lighthouse_blackout_list") {
1172
+ const result = await client.getRecurringBlackoutRules();
1173
+ if (result.ok) {
1174
+ return getSuccessToolResult(
1175
+ `recurringBlackoutRules: ${encodePayload(result.value)}`
1176
+ );
1177
+ }
1178
+ return getErrorToolResult(
1179
+ `blackout: ${result.error.category} (${result.error.reason})`
1180
+ );
1181
+ }
1182
+ if (name === "lighthouse_blackout_create") {
1183
+ const payload = isObjectRecord(argumentsPayload) ? argumentsPayload : {};
1184
+ const result = await client.createRecurringBlackoutRule(payload);
1185
+ if (result.ok) {
1186
+ return getSuccessToolResult(
1187
+ `recurringBlackoutRule: ${encodePayload(result.value)}`
1188
+ );
1189
+ }
1190
+ return getErrorToolResult(
1191
+ `blackout: ${result.error.category} (${result.error.reason})`
1192
+ );
1193
+ }
1194
+ if (name === "lighthouse_blackout_update") {
1195
+ const id = getNumericId(argumentsPayload);
1196
+ if (id === null) {
1197
+ return getErrorToolResult("blackout: invalid id (rule id required)");
1198
+ }
1199
+ const payload = isObjectRecord(argumentsPayload) ? argumentsPayload : {};
1200
+ const { id: _ignoredId, ...rulePayload } = payload;
1201
+ const result = await client.updateRecurringBlackoutRule(id, rulePayload);
1202
+ if (result.ok) {
1203
+ return getSuccessToolResult(
1204
+ `recurringBlackoutRule: ${encodePayload(result.value)}`
1205
+ );
1206
+ }
1207
+ return getErrorToolResult(
1208
+ `blackout: ${result.error.category} (${result.error.reason})`
1209
+ );
1210
+ }
1211
+ if (name === "lighthouse_blackout_delete") {
1212
+ const id = getNumericId(argumentsPayload);
1213
+ if (id === null) {
1214
+ return getErrorToolResult("blackout: invalid id (rule id required)");
1215
+ }
1216
+ const result = await client.deleteRecurringBlackoutRule(id);
1217
+ if (result.ok) {
1218
+ return getSuccessToolResult(`recurringBlackoutRule deleted: ${id}`);
1219
+ }
1220
+ return getErrorToolResult(
1221
+ `blackout: ${result.error.category} (${result.error.reason})`
1222
+ );
1223
+ }
995
1224
  if (name === "lighthouse_forecast_manual") {
996
1225
  const id = getNumericId(argumentsPayload);
997
1226
  if (id === null) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letpeoplework/lighthouse-mcp-core",
3
- "version": "1.2.0",
3
+ "version": "1.4.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.2.0"
29
+ "@letpeoplework/lighthouse-client": "1.4.0"
30
30
  },
31
31
  "scripts": {
32
32
  "build": "tsup src/index.ts --format esm,cjs --dts --clean",