@rigour-labs/mcp 3.0.6 → 4.0.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.js +25 -1
- package/dist/tools/deep-handlers.d.ts +25 -0
- package/dist/tools/deep-handlers.js +140 -0
- package/dist/tools/definitions.d.ts +64 -0
- package/dist/tools/definitions.js +43 -0
- package/dist/tools/prompts.js +11 -0
- package/dist/utils/config.d.ts +24 -1
- package/package.json +2 -2
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
|
|
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",
|
package/dist/tools/prompts.js
CHANGED
|
@@ -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
|
];
|
package/dist/utils/config.d.ts
CHANGED
|
@@ -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
|
+
"version": "4.0.1",
|
|
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": "
|
|
51
|
+
"@rigour-labs/core": "4.0.1"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@types/node": "^25.0.3",
|