@rigour-labs/mcp 6.3.1 → 6.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.
@@ -1,9 +1,18 @@
1
- /** Context, quality, and cost telemetry tools every agent should see first. */
2
- export declare const ESSENTIAL_CONTEXT_TOOLS: readonly ["rigour_recall", "rigour_index", "rigour_context_scope", "rigour_check_pattern", "rigour_check", "rigour_remember", "rigour_explain", "rigour_get_fix_packet", "rigour_review", "rigour_security_audit", "rigour_forget", "rigour_context_stats", "rigour_task_cost", "rigour_cache_stats", "rigour_context_explain"];
3
- /** Multi-agent governance, hooks, and execution tools with dispatch handlers. */
1
+ export declare const TOOL_GROUPS: {
2
+ /** Load memory, scope context, avoid reinvention, gate and review the change, learn. */
3
+ readonly core: readonly ["rigour_recall", "rigour_index", "rigour_context_scope", "rigour_check_pattern", "rigour_check", "rigour_review", "rigour_get_fix_packet", "rigour_remember"];
4
+ /** Multi-agent registration, checkpoints, handoffs, hooks and supervised runs. */
5
+ readonly governance: readonly ["rigour_agent_register", "rigour_agent_deregister", "rigour_checkpoint", "rigour_handoff", "rigour_handoff_accept", "rigour_hooks_check", "rigour_hooks_init", "rigour_run", "rigour_run_supervised"];
6
+ /** Occasional context and security tools. */
7
+ readonly context: readonly ["rigour_explain", "rigour_forget", "rigour_context_explain", "rigour_security_audit"];
8
+ /** Cost and cache telemetry, mostly for dashboards. */
9
+ readonly telemetry: readonly ["rigour_context_stats", "rigour_task_cost", "rigour_cache_stats"];
10
+ };
11
+ export type ToolGroup = keyof typeof TOOL_GROUPS;
4
12
  export declare const GOVERNANCE_TOOLS: readonly ["rigour_agent_register", "rigour_agent_deregister", "rigour_checkpoint", "rigour_handoff", "rigour_handoff_accept", "rigour_hooks_check", "rigour_hooks_init", "rigour_run", "rigour_run_supervised"];
