Metadata-Version: 2.4
Name: mitre-attack-cli
Version: 0.2.0
Summary: A fast Python CLI for MITRE ATT&CK. Designed for coding agents — clean JSON output over stdout, no MCP daemon required.
Keywords: mitre,att&ck,attack,security,threat-intelligence,cli,stix,agent
Author: Nitzan Pomerantz
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Information Technology
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Security
Requires-Dist: typer>=0.15.0
Requires-Dist: httpx>=0.28.0
Requires-Dist: mitreattack-python>=5.0.0
Requires-Dist: msgpack>=1.0
Requires-Python: >=3.12
Project-URL: Homepage, https://github.com/nitzpo/mitre-attack-cli
Project-URL: Repository, https://github.com/nitzpo/mitre-attack-cli
Project-URL: Issues, https://github.com/nitzpo/mitre-attack-cli/issues
Project-URL: Changelog, https://github.com/nitzpo/mitre-attack-cli/blob/main/CHANGELOG.md
Description-Content-Type: text/markdown

# 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](https://github.com/stoyky/mitre-attack-mcp),
[MHaggis/mitre-attack-mcp](https://github.com/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

```bash
# 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.

```bash
$ 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

```bash
# 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:

1. **`--data-path PATH`** (or `MITRE_ATTACK_DATA_PATH` env). Accepts:
   - A direct file (`/path/to/enterprise-attack.json`)
   - A flat directory containing `enterprise-attack.json`
   - A `{version}/{domain}-attack.json` layout (e.g. `~/cache/v19.0/enterprise-attack.json`).
     This matches common ETL cache layouts, so pre-downloaded bundles are reused without re-downloading.
2. **Local cache** at `~/.cache/mitre-attack-cli/{version}/{domain}-attack.json`
   (honors `XDG_CACHE_HOME`).
3. **Download** from
   `https://raw.githubusercontent.com/mitre-attack/attack-stix-data/master/{domain}-attack/{domain}-attack-{version}.json`
   unless `--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

```bash
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

```bash
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`](https://docs.astral.sh/uv) for dependency management,
[`ruff`](https://docs.astral.sh/ruff) for lint+format, [`ty`](https://github.com/astral-sh/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; `--pretty` for 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.json` layouts.
- **Stable error envelope** with documented codes (NOT_FOUND, MISSING_DATA, …)
  and useful hints in every error.

## License

MIT. See [LICENSE](LICENSE).
