Skip to main content

pyfsr

PyPI version Python versions License: MIT Tests Documentation Status codecov Ruff

Documentation · Installation · Quick start · CLI · AI / agents

pyfsr is a batteries-included Python client for the FortiSOAR REST API. It gives you a typed query/CRUD layer over any module, picklist resolution, connector execution, playbook-run history, safe deletes — and a ready-made AI/agent surface (tool-schema registry + an optional MCP server) so an agent can drive FortiSOAR with no glue code.

There's also a pyfsr CLI for the things you reach for outside a script: poking at an appliance's health and services, and authoring playbooks in YAML and pushing them to a live instance.

Python 3.10+ · Pydantic v2 · MIT.

Installation

pip install pyfsr
# with the optional generic MCP server:
pip install 'pyfsr[mcp]'

Quick start

from pyfsr import FortiSOAR, Query

# API-key auth, or ("username", "password")
client = FortiSOAR("soar.example.com", "your-api-key")

# Generic, typed CRUD for ANY module via client.records(module)
incidents = client.records("incidents")

inc = incidents.get("0d2c...")          # by uuid, "module:uuid", or full IRI
inc["name"], inc.uuid                    # records are dict- AND attribute-accessible

# Structured queries with a fluent builder -> a HydraPage you can iterate
page = incidents.query(
    Query().eq("status.itemValue", "Open").like("name", "phish").limit(50)
)
for inc in incidents.iterate(Query().eq("status.itemValue", "Open")):
    ...                                  # lazily walks every page

# Create / update / delete (soft by default; hard= for permanent)
new = incidents.create({"name": "Suspicious login", "severity": "High"},
                       resolve_picklists=True)   # friendly values -> IRIs
incidents.update(new.uuid, {"status": "Closed"}, resolve_picklists=True)
incidents.delete(new.uuid)               # delete(..., hard=True) to purge

Configure from the environment

from pyfsr import EnvConfig

# reads FSR_BASE_URL (+ FSR_API_KEY or FSR_USERNAME/FSR_PASSWORD),
# FSR_PORT, FSR_VERIFY_SSL, FSR_TIMEOUT
client = EnvConfig.from_env().client()

Features

  • Generic record accessclient.records(module) for CRUD on any module; no hand-built /api/3/... URLs or Hydra unwrapping.
  • Query DSLQuery().eq(...).in_(...).group(...).sort(...).limit(...), compiled to the FortiSOAR query-body shape (pagination handled for you).
  • Typed models — Alert/Incident/Task/Comment come back as Pydantic v2 models that are also dict-compatible; unknown modules fall back to a lenient BaseRecord, so custom fields/modules never break.
  • Picklistsclient.picklists resolves friendly values ("High") to IRIs and discovers which picklist a (module, field) binds to.
  • Connectorsclient.connectors lists configured connectors, runs healthchecks, and executes operations.
  • Playbooksclient.playbooks merges live + historical run history and resumes manual-input steps.
  • Safe deletes — soft-delete/restore + guarded single-row hard delete.
  • Schema discoveryclient.list_modules() / client.describe_module().
  • Resilient transport — configurable timeout=, automatic retry with backoff on idempotent requests (429/5xx), and secrets masked in verbose logs.
  • Bundled OpenAPI specpyfsr.spec.load_spec() for offline reference and drift(client) to compare the spec against a live appliance.

AI / agent-friendly

pyfsr ships a transport-neutral tool registry for the core operations, with token-efficient results and structured (never-raised) errors — feed it to Anthropic tool-use, OpenAI function calling, your own agent loop, or the bundled MCP server.

from pyfsr.agent.tools import to_anthropic_tools, to_openai_tools, dispatch

tools = to_anthropic_tools()             # or to_openai_tools(), or tool_schemas()

# ... your model picks a tool ...
result = dispatch(client, "search_records",
                  {"module": "alerts", "summary": True, "limit": 10})
# result is JSON-safe and trimmed; failures come back as {"error": {...}}

Reads accept summary=True or fields=[...] to keep payloads small:

client.records("alerts").query(Query().limit(20), summary=True)

Generic MCP server

Point any MCP-capable agent at any FortiSOAR with one command:

