secufusion-mcp 1.0.3 → 1.0.5
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 +496 -141
- package/index.js +141 -21
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
# SecuFusion MCP Server
|
|
2
2
|
|
|
3
3
|
> **Developer workflow tooling for the SecuFusion platform** — enforces zero-trust architecture standards, tracks task specs, and gates PRs with automated guardrail checks.
|
|
4
4
|
|
|
@@ -10,306 +10,661 @@
|
|
|
10
10
|
|
|
11
11
|
## What is this?
|
|
12
12
|
|
|
13
|
-
`secufusion-mcp` is a [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server that plugs into AI coding assistants (Claude Desktop, Cursor, Cline,
|
|
13
|
+
`secufusion-mcp` is a [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server that plugs into AI coding assistants (Claude Desktop, Cursor, Cline, etc.) and gives them three powerful tools to enforce SecuFusion's engineering standards throughout the development lifecycle:
|
|
14
14
|
|
|
15
15
|
| Tool | Phase | What it does |
|
|
16
16
|
|---|---|---|
|
|
17
|
-
| `manage_feature_spec` | Planning & Execution | Creates/updates a `.current-task-spec.md` blueprint for
|
|
17
|
+
| `manage_feature_spec` | Planning & Execution | Creates/updates a `.current-task-spec.md` blueprint (works for single-repo or cross-repo tasks) |
|
|
18
18
|
| `log_rejected_pattern` | Course Correction | Records bad patterns to `.rejected-patterns.json` so they are never repeated |
|
|
19
|
-
| `run_pre_pr_checks` | PR Handoff |
|
|
19
|
+
| `run_pre_pr_checks` | PR Handoff | Discovers modified microservices across the workspace and gates PRs via AST-level linters + structural checks |
|
|
20
20
|
|
|
21
21
|
---
|
|
22
22
|
|
|
23
23
|
## Installation
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
If you want to run it from a local build (faster, fully offline):
|
|
25
|
+
### Option 1 — `npx` (no install required)
|
|
28
26
|
|
|
29
27
|
```bash
|
|
30
|
-
|
|
31
|
-
cd secufusion-mcp
|
|
32
|
-
npm install
|
|
33
|
-
npm run build
|
|
28
|
+
npx secufusion-mcp
|
|
34
29
|
```
|
|
35
30
|
|
|
36
|
-
|
|
31
|
+
### Option 2 — Global install
|
|
37
32
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
33
|
+
```bash
|
|
34
|
+
npm install -g secufusion-mcp
|
|
35
|
+
```
|
|
41
36
|
|
|
42
|
-
|
|
43
|
-
|---|---|
|
|
44
|
-
| **You have the source on disk** (faster, offline) | `node C:\path\to\secufusion-mcp\index.js` |
|
|
45
|
-
| **Anyone else / fresh machine** (auto-downloads, cached after first run) | `npx -y secufusion-mcp` |
|
|
37
|
+
### Option 3 — Local project install
|
|
46
38
|
|
|
47
|
-
|
|
39
|
+
```bash
|
|
40
|
+
npm install --save-dev secufusion-mcp
|
|
41
|
+
```
|
|
48
42
|
|
|
49
43
|
---
|
|
50
44
|
|
|
51
|
-
|
|
45
|
+
## Setup: Add to Your MCP Client
|
|
46
|
+
|
|
47
|
+
### Claude Desktop
|
|
52
48
|
|
|
53
|
-
|
|
49
|
+
Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or
|
|
50
|
+
`%APPDATA%\Claude\claude_desktop_config.json` (Windows):
|
|
54
51
|
|
|
55
|
-
**If you have the source on disk:**
|
|
56
52
|
```json
|
|
57
53
|
{
|
|
58
54
|
"mcpServers": {
|
|
59
55
|
"secufusion-mcp": {
|
|
60
|
-
"command": "
|
|
61
|
-
"args": ["
|
|
62
|
-
"type": "stdio"
|
|
56
|
+
"command": "npx",
|
|
57
|
+
"args": ["-y", "secufusion-mcp"]
|
|
63
58
|
}
|
|
64
59
|
}
|
|
65
60
|
}
|
|
66
61
|
```
|
|
67
62
|
|
|
68
|
-
|
|
63
|
+
### Cursor
|
|
64
|
+
|
|
65
|
+
Open **Settings → MCP** and add:
|
|
66
|
+
|
|
69
67
|
```json
|
|
70
68
|
{
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
|
|
74
|
-
"args": ["-y", "secufusion-mcp"],
|
|
75
|
-
"type": "stdio"
|
|
76
|
-
}
|
|
69
|
+
"secufusion-mcp": {
|
|
70
|
+
"command": "npx",
|
|
71
|
+
"args": ["-y", "secufusion-mcp"]
|
|
77
72
|
}
|
|
78
73
|
}
|
|
79
74
|
```
|
|
80
75
|
|
|
81
|
-
|
|
76
|
+
### Cline (VS Code Extension)
|
|
82
77
|
|
|
83
|
-
|
|
78
|
+
Open Cline settings → MCP Servers → Add:
|
|
84
79
|
|
|
85
|
-
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"secufusion-mcp": {
|
|
83
|
+
"command": "npx",
|
|
84
|
+
"args": ["-y", "secufusion-mcp"],
|
|
85
|
+
"disabled": false
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Using a local build (development)
|
|
86
91
|
|
|
87
92
|
```json
|
|
88
93
|
{
|
|
89
|
-
"
|
|
90
|
-
"
|
|
91
|
-
|
|
92
|
-
"args": ["-y", "secufusion-mcp"]
|
|
93
|
-
}
|
|
94
|
+
"secufusion-mcp": {
|
|
95
|
+
"command": "node",
|
|
96
|
+
"args": ["C:/path/to/secufusion-mcp/index.js"]
|
|
94
97
|
}
|
|
95
98
|
}
|
|
96
99
|
```
|
|
97
100
|
|
|
98
101
|
---
|
|
99
102
|
|
|
100
|
-
|
|
103
|
+
## Tools Reference
|
|
104
|
+
|
|
105
|
+
### 1. `manage_feature_spec`
|
|
106
|
+
|
|
107
|
+
Creates or updates the `.current-task-spec.md` file — your single source of truth for every task. The AI reads this before writing any code.
|
|
101
108
|
|
|
102
|
-
|
|
109
|
+
**Parameters:**
|
|
110
|
+
|
|
111
|
+
| Parameter | Type | Required | Description |
|
|
112
|
+
|---|---|---|---|
|
|
113
|
+
| `action` | `"create"` \| `"update"` \| `"read"` | Yes | What to do with the spec |
|
|
114
|
+
| `task_description` | string | When `action=create` | Full description of the task/feature |
|
|
115
|
+
| `update_content` | string | When `action=update` | Markdown lines to merge (e.g. tick checkboxes) |
|
|
116
|
+
| `work_item_id` | string | No | Azure DevOps work item ID |
|
|
117
|
+
| `reference_file_path` | string | No | Path to an existing source file to extract coding patterns from |
|
|
103
118
|
|
|
119
|
+
**Example — Create a spec:**
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
Ask your AI assistant:
|
|
123
|
+
"Start working on WI-1042: Add tenant-scoped audit log export to CSV.
|
|
124
|
+
Reference file: src/services/AuditService.java"
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
The AI will call:
|
|
104
128
|
```json
|
|
105
129
|
{
|
|
106
|
-
"
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
130
|
+
"action": "create",
|
|
131
|
+
"task_description": "Add tenant-scoped audit log export to CSV...",
|
|
132
|
+
"work_item_id": "1042",
|
|
133
|
+
"reference_file_path": "src/services/AuditService.java"
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
This generates `.current-task-spec.md` with:
|
|
138
|
+
- Task description
|
|
139
|
+
- Pre-filled guardrails checklist
|
|
140
|
+
- Acceptance criteria placeholders
|
|
141
|
+
- Reference code snippet
|
|
142
|
+
- Session log
|
|
143
|
+
|
|
144
|
+
**Example — Tick off completed work:**
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
Ask: "Mark the tenantId scoping and unit tests as done in the spec."
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
The AI will call:
|
|
151
|
+
```json
|
|
152
|
+
{
|
|
153
|
+
"action": "update",
|
|
154
|
+
"update_content": "- [x] All DB queries / event payloads are scoped with `tenantId`\n- [x] Unit tests written / updated for new business logic"
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**Example — Read current spec:**
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
Ask: "Where did we leave off? Read the current spec."
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
```json
|
|
165
|
+
{ "action": "read" }
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
### 2. `log_rejected_pattern`
|
|
171
|
+
|
|
172
|
+
Appends a rejected code pattern to `.rejected-patterns.json`. The AI checks this file implicitly before every architectural suggestion to avoid repeating past mistakes.
|
|
173
|
+
|
|
174
|
+
**Parameters:**
|
|
175
|
+
|
|
176
|
+
| Parameter | Type | Required | Description |
|
|
177
|
+
|---|---|---|---|
|
|
178
|
+
| `pattern` | string | Yes | The bad pattern or approach |
|
|
179
|
+
| `reason` | string | Yes | Why it was rejected and what to do instead |
|
|
180
|
+
| `category` | enum | No | `architecture` \| `security` \| `database` \| `logging` \| `api-design` \| `testing` \| `other` |
|
|
181
|
+
| `file_context` | string | No | File or area where the pattern was observed |
|
|
182
|
+
|
|
183
|
+
**Example:**
|
|
184
|
+
|
|
185
|
+
```
|
|
186
|
+
Tell your AI: "Never use a global @Repository bean without tenantId scoping again.
|
|
187
|
+
It was leaking cross-tenant data."
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
The AI will call:
|
|
191
|
+
```json
|
|
192
|
+
{
|
|
193
|
+
"pattern": "Injecting global @Repository bean and querying without tenantId filter",
|
|
194
|
+
"reason": "Causes cross-tenant data leakage. Always add .where(tenantId = :tenantId) or use TenantAwareRepository base class.",
|
|
195
|
+
"category": "security",
|
|
196
|
+
"file_context": "src/repositories/AuditLogRepository.java"
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
This writes to `.rejected-patterns.json`:
|
|
201
|
+
```json
|
|
202
|
+
[
|
|
203
|
+
{
|
|
204
|
+
"id": 1,
|
|
205
|
+
"timestamp": "2026-08-26T14:35:00.000Z",
|
|
206
|
+
"category": "security",
|
|
207
|
+
"pattern": "Injecting global @Repository bean...",
|
|
208
|
+
"reason": "Causes cross-tenant data leakage...",
|
|
209
|
+
"file_context": "src/repositories/AuditLogRepository.java"
|
|
112
210
|
}
|
|
211
|
+
]
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
### 3. run_pre_pr_checks
|
|
217
|
+
|
|
218
|
+
| Parameter | Type | Required | Description |
|
|
219
|
+
|---|---|---|---|
|
|
220
|
+
| `work_item_id` | string | Yes | Azure DevOps work item ID |
|
|
221
|
+
| `root_dir` | string | No | Directory to scan (defaults to cwd) |
|
|
222
|
+
| `skip_checks` | array | No | `spec_boxes`, `console_logs`, `hardcoded_urls`, `flyway_migrations` |
|
|
223
|
+
|
|
224
|
+
**Guardrail checks:**
|
|
225
|
+
|
|
226
|
+
| Check | Fails when |
|
|
227
|
+
|---|---|
|
|
228
|
+
| **SPEC** | `.current-task-spec.md` is missing or has unchecked `- [ ]` boxes |
|
|
229
|
+
| **LINTING** | AST linters (ESLint, Checkstyle) fail in any discovered microservice. Fix natively, do not suppress! (Falls back to regex if no linters exist) |
|
|
230
|
+
| **SECURITY** | Hardcoded IPs or `uat.*` / `prod.*` / `staging.*` URLs in source or config files |
|
|
231
|
+
| **FLYWAY** | `@Entity`-annotated Java files exist but no `V*__.sql` Flyway migrations found |
|
|
232
|
+
|
|
233
|
+
**Example — Run checks before PR:**
|
|
234
|
+
|
|
235
|
+
```
|
|
236
|
+
Ask: "Prepare the PR for work item 1042."
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
The AI will call:
|
|
240
|
+
```json
|
|
241
|
+
{
|
|
242
|
+
"work_item_id": "1042"
|
|
113
243
|
}
|
|
114
244
|
```
|
|
115
245
|
|
|
116
|
-
|
|
246
|
+
**✅ Passing output:**
|
|
247
|
+
```
|
|
248
|
+
# ✅ Pre-PR Checks PASSED — Work Item #1042
|
|
249
|
+
|
|
250
|
+
✅ [SPEC] All spec checkboxes are checked.
|
|
251
|
+
✅ [LOGGING] No console.log / System.out.println found.
|
|
252
|
+
✅ [SECURITY] No hardcoded UAT/Prod IPs or environment URLs found.
|
|
253
|
+
✅ [FLYWAY] Flyway migration coverage looks good.
|
|
254
|
+
|
|
255
|
+
## PR Summary
|
|
256
|
+
- Work Item: #1042
|
|
257
|
+
- Spec: All acceptance criteria verified ✅
|
|
258
|
+
- Ready to raise PR 🚀
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
**❌ Failing output (example):**
|
|
262
|
+
```
|
|
263
|
+
# ❌ Pre-PR Checks FAILED — Work Item #1042
|
|
264
|
+
|
|
265
|
+
❌ [SPEC] 3 unchecked item(s) in the spec:
|
|
266
|
+
• Flyway SQL migration created for every modified JPA @Entity
|
|
267
|
+
• Unit tests written / updated for new business logic
|
|
268
|
+
• API contract updated if endpoints changed
|
|
269
|
+
|
|
270
|
+
❌ [LOGGING] Found 2 prohibited log statement(s):
|
|
271
|
+
• console.log() found at src/components/AuditTable.tsx:47
|
|
272
|
+
• System.out.println() found at src/main/java/AuditService.java:112
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## Guardrails Summary
|
|
278
|
+
|
|
279
|
+
These rules are enforced automatically — the AI will never violate them:
|
|
280
|
+
|
|
281
|
+
```
|
|
282
|
+
✅ All DB queries and event payloads scoped with tenantId
|
|
283
|
+
✅ No console.log() or System.out.println() in any source file
|
|
284
|
+
✅ No hardcoded UAT/Prod IPs or environment URLs
|
|
285
|
+
✅ Every JPA @Entity change accompanied by a Flyway .sql migration
|
|
286
|
+
✅ Spec must be fully checked before PR is raised
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## File Outputs
|
|
292
|
+
|
|
293
|
+
| File | Description |
|
|
294
|
+
|---|---|
|
|
295
|
+
| `.current-task-spec.md` | Living task blueprint — created per feature, updated as work progresses |
|
|
296
|
+
| `.rejected-patterns.json` | Cumulative log of all rejected patterns across sessions |
|
|
297
|
+
|
|
298
|
+
> **Tip:** Commit both files to your repo so the entire team benefits from the shared knowledge.
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## Workflow Overview
|
|
117
303
|
|
|
118
|
-
|
|
304
|
+
```
|
|
305
|
+
┌─────────────────────────────────────────────────────┐
|
|
306
|
+
│ SecuFusion MCP Workflow │
|
|
307
|
+
├──────────────┬──────────────────────────────────────┤
|
|
308
|
+
│ Phase 1 │ manage_feature_spec (action=create) │
|
|
309
|
+
│ Planning │ → Generates .current-task-spec.md │
|
|
310
|
+
├──────────────┼──────────────────────────────────────┤
|
|
311
|
+
│ Phase 2 │ manage_feature_spec (action=update) │
|
|
312
|
+
│ Execution │ → Tick off ACs as you complete them │
|
|
313
|
+
├──────────────┼──────────────────────────────────────┤
|
|
314
|
+
│ Phase 3 │ log_rejected_pattern │
|
|
315
|
+
│ Correction │ → Record mistakes to avoid repeat │
|
|
316
|
+
├──────────────┼──────────────────────────────────────┤
|
|
317
|
+
│ Phase 4 │ run_pre_pr_checks │
|
|
318
|
+
│ PR Handoff │ → Must pass before raising PR │
|
|
319
|
+
└──────────────┴──────────────────────────────────────┘
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
---
|
|
119
323
|
|
|
324
|
+
## Real-World Walkthrough
|
|
325
|
+
|
|
326
|
+
A complete end-to-end example of what you actually type and what happens at each phase.
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
### Step 1 — Integrate (one-time setup)
|
|
331
|
+
|
|
332
|
+
Add this to your MCP client config and restart. That's it.
|
|
333
|
+
|
|
334
|
+
**Antigravity / Claude Desktop / Cline — if you have the source on disk:**
|
|
120
335
|
```json
|
|
121
336
|
{
|
|
122
|
-
"
|
|
337
|
+
"mcpServers": {
|
|
123
338
|
"secufusion-mcp": {
|
|
124
|
-
"
|
|
125
|
-
"
|
|
126
|
-
"
|
|
339
|
+
"command": "node",
|
|
340
|
+
"args": ["C:\\Users\\YourName\\Desktop\\mcp\\secufusion-mcp\\index.js"],
|
|
341
|
+
"type": "stdio"
|
|
127
342
|
}
|
|
128
343
|
}
|
|
129
344
|
}
|
|
130
345
|
```
|
|
131
346
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
Open Settings → MCP → Add:
|
|
135
|
-
|
|
347
|
+
**Teammates / fresh machines — pulls from npm, cached after first run:**
|
|
136
348
|
```json
|
|
137
349
|
{
|
|
138
|
-
"
|
|
139
|
-
"
|
|
140
|
-
|
|
350
|
+
"mcpServers": {
|
|
351
|
+
"secufusion-mcp": {
|
|
352
|
+
"command": "npx",
|
|
353
|
+
"args": ["-y", "secufusion-mcp"],
|
|
354
|
+
"type": "stdio"
|
|
355
|
+
}
|
|
141
356
|
}
|
|
142
357
|
}
|
|
143
358
|
```
|
|
144
359
|
|
|
145
|
-
|
|
360
|
+
> **Why two options?** If you have the compiled `index.js` on disk, `node` starts instantly and works fully offline. Teammates who don't have the source use `npx` — it downloads from npm once (~3s), then caches it locally so every subsequent run is instant with no network needed.
|
|
146
361
|
|
|
147
|
-
|
|
362
|
+
---
|
|
148
363
|
|
|
149
|
-
###
|
|
364
|
+
### Step 2 — Start a new task (Planning phase)
|
|
150
365
|
|
|
151
|
-
|
|
366
|
+
Just paste your Azure DevOps work item ID and description directly into the chat. No special syntax needed.
|
|
152
367
|
|
|
368
|
+
**You type:**
|
|
153
369
|
```
|
|
154
370
|
WI-2847: Add MFA enforcement for admin users on login.
|
|
155
371
|
Admin users must be forced through TOTP verification before
|
|
156
372
|
accessing any dashboard route. Exempt service accounts.
|
|
157
373
|
```
|
|
158
374
|
|
|
159
|
-
The AI automatically calls `manage_feature_spec` and creates `.current-task-spec.md
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
-
|
|
164
|
-
|
|
375
|
+
**The AI automatically calls `manage_feature_spec` and creates `.current-task-spec.md`:**
|
|
376
|
+
```markdown
|
|
377
|
+
# SecuFusion Feature Spec
|
|
378
|
+
|
|
379
|
+
**Generated:** 2026-08-26T14:35:00.000Z
|
|
380
|
+
**Azure DevOps Work Item:** 2847 → https://dev.azure.com/secufusion/_workitems/edit/2847
|
|
381
|
+
|
|
382
|
+
## Task Description
|
|
383
|
+
Add MFA enforcement for admin users on login...
|
|
384
|
+
|
|
385
|
+
## Guardrails Checklist
|
|
386
|
+
- [ ] All DB queries / event payloads are scoped with `tenantId`
|
|
387
|
+
- [ ] No `console.log` / `System.out.println` left in source files
|
|
388
|
+
- [ ] No hardcoded UAT/Prod IPs or environment URLs
|
|
389
|
+
- [ ] Flyway SQL migration created for every modified JPA `@Entity`
|
|
390
|
+
- [ ] Unit tests written / updated for new business logic
|
|
391
|
+
- [ ] API contract updated if endpoints changed
|
|
165
392
|
|
|
166
|
-
|
|
393
|
+
## Acceptance Criteria
|
|
394
|
+
- [ ] AC-1: (fill in from ticket)
|
|
395
|
+
- [ ] AC-2: (fill in from ticket)
|
|
167
396
|
|
|
397
|
+
## Session Log
|
|
398
|
+
| 2026-08-26T14:35:00Z | Spec created |
|
|
168
399
|
```
|
|
169
|
-
|
|
400
|
+
|
|
401
|
+
You can paste as little or as much as you want:
|
|
402
|
+
|
|
403
|
+
```
|
|
404
|
+
# Minimal — one liner
|
|
170
405
|
WI-2847: MFA for admin login with TOTP.
|
|
171
406
|
|
|
172
|
-
# Full
|
|
407
|
+
# Full ticket paste — straight from Azure
|
|
173
408
|
WI-2847
|
|
174
409
|
Title: Add MFA enforcement for admin users
|
|
175
410
|
Description: Admin users must complete TOTP verification...
|
|
176
411
|
Acceptance Criteria:
|
|
177
412
|
- Given admin logs in, When MFA not done, Then redirect to /mfa
|
|
178
413
|
- Service accounts in GROUP_SERVICE_ACCOUNTS are exempt
|
|
414
|
+
Priority: High
|
|
179
415
|
```
|
|
180
416
|
|
|
181
417
|
---
|
|
182
418
|
|
|
183
|
-
###
|
|
419
|
+
### Step 3 — Write code normally
|
|
420
|
+
|
|
421
|
+
Just code as usual. With the MCP server active, the AI automatically:
|
|
422
|
+
|
|
423
|
+
- Adds `tenantId` scoping to every DB query it writes
|
|
424
|
+
- Uses a proper logger (e.g., `log.info()`) — never `console.log`
|
|
425
|
+
- Reads `.rejected-patterns.json` before making any architectural suggestion
|
|
426
|
+
- Reminds you to create a Flyway migration if it touches a `@Entity`
|
|
427
|
+
- References any `reference_file_path` you provided to match your coding style
|
|
428
|
+
|
|
429
|
+
---
|
|
430
|
+
|
|
431
|
+
### Step 4 — Tick off completed work (Execution phase)
|
|
432
|
+
|
|
433
|
+
As you finish pieces of the feature, tell the AI:
|
|
184
434
|
|
|
185
435
|
```
|
|
186
|
-
I've finished the tenantId scoping and written the unit tests.
|
|
436
|
+
I've finished the tenantId scoping on all queries and written the unit tests.
|
|
437
|
+
Update the spec.
|
|
187
438
|
```
|
|
188
439
|
|
|
189
|
-
The AI
|
|
440
|
+
The AI calls `manage_feature_spec` with `action=update` and the spec updates:
|
|
441
|
+
|
|
442
|
+
```markdown
|
|
443
|
+
# Before
|
|
444
|
+
- [ ] All DB queries / event payloads are scoped with `tenantId`
|
|
445
|
+
- [ ] Unit tests written / updated for new business logic
|
|
446
|
+
|
|
447
|
+
# After
|
|
448
|
+
- [x] All DB queries / event payloads are scoped with `tenantId`
|
|
449
|
+
- [x] Unit tests written / updated for new business logic
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
A new row is also appended to the Session Log automatically, so you always have an audit trail of progress across sessions.
|
|
190
453
|
|
|
191
454
|
---
|
|
192
455
|
|
|
193
|
-
###
|
|
456
|
+
### Step 5 — Course correction (if the AI does something wrong)
|
|
457
|
+
|
|
458
|
+
Say the AI used a hardcoded URL or proposed a pattern your team has banned:
|
|
194
459
|
|
|
195
460
|
```
|
|
196
|
-
|
|
197
|
-
All env URLs must come from application.properties.
|
|
461
|
+
Stop using hardcoded staging URLs like https://staging.secufusion.io.
|
|
462
|
+
All env URLs must come from application.properties. Never hardcode them.
|
|
198
463
|
```
|
|
199
464
|
|
|
200
|
-
The AI
|
|
465
|
+
The AI **immediately** calls `log_rejected_pattern`:
|
|
466
|
+
|
|
467
|
+
```json
|
|
468
|
+
{
|
|
469
|
+
"pattern": "Hardcoded staging URL https://staging.secufusion.io in source files",
|
|
470
|
+
"reason": "Must use @Value('${app.base-url}') from application.properties. Hardcoded URLs break environment parity and expose internal topology.",
|
|
471
|
+
"category": "security",
|
|
472
|
+
"file_context": "src/services/NotificationService.java"
|
|
473
|
+
}
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
This gets appended to `.rejected-patterns.json`:
|
|
477
|
+
|
|
478
|
+
```json
|
|
479
|
+
[
|
|
480
|
+
{
|
|
481
|
+
"id": 1,
|
|
482
|
+
"timestamp": "2026-08-26T15:10:00.000Z",
|
|
483
|
+
"category": "security",
|
|
484
|
+
"pattern": "Hardcoded staging URL https://staging.secufusion.io in source files",
|
|
485
|
+
"reason": "Must use @Value from application.properties...",
|
|
486
|
+
"file_context": "src/services/NotificationService.java"
|
|
487
|
+
}
|
|
488
|
+
]
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
From this point on, the AI checks this file before every suggestion — the mistake will never be repeated, even in future sessions.
|
|
201
492
|
|
|
202
493
|
---
|
|
203
494
|
|
|
204
|
-
###
|
|
495
|
+
### Step 6 — Pre-PR checks (PR Handoff phase)
|
|
496
|
+
|
|
497
|
+
When you're done, say:
|
|
205
498
|
|
|
206
499
|
```
|
|
207
500
|
Run pre-PR checks for work item 2847.
|
|
208
501
|
```
|
|
209
502
|
|
|
210
|
-
|
|
503
|
+
The AI scans your entire repo and produces a report.
|
|
504
|
+
|
|
505
|
+
**✅ Everything passes — ready to ship:**
|
|
211
506
|
```
|
|
507
|
+
# ✅ Pre-PR Checks PASSED — Work Item #2847
|
|
508
|
+
|
|
509
|
+
Scanned directory: C:\projects\secufusion-backend
|
|
510
|
+
Timestamp: 2026-08-26T16:00:00.000Z
|
|
511
|
+
|
|
212
512
|
✅ [SPEC] All spec checkboxes are checked.
|
|
213
513
|
✅ [LOGGING] No console.log / System.out.println found.
|
|
214
|
-
✅ [SECURITY] No hardcoded URLs found.
|
|
215
|
-
✅ [FLYWAY]
|
|
216
|
-
|
|
514
|
+
✅ [SECURITY] No hardcoded UAT/Prod IPs or environment URLs found.
|
|
515
|
+
✅ [FLYWAY] Flyway migration coverage looks good.
|
|
516
|
+
|
|
517
|
+
## PR Summary
|
|
518
|
+
- Work Item: #2847
|
|
519
|
+
- Spec: All acceptance criteria verified ✅
|
|
520
|
+
- Guardrails: tenantId scoping, no debug logs, no hardcoded URLs, Flyway covered ✅
|
|
521
|
+
- Ready to raise PR 🚀
|
|
522
|
+
|
|
523
|
+
🚫 Rejected Patterns Reminder (1 on record)
|
|
524
|
+
- [security] Hardcoded staging URL https://staging.secufusion.io in source files
|
|
217
525
|
```
|
|
218
526
|
|
|
219
|
-
|
|
527
|
+
**❌ Checks fail — you must fix before PR:**
|
|
220
528
|
```
|
|
221
|
-
❌
|
|
529
|
+
# ❌ Pre-PR Checks FAILED — Work Item #2847
|
|
530
|
+
|
|
531
|
+
## Errors (must fix before PR)
|
|
532
|
+
|
|
533
|
+
❌ [SPEC] 2 unchecked item(s) in the spec:
|
|
222
534
|
• Flyway SQL migration created for every modified JPA @Entity
|
|
223
|
-
• API contract updated if endpoints changed
|
|
224
|
-
|
|
535
|
+
• API contract (OpenAPI / TS types) updated if endpoints changed
|
|
536
|
+
|
|
537
|
+
❌ [LINTING] 2 linter error(s) across workspace — fix natively in their respective microservices:
|
|
538
|
+
• [ESLint] apps/admin-dashboard/src/components/MfaSetup.tsx:47 — Unexpected console statement (no-console)
|
|
539
|
+
• [Checkstyle/Maven] Build failed: [ERROR] AuditService.java:[112] Line contains System.out.println
|
|
540
|
+
|
|
541
|
+
## Passed
|
|
542
|
+
✅ [SECURITY] No hardcoded UAT/Prod IPs or environment URLs found.
|
|
543
|
+
✅ [FLYWAY] Flyway migration coverage looks good.
|
|
225
544
|
```
|
|
226
545
|
|
|
546
|
+
Fix the issues, run checks again, and only raise the PR once it's fully green.
|
|
547
|
+
|
|
227
548
|
---
|
|
228
549
|
|
|
229
550
|
### Quick cheat sheet
|
|
230
551
|
|
|
231
|
-
| What you want | What to say |
|
|
552
|
+
| What you want to do | What to say to the AI |
|
|
232
553
|
|---|---|
|
|
233
|
-
| Start a task | `WI-XXXX: [description]` |
|
|
554
|
+
| Start a new task | `WI-XXXX: [paste description from Azure]` |
|
|
234
555
|
| Check where you left off | `Read the current spec` |
|
|
235
|
-
| Mark work done | `Mark
|
|
556
|
+
| Mark work as done | `Mark the tenantId scoping as complete in the spec` |
|
|
236
557
|
| Record a mistake | `Never do [X] again because [Y]` |
|
|
237
|
-
|
|
|
238
|
-
| Resume a
|
|
558
|
+
| Gate the PR | `Run pre-PR checks for WI-XXXX` |
|
|
559
|
+
| Resume after a break | `What's left on the current task?` |
|
|
560
|
+
| Use a reference file | `WI-XXXX: [desc]. Reference: src/services/MyService.java` |
|
|
239
561
|
|
|
240
562
|
---
|
|
241
563
|
|
|
242
|
-
##
|
|
564
|
+
## How It Actually Works — The Invoker
|
|
243
565
|
|
|
244
|
-
|
|
566
|
+
There are two layers that need to be in place for the MCP server to work automatically.
|
|
245
567
|
|
|
246
|
-
|
|
247
|
-
|---|---|---|---|
|
|
248
|
-
| `action` | `create` / `update` / `read` | Yes | Operation to perform |
|
|
249
|
-
| `task_description` | string | When action=create | Full feature/task description |
|
|
250
|
-
| `update_content` | string | When action=update | Markdown lines to merge (e.g. tick checkboxes) |
|
|
251
|
-
| `work_item_id` | string | No | Azure DevOps work item ID |
|
|
252
|
-
| `reference_file_path` | string | No | Existing source file to extract coding patterns from |
|
|
568
|
+
### Layer 1 — `mcp_config.json` (makes tools available)
|
|
253
569
|
|
|
254
|
-
|
|
570
|
+
This tells the IDE to start the MCP server process when it launches. The tools become registered and ready, but nothing calls them yet.
|
|
255
571
|
|
|
256
|
-
|
|
572
|
+
```
|
|
573
|
+
IDE starts → reads mcp_config.json → spawns node index.js → tools registered
|
|
574
|
+
```
|
|
257
575
|
|
|
258
|
-
|
|
259
|
-
|---|---|---|---|
|
|
260
|
-
| `pattern` | string | Yes | The bad pattern or approach |
|
|
261
|
-
| `reason` | string | Yes | Why rejected and what to do instead |
|
|
262
|
-
| `category` | enum | No | `architecture`, `security`, `database`, `logging`, `api-design`, `testing`, `other` |
|
|
263
|
-
| `file_context` | string | No | File where the pattern was observed |
|
|
576
|
+
### Layer 2 — `AGENTS.md` (the invoker — tells AI when to call each tool)
|
|
264
577
|
|
|
265
|
-
|
|
578
|
+
Without this, the tools sit idle. The AI doesn't know when to invoke them.
|
|
579
|
+
Create `.agents/AGENTS.md` in your project root:
|
|
266
580
|
|
|
267
|
-
|
|
581
|
+
```markdown
|
|
582
|
+
# SecuFusion MCP Workflow Rules
|
|
268
583
|
|
|
269
|
-
|
|
270
|
-
|---|---|---|---|
|
|
271
|
-
| `work_item_id` | string | Yes | Azure DevOps work item ID |
|
|
272
|
-
| `root_dir` | string | No | Directory to scan (defaults to cwd) |
|
|
273
|
-
| `skip_checks` | array | No | `spec_boxes`, `console_logs`, `hardcoded_urls`, `flyway_migrations` |
|
|
584
|
+
You are an elite Senior Developer and Architect working on the SecuFusion workspace (containing multiple microservice repositories). You prioritize robust cross-service architecture, zero-trust security (tenant isolation), and flawless state management. You rely on standard AST-aware build tools (ESLint/Checkstyle) for code hygiene. You strictly follow project standards and always use the custom MCP tools provided.
|
|
274
585
|
|
|
275
|
-
|
|
586
|
+
## Phase 1 — Planning (TRIGGER: user assigns a task or work item)
|
|
587
|
+
- Do NOT write code immediately. First, call `manage_feature_spec`.
|
|
588
|
+
- Determine which microservices are likely affected. Pass a `reference_file_path` to observe exact coding patterns.
|
|
589
|
+
- Pass the user's requirements into `task_description` to generate the workspace-level `.current-task-spec.md` blueprint.
|
|
590
|
+
- Wait for the spec to be generated before writing any code.
|
|
276
591
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
| **SECURITY** | Hardcoded IPs or `uat.*` / `prod.*` / `staging.*` URLs in source or config files |
|
|
282
|
-
| **FLYWAY** | `@Entity`-annotated Java files exist but no `V*__.sql` Flyway migrations found |
|
|
592
|
+
## Phase 2 — Execution (TRIGGER: as you complete work)
|
|
593
|
+
- Keep the `.current-task-spec.md` file updated as your source of truth.
|
|
594
|
+
- Whenever you finish a logical chunk, call `manage_feature_spec` with `update_content` to check off the `[ ]` boxes to `[x]`.
|
|
595
|
+
- If you are resuming a session, always call `manage_feature_spec` with `action=read` first to know exactly where you left off.
|
|
283
596
|
|
|
284
|
-
|
|
597
|
+
## Phase 3 — Course Correction (TRIGGER: user corrects you or rejects an approach)
|
|
598
|
+
- Immediately call `log_rejected_pattern`.
|
|
599
|
+
- Pass the bad `pattern` you used and the `reason`/correction the user provided.
|
|
600
|
+
- Always check `.rejected-patterns.json` implicitly before suggesting architectural choices to ensure you never repeat past mistakes.
|
|
285
601
|
|
|
286
|
-
##
|
|
602
|
+
## Phase 4 — PR Handoff (TRIGGER: user says "prepare PR", "finish up", or "run checks")
|
|
603
|
+
- Call `run_pre_pr_checks` with the Azure DevOps `work_item_id`. The tool will automatically discover all modified microservices in the workspace and run their native linters.
|
|
604
|
+
- If the tool throws an error for a specific repository (e.g., missing Flyway SQL migration, or a linter failing due to console logs/bad formatting), YOU MUST navigate to that specific microservice, FIX THE ERROR in the codebase, and run the tool again until the entire workspace passes. Do not suppress linter warnings.
|
|
287
605
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
606
|
+
## Guardrails (enforce always, no exceptions)
|
|
607
|
+
- All DB queries and event payloads MUST be scoped with `tenantId` unless the spec explicitly notes it as a global/system operation.
|
|
608
|
+
- Do not ignore linter errors. AST-level tools (ESLint, Checkstyle/Maven) are the source of truth for hygiene. Fix them natively.
|
|
609
|
+
- Never hardcode UAT/Prod IPs or URLs. Use environment variables or configuration properties.
|
|
610
|
+
- If you modify a JPA `@Entity` in any backend repo, you MUST create the corresponding Flyway `.sql` migration script before running PR checks.
|
|
611
|
+
```
|
|
292
612
|
|
|
293
|
-
|
|
613
|
+
### How it all wires together
|
|
614
|
+
|
|
615
|
+
```
|
|
616
|
+
mcp_config.json → starts the server (tools available)
|
|
617
|
+
+
|
|
618
|
+
.agents/AGENTS.md → tells AI when to invoke each tool (the invoker)
|
|
619
|
+
↓
|
|
620
|
+
You say: "WI-1042: Add audit log export"
|
|
621
|
+
↓
|
|
622
|
+
AI reads AGENTS.md → Phase 1 triggered → calls manage_feature_spec
|
|
623
|
+
↓
|
|
624
|
+
.current-task-spec.md created in your project root
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
### Reusing across projects
|
|
294
628
|
|
|
295
|
-
|
|
629
|
+
Copy `.agents/AGENTS.md` into any project's root — the invoker follows you everywhere.
|
|
296
630
|
|
|
297
631
|
```
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
632
|
+
ProjectA/
|
|
633
|
+
.agents/AGENTS.md ← same file, copy it here
|
|
634
|
+
|
|
635
|
+
ProjectB/
|
|
636
|
+
.agents/AGENTS.md ← and here
|
|
637
|
+
|
|
638
|
+
mcp_config.json ← global, never changes
|
|
302
639
|
```
|
|
303
640
|
|
|
304
641
|
---
|
|
305
642
|
|
|
643
|
+
## Talking to the AI — 5 Things You'll Ever Say
|
|
644
|
+
|
|
645
|
+
Once both layers are in place, you interact completely naturally:
|
|
646
|
+
|
|
647
|
+
| Situation | What you say |
|
|
648
|
+
|---|---|
|
|
649
|
+
| 🆕 New task | `WI-XXXX: [paste description from Azure]` |
|
|
650
|
+
| ✅ Done a chunk | `Done with the tenantId scoping, update the spec` |
|
|
651
|
+
| ❌ AI did something wrong | `Don't do X, do Y instead` |
|
|
652
|
+
| 🚀 Ready for PR | `Run checks for WI-XXXX` or `Prepare PR` |
|
|
653
|
+
| 🔄 Resuming after a break | `What's left?` or `Resume the current task` |
|
|
654
|
+
|
|
655
|
+
**Before `AGENTS.md`:** You had to remember which tool to invoke and when.
|
|
656
|
+
|
|
657
|
+
**After `AGENTS.md`:** You just describe work. The AI follows the 4-phase workflow automatically — no commands, no syntax, no manual tool calls.
|
|
658
|
+
|
|
659
|
+
---
|
|
660
|
+
|
|
306
661
|
## Requirements
|
|
307
662
|
|
|
308
|
-
- Node.js >= 18.0.0
|
|
663
|
+
- **Node.js** >= 18.0.0
|
|
309
664
|
- An MCP-compatible AI client (Antigravity, Claude Desktop, Cursor, Cline, etc.)
|
|
310
665
|
|
|
311
666
|
---
|
|
312
667
|
|
|
313
668
|
## License
|
|
314
669
|
|
|
315
|
-
ISC
|
|
670
|
+
ISC © SecuFusion
|
package/index.js
CHANGED
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
* Provides developer-workflow tooling for the SecuFusion platform:
|
|
6
6
|
* - manage_feature_spec : create / update task blueprints (.current-task-spec.md)
|
|
7
7
|
* - log_rejected_pattern : record bad patterns so they are never repeated (.rejected-patterns.json)
|
|
8
|
-
* - run_pre_pr_checks : gate PRs
|
|
8
|
+
* - run_pre_pr_checks : gate PRs via AST-level linters (ESLint / Maven Checkstyle) + structural checks
|
|
9
9
|
*
|
|
10
10
|
* Guardrails enforced:
|
|
11
11
|
* 1. All DB queries and event payloads must carry tenantId.
|
|
12
|
-
* 2.
|
|
12
|
+
* 2. Code hygiene (console.log, unused vars, formatting) enforced via ESLint / Checkstyle — not regex.
|
|
13
13
|
* 3. No hardcoded UAT/Prod IPs or environment URLs.
|
|
14
14
|
* 4. Every modified JPA @Entity must have a matching Flyway SQL migration.
|
|
15
15
|
*/
|
|
@@ -18,6 +18,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
18
18
|
import { z } from "zod";
|
|
19
19
|
import fs from "fs";
|
|
20
20
|
import path from "path";
|
|
21
|
+
import { execSync } from "child_process";
|
|
21
22
|
// ─────────────────────────────────────────────
|
|
22
23
|
// Constants / helpers
|
|
23
24
|
// ─────────────────────────────────────────────
|
|
@@ -93,7 +94,7 @@ function appendSessionLog(existing, update) {
|
|
|
93
94
|
// ─────────────────────────────────────────────
|
|
94
95
|
// run_pre_pr_checks helpers
|
|
95
96
|
// ─────────────────────────────────────────────
|
|
96
|
-
const
|
|
97
|
+
const CONSOLE_LOG_REGEX = [
|
|
97
98
|
{ regex: /console\.log\s*\(/g, label: "console.log()", ext: [".ts", ".tsx", ".js", ".jsx"] },
|
|
98
99
|
{ regex: /System\.out\.println\s*\(/g, label: "System.out.println()", ext: [".java"] },
|
|
99
100
|
];
|
|
@@ -127,9 +128,71 @@ function checkSpecFile() {
|
|
|
127
128
|
}
|
|
128
129
|
return { unchecked, missing: false };
|
|
129
130
|
}
|
|
130
|
-
|
|
131
|
+
// ── AST-level linting via ESLint (preferred over regex for JS/TS) ─────────────
|
|
132
|
+
function runEslint(rootDir) {
|
|
133
|
+
// Check if ESLint is configured in the project
|
|
134
|
+
const eslintConfigs = [".eslintrc", ".eslintrc.js", ".eslintrc.json", ".eslintrc.yml",
|
|
135
|
+
".eslintrc.yaml", "eslint.config.js", "eslint.config.mjs"];
|
|
136
|
+
const hasEslintConfig = eslintConfigs.some((f) => fs.existsSync(path.join(rootDir, f)));
|
|
137
|
+
const hasPkgEslint = (() => {
|
|
138
|
+
const pkg = readFileSafe(path.join(rootDir, "package.json"));
|
|
139
|
+
if (!pkg)
|
|
140
|
+
return false;
|
|
141
|
+
try {
|
|
142
|
+
return !!(JSON.parse(pkg).eslintConfig);
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
})();
|
|
148
|
+
if (!hasEslintConfig && !hasPkgEslint)
|
|
149
|
+
return { violations: [], available: false };
|
|
150
|
+
try {
|
|
151
|
+
execSync("npx eslint . --format json --max-warnings=0 --no-error-on-unmatched-pattern", { cwd: rootDir, stdio: "pipe" });
|
|
152
|
+
return { violations: [], available: true };
|
|
153
|
+
}
|
|
154
|
+
catch (e) {
|
|
155
|
+
const raw = e.stdout?.toString() ?? "";
|
|
156
|
+
try {
|
|
157
|
+
const results = JSON.parse(raw);
|
|
158
|
+
const violations = [];
|
|
159
|
+
for (const file of results) {
|
|
160
|
+
for (const msg of file.messages) {
|
|
161
|
+
if (msg.severity > 0) {
|
|
162
|
+
violations.push(`[ESLint] ${path.relative(rootDir, file.filePath)}:${msg.line} — ${msg.message}${msg.ruleId ? ` (${msg.ruleId})` : ""}`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return { violations, available: true };
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
// ESLint output not JSON — return raw stderr summary
|
|
170
|
+
const stderr = e.stderr?.toString() ?? "";
|
|
171
|
+
return { violations: stderr ? [`[ESLint] ${stderr.slice(0, 400)}`] : [], available: true };
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// ── Maven + Checkstyle for Java/Spring projects ───────────────────────────────
|
|
176
|
+
function runCheckstyle(rootDir) {
|
|
177
|
+
const hasPom = fs.existsSync(path.join(rootDir, "pom.xml"));
|
|
178
|
+
if (!hasPom)
|
|
179
|
+
return { violations: [], available: false };
|
|
180
|
+
try {
|
|
181
|
+
execSync("mvn checkstyle:check -q --no-transfer-progress", { cwd: rootDir, stdio: "pipe" });
|
|
182
|
+
return { violations: [], available: true };
|
|
183
|
+
}
|
|
184
|
+
catch (e) {
|
|
185
|
+
const output = ((e.stdout?.toString() ?? "") + (e.stderr?.toString() ?? "")).slice(0, 1200);
|
|
186
|
+
return {
|
|
187
|
+
violations: [`[Checkstyle/Maven] Build failed:\n${output}`],
|
|
188
|
+
available: true,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
// ── Regex fallback — used only when no linter is configured ──────────────────
|
|
193
|
+
function checkConsoleLogsRegex(rootDir) {
|
|
131
194
|
const violations = [];
|
|
132
|
-
for (const { regex, label, ext } of
|
|
195
|
+
for (const { regex, label, ext } of CONSOLE_LOG_REGEX) {
|
|
133
196
|
const files = walkDir(rootDir, ext);
|
|
134
197
|
for (const file of files) {
|
|
135
198
|
const content = readFileSafe(file);
|
|
@@ -161,6 +224,28 @@ function checkHardcodedUrls(rootDir) {
|
|
|
161
224
|
}
|
|
162
225
|
return violations;
|
|
163
226
|
}
|
|
227
|
+
// ── Workspace / Microservice Discovery ───────────────────────────────────────
|
|
228
|
+
function findProjectRoots(dir, depth = 0) {
|
|
229
|
+
if (depth > 3)
|
|
230
|
+
return []; // Limit depth to avoid scanning massive trees
|
|
231
|
+
if (!fs.existsSync(dir))
|
|
232
|
+
return [];
|
|
233
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
234
|
+
const hasPackageJson = entries.some(e => e.name === "package.json");
|
|
235
|
+
const hasPomXml = entries.some(e => e.name === "pom.xml");
|
|
236
|
+
const roots = [];
|
|
237
|
+
if (hasPackageJson || hasPomXml) {
|
|
238
|
+
roots.push(dir);
|
|
239
|
+
}
|
|
240
|
+
for (const entry of entries) {
|
|
241
|
+
if (entry.isDirectory()) {
|
|
242
|
+
if (["node_modules", ".git", "dist", "build", "target", ".idea"].includes(entry.name))
|
|
243
|
+
continue;
|
|
244
|
+
roots.push(...findProjectRoots(path.join(dir, entry.name), depth + 1));
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return [...new Set(roots)];
|
|
248
|
+
}
|
|
164
249
|
function checkFlywayMigrations(rootDir) {
|
|
165
250
|
const warnings = [];
|
|
166
251
|
const javaFiles = walkDir(rootDir, [".java"]);
|
|
@@ -195,10 +280,9 @@ const server = new McpServer({
|
|
|
195
280
|
version: "1.0.0",
|
|
196
281
|
});
|
|
197
282
|
// ─── Tool 1: manage_feature_spec ─────────────────────────────────────────────
|
|
198
|
-
server.tool("manage_feature_spec", "Create or update the .current-task-spec.md
|
|
199
|
-
"
|
|
200
|
-
"
|
|
201
|
-
"so the spec generator can observe existing coding patterns.", {
|
|
283
|
+
server.tool("manage_feature_spec", "Create or update the .current-task-spec.md blueprint for the current feature. " +
|
|
284
|
+
"Use this during the Planning and Execution phases. " +
|
|
285
|
+
"Works for both single-repo and cross-repo workspace tasks.", {
|
|
202
286
|
task_description: z
|
|
203
287
|
.string()
|
|
204
288
|
.optional()
|
|
@@ -379,10 +463,11 @@ server.tool("log_rejected_pattern", "Record a coding pattern that was rejected b
|
|
|
379
463
|
};
|
|
380
464
|
});
|
|
381
465
|
// ─── Tool 3: run_pre_pr_checks ───────────────────────────────────────────────
|
|
382
|
-
server.tool("run_pre_pr_checks", "Run all SecuFusion pre-PR guardrail checks
|
|
383
|
-
"
|
|
384
|
-
"and Flyway migration coverage for JPA entities. " +
|
|
385
|
-
"
|
|
466
|
+
server.tool("run_pre_pr_checks", "Run all SecuFusion pre-PR guardrail checks across the workspace. " +
|
|
467
|
+
"Automatically discovers modified microservices and runs their native linters (ESLint, Maven Checkstyle). " +
|
|
468
|
+
"Also validates: spec checkboxes, hardcoded IPs/URLs, and Flyway migration coverage for JPA entities. " +
|
|
469
|
+
"Linter errors must be fixed natively — do not suppress warnings to pass the gate. " +
|
|
470
|
+
"MUST pass with zero errors before a PR is raised.", {
|
|
386
471
|
work_item_id: z
|
|
387
472
|
.string()
|
|
388
473
|
.describe("Azure DevOps work item ID to include in the PR summary."),
|
|
@@ -422,21 +507,56 @@ server.tool("run_pre_pr_checks", "Run all SecuFusion pre-PR guardrail checks aga
|
|
|
422
507
|
else {
|
|
423
508
|
warnings.push("⚠️ [SPEC] Spec checkbox check SKIPPED (manually bypassed).");
|
|
424
509
|
}
|
|
425
|
-
// ── 2.
|
|
510
|
+
// ── 2. AST-level linting (Workspace Discovery → ESLint/Checkstyle → regex fallback)
|
|
426
511
|
if (!skip_checks.includes("console_logs")) {
|
|
427
|
-
|
|
428
|
-
if (
|
|
429
|
-
|
|
430
|
-
|
|
512
|
+
let projectRoots = findProjectRoots(scanRoot);
|
|
513
|
+
if (projectRoots.length === 0)
|
|
514
|
+
projectRoots.push(scanRoot);
|
|
515
|
+
let anyLinterAvailable = false;
|
|
516
|
+
const allLintViolations = [];
|
|
517
|
+
const usedLinters = new Set();
|
|
518
|
+
for (const pRoot of projectRoots) {
|
|
519
|
+
const eslint = runEslint(pRoot);
|
|
520
|
+
const checkstyle = runCheckstyle(pRoot);
|
|
521
|
+
if (eslint.available) {
|
|
522
|
+
anyLinterAvailable = true;
|
|
523
|
+
usedLinters.add("ESLint");
|
|
524
|
+
allLintViolations.push(...eslint.violations);
|
|
525
|
+
}
|
|
526
|
+
if (checkstyle.available) {
|
|
527
|
+
anyLinterAvailable = true;
|
|
528
|
+
usedLinters.add("Checkstyle");
|
|
529
|
+
allLintViolations.push(...checkstyle.violations);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
if (anyLinterAvailable) {
|
|
533
|
+
// AST linters found and ran — they are the source of truth
|
|
534
|
+
if (allLintViolations.length > 0) {
|
|
535
|
+
errors.push(`❌ [LINTING] ${allLintViolations.length} linter error(s) across workspace — fix natively in their respective microservices:\n` +
|
|
536
|
+
allLintViolations.map((v) => ` • ${v}`).join("\n"));
|
|
537
|
+
}
|
|
538
|
+
else {
|
|
539
|
+
passed.push(`✅ [LINTING] AST-level linting passed across workspace (${Array.from(usedLinters).join(" + ")}).`);
|
|
540
|
+
}
|
|
431
541
|
}
|
|
432
542
|
else {
|
|
433
|
-
|
|
543
|
+
// No linters configured — fall back to regex scan with a warning
|
|
544
|
+
const regexViolations = checkConsoleLogsRegex(scanRoot);
|
|
545
|
+
if (regexViolations.length > 0) {
|
|
546
|
+
errors.push(`❌ [LOGGING] ${regexViolations.length} prohibited log statement(s) found via regex fallback\n` +
|
|
547
|
+
` (No ESLint/Checkstyle config detected in any workspace project — configure a linter for AST-level accuracy):\n` +
|
|
548
|
+
regexViolations.map((v) => ` • ${v}`).join("\n"));
|
|
549
|
+
}
|
|
550
|
+
else {
|
|
551
|
+
warnings.push("⚠️ [LOGGING] No ESLint/Checkstyle config found in workspace — used regex fallback. " +
|
|
552
|
+
"Consider adding a linter for AST-level hygiene.");
|
|
553
|
+
}
|
|
434
554
|
}
|
|
435
555
|
}
|
|
436
556
|
else {
|
|
437
|
-
warnings.push("⚠️ [
|
|
557
|
+
warnings.push("⚠️ [LINTING] Linter check SKIPPED (manually bypassed).");
|
|
438
558
|
}
|
|
439
|
-
// ── 3. Hardcoded URL check
|
|
559
|
+
// ── 3. Hardcoded URL check (regex — no AST equivalent needed here) ───────
|
|
440
560
|
if (!skip_checks.includes("hardcoded_urls")) {
|
|
441
561
|
const urlViolations = checkHardcodedUrls(scanRoot);
|
|
442
562
|
if (urlViolations.length > 0) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "secufusion-mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "SecuFusion MCP server - developer workflow tooling with guardrails",
|
|
6
6
|
"main": "index.js",
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
},
|
|
18
18
|
"scripts": {
|
|
19
19
|
"build": "tsc",
|
|
20
|
-
"prepublishOnly": "npm run build",
|
|
20
|
+
"prepublishOnly": "copy ..\\README.md README.md && npm run build",
|
|
21
|
+
"postpublish": "del README.md",
|
|
21
22
|
"start": "node index.js",
|
|
22
23
|
"dev": "tsc && node index.js"
|
|
23
24
|
},
|