Prescryb
БесплатноНе проверенA remediation orchestrator exposed as an MCP server that provides primitives for SSH host inventory, CVE matching, live advisory lookups, compliance mapping, an
Описание
A remediation orchestrator exposed as an MCP server that provides primitives for SSH host inventory, CVE matching, live advisory lookups, compliance mapping, and Ansible playbook generation.
README
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 |
|---|---|
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 OSV.dev using its ecosystem-aware version comparison (not name-only matching). Each match is enriched with an EPSS exploitation-probability score. |
fetch_advisory(cve_id) |
Fetch the current NVD record for one CVE - description, CVSS, CWE, references - live, not from training data. |
fetch_epss(cve_ids) |
Batch-fetch EPSS exploitation-probability scores for CVE IDs not already covered by check_cves (e.g. from fetch_advisory or a web search). |
map_compliance(area) |
Map a free-text topic ("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) |
Look up NIST CCE (Common Configuration Enumeration) entries for a platform (e.g. "rhel8"), sourced from the community JSON conversion at konstruktoid/cce-web. |
list_cce_targets() |
List every platform lookup_cce can query. |
generate_playbook(system, cve_matches, compliance_areas, hosts_alias) |
Render a 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.
Install
uv sync
Register with an MCP client
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"]
}
}
}
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=True- prefer running
ssh hostmanually once to pin the key instead.
- prefer running
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 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.
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/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).
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/repo
MITRE 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. - EPSS (
epss_score/epss_percentileon everycheck_cvesmatch, orfetch_epssfor 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 bycve_id,severity, orepss_score. No API key needed. CVEs with no EPSS record (very new, reserved, or rejected IDs) simply haveepss_scoreunset - not an error. A FIRST.org outage surfaces as awarningoncheck_cvesrather 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.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 |
|---|---|---|
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. |
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.
Установка Prescryb
У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.
▸ github.com/konstruktoid/prescrybFAQ
Prescryb MCP бесплатный?
Да, Prescryb MCP бесплатный — установка в пару кликов через Unyly без оплаты.
Нужен ли API-ключ для Prescryb?
Нет, Prescryb работает без API-ключей и переменных окружения.
Prescryb — hosted или self-hosted?
Доступен hosted-вариант: Unyly запускает сервер в облаке, локальная установка не обязательна.
Как установить Prescryb в Claude Desktop, Claude Code или Cursor?
Открой Prescryb на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.
Похожие MCP
GitHub
PRs, issues, code search, CI status
автор: GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Template MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
автор: mcpdotdirectCompare Prescryb with
Не уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории development