pip install 'pyfsr[mcp]'
FSR_BASE_URL=soar.example.com FSR_API_KEY=... python -m pyfsr.agent.mcp

It exposes the same registry (record CRUD, schema discovery, picklists, connectors, playbook runs) as MCP tools — generic and dependency-light, distinct from any domain-specific FortiSOAR MCP.

Command-line tools

Installing pyfsr puts a pyfsr command on your path with six groups.

pyfsr appliance — operational verbs against a FortiSOAR box (most run over SSH/sudo and stay dependency-light on the far end):

pyfsr appliance info                 # host, version, content DB, device UUID
pyfsr appliance host                 # mem / swap / load / per-service RSS / disk
pyfsr appliance service restart cyops-postman --yes
pyfsr appliance db                   # Postgres verbs, multi-DB aware
pyfsr appliance es                   # Elasticsearch health + shard state
pyfsr appliance license              # licensing / identity, drift check
pyfsr appliance content-hub sync     # pull the Content Hub catalog + artifacts

Other appliance subgroups: mq (RabbitMQ), ha, certs, logs, and diagnose (runs fsr_diagnose.sh). --help on any of them lists the verbs.

pyfsr playbook — author playbooks as YAML and deploy them:

pyfsr playbook steps                 # list every step type you can write
pyfsr playbook step-help TYPE        # keys + a compiling example for one type
pyfsr playbook examples              # foundational playbook library (--intent/--stage/--manifest)
pyfsr playbook show SLUG             # print one library playbook's metadata + YAML
pyfsr playbook validate flow.yaml    # compile + report diagnostics (offline)
pyfsr playbook compile flow.yaml     # emit the FSR import envelope (offline)
pyfsr playbook lint flow.yaml        # live preflight: connector steps missing config
pyfsr playbook deploy flow.yaml      # compile and create it on the appliance

pyfsr records — query and manage FortiSOAR records over the API:

pyfsr records alerts [--status Open] [--severity High]
pyfsr records incidents '<field=value or Query DSL JSON>'
pyfsr records delete <module> <uuid...> [--yes]

pyfsr repo — discover and download from Fortinet's content repo (no appliance needed).

pyfsr widget — upload and publish widgets on a live appliance.

pyfsr mcp — call FortiSOAR's own native MCP tool gateway (list-tools / call), distinct from the generic pyfsr.agent.mcp server.

Development

uv sync
uv run pytest -q                 # unit tests (live tests deselected by default)
uvx ruff check src tests

Live integration tests run with pytest -m integration and need an examples/config.toml pointing at a FortiSOAR instance.

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

pyfsr-0.18.4.tar.gz (1.5 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pyfsr-0.18.4-py3-none-any.whl (872.1 kB view details)

Uploaded Python 3

File details

Details for the file pyfsr-0.18.4.tar.gz.

File metadata

  • Download URL: pyfsr-0.18.4.tar.gz
  • Upload date:
  • Size: 1.5 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for pyfsr-0.18.4.tar.gz
Algorithm Hash digest
SHA256 7446aabee224e4f4c83140acbac1a1a489a8ca59cd1aeca5294076908e17c7e4
MD5 9c17b1d36057122205d660a4b90e2634
BLAKE2b-256 6487f359801cd68101f96ea9480feab55b0e2292b2428204c6eb73af7bc3bc68

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyfsr-0.18.4.tar.gz:

Publisher: publish.yml on ftnt-dspille/pyfsr

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyfsr-0.18.4-py3-none-any.whl.

File metadata

  • Download URL: pyfsr-0.18.4-py3-none-any.whl
  • Upload date:
  • Size: 872.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for pyfsr-0.18.4-py3-none-any.whl
Algorithm Hash digest
SHA256 24b19154cdd9c173f2ca6e6fc70ea7857946fc5a95d99b6dd441c96d0b2db750
MD5 0df727cbbd6d5622bee4fa903a7e20bc
BLAKE2b-256 ca4eaa37d46d647833710ab8853fe586754092dd72e22d143ad70e70e16c5632

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyfsr-0.18.4-py3-none-any.whl:

Publisher: publish.yml on ftnt-dspille/pyfsr

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page