MispFleet
Async Python library and CLI to operate many MISP instances as one coordinated fleet
Overview
MispFleet is not another thin wrapper around a single MISP REST API. Its differentiator is the orchestration layer: query, compare, govern, and synchronize multiple MISP instances through one consistent asynchronous interface — as a CLI or as a Python library.
Key Features
| Feature | Description |
|---|---|
| Fleet orchestration | Multi-instance config with server groups, roles, and tags |
| Async client | Non-blocking MISP HTTP client (httpx), usable standalone |
| Bounded concurrency | Concurrent fleet-wide execution with failure policies |
| Federated search | Fleet-wide search that preserves source provenance |
| Diff & safe copy | Event comparison and two-stage copy (plan → apply) |
| Synchronization | Bidirectional sync jobs with conflict-resolution strategies |
| Policy engine | Tag, distribution, and content governance |
| Threat-intel export | STIX 2.1 export, TAXII 2.1 push, OpenCTI integration |
| Secure credentials | Environment, OS keyring, interactive prompt, in-memory |
| Durable state | Local SQLite or shared MariaDB checkpoints and audit records |
| Streaming | Automatic pagination and memory-safe streaming |
Supported Outputs
Data JSON, JSONL, YAML, terminal tables
Threat Intel STIX 2.1 export, TAXII 2.1 push, OpenCTI
State SQLite (local) or MariaDB (shared) checkpoints & audit
Credentials env vars, OS keyring, interactive prompt, in-memory
Why MispFleet if PyMISP already exists?
PyMISP is the official Python library for MISP, and it is excellent at what it does: a rich, typed object model (MISPEvent, MISPAttribute, MISPObject, …) over the REST API of one MISP instance. If you work against a single server, PyMISP is the right tool — and MispFleet does not replace it.
MispFleet solves a different problem: operating many MISP instances as one coordinated fleet. PyMISP gives you PyMISP(url, key), a single synchronous connection; everything beyond that — iterating over servers, running requests concurrently, aggregating partial failures, preserving provenance, comparing or reconciling instances — is left for you to hand-roll. MispFleet makes that orchestration layer a first-class, typed, tested library.
| PyMISP (official) | MispFleet | |
|---|---|---|
| Scope | One MISP instance per client | A fleet: many instances with groups, roles, tags |
| Transport | Synchronous (requests) ¹ |
Asynchronous (httpx) with bounded concurrency |
| Failures | Per-call exceptions | Partial-fleet failures as data + failure policies |
| Search | Query one server | Federated search that preserves source provenance |
| Compare instances | — | Deterministic event diff between servers |
| Move data safely | Manual add/update | Two-stage copy: plan (credential-free) → apply (re-validated) |
| Keep instances in sync | — | Bidirectional sync jobs with conflict-resolution strategies |
| Governance | — | Policy engine (tag / distribution / content) applied on transfer |
| State & audit | — | Durable SQLite / MariaDB checkpoints and audit records |
| Interop export | — | STIX 2.1, TAXII 2.1 push, OpenCTI |
| Interface | Library | CLI and typed library |
¹ An experimental pymisp-async (aiohttp) exists as a separate project; the mainline PyMISP is synchronous.
In short: use PyMISP to talk to a MISP instance; use MispFleet to run a set of them. The two are complementary — MispFleet ships its own async client rather than wrapping PyMISP, but they target different layers of the same problem. For deep single-instance API coverage and MISP's canonical object generators, reach for PyMISP; for fleet-wide search, diffing, governed copy, and synchronization, reach for MispFleet.
Installation
From PyPI (Recommended)
python3.14 -m pip install mispfleet
Python 3.14 is the only supported runtime for the first major version.
From Source
git clone https://github.com/seifreed/MispFleet.git
cd MispFleet
python3.14 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e .
Optional Extras
pip install "mispfleet[all]" # keyring + mariadb + telemetry + http2
pip install "mispfleet[keyring]" # OS keyring credential provider
pip install "mispfleet[mariadb]" # shared MariaDB state backend
pip install "mispfleet[telemetry]" # OpenTelemetry metrics
pip install "mispfleet[http2]" # HTTP/2 transport
Quick Start
# Create and validate a fleet configuration
mispfleet config init
mispfleet config validate
# Check health across every configured server
mispfleet servers health --all
# Federated search across the fleet
mispfleet search value evil.example --all --format json
Usage
Command Line Interface
# Compare one event between two servers
mispfleet event diff EVENT_UUID --left production --right research
# Plan a copy without mutating anything, then apply the reviewed plan
mispfleet event copy EVENT_UUID --from research --to production --dry-run
mispfleet apply plan.json
Main Commands
| Command | Description |
|---|---|
mispfleet config |
Create, validate, and edit fleet configuration |
mispfleet servers |
Per-server health and capability checks |
mispfleet search |
Federated search preserving source provenance |
mispfleet event |
Retrieve, diff, and safely copy events (plan / apply) |
mispfleet attribute |
Attribute-level operations across the fleet |
mispfleet policy |
Tag, distribution, and content governance policies |
mispfleet sync |
Bidirectional synchronization jobs |
mispfleet sightings |
Federated sightings |
mispfleet stix |
STIX 2.1 export |
mispfleet opencti |
Push to OpenCTI |
mispfleet state |
Inspect and prune local state |
mispfleet plugins |
Manage plugins |
mispfleet apply |
Re-validate and apply a copy plan |
Python Library
Basic Usage
import asyncio
from pathlib import Path
from mispfleet import MispFleet, SearchQuery, ServerSelector
async def main() -> None:
async with await MispFleet.from_file(Path("mispfleet.yml")) as fleet:
result = await fleet.search(
SearchQuery(value="evil.example", metadata_only=True),
selector=ServerSelector.group("all"),
)
for match in result.matches:
print(match.server, match.event_uuid)
if __name__ == "__main__":
asyncio.run(main())
Configuration
version: 1
defaults:
verify_tls: true
request_timeout: 60
connect_timeout: 10
concurrency: 5
servers:
production:
url: https://misp.company.example
credential:
provider: env
key: MISPFLEET_PRODUCTION_API_KEY
role: primary
groups: [internal, all]
partner-cert:
url: https://misp.partner.example
credential:
provider: env
key: MISPFLEET_PARTNER_CERT_API_KEY
role: partner
read_only: true
groups: [partners, all]
API keys are never stored in the configuration file: credentials are references to environment variables, the OS keyring, an interactive prompt, or in-memory values.
Safety Model
- Read operations run directly; mutating and cross-server operations support plan and dry-run modes.
- Copying an event is a two-stage operation:
planproduces a deterministic, credential-free plan file;applyre-validates it before mutating anything. - Partial fleet failures are represented as data, never as silent total success.
- Secrets are redacted from logs, exceptions, plans, and debug output.
Requirements
- Python 3.14
- See pyproject.toml for dependencies and extras
Development
python3.14 -m venv .venv && .venv/bin/pip install -e '.[dev]'
black --check . && ruff check . && mypy .
pytest
bandit -r . && pip-audit
Contributing
Contributions are welcome.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Support the Project
If this project is useful in your workflows, you can support development:
License
This project is licensed under the MIT license. See LICENSE.
Attribution
- Author: Marc Rivero López | @seifreed
- Repository: github.com/seifreed/MispFleet
Built for practical multi-instance MISP operations and threat-intel automation
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 mispfleet-0.1.0.tar.gz.
File metadata
- Download URL: mispfleet-0.1.0.tar.gz
- Upload date:
- Size: 278.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8e183b2cffc1b003eeff02d6c4eec19948a3fc70e34a75851e8601249df0dc1f
|
|
| MD5 |
e9a1ed65d017419c836b6fd0401c411e
|
|
| BLAKE2b-256 |
4f31556beab71ad8810a3e9fbbb554af8b3298c3dee6ef13511e0989a499bcf0
|
Provenance
The following attestation bundles were made for mispfleet-0.1.0.tar.gz:
Publisher:
publish.yml on seifreed/MispFleet
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mispfleet-0.1.0.tar.gz -
Subject digest:
8e183b2cffc1b003eeff02d6c4eec19948a3fc70e34a75851e8601249df0dc1f - Sigstore transparency entry: 2498477759
- Sigstore integration time:
-
Permalink:
seifreed/MispFleet@d1ff29217ccf90f32a446b6edeb613a9e446b274 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/seifreed
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d1ff29217ccf90f32a446b6edeb613a9e446b274 -
Trigger Event:
release
-
Statement type:
File details
Details for the file mispfleet-0.1.0-py3-none-any.whl.
File metadata
- Download URL: mispfleet-0.1.0-py3-none-any.whl
- Upload date:
- Size: 163.2 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 |
b58f4bc925045f7ffb36677cccf19685a71985388bef65a47f6d70bfd53eb91e
|
|
| MD5 |
3bf9967e8ba5c7d4d7c6b0341c81a1e6
|
|
| BLAKE2b-256 |
f4e6a14279ad1b8e957abff1f5683c1a43ce017122b86cf68da159605659fea1
|
Provenance
The following attestation bundles were made for mispfleet-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on seifreed/MispFleet
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mispfleet-0.1.0-py3-none-any.whl -
Subject digest:
b58f4bc925045f7ffb36677cccf19685a71985388bef65a47f6d70bfd53eb91e - Sigstore transparency entry: 2498477765
- Sigstore integration time:
-
Permalink:
seifreed/MispFleet@d1ff29217ccf90f32a446b6edeb613a9e446b274 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/seifreed
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d1ff29217ccf90f32a446b6edeb613a9e446b274 -
Trigger Event:
release
-
Statement type: