@letpeoplework/lighthouse-mcp-core 0.1.0 → 0.3.1

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.d.mts CHANGED
@@ -13,7 +13,7 @@ type McpToolResult = {
13
13
  readonly content: readonly McpToolContent[];
14
14
  };
15
15
  type McpToolDefinition = {
16
- 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";
16
+ 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.portfolio.metrics.throughput" | "lighthouse.feature.get" | "lighthouse.feature.workitems" | "lighthouse.delivery.list" | "lighthouse.forecast.manual" | "lighthouse.forecast.backtest";
17
17
  readonly description: string;
18
18
  readonly inputSchema: {
19
19
  readonly type: "object";
@@ -116,6 +116,143 @@ type McpRuntimeClient = {
116
116
  readonly reason: string;
117
117
  };
118
118
  }>;
119
+ readonly getTeamThroughput: (id: number, range?: {
120
+ readonly startDate: string;
121
+ readonly endDate: string;
122
+ }) => Promise<{
123
+ readonly ok: true;
124
+ readonly value: unknown;
125
+ } | {
126
+ readonly ok: false;
127
+ readonly error: {
128
+ readonly category: string;
129
+ readonly reason: string;
130
+ };
131
+ }>;
132
+ readonly getTeamCycleTimePercentiles: (id: number, range?: {
133
+ readonly startDate: string;
134
+ readonly endDate: string;
135
+ }) => Promise<{
136
+ readonly ok: true;
137
+ readonly value: readonly unknown[];
138
+ } | {
139
+ readonly ok: false;
140
+ readonly error: {
141
+ readonly category: string;
142
+ readonly reason: string;
143
+ };
144
+ }>;
145
+ readonly getPortfolioThroughput: (id: number, range?: {
146
+ readonly startDate: string;
147
+ readonly endDate: string;
148
+ }) => Promise<{
149
+ readonly ok: true;
150
+ readonly value: unknown;
151
+ } | {
152
+ readonly ok: false;
153
+ readonly error: {
154
+ readonly category: string;
155
+ readonly reason: string;
156
+ };
157
+ }>;
158
+ readonly getFeaturesByIds: (ids: readonly number[]) => Promise<{
159
+ readonly ok: true;
160
+ readonly value: readonly unknown[];
161
+ } | {
162
+ readonly ok: false;
163
+ readonly error: {
164
+ readonly category: string;
165
+ readonly reason: string;
166
+ };
167
+ }>;
168
+ readonly getFeaturesByReferences: (refs: readonly string[]) => Promise<{
169
+ readonly ok: true;
170
+ readonly value: readonly unknown[];
171
+ } | {
172
+ readonly ok: false;
173
+ readonly error: {
174
+ readonly category: string;
175
+ readonly reason: string;
176
+ };
177
+ }>;
178
+ readonly getFeatureWorkItems: (featureId: number) => Promise<{
179
+ readonly ok: true;
180
+ readonly value: readonly unknown[];
181
+ } | {
182
+ readonly ok: false;
183
+ readonly error: {
184
+ readonly category: string;
185
+ readonly reason: string;
186
+ };
187
+ }>;
188
+ readonly listDeliveries: (portfolioId: number) => Promise<{
189
+ readonly ok: true;
190
+ readonly value: readonly unknown[];
191
+ } | {
192
+ readonly ok: false;
193
+ readonly error: {
194
+ readonly category: string;
195
+ readonly reason: string;
196
+ };
197
+ }>;
198
+ readonly createDelivery: (portfolioId: number, payload: Readonly<Record<string, unknown>>) => Promise<{
199
+ readonly ok: true;
200
+ readonly value: unknown;
201
+ } | {
202
+ readonly ok: false;
203
+ readonly error: {
204
+ readonly category: string;
205
+ readonly reason: string;
206
+ };
207
+ }>;
208
+ readonly updateDelivery: (deliveryId: number, payload: Readonly<Record<string, unknown>>) => Promise<{
209
+ readonly ok: true;
210
+ readonly value: unknown;
211
+ } | {
212
+ readonly ok: false;
213
+ readonly error: {
214
+ readonly category: string;
215
+ readonly reason: string;
216
+ };
217
+ }>;
218
+ readonly deleteDelivery: (deliveryId: number) => Promise<{
219
+ readonly ok: true;
220
+ readonly value: undefined;
221
+ } | {
222
+ readonly ok: false;
223
+ readonly error: {
224
+ readonly category: string;
225
+ readonly reason: string;
226
+ };
227
+ }>;
228
+ readonly runManualForecast: (teamId: number, payload: {
229
+ readonly remainingItems?: number;
230
+ readonly targetDate?: string;
231
+ }) => Promise<{
232
+ readonly ok: true;
233
+ readonly value: unknown;
234
+ } | {
235
+ readonly ok: false;
236
+ readonly error: {
237
+ readonly category: string;
238
+ readonly reason: string;
239
+ };
240
+ }>;
241
+ readonly runBacktest: (teamId: number, payload: {
242
+ readonly startDate: string;
243
+ readonly endDate: string;
244
+ readonly historicalStartDate: string;
245
+ readonly historicalEndDate: string;
246
+ }) => Promise<{
247
+ readonly ok: true;
248
+ readonly value: unknown;
249
+ } | {
250
+ readonly ok: false;
251
+ readonly error: {
252
+ readonly category: string;
253
+ readonly reason: string;
254
+ };
255
+ }>;
119
256
  };
