A fast Python CLI for MITRE ATT&CK. Designed for coding agents — clean JSON output over stdout, no MCP daemon required.
Project description
mitre-attack-cli
A fast, dependency-light Python CLI for MITRE ATT&CK. Built for coding agents
to invoke through the Bash tool: clean JSON on stdout, useful errors on stderr,
predictable exit codes. No MCP daemon required.
Why
Coding agents that need MITRE ATT&CK knowledge currently rely on MCP servers
(e.g. stoyky/mitre-attack-mcp,
MHaggis/mitre-attack-mcp). An MCP
brings infrastructure — a long-lived process, a transport, an MCP-aware host —
to what is fundamentally a read-only data lookup. This CLI is just a binary on
$PATH, easier to install (uvx mitre-attack-cli ...), easier to use in CI or
sandboxes, and equally agent-friendly: every command returns parseable JSON.
Quickstart
# One-shot via uvx (no install)
uvx mitre-attack-cli technique get T1059.001
# Or install globally
uv tool install mitre-attack-cli
mitre technique get T1059.001
First invocation downloads the ATT&CK Enterprise STIX bundle (~25–45 MB) into
~/.cache/mitre-attack-cli/. Subsequent calls are local.
Output
Default is compact JSON on stdout. Errors are JSON envelopes on stderr.
$ mitre technique get T1059.001
{"attack_id":"T1059.001","name":"PowerShell","tactics":["execution"],"platforms":["Windows"],"is_subtechnique":true}
$ mitre technique get T9999
# stdout: empty
# stderr:
{"error":"Not found: 'T9999' in enterprise@v19.0.","code":"NOT_FOUND","hint":"Try `mitre search T9999` or `mitre update`."}
# exit code: 3
Three formats:
| Flag | Behavior |
|---|---|
--format json (default) |
Compact JSON. Single line per object, single array for lists. |
--format jsonl |
Newline-delimited JSON. Best for piping large lists to jq. |
--pretty (or --format pretty) |
Markdown for objects, table for lists. For humans. |
Exit codes: 0 success · 2 invalid usage · 3 not found · 4 missing data · 5 network · 1 other.
Subcommands
mitre technique get | list | subtechniques | parent | groups-using | software-using
| mitigations | detections | procedures | tactics
mitre tactic get | list | techniques
mitre group get | list | techniques | software | campaigns
mitre software get | list | groups-using | techniques | campaigns
mitre mitigation get | list | techniques
mitre campaign get | list | groups | techniques | software
mitre data-source get | list | components | techniques
mitre search <query> [--type … --regex --limit N]
mitre update [--domain … --all-domains --force]
mitre info # diagnostic JSON: cache path, active version, etc.
Global flags must precede the subcommand:
--domain {enterprise|mobile|ics} # default: enterprise
--attack-version v19.0 # default; or MITRE_ATTACK_VERSION env
--data-path PATH # pre-downloaded STIX dir/file (or MITRE_ATTACK_DATA_PATH)
--format {json|jsonl|pretty} # default: json
--pretty # human-readable
--fields a,b,c # whitelisted field projection
--full # all fields
--include-revoked # include revoked/deprecated objects
--offline # fail rather than download
--quiet # suppress stderr progress logs
Examples
# Lookup
mitre --pretty technique get T1059.001
mitre group get APT28 # alias resolves to G0007
# Relationships
mitre technique groups-using T1059.001
mitre technique mitigations T1059.001
mitre group techniques G0007
# Listings + filtering + field selection
mitre technique list --tactic lateral-movement --platform Windows
mitre --fields attack_id,name --format jsonl technique list
# Search
mitre search "kerberoasting" --limit 5
mitre search '^Power' --regex --type technique
# Diagnostics
mitre info
Data: bring your own or let it download
Three resolution paths, in order:
--data-path PATH(orMITRE_ATTACK_DATA_PATHenv). Accepts:- A direct file (
/path/to/enterprise-attack.json) - A flat directory containing
enterprise-attack.json - A
{version}/{domain}-attack.jsonlayout (e.g.~/cache/v19.0/enterprise-attack.json). This matches common ETL cache layouts, so pre-downloaded bundles are reused without re-downloading.
- A direct file (
- Local cache at
~/.cache/mitre-attack-cli/{version}/{domain}-attack.json(honorsXDG_CACHE_HOME). - Download from
https://raw.githubusercontent.com/mitre-attack/attack-stix-data/master/{domain}-attack/{domain}-attack-{version}.jsonunless--offline.
Refresh is explicit via mitre update. The pinned default version is v19.0;
override with --attack-version v15.1 or MITRE_ATTACK_VERSION=v15.1. The
version is the reproducibility contract — same CLI version + same --attack-version
returns the same answers.
Only the domain you request is downloaded. --domain mobile will fetch
mobile-attack lazily; enterprise and ics aren't touched.
Performance
Coding agents fire many short-lived mitre ... invocations. Loading the full
ATT&CK STIX bundle through stix2 every time would cost ~2.4 s per call. To
avoid that, the CLI maintains a compiled snapshot cache next to each STIX
file:
~/.cache/mitre-attack-cli/v19.0/
├── enterprise-attack.json # raw STIX (downloaded on demand)
└── enterprise-attack.cache.msgpack # compiled snapshot — used by every warm run
| Run | Wall clock | What happens |
|---|---|---|
| First (cold) | ~25–30 s | mitreattack-python loads the STIX bundle once, builds a msgpack snapshot with every relationship pre-resolved. |
| Warm | ~150–300 ms | mitreattack-python is never imported. The hot path is typer + httpx + msgpack + pure-dict lookups. |
| Cache invalid | ~25–30 s | Rebuilt automatically when the STIX file's mtime/size changes, when the CLI version changes, or when you run mitre update --force. |
The snapshot uses msgpack — a binary, data-only format. It lives in your own
writable cache dir even when the STIX bundle itself comes from --data-path,
so a read-only data path remains read-only.
Install
uv tool install mitre-attack-cli # recommended
pipx install mitre-attack-cli # alternative
uvx mitre-attack-cli technique get T1059 # no install, one-shot
Development
git clone https://github.com/nitzpo/mitre-attack-cli
cd mitre-attack-cli
uv sync --all-groups
uv run python tests/fixtures/build_tiny_bundle.py # build test fixture
uv run pytest # 114 tests, ~1s
uv run ruff check . && uv run ruff format --check .
The project uses uv for dependency management,
ruff for lint+format, ty
for type checking, and pytest for tests. CI runs on Python 3.12 and 3.13 across
Ubuntu and macOS.
Architecture
Four layers, each independently testable:
cli/ # Typer commands, global flags, CliContext
└─ output/ # JSON/JSONL/markdown formatters, field projection, error envelope
└─ domain/ # ranked search, per-kind list/get/filter logic
└─ repo/ # AttackRepository wrapping mitreattack-python's MitreAttackData
└─ data/ # path resolution, httpx download with atomic-rename
The data layer is intentionally agnostic about ATT&CK schema specifics so future loaders (D3FEND, CAPEC, Atomic Red Team) can plug in without disturbing the CLI surface.
Differences vs the existing MCPs
- No daemon, no MCP server, no transport. Just a binary on
$PATH. - JSON-by-default for agents;
--prettyfor humans. - Lazy per-domain download — only fetches what you ask for, not all three.
- Pre-downloaded path interop — points at any existing STIX bundle including
versioned
{version}/{domain}-attack.jsonlayouts. - Stable error envelope with documented codes (NOT_FOUND, MISSING_DATA, …) and useful hints in every error.
License
MIT. See LICENSE.
Project details
Release history Release notifications | RSS feed
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 mitre_attack_cli-0.2.0.tar.gz.
File metadata
- Download URL: mitre_attack_cli-0.2.0.tar.gz
- Upload date:
- Size: 32.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
13e2f015be1e94fef36550fab548aa1a951ef7077553d0fa4f2a4fe1e241a43b
|
|
| MD5 |
88b5739ecf88575691cff39fba79ea67
|
|
| BLAKE2b-256 |
6e2b035a8642099acf4c6585d6b8c3de918808a621ed76b2b55a8d5c92ba3a6a
|
Provenance
The following attestation bundles were made for mitre_attack_cli-0.2.0.tar.gz:
Publisher:
release.yml on nitzpo/mitre-attack-cli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mitre_attack_cli-0.2.0.tar.gz -
Subject digest:
13e2f015be1e94fef36550fab548aa1a951ef7077553d0fa4f2a4fe1e241a43b - Sigstore transparency entry: 1582163703
- Sigstore integration time:
-
Permalink:
nitzpo/mitre-attack-cli@dd54ec5589113fcd18b9752d1a601eb97049e266 -
Branch / Tag:
refs/tags/v0.1 - Owner: https://github.com/nitzpo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@dd54ec5589113fcd18b9752d1a601eb97049e266 -
Trigger Event:
push
-
Statement type:
File details
Details for the file mitre_attack_cli-0.2.0-py3-none-any.whl.
File metadata
- Download URL: mitre_attack_cli-0.2.0-py3-none-any.whl
- Upload date:
- Size: 47.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6e7789d4c2333f02eb8268d52ec3d218c7c8634c0529c28bc74a18186faac0ed
|
|
| MD5 |
b7c8b11782f0474019fea464eed43da6
|
|
| BLAKE2b-256 |
fe98940e11abef799c132103d92e65aa0db2e91b24737501bcb3b3c6f824dcf3
|
Provenance
The following attestation bundles were made for mitre_attack_cli-0.2.0-py3-none-any.whl:
Publisher:
release.yml on nitzpo/mitre-attack-cli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mitre_attack_cli-0.2.0-py3-none-any.whl -
Subject digest:
6e7789d4c2333f02eb8268d52ec3d218c7c8634c0529c28bc74a18186faac0ed - Sigstore transparency entry: 1582163918
- Sigstore integration time:
-
Permalink:
nitzpo/mitre-attack-cli@dd54ec5589113fcd18b9752d1a601eb97049e266 -
Branch / Tag:
refs/tags/v0.1 - Owner: https://github.com/nitzpo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@dd54ec5589113fcd18b9752d1a601eb97049e266 -
Trigger Event:
push
-
Statement type: