@rigour-labs/mcp 2.9.3 → 2.10.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/README.md +72 -0
- package/dist/index.js +120 -0
- package/package.json +2 -2
- package/server.json +2 -2
- package/src/index.ts +141 -1
package/README.md
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# 🛡️ Rigour MCP Server
|
|
2
|
+
|
|
3
|
+
**The Quality Gate for AI-Assisted Engineering.**
|
|
4
|
+
|
|
5
|
+
Rigour is a local-first Model Context Protocol (MCP) server that forces AI agents (Claude, Cursor, Windsurf, etc.) to meet strict engineering standards before marking tasks as complete.
|
|
6
|
+
|
|
7
|
+
[](https://github.com/mcp)
|
|
8
|
+
[](https://www.npmjs.com/package/@rigour-labs/mcp)
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 🚀 Overview
|
|
13
|
+
|
|
14
|
+
Rigour moves code quality enforcement from the "Post-Commit" phase to the "In-Progress" phase. By running as an MCP server inside your editor, it provides the AI with a deterministic PASS/FAIL loop, preventing "Vibe Coding" and broken builds.
|
|
15
|
+
|
|
16
|
+
### Key Features:
|
|
17
|
+
- **Quality Gates**: Deterministic checks for file size, complexity, and hygiene.
|
|
18
|
+
- **Context Memory**: Persistent memory that tracks project rules and patterns across sessions.
|
|
19
|
+
- **Pattern Reinvention Blocking**: Warns or blocks the AI when it tries to rewrite existing utilities.
|
|
20
|
+
- **Security Audits**: Real-time CVE detection for dependencies the AI is suggesting.
|
|
21
|
+
- **Zero Cloud**: 100% local analysis. Your code never leaves your machine.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 🛠️ Available Tools
|
|
26
|
+
|
|
27
|
+
| Tool | Description |
|
|
28
|
+
|:---|:---|
|
|
29
|
+
| `rigour_check` | Runs all configured quality gates on the current workspace. |
|
|
30
|
+
| `rigour_explain` | Explains why a specific gate failed and provides actionable fix instructions. |
|
|
31
|
+
| `rigour_check_pattern` | Checks if a proposed code pattern already exists in the codebase. |
|
|
32
|
+
| `rigour_remember` | Stores project-specific context or rules in Rigour's persistent memory. |
|
|
33
|
+
| `rigour_recall` | Retrieves stored context to guide AI generation. |
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 📦 Installation
|
|
38
|
+
|
|
39
|
+
### 1. Install via npm
|
|
40
|
+
```bash
|
|
41
|
+
npm install -g @rigour-labs/mcp
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 2. Configure your IDE
|
|
45
|
+
|
|
46
|
+
#### Cursor / Claude Desktop
|
|
47
|
+
Add the following to your MCP settings:
|
|
48
|
+
```json
|
|
49
|
+
{
|
|
50
|
+
"mcpServers": {
|
|
51
|
+
"rigour": {
|
|
52
|
+
"command": "npx",
|
|
53
|
+
"args": ["-y", "@rigour-labs/mcp"],
|
|
54
|
+
"env": {
|
|
55
|
+
"RIGOUR_CWD": "/path/to/your/project"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## 📖 Documentation
|
|
65
|
+
|
|
66
|
+
For full configuration and advanced usage, visit **[docs.rigour.run](https://docs.rigour.run)**.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## 📜 License
|
|
71
|
+
|
|
72
|
+
MIT © [Rigour Labs](https://github.com/rigour-labs)
|
package/dist/index.js
CHANGED
|
@@ -11,6 +11,7 @@ const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
|
11
11
|
const path_1 = __importDefault(require("path"));
|
|
12
12
|
const yaml_1 = __importDefault(require("yaml"));
|
|
13
13
|
const core_1 = require("@rigour-labs/core");
|
|
14
|
+
const pattern_index_1 = require("@rigour-labs/core/pattern-index");
|
|
14
15
|
const server = new index_js_1.Server({
|
|
15
16
|
name: "rigour-mcp",
|
|
16
17
|
version: "1.0.0",
|
|
@@ -189,6 +190,46 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
|
|
|
189
190
|
required: ["cwd", "key"],
|
|
190
191
|
},
|
|
191
192
|
},
|
|
193
|
+
{
|
|
194
|
+
name: "rigour_check_pattern",
|
|
195
|
+
description: "Checks if a proposed code pattern (function, component, etc.) already exists, is stale, or has security vulnerabilities (CVEs). CALL THIS BEFORE CREATING NEW CODE.",
|
|
196
|
+
inputSchema: {
|
|
197
|
+
type: "object",
|
|
198
|
+
properties: {
|
|
199
|
+
cwd: {
|
|
200
|
+
type: "string",
|
|
201
|
+
description: "Absolute path to the project root.",
|
|
202
|
+
},
|
|
203
|
+
name: {
|
|
204
|
+
type: "string",
|
|
205
|
+
description: "The name of the function, class, or component you want to create.",
|
|
206
|
+
},
|
|
207
|
+
type: {
|
|
208
|
+
type: "string",
|
|
209
|
+
description: "The type of pattern (e.g., 'function', 'component', 'hook', 'type').",
|
|
210
|
+
},
|
|
211
|
+
intent: {
|
|
212
|
+
type: "string",
|
|
213
|
+
description: "What the code is for (e.g., 'format dates', 'user authentication').",
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
required: ["cwd", "name"],
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
name: "rigour_security_audit",
|
|
221
|
+
description: "Runs a live security audit (CVE check) on the project dependencies.",
|
|
222
|
+
inputSchema: {
|
|
223
|
+
type: "object",
|
|
224
|
+
properties: {
|
|
225
|
+
cwd: {
|
|
226
|
+
type: "string",
|
|
227
|
+
description: "Absolute path to the project root.",
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
required: ["cwd"],
|
|
231
|
+
},
|
|
232
|
+
},
|
|
192
233
|
],
|
|
193
234
|
};
|
|
194
235
|
});
|
|
@@ -394,6 +435,85 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
|
394
435
|
],
|
|
395
436
|
};
|
|
396
437
|
}
|
|
438
|
+
case "rigour_check_pattern": {
|
|
439
|
+
const { name: patternName, type, intent } = args;
|
|
440
|
+
const indexPath = (0, pattern_index_1.getDefaultIndexPath)(cwd);
|
|
441
|
+
const index = await (0, pattern_index_1.loadPatternIndex)(indexPath);
|
|
442
|
+
let resultText = "";
|
|
443
|
+
// 1. Check for Reinvention
|
|
444
|
+
if (index) {
|
|
445
|
+
const matcher = new pattern_index_1.PatternMatcher(index);
|
|
446
|
+
const matchResult = await matcher.match({ name: patternName, type, intent });
|
|
447
|
+
if (matchResult.status === "FOUND_SIMILAR") {
|
|
448
|
+
resultText += `🚨 PATTERN REINVENTION DETECTED\n`;
|
|
449
|
+
resultText += `Similar pattern already exists: "${matchResult.matches[0].pattern.name}" in ${matchResult.matches[0].pattern.file}\n`;
|
|
450
|
+
resultText += `SUGGESTION: ${matchResult.suggestion}\n\n`;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
else {
|
|
454
|
+
resultText += `⚠️ Pattern index not found. Run 'rigour index' to enable reinvention detection.\n\n`;
|
|
455
|
+
}
|
|
456
|
+
// 2. Check for Staleness/Best Practices
|
|
457
|
+
const detector = new pattern_index_1.StalenessDetector(cwd);
|
|
458
|
+
const staleness = await detector.checkStaleness(`${type || 'function'} ${patternName} {}`);
|
|
459
|
+
if (staleness.status !== "FRESH") {
|
|
460
|
+
resultText += `⚠️ STALENESS/ANTI-PATTERN WARNING\n`;
|
|
461
|
+
for (const issue of staleness.issues) {
|
|
462
|
+
resultText += `- ${issue.reason}\n REPLACEMENT: ${issue.replacement}\n`;
|
|
463
|
+
}
|
|
464
|
+
resultText += `\n`;
|
|
465
|
+
}
|
|
466
|
+
// 3. Check Security for this library (if it's an import)
|
|
467
|
+
if (intent && intent.includes('import')) {
|
|
468
|
+
const security = new pattern_index_1.SecurityDetector(cwd);
|
|
469
|
+
const audit = await security.runAudit();
|
|
470
|
+
const relatedVulns = audit.vulnerabilities.filter(v => patternName.toLowerCase().includes(v.packageName.toLowerCase()) ||
|
|
471
|
+
intent.toLowerCase().includes(v.packageName.toLowerCase()));
|
|
472
|
+
if (relatedVulns.length > 0) {
|
|
473
|
+
resultText += `🛡️ SECURITY/CVE WARNING\n`;
|
|
474
|
+
for (const v of relatedVulns) {
|
|
475
|
+
resultText += `- [${v.severity.toUpperCase()}] ${v.packageName}: ${v.title} (${v.url})\n`;
|
|
476
|
+
}
|
|
477
|
+
resultText += `\n`;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
if (!resultText) {
|
|
481
|
+
resultText = `✅ Pattern "${patternName}" is fresh, secure, and unique to the codebase.\n\nRECOMMENDED ACTION: Proceed with implementation.`;
|
|
482
|
+
}
|
|
483
|
+
else {
|
|
484
|
+
let recommendation = "Proceed with caution, addressing the warnings above.";
|
|
485
|
+
if (resultText.includes("🚨 PATTERN REINVENTION")) {
|
|
486
|
+
recommendation = "STOP and REUSE the existing pattern mentioned above. Do not create a duplicate.";
|
|
487
|
+
}
|
|
488
|
+
else if (resultText.includes("🛡️ SECURITY/CVE WARNING")) {
|
|
489
|
+
recommendation = "STOP and update your dependencies or find an alternative library. Do not proceed with vulnerable code.";
|
|
490
|
+
}
|
|
491
|
+
else if (resultText.includes("⚠️ STALENESS")) {
|
|
492
|
+
recommendation = "Follow the replacement suggestion to ensure best practices.";
|
|
493
|
+
}
|
|
494
|
+
resultText += `\nRECOMMENDED ACTION: ${recommendation}`;
|
|
495
|
+
}
|
|
496
|
+
return {
|
|
497
|
+
content: [
|
|
498
|
+
{
|
|
499
|
+
type: "text",
|
|
500
|
+
text: resultText,
|
|
501
|
+
},
|
|
502
|
+
],
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
case "rigour_security_audit": {
|
|
506
|
+
const security = new pattern_index_1.SecurityDetector(cwd);
|
|
507
|
+
const summary = await security.getSecuritySummary();
|
|
508
|
+
return {
|
|
509
|
+
content: [
|
|
510
|
+
{
|
|
511
|
+
type: "text",
|
|
512
|
+
text: summary,
|
|
513
|
+
},
|
|
514
|
+
],
|
|
515
|
+
};
|
|
516
|
+
}
|
|
397
517
|
default:
|
|
398
518
|
throw new Error(`Unknown tool: ${name}`);
|
|
399
519
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rigour-labs/mcp",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.10.0",
|
|
4
4
|
"mcpName": "io.github.rigour-labs/rigour",
|
|
5
5
|
"description": "Quality gates for AI-generated code. Forces AI agents to meet strict engineering standards with PASS/FAIL enforcement.",
|
|
6
6
|
"bin": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"@modelcontextprotocol/sdk": "^1.25.2",
|
|
19
19
|
"fs-extra": "^11.2.0",
|
|
20
20
|
"yaml": "^2.8.2",
|
|
21
|
-
"@rigour-labs/core": "2.
|
|
21
|
+
"@rigour-labs/core": "2.10.0"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@types/node": "^25.0.3"
|
package/server.json
CHANGED
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
"url": "https://github.com/rigour-labs/rigour",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "
|
|
9
|
+
"version": "2.9.3",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "@rigour-labs/mcp",
|
|
14
|
-
"version": "
|
|
14
|
+
"version": "2.9.3",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|
package/src/index.ts
CHANGED
|
@@ -8,7 +8,18 @@ import {
|
|
|
8
8
|
import fs from "fs-extra";
|
|
9
9
|
import path from "path";
|
|
10
10
|
import yaml from "yaml";
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
GateRunner,
|
|
13
|
+
ConfigSchema,
|
|
14
|
+
Report,
|
|
15
|
+
} from "@rigour-labs/core";
|
|
16
|
+
import {
|
|
17
|
+
PatternMatcher,
|
|
18
|
+
loadPatternIndex,
|
|
19
|
+
getDefaultIndexPath,
|
|
20
|
+
StalenessDetector,
|
|
21
|
+
SecurityDetector
|
|
22
|
+
} from "@rigour-labs/core/pattern-index";
|
|
12
23
|
|
|
13
24
|
const server = new Server(
|
|
14
25
|
{
|
|
@@ -201,6 +212,46 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
201
212
|
required: ["cwd", "key"],
|
|
202
213
|
},
|
|
203
214
|
},
|
|
215
|
+
{
|
|
216
|
+
name: "rigour_check_pattern",
|
|
217
|
+
description: "Checks if a proposed code pattern (function, component, etc.) already exists, is stale, or has security vulnerabilities (CVEs). CALL THIS BEFORE CREATING NEW CODE.",
|
|
218
|
+
inputSchema: {
|
|
219
|
+
type: "object",
|
|
220
|
+
properties: {
|
|
221
|
+
cwd: {
|
|
222
|
+
type: "string",
|
|
223
|
+
description: "Absolute path to the project root.",
|
|
224
|
+
},
|
|
225
|
+
name: {
|
|
226
|
+
type: "string",
|
|
227
|
+
description: "The name of the function, class, or component you want to create.",
|
|
228
|
+
},
|
|
229
|
+
type: {
|
|
230
|
+
type: "string",
|
|
231
|
+
description: "The type of pattern (e.g., 'function', 'component', 'hook', 'type').",
|
|
232
|
+
},
|
|
233
|
+
intent: {
|
|
234
|
+
type: "string",
|
|
235
|
+
description: "What the code is for (e.g., 'format dates', 'user authentication').",
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
required: ["cwd", "name"],
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
name: "rigour_security_audit",
|
|
243
|
+
description: "Runs a live security audit (CVE check) on the project dependencies.",
|
|
244
|
+
inputSchema: {
|
|
245
|
+
type: "object",
|
|
246
|
+
properties: {
|
|
247
|
+
cwd: {
|
|
248
|
+
type: "string",
|
|
249
|
+
description: "Absolute path to the project root.",
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
required: ["cwd"],
|
|
253
|
+
},
|
|
254
|
+
},
|
|
204
255
|
],
|
|
205
256
|
};
|
|
206
257
|
});
|
|
@@ -429,6 +480,95 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
429
480
|
};
|
|
430
481
|
}
|
|
431
482
|
|
|
483
|
+
case "rigour_check_pattern": {
|
|
484
|
+
const { name: patternName, type, intent } = args as any;
|
|
485
|
+
const indexPath = getDefaultIndexPath(cwd);
|
|
486
|
+
const index = await loadPatternIndex(indexPath);
|
|
487
|
+
|
|
488
|
+
let resultText = "";
|
|
489
|
+
|
|
490
|
+
// 1. Check for Reinvention
|
|
491
|
+
if (index) {
|
|
492
|
+
const matcher = new PatternMatcher(index);
|
|
493
|
+
const matchResult = await matcher.match({ name: patternName, type, intent });
|
|
494
|
+
|
|
495
|
+
if (matchResult.status === "FOUND_SIMILAR") {
|
|
496
|
+
resultText += `🚨 PATTERN REINVENTION DETECTED\n`;
|
|
497
|
+
resultText += `Similar pattern already exists: "${matchResult.matches[0].pattern.name}" in ${matchResult.matches[0].pattern.file}\n`;
|
|
498
|
+
resultText += `SUGGESTION: ${matchResult.suggestion}\n\n`;
|
|
499
|
+
}
|
|
500
|
+
} else {
|
|
501
|
+
resultText += `⚠️ Pattern index not found. Run 'rigour index' to enable reinvention detection.\n\n`;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// 2. Check for Staleness/Best Practices
|
|
505
|
+
const detector = new StalenessDetector(cwd);
|
|
506
|
+
const staleness = await detector.checkStaleness(`${type || 'function'} ${patternName} {}`);
|
|
507
|
+
|
|
508
|
+
if (staleness.status !== "FRESH") {
|
|
509
|
+
resultText += `⚠️ STALENESS/ANTI-PATTERN WARNING\n`;
|
|
510
|
+
for (const issue of staleness.issues) {
|
|
511
|
+
resultText += `- ${issue.reason}\n REPLACEMENT: ${issue.replacement}\n`;
|
|
512
|
+
}
|
|
513
|
+
resultText += `\n`;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// 3. Check Security for this library (if it's an import)
|
|
517
|
+
if (intent && intent.includes('import')) {
|
|
518
|
+
const security = new SecurityDetector(cwd);
|
|
519
|
+
const audit = await security.runAudit();
|
|
520
|
+
const relatedVulns = audit.vulnerabilities.filter(v =>
|
|
521
|
+
patternName.toLowerCase().includes(v.packageName.toLowerCase()) ||
|
|
522
|
+
intent.toLowerCase().includes(v.packageName.toLowerCase())
|
|
523
|
+
);
|
|
524
|
+
|
|
525
|
+
if (relatedVulns.length > 0) {
|
|
526
|
+
resultText += `🛡️ SECURITY/CVE WARNING\n`;
|
|
527
|
+
for (const v of relatedVulns) {
|
|
528
|
+
resultText += `- [${v.severity.toUpperCase()}] ${v.packageName}: ${v.title} (${v.url})\n`;
|
|
529
|
+
}
|
|
530
|
+
resultText += `\n`;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
if (!resultText) {
|
|
535
|
+
resultText = `✅ Pattern "${patternName}" is fresh, secure, and unique to the codebase.\n\nRECOMMENDED ACTION: Proceed with implementation.`;
|
|
536
|
+
} else {
|
|
537
|
+
let recommendation = "Proceed with caution, addressing the warnings above.";
|
|
538
|
+
if (resultText.includes("🚨 PATTERN REINVENTION")) {
|
|
539
|
+
recommendation = "STOP and REUSE the existing pattern mentioned above. Do not create a duplicate.";
|
|
540
|
+
} else if (resultText.includes("🛡️ SECURITY/CVE WARNING")) {
|
|
541
|
+
recommendation = "STOP and update your dependencies or find an alternative library. Do not proceed with vulnerable code.";
|
|
542
|
+
} else if (resultText.includes("⚠️ STALENESS")) {
|
|
543
|
+
recommendation = "Follow the replacement suggestion to ensure best practices.";
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
resultText += `\nRECOMMENDED ACTION: ${recommendation}`;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
return {
|
|
550
|
+
content: [
|
|
551
|
+
{
|
|
552
|
+
type: "text",
|
|
553
|
+
text: resultText,
|
|
554
|
+
},
|
|
555
|
+
],
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
case "rigour_security_audit": {
|
|
560
|
+
const security = new SecurityDetector(cwd);
|
|
561
|
+
const summary = await security.getSecuritySummary();
|
|
562
|
+
return {
|
|
563
|
+
content: [
|
|
564
|
+
{
|
|
565
|
+
type: "text",
|
|
566
|
+
text: summary,
|
|
567
|
+
},
|
|
568
|
+
],
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
|
|
432
572
|
default:
|
|
433
573
|
throw new Error(`Unknown tool: ${name}`);
|
|
434
574
|
}
|