Skip to main content

EndpointSweep

Find every MCP server and AI agent on your fleet — before your attacker does.

Nmap + osquery for the agentic AI era: discover every MCP server, agentic CLI and AI integration running across an endpoint fleet, audit each against a published risk rubric, and aggregate the findings into one report — built to run under real EDR/MDM deployment constraints.

PyPI Python CI License: MIT

EndpointSweep auditing a host from the synthetic test fleet

Output is verbatim from testdata/, a fleet of 28 synthetic hosts shipped with the repo. No real hostname, path or credential appears anywhere — by design, there is nothing to redact.


Why this exists

The per-machine MCP scanner niche is crowded and good: MCP-Scan, mcp-audit, MCTS and others all answer "is this laptop's MCP configuration safe?" well.

Nobody answers the enterprise question:

What MCP servers and agentic AI tools exist across my 20,000 endpoints, what can they touch, and which ones violate policy?

That question needs a different shape of tool: tiny collectors that survive real fleet-deployment constraints, and a central analyzer that can compare hosts to each other. Run mcp-audit on one box; run EndpointSweep on ten thousand.

Three findings in this tool cannot exist on a single machine at all:

  • ES-901 — one server name resolving to different commands across the fleet. Every host looks internally consistent; the divergence is the finding.
  • ES-902 — a server on 0.4% of the fleet and on no approved-software list. Rarity is only measurable against a denominator.
  • ES-903 — the census: what is actually deployed, ranked by prevalence.

Install

pipx install endpointsweep     # recommended: isolated, still on your PATH
pip install endpointsweep

Python 3.10+ and the standard library — no runtime dependencies. The collectors have none at all, not even Python: they are plain sh, bash and PowerShell.

Two entry points are installed, endpointsweep and the short alias esweep. This README uses the long form; use whichever you prefer.

Releases are published from CI by PyPI Trusted Publishing — no API token exists for this project — so every artifact carries a PEP 740 attestation naming the repository, commit and workflow that built it:

curl -s https://pypi.org/integrity/endpointsweep/0.1.2/endpointsweep-0.1.2-py3-none-any.whl/provenance \
  | jq '.attestation_bundles[0].publisher'

From source

Needed if you want the synthetic test fleet, or the collectors as loose files to paste into an MDM console:

git clone https://github.com/harish-ravichandra/endpointsweep
cd endpointsweep
pip install -e ".[dev]"

Quick start

One machine (the on-ramp)

endpointsweep scan runs this machine's collector and analyses the result — same output as below, for your own laptop:

$ endpointsweep analyze testdata/hosts/ws-win-1175.json
# EndpointSweep host report — `ws-win-1175`

**Risk score:** 82.5/100 (CRITICAL) · **Max severity:** CRITICAL · **Findings:** 8

**CRITICAL** 1 · **HIGH** 3 · **MEDIUM** 0 · **LOW** 0 · **INFO** 4
...
### CRITICAL (1)

#### ES-201 — Imperative-instruction pattern in MCP tool description (tool poisoning)

**Severity:** CRITICAL · **Vector:** 4 (Local MCP servers)

- **Subject:** `notes:read_file`
- **Detail:** tool description matches 4 injection pattern(s): fake-system-tag,
  conceal-from-user, mandatory-tool-call, tool-ordering-hijack
- **Location:** `C:\Users\morgan\.cursor\mcp.json`
- **OWASP LLM Top 10:** LLM01: Prompt Injection, LLM04: Data and Model Poisoning
- **MITRE ATLAS:** AML.T0051: LLM Prompt Injection, AML.T0053: LLM Plugin Compromise
- **Fix:** Treat the server as compromised until proven otherwise: disable it,
  diff the tool descriptions against the upstream source, and pin the package version.

$ echo $?
1

A fleet

# 1. Push a collector with your MDM/EDR (see deploy/) and collect the JSON.
# 2. Merge and report.
endpointsweep merge collected/ -o fleet.json
endpointsweep report fleet.json -o fleet.md
endpointsweep report fleet.json -f sarif -o fleet.sarif   # into your scanning pipeline
endpointsweep report fleet.json -f html  -o fleet.html    # for the people who want a PDF

Try it on the synthetic fleet

The repo ships 28 synthetic hosts (all invented — no real fleet data, ever). These examples need a checkout, since testdata/ is not part of the wheel:

$ endpointsweep report testdata/hosts --drilldown 0 | head -20
# EndpointSweep fleet report

**Generated:** 2026-09-14T04:00:00+00:00 · **EndpointSweep:** v0.1.2 · **Hosts:** 28

**Fleet risk score:** 38.4/100 (MODERATE)

## Executive summary

**CRITICAL** 3 · **HIGH** 29 · **MEDIUM** 23 · **LOW** 0 · **INFO** 74

| Metric | Value |
|---|---|
| Hosts analysed | 28 |
| Hosts with at least one MCP server | 22 |
| Hosts with an agentic CLI | 21 |
| Hosts with a local model runtime | 5 |
| Total findings | 129 |
| Fleet-level findings | 10 |
| Median host score | 13.3 |
| p95 host score | 80.9 |
| Hosts by band | LOW 14 · MODERATE 4 · ELEVATED 5 · CRITICAL 5 |

