Prescryb – an MCP server for CVE and config remediation Prescryb, a new open-source MCP server, enables natural-language-driven vulnerability and compliance remediation by connecting AI assistants to SSH-based host inventory, CVE matching, advisory lookups, and Ansible playbook generation. The tool remains read-only against target hosts, letting the connected model reason about findings and generate suggested fixes without applying changes automatically. See OVERVIEW.md /konstruktoid/prescryb/blob/main/OVERVIEW.md for a high-level description of the repository's purpose, components, and scope before making behavioral changes. A remediation orchestrator, exposed as an MCP server. Connect an MCP client Claude Desktop, Claude Code, or similar and submit a natural-language request, for example: Log into host a.b.c, check installed packages, find CVEs, and suggest a fix - Ansible if possible, and tell me what compliance controls it maps to. prescryb supplies the primitives SSH inventory, CVE matching, live advisory lookups, compliance-topic mapping, Ansible playbook rendering . The connected model does the reasoning: which findings matter, which CVEs to dig into, which playbook to generate. prescryb never applies anything to the target host - every tool is read-only against it, or pure text/data generation. | Tool | What it does | |---|---| inventory host host, user="", port=22, hostname="", identity file="", trust unknown host=False | SSH in, detect the distro, list installed packages with versions. | check cves system, packages | Batch-match package versions against | fetch advisory cve id fetch epss cve ids EPSS https://www.first.org/epss/api exploitation-probability scores for CVE IDs not already covered by check cves e.g. from fetch advisory or a web search . map compliance area "ssh" , "sudo" , "kernel modules" , ... to CIS/DISA STIG topic areas and, if present in the konstruktoid.hardening GitHub repo, the matching role - plus the MITRE ATT&CK techniques and mitigations that area addresses. lookup cce target, keyword, cve id NIST CCE https://ncp.nist.gov/cce Common Configuration Enumeration entries for a platform e.g. "rhel8" , sourced from the community JSON conversion at . https://github.com/konstruktoid/cce-web konstruktoid/cce-web list cce targets lookup cce can query. generate playbook system, cve matches, compliance areas, hosts alias suggest-only Ansible playbook: CVE fixes become package-upgrade tasks, compliance areas become roles: references.Typical flow: inventory host , then check cves on the returned packages, then optionally fetch advisory on interesting CVEs, then map compliance and lookup cce for any insecure-config areas noticed, then generate playbook to produce something to review. uv sync Claude Code: claude mcp add prescryb -- uv --directory /path/to/prescryb run prescryb Claude Desktop claude desktop config.json : { "mcpServers": { "prescryb": { "command": "uv", "args": "--directory", "/path/to/prescryb", "run", "prescryb" } } } inventory host never accepts a password argument. MCP tool-call arguments can be logged by clients and are visible to the connected model, so credentials must never flow through them. Auth works exactly like running ssh host yourself: - Host/user/port/identity files are resolved from ~/.ssh/config . - Keys come from an SSH agent or the default identity files. inventory host 's hostname / identity file arguments override the resolved address/key path directly, for hosts you do not want to add to ~/.ssh/config only a path is passed, never key contents .- Unknown host keys are rejected unless you pass trust unknown host=True - prefer running ssh host manually once to pin the key instead. - prefer running claude 'run vagrant up, connect to the created VM, check any vulnerabilities and suggest a fix, include compliance mapping if possible, write the playbook suggestion to /tmp/ and print the file location' For a host already reachable via ssh resolved through ~/.ssh/config , an agent key, or the default identity file , specify the hostname directly; no port or identity-file configuration is required: Inventory prod-web-01, check installed packages, find CVEs, and suggest a fix - Ansible if possible, and tell me what compliance controls it maps to. If the host is not in ~/.ssh/config yet, either add a Host block or pass user / port / hostname / identity file straight to inventory host for a one-off connection - same as the molecule example below. molecule converge -s default Find the ssh port / ssh user from that scenario's molecule.yml platform entry e.g. ssh port: 22201 , ssh user: almalinux for the almalinux10 platform and the private key molecule login uses to connect - either add a Host block to ~/.ssh/config , or skip the file entirely and pass them straight to inventory host for a one-off, ephemeral connection: Inventory 127.0.0.1, port 22201, user almalinux, identity file /path/to/molecule's/generated/key, check installed packages, find CVEs, and suggest a fix - Ansible if possible, and tell me what compliance controls it maps to. Run molecule destroy -s default when finished; prescryb will not do it for you, and will not touch the instance beyond reading it. map compliance names topic areas e.g. "SSH Server Configuration" and, if found in the konstruktoid/ansible-collection-hardening https://github.com/konstruktoid/ansible-collection-hardening GitHub repository, a link to the Ansible role that implements it. By default it queries the GitHub API against konstruktoid/ansible-collection-hardening https://github.com/konstruktoid/ansible-collection-hardening . Override with: export HARDENING COLLECTION REPO=owner/repo Set GITHUB TOKEN to raise the otherwise low unauthenticated GitHub API rate limit. If a role is not found in the repo, map compliance still returns the topic/framework/role name so you know what to install ansible-galaxy collection install konstruktoid.hardening . lookup cce looks up NIST Common Configuration Enumeration https://ncp.nist.gov/cce entries - unique identifiers for individual configuration checks, distinct from the topic-area CIS/DISA STIG mapping above. NIST only publishes CCE as spreadsheets, so this reads the pre-converted JSON exports hosted by the community project konstruktoid/cce-web https://github.com/konstruktoid/cce-web instead of parsing Excel. Coverage is per-platform, not per-topic, and thin for this project's target distros: only RHEL-family rhel6 / rhel7 / rhel8 - AlmaLinux/Rocky use the matching upstream RHEL number and SUSE SLES12-DISA-STIG / SLES15-DISA-STIG / SLES15-PCI-DSS have usable data. Debian, Ubuntu, Alpine, and Arch have no CCE data upstream at all. A few older cce-web exports e.g. rhel4 , rhel5 , apache-httpd2.2 lost their column headers in the upstream Excel-to-JSON conversion; those are reported as unsupported rather than returning garbled fields. Call list cce targets to see every published platform, including non-Linux ones firefox , win2k8r2 , ... . Override the source repo with: export CCE REPO=owner/repo Alongside CIS/DISA STIG, map compliance and generate playbook also cite the MITRE ATT&CK https://attack.mitre.org technique s mitigated by a topic area's hardening e.g. "ssh" maps to T1110 Brute Force and T1021.004 Remote Services: SSH and, where ATT&CK defines one, the corresponding mitigation e.g. M1032 Multi-factor Authentication with a link to attack.mitre.org. Unlike CIS/DISA STIG rule numbers, ATT&CK technique and mitigation IDs are MITRE's own public catalog, so they are cited directly rather than needing a licensed benchmark lookup. This mapping is static built into attack.py , not fetched live. OSV.dev is the sole CVE-matching source. It resolves {name, ecosystem, version} server-side against the ecosystem's actual version ordering, so a match reflects the exact installed version rather than "any CVE that mentions this package name." Coverage is mature for Debian, Ubuntu, Alpine ; thinner for RHEL-family AlmaLinux, Rocky and SUSE. check cves returns a warning field flagging thinner-coverage ecosystems, and returns nothing rather than a guess for distros with no ecosystem mapping at all - an empty result there means "not checked," not "clean." NVD fetch advisory is used only to enrich a CVE you already have the ID for. Set NVD API KEY to raise the otherwise low unauthenticated rate limit. EPSS epss score / epss percentile on every check cves match, or fetch epss for CVE IDs from elsewhere estimates the probability of exploitation in the next 30 days - independent of, and a useful complement to, CVSS/severity: a LOW-severity CVE can carry a high EPSS score, and vice versa. This lets findings be sorted/filtered by cve id , severity , or epss score . No API key needed. CVEs with no EPSS record very new, reserved, or rejected IDs simply have epss score unset - not an error. A FIRST.org outage surfaces as a warning on check cves rather than failing the CVE match itself.- Severity: OSV gives a raw CVSS vector string cvss vector , not a precomputed label, for most OS-package entries. severity is only populated when the source explicitly labels it; otherwise it is "UNKNOWN" and the vector is left for you or the model to interpret, rather than guessing. Output is always a full playbook as text, prefixed with a comment header citing every CVE/compliance source used. It is never executed by prescryb . Review it - ansible-playbook --syntax-check , then --check --diff - before running it anywhere. Package-upgrade tasks use the module for the target's package manager ansible.builtin.apt / dnf / zypper / community.general.apk . Version pins are only applied where the module supports them; Arch/pacman targets get state: latest since pacman does not support the same pinning syntax. | Variable | Default | Purpose | |---|---|---| HARDENING COLLECTION REPO | konstruktoid/ansible-collection-hardening | GitHub owner/repo queried for compliance-mapped Ansible roles. | CCE REPO | konstruktoid/cce-web | GitHub owner/repo queried for CCE JSON exports by lookup cce / list cce targets . | GITHUB TOKEN | unset | Raises GitHub API rate limits for map compliance , lookup cce , and list cce targets . | NVD API KEY | unset | Raises NVD API rate limits for fetch advisory . | - Does not apply playbooks or otherwise mutate the target host. - Does not accept passwords as tool arguments. - Does not fabricate CIS/DISA STIG rule numbers. - Does not guess CVEs for ecosystems OSV does not cover; it reports that instead.