@rigour-labs/mcp 3.0.5 → 4.0.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.js CHANGED
@@ -24,6 +24,7 @@ import { handleRun, handleRunSupervised } from './tools/execution-handlers.js';
24
24
  import { handleAgentRegister, handleCheckpoint, handleHandoff, handleAgentDeregister, handleHandoffAccept } from './tools/agent-handlers.js';
25
25
  import { handleReview } from './tools/review-handler.js';
26
26
  import { handleHooksCheck, handleHooksInit } from './tools/hooks-handler.js';
27
+ import { handleCheckDeep, handleDeepStats } from './tools/deep-handlers.js';
27
28
  // ─── Server Setup ─────────────────────────────────────────────────
28
29
  const server = new Server({ name: "rigour-mcp", version: "3.0.1" }, { capabilities: { tools: {}, prompts: {} } });
29
30
  // ─── Tool Listing ─────────────────────────────────────────────────
@@ -113,6 +114,15 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
113
114
  case "rigour_hooks_init":
114
115
  result = await handleHooksInit(cwd, args.tool, args.force, args.dryRun);
115
116
  break;
117
+ // Deep analysis (v4.0+)
118
+ case "rigour_check_deep": {
119
+ const { pro, apiKey, provider, apiBaseUrl, modelName } = args;
120
+ result = await handleCheckDeep(runner, cwd, config, { pro, apiKey, provider, apiBaseUrl, modelName });
121
+ break;
122
+ }
123
+ case "rigour_deep_stats":
124
+ result = await handleDeepStats(cwd, args.limit);
125
+ break;
116
126
  // Code review
117
127
  case "rigour_review":
118
128
  result = await handleReview(runner, cwd, args.diff, args.files);
@@ -222,6 +232,20 @@ server.setRequestHandler(GetPromptRequestSchema, async (request) => {
222
232
  ],
223
233
  };
224
234
  }
235
+ case "rigour-deep-analysis": {
236
+ return {
237
+ description: prompt.description,
238
+ messages: [
239
+ {
240
+ role: "user",
241
+ content: {
242
+ type: "text",
243
+ text: `Run \`rigour_check_deep\` on ${cwd} for a full deep code quality analysis. This uses the three-step pipeline: AST extracts facts → LLM interprets patterns → AST verifies findings. Report the AI Health score, Code Quality score, and Overall score. List all verified findings grouped by category (SOLID violations, code smells, architecture issues, test quality). For each finding, show the file, description, and suggestion. If any critical findings exist, prioritize them. End with concrete action items to improve the code quality score.`,
244
+ },
245
+ },
246
+ ],
247
+ };
248
+ }
225
249
  default:
226
250
  throw new Error(`Unknown prompt: ${name}`);
227
251
  }
