prescryb
prescryb is a read-only remediation orchestrator MCP server for inventorying SSH-accessible hosts, identifying vulnerabilities, mapping compliance controls, and generating suggested Ansible playbooks — without ever modifying any target system.
Inventory hosts — SSH into a host to detect its Linux distro and list all installed packages with versions. Supports SSH agent/config-based auth, custom identity files, and port overrides. Never accepts passwords as arguments.
Check CVEs — Batch-match installed packages against known vulnerabilities via OSV.dev using ecosystem-aware version comparison. Returns matched CVEs with severity info (note: coverage may be thin for RHEL-family distros).
Fetch advisories — Retrieve live NVD records for a specific CVE ID, including description, CVSS score/severity, CWE classification, and reference links.
Map compliance — Translate free-text topics (e.g., "ssh", "sudo") into CIS Benchmark / DISA STIG topic areas, matching
konstruktoid/ansible-collection-hardeningroles (if found), and relevant MITRE ATT&CK techniques and mitigations.Look up CCEs — Query NIST Common Configuration Enumeration (CCE) entries for platforms like RHEL and SUSE, filtered by keyword or exact CCE ID.
List CCE targets — View all platforms available for CCE lookup (e.g.,
rhel6–8, SUSE variants,firefox,win2k8r2, etc.).Generate playbooks — Render a suggest-only Ansible playbook with package-upgrade tasks for CVE fixes and hardening role references for compliance areas, with a header citing all sources. The playbook is never executed — always for human review.
All host operations are read-only. GitHub repo sources for compliance/CCE data and API keys for NVD/GitHub are configurable to manage rate limits.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@prescrybInventory host 10.0.0.5, check CVEs, and suggest an Ansible fix with compliance mapping."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
prescryb - A remediation orchestrator
See 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.
How it works
Tool | What it does |
| SSH in, detect the distro, list installed packages with versions. |
| Batch-match package versions against OSV.dev using its ecosystem-aware version comparison (not name-only matching). |
| Fetch the current NVD record for one CVE - description, CVSS, CWE, references - live, not from training data. |
| Map a free-text topic ( |
| Look up NIST CCE (Common Configuration Enumeration) entries for a platform (e.g. |
| List every platform |
| Render a suggest-only Ansible playbook: CVE fixes become package-upgrade tasks, compliance areas become |
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.
Related MCP server: gke-cred-audit
Install
uv syncRegister with an MCP client
Claude Code:
claude mcp add prescryb -- uv --directory /path/to/prescryb run prescrybClaude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"prescryb": {
"command": "uv",
"args": ["--directory", "/path/to/prescryb", "run", "prescryb"]
}
}
}SSH auth model
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'shostname/identity_filearguments 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=Trueprefer running
ssh hostmanually once to pin the key instead.
Example: running claude against the repository Vagrant VM
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'Example: checking a regular host
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.
Example: inspecting a molecule test instance
molecule converge -s defaultFind 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.
Compliance mapping
map_compliance names topic areas (e.g. "SSH Server Configuration") and, if
found in the 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.
Override with:
export HARDENING_COLLECTION_REPO=owner/repoSet 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).
CCE lookup
lookup_cce looks up NIST Common Configuration Enumeration
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
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/repoMITRE ATT&CK mapping
Alongside CIS/DISA STIG, map_compliance and generate_playbook also cite
the MITRE ATT&CK 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.
CVE data sources and their limits
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_cvesreturns awarningfield 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. SetNVD_API_KEYto raise the (otherwise low) unauthenticated rate limit.Severity: OSV gives a raw CVSS vector string (
cvss_vector), not a precomputed label, for most OS-package entries.severityis 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.
Playbook generation
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.
Environment variables
Variable | Default | Purpose |
|
| GitHub |
|
| GitHub |
| unset | Raises GitHub API rate limits for |
| unset | Raises NVD API rate limits for |
What this deliberately does not do
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.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/konstruktoid/prescryb'
If you have feedback or need assistance with the MCP directory API, please join our Discord server