@letpeoplework/lighthouse-mcp-core 1.9.0 → 1.10.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 +118 -1
- package/dist/index.d.cts +6 -3
- package/dist/index.d.ts +6 -3
- package/dist/index.js +119 -2
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -426,6 +426,119 @@ const REFINEMENT_TOOLS = /* @__PURE__ */ new Map([
|
|
|
426
426
|
/** The handler of a refinement tool, or undefined for a tool that is not one. */
|
|
427
427
|
const findRefinementTool = (name) => REFINEMENT_TOOLS.get(name);
|
|
428
428
|
//#endregion
|
|
429
|
+
//#region src/reportTools.ts
|
|
430
|
+
const HOW_LIGHTHOUSE_SHOWS_IT = "Read the lighthouse-reports skill for how Lighthouse shows these values, and quote them as they come.";
|
|
431
|
+
const HOW_THE_ANSWER_READS = "The first block is Lighthouse's answer, unchanged; a second text block, `summary`,";
|
|
432
|
+
const LIST_LABEL = "reports";
|
|
433
|
+
const GET_LABEL = "report";
|
|
434
|
+
const NEEDS_A_SERVER = "Needs a Lighthouse newer than v26.10.10.1.";
|
|
435
|
+
const ownerIdProperty = (kind) => ({
|
|
436
|
+
type: "integer",
|
|
437
|
+
description: `The ${kind}'s numeric id.`
|
|
438
|
+
});
|
|
439
|
+
const reportIdProperty = {
|
|
440
|
+
type: "integer",
|
|
441
|
+
description: "The report's id, as its owner's report list names it under reports[].id."
|
|
442
|
+
};
|
|
443
|
+
const listInputSchema = (kind) => ({
|
|
444
|
+
type: "object",
|
|
445
|
+
properties: { id: ownerIdProperty(kind) },
|
|
446
|
+
required: ["id"],
|
|
447
|
+
additionalProperties: false
|
|
448
|
+
});
|
|
449
|
+
const getInputSchema = (kind) => ({
|
|
450
|
+
type: "object",
|
|
451
|
+
properties: {
|
|
452
|
+
id: ownerIdProperty(kind),
|
|
453
|
+
reportId: reportIdProperty
|
|
454
|
+
},
|
|
455
|
+
required: ["id", "reportId"],
|
|
456
|
+
additionalProperties: false
|
|
457
|
+
});
|
|
458
|
+
const listDescription = (kind) => `List the reports a ${kind} holds by ${kind} ID: each report's id, name, type (templateKey) and when it was created. ${HOW_THE_ANSWER_READS} names the ${kind} and counts its reports in the instance's terminology. ${HOW_LIGHTHOUSE_SHOWS_IT} ${NEEDS_A_SERVER}`;
|
|
459
|
+
const getDescription = (kind) => `Get one of a ${kind}'s reports by ${kind} ID and reportId, exactly as Lighthouse answers it: its Then side as Lighthouse froze it, its Now side read afresh up to today, and every value, a missing value with its reason. ${HOW_LIGHTHOUSE_SHOWS_IT} ${HOW_THE_ANSWER_READS} names the report, its ${kind} and its Then and Now windows. ${NEEDS_A_SERVER}`;
|
|
460
|
+
const reportToolDefinitions = [
|
|
461
|
+
{
|
|
462
|
+
name: "lighthouse_team_report_list",
|
|
463
|
+
description: listDescription("team"),
|
|
464
|
+
inputSchema: listInputSchema("team")
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
name: "lighthouse_team_report_get",
|
|
468
|
+
description: getDescription("team"),
|
|
469
|
+
inputSchema: getInputSchema("team")
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
name: "lighthouse_portfolio_report_list",
|
|
473
|
+
description: listDescription("portfolio"),
|
|
474
|
+
inputSchema: listInputSchema("portfolio")
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
name: "lighthouse_portfolio_report_get",
|
|
478
|
+
description: getDescription("portfolio"),
|
|
479
|
+
inputSchema: getInputSchema("portfolio")
|
|
480
|
+
}
|
|
481
|
+
];
|
|
482
|
+
const listSchema = zod.z.object({ id: zod.z.number().int() });
|
|
483
|
+
const getSchema = zod.z.object({
|
|
484
|
+
id: zod.z.number().int(),
|
|
485
|
+
reportId: zod.z.number().int()
|
|
486
|
+
});
|
|
487
|
+
const reportInputSchemas = {
|
|
488
|
+
lighthouse_team_report_list: listSchema,
|
|
489
|
+
lighthouse_team_report_get: getSchema,
|
|
490
|
+
lighthouse_portfolio_report_list: listSchema,
|
|
491
|
+
lighthouse_portfolio_report_get: getSchema
|
|
492
|
+
};
|
|
493
|
+
const getReportId = (argumentsPayload) => {
|
|
494
|
+
const reportId = typeof argumentsPayload === "object" && argumentsPayload !== null ? argumentsPayload.reportId : void 0;
|
|
495
|
+
return typeof reportId === "number" && Number.isInteger(reportId) ? reportId : null;
|
|
496
|
+
};
|
|
497
|
+
const answerReportRead = async (client, owner, result, answer) => {
|
|
498
|
+
if (!result.ok) return getErrorToolResult(`${answer.label}: ${await (0, _letpeoplework_lighthouse_client.readReportRefusal)(client, result.error, owner.kind, answer.read)}`);
|
|
499
|
+
const ownerName = await (0, _letpeoplework_lighthouse_client.readReportOwner)(client, owner);
|
|
500
|
+
return withSummaryBlock(`${answer.label}: ${encodePayload(result.value)}`, answer.summarise(result.value, ownerName));
|
|
501
|
+
};
|
|
502
|
+
const invalid = (label, what) => getErrorToolResult(`${label}: invalid ${what}`);
|
|
503
|
+
const reportList = (kind) => async (argumentsPayload, client) => {
|
|
504
|
+
const id = getNumericId(argumentsPayload);
|
|
505
|
+
if (id === null) return invalid(LIST_LABEL, "id");
|
|
506
|
+
const owner = {
|
|
507
|
+
kind,
|
|
508
|
+
id
|
|
509
|
+
};
|
|
510
|
+
return answerReportRead(client, owner, await (0, _letpeoplework_lighthouse_client.readOwnersReports)(client, owner), {
|
|
511
|
+
label: LIST_LABEL,
|
|
512
|
+
read: "list",
|
|
513
|
+
summarise: _letpeoplework_lighthouse_client.summariseReportList
|
|
514
|
+
});
|
|
515
|
+
};
|
|
516
|
+
const reportGet = (kind) => async (argumentsPayload, client) => {
|
|
517
|
+
const id = getNumericId(argumentsPayload);
|
|
518
|
+
if (id === null) return invalid(GET_LABEL, "id");
|
|
519
|
+
const reportId = getReportId(argumentsPayload);
|
|
520
|
+
if (reportId === null) return invalid(GET_LABEL, "reportId");
|
|
521
|
+
const owner = {
|
|
522
|
+
kind,
|
|
523
|
+
id
|
|
524
|
+
};
|
|
525
|
+
const result = await (0, _letpeoplework_lighthouse_client.readOwnersReport)(client, owner, reportId);
|
|
526
|
+
const answered = await answerReportRead(client, owner, result, {
|
|
527
|
+
label: GET_LABEL,
|
|
528
|
+
read: "report",
|
|
529
|
+
summarise: _letpeoplework_lighthouse_client.summariseReport
|
|
530
|
+
});
|
|
531
|
+
return countedToolResult(answered, (0, _letpeoplework_lighthouse_client.reportOpenedOccurrencesOf)(result));
|
|
532
|
+
};
|
|
533
|
+
const REPORT_TOOLS = /* @__PURE__ */ new Map([
|
|
534
|
+
["lighthouse_team_report_list", reportList("team")],
|
|
535
|
+
["lighthouse_team_report_get", reportGet("team")],
|
|
536
|
+
["lighthouse_portfolio_report_list", reportList("portfolio")],
|
|
537
|
+
["lighthouse_portfolio_report_get", reportGet("portfolio")]
|
|
538
|
+
]);
|
|
539
|
+
/** The handler of one of the report tools, or undefined for any other tool. */
|
|
540
|
+
const findReportTool = (name) => REPORT_TOOLS.get(name);
|
|
541
|
+
//#endregion
|
|
429
542
|
//#region src/index.ts
|
|
430
543
|
const getMcpCorePackageContract = () => ({
|
|
431
544
|
name: "@letpeoplework/lighthouse-mcp-core",
|
|
@@ -1076,7 +1189,8 @@ const toolDefinitions = [
|
|
|
1076
1189
|
name: "lighthouse_portfolio_metrics_processBehaviorChart",
|
|
1077
1190
|
description: "Get one Process Behaviour Chart of a portfolio by ID, as Lighthouse computes it: its status (and statusReason when it is not Ready), the average and natural process limits, whether a baseline is configured, and every point (xValue, yValue) with the signals Lighthouse found on it (specialCauses: LargeChange, ModerateChange, ModerateShift, SmallShift; None means no signal) and whether it falls on a blackout day (isBlackout). metricType picks the chart: Throughput, Arrivals, Wip, WorkItemAge (the Total Work Item Age chart), CycleTime or FeatureSize. A point is a day, except on CycleTime, which has one point per finished work item, and FeatureSize, which has one per finished feature, each dated when it finished, so several can share a day. Use it for \"is something unusual going on\" and \"did our process change\"; never work a signal out yourself. Optionally filtered by start and end dates. A second text block, `summary: …`, states the answer as lh does, in the instance's terminology: the heading, the chart's title, and each signal with the days it fired, or that there are no signals; the facts are unchanged.",
|
|
1078
1191
|
inputSchema: chartInputSchema(processBehaviorMetricTypes)
|
|
1079
|
-
}
|
|
1192
|
+
},
|
|
1193
|
+
...reportToolDefinitions
|
|
1080
1194
|
];
|
|
1081
1195
|
const getDefinitionId = (argumentsPayload) => {
|
|
1082
1196
|
if (typeof argumentsPayload !== "object" || argumentsPayload === null || Array.isArray(argumentsPayload)) return;
|
|
@@ -1363,6 +1477,7 @@ const toolInputSchemas = {
|
|
|
1363
1477
|
lighthouse_team_refresh: zod.z.object({ id: zod.z.number().int() }),
|
|
1364
1478
|
lighthouse_team_refinement_get: zod.z.object({ id: zod.z.number().int() }),
|
|
1365
1479
|
...refinementWriteInputSchemas,
|
|
1480
|
+
...reportInputSchemas,
|
|
1366
1481
|
lighthouse_portfolio_list: zod.z.object({}),
|
|
1367
1482
|
lighthouse_portfolio_get: zod.z.object({ id: zod.z.number().int() }),
|
|
1368
1483
|
lighthouse_portfolio_refresh: zod.z.object({ id: zod.z.number().int() }),
|
|
@@ -1589,6 +1704,8 @@ const answerToolCall = (dependencies) => async (name, argumentsPayload) => {
|
|
|
1589
1704
|
}
|
|
1590
1705
|
const refinementTool = findRefinementTool(name);
|
|
1591
1706
|
if (refinementTool !== void 0) return refinementTool(argumentsPayload, client, dependencies);
|
|
1707
|
+
const reportTool = findReportTool(name);
|
|
1708
|
+
if (reportTool !== void 0) return reportTool(argumentsPayload, client);
|
|
1592
1709
|
if (name === "lighthouse_portfolio_list") return answerOwnerList("portfolio", "portfolios", client.listPortfolios(), client);
|
|
1593
1710
|
if (name === "lighthouse_portfolio_get") {
|
|
1594
1711
|
const id = getNumericId(argumentsPayload);
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DeliveryMetricsHistory, LighthouseApiResult, LighthouseClient, LighthouseVoterKeyStore, PortfolioDeliveries, RefinementMomentFacts, RefinementWordingSource, TeamRefinement, UsageDataOccurrence, UsageDataQuestionAnswer, UsageDataStep, VotedRow } from "@letpeoplework/lighthouse-client";
|
|
1
|
+
import { DeliveryMetricsHistory, LighthouseApiResult, LighthouseClient, LighthouseVoterKeyStore, PortfolioDeliveries, RefinementMomentFacts, RefinementWordingSource, ReportOwnerSource, ReportReads, TeamRefinement, UsageDataOccurrence, UsageDataQuestionAnswer, UsageDataStep, VotedRow } from "@letpeoplework/lighthouse-client";
|
|
2
2
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
3
|
import "zod";
|
|
4
4
|
import { ElicitRequestFormParams, ElicitResult } from "@modelcontextprotocol/sdk/types.js";
|
|
@@ -75,6 +75,9 @@ type ToolError = {
|
|
|
75
75
|
};
|
|
76
76
|
type RefinementToolClient = RefinementWordingSource<ToolError> & Pick<LighthouseClient, "getTeamRefinement" | "castRefinementVote" | "addRefinementComment" | "takeBackRefinementVote" | "getRefinementLog" | "getTerminology">;
|
|
77
77
|
//#endregion
|
|
78
|
+
//#region src/reportTools.d.ts
|
|
79
|
+
type ReportToolClient = ReportReads & ReportOwnerSource;
|
|
80
|
+
//#endregion
|
|
78
81
|
//#region src/index.d.ts
|
|
79
82
|
export type McpCorePackageContract = {
|
|
80
83
|
readonly name: "@letpeoplework/lighthouse-mcp-core";
|
|
@@ -83,7 +86,7 @@ export type McpCorePackageContract = {
|
|
|
83
86
|
};
|
|
84
87
|
export declare const getMcpCorePackageContract: () => McpCorePackageContract;
|
|
85
88
|
export type McpToolDefinition = {
|
|
86
|
-
readonly name: "lighthouse_health_check" | "lighthouse_version_get" | "lighthouse_worktracking_list" | "lighthouse_worktracking_get" | "lighthouse_team_list" | "lighthouse_team_get" | "lighthouse_team_refresh" | "lighthouse_team_refinement_get" | "lighthouse_team_refinement_vote" | "lighthouse_team_refinement_comment" | "lighthouse_team_refinement_voteTakeBack" | "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_wip" | "lighthouse_team_metrics_sleRisk" | "lighthouse_team_metrics_processBehaviorChart" | "lighthouse_portfolio_metrics_processBehaviorChart" | "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_delivery_metrics" | "lighthouse_blackout_list" | "lighthouse_blackout_create" | "lighthouse_blackout_update" | "lighthouse_blackout_delete" | "lighthouse_forecast_manual" | "lighthouse_forecast_backtest";
|
|
89
|
+
readonly name: "lighthouse_health_check" | "lighthouse_version_get" | "lighthouse_worktracking_list" | "lighthouse_worktracking_get" | "lighthouse_team_list" | "lighthouse_team_get" | "lighthouse_team_refresh" | "lighthouse_team_refinement_get" | "lighthouse_team_refinement_vote" | "lighthouse_team_refinement_comment" | "lighthouse_team_refinement_voteTakeBack" | "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_wip" | "lighthouse_team_metrics_sleRisk" | "lighthouse_team_metrics_processBehaviorChart" | "lighthouse_portfolio_metrics_processBehaviorChart" | "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_delivery_metrics" | "lighthouse_blackout_list" | "lighthouse_blackout_create" | "lighthouse_blackout_update" | "lighthouse_blackout_delete" | "lighthouse_forecast_manual" | "lighthouse_forecast_backtest" | "lighthouse_team_report_list" | "lighthouse_team_report_get" | "lighthouse_portfolio_report_list" | "lighthouse_portfolio_report_get";
|
|
87
90
|
readonly description: string;
|
|
88
91
|
readonly inputSchema: {
|
|
89
92
|
readonly type: "object";
|
|
@@ -669,7 +672,7 @@ type McpRuntimeClient = {
|
|
|
669
672
|
readonly reason: string;
|
|
670
673
|
};
|
|
671
674
|
}>;
|
|
672
|
-
} & Omit<RefinementToolClient, "getTeam">;
|
|
675
|
+
} & Omit<RefinementToolClient, "getTeam"> & Omit<ReportToolClient, "getTeam" | "getPortfolio">;
|
|
673
676
|
export type McpCoreRuntimeDependencies = {
|
|
674
677
|
readonly createClient: () => McpRuntimeClient;
|
|
675
678
|
/** Where usage data goes; without it a tool call does exactly what it always did. */
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DeliveryMetricsHistory, LighthouseApiResult, LighthouseClient, LighthouseVoterKeyStore, PortfolioDeliveries, RefinementMomentFacts, RefinementWordingSource, TeamRefinement, UsageDataOccurrence, UsageDataQuestionAnswer, UsageDataStep, VotedRow } from "@letpeoplework/lighthouse-client";
|
|
1
|
+
import { DeliveryMetricsHistory, LighthouseApiResult, LighthouseClient, LighthouseVoterKeyStore, PortfolioDeliveries, RefinementMomentFacts, RefinementWordingSource, ReportOwnerSource, ReportReads, TeamRefinement, UsageDataOccurrence, UsageDataQuestionAnswer, UsageDataStep, VotedRow } from "@letpeoplework/lighthouse-client";
|
|
2
2
|
import { ElicitRequestFormParams, ElicitResult } from "@modelcontextprotocol/sdk/types.js";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -75,6 +75,9 @@ type ToolError = {
|
|
|
75
75
|
};
|
|
76
76
|
type RefinementToolClient = RefinementWordingSource<ToolError> & Pick<LighthouseClient, "getTeamRefinement" | "castRefinementVote" | "addRefinementComment" | "takeBackRefinementVote" | "getRefinementLog" | "getTerminology">;
|
|
77
77
|
//#endregion
|
|
78
|
+
//#region src/reportTools.d.ts
|
|
79
|
+
type ReportToolClient = ReportReads & ReportOwnerSource;
|
|
80
|
+
//#endregion
|
|
78
81
|
//#region src/index.d.ts
|
|
79
82
|
export type McpCorePackageContract = {
|
|
80
83
|
readonly name: "@letpeoplework/lighthouse-mcp-core";
|
|
@@ -83,7 +86,7 @@ export type McpCorePackageContract = {
|
|
|
83
86
|
};
|
|
84
87
|
export declare const getMcpCorePackageContract: () => McpCorePackageContract;
|
|
85
88
|
export type McpToolDefinition = {
|
|
86
|
-
readonly name: "lighthouse_health_check" | "lighthouse_version_get" | "lighthouse_worktracking_list" | "lighthouse_worktracking_get" | "lighthouse_team_list" | "lighthouse_team_get" | "lighthouse_team_refresh" | "lighthouse_team_refinement_get" | "lighthouse_team_refinement_vote" | "lighthouse_team_refinement_comment" | "lighthouse_team_refinement_voteTakeBack" | "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_wip" | "lighthouse_team_metrics_sleRisk" | "lighthouse_team_metrics_processBehaviorChart" | "lighthouse_portfolio_metrics_processBehaviorChart" | "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_delivery_metrics" | "lighthouse_blackout_list" | "lighthouse_blackout_create" | "lighthouse_blackout_update" | "lighthouse_blackout_delete" | "lighthouse_forecast_manual" | "lighthouse_forecast_backtest";
|
|
89
|
+
readonly name: "lighthouse_health_check" | "lighthouse_version_get" | "lighthouse_worktracking_list" | "lighthouse_worktracking_get" | "lighthouse_team_list" | "lighthouse_team_get" | "lighthouse_team_refresh" | "lighthouse_team_refinement_get" | "lighthouse_team_refinement_vote" | "lighthouse_team_refinement_comment" | "lighthouse_team_refinement_voteTakeBack" | "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_wip" | "lighthouse_team_metrics_sleRisk" | "lighthouse_team_metrics_processBehaviorChart" | "lighthouse_portfolio_metrics_processBehaviorChart" | "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_delivery_metrics" | "lighthouse_blackout_list" | "lighthouse_blackout_create" | "lighthouse_blackout_update" | "lighthouse_blackout_delete" | "lighthouse_forecast_manual" | "lighthouse_forecast_backtest" | "lighthouse_team_report_list" | "lighthouse_team_report_get" | "lighthouse_portfolio_report_list" | "lighthouse_portfolio_report_get";
|
|
87
90
|
readonly description: string;
|
|
88
91
|
readonly inputSchema: {
|
|
89
92
|
readonly type: "object";
|
|
@@ -669,7 +672,7 @@ type McpRuntimeClient = {
|
|
|
669
672
|
readonly reason: string;
|
|
670
673
|
};
|
|
671
674
|
}>;
|
|
672
|
-
} & Omit<RefinementToolClient, "getTeam">;
|
|
675
|
+
} & Omit<RefinementToolClient, "getTeam"> & Omit<ReportToolClient, "getTeam" | "getPortfolio">;
|
|
673
676
|
export type McpCoreRuntimeDependencies = {
|
|
674
677
|
readonly createClient: () => McpRuntimeClient;
|
|
675
678
|
/** Where usage data goes; without it a tool call does exactly what it always did. */
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { LIGHTHOUSE_IS_REACHABLE, REFINEMENT_ANSWERS, describeAsOfHeading, describeBacktestActual, describeBacktestPeriod, describeBacktestSummary, describeBlackoutRuleCount, describeBlackoutRuleWriteConfirmation, describeBlockedDays, describeBlockedNow, describeConnectionSummary, describeCycleTimeDays, describeDeliveryCount, describeDeliveryMetricsHeading, describeFeatureListCount, describeFeatureWorkItemsHeading, describeInProgressNow, describeManualForecastLikelihood, describeManualForecastSummary, describeMetricSummary, describeMetricsHeading, describeMissingCondition, describeNothingToTakeBack, describeOwnerCount, describePercentilesOverTimeDays, describePortfolioSummary, describeProcessBehaviorChart, describeProcessBehaviorOverTimeDays, describeRecordedComment, describeRecordedVote, describeRefinementSummary, describeRefreshConfirmation, describeSleRiskNow, describeStaleNow, describeTakenBack, describeTeamSummary, describeThroughputDays, describeTimeInStateContributorDays, describeTimeInStateDays, describeTotalWorkItemAgeDays, describeVersion, describeWhatWipLeavesUnsaid, describeWorkItemAgeDays, describeWorkItemAgePercentiles, describeWorkTrackingSystemCount, getDefaultMetricsDateRange, isMissingItsCondition, isRefinementAnswer, keepVoterKey, myVoteOn, readAnswerWording, readBacktest, readBlackoutRules, readBlocked, readCycleTimeDefinitionName, readCycleTimePercentiles, readDeliveryMetricsHistory, readFeatureList, readFeatureWording, readFeatureWorkItems, readInProgressItems, readManualForecast, readNameOfMyVote, readOwnerList, readPercentilesOverTime, readPortfolio, readPortfolioDeliveries, readProcessBehaviorChart, readProcessBehaviorOverTime, readRefinementWording, readRunChart, readServiceLevelExpectation, readSleRisk, readSystemWipLimit, readTeam, readTerms, readTimeInStateBar, readTimeInStateContributors, readTotalWorkItemAge, readVoteRefusal, readWorkItemAge, readWorkItemAgePercentiles, readWorkTrackingConnections, readWrittenBlackoutRule, refinementDayVerdictOf, sizingMomentOf, summariseDeliveryMetricsHistory } from "@letpeoplework/lighthouse-client";
|
|
1
|
+
import { LIGHTHOUSE_IS_REACHABLE, REFINEMENT_ANSWERS, describeAsOfHeading, describeBacktestActual, describeBacktestPeriod, describeBacktestSummary, describeBlackoutRuleCount, describeBlackoutRuleWriteConfirmation, describeBlockedDays, describeBlockedNow, describeConnectionSummary, describeCycleTimeDays, describeDeliveryCount, describeDeliveryMetricsHeading, describeFeatureListCount, describeFeatureWorkItemsHeading, describeInProgressNow, describeManualForecastLikelihood, describeManualForecastSummary, describeMetricSummary, describeMetricsHeading, describeMissingCondition, describeNothingToTakeBack, describeOwnerCount, describePercentilesOverTimeDays, describePortfolioSummary, describeProcessBehaviorChart, describeProcessBehaviorOverTimeDays, describeRecordedComment, describeRecordedVote, describeRefinementSummary, describeRefreshConfirmation, describeSleRiskNow, describeStaleNow, describeTakenBack, describeTeamSummary, describeThroughputDays, describeTimeInStateContributorDays, describeTimeInStateDays, describeTotalWorkItemAgeDays, describeVersion, describeWhatWipLeavesUnsaid, describeWorkItemAgeDays, describeWorkItemAgePercentiles, describeWorkTrackingSystemCount, getDefaultMetricsDateRange, isMissingItsCondition, isRefinementAnswer, keepVoterKey, myVoteOn, readAnswerWording, readBacktest, readBlackoutRules, readBlocked, readCycleTimeDefinitionName, readCycleTimePercentiles, readDeliveryMetricsHistory, readFeatureList, readFeatureWording, readFeatureWorkItems, readInProgressItems, readManualForecast, readNameOfMyVote, readOwnerList, readOwnersReport, readOwnersReports, readPercentilesOverTime, readPortfolio, readPortfolioDeliveries, readProcessBehaviorChart, readProcessBehaviorOverTime, readRefinementWording, readReportOwner, readReportRefusal, readRunChart, readServiceLevelExpectation, readSleRisk, readSystemWipLimit, readTeam, readTerms, readTimeInStateBar, readTimeInStateContributors, readTotalWorkItemAge, readVoteRefusal, readWorkItemAge, readWorkItemAgePercentiles, readWorkTrackingConnections, readWrittenBlackoutRule, refinementDayVerdictOf, reportOpenedOccurrencesOf, sizingMomentOf, summariseDeliveryMetricsHistory, summariseReport, summariseReportList } from "@letpeoplework/lighthouse-client";
|
|
2
2
|
import { ElicitResultSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { encode } from "@toon-format/toon";
|
|
@@ -425,6 +425,119 @@ const REFINEMENT_TOOLS = /* @__PURE__ */ new Map([
|
|
|
425
425
|
/** The handler of a refinement tool, or undefined for a tool that is not one. */
|
|
426
426
|
const findRefinementTool = (name) => REFINEMENT_TOOLS.get(name);
|
|
427
427
|
//#endregion
|
|
428
|
+
//#region src/reportTools.ts
|
|
429
|
+
const HOW_LIGHTHOUSE_SHOWS_IT = "Read the lighthouse-reports skill for how Lighthouse shows these values, and quote them as they come.";
|
|
430
|
+
const HOW_THE_ANSWER_READS = "The first block is Lighthouse's answer, unchanged; a second text block, `summary`,";
|
|
431
|
+
const LIST_LABEL = "reports";
|
|
432
|
+
const GET_LABEL = "report";
|
|
433
|
+
const NEEDS_A_SERVER = "Needs a Lighthouse newer than v26.10.10.1.";
|
|
434
|
+
const ownerIdProperty = (kind) => ({
|
|
435
|
+
type: "integer",
|
|
436
|
+
description: `The ${kind}'s numeric id.`
|
|
437
|
+
});
|
|
438
|
+
const reportIdProperty = {
|
|
439
|
+
type: "integer",
|
|
440
|
+
description: "The report's id, as its owner's report list names it under reports[].id."
|
|
441
|
+
};
|
|
442
|
+
const listInputSchema = (kind) => ({
|
|
443
|
+
type: "object",
|
|
444
|
+
properties: { id: ownerIdProperty(kind) },
|
|
445
|
+
required: ["id"],
|
|
446
|
+
additionalProperties: false
|
|
447
|
+
});
|
|
448
|
+
const getInputSchema = (kind) => ({
|
|
449
|
+
type: "object",
|
|
450
|
+
properties: {
|
|
451
|
+
id: ownerIdProperty(kind),
|
|
452
|
+
reportId: reportIdProperty
|
|
453
|
+
},
|
|
454
|
+
required: ["id", "reportId"],
|
|
455
|
+
additionalProperties: false
|
|
456
|
+
});
|
|
457
|
+
const listDescription = (kind) => `List the reports a ${kind} holds by ${kind} ID: each report's id, name, type (templateKey) and when it was created. ${HOW_THE_ANSWER_READS} names the ${kind} and counts its reports in the instance's terminology. ${HOW_LIGHTHOUSE_SHOWS_IT} ${NEEDS_A_SERVER}`;
|
|
458
|
+
const getDescription = (kind) => `Get one of a ${kind}'s reports by ${kind} ID and reportId, exactly as Lighthouse answers it: its Then side as Lighthouse froze it, its Now side read afresh up to today, and every value, a missing value with its reason. ${HOW_LIGHTHOUSE_SHOWS_IT} ${HOW_THE_ANSWER_READS} names the report, its ${kind} and its Then and Now windows. ${NEEDS_A_SERVER}`;
|
|
459
|
+
const reportToolDefinitions = [
|
|
460
|
+
{
|
|
461
|
+
name: "lighthouse_team_report_list",
|
|
462
|
+
description: listDescription("team"),
|
|
463
|
+
inputSchema: listInputSchema("team")
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
name: "lighthouse_team_report_get",
|
|
467
|
+
description: getDescription("team"),
|
|
468
|
+
inputSchema: getInputSchema("team")
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
name: "lighthouse_portfolio_report_list",
|
|
472
|
+
description: listDescription("portfolio"),
|
|
473
|
+
inputSchema: listInputSchema("portfolio")
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
name: "lighthouse_portfolio_report_get",
|
|
477
|
+
description: getDescription("portfolio"),
|
|
478
|
+
inputSchema: getInputSchema("portfolio")
|
|
479
|
+
}
|
|
480
|
+
];
|
|
481
|
+
const listSchema = z.object({ id: z.number().int() });
|
|
482
|
+
const getSchema = z.object({
|
|
483
|
+
id: z.number().int(),
|
|
484
|
+
reportId: z.number().int()
|
|
485
|
+
});
|
|
486
|
+
const reportInputSchemas = {
|
|
487
|
+
lighthouse_team_report_list: listSchema,
|
|
488
|
+
lighthouse_team_report_get: getSchema,
|
|
489
|
+
lighthouse_portfolio_report_list: listSchema,
|
|
490
|
+
lighthouse_portfolio_report_get: getSchema
|
|
491
|
+
};
|
|
492
|
+
const getReportId = (argumentsPayload) => {
|
|
493
|
+
const reportId = typeof argumentsPayload === "object" && argumentsPayload !== null ? argumentsPayload.reportId : void 0;
|
|
494
|
+
return typeof reportId === "number" && Number.isInteger(reportId) ? reportId : null;
|
|
495
|
+
};
|
|
496
|
+
const answerReportRead = async (client, owner, result, answer) => {
|
|
497
|
+
if (!result.ok) return getErrorToolResult(`${answer.label}: ${await readReportRefusal(client, result.error, owner.kind, answer.read)}`);
|
|
498
|
+
const ownerName = await readReportOwner(client, owner);
|
|
499
|
+
return withSummaryBlock(`${answer.label}: ${encodePayload(result.value)}`, answer.summarise(result.value, ownerName));
|
|
500
|
+
};
|
|
501
|
+
const invalid = (label, what) => getErrorToolResult(`${label}: invalid ${what}`);
|
|
502
|
+
const reportList = (kind) => async (argumentsPayload, client) => {
|
|
503
|
+
const id = getNumericId(argumentsPayload);
|
|
504
|
+
if (id === null) return invalid(LIST_LABEL, "id");
|
|
505
|
+
const owner = {
|
|
506
|
+
kind,
|
|
507
|
+
id
|
|
508
|
+
};
|
|
509
|
+
return answerReportRead(client, owner, await readOwnersReports(client, owner), {
|
|
510
|
+
label: LIST_LABEL,
|
|
511
|
+
read: "list",
|
|
512
|
+
summarise: summariseReportList
|
|
513
|
+
});
|
|
514
|
+
};
|
|
515
|
+
const reportGet = (kind) => async (argumentsPayload, client) => {
|
|
516
|
+
const id = getNumericId(argumentsPayload);
|
|
517
|
+
if (id === null) return invalid(GET_LABEL, "id");
|
|
518
|
+
const reportId = getReportId(argumentsPayload);
|
|
519
|
+
if (reportId === null) return invalid(GET_LABEL, "reportId");
|
|
520
|
+
const owner = {
|
|
521
|
+
kind,
|
|
522
|
+
id
|
|
523
|
+
};
|
|
524
|
+
const result = await readOwnersReport(client, owner, reportId);
|
|
525
|
+
const answered = await answerReportRead(client, owner, result, {
|
|
526
|
+
label: GET_LABEL,
|
|
527
|
+
read: "report",
|
|
528
|
+
summarise: summariseReport
|
|
529
|
+
});
|
|
530
|
+
return countedToolResult(answered, reportOpenedOccurrencesOf(result));
|
|
531
|
+
};
|
|
532
|
+
const REPORT_TOOLS = /* @__PURE__ */ new Map([
|
|
533
|
+
["lighthouse_team_report_list", reportList("team")],
|
|
534
|
+
["lighthouse_team_report_get", reportGet("team")],
|
|
535
|
+
["lighthouse_portfolio_report_list", reportList("portfolio")],
|
|
536
|
+
["lighthouse_portfolio_report_get", reportGet("portfolio")]
|
|
537
|
+
]);
|
|
538
|
+
/** The handler of one of the report tools, or undefined for any other tool. */
|
|
539
|
+
const findReportTool = (name) => REPORT_TOOLS.get(name);
|
|
540
|
+
//#endregion
|
|
428
541
|
//#region src/index.ts
|
|
429
542
|
const getMcpCorePackageContract = () => ({
|
|
430
543
|
name: "@letpeoplework/lighthouse-mcp-core",
|
|
@@ -1075,7 +1188,8 @@ const toolDefinitions = [
|
|
|
1075
1188
|
name: "lighthouse_portfolio_metrics_processBehaviorChart",
|
|
1076
1189
|
description: "Get one Process Behaviour Chart of a portfolio by ID, as Lighthouse computes it: its status (and statusReason when it is not Ready), the average and natural process limits, whether a baseline is configured, and every point (xValue, yValue) with the signals Lighthouse found on it (specialCauses: LargeChange, ModerateChange, ModerateShift, SmallShift; None means no signal) and whether it falls on a blackout day (isBlackout). metricType picks the chart: Throughput, Arrivals, Wip, WorkItemAge (the Total Work Item Age chart), CycleTime or FeatureSize. A point is a day, except on CycleTime, which has one point per finished work item, and FeatureSize, which has one per finished feature, each dated when it finished, so several can share a day. Use it for \"is something unusual going on\" and \"did our process change\"; never work a signal out yourself. Optionally filtered by start and end dates. A second text block, `summary: …`, states the answer as lh does, in the instance's terminology: the heading, the chart's title, and each signal with the days it fired, or that there are no signals; the facts are unchanged.",
|
|
1077
1190
|
inputSchema: chartInputSchema(processBehaviorMetricTypes)
|
|
1078
|
-
}
|
|
1191
|
+
},
|
|
1192
|
+
...reportToolDefinitions
|
|
1079
1193
|
];
|
|
1080
1194
|
const getDefinitionId = (argumentsPayload) => {
|
|
1081
1195
|
if (typeof argumentsPayload !== "object" || argumentsPayload === null || Array.isArray(argumentsPayload)) return;
|
|
@@ -1362,6 +1476,7 @@ const toolInputSchemas = {
|
|
|
1362
1476
|
lighthouse_team_refresh: z.object({ id: z.number().int() }),
|
|
1363
1477
|
lighthouse_team_refinement_get: z.object({ id: z.number().int() }),
|
|
1364
1478
|
...refinementWriteInputSchemas,
|
|
1479
|
+
...reportInputSchemas,
|
|
1365
1480
|
lighthouse_portfolio_list: z.object({}),
|
|
1366
1481
|
lighthouse_portfolio_get: z.object({ id: z.number().int() }),
|
|
1367
1482
|
lighthouse_portfolio_refresh: z.object({ id: z.number().int() }),
|
|
@@ -1588,6 +1703,8 @@ const answerToolCall = (dependencies) => async (name, argumentsPayload) => {
|
|
|
1588
1703
|
}
|
|
1589
1704
|
const refinementTool = findRefinementTool(name);
|
|
1590
1705
|
if (refinementTool !== void 0) return refinementTool(argumentsPayload, client, dependencies);
|
|
1706
|
+
const reportTool = findReportTool(name);
|
|
1707
|
+
if (reportTool !== void 0) return reportTool(argumentsPayload, client);
|
|
1591
1708
|
if (name === "lighthouse_portfolio_list") return answerOwnerList("portfolio", "portfolios", client.listPortfolios(), client);
|
|
1592
1709
|
if (name === "lighthouse_portfolio_get") {
|
|
1593
1710
|
const id = getNumericId(argumentsPayload);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@letpeoplework/lighthouse-mcp-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "Shared MCP semantics for Lighthouse",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"registry": "https://registry.npmjs.org/"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@letpeoplework/lighthouse-client": "1.
|
|
29
|
+
"@letpeoplework/lighthouse-client": "1.12.0",
|
|
30
30
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
31
31
|
"@toon-format/toon": "^4.0.0",
|
|
32
32
|
"zod": "^4.0.0"
|