120
257
  type McpCoreRuntimeDependencies = {
121
258
  readonly createClient: () => McpRuntimeClient;
package/dist/index.d.ts CHANGED
@@ -13,7 +13,7 @@ type McpToolResult = {
13
13
  readonly content: readonly McpToolContent[];
14
14
  };
15
15
  type McpToolDefinition = {
16
- 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";
16
+ 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.portfolio.metrics.throughput" | "lighthouse.feature.get" | "lighthouse.feature.workitems" | "lighthouse.delivery.list" | "lighthouse.forecast.manual" | "lighthouse.forecast.backtest";
17
17
  readonly description: string;
18
18
  readonly inputSchema: {
19
19
  readonly type: "object";
@@ -116,6 +116,143 @@ type McpRuntimeClient = {
116
116
  readonly reason: string;
117
117
  };
118
118
  }>;
119
+ readonly getTeamThroughput: (id: number, range?: {
120
+ readonly startDate: string;
121
+ readonly endDate: string;
122
+ }) => Promise<{
123
+ readonly ok: true;
124
+ readonly value: unknown;
125
+ } | {
126
+ readonly ok: false;
127
+ readonly error: {
128
+ readonly category: string;
129
+ readonly reason: string;
130
+ };
131
+ }>;
132
+ readonly getTeamCycleTimePercentiles: (id: number, range?: {
133
+ readonly startDate: string;
134
+ readonly endDate: string;
135
+ }) => Promise<{
136
+ readonly ok: true;
137
+ readonly value: readonly unknown[];
138
+ } | {
139
+ readonly ok: false;
140
+ readonly error: {
141
+ readonly category: string;
142
+ readonly reason: string;
143
+ };
144
+ }>;
145
+ readonly getPortfolioThroughput: (id: number, range?: {
146
+ readonly startDate: string;
147
+ readonly endDate: string;
148
+ }) => Promise<{
149
+ readonly ok: true;
150
+ readonly value: unknown;
151
+ } | {
152
+ readonly ok: false;
153
+ readonly error: {
154
+ readonly category: string;
155
+ readonly reason: string;
156
+ };
157
+ }>;
158
+ readonly getFeaturesByIds: (ids: readonly number[]) => Promise<{
159
+ readonly ok: true;
160
+ readonly value: readonly unknown[];
161
+ } | {
162
+ readonly ok: false;
163
+ readonly error: {
164
+ readonly category: string;
165
+ readonly reason: string;
166
+ };
167
+ }>;
168
+ readonly getFeaturesByReferences: (refs: readonly string[]) => Promise<{
169
+ readonly ok: true;
170
+ readonly value: readonly unknown[];
171
+ } | {
172
+ readonly ok: false;
173
+ readonly error: {
174
+ readonly category: string;
175
+ readonly reason: string;
176
+ };
177
+ }>;
178
+ readonly getFeatureWorkItems: (featureId: number) => Promise<{
179
+ readonly ok: true;
180
+ readonly value: readonly unknown[];
181
+ } | {
182
+ readonly ok: false;
183
+ readonly error: {
184
+ readonly category: string;
185
+ readonly reason: string;
186
+ };
187
+ }>;
188
+ readonly listDeliveries: (portfolioId: number) => Promise<{
189
+ readonly ok: true;
190
+ readonly value: readonly unknown[];
191
+ } | {
192
+ readonly ok: false;
193
+ readonly error: {
194
+ readonly category: string;
195
+ readonly reason: string;
196
+ };
197
+ }>;
198
+ readonly createDelivery: (portfolioId: number, payload: Readonly<Record<string, unknown>>) => Promise<{
199
+ readonly ok: true;
200
+ readonly value: unknown;
201
+ } | {
202
+ readonly ok: false;
203
+ readonly error: {
204
+ readonly category: string;
205
+ readonly reason: string;
206
+ };
207
+ }>;
208
+ readonly updateDelivery: (deliveryId: number, payload: Readonly<Record<string, unknown>>) => Promise<{
209
+ readonly ok: true;
210
+ readonly value: unknown;
211
+ } | {
212
+ readonly ok: false;
213
+ readonly error: {
214
+ readonly category: string;
215
+ readonly reason: string;
216
+ };
217
+ }>;
218
+ readonly deleteDelivery: (deliveryId: number) => Promise<{
219
+ readonly ok: true;
220
+ readonly value: undefined;
221
+ } | {
222
+ readonly ok: false;
223
+ readonly error: {
224
+ readonly category: string;
225
+ readonly reason: string;
226
+ };
227
+ }>;
228
+ readonly runManualForecast: (teamId: number, payload: {
229
+ readonly remainingItems?: number;
230
+ readonly targetDate?: string;
231
+ }) => Promise<{
232
+ readonly ok: true;
233
+ readonly value: unknown;
234
+ } | {
235
+ readonly ok: false;
236
+ readonly error: {
237
+ readonly category: string;
238
+ readonly reason: string;
239
+ };
240
+ }>;
241
+ readonly runBacktest: (teamId: number, payload: {
242
+ readonly startDate: string;
243
+ readonly endDate: string;
244
+ readonly historicalStartDate: string;
245
+ readonly historicalEndDate: string;
246
+ }) => Promise<{
247
+ readonly ok: true;
248
+ readonly value: unknown;
249
+ } | {
250
+ readonly ok: false;
251
+ readonly error: {
252
+ readonly category: string;
253
+ readonly reason: string;
254
+ };
255
+ }>;
119
256
  };
120
257
  type McpCoreRuntimeDependencies = {
121
258
  readonly createClient: () => McpRuntimeClient;
package/dist/index.js CHANGED
@@ -119,6 +119,78 @@ var toolDefinitions = [
119
119
  properties: {},
120
120
  additionalProperties: false
121
121
  }
122
+ },
123
+ {
124
+ name: "lighthouse.team.metrics.throughput",
125
+ description: "Get throughput run-chart data for a team. Requires id. Optional startDate and endDate (ISO date strings, defaults to last 90 days).",
126
+ inputSchema: {
127
+ type: "object",
128
+ properties: {},
129
+ additionalProperties: false
130
+ }
131
+ },
132
+ {
133
+ name: "lighthouse.team.metrics.cycleTimePercentiles",
134
+ description: "Get cycle-time percentiles for a team. Requires id. Optional startDate and endDate (ISO date strings, defaults to last 90 days).",
135
+ inputSchema: {
136
+ type: "object",
137
+ properties: {},
138
+ additionalProperties: false
139
+ }
140
+ },
141
+ {
142
+ name: "lighthouse.portfolio.metrics.throughput",
143
+ description: "Get throughput run-chart data for a portfolio. Requires id. Optional startDate and endDate (ISO date strings, defaults to last 90 days).",
144
+ inputSchema: {
145
+ type: "object",
146
+ properties: {},
147
+ additionalProperties: false
148
+ }
149
+ },
150
+ {
151
+ name: "lighthouse.feature.get",
152
+ description: "Get features by ids (provide ids array) or by reference ids (provide refs array).",
153
+ inputSchema: {
154
+ type: "object",
155
+ properties: {},
156
+ additionalProperties: false
157
+ }
158
+ },
159
+ {
160
+ name: "lighthouse.feature.workitems",
161
+ description: "Get work items for a feature. Requires id.",
162
+ inputSchema: {
163
+ type: "object",
164
+ properties: {},
165
+ additionalProperties: false
166
+ }
167
+ },
168
+ {
169
+ name: "lighthouse.delivery.list",
170
+ description: "List deliveries for a portfolio. Requires id (portfolio id).",
171
+ inputSchema: {
172
+ type: "object",
173
+ properties: {},
174
+ additionalProperties: false
175
+ }
176
+ },
177
+ {
178
+ name: "lighthouse.forecast.manual",
179
+ description: "Run a manual forecast for a team. Requires id (team id). Optional remainingItems and targetDate.",
180
+ inputSchema: {
181
+ type: "object",
182
+ properties: {},
183
+ additionalProperties: false
184
+ }
185
+ },
186
+ {
187
+ name: "lighthouse.forecast.backtest",
188
+ description: "Run a backtest forecast for a team. Requires id, startDate, endDate, historicalStartDate, historicalEndDate.",
189
+ inputSchema: {
190
+ type: "object",
191
+ properties: {},
192
+ additionalProperties: false
193
+ }
122
194
  }
123
195
  ];
