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 +133 -38
- package/dist/aguara.d.ts +8 -2
- package/dist/aguara.d.ts.map +1 -1
- package/dist/aguara.js +158 -52
- package/dist/aguara.js.map +1 -1
- package/dist/analyzer.d.ts +3 -3
- package/dist/analyzer.d.ts.map +1 -1
- package/dist/analyzer.js +23 -6
- package/dist/analyzer.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +28 -5
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +20 -8
- package/dist/config.js.map +1 -1
- package/dist/formatter.d.ts +4 -1
- package/dist/formatter.d.ts.map +1 -1
- package/dist/formatter.js +180 -49
- package/dist/formatter.js.map +1 -1
- package/dist/index.js +36 -7
- package/dist/index.js.map +1 -1
- package/dist/markdown.d.ts.map +1 -1
- package/dist/markdown.js +9 -4
- package/dist/markdown.js.map +1 -1
- package/dist/policy.d.ts.map +1 -1
- package/dist/policy.js +66 -1
- package/dist/policy.js.map +1 -1
- package/dist/sarif.d.ts +3 -0
- package/dist/sarif.d.ts.map +1 -0
- package/dist/sarif.js +75 -0
- package/dist/sarif.js.map +1 -0
- package/dist/scanner.d.ts +1 -1
- package/dist/scanner.d.ts.map +1 -1
- package/dist/scanner.js +23 -7
- package/dist/scanner.js.map +1 -1
- package/dist/score.d.ts +21 -0
- package/dist/score.d.ts.map +1 -0
- package/dist/score.js +45 -0
- package/dist/score.js.map +1 -0
- package/dist/types.d.ts +25 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +10 -3
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
36
|
-
|
|
59
|
+
⚠ move_file write
|
|
60
|
+
Move or rename files and directories
|
|
37
61
|
|
|
38
|
-
|
|
62
|
+
⚠ edit_file write
|
|
63
|
+
Make line-based edits to a text file
|
|
64
|
+
path* · edits* · dryRun
|
|
39
65
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
-
|
|
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
|
-
|
|
129
|
+
✖ secure-filesystem-server policy FAILED (2 violations)
|
|
78
130
|
|
|
79
|
-
|
|
80
|
-
|
|
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
|
|
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
|
|
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
|
|
155
|
-
| [`standard.yml`](examples/policies/standard.yml) | Team development
|
|
156
|
-
| [`strict.yml`](examples/policies/strict.yml) | Production
|
|
157
|
-
| [`ci-pipeline.yml`](examples/policies/ci-pipeline.yml) | CI/CD
|
|
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
|
|
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
|
|
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
|
-
│
|
|
197
|
-
│
|
|
198
|
-
│
|
|
199
|
-
|
|
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
|
|
213
|
-
| **[MCP Aguara](https://github.com/garagon/mcp-aguara)** | MCP server
|
|
214
|
-
| **MCP Sentinel** | Policy enforcement
|
|
215
|
-
| **[Aguara Watch](https://aguarascan.com)** | Cloud platform
|
|
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)
|
|
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
|
|
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
|
package/dist/aguara.d.ts.map
CHANGED
|
@@ -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;
|
|
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
|
|
22
|
+
function buildToolFile(tool) {
|
|
17
23
|
const lines = [];
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
|
|
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
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if (
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
|
|
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
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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",
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
194
|
+
summary: "aguara scan failed",
|
|
91
195
|
};
|
|
92
196
|
}
|
|
93
197
|
finally {
|
|
94
|
-
|
|
95
|
-
|
|
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 {
|
|
100
|
-
await
|
|
205
|
+
const { rm } = await import("node:fs/promises");
|
|
206
|
+
await rm(tmpDir, { recursive: true });
|
|
101
207
|
}
|
|
102
208
|
catch { /* cleanup */ }
|
|
103
209
|
}
|
package/dist/aguara.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aguara.js","sourceRoot":"","sources":["../src/aguara.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"aguara.js","sourceRoot":"","sources":["../src/aguara.ts"],"names":[],"mappings":"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"}
|
package/dist/analyzer.d.ts
CHANGED
|
@@ -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;
|
package/dist/analyzer.d.ts.map
CHANGED
|
@@ -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,
|
|
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"}
|