@@ -230,7 +254,7 @@ server.setRequestHandler(GetPromptRequestSchema, async (request) => {
230
254
  async function main() {
231
255
  const transport = new StdioServerTransport();
232
256
  await server.connect(transport);
233
- console.error("Rigour MCP server v3.0.0 running on stdio");
257
+ console.error("Rigour MCP server v4.0.0 running on stdio");
234
258
  }
235
259
  main().catch((error) => {
236
260
  console.error("Fatal error in Rigour MCP server:", error);
@@ -0,0 +1,25 @@
1
+ import { GateRunner, Report } from "@rigour-labs/core";
2
+ import type { Config } from "@rigour-labs/core";
3
+ type ToolResult = {
4
+ content: {
5
+ type: string;
6
+ text: string;
7
+ }[];
8
+ isError?: boolean;
9
+ _rigour_report?: Report;
10
+ };
11
+ /**
12
+ * Run quality gates with deep LLM-powered analysis.
13
+ */
14
+ export declare function handleCheckDeep(runner: GateRunner, cwd: string, config: Config, args: {
15
+ pro?: boolean;
16
+ apiKey?: string;
17
+ provider?: string;
18
+ apiBaseUrl?: string;
19
+ modelName?: string;
20
+ }): Promise<ToolResult>;
21
+ /**
22
+ * Get deep analysis statistics from SQLite storage.
23
+ */
24
+ export declare function handleDeepStats(cwd: string, limit?: number): Promise<ToolResult>;
25
+ export {};
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Deep Analysis Tool Handlers
3
+ *
4
+ * Handlers for: rigour_check_deep, rigour_deep_stats
5
+ *
6
+ * @since v4.0.0
7
+ */
8
+ import path from "path";
9
+ /**
10
+ * Run quality gates with deep LLM-powered analysis.
11
+ */
12
+ export async function handleCheckDeep(runner, cwd, config, args) {
13
+ const deepOpts = {
14
+ enabled: true,
15
+ pro: !!args.pro,
16
+ apiKey: args.apiKey,
17
+ provider: args.apiKey ? (args.provider || 'claude') : 'local',
18
+ apiBaseUrl: args.apiBaseUrl,
19
+ modelName: args.modelName,
20
+ };
21
+ const report = await runner.run(cwd, undefined, deepOpts);
22
+ // Persist to SQLite (best-effort)
23
+ try {
24
+ const { openDatabase, insertScan, insertFindings } = await import('@rigour-labs/core');
25
+ const db = openDatabase();
26
+ if (db) {
27
+ const repoName = path.basename(cwd);
28
+ const scanId = insertScan(db, repoName, report, {
29
+ deepTier: args.pro ? 'pro' : (args.apiKey ? 'cloud' : 'deep'),
30
+ deepModel: report.stats.deep?.model,
31
+ });
32
+ insertFindings(db, scanId, report.failures);
33
+ db.close();
34
+ }
35
+ }
36
+ catch {
37
+ // SQLite persistence is best-effort
38
+ }
39
+ // Format response
40
+ const stats = report.stats;
41
+ const aiHealth = stats.ai_health_score ?? 100;
42
+ const codeQuality = stats.code_quality_score ?? stats.structural_score ?? 100;
43
+ const overall = stats.score ?? 100;
44
+ const isLocal = !args.apiKey;
45
+ let text = `RIGOUR DEEP ANALYSIS: ${report.status}\n\n`;
46
+ text += `AI Health: ${aiHealth}/100\n`;
47
+ text += `Code Quality: ${codeQuality}/100\n`;
48
+ text += `Overall: ${overall}/100\n\n`;
49
+ if (isLocal) {
50
+ text += `🔒 100% local. Code never left this machine.\n`;
51
+ }
52
+ else {
53
+ text += `☁️ Code was sent to ${args.provider || 'cloud'} API.\n`;
54
+ }
55
+ if (stats.deep) {
56
+ const tier = stats.deep.tier === 'cloud' ? (args.provider || 'cloud') : stats.deep.tier;
57
+ const model = stats.deep.model || 'unknown';
58
+ const inferenceSec = stats.deep.total_ms ? (stats.deep.total_ms / 1000).toFixed(1) + 's' : '';
59
+ text += `Model: ${model} (${tier}) ${inferenceSec}\n`;
60
+ }
61
+ if (report.failures.length > 0) {
62
+ text += `\n--- Findings (${report.failures.length}) ---\n\n`;
63
+ // Group by provenance
64
+ const grouped = {};
65
+ for (const f of report.failures) {
66
+ const prov = f.provenance || 'traditional';
67
+ if (!grouped[prov])
68
+ grouped[prov] = [];
69
+ grouped[prov].push(f);
70
+ }
71
+ for (const [prov, failures] of Object.entries(grouped)) {
72
+ text += `[${prov}] (${failures.length} issues)\n`;
73
+ for (const f of failures.slice(0, 10)) {
74
+ const sev = (f.severity || 'medium').toUpperCase();
75
+ const conf = f.confidence ? ` (${(f.confidence * 100).toFixed(0)}%)` : '';
76
+ text += ` ${sev}: ${f.title}${conf}\n`;
77
+ if (f.hint)
78
+ text += ` → ${f.hint}\n`;
79
+ }
80
+ if (failures.length > 10) {
81
+ text += ` ... +${failures.length - 10} more\n`;
82
+ }
83
+ text += '\n';
84
+ }
85
+ }
86
+ text += `\nDuration: ${(stats.duration_ms / 1000).toFixed(1)}s`;
87
+ const result = {
88
+ content: [{ type: "text", text }],
89
+ };
90
+ result._rigour_report = report;
91
+ return result;
92
+ }
93
+ /**
94
+ * Get deep analysis statistics from SQLite storage.
95
+ */
96
+ export async function handleDeepStats(cwd, limit = 10) {
97
+ try {
98
+ const { openDatabase, getRecentScans, getScoreTrendFromDB, getTopIssues } = await import('@rigour-labs/core');
99
+ const db = openDatabase();
100
+ if (!db) {
101
+ return {
102
+ content: [{ type: "text", text: "SQLite storage not available. Run `rigour check --deep` first to generate scan data." }],
103
+ };
104
+ }
105
+ const repoName = path.basename(cwd);
106
+ const scans = getRecentScans(db, repoName, limit);
107
+ const trend = getScoreTrendFromDB(db, repoName, limit);
108
+ const topIssues = getTopIssues(db, repoName, 10);
109
+ db.close();
110
+ if (scans.length === 0) {
111
+ return {
112
+ content: [{ type: "text", text: `No deep analysis scans found for "${repoName}". Run \`rigour check --deep\` first.` }],
113
+ };
114
+ }
115
+ let text = `DEEP ANALYSIS STATS for "${repoName}"\n\n`;
116
+ // Score trend
117
+ text += `Score Trend: ${trend.scores.join(' → ')} (${trend.direction})\n\n`;
118
+ // Recent scans
119
+ text += `Recent Scans (${scans.length}):\n`;
120
+ for (const scan of scans) {
121
+ const date = new Date(scan.timestamp).toISOString().split('T')[0];
122
+ const tier = scan.deep_tier || '?';
123
+ text += ` ${date} | Overall: ${scan.overall_score ?? '?'}/100 | AI: ${scan.ai_health_score ?? '?'}/100 | Quality: ${scan.code_quality_score ?? '?'}/100 | Tier: ${tier}\n`;
124
+ }
125
+ // Top issues
126
+ if (topIssues.length > 0) {
127
+ text += `\nTop Issue Categories:\n`;
128
+ for (const issue of topIssues) {
129
+ text += ` ${issue.category}: ${issue.count} occurrences\n`;
130
+ }
131
+ }
132
+ return { content: [{ type: "text", text }] };
133
+ }
134
+ catch (error) {
135
+ return {
136
+ content: [{ type: "text", text: `Error reading deep stats: ${error.message}` }],
137
+ isError: true,
138
+ };
139
+ }
140
+ }
@@ -407,6 +407,70 @@ export declare const TOOL_DEFINITIONS: ({
407
407
  idempotentHint: boolean;
408
408
  openWorldHint: boolean;
409
409
  };
410
+ } | {
411
+ name: string;
412
+ description: string;
413
+ inputSchema: {
414
+ type: string;
415
+ properties: {
416
+ pro: {
417
+ type: string;
418
+ description: string;
419
+ };
420
+ apiKey: {
421
+ type: string;
422
+ description: string;
423
+ };
424
+ provider: {
425
+ type: string;
426
+ description: string;
427
+ };
428
+ apiBaseUrl: {
429
+ type: string;
430
+ description: string;
431
+ };
432
+ modelName: {
433
+ type: string;
434
+ description: string;
435
+ };
436
+ cwd: {
437
+ type: "string";
438
+ description: string;
439
+ };
440
+ };
441
+ required: string[];
442
+ };
443
+ annotations: {
444
+ title: string;
445
+ readOnlyHint: boolean;
446
+ destructiveHint: boolean;
447
+ idempotentHint: boolean;
448
+ openWorldHint: boolean;
449
+ };
450
+ } | {
451
+ name: string;
452
+ description: string;
453
+ inputSchema: {
454
+ type: string;
455
+ properties: {
456
+ limit: {
457
+ type: string;
458
+ description: string;
459
+ };
460
+ cwd: {
461
+ type: "string";
462
+ description: string;
463
+ };
464
+ };
465
+ required: string[];
466
+ };
467
+ annotations: {
468
+ title: string;
469
+ readOnlyHint: boolean;
470
+ destructiveHint: boolean;
471
+ idempotentHint: boolean;
472
+ openWorldHint: boolean;
473
+ };
410
474
  } | {
411
475
  name: string;
412
476
  description: string;
@@ -407,6 +407,49 @@ export const TOOL_DEFINITIONS = [
407
407
  openWorldHint: false,
408
408
  },
409
409
  },
410
+ // ─── Deep Analysis (v4.0+) ──────────────────────────────
411
+ {
412
+ name: "rigour_check_deep",
413
+ description: "Run quality gates WITH deep LLM-powered analysis. Three-step pipeline: AST extracts facts → LLM interprets → AST verifies. Local-first by default (Qwen2.5-Coder), or bring your own API key for any cloud provider.",
414
+ inputSchema: {
415
+ type: "object",
416
+ properties: {
417
+ ...cwdParam(),
418
+ pro: { type: "boolean", description: "Use the larger 1.5B model (--pro tier). Default: false (0.5B model)." },
419
+ apiKey: { type: "string", description: "API key for cloud LLM provider. If provided, uses cloud instead of local sidecar." },
420
+ provider: { type: "string", description: "Cloud provider name (e.g., 'claude', 'openai', 'gemini', 'groq', 'mistral', 'together', 'fireworks', 'deepseek', 'perplexity', 'ollama', 'lmstudio'). Default: 'claude' when apiKey is provided." },
421
+ apiBaseUrl: { type: "string", description: "Custom API base URL for self-hosted or proxy endpoints." },
422
+ modelName: { type: "string", description: "Override the default model name for the chosen provider." },
423
+ },
424
+ required: ["cwd"],
425
+ },
426
+ annotations: {
427
+ title: "Deep Analysis",
428
+ readOnlyHint: true,
429
+ destructiveHint: false,
430
+ idempotentHint: true,
431
+ openWorldHint: false,
432
+ },
433
+ },
434
+ {
435
+ name: "rigour_deep_stats",
436
+ description: "Get deep analysis statistics from SQLite storage. Returns recent scan scores, top issues, and score trends for a repository.",
437
+ inputSchema: {
438
+ type: "object",
439
+ properties: {
440
+ ...cwdParam(),
441
+ limit: { type: "number", description: "Number of recent scans to return (default: 10)." },
442
+ },
443
+ required: ["cwd"],
444
+ },
445
+ annotations: {
446
+ title: "Deep Analysis Stats",
447
+ readOnlyHint: true,
448
+ destructiveHint: false,
449
+ idempotentHint: true,
450
+ openWorldHint: false,
451
+ },
452
+ },
410
453
  // ─── Code Review ──────────────────────────────────────
411
454
  {
412
455
  name: "rigour_review",
@@ -62,4 +62,15 @@ export const PROMPT_DEFINITIONS = [
62
62
  },
63
63
  ],
64
64
  },
65
+ {
66
+ name: "rigour-deep-analysis",
67
+ description: "Run deep LLM-powered code quality analysis. AST extracts facts, LLM interprets patterns (SOLID violations, code smells, architecture issues), AST verifies findings. 100% local by default.",
68
+ arguments: [
69
+ {
70
+ name: "cwd",
71
+ description: "Absolute path to the project root.",
72
+ required: false,
73
+ },
74
+ ],
75
+ },
65
76
  ];
@@ -8,6 +8,29 @@ export declare function loadConfig(cwd: string): Promise<{
8
8
  test?: string | undefined;
9
9
  };
10
10
  gates: {
11
+ deep: {
12
+ enabled: boolean;
13
+ pro: boolean;
14
+ provider: string;
15
+ threads: number;
16
+ max_tokens: number;
17
+ temperature: number;
18
+ timeout_ms: number;
19
+ checks: {
20
+ architecture: boolean;
21
+ test_quality: boolean;
22
+ solid: boolean;
23
+ dry: boolean;
24
+ design_patterns: boolean;
25
+ language_idioms: boolean;
26
+ error_handling: boolean;
27
+ code_smells: boolean;
28
+ };
29
+ api_key?: string | undefined;
30
+ api_base_url?: string | undefined;
31
+ model_name?: string | undefined;
32
+ model_path?: string | undefined;
33
+ };
11
34
  max_file_lines: number;
12
35
  forbid_todos: boolean;
13
36
  forbid_fixme: boolean;
@@ -159,8 +182,8 @@ export declare function loadConfig(cwd: string): Promise<{
159
182
  hooks: {
160
183
  enabled: boolean;
161
184
  tools: ("claude" | "cursor" | "cline" | "windsurf")[];
162
- fast_gates: string[];
163
185
  timeout_ms: number;
186
+ fast_gates: string[];
164
187
  block_on_failure: boolean;
165
188
  };
166
189
  output: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rigour-labs/mcp",
3
- "version": "3.0.5",
3
+ "version": "4.0.0",
4
4
  "description": "MCP server for AI code governance — OWASP LLM Top 10 (10/10), real-time hooks, 25+ security patterns, hallucinated import detection, multi-agent governance. Works with Claude, Cursor, Cline, Windsurf, Gemini. Industry presets for HIPAA, SOC2, FedRAMP.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://rigour.run",
@@ -48,7 +48,7 @@
48
48
  "execa": "^8.0.1",
49
49
  "fs-extra": "^11.2.0",
50
50
  "yaml": "^2.8.2",
51
- "@rigour-labs/core": "3.0.5"
51
+ "@rigour-labs/core": "4.0.0"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@types/node": "^25.0.3",