124
196
  var getSuccessToolResult = (text) => ({
@@ -149,6 +221,20 @@ var getNumericId = (argumentsPayload) => {
149
221
  }
150
222
  return null;
151
223
  };
224
+ var isObjectRecord = (value) => {
225
+ return typeof value === "object" && value !== null && !Array.isArray(value);
226
+ };
227
+ var getDateRange = (argumentsPayload) => {
228
+ if (!isObjectRecord(argumentsPayload)) {
229
+ return void 0;
230
+ }
231
+ const startDate = argumentsPayload.startDate;
232
+ const endDate = argumentsPayload.endDate;
233
+ if (typeof startDate === "string" && typeof endDate === "string") {
234
+ return { startDate, endDate };
235
+ }
236
+ return void 0;
237
+ };
152
238
  var createMcpCoreRuntime = (dependencies) => ({
153
239
  listTools: () => toolDefinitions,
154
240
  callTool: async (name, argumentsPayload) => {
@@ -271,6 +357,171 @@ var createMcpCoreRuntime = (dependencies) => ({
271
357
  `portfolio refresh: ${result.error.category} (${result.error.reason})`
272
358
  );
273
359
  }
360
+ if (name === "lighthouse.team.metrics.throughput") {
361
+ const id = getNumericId(argumentsPayload);
362
+ if (id === null) {
363
+ return getErrorToolResult("team metrics: invalid id");
364
+ }
365
+ const range = getDateRange(argumentsPayload);
366
+ const result = await client.getTeamThroughput(id, range);
367
+ if (result.ok) {
368
+ return getSuccessToolResult(
369
+ `team throughput: ${JSON.stringify(result.value)}`
370
+ );
371
+ }
372
+ return getErrorToolResult(
373
+ `team metrics: ${result.error.category} (${result.error.reason})`
374
+ );
375
+ }
376
+ if (name === "lighthouse.team.metrics.cycleTimePercentiles") {
377
+ const id = getNumericId(argumentsPayload);
378
+ if (id === null) {
379
+ return getErrorToolResult("team metrics: invalid id");
380
+ }
381
+ const range = getDateRange(argumentsPayload);
382
+ const result = await client.getTeamCycleTimePercentiles(id, range);
383
+ if (result.ok) {
384
+ return getSuccessToolResult(
385
+ `team cycleTimePercentiles: ${JSON.stringify(result.value)}`
386
+ );
387
+ }
388
+ return getErrorToolResult(
389
+ `team metrics: ${result.error.category} (${result.error.reason})`
390
+ );
391
+ }
392
+ if (name === "lighthouse.portfolio.metrics.throughput") {
393
+ const id = getNumericId(argumentsPayload);
394
+ if (id === null) {
395
+ return getErrorToolResult("portfolio metrics: invalid id");
396
+ }
397
+ const range = getDateRange(argumentsPayload);
398
+ const result = await client.getPortfolioThroughput(id, range);
399
+ if (result.ok) {
400
+ return getSuccessToolResult(
401
+ `portfolio throughput: ${JSON.stringify(result.value)}`
402
+ );
403
+ }
404
+ return getErrorToolResult(
405
+ `portfolio metrics: ${result.error.category} (${result.error.reason})`
406
+ );
407
+ }
408
+ if (name === "lighthouse.feature.get") {
409
+ const payload = isObjectRecord(argumentsPayload) ? argumentsPayload : {};
410
+ const idsValue = payload.ids;
411
+ const refsValue = payload.refs;
412
+ if (Array.isArray(idsValue) && idsValue.length > 0) {
413
+ const ids = idsValue.filter((v) => typeof v === "number");
414
+ const result = await client.getFeaturesByIds(ids);
415
+ if (result.ok) {
416
+ return getSuccessToolResult(
417
+ `features: ${JSON.stringify(result.value)}`
418
+ );
419
+ }
420
+ return getErrorToolResult(
421
+ `features: ${result.error.category} (${result.error.reason})`
422
+ );
423
+ }
424
+ if (Array.isArray(refsValue) && refsValue.length > 0) {
425
+ const refs = refsValue.filter(
426
+ (v) => typeof v === "string"
427
+ );
428
+ const result = await client.getFeaturesByReferences(refs);
429
+ if (result.ok) {
430
+ return getSuccessToolResult(
431
+ `features: ${JSON.stringify(result.value)}`
432
+ );
433
+ }
434
+ return getErrorToolResult(
435
+ `features: ${result.error.category} (${result.error.reason})`
436
+ );
437
+ }
438
+ return getErrorToolResult(
439
+ "features: provide ids (array of numbers) or refs (array of strings)"
440
+ );
441
+ }
442
+ if (name === "lighthouse.feature.workitems") {
443
+ const id = getNumericId(argumentsPayload);
444
+ if (id === null) {
445
+ return getErrorToolResult("feature workitems: invalid id");
446
+ }
447
+ const result = await client.getFeatureWorkItems(id);
448
+ if (result.ok) {
449
+ return getSuccessToolResult(
450
+ `feature workitems: ${JSON.stringify(result.value)}`
451
+ );
452
+ }
453
+ return getErrorToolResult(
454
+ `feature workitems: ${result.error.category} (${result.error.reason})`
455
+ );
456
+ }
457
+ if (name === "lighthouse.delivery.list") {
458
+ const id = getNumericId(argumentsPayload);
459
+ if (id === null) {
460
+ return getErrorToolResult(
461
+ "delivery: invalid id (portfolio id required)"
462
+ );
463
+ }
464
+ const result = await client.listDeliveries(id);
465
+ if (result.ok) {
466
+ return getSuccessToolResult(
467
+ `deliveries: ${JSON.stringify(result.value)}`
468
+ );
469
+ }
470
+ return getErrorToolResult(
471
+ `delivery: ${result.error.category} (${result.error.reason})`
472
+ );
473
+ }
474
+ if (name === "lighthouse.forecast.manual") {
475
+ const id = getNumericId(argumentsPayload);
476
+ if (id === null) {
477
+ return getErrorToolResult("forecast: invalid id (team id required)");
478
+ }
479
+ const payload = isObjectRecord(argumentsPayload) ? argumentsPayload : {};
480
+ const remainingItems = typeof payload.remainingItems === "number" ? payload.remainingItems : void 0;
481
+ const targetDate = typeof payload.targetDate === "string" ? payload.targetDate : void 0;
482
+ const result = await client.runManualForecast(id, {
483
+ remainingItems,
484
+ targetDate
485
+ });
486
+ if (result.ok) {
487
+ return getSuccessToolResult(
488
+ `forecast: ${JSON.stringify(result.value)}`
489
+ );
490
+ }
491
+ return getErrorToolResult(
492
+ `forecast: ${result.error.category} (${result.error.reason})`
493
+ );
494
+ }
495
+ if (name === "lighthouse.forecast.backtest") {
496
+ const id = getNumericId(argumentsPayload);
497
+ if (id === null) {
498
+ return getErrorToolResult("backtest: invalid id (team id required)");
499
+ }
500
+ const payload = isObjectRecord(argumentsPayload) ? argumentsPayload : {};
501
+ const startDate = typeof payload.startDate === "string" ? payload.startDate : void 0;
502
+ const endDate = typeof payload.endDate === "string" ? payload.endDate : void 0;
503
+ const historicalStartDate = typeof payload.historicalStartDate === "string" ? payload.historicalStartDate : void 0;
504
+ const historicalEndDate = typeof payload.historicalEndDate === "string" ? payload.historicalEndDate : void 0;
505
+ if (!startDate || !endDate || !historicalStartDate || !historicalEndDate) {
506
+ return getErrorToolResult(
507
+ "backtest: startDate, endDate, historicalStartDate, and historicalEndDate are required"
508
+ );
509
+ }
510
+ const result = await client.runBacktest(id, {
511
+ startDate,
512
+ endDate,
513
+ historicalStartDate,
514
+ historicalEndDate
515
+ });
516
+ if (result.ok) {
517
+ return getSuccessToolResult(
518
+ `backtest: ${JSON.stringify(result.value)}`
519
+ );
520
+ }
521
+ return getErrorToolResult(
522
+ `backtest: ${result.error.category} (${result.error.reason})`
523
+ );
524
+ }
274
525
  return getErrorToolResult(`Unknown tool: ${name}`);
275
526
  }
276
527
  });
package/dist/index.mjs CHANGED
@@ -94,6 +94,78 @@ var toolDefinitions = [
94
94
  properties: {},
95
95
  additionalProperties: false
96
96
  }
97
+ },
98
+ {
99
+ name: "lighthouse.team.metrics.throughput",
100
+ description: "Get throughput run-chart data for a team. Requires id. Optional startDate and endDate (ISO date strings, defaults to last 90 days).",
101
+ inputSchema: {
102
+ type: "object",
103
+ properties: {},
104
+ additionalProperties: false
105
+ }
106
+ },
107
+ {
108
+ name: "lighthouse.team.metrics.cycleTimePercentiles",
109
+ description: "Get cycle-time percentiles for a team. Requires id. Optional startDate and endDate (ISO date strings, defaults to last 90 days).",
110
+ inputSchema: {
111
+ type: "object",
112
+ properties: {},
113
+ additionalProperties: false
114
+ }
115
+ },
116
+ {
117
+ name: "lighthouse.portfolio.metrics.throughput",
118
+ description: "Get throughput run-chart data for a portfolio. Requires id. Optional startDate and endDate (ISO date strings, defaults to last 90 days).",
119
+ inputSchema: {
120
+ type: "object",
121
+ properties: {},
122
+ additionalProperties: false
123
+ }
124
+ },
125
+ {
126
+ name: "lighthouse.feature.get",
127
+ description: "Get features by ids (provide ids array) or by reference ids (provide refs array).",
128
+ inputSchema: {
129
+ type: "object",
130
+ properties: {},
131
+ additionalProperties: false
132
+ }
133
+ },
134
+ {
135
+ name: "lighthouse.feature.workitems",
136
+ description: "Get work items for a feature. Requires id.",
137
+ inputSchema: {
138
+ type: "object",
139
+ properties: {},
140
+ additionalProperties: false
141
+ }
142
+ },
143
+ {
144
+ name: "lighthouse.delivery.list",
145
+ description: "List deliveries for a portfolio. Requires id (portfolio id).",
146
+ inputSchema: {
147
+ type: "object",
148
+ properties: {},
149
+ additionalProperties: false
150
+ }
151
+ },
152
+ {
153
+ name: "lighthouse.forecast.manual",
154
+ description: "Run a manual forecast for a team. Requires id (team id). Optional remainingItems and targetDate.",
155
+ inputSchema: {
156
+ type: "object",
157
+ properties: {},
158
+ additionalProperties: false
159
+ }
160
+ },
161
+ {
162
+ name: "lighthouse.forecast.backtest",
163
+ description: "Run a backtest forecast for a team. Requires id, startDate, endDate, historicalStartDate, historicalEndDate.",
164
+ inputSchema: {
165
+ type: "object",
166
+ properties: {},
167
+ additionalProperties: false
168
+ }
97
169
  }