5
- export declare const ADVERTISED_TOOLS: Set<string>;
6
- export declare function getAdvertisedToolDefinitions(): ({
13
+ /** Tool names for a RIGOUR_MCP_TOOLS value; core is always included, unknown groups are ignored. */
14
+ export declare function advertisedToolNames(spec?: string | undefined): Set<string>;
15
+ export declare function getAdvertisedToolDefinitions(spec?: string): ({
7
16
  name: string;
8
17
  description: string;
9
18
  inputSchema: {
@@ -599,11 +608,7 @@ export declare function getAdvertisedToolDefinitions(): ({
599
608
  inputSchema: {
600
609
  type: string;
601
610
  properties: {
602
- repository: {
603
- type: string;
604
- description: string;
605
- };
606
- branch: {
611
+ base: {
607
612
  type: string;
608
613
  description: string;
609
614
  };
@@ -1,46 +1,59 @@
1
1
  /**
2
2
  * MCP tools advertised to clients via ListTools.
3
3
  *
4
- * Essential context/quality tools stay visible for day-to-day agent work.
5
- * Governance tools are included so Cursor and other MCP clients can discover
6
- * multi-agent registration, checkpoints, handoffs, hooks, and supervised runs
7
- * without hunting for undocumented callable tools.
4
+ * Every advertised tool costs every agent session its definition in context
5
+ * and one more choice to get wrong, so the default is the core loop a single
6
+ * agent needs. Other groups are opt-in through RIGOUR_MCP_TOOLS in the MCP
7
+ * client's config, e.g. "governance,telemetry" or "full". Tools outside the
8
+ * advertised set stay callable; they are just not listed.
8
9
  */
9
10
  import { TOOL_DEFINITIONS } from './tools/definitions.js';
10
- /** Context, quality, and cost telemetry tools every agent should see first. */
11
- export const ESSENTIAL_CONTEXT_TOOLS = [
12
- 'rigour_recall',
13
- 'rigour_index',
14
- 'rigour_context_scope',
15
- 'rigour_check_pattern',
16
- 'rigour_check',
17
- 'rigour_remember',
18
- 'rigour_explain',
19
- 'rigour_get_fix_packet',
20
- 'rigour_review',
21
- 'rigour_security_audit',
22
- 'rigour_forget',
23
- 'rigour_context_stats',
24
- 'rigour_task_cost',
25
- 'rigour_cache_stats',
26
- 'rigour_context_explain',
27
- ];
28
- /** Multi-agent governance, hooks, and execution tools with dispatch handlers. */
29
- export const GOVERNANCE_TOOLS = [
30
- 'rigour_agent_register',
31
- 'rigour_agent_deregister',
32
- 'rigour_checkpoint',
33
- 'rigour_handoff',
34
- 'rigour_handoff_accept',
35
- 'rigour_hooks_check',
36
- 'rigour_hooks_init',
37
- 'rigour_run',
38
- 'rigour_run_supervised',
39
- ];
40
- export const ADVERTISED_TOOLS = new Set([
41
- ...ESSENTIAL_CONTEXT_TOOLS,
42
- ...GOVERNANCE_TOOLS,
43
- ]);
44
- export function getAdvertisedToolDefinitions() {
45
- return TOOL_DEFINITIONS.filter(t => ADVERTISED_TOOLS.has(t.name));
11
+ export const TOOL_GROUPS = {
12
+ /** Load memory, scope context, avoid reinvention, gate and review the change, learn. */
13
+ core: [
14
+ 'rigour_recall',
15
+ 'rigour_index',
16
+ 'rigour_context_scope',
17
+ 'rigour_check_pattern',
18
+ 'rigour_check',
19
+ 'rigour_review',
20
+ 'rigour_get_fix_packet',
21
+ 'rigour_remember',
22
+ ],
23
+ /** Multi-agent registration, checkpoints, handoffs, hooks and supervised runs. */
24
+ governance: [
25
+ 'rigour_agent_register',
26
+ 'rigour_agent_deregister',
27
+ 'rigour_checkpoint',
28
+ 'rigour_handoff',
29
+ 'rigour_handoff_accept',
30
+ 'rigour_hooks_check',
31
+ 'rigour_hooks_init',
32
+ 'rigour_run',
33
+ 'rigour_run_supervised',
34
+ ],
35
+ /** Occasional context and security tools. */
36
+ context: [
37
+ 'rigour_explain',
38
+ 'rigour_forget',
39
+ 'rigour_context_explain',
40
+ 'rigour_security_audit',
41
+ ],
42
+ /** Cost and cache telemetry, mostly for dashboards. */
43
+ telemetry: [
44
+ 'rigour_context_stats',
45
+ 'rigour_task_cost',
46
+ 'rigour_cache_stats',
47
+ ],
48
+ };
49
+ export const GOVERNANCE_TOOLS = TOOL_GROUPS.governance;
50
+ /** Tool names for a RIGOUR_MCP_TOOLS value; core is always included, unknown groups are ignored. */
51
+ export function advertisedToolNames(spec = process.env.RIGOUR_MCP_TOOLS) {
52
+ const requested = (spec ?? '').split(',').map(s => s.trim().toLowerCase()).filter(Boolean);
53
+ const groups = requested.includes('full') ? Object.keys(TOOL_GROUPS) : ['core', ...requested];
54
+ return new Set(groups.filter((g) => g in TOOL_GROUPS).flatMap(g => [...TOOL_GROUPS[g]]));
55
+ }
56
+ export function getAdvertisedToolDefinitions(spec) {
57
+ const names = advertisedToolNames(spec);
58
+ return TOOL_DEFINITIONS.filter(t => names.has(t.name));
46
59
  }
package/dist/index.js CHANGED
@@ -214,7 +214,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
214
214
  break;
215
215
  // Code review
216
216
  case "rigour_review":
217
- result = await handleReview(runner, cwd, args.diff, args.files);
217
+ result = await handleReview(config, cwd, args);
218
218
  break;
219
219
  // Context Telemetry & Cost Tools
220
220
  case "rigour_context_stats":
@@ -611,11 +611,7 @@ export declare const TOOL_DEFINITIONS: ({
611
611
  inputSchema: {
612
612
  type: string;
613
613
  properties: {
614
- repository: {
615
- type: string;
616
- description: string;
617
- };
618
- branch: {
614
+ base: {
619
615
  type: string;
620
616
  description: string;
621
617
  };
@@ -511,20 +511,19 @@ export const TOOL_DEFINITIONS = [
511
511
  // ─── Code Review ──────────────────────────────────────
512
512
  {
513
513
  name: "rigour_review",
514
- description: "Perform a high-fidelity code review on a pull request diff. Analyzes changed files using all active quality gates.",
514
+ description: "Review the change you just made before calling it done: runs Rigour's gates and keeps only findings on changed lines, each with file, line and a suggested fix. With no diff it reads your uncommitted work from git (new files included); pass base to review the whole branch (e.g. 'main'). Same verdict as `rigour review` in CI.",
515
515
  inputSchema: {
516
516
  type: "object",
517
517
  properties: {
518
518
  ...cwdParam(),
519
- repository: { type: "string", description: "Full repository name (e.g., 'owner/repo')." },
520
- branch: { type: "string", description: "The branch containing the changes." },
521
- diff: { type: "string", description: "The git diff content to analyze." },
522
- files: { type: "array", items: { type: "string" }, description: "List of filenames that were changed." },
519
+ base: { type: "string", description: "Review this branch against a base ref instead of uncommitted work, e.g. 'main'." },
520
+ diff: { type: "string", description: "A unified diff to review instead of reading git. Rarely needed." },
521
+ files: { type: "array", items: { type: "string" }, description: "Review exactly these files instead of the ones the change touches." },
523
522
  },
524
- required: ["cwd", "diff"],
523
+ required: ["cwd"],
525
524
  },
526
525
  annotations: {
527
- title: "Code Review",
526
+ title: "Review Change",
528
527
  readOnlyHint: true,
529
528
  destructiveHint: false,
530
529
  idempotentHint: true,
@@ -1,16 +1,22 @@
1
1
  /**
2
- * Code Review Tool Handler
2
+ * rigour_review: the same review as `rigour review` (core reviewChange), so an
3
+ * agent and CI get the same verdict for the same change.
3
4
  *
4
- * Handler for: rigour_review
5
- *
6
- * @since v2.17.0 — extracted from monolithic index.ts
5
+ * With no diff, the change is taken from git: uncommitted work (what the
6
+ * agent just wrote, new files included), or the branch against `base`.
7
7
  */
8
- import { GateRunner } from "@rigour-labs/core";
8
+ import { type Config } from "@rigour-labs/core";
9
9
  type ToolResult = {
10
10
  content: {
11
11
  type: string;
12
12
  text: string;
13
13
  }[];
14
+ isError?: boolean;
14
15
  };
15
- export declare function handleReview(runner: GateRunner, cwd: string, diff: string, changedFiles?: string[]): Promise<ToolResult>;
16
+ export interface ReviewArgs {
17
+ diff?: string;
18
+ base?: string;
19
+ files?: string[];
20
+ }
21
+ export declare function handleReview(config: Config, cwd: string, args: ReviewArgs): Promise<ToolResult>;
16
22
  export {};
@@ -1,51 +1,41 @@
1
1
  /**
2
- * Code Review Tool Handler
2
+ * rigour_review: the same review as `rigour review` (core reviewChange), so an
3
+ * agent and CI get the same verdict for the same change.
3
4
  *
4
- * Handler for: rigour_review
5
- *
6
- * @since v2.17.0 — extracted from monolithic index.ts
5
+ * With no diff, the change is taken from git: uncommitted work (what the
6
+ * agent just wrote, new files included), or the branch against `base`.
7
7
  */
8
- import { parseDiff, normalizeScopePatterns } from "@rigour-labs/core";
8
+ import { recordReviewOutcome, reviewChange, toReviewFinding } from "@rigour-labs/core";
9
9
  import { notifyProgress } from '../utils/notifications.js';
10
- export async function handleReview(runner, cwd, diff, changedFiles) {
11
- // 1. Map diff to line numbers for filtering
12
- const diffMapping = parseDiff(diff);
13
- const targetFiles = changedFiles || Object.keys(diffMapping);
14
- // 2. Run high-fidelity analysis on changed files
15
- notifyProgress("info", `Reviewing ${targetFiles.length} changed files...`);
16
- const report = await runner.run(cwd, await normalizeScopePatterns(cwd, targetFiles));
17
- // 3. Filter failures to only those on changed lines (or global gate failures)
18
- const filteredFailures = report.failures.filter(failure => {
19
- if (!failure.files || failure.files.length === 0)
20
- return true;
21
- return failure.files.some(file => {
22
- const fileModifiedLines = diffMapping[file];
23
- if (!fileModifiedLines)
24
- return false;
25
- if (failure.line !== undefined)
26
- return fileModifiedLines.has(failure.line);
27
- return true;
10
+ export async function handleReview(config, cwd, args) {
11
+ notifyProgress("info", args.diff ? "Reviewing the provided diff..." : `Reviewing ${args.base ? `this branch against ${args.base}` : "uncommitted changes"}...`);
12
+ try {
13
+ const result = await reviewChange({
14
+ cwd, config, diff: args.diff,
15
+ source: args.base ? { mode: 'base', base: args.base } : { mode: 'working' },
16
+ files: args.files,
17
+ });
18
+ recordReviewOutcome(cwd, result.findings, Object.keys(result.changedLines));
19
+ const stats = result.report?.stats;
20
+ return text({
21
+ status: result.status,
22
+ score: stats?.score ?? 100,
23
+ ai_health_score: stats?.ai_health_score,
24
+ structural_score: stats?.structural_score,
25
+ changed_files: Object.keys(result.changedLines).length,
26
+ failures: result.findings.map(toReviewFinding),
27
+ file_findings: result.fileFindings.map(toReviewFinding),
28
+ excluded_outside_changed_lines: result.excludedOutsideChangedLines,
29
+ unlocated_failures: result.unlocated,
30
+ next_step: result.findings.length
31
+ ? "Fix each failure at its file:line (see suggestion), then call rigour_review again."
32
+ : "No findings on changed lines.",
28
33
  });
29
- });
30
- return {
31
- content: [{
32
- type: "text",
33
- text: JSON.stringify({
34
- status: filteredFailures.length > 0 ? "FAIL" : "PASS",
35
- score: report.stats.score,
36
- ai_health_score: report.stats.ai_health_score,
37
- structural_score: report.stats.structural_score,
38
- failures: filteredFailures.map(f => ({
39
- id: f.id,
40
- gate: f.title,
41
- severity: f.severity || 'medium',
42
- provenance: f.provenance || 'traditional',
43
- message: f.details,
44
- file: f.files?.[0] || "",
45
- line: f.line || 1,
46
- suggestion: f.hint,
47
- })),
48
- }),
49
- }],
50
- };
34
+ }
35
+ catch (error) {
36
+ return { ...text({ error: error instanceof Error ? error.message : String(error) }), isError: true };
37
+ }
38
+ }
39
+ function text(value) {
40
+ return { content: [{ type: "text", text: JSON.stringify(value) }] };
51
41
  }
@@ -1,3 +1,8 @@
1
+ /**
2
+ * The repository's rigour.yml, or Rigour's defaults when it has none. A tool
3
+ * call never writes into the user's repository to create one (run `rigour init`
4
+ * for that), so the first call in a new repository behaves like `rigour review`.
5
+ */
1
6
  export declare function loadConfig(cwd: string): Promise<{
2
7
  ignore: string[];
3
8
  version: number;
@@ -12,22 +12,27 @@ import yaml from "yaml";
12
12
  import { randomUUID } from "crypto";
13
13
  import { ConfigSchema } from "@rigour-labs/core";
14
14
  // ─── Config Loading ───────────────────────────────────────────────
15
+ /**
16
+ * The repository's rigour.yml, or Rigour's defaults when it has none. A tool
17
+ * call never writes into the user's repository to create one (run `rigour init`
18
+ * for that), so the first call in a new repository behaves like `rigour review`.
19
+ */
15
20
  export async function loadConfig(cwd) {
16
21
  const configPath = path.join(cwd, "rigour.yml");
17
22
  if (!(await fs.pathExists(configPath))) {
18
- console.error(`[RIGOUR] rigour.yml not found in ${cwd}, auto-initializing...`);
19
- const { execa } = await import("execa");
20
- try {
21
- await execa("npx", ["rigour", "init"], { cwd, shell: true });
22
- console.error(`[RIGOUR] Auto-initialization complete.`);
23
- }
24
- catch (initError) {
25
- throw new Error(`Rigour auto-initialization failed: ${initError.message}. Please run 'npx rigour init' manually.`);
26
- }
23
+ noteMissingConfig(cwd);
24
+ return ConfigSchema.parse({ version: 1 });
27
25
  }
28
26
  const configContent = await fs.readFile(configPath, "utf-8");
29
27
  return ConfigSchema.parse(yaml.parse(configContent));
30
28
  }
29
+ const notedMissingConfig = new Set();
30
+ function noteMissingConfig(cwd) {
31
+ if (notedMissingConfig.has(cwd))
32
+ return;
33
+ notedMissingConfig.add(cwd);
34
+ console.error(`[RIGOUR] No rigour.yml in ${cwd}; using defaults. Run \`npx rigour init\` to configure gates and hooks.`);
35
+ }
31
36
  export async function getMemoryPath(cwd) {
32
37
  const rigourDir = path.join(cwd, ".rigour");
33
38
  await fs.ensureDir(rigourDir);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rigour-labs/mcp",
3
- "version": "6.3.1",
3
+ "version": "6.4.0",
4
4
  "description": "MCP server + live dashboard for AI code governance — OWASP LLM Top 10 (10/10), real-time MCP App UI, 25+ security patterns, Bayesian learning Brain, hallucinated import detection, multi-agent governance. Works with Claude, Cursor, VS Code, ChatGPT, Goose, Windsurf. Industry presets for HIPAA, SOC2, FedRAMP.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://rigour.run",
@@ -62,7 +62,7 @@
62
62
  "execa": "^8.0.1",
63
63
  "fs-extra": "^11.4.0",
64
64
  "yaml": "^2.8.2",
65
- "@rigour-labs/core": "6.3.1"
65
+ "@rigour-labs/core": "6.4.0"
66
66
  },
67
67
  "devDependencies": {
68
68
  "@types/node": "^25.0.3",