stig-mcp
Click on "Deploy 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., "@stig-mcpwhat STIG fixes mitigate T1059 on Windows Server 2022?"
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.
stig-mcp
Local MCP server that maps MITRE ATT&CK® techniques (and actors) to the NIST 800-53r5 controls that mitigate them, with the DISA STIG fix and check steps for the systems under consideration, severity-ordered.
Install
stig-mcp is on PyPI. With uv, a client runs it with no separate install step:
uvx stig-mcpuvx comes with uv; install uv
first if uvx --version does not run. The VS Code badge and the Claude Code plugin below both
need it.
From a source checkout instead, install the dependencies with:
uv syncThe commands below are written for a checkout (uv run ...). Without one, run the same entry
point with uvx --from stig-mcp, for example uvx --from stig-mcp stig-mcp-install-kb.
Related MCP server: MITRE ATT&CK MCP Server
Quickstart
Wire the server into a client (see "Run the server" below) and start it.
Ask the agent to install the knowledge base. It calls the
install_knowledge_basetool, which downloads the newest published release from this project's GitHub releases and verifies its SHA-256 before installing it. From a terminal the same isuv run stig-mcp-install-kb. A host that cannot reach GitHub installs from a file; see docs/operations.md, "Install a prebuilt knowledge base".Or build it yourself:
uv run stig-mcp-fetchdownloads ATT&CK, the CTID mapping, the 800-53 catalog, and DISA's STIG content. This transfers roughly a gigabyte and refuses to start with less than 2 GiB free. Thenuv run stig-mcp-ingestbuilds the knowledge base.
On a host that cannot reach dl.dod.cyber.mil, place the artifacts in the sources
directory yourself and go straight to stig-mcp-ingest. That is a first-class path rather
than a fallback: the ingest reads a directory and never consults the fetch. See
docs/operations.md, "Placing the sources by hand".
Afterwards, uv run stig-mcp-fetch --check reports what MITRE ATT&CK, CTID, NIST and DISA
have published since, exiting 10 when there is something to take and 3 when a source could not
be reached, and --refresh takes it.
Neither rebuilds the knowledge base; see "Keeping current" in the same document.
Run the server
uvx stig-mcpor, from a checkout, uv run stig-mcp.
This is a stdio MCP server: it speaks JSON-RPC on stdin/stdout and logs to stderr, so it is launched by an MCP client rather than run standalone.
It starts whether or not the knowledge base exists, and it never answers from one it
cannot trust. Called before the knowledge base is installed, or against one an older release
wrote, every tool returns a not_ready payload instead of an answer: the reason, which
source files it can and cannot see, the sources directory it looked in, and the next steps,
led by the install_knowledge_base tool and followed by the commands to run. Each command
comes in two forms: run, which works from the server's own environment, and as_installed,
which a person can type into a terminal, written for how the server was installed (uvx, a
checkout, or an installed copy). That is deliberate, so an agent can read the remedy from
the tool result rather than the operator having to find a log pane. Install or rebuild the
knowledge base and the running server picks it up without a restart.
The check_sources tool tells an agent whether a newer knowledge base is published. It and
install_knowledge_base are the only two tools that contact the network, and they reach
only this project's GitHub releases.
GitHub Copilot in VS Code
Or run MCP: Open User Configuration from the Command Palette and add:
{
"servers": {
"stig-mcp": {
"type": "stdio",
"command": "uvx",
"args": ["stig-mcp"]
}
}
}From a checkout, create .vscode/mcp.json in this repository instead (git-ignored, so it
stays local):
{
"servers": {
"stig-mcp": {
"type": "stdio",
"command": "uv",
"args": ["run", "stig-mcp"],
"cwd": "${workspaceFolder}"
}
}
}Then:
Open Copilot Chat and set the mode dropdown to Agent. MCP tools are not available in Ask or Edit mode.
Command Palette (
Ctrl+Shift+P, orCmd+Shift+Pon macOS) and run MCP: List Servers, selectstig-mcp, then Start. Trust the server when prompted, since it runs a local command.Click Configure Tools in the chat input to confirm the eight tools are listed and enabled.
Reference a tool explicitly to verify the wiring, rather than hoping the model picks it up on its own. See docs/user-guide.md's "Getting the LLM to use the server" for a prompt shape that reliably does this.
Copilot saves a tool answer over 8 KB to a temporary file and reads it back, so with
manual permissions it asks to read a file named like …copilot-tool-output-….txt
outside the workspace. That file is this server's answer; allow it.
To debug, run MCP: List Servers, select the server, and choose Show Output.
The two common failures are that uvx or uv is not on the PATH VS Code inherited,
which looks like a broken server but is a missing command, and an absent knowledge base.
For the first, use the absolute path (which uvx or which uv) as command. A missing
uvx shows in VS Code's output as Connection state: Error spawn uvx ENOENT, and in
claude mcp list as Failed to connect — ENOENT: Executable not found in $PATH: "uvx". For
the second, see docs/operations.md.
Other clients
Any MCP client that launches a stdio server works, with uvx stig-mcp as the command. For
Claude Code, install the plugin from this repository's marketplace, inside a session (Claude
Code 2.1.275 or later):
/plugin install stig-mcp --marketplace jeneric/STIG-MCPor from a shell, claude plugin marketplace add jeneric/STIG-MCP then
claude plugin install stig-mcp@stig-mcp. The plugin pins the current release, and
claude plugin update stig-mcp@stig-mcp moves it to the next one. Without the plugin:
claude mcp add stig-mcp -- uvx stig-mcpFrom a checkout, uv run locates the project from the working directory, so a client that
starts elsewhere needs --directory, which makes the command independent of where it is
launched:
uv run --directory /path/to/STIG-MCP stig-mcpor, from the repository root, claude mcp add stig-mcp -- uv run stig-mcp.
By default the knowledge base is not found relative to the working directory, so only
uv run cares where the client starts the server. Where it is found depends on whether this is a
checkout or an installed copy. (A relative STIG_MCP_DATA does resolve against the working
directory, so give it an absolute path if the client's is not yours.)
Where the data lives
Two environment variables override the defaults, and the defaults differ between a source
checkout and an installed copy (which includes uvx stig-mcp):
source checkout | installed, POSIX and macOS | installed, Windows | |
data directory ( |
|
|
|
mapping overrides ( |
|
|
|
A checkout is a directory holding both the package and the pyproject.toml that declares
it, so an editable install counts as one. XDG is used on POSIX, including macOS. On Windows
with the XDG variables unset, the default is %LOCALAPPDATA%, because a roaming profile
copies ~/.local/share at every logon and logoff, and this project's downloads can run to a
gigabyte; when
%LOCALAPPDATA% is set this puts the mapping overrides file inside the data directory rather
than beside it, since Windows has one such variable rather than XDG's separate data and config
locations. (With %LOCALAPPDATA% unset, Windows falls back to the same separate ~/.config
and ~/.local/share trees POSIX uses, so the two stay apart in that case, same as the table
above shows.)
The XDG variables are read first on every platform, Windows included, as the table's
Windows column shows: a Windows host with XDG_DATA_HOME set uses it and never reaches
%LOCALAPPDATA%, so the roaming argument above holds only where that variable is unset. The
order is kept so that an existing install's data directory never moves under it.
STIG_MCP_DATA and STIG_MCP_OVERRIDES outrank everything above and are the escape hatch
everywhere, for a native location or any other.
stig-mcp-ingest creates the data directory if it does not exist. It refuses to run when
STIG_MCP_OVERRIDES names a file that is not there, rather than silently applying no
overrides; a missing file at the default location is fine, because that file is optional.
What this server fetches
The MCP server contacts nothing unless
check_sourcesorinstall_knowledge_baseis called. Then it sends HTTPS GET requests toapi.github.com(this repository's release listing) andgithub.com(/jeneric/STIG-MCP/releases/download/...), which redirects torelease-assets.githubusercontent.comorobjects.githubusercontent.com. Any other URL, a redirect included, is refused. Nothing is uploaded, and there is no telemetry.install_knowledge_basegiven a file path and its SHA-256 requests nothing at all.stig-mcp-install-kbcontacts the same hosts, and nothing at all with--file.stig-mcp-fetch, used only to build the knowledge base yourself, downloads fromraw.githubusercontent.comandapi.github.com(MITRE ATT&CK, the CTID mapping, the NIST 800-53 catalog) and fromdl.dod.cyber.mil(DISA).
PRIVACY.md states what each of these requests sends and what is stored locally.
Example prompts
With the knowledge base installed and the server wired into an agent, these are answered from it:
What DISA STIG steps mitigate T1078 on Windows 11?Which ATT&CK techniques does APT29 use?Which STIG benchmarks apply to RHEL 9?
Documentation
docs/operations.md: for whoever installs, builds and maintains the knowledge base.
docs/user-guide.md: for a person talking to an LLM that has this server wired in.
SECURITY.md: reporting a vulnerability, and what is in scope.
CONTRIBUTING.md: working from a source checkout, running the tests, and the project's conventions.
RELEASING.md: for the maintainer, publishing the package to PyPI and the MCP Registry.
PRIVACY.md: what the server and the fetch tool contact, and what is stored locally.
Third-party content
The knowledge base aggregates MITRE ATT&CK, CTID mapping, DISA STIG, DISA CCI list, and NIST OSCAL content. See NOTICE for attribution and licensing obligations and licenses/apache-2.0.txt for the Apache 2.0 license text that notice requires.
Development
Developed with the assistance of Claude Code (Anthropic). All changes were reviewed and tested by the maintainer.
Available Tools
8 toolscheck_sourcesA
Check whether a newer prebuilt knowledge base is published than the one installed. This contacts only this project's GitHub releases (github.com/jeneric/STIG-MCP). action is "install" (call install_knowledge_base), "upgrade_package" (a newer knowledge base needs a newer stig-mcp; upgrade_to says which), "build_locally" (nothing usable is installed and no release exists for this stig-mcp; build with stig-mcp-fetch and stig-mcp-ingest), or "none"; reason says why. It works even when the knowledge base is not built, and then not_ready says why and what to run.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden and does well: it discloses that it contacts only this project's GitHub releases (network scope), that it works even when the knowledge base is not built, and what not_ready conveys. It still omits whether the call is cached, rate-limited, or purely read-only, so it falls short of a complete behavioral picture.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose, then the network scope, then the action/return contract. The enumeration is dense but every clause maps to a real behavior or routing decision; only the nested parenthetical about build_locally is slightly heavy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, so the description must describe the return contract, and it does: action, reason, not_ready, and upgrade_to. Together with the edge-case note about running before a knowledge base is built, an agent has everything needed to call it and react to its result.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes no input parameters, so there is nothing to document; per the baseline, a 0-parameter tool scores 4. The description correctly spends no space on nonexistent inputs.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: check whether a newer prebuilt knowledge base is published than the one installed. It also scopes the network call to this project's GitHub releases, so an agent knows exactly what this check touches, distinct from siblings like install_knowledge_base or list_stigs.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It enumerates every outcome of action (install, upgrade_package, build_locally, none) and routes each to the concrete next step, naming install_knowledge_base, upgrade_to, and the stig-mcp-fetch/stig-mcp-ingest path. This is explicit when/when-not guidance tied to alternatives rather than inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
finding_detailsA
Return DISA's check and fix text for STIG findings, with each finding's benchmark, release and CCIs. ids takes up to 50 rule ids (SV-...r..._rule) or V- ids as listed under findings in a mitigations_for_technique or techniques_for_actor answer, in any case. Prefer the V- id: a rule id carries its release's revision and matches only that release. A V- id that two benchmarks or majors share returns every match, each labeled with its benchmark. not_found lists ids that matched nothing; if none match, the call is refused with an error instead. Quote check_text and fix_text as DISA wrote them, and label anything you add, such as commands or explanations, as your own rather than DISA's. If the knowledge base is not built yet this returns {"status": "not_ready"} with the commands to run, rather than an error.
| Name | Required | Description | Default |
|---|---|---|---|
| ids | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so well: it discloses the 50-id cap, release-specific matching semantics, that a shared V- id returns every match labeled by benchmark, that unmatched ids land in not_found, that an all-miss call is refused with an error, and that an unbuilt knowledge base returns {"status": "not_ready"} with commands instead of erroring.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense but front-loaded: purpose first, then id semantics, then edge-case behavior. Every sentence carries information, though the id-format and labeling guidance makes it longer than a minimal description.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema and no annotations, so the description must cover returns and edge cases; it names the returned fields (check/fix text, benchmark, release, CCIs), the not_found list, the error-on-no-match path, and the not_ready path. Nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate, and it does: it defines the accepted id forms (SV-...r..._rule and V-), the 50-item limit, the matching behavior per form, and the preferred form. This adds far more meaning than the bare `ids: array of string` schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: returns DISA's check and fix text for STIG findings, plus each finding's benchmark, release and CCIs. This is clearly separable from siblings like mitigations_for_technique and list_stigs, which serve different lookups.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explains where the ids come from (findings under a mitigations_for_technique or techniques_for_actor answer) and gives an explicit preference rule (prefer V- over rule ids, since a rule id matches only its release). It stops short of stating when to avoid this tool entirely, but the routing guidance is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
install_knowledge_baseA
Install the prebuilt knowledge base this server answers from. With no arguments, download the newest release for this server from this project's GitHub releases (github.com/jeneric/STIG-MCP), verify its SHA-256 and install it; this downloads and verifies about 5 MB and can take several seconds. It is the only tool besides check_sources that uses the network. release pins an exact kb-YYYY-MM-DD tag, for rollback. On a host without network access, pass path (a .sqlite.xz or .sqlite copied from a release) and sha256 (the value its SHA256SUMS lists); nothing is then requested. Call this when another tool returns {"status": "not_ready"}, or when check_sources reports "install".
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | ||
| sha256 | No | ||
| release | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so well: it discloses network dependency ('uses the network'), approximate size and duration ('about 5 MB and can take several seconds'), the SHA-256 verification step, the rollback mechanism via 'release pins an exact kb-YYYY-MM-DD tag', and the no-network branch. This is unusually rich behavioral context for an install/mutate operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Every sentence contributes information — download source, verification, size/latency, offline path, trigger conditions — and the primary action is front-loaded. It is somewhat dense and reads as one continuous block rather than clearly separated modes, which costs a point.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a no-annotation, no-output-schema, 3-parameter tool, the description covers inputs, network behavior, verification, and invocation triggers thoroughly. It does not mention what a successful invocation returns or how failures surface, a minor gap given there is no output schema to lean on.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate, and it does: 'release pins an exact kb-YYYY-MM-DD tag, for rollback'; 'path (a .sqlite.xz or .sqlite copied from a release)'; 'sha256 (the value its SHA256SUMS lists)'. Each of the three parameters gets format and purpose beyond the bare schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('Install the prebuilt knowledge base this server answers from') and immediately scopes the default behavior (download newest release, verify SHA-256, install). It also differentiates itself from siblings by noting it is 'the only tool besides check_sources that uses the network.'
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit trigger conditions: 'Call this when another tool returns {"status": "not_ready"}, or when check_sources reports "install".' It also names the conditions under which the offline parameters apply ('On a host without network access, pass path ... and sha256'). Both when-to-use and when-to-use-the-alternative-mode are covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_stigsA
List the STIGs in the knowledge base, optionally filtered by a substring of the title, the benchmark id (e.g. RHEL_9_STIG), or the product keywords. If the knowledge base is not built yet this returns {"status": "not_ready"} with the commands to run, rather than an error.
| Name | Required | Description | Default |
|---|---|---|---|
| filter | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It adds genuine behavioral value by disclosing the not-ready state return ({"status": "not_ready"}) instead of an error, but says nothing about permissions, pagination, or the shape/ordering of the returned STIG list.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the core purpose and followed by the edge-case behavior. No filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-param, no-output-schema list tool this is nearly complete: purpose, filter semantics, and the not-ready edge case are all covered. Only the return format of a successful call (fields, ordering, size) is left unspecified.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0% and the single 'filter' param is undocumented in the schema, so the description must compensate. It does, explaining that the filter is a substring match against title, benchmark id (with a concrete example, RHEL_9_STIG), or product keywords — meaning the schema alone does not provide.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (List) and resource (STIGs in the knowledge base) and scopes it by the filter dimensions. An agent can immediately distinguish this read/list tool from siblings like search_techniques or mitigations_for_technique.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage through the filtering options (title substring, benchmark id, product keywords) but never states when to prefer this over siblings or any prerequisite workflow. It does tell the agent what happens when the KB isn't built, which is useful context, but no explicit when/when-not guidance is given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
mitigations_for_techniqueA
Return 800-53r5 controls and the DISA STIG findings that mitigate an ATT&CK technique. The answer opens with summary: rules found, rules per CAT, control_counts (how many controls map and how many have rules), cat_i (the CAT I V- ids with their count) and controls_with_rules. Use those counts rather than counting lists yourself. Then each control lists the rule ids of its findings, and findings lists each finding once. Findings carry no check or fix text: call finding_details with their rule ids or V- ids for DISA's exact steps. severity narrows findings to CAT levels, e.g. ["I"]. A technique id ATT&CK has revoked (e.g. T1562) is answered for its replacement, and the response reports the redirect in technique.redirected_from. Include the product build in system_description where one exists (e.g. 'ESXi 8.0 U3'): some products ship two STIG versions with different remediations, and the build selects the one that applies. stig_ids narrows to benchmarks you already know and accepts at most 200; to scope a system you cannot name, pass system_description instead and let the resolver do it. If the knowledge base is not built yet this returns {"status": "not_ready"} with the commands to run, rather than an error.
| Name | Required | Description | Default |
|---|---|---|---|
| severity | No | ||
| stig_ids | No | ||
| technique_id | Yes | ||
| system_description | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so: it discloses the response envelope (summary, rules found, cat_i, controls_with_rules), that findings lack check/fix text, that revoked techniques are redirected and reported via technique.redirected_from, and that an unbuilt KB returns {"status": "not_ready"} instead of an error.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose, then response shape, then parameter guidance. Dense but nearly every sentence adds a distinct behavioral fact; the length is justified by the amount of non-obvious behavior it must convey, though it could be tightened slightly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema or annotations exist, yet the description sketches the return structure, the redirect field, and the not_ready case, which is everything an agent needs to call and interpret this tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must compensate, and it documents all four: severity's CAT-level semantics with an example, stig_ids' cap and intended use, system_description's build string format with an ESXi example and rationale, and technique_id's redirect behavior.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a precise verb+resource pair ('Return 800-53r5 controls and the DISA STIG findings that mitigate an ATT&CK technique') and distinguishes itself from the sibling finding_details by naming what it does not return (check/fix text). An agent can tell exactly what this produces.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit routing rules: use finding_details for exact DISA steps, pass system_description when you cannot name a system, use stig_ids only for benchmarks you already know. It also states the 200-item cap and what severity accepts, so the agent knows when each parameter applies.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
resolve_systemA
Resolve a free-text system description to candidate DISA STIG(s). Returns 'candidates' and 'notes'. limit caps the number of distinct benchmarks returned, not rows: a benchmark holding more than one STIG major (for example vSphere 8.0) contributes every major as its own row, so a caller asking for limit=5 may receive more than 5 rows. Include the product build where one exists (e.g. 'ESXi 8.0 U3'); each candidate reports whether it applies to that build in the 'applicable' field. When the description names a product version this knowledge base does not hold, a note in 'notes' says so and names the versions it does hold. A description naming more than one system is split on 'and' and commas and each part judged separately, so it can carry one such note per part, each quoting the part it is about. When more benchmarks tie with the last benchmark shown than limit allows, a note in 'notes' says how many and suggests calling again with a higher limit. If the knowledge base is not built yet this returns {"status": "not_ready"} with the commands to run, rather than an error.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| system_description | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and discharges it: it explains the limit semantics (caps distinct benchmarks, not rows, and can yield more rows than limit), the 'applicable' field, the tie-overflow note, and the not_ready status with remediation commands instead of an error. This is unusually rich operational disclosure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and return shape are front-loaded, and each sentence carries information. It is dense and runs long, with the tie-note and multi-part-note behavior occupying separate sentences that could be tightened, but nothing is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, so the description must describe returns itself; it names 'candidates', 'notes', the 'applicable' field, and the not_ready shape. For a 2-parameter lookup tool with no annotations, everything an agent needs to call and interpret it is present.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must compensate and does: limit is explained in depth (benchmarks vs rows, multi-major benchmarks contributing several rows), and system_description gets guidance on including build strings and how multi-system input is parsed. Both parameters gain meaning beyond their bare schema titles.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence states a specific verb (resolve) and resource (free-text system description → candidate DISA STIGs), and the tool is clearly distinguishable from siblings like list_stigs or search_techniques. An agent can tell what it returns ('candidates' and 'notes') without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives strong input-shaping advice (include the product build, multi-system descriptions are split on 'and'/commas) but never states when to prefer this over list_stigs or another sibling, nor any explicit when-not-to-use condition. Usage is implied rather than contrasted against alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_techniquesA
Search ATT&CK techniques by name or id. Ids and names ATT&CK has revoked also match, returning the replacement technique with redirected_from set to the old id. If the knowledge base is not built yet this returns {"status": "not_ready"} with the commands to run, rather than an error.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| query | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses that revoked ids/names still match and return a replacement with redirected_from set, and that an unbuilt knowledge base yields {"status": "not_ready"} with commands rather than an error. It does not mention pagination, result caps, or auth needs, so it is not exhaustive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, each earning its place: the core purpose first, then revoked-id behavior, then the not-ready edge case. No filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema and no annotations, the description covers the important edge cases (revoked techniques, unbuilt knowledge base) well. It is only slightly incomplete in not describing the 'limit' parameter or the shape of successful results.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must compensate. It adds real meaning for 'query' (matches by name or id, including revoked ids), but 'limit' (default 10) is never explained and no query syntax or matching semantics are given.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (search) and resource (ATT&CK techniques) plus the matching keys (name or id). It is clearly distinct from siblings like mitigations_for_technique or techniques_for_actor, but it never names or contrasts those siblings explicitly, so it falls short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The purpose implies when to use it, but there is no explicit when/when-not guidance and no routing to alternatives such as techniques_for_actor or mitigations_for_technique. Usage is left to be inferred from the verb.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
techniques_for_actorA
List an ATT&CK actor's techniques, optionally expanded with mitigations for given systems. actor is an ATT&CK group id, name or alias; case, spacing, punctuation and a trailing "Group" or "Team" are ignored, and actor.matched_as then names what matched. actor.also_matches, when present, lists other groups the same label loosely names. A misspelling is not corrected: the error names the closest groups, so call again with the group id of the one meant. The answer opens with summary, which counts the techniques; with include_mitigations it adds the same counts mitigations_for_technique gives, across every technique. Use those counts rather than counting lists yourself. controls lists each control once with its rule ids, and findings lists each finding once, without check or fix text (call finding_details for those). Each technique lists its control ids grouped by where the mapping came from ("ctid" or "override"). stig_ids accepts at most 200; it and severity (CAT levels, e.g. ["I"]) are validated always but only take effect with include_mitigations. To scope a system you cannot name, pass system_description instead. If the knowledge base is not built yet this returns {"status": "not_ready"} with the commands to run, rather than an error.
| Name | Required | Description | Default |
|---|---|---|---|
| actor | Yes | ||
| severity | No | ||
| stig_ids | No | ||
| system_description | No | ||
| include_mitigations | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so: it discloses actor-matching normalization (case, spacing, punctuation, trailing Group/Team), matched_as/also_matches behavior, that misspellings are not auto-corrected, and the exact not_ready return shape instead of an error. It also explains the response structure and control-id provenance grouping.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense but front-loaded, leading with purpose and expansion option before edge cases. Every sentence carries information, though the middle section is packed and could be broken into clearer chunks.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema or annotations exist, so the description must explain both behavior and return shape, which it does (summary counts, controls, findings, per-technique control ids by source). An agent has everything needed to call it and interpret the result.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, but the description gives meaning to all five parameters: actor accepts id/name/alias with fuzzy matching rules, severity takes CAT levels like ["I"], stig_ids is capped at 200, system_description scopes an unnameable system, and include_mitigations gates the other two. This fully compensates for the empty schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource ('List an ATT&CK actor's techniques') and immediately states the expansion option. It distinguishes itself from siblings by name, noting that mitigations_for_technique gives the same counts and that finding_details should be called for check/fix text.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-to-use guidance for nearly every branch: include_mitigations activates severity/stig_ids, system_description is the fallback for unnameable systems, and a misspelled actor should be retried with the closest group id. It even states the not_ready path and its remedy.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
8 tool updates
v0.1.1- First observed
check_sources - First observed
finding_details - First observed
install_knowledge_base - First observed
list_stigs - First observed
mitigations_for_technique - First observed
resolve_system - First observed
search_techniques - First observed
techniques_for_actor
TDQS
Scored across 8 tools
Tools are largely distinct: search_techniques finds ATT&CK techniques, mitigations_for_technique maps a technique, techniques_for_actor maps an actor, and finding_details fetches check/fix text. Minor overlap exists between mitigations_for_technique and techniques_for_actor with include_mitigations, and resolve_system vs list_stigs both surface STIGs, but the descriptions differentiate them well.
All names use snake_case, but the set mixes verb_noun names (search_techniques, resolve_system, list_stigs, install_knowledge_base, check_sources) with noun_phrase names (mitigations_for_technique, techniques_for_actor, finding_details). The pattern is readable but not a single predictable convention.
Eight tools is well within the 3-15 range and each has a clear role: discovery, mapping, detail retrieval, system resolution, STIG listing, and knowledge-base lifecycle. No tool feels redundant or missing from a count perspective.
The surface covers the primary workflow: find technique or actor, get mapped controls/findings, then fetch DISA check/fix text, plus STIG discovery and KB install/check. Some reverse-lookup or bulk-finding operations are absent, such as control-to-technique lookup or all findings for a STIG, but agents can work around these via existing mapping and detail tools.
Maintenance
Related MCP Connectors
Query and retrieve information about various adversarial tactics and techniques used in cyber atta…
2,029 DISA STIG rules with official check/fix text, CCI mappings, and .ckl checklist export.
Live threat intel for agents: incidents, actors, CVEs with KEV/EPSS, ransomware leak-site victims.
MITRE ATT&CK MCP — STIX bundles from github.com/mitre/cti.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables querying the MITRE ATT\&CK framework for adversarial tactics, techniques, mitigations, and detection methods through natural language, supporting both ID-based and fuzzy name-based searches.3-
- AlicenseAqualityDmaintenanceEnables AI-native access to the MITRE ATT\&CK framework, allowing LLMs and agents to query techniques, threat groups, software, and generate ATT\&CK Navigator layers for threat intelligence and security workflows.6554 npm5Apache 2.0
- AlicenseBqualityDmaintenanceEnables cyber defenders to query ATT\&CK techniques, list tactics, map incidents to techniques, look up threat actor groups and mitigations, all via the MCP protocol.5MIT
- FlicenseNot gradedqualityDmaintenanceProvides search, detail lookup, and gap listing tools for a security control inventory, enabling natural language queries about control status and gaps.-