The census section is the part people actually read (excerpt, aligned for legibility — the real table is markdown):

### MCP servers by prevalence

| Server              | Hosts | % fleet | Distinct invocations |
|---------------------|-------|---------|----------------------|
| memory              |    15 |   53.6% |                    1 |
| sequential-thinking |    13 |   46.4% |                    1 |
| time                |     9 |   32.1% |                    1 |
| filesystem          |     8 |   28.6% |                    1 |
| internal-docs       |     6 |   21.4% |                    1 |
| github              |     4 |   14.3% |                    1 |
| internal-tools      |     4 |   14.3% |                    3 |  <- ES-901
| …                                                              |
| desktop-commander   |     1 |    3.6% |                    1 |  <- ES-902

How it works

                 endpoint                          central
  ┌──────────────────────────────┐      ┌───────────────────────────────┐
  │ endpointsweep_collect.sh/.bash  │      │  endpointsweep analyze           │
  │ endpointsweep_collect.ps1       │ JSON │    parsers → checks → score   │
  │                              │ ───► │                               │
  │  · MCP client configs        │      │  endpointsweep merge             │
  │  · agentic CLIs, IDE plugins │      │    N hosts → fleet model      │
  │  · model runtimes, manifests │      │    → ES-9xx fleet checks      │
  │  · credential-shaped NAMES   │      │                               │
  │                              │      │  endpointsweep report            │
  │  no deps · root-tolerant     │      │    Markdown · SARIF · HTML    │
  └──────────────────────────────┘      └───────────────────────────────┘

Collectors are tiny and constraint-compliant, because that is the part that has to survive an MDM console. Everything else is central, because that is where it can be tested, reviewed, and changed without touching 20,000 endpoints.

The collector contract

endpointsweep_collect.sh   [OUTPUT_JSON_PATH]   # macOS   — POSIX sh, .sh extension
endpointsweep_collect.bash [OUTPUT_JSON_PATH]   # Linux
endpointsweep_collect.ps1  [OUTPUT_JSON_PATH]   # Windows — PowerShell 5.1
  • With a path: JSON goes to the file, the summary line goes to stdout.
  • Without one: JSON goes to stdout, the summary line goes to stderr.
  • Exit 0 = nothing flagged, 1 = something flagged, 2 = the collector failed.
ENDPOINTSWEEP|ws-mac-1042|9|HIGH

One line, under 500 characters, so it survives a console that truncates stdout — and an exit code, for the consoles that only trust exit codes. See deploy/ for Endpoint Central, Jamf, Intune and ssh recipes.


The red line

EndpointSweep reports variable NAMES and file PATHS. It never reports a value.

This is enforced in four places, not asserted in a README:

  1. The collectors cut each rc-file line at the first = before the name reaches a pipeline, and pass every config file through an embedded JSONC-aware redactor that replaces the value of any env/headers/ credential-shaped key with "[redacted]" before it is written.
  2. The parsers drop the env mapping entirely at the boundary, and strip credential-shaped segments out of remote server URLs.
  3. The schema has no field that can hold a value — MCPServer.env_var_names exists, MCPServer.env does not — and to_json() refuses to serialise any structure containing a forbidden key.
  4. The tests prove it: every schema dataclass is inspected for value-bearing fields, and the Linux collector is executed against a fake home seeded with real-looking secrets, which must not appear in its output.

The collectors also never execute a binary from a user-writable path while running as root — a fleet script that runs ~/.local/bin/claude --version as root is a privilege-escalation primitive, not an inventory tool.


The check catalog

17 checks, each carrying an ID, severity, vector, OWASP LLM Top 10 and MITRE ATLAS mapping, and fix guidance. Full detail in docs/checks.md.

$ endpointsweep checks
ES-101  HIGH     V4 host  MCP server has local command-execution capability
ES-102  HIGH     V4 host  Filesystem MCP server rooted at a filesystem or home directory
ES-103  MEDIUM   V4 host  Network-egress MCP server with unrestricted host scope
ES-104  HIGH     V4 host  MCP server binary runs from a user- or world-writable path
ES-105  MEDIUM   V4 host  MCP server declared in an elevated (root/SYSTEM) scope
ES-201  CRITICAL V4 host  Imperative-instruction pattern in MCP tool description (tool poisoning)
ES-202  MEDIUM   V4 host  Anomalous MCP tool description length, entropy or character mix
ES-301  HIGH     V7 host  MCP server launched from an unpinned package version
ES-302  MEDIUM   V7 host  MCP server package name is a near-miss of a known server (typosquat)
ES-303  MEDIUM   V7 host  MCP server package is very new or has a single maintainer [--online]
ES-401  HIGH     V8 host  Credential-shaped variable names embedded in an MCP server config
ES-402  MEDIUM   V8 host  Credential-shaped variable names in shell rc or .env files
ES-403  LOW      V5 host  Local model runtime listening on a non-loopback interface
ES-404  INFO     V3 host  Shadow-AI inventory (census signal, not an alert)
ES-901  HIGH     V4 fleet Same MCP server name resolves to different commands across the fleet
ES-902  MEDIUM   V4 fleet Long-tail MCP server installed on a small fraction of the fleet
ES-903  INFO     V3 fleet Fleet shadow-AI census

