mcp-sentinel 0.1.3 → 0.2.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 CHANGED
@@ -1,54 +1,102 @@
1
1
  <p align="center">
2
2
  <h1 align="center">MCP Sentinel</h1>
3
3
  <p align="center">
4
- <strong>Know what your MCP servers can do before your AI agent does.</strong>
4
+ <strong>Know what your MCP servers can do -- before your AI agent does.</strong>
5
5
  </p>
6
6
  <p align="center">
7
7
  <a href="https://www.npmjs.com/package/mcp-sentinel"><img src="https://img.shields.io/npm/v/mcp-sentinel.svg" alt="npm version"></a>
8
+ <a href="https://www.npmjs.com/package/mcp-sentinel"><img src="https://img.shields.io/npm/dm/mcp-sentinel.svg" alt="npm downloads"></a>
8
9
  <a href="https://github.com/oktsec/mcp-sentinel/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/mcp-sentinel.svg" alt="license"></a>
9
10
  <a href="https://nodejs.org"><img src="https://img.shields.io/node/v/mcp-sentinel.svg" alt="node version"></a>
11
+ <a href="https://github.com/oktsec/mcp-sentinel"><img src="https://img.shields.io/github/stars/oktsec/mcp-sentinel?style=social" alt="GitHub stars"></a>
10
12
  </p>
11
13
  </p>
12
14
 
15
+ > **v0.2.0** -- Risk scoring (A-F), SARIF output, per-tool security analysis, verbose mode, HTTP header support
16
+
13
17
  ---
14
18
 
15
19
  ## The Problem
16
20
 
17
- You add an MCP server to Claude Desktop, Cursor, or your agent framework. Now that server has tools your AI can call tools that might read your files, run shell commands, or delete data.
21
+ You add an MCP server to Claude Desktop, Cursor, or your agent framework. Now that server has tools your AI can call -- tools that might read your files, run shell commands, or delete data.
18
22
 
19
23
  **You're trusting code you haven't reviewed.**
20
24
 