98
170
  ];
99
171
  var getSuccessToolResult = (text) => ({
@@ -124,6 +196,20 @@ var getNumericId = (argumentsPayload) => {
124
196
  }
125
197
  return null;
126
198
  };
199
+ var isObjectRecord = (value) => {
200
+ return typeof value === "object" && value !== null && !Array.isArray(value);
201
+ };
202
+ var getDateRange = (argumentsPayload) => {
203
+ if (!isObjectRecord(argumentsPayload)) {
204
+ return void 0;
205
+ }
206
+ const startDate = argumentsPayload.startDate;
207
+ const endDate = argumentsPayload.endDate;
208
+ if (typeof startDate === "string" && typeof endDate === "string") {
209
+ return { startDate, endDate };
210
+ }
211
+ return void 0;
212
+ };
127
213
  var createMcpCoreRuntime = (dependencies) => ({
128
214
  listTools: () => toolDefinitions,
129
215
  callTool: async (name, argumentsPayload) => {
@@ -246,6 +332,171 @@ var createMcpCoreRuntime = (dependencies) => ({
246
332
  `portfolio refresh: ${result.error.category} (${result.error.reason})`
247
333
  );
248
334
  }
335
+ if (name === "lighthouse.team.metrics.throughput") {
336
+ const id = getNumericId(argumentsPayload);
337
+ if (id === null) {
338
+ return getErrorToolResult("team metrics: invalid id");
339
+ }
340
+ const range = getDateRange(argumentsPayload);
341
+ const result = await client.getTeamThroughput(id, range);
342
+ if (result.ok) {
343
+ return getSuccessToolResult(
344
+ `team throughput: ${JSON.stringify(result.value)}`
345
+ );
346
+ }
347
+ return getErrorToolResult(
348
+ `team metrics: ${result.error.category} (${result.error.reason})`
349
+ );
350
+ }
351
+ if (name === "lighthouse.team.metrics.cycleTimePercentiles") {
352
+ const id = getNumericId(argumentsPayload);
353
+ if (id === null) {
354
+ return getErrorToolResult("team metrics: invalid id");
355
+ }
356
+ const range = getDateRange(argumentsPayload);
357
+ const result = await client.getTeamCycleTimePercentiles(id, range);
358
+ if (result.ok) {
359
+ return getSuccessToolResult(
360
+ `team cycleTimePercentiles: ${JSON.stringify(result.value)}`
361
+ );
362
+ }
363
+ return getErrorToolResult(
364
+ `team metrics: ${result.error.category} (${result.error.reason})`
365
+ );
366
+ }
367
+ if (name === "lighthouse.portfolio.metrics.throughput") {
368
+ const id = getNumericId(argumentsPayload);
369
+ if (id === null) {
370
+ return getErrorToolResult("portfolio metrics: invalid id");
371
+ }
372
+ const range = getDateRange(argumentsPayload);
373
+ const result = await client.getPortfolioThroughput(id, range);
374
+ if (result.ok) {
375
+ return getSuccessToolResult(
376
+ `portfolio throughput: ${JSON.stringify(result.value)}`
377
+ );
378
+ }
379
+ return getErrorToolResult(
380
+ `portfolio metrics: ${result.error.category} (${result.error.reason})`
381
+ );
382
+ }
383
+ if (name === "lighthouse.feature.get") {
384
+ const payload = isObjectRecord(argumentsPayload) ? argumentsPayload : {};
385
+ const idsValue = payload.ids;
386
+ const refsValue = payload.refs;
387
+ if (Array.isArray(idsValue) && idsValue.length > 0) {
388
+ const ids = idsValue.filter((v) => typeof v === "number");
389
+ const result = await client.getFeaturesByIds(ids);
390
+ if (result.ok) {
391
+ return getSuccessToolResult(
392
+ `features: ${JSON.stringify(result.value)}`
393
+ );
394
+ }
395
+ return getErrorToolResult(
396
+ `features: ${result.error.category} (${result.error.reason})`
397
+ );
398
+ }
399
+ if (Array.isArray(refsValue) && refsValue.length > 0) {
400
+ const refs = refsValue.filter(
401
+ (v) => typeof v === "string"
402
+ );
403
+ const result = await client.getFeaturesByReferences(refs);
404
+ if (result.ok) {
405
+ return getSuccessToolResult(
406
+ `features: ${JSON.stringify(result.value)}`
407
+ );
408
+ }
409
+ return getErrorToolResult(
410
+ `features: ${result.error.category} (${result.error.reason})`
411
+ );
412
+ }
413
+ return getErrorToolResult(
414
+ "features: provide ids (array of numbers) or refs (array of strings)"
415
+ );
416
+ }
417
+ if (name === "lighthouse.feature.workitems") {
418
+ const id = getNumericId(argumentsPayload);
419
+ if (id === null) {
420
+ return getErrorToolResult("feature workitems: invalid id");
421
+ }
422
+ const result = await client.getFeatureWorkItems(id);
423
+ if (result.ok) {
424
+ return getSuccessToolResult(
425
+ `feature workitems: ${JSON.stringify(result.value)}`
426
+ );
427
+ }
428
+ return getErrorToolResult(
429
+ `feature workitems: ${result.error.category} (${result.error.reason})`
430
+ );
431
+ }
432
+ if (name === "lighthouse.delivery.list") {
433
+ const id = getNumericId(argumentsPayload);
434
+ if (id === null) {
435
+ return getErrorToolResult(
436
+ "delivery: invalid id (portfolio id required)"
437
+ );
438
+ }
439
+ const result = await client.listDeliveries(id);
440
+ if (result.ok) {
441
+ return getSuccessToolResult(
442
+ `deliveries: ${JSON.stringify(result.value)}`
443
+ );
444
+ }
445
+ return getErrorToolResult(
446
+ `delivery: ${result.error.category} (${result.error.reason})`
447
+ );
448
+ }
449
+ if (name === "lighthouse.forecast.manual") {
450
+ const id = getNumericId(argumentsPayload);
451
+ if (id === null) {
452
+ return getErrorToolResult("forecast: invalid id (team id required)");
453
+ }
454
+ const payload = isObjectRecord(argumentsPayload) ? argumentsPayload : {};
455
+ const remainingItems = typeof payload.remainingItems === "number" ? payload.remainingItems : void 0;
456
+ const targetDate = typeof payload.targetDate === "string" ? payload.targetDate : void 0;
457
+ const result = await client.runManualForecast(id, {
458
+ remainingItems,
459
+ targetDate
460
+ });
461
+ if (result.ok) {
462
+ return getSuccessToolResult(
463
+ `forecast: ${JSON.stringify(result.value)}`
464
+ );
465
+ }
466
+ return getErrorToolResult(
467
+ `forecast: ${result.error.category} (${result.error.reason})`
468
+ );
469
+ }
470
+ if (name === "lighthouse.forecast.backtest") {
471
+ const id = getNumericId(argumentsPayload);
472
+ if (id === null) {
473
+ return getErrorToolResult("backtest: invalid id (team id required)");
474
+ }
475
+ const payload = isObjectRecord(argumentsPayload) ? argumentsPayload : {};
476
+ const startDate = typeof payload.startDate === "string" ? payload.startDate : void 0;
477
+ const endDate = typeof payload.endDate === "string" ? payload.endDate : void 0;
478
+ const historicalStartDate = typeof payload.historicalStartDate === "string" ? payload.historicalStartDate : void 0;
479
+ const historicalEndDate = typeof payload.historicalEndDate === "string" ? payload.historicalEndDate : void 0;
480
+ if (!startDate || !endDate || !historicalStartDate || !historicalEndDate) {
481
+ return getErrorToolResult(
482
+ "backtest: startDate, endDate, historicalStartDate, and historicalEndDate are required"
483
+ );
484
+ }
485
+ const result = await client.runBacktest(id, {
486
+ startDate,
487
+ endDate,
488
+ historicalStartDate,
489
+ historicalEndDate
490
+ });
491
+ if (result.ok) {
492
+ return getSuccessToolResult(
493
+ `backtest: ${JSON.stringify(result.value)}`
494
+ );
495
+ }
496
+ return getErrorToolResult(
497
+ `backtest: ${result.error.category} (${result.error.reason})`
498
+ );
499
+ }
249
500
  return getErrorToolResult(`Unknown tool: ${name}`);
250
501
  }
251
502
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letpeoplework/lighthouse-mcp-core",
3
- "version": "0.1.0",
3
+ "version": "0.3.1",
4
4
  "description": "Shared MCP semantics for Lighthouse",
5
5
  "repository": "https://github.com/LetPeopleWork/lighthouse-clients",
6
6
  "main": "dist/index.cjs",
@@ -17,10 +17,12 @@
17
17
  "dist"
18
18
  ],
19
19
  "publishConfig": {
20
- "access": "public"
20
+ "access": "public",
21
+ "provenance": true,
22
+ "registry": "https://registry.npmjs.org/"
21
23
  },
22
24
  "dependencies": {
23
- "@letpeoplework/lighthouse-client": "0.1.0"
25
+ "@letpeoplework/lighthouse-client": "0.3.1"
24
26
  },
25
27
  "scripts": {
26
28
  "build": "tsup src/index.ts --format esm,cjs --dts --clean",