Everything is deterministic and offline by default. Exactly one check (ES-303) makes a network request, and only behind --online.


The rubric

docs/rubric.md is the durable part of this project: a tool-agnostic way to describe enterprise AI exposure that outlives the MCP spec.

  • Eight vectors — browser AI modes, browser AI extensions, agentic AI, local MCP servers, local model runtimes, IDE AI plugins, AI libraries, direct API-key integrations.
  • Six capability axes — execution, filesystem reach, network reach, credential exposure, privilege, provenance & control.
  • A scoring formula you can reproduce by hand, that saturates, with honest coverage reporting: vectors EndpointSweep does not yet collect are shown as gaps, never as clean.

Commands

Command What it does
endpointsweep scan Run this machine's collector, then analyse it
endpointsweep analyze HOST.json... Analyse collector output, one report per host
endpointsweep merge HOSTS/ -o fleet.json N hosts → one scored fleet model
endpointsweep report fleet.json Markdown (default), -f html|sarif|json
endpointsweep checks Print the catalog (-f json for machines)
endpointsweep collector --os macos --print Emit a collector for deployment

esweep is a drop-in alias for endpointsweep on every command above.

Useful flags: --fail-on {none,info,low,medium,high,critical} (default high) for CI exit codes, --managed-software FILE to suppress expected long-tail installs, --rare-threshold to tune ES-902, --online to enable ES-303.


Project layout

collectors/    three self-contained endpoint scripts (the deployable part)
endpointsweep/    parsers → checks → scoring → merge → report
  checks/      one module per family; registry pattern; ES-1xx … ES-9xx
  parsers/     one module per client config shape
  report/      markdown, sarif, html
plugins/       optional: fold mcp-scan / mcp-audit output into the fleet report
testdata/      28 synthetic hosts, config fixtures, golden expectations, SARIF schema
deploy/        Endpoint Central, Jamf, Intune, ssh recipes
docs/          rubric.md (the IP), checks.md (the catalog)

Development

pip install -e ".[dev]"
pytest            # 165 tests, incl. live collector runs and SARIF schema validation
ruff check .
python3 testdata/generate_fleet.py    # regenerate the synthetic fleet
python3 testdata/generate_golden.py   # regenerate golden expectations, then read the diff

Adding a check: docs/checks.md § Adding a check. tests/test_docs.py fails the build if a check is not documented.


Scope

In scope: discovery, audit, aggregation, reporting.

Out of scope, deliberately: runtime proxying and traffic inspection (MCP-Scan owns that lane); LLM-based semantic analysis of tool descriptions (checks stay deterministic); remediation and enforcement (report first, enforce later); and any transmission of secret values, file contents or user documents.

Credits

EndpointSweep stands on work done by others in the open: MCP-Scan for naming tool poisoning and rug pulls, mcp-audit for the OWASP MCP mapping, and MCTS for live tool discovery. They solve the single-machine problem well — plugins/external_scanners.py will fold their output into an EndpointSweep fleet report rather than duplicate it.

Mappings reference the OWASP LLM Top 10 (2025) and MITRE ATLAS.

License

MIT. All test data in this repository is synthetic.

Metadata

Release files for endpointsweep 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for endpointsweep 0.1.2
File Size Uploaded Provenance Actions
endpointsweep-0.1.2.tar.gz 98.0 kB With provenance Details for endpointsweep-0.1.2.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for endpointsweep 0.1.2
File Interpreter ABI Platform Actions
endpointsweep-0.1.2-py3-none-any.whl Python 3 none any Details for endpointsweep-0.1.2-py3-none-any.whl

Total release size: 187.0 kB

Release files / endpointsweep-0.1.2.tar.gz

Download URL endpointsweep-0.1.2.tar.gz
Size 98.0 kB
Tags Source
SHA-256 checksum
How to use checksums
7f6beade766259dd2eecedd1ea6ec285f4245c2e5aad24637f78ab6624c1c0f9
BLAKE2b-256 checksum
How to use checksums
780d2c3aa05c43a4b39223d16f4a0c089d4ba4a5c91dfc2bf311ec7f62509136
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 15, 2026.

Transparency log

Release files / endpointsweep-0.1.2-py3-none-any.whl

Download URL endpointsweep-0.1.2-py3-none-any.whl
Size 89.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
86e11f59381b25302e810e11f567bbf304fc05bbf07e93c1782f6acf37e4eb40
BLAKE2b-256 checksum
How to use checksums
e35db1dc51a3a9fa014542cedb62d938b568a52c85f1d08f86ad9460e4a98e1a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 15, 2026.

Transparency log

Security for endpointsweep 0.1.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for endpointsweep-0.1.2.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 15, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page