mcp-sentinel
A security scanner for MCP (Model Context Protocol) servers.
MCP servers are exploding — every agent framework now connects to dozens of
them. Almost none of them get security-reviewed. mcp-sentinel finds the
things that quietly turn a "helpful tool" into an attack surface:
- 🧠 Prompt-injection-prone tool descriptions — phrasing designed to hijack the calling LLM ("ignore previous instructions", hidden invisible unicode, suspiciously long descriptions that smuggle instructions). Checked both in static JSON manifests and in the tool descriptions most servers actually ship: string literals inside their JS/TS/Python source.
- 🔓 Over-broad capabilities — tools that expose shell/exec/arbitrary file
access, or accept unvalidated free-form input (
additionalProperties: true). - 💣 Dangerous code paths in the server implementation —
eval,subprocess(..., shell=True),os.system,pickle.loads, unsafeyaml.load. - 🔑 Hardcoded secrets — API keys, AWS keys, GitHub/Slack tokens baked into source or config instead of environment variables.
- 🌐 Unsafe defaults — binding to
0.0.0.0,trust/skip_authflags left enabled.
Install
pip install mcp-sentinel-cli
(the PyPI distribution is named mcp-sentinel-cli since mcp-sentinel was
already taken; the installed command is still mcp-sentinel)
Or from source:
git clone https://github.com/YashkantG/mcp-sentinel.git
cd mcp-sentinel
pip install -e .
Usage
Scan a server's project directory, a single source file, or a captured
tools/list / mcp.json manifest:
mcp-sentinel scan ./my-mcp-server
mcp-sentinel findings
┌──────────┬──────────────────────────────────┬─────────────────┬────────────────────────────────────────────────┐
│ Severity │ Rule │ Location │ Message │
├──────────┼──────────────────────────────────┼──────────────────┼─────────────────────────────────────────────────┤
│ HIGH │ MCP001 (Prompt-injection...) │ mcp.json │ Tool 'run_shell' description matches... │
│ HIGH │ MCP102 (Shell command built...) │ server.py:8 │ subprocess call with shell=True │
│ HIGH │ MCP201 (Hardcoded secret...) │ mcp.json │ Possible hardcoded secret: AWS Access Key ID │
│ MEDIUM │ MCP301 (Server bound to all...) │ mcp.json │ 'host' binds to all network interfaces │
└──────────┴──────────────────────────────────┴──────────────────┴─────────────────────────────────────────────────┘
11 finding(s) (HIGH: 8 MEDIUM: 3)
Use --format json for machine-readable output (great for CI), and
--fail-on to control what severity trips a non-zero exit code:
mcp-sentinel scan ./my-mcp-server --format json
mcp-sentinel scan ./my-mcp-server --fail-on medium # fail CI on MEDIUM or higher
Scanning real servers
Running mcp-sentinel against the official MCP reference servers
(filesystem, git, fetch, memory, time, sequentialthinking, everything) turns
up genuine, non-hypothetical signal — nothing catastrophic here (these are
well-maintained reference implementations), but exactly the kind of thing
worth a second look before you point an agent at a less scrutinized server:
src/filesystem:
LOW MCP003 'read_text_file' description is longer than typical (457 chars)
MEDIUM MCP004 'list_directory' exposes a broad capability (matched keyword: 'all files')
MEDIUM MCP004 'list_directory_with_sizes' exposes a broad capability (matched keyword: 'all files')
LOW MCP003 'search_files' description is longer than typical (424 chars)
src/sequentialthinking:
MEDIUM MCP003 'sequentialthinking' description is unusually long (2781 chars)
None of these are bugs in those servers — a filesystem tool legitimately needs to describe listing "all files" — but they're exactly the kind of capability/length signal you'd want flagged automatically before granting an agent access to a server you didn't write.
Rules
| ID | Check |
|---|---|
| MCP001 | Prompt-injection phrasing in tool description |
| MCP002 | Hidden/invisible unicode characters in tool description |
| MCP003 | Suspiciously long tool description (payload smuggling risk) |
| MCP004 | Over-broad capability exposed by tool name/description |
| MCP005 | Tool schema accepts arbitrary/unvalidated input |
| MCP101 | Dangerous code execution sink (eval, exec, new Function) |
| MCP102 | Shell command built from untrusted input |
| MCP103 | Unsafe deserialization (pickle.loads, unsafe yaml.load) |
| MCP201 | Hardcoded secret or credential |
| MCP301 | Server bound to all network interfaces |
| MCP302 | Authentication / trust check disabled |
Why this exists
The MCP ecosystem grew faster than its security tooling. A malicious or
careless MCP server can manipulate the LLM that's using it (via crafted tool
descriptions) or simply be a badly-secured piece of software with shell
access. mcp-sentinel is a fast, dependency-light first pass you can run
locally or in CI before trusting a new server.
It's intentionally simple — pattern/regex-based checks rather than a full taint-tracking analyzer — so it's fast, has no false-negative-hiding complexity, and is easy to extend. Contributions adding new rules are very welcome.
Contributing
Issues and PRs welcome — especially new rules, language support (only
Python/JS/TS source checks exist today), and real-world MCP servers to test
against. See the tests/fixtures/ directory for the pattern used to add a
new check with a positive and negative fixture.
License
MIT — see LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mcp_sentinel_cli-0.2.0.tar.gz.
File metadata
- Download URL: mcp_sentinel_cli-0.2.0.tar.gz
- Upload date:
- Size: 16.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8ba345bd60a1ae13c188f95bdff950ddf73a95c7ad5018eaa00a1f84245441ce
|
|
| MD5 |
71a232ec6e0bd4831e1db895da641a41
|
|
| BLAKE2b-256 |
35fcdb3f4b0fc01df9f93fadc4ddaeab1733e9a15b7772b7fd4d2886550fa2e3
|
Provenance
The following attestation bundles were made for mcp_sentinel_cli-0.2.0.tar.gz:
Publisher:
publish.yml on YashkantG/mcp-sentinel
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcp_sentinel_cli-0.2.0.tar.gz -
Subject digest:
8ba345bd60a1ae13c188f95bdff950ddf73a95c7ad5018eaa00a1f84245441ce - Sigstore transparency entry: 2727409063
- Sigstore integration time:
-
Permalink:
YashkantG/mcp-sentinel@05907ea19ba5fb1a1248398638f5b6a7884543df -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/YashkantG
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@05907ea19ba5fb1a1248398638f5b6a7884543df -
Trigger Event:
release
-
Statement type:
File details
Details for the file mcp_sentinel_cli-0.2.0-py3-none-any.whl.
File metadata
- Download URL: mcp_sentinel_cli-0.2.0-py3-none-any.whl
- Upload date:
- Size: 16.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9c18217f2340fa3445ad0f9a67193e7373e1d316d3a0fcab7ddf80d6755af26e
|
|
| MD5 |
dec8658a7e646d9f1ffacdc8bc990bfa
|
|
| BLAKE2b-256 |
eaa781f079d1b218bd0976b6d1f320013c26c32a9a14812faca1a3ac85cfca69
|
Provenance
The following attestation bundles were made for mcp_sentinel_cli-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on YashkantG/mcp-sentinel
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcp_sentinel_cli-0.2.0-py3-none-any.whl -
Subject digest:
9c18217f2340fa3445ad0f9a67193e7373e1d316d3a0fcab7ddf80d6755af26e - Sigstore transparency entry: 2727409809
- Sigstore integration time:
-
Permalink:
YashkantG/mcp-sentinel@05907ea19ba5fb1a1248398638f5b6a7884543df -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/YashkantG
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@05907ea19ba5fb1a1248398638f5b6a7884543df -
Trigger Event:
release
-
Statement type: