trustmcp 0.1.0__tar.gz
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.
- trustmcp-0.1.0/LICENSE +21 -0
- trustmcp-0.1.0/MANIFEST.in +14 -0
- trustmcp-0.1.0/PKG-INFO +253 -0
- trustmcp-0.1.0/README.md +220 -0
- trustmcp-0.1.0/pyproject.toml +58 -0
- trustmcp-0.1.0/requirements.txt +3 -0
- trustmcp-0.1.0/setup.cfg +4 -0
- trustmcp-0.1.0/trustmcp/__init__.py +15 -0
- trustmcp-0.1.0/trustmcp/cli.py +257 -0
- trustmcp-0.1.0/trustmcp/core/__init__.py +1 -0
- trustmcp-0.1.0/trustmcp/core/auth_posture.py +204 -0
- trustmcp-0.1.0/trustmcp/core/dynamic_client.py +440 -0
- trustmcp-0.1.0/trustmcp/core/models.py +70 -0
- trustmcp-0.1.0/trustmcp/core/plugins.py +79 -0
- trustmcp-0.1.0/trustmcp/core/scoring.py +152 -0
- trustmcp-0.1.0/trustmcp/core/static_analyzer.py +625 -0
- trustmcp-0.1.0/trustmcp/core/text_safety.py +44 -0
- trustmcp-0.1.0/trustmcp/reporters/__init__.py +1 -0
- trustmcp-0.1.0/trustmcp/reporters/cli_reporter.py +137 -0
- trustmcp-0.1.0/trustmcp/reporters/json_reporter.py +49 -0
- trustmcp-0.1.0/trustmcp/reporters/sarif_reporter.py +143 -0
- trustmcp-0.1.0/trustmcp/utils/__init__.py +1 -0
- trustmcp-0.1.0/trustmcp/utils/exceptions.py +22 -0
- trustmcp-0.1.0/trustmcp/utils/logging.py +34 -0
- trustmcp-0.1.0/trustmcp.egg-info/PKG-INFO +253 -0
- trustmcp-0.1.0/trustmcp.egg-info/SOURCES.txt +28 -0
- trustmcp-0.1.0/trustmcp.egg-info/dependency_links.txt +1 -0
- trustmcp-0.1.0/trustmcp.egg-info/entry_points.txt +2 -0
- trustmcp-0.1.0/trustmcp.egg-info/requires.txt +6 -0
- trustmcp-0.1.0/trustmcp.egg-info/top_level.txt +1 -0
trustmcp-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 v0idw4lker
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
trustmcp-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: trustmcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Security scanner for MCP (Model Context Protocol) servers: static (SAST), dynamic (live), and authentication-posture analysis, with an A-F score and SARIF output for the GitHub Security tab.
|
|
5
|
+
Author: v0idw4lker
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/v0idw4lker/trustmcp
|
|
8
|
+
Project-URL: Repository, https://github.com/v0idw4lker/trustmcp
|
|
9
|
+
Project-URL: Issues, https://github.com/v0idw4lker/trustmcp/issues
|
|
10
|
+
Keywords: mcp,model-context-protocol,security,sast,ai-security,sarif
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: Information Technology
|
|
14
|
+
Classifier: Topic :: Security
|
|
15
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: rich>=13.7.0
|
|
28
|
+
Requires-Dist: httpx>=0.28.1
|
|
29
|
+
Requires-Dist: mcp[cli]<3.0.0,>=2.0.0
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
|
|
34
|
+
# trustmcp
|
|
35
|
+
|
|
36
|
+
**Security scanner for MCP (Model Context Protocol) servers** — the protocol through which AI agents (Claude, ChatGPT, Cursor, etc.) connect to external tools.
|
|
37
|
+
|
|
38
|
+
Given an MCP server (source code, a running server, or both), `trustmcp` produces a vulnerability report and an **A–F** score, natively integrated into the **GitHub Security tab** via SARIF.
|
|
39
|
+
|
|
40
|
+
Interested in the premium tier (semantic analysis, cross-server toxic-flow, continuous monitoring)? Join the waitlist at [mcp-scanner.netlify.app](https://mcp-scanner.netlify.app).
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
Grade: F Score: 45/100
|
|
44
|
+
Total findings across all modules: 12
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## ✅ Prerequisites
|
|
50
|
+
|
|
51
|
+
New to the command line? You'll need three things: [Python 3.10 or newer](https://www.python.org/downloads/) installed on your computer; a terminal open (**Command Prompt** or **PowerShell** on Windows, **Terminal** on Mac); and that terminal pointed at the folder containing the MCP server code you want to scan — use the `cd` command to get there, e.g. `cd path/to/my-mcp-server`.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## ⚡ Quick Installation
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# Direct execution without installation (recommended)
|
|
59
|
+
uvx trustmcp@latest scan --path . --mode static
|
|
60
|
+
|
|
61
|
+
# Or permanent installation
|
|
62
|
+
pip install trustmcp
|
|
63
|
+
trustmcp scan --path . --mode static
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Static scan only** (source code, no running server required):
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
trustmcp scan --path ./my-mcp-server --mode static
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Full scan** (static + live dynamic analysis + auth posture + unified score + SARIF):
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
trustmcp scan --path ./my-mcp-server --mode both \
|
|
76
|
+
--target "stdio:python3 server.py" \
|
|
77
|
+
--target "url:http://127.0.0.1:8931/mcp"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Outputs: a color-coded console report (via `rich`), `mcp-scan-report.json`, and `mcp-scan-report.sarif` — drop the SARIF file into CI and it automatically appears in the **Security → Code scanning** tab of your repository.
|
|
81
|
+
|
|
82
|
+
| Flag | What it does |
|
|
83
|
+
| ----------------- | -------------------------------------------------------------------------------------- |
|
|
84
|
+
| `--path` | Directory to statically scan and to search for auth-posture evidence (default `.`) |
|
|
85
|
+
| `--mode` | `static`, `dynamic`, or `both` (default `both`) |
|
|
86
|
+
| `--target` | Live MCP server to scan dynamically. Repeatable. `stdio:<command>` or `url:<url>` |
|
|
87
|
+
| `--no-fuzz` | Disables tool input fuzzing during dynamic analysis |
|
|
88
|
+
| `--json-output` | Path for the JSON report (default `mcp-scan-report.json`) |
|
|
89
|
+
| `--no-json` | Do not write a JSON report |
|
|
90
|
+
| `--sarif-output` | Path for the SARIF report (default `mcp-scan-report.sarif`) |
|
|
91
|
+
| `--no-sarif` | Do not write a SARIF report |
|
|
92
|
+
| `--fail-on` | Exit non-zero if a finding at/above this severity exists — `low`/`medium`/`high`/`critical` (CI gating) |
|
|
93
|
+
| `-v`, `--verbose` | Verbose logging |
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## 🎯 What It Detects
|
|
98
|
+
|
|
99
|
+
Four modules, all included in the free tier and always combined into a single score.
|
|
100
|
+
|
|
101
|
+
| Module | What it checks |
|
|
102
|
+
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
103
|
+
| **Static** (source code) | `eval`/`exec`, `os.system`/`os.popen`, `subprocess(shell=True)`, unsafe `pickle`/`yaml.load`, path traversal, hardcoded secrets (OpenAI, Anthropic, GitHub, AWS, Stripe, Google, Slack, PEM keys), hidden/obfuscated Unicode (zero-width, bidi-control, and Unicode Tag "ASCII smuggling" characters), MCP config exposed on `0.0.0.0`, unpinned or known-vulnerable dependencies (`requirements.txt` and `package.json`) |
|
|
104
|
+
| **Dynamic** (live server) | Tool/resource/prompt enumeration, authentication enforcement (401/403 vs. 200), TLS/HSTS for remote servers, live description drift vs. source code, and **input fuzzing** — malformed payloads sent to every discovered tool to catch crashes and stack-trace/error leakage |
|
|
105
|
+
| **Auth posture** | Detects whether a server appears to implement OAuth 2.1, a static API key, or an environment-variable token — and flags weak or missing mechanisms |
|
|
106
|
+
| **Scoring** | A–F grade, with findings explicitly mapped to the **OWASP MCP Top 10** |
|
|
107
|
+
|
|
108
|
+
### OWASP MCP Top 10 Coverage
|
|
109
|
+
|
|
110
|
+
`trustmcp` maps findings to official categories rather than inventing its own taxonomy:
|
|
111
|
+
|
|
112
|
+
- `MCP01:2025` Token Mismanagement & Secret Exposure
|
|
113
|
+
- `MCP02:2025` Privilege Escalation via Scope Creep
|
|
114
|
+
- `MCP03:2025` Tool Poisoning
|
|
115
|
+
- `MCP04:2025` Software Supply Chain Attacks & Dependency Tampering
|
|
116
|
+
- `MCP05:2025` Command Injection & Execution
|
|
117
|
+
- `MCP07:2025` Insufficient Authentication & Authorization
|
|
118
|
+
- `MCP10:2025` Context Injection & Over-Sharing
|
|
119
|
+
|
|
120
|
+
Findings without a clear match are **not** forced into a category — see [`trustmcp/core/scoring.py`](trustmcp/core/scoring.py).
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## 🔬 Honesty Over Marketing
|
|
125
|
+
|
|
126
|
+
> The `confidence` field on every finding is a heuristic per-rule prior (how specific/unambiguous the signature is) — **not** a statistically measured false-positive rate. Empirical calibration against known-vulnerable and clean MCP servers was run 2026-08-19 — see [Validation](#-validation-dvmcp-benchmark-2026-08-19) below.
|
|
127
|
+
|
|
128
|
+
The dependency-vulnerability list is a small, hand-curated set of notorious CVEs, checked entirely offline — it is **not** a substitute for `pip-audit`, `npm audit`, or [OSV.dev](https://osv.dev), which trustmcp does not call out to by design (no network dependency for a security tool's core scan).
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## 📊 Validation: DVMCP Benchmark (2026-08-19)
|
|
133
|
+
|
|
134
|
+
Run against [Damn Vulnerable MCP Server](https://github.com/harishsg993010/damn-vulnerable-MCP-server) (DVMCP), built and run via its own Docker instructions (`docker build -t dvmcp .` / `docker run -p 9001-9010:9001-9010 dvmcp`), plus 3 clean official [`modelcontextprotocol/python-sdk`](https://github.com/modelcontextprotocol/python-sdk) example servers for false positives. Full methodology, caveats, and per-challenge evidence below — numbers are exact, not rounded up.
|
|
135
|
+
|
|
136
|
+
**Headline:**
|
|
137
|
+
|
|
138
|
+
- **Canonical DVMCP challenges (documented vulnerability, `server.py`, matches `docs/challenges.md`): 3/10 fully detected, 1/10 partially detected, 6/10 missed.**
|
|
139
|
+
- **As-deployed Docker containers (`server_sse.py`, what `docker run` on ports 9001-9010 actually serves): 4/10 detected (2 off-label — see caveat), 6/10 missed.**
|
|
140
|
+
- **False positives: 0/3 clean servers** (after a scanner bug found and fixed during this run — see below). All 3 also triggered a generic "no authentication mechanism" HIGH finding, which is accurate but fires on any unauthenticated local stdio server regardless of context — not counted as a false positive, but worth knowing it inflates finding counts for local dev/example servers.
|
|
141
|
+
|
|
142
|
+
**Important caveat discovered during this run:** DVMCP's own repo has two independent implementations of most challenges — `server.py` (matches the documented vulnerability class in `docs/challenges.md`) and `server_sse.py` (what the official Docker image actually runs on ports 9001-9010). On 6 of 10 challenges these diverge, sometimes completely — e.g. the live "Tool Poisoning" container (port 9002) contains no hidden tool-description instructions at all; it's a command-injection/path-traversal server instead. Both variants are reported below, labeled separately, so neither number is cherry-picked.
|
|
143
|
+
|
|
144
|
+
**Two upstream DVMCP bugs had to be worked around to get it running at all**, unrelated to trustmcp: `requirements.txt` pins `mcp[cli]>=0.5.0` unpinned, which today resolves to `mcp==2.0.0` — a version that removed `mcp.server.fastmcp`, so every challenge server crash-loops out of the box (fixed locally by pinning `<2.0.0`, which resolved to `1.29.0`). Challenge 5's canonical `server.py` additionally calls `FastMCP.resource(..., listed=False)`, a kwarg that doesn't exist in any current SDK version — it cannot start at all, on any modern `mcp` release. Since DVMCP ships only HTTP entrypoints (legacy SSE or raw uvicorn) and trustmcp's dynamic client only speaks Streamable HTTP (not legacy SSE), each challenge was instead driven over **stdio** by importing its `FastMCP`/`Challenge<N>Server` object directly and calling `.run(transport="stdio")` — same tool/resource/prompt logic, different wire transport only.
|
|
145
|
+
|
|
146
|
+
**Per-challenge results:**
|
|
147
|
+
|
|
148
|
+
| # | Challenge | Canonical (`server.py`) | Deployed Docker (`server_sse.py`, port 900*N*) |
|
|
149
|
+
|---|---|---|---|
|
|
150
|
+
| 1 | Basic Prompt Injection | ❌ Miss — no finding relates to the unsanitized `notes://{user_id}` reflection | ❌ Miss — identical implementation to canonical |
|
|
151
|
+
| 2 | Tool Poisoning | ❌ Miss — hidden `<IMPORTANT>`/`<HIDDEN>` instructions in tool descriptions are plain ASCII text; not caught by the hidden-*Unicode* check or any static rule (semantic/LLM analysis is paid-tier only) | ⚠️ Off-label hit — CRITICAL `subprocess-shell-true` (MCP05) + MEDIUM `path-traversal-open-param` (MCP05), but the deployed container replaces tool poisoning with command injection + arbitrary file read entirely; it does not exercise the named vulnerability |
|
|
152
|
+
| 3 | Excessive Permission Scope | ✅ Hit — 2× MEDIUM `path-traversal-open-param` (MCP05), directly on `read_file`/`search_files`' unrestricted `open()` | ✅ Hit — same pattern, same file-access tools |
|
|
153
|
+
| 4 | Rug Pull Attack | ❌ Miss — the `__doc__` mutation after 3 calls (the actual rug-pull mechanism) is not detected; the one CRITICAL `secret-aws-key` (MCP01) finding is an unrelated, incidental hardcoded key elsewhere in the file | ❌ Miss — 0 findings beyond generic auth; deployed variant strips out the secret text and the mutation logic |
|
|
154
|
+
| 5 | Tool Shadowing | ❌ Miss — dynamic scan couldn't connect (`server.py` itself crashes on the `listed=False` bug above, unrelated to trustmcp); static analysis caught real but unrelated issues (4× CRITICAL `dangerous-eval-exec`, 2× CRITICAL `secret-stripe-key`, both MCP05/MCP01) elsewhere in the file, not the name-collision shadowing mechanism | ❌ Miss — only a MEDIUM `dynamic.fuzz-timeout` on `get_user_roles`; the deployed variant is a different role-check server, not the shadowing calculators |
|
|
155
|
+
| 6 | Indirect Prompt Injection | ❌ Miss — no finding relates to unsanitized external/document data | ❌ Miss — same |
|
|
156
|
+
| 7 | Token Theft | ❌ Miss — tokens are hardcoded JWTs and custom-prefixed API keys (`epro_api_...`, `cbx_api_...`); none match the scanner's curated secret-regex list (OpenAI/Anthropic/GitHub/AWS/Stripe/Google/Slack/PEM) | ❌ Miss — same reason, different tool names |
|
|
157
|
+
| 8 | Malicious Code Execution | ✅ Hit — CRITICAL `subprocess-shell-true` (MCP05) on `execute_shell_command` + MEDIUM `path-traversal-open-param` (MCP05) on `analyze_log_file` | ✅ Hit — CRITICAL `dangerous-eval-exec` (MCP05); deployed variant's `evaluate_expression` calls `eval()` directly |
|
|
158
|
+
| 9 | Remote Access Control | ✅ Hit — 4× CRITICAL `subprocess-shell-true` (MCP05) across the network-diagnostic tools | ❌ Miss — deployed variant replaced the shell-exec tools with a broken-auth-token-check simulation (`if auth_token:` truthy check, no shell calls at all); a real but different, logic-level flaw the scanner can't reach with regex/AST rules |
|
|
159
|
+
| 10 | Multi-Vector Attack | ⚠️ Partial — 2 of 5 explicitly chained vulnerabilities caught (CRITICAL `subprocess-shell-true`, MEDIUM `path-traversal-open-param`, both MCP05); missed: token leakage in tool output, poisoned tool description, and tool-name shadowing | ⚠️ Off-label hit — 2× MEDIUM `path-traversal-open-param` (MCP05) on `get_config`; the deployed variant only implements one vulnerability (file read), not an actual multi-vector chain |
|
|
160
|
+
|
|
161
|
+
*(Every finding above also produced a generic HIGH `auth.no-mechanism-detected` (MCP07) — omitted from each cell for brevity; it fired on all 10 challenges both ways.)*
|
|
162
|
+
|
|
163
|
+
**False-positive testing:** ran full `--mode both` scans (static + stdio dynamic, fuzzing on) against 3 clean servers from the official SDK's `examples/` — `mcpserver/simple_echo.py`, `servers/simple-prompt`, `servers/simple-pagination`. Static analysis: 0 findings on all 3 (no false secret/eval/subprocess/traversal/Unicode matches). Dynamic analysis: while testing `simple-prompt` (a prompts-only server with no `tools`/`resources` capability), a real trustmcp bug surfaced — `dynamic_client.py`'s `_enumerate_session()` called `list_tools()`/`list_resources()`/`list_prompts()` unconditionally with no per-call exception handling, so a server correctly declining an unsupported capability (JSON-RPC "Method not found") was misreported as a HIGH-severity connection failure. **Fixed** in this session (`_list_capability()` now catches `MCPError` with code `METHOD_NOT_FOUND` per call and records it as a passed check, not a finding); all 3 clean servers now correctly show 0 vulnerability findings.
|
|
164
|
+
|
|
165
|
+
**Known limitation this run confirms:** the free tier has no semantic/LLM analysis, so any vulnerability that lives entirely in plausible-sounding natural-language tool-description text (tool poisoning, rug-pull description mutation, indirect prompt injection) is structurally invisible to it — that's exactly what the paid semantic module (see Enterprise tier below) is for. Regex-based secret detection also has a fixed pattern list; JWTs and custom-prefixed API keys outside that list won't be caught.
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## 🏢 Enterprise / SaaS Tier
|
|
170
|
+
|
|
171
|
+
Everything above is free, open source, and stays that way. It's a genuinely complete scanner on its own — static analysis, live dynamic probing with input fuzzing, authentication posture, unified scoring, and SARIF/JSON reporting.
|
|
172
|
+
|
|
173
|
+
The paid tier builds on top of it with capabilities that go beyond what a single, stateless scan can offer:
|
|
174
|
+
|
|
175
|
+
- **Semantic (LLM) analysis** — sends every tool/resource/prompt description to an LLM with a strict, conservatively calibrated rubric to catch what regex cannot: naturally phrased hidden instructions, ambiguous scope, and language attempting to dictate model behavior.
|
|
176
|
+
- **Cross-server toxic-flow detection** — real AI agents connect multiple MCP servers simultaneously; a file-reading server plus a network-calling server can form an exfiltration channel even though each looks harmless alone. Single-server scans, by definition, cannot see this.
|
|
177
|
+
- **Continuous monitoring** — a one-time scan cannot catch a *rug pull*: a server that passes review cleanly, then changes its tool descriptions or scope after gaining trust. This requires fingerprinting + a saved baseline + drift alerting across scans over time.
|
|
178
|
+
- API access for CI/CD integration beyond static SARIF, and a verified, embeddable README badge for MCP registries.
|
|
179
|
+
|
|
180
|
+
The free tier's `trustmcp/core/plugins.py` defines the extension point these capabilities plug into — the architecture already supports them; they are simply not distributed in this open-source package.
|
|
181
|
+
|
|
182
|
+
📩 Interested in early access? Open an [issue](https://github.com/v0idw4lker/trustmcp/issues) or contact [@v0idw4lker](https://github.com/v0idw4lker).
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## 🧪 Quick Testing
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
git clone https://github.com/v0idw4lker/trustmcp
|
|
190
|
+
cd trustmcp
|
|
191
|
+
pip install -r requirements.txt
|
|
192
|
+
|
|
193
|
+
# Static scan on this repo itself (fixtures/ is intentionally vulnerable)
|
|
194
|
+
trustmcp scan --path . --mode static
|
|
195
|
+
|
|
196
|
+
# Full pipeline against a fixture server
|
|
197
|
+
trustmcp scan --path . --mode both --target "stdio:python3 fixtures/target_server_stdio.py"
|
|
198
|
+
|
|
199
|
+
# Two fixture servers at once — a good demo of live multi-target scanning
|
|
200
|
+
trustmcp scan --path . --mode both \
|
|
201
|
+
--target "stdio:python3 fixtures/vulnerable_server_a.py" \
|
|
202
|
+
--target "stdio:python3 fixtures/vulnerable_server_b.py"
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Running the test suite
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
pip install -e ".[dev]"
|
|
209
|
+
pytest
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## 🗺️ Roadmap
|
|
215
|
+
|
|
216
|
+
- [x] Published detection-rate + false-positive-rate validation against known-vulnerable and clean MCP server benchmarks — see [Validation](#-validation-dvmcp-benchmark-2026-08-19) (2026-08-19)
|
|
217
|
+
- [ ] Complete OAuth 2.1 flow for authenticated dynamic scanning
|
|
218
|
+
- [ ] Semantic analysis, cross-server toxic-flow, and continuous monitoring (paid tier)
|
|
219
|
+
- [ ] Listing on `awesome-mcp-security` and official MCP registries
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Project Structure
|
|
224
|
+
|
|
225
|
+
```
|
|
226
|
+
trustmcp/
|
|
227
|
+
├── trustmcp/ # installable package — the free tier
|
|
228
|
+
│ ├── cli.py # entrypoint: `trustmcp scan --path ... --mode both`
|
|
229
|
+
│ ├── core/
|
|
230
|
+
│ │ ├── models.py # shared Finding contract used by every module + reporter
|
|
231
|
+
│ │ ├── text_safety.py # hidden/obfuscated Unicode detection (shared static + dynamic)
|
|
232
|
+
│ │ ├── static_analyzer.py # AST/regex SAST, secrets, dependency auditing
|
|
233
|
+
│ │ ├── dynamic_client.py # live MCP client — stdio/HTTP, enumeration, TLS/auth, fuzzing
|
|
234
|
+
│ │ ├── auth_posture.py # OAuth 2.1 / static key / env-var token detection
|
|
235
|
+
│ │ ├── scoring.py # A-F scoring engine + OWASP MCP Top 10 mapping
|
|
236
|
+
│ │ └── plugins.py # extension point for premium modules (unused in the free tier)
|
|
237
|
+
│ ├── reporters/
|
|
238
|
+
│ │ ├── cli_reporter.py # color-coded terminal report
|
|
239
|
+
│ │ ├── json_reporter.py # structured JSON for CI/CD
|
|
240
|
+
│ │ └── sarif_reporter.py # SARIF 2.1.0 export for GitHub Security
|
|
241
|
+
│ └── utils/ # logging + exception hierarchy
|
|
242
|
+
├── fixtures/ # intentionally vulnerable test MCP servers
|
|
243
|
+
├── tests/ # pytest suite + clean/vulnerable fixture modules
|
|
244
|
+
└── premium/ # LOCAL ONLY, gitignored — see "Enterprise / SaaS Tier" above
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## License
|
|
250
|
+
|
|
251
|
+
MIT — see [LICENSE](LICENSE).
|
|
252
|
+
|
|
253
|
+
Built by [@v0idw4lker](https://github.com/v0idw4lker).
|
trustmcp-0.1.0/README.md
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# trustmcp
|
|
2
|
+
|
|
3
|
+
**Security scanner for MCP (Model Context Protocol) servers** — the protocol through which AI agents (Claude, ChatGPT, Cursor, etc.) connect to external tools.
|
|
4
|
+
|
|
5
|
+
Given an MCP server (source code, a running server, or both), `trustmcp` produces a vulnerability report and an **A–F** score, natively integrated into the **GitHub Security tab** via SARIF.
|
|
6
|
+
|
|
7
|
+
Interested in the premium tier (semantic analysis, cross-server toxic-flow, continuous monitoring)? Join the waitlist at [mcp-scanner.netlify.app](https://mcp-scanner.netlify.app).
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
Grade: F Score: 45/100
|
|
11
|
+
Total findings across all modules: 12
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## ✅ Prerequisites
|
|
17
|
+
|
|
18
|
+
New to the command line? You'll need three things: [Python 3.10 or newer](https://www.python.org/downloads/) installed on your computer; a terminal open (**Command Prompt** or **PowerShell** on Windows, **Terminal** on Mac); and that terminal pointed at the folder containing the MCP server code you want to scan — use the `cd` command to get there, e.g. `cd path/to/my-mcp-server`.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## ⚡ Quick Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# Direct execution without installation (recommended)
|
|
26
|
+
uvx trustmcp@latest scan --path . --mode static
|
|
27
|
+
|
|
28
|
+
# Or permanent installation
|
|
29
|
+
pip install trustmcp
|
|
30
|
+
trustmcp scan --path . --mode static
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Static scan only** (source code, no running server required):
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
trustmcp scan --path ./my-mcp-server --mode static
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Full scan** (static + live dynamic analysis + auth posture + unified score + SARIF):
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
trustmcp scan --path ./my-mcp-server --mode both \
|
|
43
|
+
--target "stdio:python3 server.py" \
|
|
44
|
+
--target "url:http://127.0.0.1:8931/mcp"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Outputs: a color-coded console report (via `rich`), `mcp-scan-report.json`, and `mcp-scan-report.sarif` — drop the SARIF file into CI and it automatically appears in the **Security → Code scanning** tab of your repository.
|
|
48
|
+
|
|
49
|
+
| Flag | What it does |
|
|
50
|
+
| ----------------- | -------------------------------------------------------------------------------------- |
|
|
51
|
+
| `--path` | Directory to statically scan and to search for auth-posture evidence (default `.`) |
|
|
52
|
+
| `--mode` | `static`, `dynamic`, or `both` (default `both`) |
|
|
53
|
+
| `--target` | Live MCP server to scan dynamically. Repeatable. `stdio:<command>` or `url:<url>` |
|
|
54
|
+
| `--no-fuzz` | Disables tool input fuzzing during dynamic analysis |
|
|
55
|
+
| `--json-output` | Path for the JSON report (default `mcp-scan-report.json`) |
|
|
56
|
+
| `--no-json` | Do not write a JSON report |
|
|
57
|
+
| `--sarif-output` | Path for the SARIF report (default `mcp-scan-report.sarif`) |
|
|
58
|
+
| `--no-sarif` | Do not write a SARIF report |
|
|
59
|
+
| `--fail-on` | Exit non-zero if a finding at/above this severity exists — `low`/`medium`/`high`/`critical` (CI gating) |
|
|
60
|
+
| `-v`, `--verbose` | Verbose logging |
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## 🎯 What It Detects
|
|
65
|
+
|
|
66
|
+
Four modules, all included in the free tier and always combined into a single score.
|
|
67
|
+
|
|
68
|
+
| Module | What it checks |
|
|
69
|
+
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
70
|
+
| **Static** (source code) | `eval`/`exec`, `os.system`/`os.popen`, `subprocess(shell=True)`, unsafe `pickle`/`yaml.load`, path traversal, hardcoded secrets (OpenAI, Anthropic, GitHub, AWS, Stripe, Google, Slack, PEM keys), hidden/obfuscated Unicode (zero-width, bidi-control, and Unicode Tag "ASCII smuggling" characters), MCP config exposed on `0.0.0.0`, unpinned or known-vulnerable dependencies (`requirements.txt` and `package.json`) |
|
|
71
|
+
| **Dynamic** (live server) | Tool/resource/prompt enumeration, authentication enforcement (401/403 vs. 200), TLS/HSTS for remote servers, live description drift vs. source code, and **input fuzzing** — malformed payloads sent to every discovered tool to catch crashes and stack-trace/error leakage |
|
|
72
|
+
| **Auth posture** | Detects whether a server appears to implement OAuth 2.1, a static API key, or an environment-variable token — and flags weak or missing mechanisms |
|
|
73
|
+
| **Scoring** | A–F grade, with findings explicitly mapped to the **OWASP MCP Top 10** |
|
|
74
|
+
|
|
75
|
+
### OWASP MCP Top 10 Coverage
|
|
76
|
+
|
|
77
|
+
`trustmcp` maps findings to official categories rather than inventing its own taxonomy:
|
|
78
|
+
|
|
79
|
+
- `MCP01:2025` Token Mismanagement & Secret Exposure
|
|
80
|
+
- `MCP02:2025` Privilege Escalation via Scope Creep
|
|
81
|
+
- `MCP03:2025` Tool Poisoning
|
|
82
|
+
- `MCP04:2025` Software Supply Chain Attacks & Dependency Tampering
|
|
83
|
+
- `MCP05:2025` Command Injection & Execution
|
|
84
|
+
- `MCP07:2025` Insufficient Authentication & Authorization
|
|
85
|
+
- `MCP10:2025` Context Injection & Over-Sharing
|
|
86
|
+
|
|
87
|
+
Findings without a clear match are **not** forced into a category — see [`trustmcp/core/scoring.py`](trustmcp/core/scoring.py).
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## 🔬 Honesty Over Marketing
|
|
92
|
+
|
|
93
|
+
> The `confidence` field on every finding is a heuristic per-rule prior (how specific/unambiguous the signature is) — **not** a statistically measured false-positive rate. Empirical calibration against known-vulnerable and clean MCP servers was run 2026-08-19 — see [Validation](#-validation-dvmcp-benchmark-2026-08-19) below.
|
|
94
|
+
|
|
95
|
+
The dependency-vulnerability list is a small, hand-curated set of notorious CVEs, checked entirely offline — it is **not** a substitute for `pip-audit`, `npm audit`, or [OSV.dev](https://osv.dev), which trustmcp does not call out to by design (no network dependency for a security tool's core scan).
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## 📊 Validation: DVMCP Benchmark (2026-08-19)
|
|
100
|
+
|
|
101
|
+
Run against [Damn Vulnerable MCP Server](https://github.com/harishsg993010/damn-vulnerable-MCP-server) (DVMCP), built and run via its own Docker instructions (`docker build -t dvmcp .` / `docker run -p 9001-9010:9001-9010 dvmcp`), plus 3 clean official [`modelcontextprotocol/python-sdk`](https://github.com/modelcontextprotocol/python-sdk) example servers for false positives. Full methodology, caveats, and per-challenge evidence below — numbers are exact, not rounded up.
|
|
102
|
+
|
|
103
|
+
**Headline:**
|
|
104
|
+
|
|
105
|
+
- **Canonical DVMCP challenges (documented vulnerability, `server.py`, matches `docs/challenges.md`): 3/10 fully detected, 1/10 partially detected, 6/10 missed.**
|
|
106
|
+
- **As-deployed Docker containers (`server_sse.py`, what `docker run` on ports 9001-9010 actually serves): 4/10 detected (2 off-label — see caveat), 6/10 missed.**
|
|
107
|
+
- **False positives: 0/3 clean servers** (after a scanner bug found and fixed during this run — see below). All 3 also triggered a generic "no authentication mechanism" HIGH finding, which is accurate but fires on any unauthenticated local stdio server regardless of context — not counted as a false positive, but worth knowing it inflates finding counts for local dev/example servers.
|
|
108
|
+
|
|
109
|
+
**Important caveat discovered during this run:** DVMCP's own repo has two independent implementations of most challenges — `server.py` (matches the documented vulnerability class in `docs/challenges.md`) and `server_sse.py` (what the official Docker image actually runs on ports 9001-9010). On 6 of 10 challenges these diverge, sometimes completely — e.g. the live "Tool Poisoning" container (port 9002) contains no hidden tool-description instructions at all; it's a command-injection/path-traversal server instead. Both variants are reported below, labeled separately, so neither number is cherry-picked.
|
|
110
|
+
|
|
111
|
+
**Two upstream DVMCP bugs had to be worked around to get it running at all**, unrelated to trustmcp: `requirements.txt` pins `mcp[cli]>=0.5.0` unpinned, which today resolves to `mcp==2.0.0` — a version that removed `mcp.server.fastmcp`, so every challenge server crash-loops out of the box (fixed locally by pinning `<2.0.0`, which resolved to `1.29.0`). Challenge 5's canonical `server.py` additionally calls `FastMCP.resource(..., listed=False)`, a kwarg that doesn't exist in any current SDK version — it cannot start at all, on any modern `mcp` release. Since DVMCP ships only HTTP entrypoints (legacy SSE or raw uvicorn) and trustmcp's dynamic client only speaks Streamable HTTP (not legacy SSE), each challenge was instead driven over **stdio** by importing its `FastMCP`/`Challenge<N>Server` object directly and calling `.run(transport="stdio")` — same tool/resource/prompt logic, different wire transport only.
|
|
112
|
+
|
|
113
|
+
**Per-challenge results:**
|
|
114
|
+
|
|
115
|
+
| # | Challenge | Canonical (`server.py`) | Deployed Docker (`server_sse.py`, port 900*N*) |
|
|
116
|
+
|---|---|---|---|
|
|
117
|
+
| 1 | Basic Prompt Injection | ❌ Miss — no finding relates to the unsanitized `notes://{user_id}` reflection | ❌ Miss — identical implementation to canonical |
|
|
118
|
+
| 2 | Tool Poisoning | ❌ Miss — hidden `<IMPORTANT>`/`<HIDDEN>` instructions in tool descriptions are plain ASCII text; not caught by the hidden-*Unicode* check or any static rule (semantic/LLM analysis is paid-tier only) | ⚠️ Off-label hit — CRITICAL `subprocess-shell-true` (MCP05) + MEDIUM `path-traversal-open-param` (MCP05), but the deployed container replaces tool poisoning with command injection + arbitrary file read entirely; it does not exercise the named vulnerability |
|
|
119
|
+
| 3 | Excessive Permission Scope | ✅ Hit — 2× MEDIUM `path-traversal-open-param` (MCP05), directly on `read_file`/`search_files`' unrestricted `open()` | ✅ Hit — same pattern, same file-access tools |
|
|
120
|
+
| 4 | Rug Pull Attack | ❌ Miss — the `__doc__` mutation after 3 calls (the actual rug-pull mechanism) is not detected; the one CRITICAL `secret-aws-key` (MCP01) finding is an unrelated, incidental hardcoded key elsewhere in the file | ❌ Miss — 0 findings beyond generic auth; deployed variant strips out the secret text and the mutation logic |
|
|
121
|
+
| 5 | Tool Shadowing | ❌ Miss — dynamic scan couldn't connect (`server.py` itself crashes on the `listed=False` bug above, unrelated to trustmcp); static analysis caught real but unrelated issues (4× CRITICAL `dangerous-eval-exec`, 2× CRITICAL `secret-stripe-key`, both MCP05/MCP01) elsewhere in the file, not the name-collision shadowing mechanism | ❌ Miss — only a MEDIUM `dynamic.fuzz-timeout` on `get_user_roles`; the deployed variant is a different role-check server, not the shadowing calculators |
|
|
122
|
+
| 6 | Indirect Prompt Injection | ❌ Miss — no finding relates to unsanitized external/document data | ❌ Miss — same |
|
|
123
|
+
| 7 | Token Theft | ❌ Miss — tokens are hardcoded JWTs and custom-prefixed API keys (`epro_api_...`, `cbx_api_...`); none match the scanner's curated secret-regex list (OpenAI/Anthropic/GitHub/AWS/Stripe/Google/Slack/PEM) | ❌ Miss — same reason, different tool names |
|
|
124
|
+
| 8 | Malicious Code Execution | ✅ Hit — CRITICAL `subprocess-shell-true` (MCP05) on `execute_shell_command` + MEDIUM `path-traversal-open-param` (MCP05) on `analyze_log_file` | ✅ Hit — CRITICAL `dangerous-eval-exec` (MCP05); deployed variant's `evaluate_expression` calls `eval()` directly |
|
|
125
|
+
| 9 | Remote Access Control | ✅ Hit — 4× CRITICAL `subprocess-shell-true` (MCP05) across the network-diagnostic tools | ❌ Miss — deployed variant replaced the shell-exec tools with a broken-auth-token-check simulation (`if auth_token:` truthy check, no shell calls at all); a real but different, logic-level flaw the scanner can't reach with regex/AST rules |
|
|
126
|
+
| 10 | Multi-Vector Attack | ⚠️ Partial — 2 of 5 explicitly chained vulnerabilities caught (CRITICAL `subprocess-shell-true`, MEDIUM `path-traversal-open-param`, both MCP05); missed: token leakage in tool output, poisoned tool description, and tool-name shadowing | ⚠️ Off-label hit — 2× MEDIUM `path-traversal-open-param` (MCP05) on `get_config`; the deployed variant only implements one vulnerability (file read), not an actual multi-vector chain |
|
|
127
|
+
|
|
128
|
+
*(Every finding above also produced a generic HIGH `auth.no-mechanism-detected` (MCP07) — omitted from each cell for brevity; it fired on all 10 challenges both ways.)*
|
|
129
|
+
|
|
130
|
+
**False-positive testing:** ran full `--mode both` scans (static + stdio dynamic, fuzzing on) against 3 clean servers from the official SDK's `examples/` — `mcpserver/simple_echo.py`, `servers/simple-prompt`, `servers/simple-pagination`. Static analysis: 0 findings on all 3 (no false secret/eval/subprocess/traversal/Unicode matches). Dynamic analysis: while testing `simple-prompt` (a prompts-only server with no `tools`/`resources` capability), a real trustmcp bug surfaced — `dynamic_client.py`'s `_enumerate_session()` called `list_tools()`/`list_resources()`/`list_prompts()` unconditionally with no per-call exception handling, so a server correctly declining an unsupported capability (JSON-RPC "Method not found") was misreported as a HIGH-severity connection failure. **Fixed** in this session (`_list_capability()` now catches `MCPError` with code `METHOD_NOT_FOUND` per call and records it as a passed check, not a finding); all 3 clean servers now correctly show 0 vulnerability findings.
|
|
131
|
+
|
|
132
|
+
**Known limitation this run confirms:** the free tier has no semantic/LLM analysis, so any vulnerability that lives entirely in plausible-sounding natural-language tool-description text (tool poisoning, rug-pull description mutation, indirect prompt injection) is structurally invisible to it — that's exactly what the paid semantic module (see Enterprise tier below) is for. Regex-based secret detection also has a fixed pattern list; JWTs and custom-prefixed API keys outside that list won't be caught.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## 🏢 Enterprise / SaaS Tier
|
|
137
|
+
|
|
138
|
+
Everything above is free, open source, and stays that way. It's a genuinely complete scanner on its own — static analysis, live dynamic probing with input fuzzing, authentication posture, unified scoring, and SARIF/JSON reporting.
|
|
139
|
+
|
|
140
|
+
The paid tier builds on top of it with capabilities that go beyond what a single, stateless scan can offer:
|
|
141
|
+
|
|
142
|
+
- **Semantic (LLM) analysis** — sends every tool/resource/prompt description to an LLM with a strict, conservatively calibrated rubric to catch what regex cannot: naturally phrased hidden instructions, ambiguous scope, and language attempting to dictate model behavior.
|
|
143
|
+
- **Cross-server toxic-flow detection** — real AI agents connect multiple MCP servers simultaneously; a file-reading server plus a network-calling server can form an exfiltration channel even though each looks harmless alone. Single-server scans, by definition, cannot see this.
|
|
144
|
+
- **Continuous monitoring** — a one-time scan cannot catch a *rug pull*: a server that passes review cleanly, then changes its tool descriptions or scope after gaining trust. This requires fingerprinting + a saved baseline + drift alerting across scans over time.
|
|
145
|
+
- API access for CI/CD integration beyond static SARIF, and a verified, embeddable README badge for MCP registries.
|
|
146
|
+
|
|
147
|
+
The free tier's `trustmcp/core/plugins.py` defines the extension point these capabilities plug into — the architecture already supports them; they are simply not distributed in this open-source package.
|
|
148
|
+
|
|
149
|
+
📩 Interested in early access? Open an [issue](https://github.com/v0idw4lker/trustmcp/issues) or contact [@v0idw4lker](https://github.com/v0idw4lker).
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## 🧪 Quick Testing
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
git clone https://github.com/v0idw4lker/trustmcp
|
|
157
|
+
cd trustmcp
|
|
158
|
+
pip install -r requirements.txt
|
|
159
|
+
|
|
160
|
+
# Static scan on this repo itself (fixtures/ is intentionally vulnerable)
|
|
161
|
+
trustmcp scan --path . --mode static
|
|
162
|
+
|
|
163
|
+
# Full pipeline against a fixture server
|
|
164
|
+
trustmcp scan --path . --mode both --target "stdio:python3 fixtures/target_server_stdio.py"
|
|
165
|
+
|
|
166
|
+
# Two fixture servers at once — a good demo of live multi-target scanning
|
|
167
|
+
trustmcp scan --path . --mode both \
|
|
168
|
+
--target "stdio:python3 fixtures/vulnerable_server_a.py" \
|
|
169
|
+
--target "stdio:python3 fixtures/vulnerable_server_b.py"
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Running the test suite
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
pip install -e ".[dev]"
|
|
176
|
+
pytest
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## 🗺️ Roadmap
|
|
182
|
+
|
|
183
|
+
- [x] Published detection-rate + false-positive-rate validation against known-vulnerable and clean MCP server benchmarks — see [Validation](#-validation-dvmcp-benchmark-2026-08-19) (2026-08-19)
|
|
184
|
+
- [ ] Complete OAuth 2.1 flow for authenticated dynamic scanning
|
|
185
|
+
- [ ] Semantic analysis, cross-server toxic-flow, and continuous monitoring (paid tier)
|
|
186
|
+
- [ ] Listing on `awesome-mcp-security` and official MCP registries
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Project Structure
|
|
191
|
+
|
|
192
|
+
```
|
|
193
|
+
trustmcp/
|
|
194
|
+
├── trustmcp/ # installable package — the free tier
|
|
195
|
+
│ ├── cli.py # entrypoint: `trustmcp scan --path ... --mode both`
|
|
196
|
+
│ ├── core/
|
|
197
|
+
│ │ ├── models.py # shared Finding contract used by every module + reporter
|
|
198
|
+
│ │ ├── text_safety.py # hidden/obfuscated Unicode detection (shared static + dynamic)
|
|
199
|
+
│ │ ├── static_analyzer.py # AST/regex SAST, secrets, dependency auditing
|
|
200
|
+
│ │ ├── dynamic_client.py # live MCP client — stdio/HTTP, enumeration, TLS/auth, fuzzing
|
|
201
|
+
│ │ ├── auth_posture.py # OAuth 2.1 / static key / env-var token detection
|
|
202
|
+
│ │ ├── scoring.py # A-F scoring engine + OWASP MCP Top 10 mapping
|
|
203
|
+
│ │ └── plugins.py # extension point for premium modules (unused in the free tier)
|
|
204
|
+
│ ├── reporters/
|
|
205
|
+
│ │ ├── cli_reporter.py # color-coded terminal report
|
|
206
|
+
│ │ ├── json_reporter.py # structured JSON for CI/CD
|
|
207
|
+
│ │ └── sarif_reporter.py # SARIF 2.1.0 export for GitHub Security
|
|
208
|
+
│ └── utils/ # logging + exception hierarchy
|
|
209
|
+
├── fixtures/ # intentionally vulnerable test MCP servers
|
|
210
|
+
├── tests/ # pytest suite + clean/vulnerable fixture modules
|
|
211
|
+
└── premium/ # LOCAL ONLY, gitignored — see "Enterprise / SaaS Tier" above
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## License
|
|
217
|
+
|
|
218
|
+
MIT — see [LICENSE](LICENSE).
|
|
219
|
+
|
|
220
|
+
Built by [@v0idw4lker](https://github.com/v0idw4lker).
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "trustmcp"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Security scanner for MCP (Model Context Protocol) servers: static (SAST), dynamic (live), and authentication-posture analysis, with an A-F score and SARIF output for the GitHub Security tab."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "v0idw4lker" },
|
|
14
|
+
]
|
|
15
|
+
keywords = [
|
|
16
|
+
"mcp",
|
|
17
|
+
"model-context-protocol",
|
|
18
|
+
"security",
|
|
19
|
+
"sast",
|
|
20
|
+
"ai-security",
|
|
21
|
+
"sarif",
|
|
22
|
+
]
|
|
23
|
+
classifiers = [
|
|
24
|
+
"Development Status :: 4 - Beta",
|
|
25
|
+
"Intended Audience :: Developers",
|
|
26
|
+
"Intended Audience :: Information Technology",
|
|
27
|
+
"Topic :: Security",
|
|
28
|
+
"Topic :: Software Development :: Quality Assurance",
|
|
29
|
+
"License :: OSI Approved :: MIT License",
|
|
30
|
+
"Operating System :: OS Independent",
|
|
31
|
+
"Programming Language :: Python :: 3",
|
|
32
|
+
"Programming Language :: Python :: 3.10",
|
|
33
|
+
"Programming Language :: Python :: 3.11",
|
|
34
|
+
"Programming Language :: Python :: 3.12",
|
|
35
|
+
"Programming Language :: Python :: 3.13",
|
|
36
|
+
"Programming Language :: Python :: 3.14",
|
|
37
|
+
]
|
|
38
|
+
dependencies = [
|
|
39
|
+
"rich>=13.7.0",
|
|
40
|
+
"httpx>=0.28.1",
|
|
41
|
+
"mcp[cli]>=2.0.0,<3.0.0",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[project.optional-dependencies]
|
|
45
|
+
dev = ["pytest>=8.0"]
|
|
46
|
+
|
|
47
|
+
[project.urls]
|
|
48
|
+
Homepage = "https://github.com/v0idw4lker/trustmcp"
|
|
49
|
+
Repository = "https://github.com/v0idw4lker/trustmcp"
|
|
50
|
+
Issues = "https://github.com/v0idw4lker/trustmcp/issues"
|
|
51
|
+
|
|
52
|
+
# Installed, the command is `trustmcp` — e.g.:
|
|
53
|
+
# uvx trustmcp@latest scan --path . --mode both --target "stdio:python3 server.py"
|
|
54
|
+
[project.scripts]
|
|
55
|
+
trustmcp = "trustmcp.cli:main"
|
|
56
|
+
|
|
57
|
+
[tool.setuptools.packages.find]
|
|
58
|
+
include = ["trustmcp*"]
|
trustmcp-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""
|
|
2
|
+
trustmcp — security scanner for MCP (Model Context Protocol) servers.
|
|
3
|
+
|
|
4
|
+
Free tier (this package): static (SAST) analysis, live dynamic analysis,
|
|
5
|
+
authentication posture assessment, unified A-F scoring, and CLI/JSON/SARIF
|
|
6
|
+
reporting.
|
|
7
|
+
|
|
8
|
+
Semantic (LLM-based) analysis and cross-server toxic-flow detection are
|
|
9
|
+
premium capabilities reserved for the paid SaaS tier. They are not
|
|
10
|
+
implemented in this package; core.plugins defines the extension point a
|
|
11
|
+
premium module registers against, so the free-tier pipeline can pick them
|
|
12
|
+
up automatically if one is installed locally.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
__version__ = "0.1.0"
|