@taiga-ai/mcp-server 0.26.0-dev.488 → 0.26.0-dev.489

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.
Files changed (2) hide show
  1. package/dist/index.js +21 -3
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5161,10 +5161,13 @@ function standingSummary(standing) {
5161
5161
  const severity = String(violation["severity"] ?? "unknown");
5162
5162
  bySeverity[severity] = (bySeverity[severity] ?? 0) + 1;
5163
5163
  }
5164
+ const stated = (state) => controls.filter((c) => c["state"] === state).length;
5164
5165
  return {
5165
5166
  controls: listed.length,
5166
5167
  controlsInPolicies: controls.length,
5167
- controlsWithNothingRecorded: controls.length - listed.length,
5168
+ controlsMet: stated("met"),
5169
+ controlsNotApplicable: stated("not_applicable"),
5170
+ controlsNotAssessed: stated("no_evidence"),
5168
5171
  violations: violations.length,
5169
5172
  bySeverity,
5170
5173
  resolvedViolations: resolved
@@ -5232,11 +5235,12 @@ function registerMaintenanceTools(server, client) {
5232
5235
  }));
5233
5236
  server.registerTool("taiga_get_policy_standing", {
5234
5237
  title: "Get a product's policy standing",
5235
- description: "How a product stands against the organization's published policies: summary counts, when the documents were assessed, and each violated control with its violations (critical and high only, citing the policy sentence and the contradicting passage) and the work on each. state: breached (open scanner findings map to it, by findingsByTier; routine-only is not urgent) or diverged (the documents contradict it). live: false means the violation's initiative ended without fixing it: it needs a person or a new fix. raisedFor: false means the link is the backlog planner's: it said an initiative a person asked it for would close the violation, which may be a dedicated fix or broader work; true means a fix was raised for it (taiga_fix_policy_violation or the sweep). An unlisted control is not \"passing\" (summary.controlsWithNothingRecorded counts them). full: true adds evidence and resolved ones. Fix with taiga_fix_policy_violation.",
5238
+ description: "How a product stands against the organization's published policies: summary counts, when the documents were assessed, and each violated control with its violations (critical and high only, citing the policy sentence and the contradicting passage) and the work on each. state: breached (open scanner findings map to it, by findingsByTier; routine-only is not urgent) or diverged (the documents contradict it). live: false means the violation's initiative ended without fixing it: it needs a person or a new fix. raisedFor: false means the link is the backlog planner's: it said an initiative a person asked it for would close the violation, which may be a dedicated fix or broader work; true means a fix was raised for it (taiga_fix_policy_violation or the sweep). summary counts the other controls: met or not applicable as the documents show it, or not assessed (no evidence either way, which is no pass). controlId reads one control: its state, the passage behind a verdict, its document violations and how many scanner findings breach it. full: true adds evidence and resolved ones. Fix with taiga_fix_policy_violation.",
5236
5239
  inputSchema: z.object({
5237
5240
  productId,
5238
5241
  full: z.boolean().optional().describe("Carry each violation's evidence and policy excerpt, cut to about 1,500 characters each, and up to 20 resolved violations (default false)"),
5239
- violationId: idInput("violation", "this tool lists them").optional().describe("Only this violation, in full and uncut: its evidence, policy excerpt and work")
5242
+ violationId: idInput("violation", "this tool lists them").optional().describe("Only this violation, in full and uncut: its evidence, policy excerpt and work"),
5243
+ controlId: z.string().trim().min(1).max(40).optional().describe("Only this control, such as SEC-5.1: whether it is met, not applicable, violated or not assessed, with the passage")
5240
5244
  }),
5241
5245
  annotations: READ_ONLY
5242
5246
  }, (params) => runTool(async () => {
@@ -5248,6 +5252,20 @@ function registerMaintenanceTools(server, client) {
5248
5252
  const note = standing.assessment?.state === "never" ? "Never assessed: the documents have not been checked against the policies yet, so nothing here is an all-clear. An assessment runs when the reality documents are derived or refreshed (taiga_refresh_reality_documents, paid work: ask first)." : null;
5249
5253
  const resolvedAny = Array.isArray(standing.resolvedDivergences) && standing.resolvedDivergences.length > 0;
5250
5254
  const wording = violations.length > 0 || resolvedAny ? { wordingNote: "A violation's evidence is from its assessedAt; its title and summary may be from when it was first recorded. Where they disagree, the evidence is current." } : {};
5255
+ if (params.controlId && params.violationId) return toolError("VALIDATION_ERROR", "Name either a control (controlId) or one violation (violationId), not both.");
5256
+ if (params.controlId) {
5257
+ const wanted = params.controlId.toUpperCase();
5258
+ const control = controls.find((c) => String(c.controlId).toUpperCase() === wanted);
5259
+ if (!control) return toolError("NOT_FOUND", "No control with that id in this product's policies; taiga_get_document (type, sections: []) lists a policy's controls.");
5260
+ const own = violations.filter((violation) => String(violation["controlId"]).toUpperCase() === wanted);
5261
+ return toolResult({
5262
+ ...control,
5263
+ ...control.state === "no_evidence" ? { meaning: "Not assessed: no finding or violation is recorded against it, and the documents were not found to show it met. That is no evidence either way, not a pass." } : {},
5264
+ violations: pickFields(own, VIOLATION_FIELDS),
5265
+ ...Number(control.findingCount ?? 0) > 0 ? { findingsNote: `${String(control.findingCount)} open scanner finding${control.findingCount === 1 ? "" : "s"} breach it; taiga_list_findings (productId) lists them with the controls each breaches.` } : {},
5266
+ ...own.length > 0 ? wording : {}
5267
+ });
5268
+ }
5251
5269
  if (params.violationId) {
5252
5270
  const one = [...violations, ...Array.isArray(standing.resolvedDivergences) ? standing.resolvedDivergences : []].find((violation) => violation["id"] === params.violationId);
5253
5271
  if (!one) return toolError("NOT_FOUND", "No violation with that ID on this product; this tool without violationId lists them.");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taiga-ai/mcp-server",
3
- "version": "0.26.0-dev.488",
3
+ "version": "0.26.0-dev.489",
4
4
  "description": "Taiga for AI coding assistants: read products, policies, initiatives and runs, and operate the line, over MCP",
5
5
  "mcpName": "ga.tai/mcp-server",
6
6
  "type": "module",