21
- MCP Sentinel connects to any MCP server, shows you every tool it exposes, and lets you define security policies that block dangerous ones automatically.
25
+ MCP Sentinel connects to any MCP server, shows you every tool it exposes, assigns a risk score, and lets you define security policies that block dangerous ones automatically.
26
+
27
+ ### Features
28
+
29
+ - **Risk Scoring** -- A-F grade for every server based on tool risk, security findings, and attack surface
30
+ - **Policy Engine** -- YAML-based deny/require/allow rules with glob patterns and auto-detection
31
+ - **Deep Security Analysis** -- Per-tool scanning with [Aguara](https://github.com/garagon/aguara) (177 rules: prompt injection, exfiltration, credential leaks)
32
+ - **Smart Categorization** -- Tools auto-escalate from "read" to "admin" when critical findings are detected
33
+ - **Multi-Transport** -- stdio, SSE, and Streamable HTTP with custom header support
34
+ - **Config Discovery** -- Auto-scan servers from Claude Desktop, Cursor, Windsurf, VS Code, Zed
35
+ - **CI/CD Ready** -- SARIF output for GitHub Code Scanning, exit codes for policy violations
36
+ - **Drift Detection** -- Save baselines and detect added/removed/changed tools over time
37
+ - **Multiple Exports** -- Terminal, JSON, Markdown, SARIF
22
38
 
23
39
  ## Quick Start
24
40
 
25
41
  ```bash
26
- # Scan any MCP server no install needed
42
+ # Scan any MCP server -- no install needed
27
43
  npx mcp-sentinel npx @modelcontextprotocol/server-filesystem /tmp
28
44
  ```
29
45
 
30
46
  That's it. You'll see every tool the server exposes, categorized by risk:
31
47
 
32
48
  ```
33
- 🔍 MCP Sentinel v0.1.0
49
+ ┌──────────────────────────────┐
50
+ │ MCP Sentinel v0.2.0 │
51
+ └──────────────────────────────┘
52
+
53
+ Server secure-filesystem-server v0.2.0
54
+ Capabilities tools
55
+ Risk Score B (82/100)
56
+
57
+ 🔧 Tools (14) 11 read · 3 write · 0 admin
34
58
 
35
- 📦 Server: secure-filesystem-server v0.2.0
36
- Capabilities: tools
59
+ move_file write
60
+ Move or rename files and directories
37
61
 
38
- 🔧 Tools (14) 11 read · 3 write · 0 admin
62
+ edit_file write
63
+ Make line-based edits to a text file
64
+ path* · edits* · dryRun
39
65
 
40
- read_file Read the complete contents of a file... (3 params)
41
- read_multiple_files Read multiple files simultaneously... (1 params)
42
- ✏️ write_file Create a new file or overwrite... [write] (2 params)
43
- ✏️ create_directory Create a new directory... [write] (1 params)
44
- ✏️ move_file Move or rename files... [write] (2 params)
45
- list_directory Get a detailed listing of all files... (1 params)
46
- ✅ search_files Recursively search for files... (3 params)
66
+ write_file write
67
+ Create a new file or overwrite an existing file
68
+ path* · content*
69
+
70
+ read_file read
71
+ Read the complete contents of a file from the file system
72
+ path*
73
+
74
+ ✔ list_directory read
75
+ Get a detailed listing of all files and directories
76
+ path*
47
77
  ...
48
78
 
49
- Scanned in 1706ms
79
+ ──────────────────────────────────────────────────────────────
80
+
81
+ 🛡️ No security findings · aguara scan clean
82
+
83
+ ──────────────────────────────────────────────────────────────
84
+
85
+ Scanned in 1706ms · Deep scan: https://aguarascan.com
50
86
  ```
51
87
 
88
+ ## Risk Score
89
+
90
+ Every server gets an **A-F grade** (0-100 scale) based on three factors:
91
+
92
+ | Factor | Weight | What it measures |
93
+ |--------|--------|-----------------|
94
+ | Tool risk | 40 pts | Penalty for write (-3) and admin (-8) tools |
95
+ | Finding risk | 40 pts | Penalty per aguara finding, weighted by severity |
96
+ | Surface risk | 20 pts | Penalty for large tool counts (>10, >20) |
97
+
98
+ A read-only server with no findings scores **A (100/100)**. A server with admin tools and critical findings scores **D** or **F**.
99
+
52
100
  ## Add a Security Policy
53
101
 
54
102
  Create a `.mcp-policy.yml` in your project root:
@@ -57,9 +105,13 @@ Create a `.mcp-policy.yml` in your project root:
57
105
  deny:
58
106
  categories: [admin] # Block dangerous tools (delete, exec, shell)
59
107
  tools: ["write_*", "move_*"] # Block by name pattern
108
+ descriptions: ["*ssh*"] # Block tools mentioning SSH in descriptions
60
109
 
61
110
  require:
62
111
  maxTools: 10 # Limit attack surface
112
+ maxFindings: # Limit security findings by severity
113
+ critical: 0
114
+ high: 0
63
115
 
64
116
  allow:
65
117
  tools: ["write_file"] # Exceptions to deny rules
@@ -74,10 +126,10 @@ npx mcp-sentinel --policy .mcp-policy.yml npx @modelcontextprotocol/server-files
74
126
  ```
75
127
  🛡️ Policy: .mcp-policy.yml
76
128
 
77
- secure-filesystem-server: policy FAILED (2 violations)
129
+ secure-filesystem-server policy FAILED (2 violations)
78
130
 
79
- [deny.tools] Tool 'move_file' matches denied pattern 'move_*'
80
- [require.maxTools] Server exposes 14 tools, policy allows max 10
131
+ [deny.tools] Tool 'move_file' matches denied pattern 'move_*'
132
+ [require.maxTools] Server exposes 14 tools, policy allows max 10
81
133
  ```
82
134
 
83
135
  Exit code `2` = violations found. Your CI pipeline stops here.
@@ -114,13 +166,40 @@ jobs:
114
166
 
115
167
  </details>
116
168
 
169
+ <details>
170
+ <summary>SARIF integration for GitHub Code Scanning</summary>
171
+
172
+ ```yaml
173
+ # .github/workflows/mcp-audit.yml
174
+ name: MCP Security Audit
175
+ on: [pull_request]
176
+
177
+ jobs:
178
+ audit:
179
+ runs-on: ubuntu-latest
180
+ steps:
181
+ - uses: actions/checkout@v4
182
+ - uses: actions/setup-node@v4
183
+ with: { node-version: 20 }
184
+ - run: npx mcp-sentinel --sarif results.sarif npx ./your-mcp-server
185
+ - uses: github/codeql-action/upload-sarif@v3
186
+ with:
187
+ sarif_file: results.sarif
188
+ if: always()
189
+ ```
190
+
191
+ </details>
192
+
117
193
  ## What Else Can It Do?
118
194
 
119
195
  ```bash
120
196
  # Scan a remote server over HTTP
121
197
  npx mcp-sentinel http://localhost:3000/mcp
122
198
 
123
- # Scan all servers from your Claude Desktop, Cursor, or Windsurf config
199
+ # Scan with custom headers (for authenticated servers)
200
+ npx mcp-sentinel --header "Authorization: Bearer xxx" http://localhost:3000/mcp
201
+
202
+ # Scan all servers from your Claude Desktop, Cursor, Windsurf, VS Code, or Zed config
124
203
  npx mcp-sentinel --config
125
204
 
126
205
  # Save a scan and detect changes later (drift detection)
@@ -130,9 +209,13 @@ npx mcp-sentinel npx @modelcontextprotocol/server-filesystem /tmp --diff baselin
130
209
  # Scan multiple servers in one command
131
210
  npx mcp-sentinel npx @modelcontextprotocol/server-filesystem /tmp --- npx @modelcontextprotocol/server-github
132
211
 
133
- # Export as JSON or Markdown
212
+ # Export as JSON, Markdown, or SARIF
134
213
  npx mcp-sentinel --json npx @modelcontextprotocol/server-filesystem /tmp
135
214
  npx mcp-sentinel --markdown report.md npx @modelcontextprotocol/server-filesystem /tmp
215
+ npx mcp-sentinel --sarif report.sarif npx @modelcontextprotocol/server-filesystem /tmp
216
+
217
+ # Verbose mode: full descriptions, finding details, and remediation
218
+ npx mcp-sentinel --verbose npx @modelcontextprotocol/server-filesystem /tmp
136
219
  ```
137
220
 
138
221
  ## Policy Reference
@@ -141,8 +224,10 @@ npx mcp-sentinel --markdown report.md npx @modelcontextprotocol/server-filesyste
141
224
  |------|-------------|---------|
142
225
  | `deny.categories` | Block tools by category | `[admin]`, `[admin, write]` |
143
226
  | `deny.tools` | Block by name or glob | `["delete_*", "run_command"]` |
227
+ | `deny.descriptions` | Block tools by description content | `["*ssh*", "*IMPORTANT*"]` |
144
228
  | `require.maxTools` | Max number of tools allowed | `20` |
145
229
  | `require.aguara` | Require zero security findings | `clean` |
230
+ | `require.maxFindings` | Limit findings by severity | `{ critical: 0, high: 0 }` |
146
231
  | `allow.tools` | Exceptions to deny rules | `["execute_query"]` |
147
232
 
148
233
  ### Starter Policies
@@ -151,32 +236,41 @@ Pick one from [`examples/policies/`](examples/policies/) and customize:
151
236
 
152
237
  | Policy | Best for |
153
238
  |--------|----------|
154
- | [`permissive.yml`](examples/policies/permissive.yml) | Local development blocks only destructive patterns |
155
- | [`standard.yml`](examples/policies/standard.yml) | Team development blocks admin + exec, allows writes |
156
- | [`strict.yml`](examples/policies/strict.yml) | Production blocks admin + write, requires security scan |
157
- | [`ci-pipeline.yml`](examples/policies/ci-pipeline.yml) | CI/CD blocks admin + deploy + push |
239
+ | [`permissive.yml`](examples/policies/permissive.yml) | Local development -- blocks only destructive patterns |
240
+ | [`standard.yml`](examples/policies/standard.yml) | Team development -- blocks admin + exec, allows writes |
241
+ | [`strict.yml`](examples/policies/strict.yml) | Production -- blocks admin + write, requires security scan |
242
+ | [`ci-pipeline.yml`](examples/policies/ci-pipeline.yml) | CI/CD -- blocks admin + deploy + push |
158
243
 
159
244
  ## Deep Security Analysis with Aguara
160
245
 
161
- MCP Sentinel can optionally integrate with [Aguara](https://github.com/garagon/aguara), a security scanner with 177 rules that detects prompt injection, data exfiltration, credential leaks, and more.
246
+ MCP Sentinel integrates with [Aguara](https://github.com/garagon/aguara), a security scanner with 177 rules that detects prompt injection, data exfiltration, credential leaks, and more.
247
+
248
+ When Aguara is installed, MCP Sentinel:
249
+ - Scans each tool individually and attributes findings to specific tools
250
+ - Escalates tool categories based on findings (a "read" tool with a critical injection finding becomes "admin")
251
+ - Reports severity, category, description, and remediation for each finding
252
+ - Factors findings into the risk score
162
253
 
163
254
  ```bash
164
255
  # Install Aguara (optional)
165
256
  curl -fsSL https://raw.githubusercontent.com/garagon/aguara/main/install.sh | bash
166
257
  ```
167
258
 
168
- Once installed, MCP Sentinel auto-detects it and runs the analysis. Add `require.aguara: clean` to your policy to enforce zero findings.
259
+ Once installed, MCP Sentinel auto-detects it. Add `require.aguara: clean` to your policy to enforce zero findings.
169
260
 
170
261
  ## All Options
171
262
 
172
263
  | Flag | Description |
173
264
  |------|-------------|
174
265
  | `--policy <file>` | Enforce a security policy (auto-detects `.mcp-policy.yml`) |
175
- | `--config` | Scan servers from Claude Desktop / Cursor / Windsurf config |
266
+ | `--config` | Scan servers from Claude Desktop / Cursor / Windsurf / VS Code / Zed config |
176
267
  | `--diff <file.json>` | Compare against a previous scan |
268
+ | `--sarif <file>` | Export SARIF report for GitHub Code Scanning |
177
269
  | `--transport <type>` | Force transport: `stdio`, `sse`, `streamable-http` |
178
270
  | `--json` | JSON output |
179
271
  | `--markdown <file>` | Export Markdown report |
272
+ | `--verbose` | Show full descriptions, finding details, and remediation |
273
+ | `--header <value>` | HTTP header for remote servers (repeatable) |
180
274
  | `--fail-on-findings` | Exit code 2 if aguara finds issues |
181
275
  | `--no-color` | Disable colors |
182
276
  | `--timeout <ms>` | Connection timeout (default: 30000) |
@@ -193,11 +287,12 @@ Once installed, MCP Sentinel auto-detects it and runs the analysis. Add `require
193
287
  │ sentinel │ SSE │ MCP Server │
194
288
  │ ├──────── │ (remote) │
195
289
  │ Scan │ └────────────────┘
196
- Enforce
197
- Diff │ ┌──────────────────┐
198
- Report │ ──────► │ Aguara (177 │
199
- └───────────┘ │ security rules) │
200
- └──────────────────┘
290
+ Score
291
+ Enforce │ ┌──────────────────┐
292
+ Diff │ ──────► │ Aguara (177 │
293
+ │ Report │ │ security rules) │
294
+ └───────────┘ └──────────────────┘
295
+
201
296
 
202
297
  .mcp-policy.yml
203
298
  (deny / require / allow)
@@ -209,10 +304,10 @@ MCP Sentinel is part of the [Aguara](https://github.com/garagon/aguara) security
209
304
 
210
305
  | Tool | What it does |
211
306
  |------|-------------|
212
- | **[Aguara](https://github.com/garagon/aguara)** | Security scanner 177 rules, NLP, toxic-flow analysis |
213
- | **[MCP Aguara](https://github.com/garagon/mcp-aguara)** | MCP server gives AI agents security scanning as a tool |
214
- | **MCP Sentinel** | Policy enforcement audit, enforce, and monitor MCP servers |
215
- | **[Aguara Watch](https://aguarascan.com)** | Cloud platform continuous monitoring of MCP registries |
307
+ | **[Aguara](https://github.com/garagon/aguara)** | Security scanner -- 177 rules, NLP, toxic-flow analysis |
308
+ | **[MCP Aguara](https://github.com/garagon/mcp-aguara)** | MCP server -- gives AI agents security scanning as a tool |
309
+ | **MCP Sentinel** | Policy enforcement -- audit, score, enforce, and monitor MCP servers |
310
+ | **[Aguara Watch](https://aguarascan.com)** | Cloud platform -- continuous monitoring of MCP registries |
216
311
 
217
312
  ## Contributing
218
313
 
@@ -220,4 +315,4 @@ Contributions welcome. Please open an issue first to discuss what you'd like to
220
315
 
221
316
  ## License
222
317
 
223
- [Apache 2.0](LICENSE) Gustavo Aragon ([@oktsec](https://github.com/oktsec))
318
+ [Apache 2.0](LICENSE) -- Gustavo Aragon ([@oktsec](https://github.com/oktsec))
package/dist/aguara.d.ts CHANGED
@@ -1,4 +1,10 @@
1
- import type { ToolInfo, AguaraResult } from "./types.js";
1
+ import type { ToolInfo, ResourceInfo, ResourceTemplateInfo, PromptInfo, AguaraResult } from "./types.js";
2
2
  export declare function isAguaraInstalled(): Promise<boolean>;
3
- export declare function scanWithAguara(tools: ToolInfo[]): Promise<AguaraResult>;
3
+ export interface AguaraScanInput {
4
+ tools: ToolInfo[];
5
+ resources: ResourceInfo[];
6
+ resourceTemplates: ResourceTemplateInfo[];
7
+ prompts: PromptInfo[];
8
+ }
9
+ export declare function scanWithAguara(input: AguaraScanInput): Promise<AguaraResult>;
4
10
  //# sourceMappingURL=aguara.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"aguara.d.ts","sourceRoot":"","sources":["../src/aguara.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAiB,MAAM,YAAY,CAAC;AAIxE,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC,CAO1D;AAyDD,wBAAsB,cAAc,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CAgD7E"}
1
+ {"version":3,"file":"aguara.d.ts","sourceRoot":"","sources":["../src/aguara.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,oBAAoB,EAAE,UAAU,EAAE,YAAY,EAAiB,MAAM,YAAY,CAAC;AAWxH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC,CAO1D;AAqHD,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,iBAAiB,EAAE,oBAAoB,EAAE,CAAC;IAC1C,OAAO,EAAE,UAAU,EAAE,CAAC;CACvB;AAED,wBAAsB,cAAc,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,YAAY,CAAC,CA8FlF"}
package/dist/aguara.js CHANGED
@@ -1,9 +1,15 @@
1
1
  import { execFile } from "node:child_process";
2
- import { writeFile, unlink, mkdtemp } from "node:fs/promises";
2
+ import { writeFile, unlink, mkdtemp, mkdir } from "node:fs/promises";
3
3
  import { join } from "node:path";
4
4
  import { tmpdir } from "node:os";
5
5
  import { promisify } from "node:util";
6
6
  const execFileAsync = promisify(execFile);
7
+ const SEV_LABELS = {
8
+ 4: "CRITICAL",
9
+ 3: "HIGH",
10
+ 2: "MEDIUM",
11
+ 1: "LOW",
12
+ };
7
13
  export async function isAguaraInstalled() {
8
14
  try {
9
15
  await execFileAsync("aguara", ["version"]);
@@ -13,91 +19,191 @@ export async function isAguaraInstalled() {
13
19
  return false;
14
20
  }
15
21
  }
16
- function buildScanContent(tools) {
22
+ function buildToolFile(tool) {
17
23
  const lines = [];
18
- for (const tool of tools) {
19
- lines.push(`## Tool: ${tool.name}`);
24
+ lines.push(`## Tool: ${tool.name}`);
25
+ lines.push("");
26
+ lines.push(tool.description);
27
+ lines.push("");
28
+ if (tool.parameters.length > 0) {
29
+ for (const p of tool.parameters) {
30
+ lines.push(`- ${p.name} (${p.type}${p.required ? ", required" : ""}): ${p.description}`);
31
+ }
20
32
  lines.push("");
21
- lines.push(tool.description);
33
+ }
34
+ return lines.join("\n");
35
+ }
36
+ function buildResourceContent(resources, templates) {
37
+ const lines = [];
38
+ for (const r of resources) {
39
+ lines.push(`## Resource: ${r.name}`);
40
+ lines.push(`URI: ${r.uri}`);
41
+ if (r.description.length > 0)
42
+ lines.push(r.description);
43
+ lines.push("");
44
+ }
45
+ for (const r of templates) {
46
+ lines.push(`## Resource Template: ${r.name}`);
47
+ lines.push(`URI Template: ${r.uriTemplate}`);
48
+ if (r.description.length > 0)
49
+ lines.push(r.description);
22
50
  lines.push("");
23
- if (tool.parameters.length > 0) {
24
- lines.push(`Parameters: ${tool.parameters.map((p) => p.name).join(", ")}`);
25
- lines.push("");
26
- }
27
51
  }
28
52
  return lines.join("\n");
29
53
  }
30
- function parseAguaraOutput(stdout) {
31
- try {
32
- const parsed = JSON.parse(stdout);
33
- const findings = [];
34
- if (Array.isArray(parsed.findings)) {
35
- for (const f of parsed.findings) {
36
- findings.push({
37
- severity: String(f.severity ?? "UNKNOWN"),
38
- ruleId: String(f.rule_id ?? ""),
39
- ruleName: String(f.rule_name ?? ""),
40
- matchedText: String(f.matched_text ?? ""),
41
- line: typeof f.line === "number" ? f.line : undefined,
42
- });
54
+ function buildPromptContent(prompts) {
55
+ const lines = [];
56
+ for (const p of prompts) {
57
+ lines.push(`## Prompt: ${p.name}`);
58
+ if (p.description.length > 0)
59
+ lines.push(p.description);
60
+ if (p.arguments.length > 0) {
61
+ for (const a of p.arguments) {
62
+ lines.push(`- ${a.name}${a.required ? " (required)" : ""}: ${a.description}`);
43
63
  }
44
64
  }
45
- return {
46
- findings,
47
- summary: typeof parsed.summary === "string" ? parsed.summary : `${findings.length} finding(s)`,
48
- };
49
- }
50
- catch {
51
- return { findings: [], summary: "Failed to parse aguara output" };
65
+ lines.push("");
52
66
  }
67
+ return lines.join("\n");
53
68
  }
54
- export async function scanWithAguara(tools) {
55
- const installed = await isAguaraInstalled();
56
- if (!installed) {
57
- return {
58
- available: false,
59
- findings: [],
60
- summary: "aguara not installed — install from https://github.com/garagon/aguara for deep security analysis",
61
- };
69
+ function normalizeSeverity(sev) {
70
+ if (typeof sev === "number")
71
+ return SEV_LABELS[sev] ?? String(sev);
72
+ if (typeof sev === "string") {
73
+ const upper = sev.toUpperCase();
74
+ if (["CRITICAL", "HIGH", "MEDIUM", "LOW"].includes(upper))
75
+ return upper;
76
+ return sev;
62
77
  }
63
- const content = buildScanContent(tools);
64
- const tmpDir = await mkdtemp(join(tmpdir(), "mcp-sentinel-"));
65
- const tmpFile = join(tmpDir, "tools.md");
78
+ return "UNKNOWN";
79
+ }
80
+ function parseFindings(raw, toolName) {
81
+ return raw.map((f) => ({
82
+ severity: normalizeSeverity(f.severity),
83
+ ruleId: String(f.rule_id ?? ""),
84
+ ruleName: String(f.rule_name ?? ""),
85
+ category: String(f.category ?? ""),
86
+ description: String(f.description ?? ""),
87
+ matchedText: String(f.matched_text ?? ""),
88
+ toolName,
89
+ line: typeof f.line === "number" ? f.line : undefined,
90
+ confidence: typeof f.confidence === "number" ? f.confidence : undefined,
91
+ score: typeof f.score === "number" ? f.score : undefined,
92
+ remediation: typeof f.remediation === "string" ? f.remediation : undefined,
93
+ }));
94
+ }
95
+ async function runAguara(filePath) {
66
96
  try {
67
- await writeFile(tmpFile, content, "utf-8");
68
97
  const { stdout } = await execFileAsync("aguara", [
69
- "scan", tmpFile, "--format", "json", "--severity", "low",
98
+ "scan", filePath, "--format", "json", "--severity", "low",
70
99
  ], {
71
100
  timeout: 30_000,
72
101
  env: process.env,
73
102
  maxBuffer: 10 * 1024 * 1024,
74
103
  });
75
- const result = parseAguaraOutput(stdout);
76
- return { available: true, ...result };
104
+ return JSON.parse(stdout);
77
105
  }
78
106
  catch (err) {
79
107
  // aguara exits with code 1 when findings are found, but still outputs JSON
80
108
  if (typeof err === "object" && err !== null && "stdout" in err) {
81
109
  const stdout = String(err.stdout);
82
110
  if (stdout.trim().length > 0) {
83
- const result = parseAguaraOutput(stdout);
84
- return { available: true, ...result };
111
+ return JSON.parse(stdout);
85
112
  }
86
113
  }
114
+ return { findings: [] };
115
+ }
116
+ }
117
+ export async function scanWithAguara(input) {
118
+ const installed = await isAguaraInstalled();
119
+ if (!installed) {
120
+ return {
121
+ available: false,
122
+ findings: [],
123
+ summary: "aguara not installed",
124
+ };
125
+ }
126
+ const tmpDir = await mkdtemp(join(tmpdir(), "mcp-sentinel-"));
127
+ const toolsDir = join(tmpDir, "tools");
128
+ await mkdir(toolsDir);
129
+ const allFindings = [];
130
+ const filesToClean = [];
131
+ let rulesLoaded = 0;
132
+ let totalDuration = 0;
133
+ try {
134
+ // Scan each tool individually for per-tool finding attribution
135
+ for (const tool of input.tools) {
136
+ const content = buildToolFile(tool);
137
+ const filePath = join(toolsDir, `${tool.name}.md`);
138
+ await writeFile(filePath, content, "utf-8");
139
+ filesToClean.push(filePath);
140
+ const output = await runAguara(filePath);
141
+ if (output.rules_loaded !== undefined)
142
+ rulesLoaded = output.rules_loaded;
143
+ if (output.duration_ms !== undefined)
144
+ totalDuration += output.duration_ms;
145
+ if (Array.isArray(output.findings)) {
146
+ allFindings.push(...parseFindings(output.findings, tool.name));
147
+ }
148
+ }
149
+ // Scan resources
150
+ if (input.resources.length > 0 || input.resourceTemplates.length > 0) {
151
+ const content = buildResourceContent(input.resources, input.resourceTemplates);
152
+ if (content.trim().length > 0) {
153
+ const filePath = join(tmpDir, "resources.md");
154
+ await writeFile(filePath, content, "utf-8");
155
+ filesToClean.push(filePath);
156
+ const output = await runAguara(filePath);
157
+ if (output.duration_ms !== undefined)
158
+ totalDuration += output.duration_ms;
159
+ if (Array.isArray(output.findings)) {
160
+ allFindings.push(...parseFindings(output.findings, "[resource]"));
161
+ }
162
+ }
163
+ }
164
+ // Scan prompts
165
+ if (input.prompts.length > 0) {
166
+ const content = buildPromptContent(input.prompts);
167
+ if (content.trim().length > 0) {
168
+ const filePath = join(tmpDir, "prompts.md");
169
+ await writeFile(filePath, content, "utf-8");
170
+ filesToClean.push(filePath);
171
+ const output = await runAguara(filePath);
172
+ if (output.duration_ms !== undefined)
173
+ totalDuration += output.duration_ms;
174
+ if (Array.isArray(output.findings)) {
175
+ allFindings.push(...parseFindings(output.findings, "[prompt]"));
176
+ }
177
+ }
178
+ }
179
+ // Sort by severity (CRITICAL first)
180
+ const sevOrder = { CRITICAL: 0, HIGH: 1, MEDIUM: 2, LOW: 3 };
181
+ allFindings.sort((a, b) => (sevOrder[a.severity] ?? 9) - (sevOrder[b.severity] ?? 9));
182
+ return {
183
+ available: true,
184
+ findings: allFindings,
185
+ summary: `${allFindings.length} finding(s)`,
186
+ rulesLoaded: rulesLoaded > 0 ? rulesLoaded : undefined,
187
+ durationMs: totalDuration > 0 ? totalDuration : undefined,
188
+ };
189
+ }
190
+ catch {
87
191
  return {
88
192
  available: true,
89
193
  findings: [],
90
- summary: `aguara scan failed: ${err instanceof Error ? err.message : "unknown error"}`,
194
+ summary: "aguara scan failed",
91
195
  };
92
196
  }
93
197
  finally {
94
- try {
95
- await unlink(tmpFile);
198
+ for (const f of filesToClean) {
199
+ try {
200
+ await unlink(f);
201
+ }
202
+ catch { /* cleanup */ }
96
203
  }
97
- catch { /* cleanup */ }
98
204
  try {
99
- const { rmdir } = await import("node:fs/promises");
100
- await rmdir(tmpDir);
205
+ const { rm } = await import("node:fs/promises");
206
+ await rm(tmpDir, { recursive: true });
101
207
  }
102
208
  catch { /* cleanup */ }
103
209
  }
@@ -1 +1 @@
1
- {"version":3,"file":"aguara.js","sourceRoot":"","sources":["../src/aguara.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"aguara.js","sourceRoot":"","sources":["../src/aguara.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- import type { ToolInfo, AnalyzedTool, ToolCategory } from "./types.js";
2
- export declare function categorizeTool(tool: ToolInfo): ToolCategory;
3
- export declare function analyzeTools(tools: ToolInfo[]): AnalyzedTool[];
1
+ import type { ToolInfo, AnalyzedTool, ToolCategory, AguaraFinding } from "./types.js";
2
+ export declare function categorizeTool(tool: ToolInfo, findings?: AguaraFinding[]): ToolCategory;
3
+ export declare function analyzeTools(tools: ToolInfo[], findingsByTool?: Map<string, AguaraFinding[]>): AnalyzedTool[];
4
4
  export declare function summarize(tools: AnalyzedTool[]): {
5
5
  read: number;
6
6
  write: number;
@@ -1 +1 @@
1
- {"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EACR,YAAY,EACZ,YAAY,EACb,MAAM,YAAY,CAAC;AAepB,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,YAAY,CAU3D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,YAAY,EAAE,CAK9D;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAY/F"}
1
+ {"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,aAAa,EACd,MAAM,YAAY,CAAC;AAsBpB,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,aAAa,EAAE,GAAG,YAAY,CAmBvF;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,cAAc,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,GAAG,YAAY,EAAE,CAS7G;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAY/F"}