stig-mcp
stig-mcp is a local, read-only MCP server that answers security questions from a ~6 MB local knowledge base — mapping MITRE ATT&CK techniques and actors to NIST SP 800-53 controls, DISA STIG rules, and ATT&CK mitigations/detections — without scanning or connecting to your systems.
Technique → mitigations:
mitigations_for_techniquereturns 800-53r5 controls and DISA STIG findings for an ATT&CK technique, with counts (rules, per-CAT, controls with rules), CAT severity filtering,stig_idsscoping (max 200), build-awaresystem_description, and revoked-technique redirects.Actor → techniques:
techniques_for_actorlists an ATT&CK group's techniques (id, name, or alias, typo-tolerant errors), optionally expanded with per-system mitigations viainclude_mitigations.Exact DISA text:
finding_detailsreturns check and fix text for up to 50 rule ids (SV-…r…_rule) or V- ids, with benchmark, release, and CCIs; V- ids are preferred and may match multiple benchmarks.System resolution:
resolve_systemturns a free-text system description into candidate STIG benchmarks, flagging build applicability and noting unknown versions or ties.Discovery:
search_techniquesfinds techniques by name or id (including revoked ones);list_stigslists/filters benchmarks by title, id, or keywords.Knowledge base management:
install_knowledge_basedownloads and SHA-256-verifies the prebuilt KB from GitHub releases, pins a release for rollback, or installs offline from a local path + hash;check_sourcesreports whether a newer KB exists and whether to install, upgrade the package, or build locally.Offline-friendly: tools return
{"status": "not_ready"}with next commands instead of erroring; onlyinstall_knowledge_baseandcheck_sourcesuse the network (limited to this project's GitHub hosts).
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
A local MCP (Model Context Protocol) server that lets an AI assistant, such as GitHub Copilot in VS Code or Claude Code, answer security questions from published guidance instead of from memory. Name a MITRE ATT&CK® technique or threat actor and the system you care about, and the answer gives you:
the NIST SP 800-53 security controls that mitigate it;
the DISA STIG configuration rules that implement those controls on that system, most severe first, with DISA's check and fix text on request;
ATT&CK's own mitigations, and which of its detections work with the logs you collect.
It does not scan or connect to your systems. Its answers come from a knowledge base, a local database of about 6 MB built from those public sources, which you install once. The user guide explains what it does and shows three ways to use it: as a security controls assessor, a system owner, or a SOC analyst.
Prerequisite
stig-mcp is published on PyPI and runs through uvx,
which comes with uv.
Install uv, then check that
uvx --version runs in a new terminal. Restart VS Code or Claude Code after installing uv
so it sees the new PATH.
Related MCP server: MITRE ATT&CK MCP Server
Quick start
VS Code (GitHub Copilot)
Click this badge. VS Code opens and offers to install stig-mcp; choose Install.
Open Copilot Chat and set the mode dropdown to Agent. MCP tools are not available in Ask or Edit mode.
Ask:
Install the stig-mcp knowledge base.This is a one-time download of about 6 MB. Allow the tool when VS Code asks.
If that doesn't work, see troubleshooting or setting up VS Code by hand.
Claude Code
Inside a Claude Code session (2.1.275 or later), run:
/plugin install stig-mcp --marketplace jeneric/STIG-MCPAsk:
Install the stig-mcp knowledge base.This is a one-time download of about 6 MB. Allow the tool when Claude Code asks.
If that doesn't work, see troubleshooting or setting up Claude Code by hand.
Example prompts
With the knowledge base installed, try:
System owner:
What DISA STIG steps mitigate T1078 on Windows 11?Security controls assessor:
Which ATT&CK techniques does APT29 use?Anyone, to find the right STIG:
Which STIG benchmarks apply to RHEL 9?SOC analyst:
What can I detect of APT29 on Windows Server 2022 with Security and Sysmon logs?
More example prompts are in the user guide, with how to get more out of it and how to make sure the agent answers from the server.
Other MCP clients
Use this only if you are not using VS Code or Claude Code. Any client that launches a local
(stdio) MCP server works with this configuration, shown in the common mcpServers shape:
{
"mcpServers": {
"stig-mcp": {
"command": "uvx",
"args": ["stig-mcp"],
"env": { "UV_SYSTEM_CERTS": "true", "UV_NATIVE_TLS": "true" }
}
}
}The two environment variables let uv download stig-mcp behind a TLS-inspecting proxy. They are harmless on most other hosts; that section names the one exception. Then ask the agent to install the stig-mcp knowledge base, as in the quick start.
docs/install.md has the details:
manual VS Code and Claude Code setup
installing the knowledge base without an agent or without network access
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.
Documentation
docs/install.md: installation details for every client, where the data lives, and troubleshooting.
docs/user-guide.md: for a person talking to an LLM that has this server wired in.
docs/operations.md: for whoever installs, builds and maintains the knowledge base.
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
9 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.
defense_detailsA
Return MITRE's text for ATT&CK defenses named by id: mitigations (M1026), detection strategies (DET0103) and analytics (AN0286), as listed under protect.mitigations and detect in a defenses_for_technique answer or under each technique in a techniques_for_actor answer. ids takes up to 10 per call, matched case-insensitively. A mitigation returns its description and how many techniques it covers; with technique_id it also returns MITRE's text about that mitigation on that technique as technique_description, which is null when that mitigation is not paired with that technique (a revoked id answers for its replacement, reported in technique.redirected_from). A detection strategy returns every analytic in full: description, platforms, log_sources (name, channel and data component) and mutable_elements, the tunables a detection engineer sets. An analytic id returns that analytic alone. Analytics say what to collect, not how to enable it: the enabling steps are in the vendor's documentation. not_found lists ids that matched nothing; if none match, the call is refused. Quote MITRE's text as written and label anything you add as your own. 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 | ||
| technique_id | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full load and does so richly: per-id-family return shapes, technique_description being null when a mitigation is not paired with the technique, revoked ids answering for their replacement via technique.redirected_from, not_found listing unmatched ids, outright refusal when nothing matches, and a {"status": "not_ready"} fallback instead of an error. It even discloses a semantic caveat that analytics describe what to collect, not how to enable it.
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 action and the id families, then moving into return shapes and edge cases. It is a dense wall of text with long compound sentences, but nearly every clause conveys a distinct behavioral fact rather than repeating structured data.
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, yet the description specifies what comes back for each id family, the fields of a detection strategy and analytic, the null/redirect edge cases, the not_found contract, and the not_ready state. An agent has everything needed to call and interpret this correctly.
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 does: ids is documented as taking up to 10 case-insensitively matched identifiers, and technique_id is documented as adding technique_description to the response. It does not state that technique_id is only meaningful for mitigations (not detection strategies or analytics), leaving a small ambiguity.
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 — return MITRE's text for ATT&CK defenses named by id — and enumerates the three id families it accepts (M1026 mitigations, DET0103 detection strategies, AN0286 analytics). It also tells the agent where those ids come from (protect.mitigations / detect in a defenses_for_technique answer), which separates it from the sibling defenses_for_technique that discovers rather than resolves ids.
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?
Usage context is clear: this is the detail-lookup step after you already hold ids from defenses_for_technique or techniques_for_actor, and chunking is bounded at 10 ids per call. It never explicitly names an alternative tool or states a when-not-to-use condition, so it stops short of the top tier.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
defenses_for_techniqueA
Return the defenses the knowledge base holds for an ATT&CK technique: the 800-53r5 controls CTID maps to it, the DISA STIG findings that implement those controls on the systems you name, and ATT&CK's own mitigations and detection strategy. The answer opens with summary: rules found, rules per CAT, control_counts, mitigation and detection counts (detection counts analytics), cat_i (the CAT I V- ids with their count), then controls_with_rules. Use those counts rather than counting lists yourself. protect.controls maps each control id to its name, family, source and rules. A control's rules include those DISA tags to its enhancements (e.g. AC-6(9) under AC-6), since the ATT&CK mapping names base controls; via, when present, maps each enhancement to the rules that reach the control only through it. Each finding gives its benchmark (stig_id/version, described in resolved_systems), V- id and CAT; titles come with CAT I findings, or with every CAT named in severity; when any are missing, summary.titles reads "CAT I only", so never name or describe an untitled finding without fetching its title (call again with severity naming its CAT); call finding_details with rule ids or V- ids for DISA's check and fix text and the CCIs. 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. benchmark_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. platforms names ATT&CK platforms, e.g. ["Windows"], and detect.applicable then lists the analytics that apply to them; an unknown name is refused with the full list. log_sources names the telemetry you collect, with ATT&CK's log source names, in any case (e.g. ["WinEventLog:Security", "WinEventLog:Sysmon"]); log_sources takes up to 100 names. When platforms is given, detect.detectable lists (and summary.detection counts) only applicable analytics whose every log source is in the list; without platforms, every analytic whose log sources are all collected. detect.analytics maps each analytic id to its name and platforms; detect.applicable and detect.detectable list the qualifying ids and are present only when platforms or log_sources was given (absent: not judged; empty: none qualify). Mitigations are listed by id and name only: call defense_details with M-, DET- or AN- ids for MITRE's text, log sources and tunable elements.
| Name | Required | Description | Default |
|---|---|---|---|
| severity | No | ||
| platforms | No | ||
| log_sources | No | ||
| technique_id | Yes | ||
| benchmark_ids | No | ||
| 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 richly: it discloses the {"status": "not_ready"} state instead of an error, revoked-technique redirection via technique.redirected_from, the titles degradation rule ('CAT I only') with an explicit warning never to describe untitled findings, the 200-item cap on benchmark_ids and 100 on log_sources, and the precise present/absent/empty semantics of detect.applicable and detect.detectable.
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?
Almost every sentence carries non-redundant information, so the size is largely earned, but it is delivered as one massive unstructured block that jumps between return shape, parameter behavior and error states, making it hard to scan. Bullets or headers would preserve the content with far better retrieval.
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?
There is no output schema, and the description fully assumes that duty by walking through the response layout (summary counts, protect.controls, via mappings, detect.*, mitigations) and explaining how counts should be used rather than recomputed. Combined with the not_ready and redirect handling, an agent has everything needed 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 six parameters with formats, constraints and examples: severity narrows to CAT levels (e.g. ["I"]), platforms takes ATT&CK platform names and is validated, log_sources takes ATT&CK log source names case-insensitively up to 100, benchmark_ids caps at 200, and system_description should include the product build because it selects between STIG versions.
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 up front ('Return the defenses the knowledge base holds for an ATT&CK technique') and enumerates the three content families returned: 800-53r5 controls, DISA STIG findings, and ATT&CK mitigations/detection strategy. It distinguishes itself from siblings by directing detail lookups to finding_details and defense_details rather than doing everything itself.
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 clear routing conditions: call finding_details for check/fix text or CCIs, defense_details for M-/DET-/AN- ids, pass system_description when you cannot name a system, and benchmark_ids when you already know the benchmark. It does not, however, position itself against other entry points such as search_techniques or techniques_for_actor, so the top-level choice is left implicit.
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 defenses_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: it documents the refusal-on-no-match behavior, the not_found list, the {"status": "not_ready"} response for an unbuilt knowledge base, and the quoting/labeling protocol for check_text and fix_text. These are non-obvious behaviors an agent cannot infer from the schema.
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-loads the core purpose and the payload contents before the id mechanics, and every sentence adds actionable detail. It is dense and slightly long, but no sentence 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?
For a single-param tool with no output schema or annotations, the description covers the return contents, id semantics, error/refusal modes, and degraded-state response. An agent has everything needed to call it correctly.
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 does: it specifies the 50-id cap, the two accepted id formats (SV-...r..._rule and V- ids), the prefer-V- rule, and the multi-benchmark dedup behavior. This is far more than the bare string array in the 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: 'Return DISA's check and fix text for STIG findings,' and immediately names the payload fields (benchmark, release, CCIs). It is clearly distinguishable from siblings like defense_details or check_sources.
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?
Tells the agent where ids come from (defenses_for_technique, techniques_for_actor) and which id form to prefer (V- over rule id, with the release-matching rationale). It stops short of explicitly saying when to choose this tool over defense_details or check_sources, so no full exclusion clause.
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.
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 defenses 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_defenses it adds the same counts defenses_for_technique gives, across every technique. Use those counts rather than counting lists yourself. controls lists each control once with its rule ids, including rules DISA tags to its enhancements, which via names, and findings lists each finding once, without check or fix text (call finding_details for those), each naming its benchmark, V- id and CAT, with titles for CAT I or for the CATs named in severity; summary.titles reads "CAT I only" when the rest are missing, so fetch a title before naming an untitled finding. Each technique lists its control ids grouped by where the mapping came from ("ctid" or "override"). benchmark_ids accepts at most 200; it, severity (CAT levels, e.g. ["I"]), platforms and log_sources are validated always but only take effect with include_defenses. To scope a system you cannot name, pass system_description instead. With include_defenses each technique also lists its ATT&CK mitigations (M-ids), its detection strategy (DET-id), analytics (a map of AN-id to platforms, with applicable and detectable id lists as in defenses_for_technique), and gaps, the coverage classes the call can judge that count that technique as a gap (mitigated_without_rules needs a scoped system, without_applicable_analytic platforms, undetectable log_sources), so read gaps rather than deriving them. mitigations maps each M-id to its name once, while summary.mitigations counts mitigation references across techniques (one on two techniques counts twice). summary.coverage, which comes right after control_counts, counts techniques: without_mitigation, mitigated_without_rules (only when a system was scoped; with severity, no rules at the requested CAT levels), without_applicable_analytic (only with platforms), detectable and undetectable (only with log_sources); summary.detection counts analytics instead. Detection is judged applicability first when platforms is given, then detectability over the applicable analytics. Each technique's applicable and detectable id lists are judged as in defenses_for_technique, so with platforms detectable is always a subset of applicable; log_sources takes up to 100 names. Call defense_details with M-, DET- or AN- ids for MITRE's text. 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 | ||
| platforms | No | ||
| log_sources | No | ||
| benchmark_ids | No | ||
| include_defenses | No | ||
| system_description | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations present, the description carries the entire burden and does so unusually well: it discloses that misspellings are not auto-corrected and the error names nearest groups, that benchmark_ids caps at 200 and log_sources at 100, that severity/platforms/log_sources are validated but inert without include_defenses, that controls/findings are de-duplicated, and that an unbuilt knowledge base returns {"status": "not_ready"} rather than 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?
The purpose is front-loaded, but the body is a single dense paragraph of conditionals and nested return-shape semantics (summary.coverage, gaps, applicable/detectable id lists) with no structural breaks. Much of it is legitimately load-bearing given the complexity, yet grouping into sections would have made it materially easier to scan.
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 7-parameter tool with no output schema and no annotations, the description covers essentially everything an agent needs: normalization and error behavior, parameter limits, the effect of include_defenses, the shape of summary/counts/coverage/gaps, and the not_ready state. Nothing critical for correct invocation appears to be 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 for every one of the seven parameters: actor (id/name/alias, normalization rules, matched_as/also_matches), severity (CAT levels, e.g. ["I"]), platforms, log_sources, benchmark_ids, include_defenses, and system_description. This is far beyond what the bare schema conveys.
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 and resource: 'List an ATT&CK actor's techniques,' then qualifies scope with 'optionally expanded with defenses for given systems.' It also implicitly separates this tool from siblings by routing sub-data (defenses_for_technique, finding_details, defense_details) elsewhere, so an agent can tell what this tool owns.
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 concrete conditional guidance: use system_description 'to scope a system you cannot name,' call finding_details for check/fix text, and call defense_details for MITRE's text on M-/DET-/AN- ids. It also instructs the agent to retry with a group id after a misspelling. It never states when this tool should be preferred over siblings like search_techniques, so it stops short of full when/when-not coverage.
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.
4 tool updates
v0.1.2- Added
defense_details - Added
defenses_for_technique - Removed
mitigations_for_technique - Changed
techniques_for_actor6 fields changed- added
Input schema / properties / benchmark_idsAdded value: +{ + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Benchmark Ids" +} - added
Input schema / properties / include_defensesAdded value: +{ + "default": false, + "title": "Include Defenses", + "type": "boolean" +} - removed
Input schema / properties / include_mitigationsRemoved value: -{ - "default": false, - "title": "Include Mitigations", - "type": "boolean" -} - added
Input schema / properties / log_sourcesAdded value: +{ + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Log Sources" +} - added
Input schema / properties / platformsAdded value: +{ + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Platforms" +} - removed
Input schema / properties / stig_idsRemoved value: -{ - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Stig Ids" -}
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 9 tools
Most tools target distinct resources: resolve_system finds benchmarks, list_stigs enumerates them, finding_details and defense_details fetch text for specific ids, and install/check handle the knowledge base. The main overlap is between defenses_for_technique and techniques_for_actor, since the latter's include_defenses effectively re-runs the former's logic, and resolve_system vs list_stigs both deal with the benchmark catalog. The very detailed descriptions mitigate most of this, so an agent can usually pick correctly.
All names use snake_case consistently, with no casing chaos. The convention is only split between action-led names (resolve_system, list_stigs, search_techniques, check_sources, install_knowledge_base) and noun-phrase lookups (finding_details, defense_details, defenses_for_technique, techniques_for_actor), which reads a bit mixed but remains predictable and readable.
Nine tools is well within a healthy range and each appears to earn its place: a handful of query tools, two detail-fetch tools, and two knowledge-base lifecycle tools. Nothing feels redundant or thin.
The surface covers the full workflow: resolving systems, listing STIGs, fetching finding check/fix text, mapping techniques/actors to defenses and controls, fetching MITRE defense text, and installing/updating the knowledge base. A minor gap is a direct control-id lookup (controls are only reachable through technique/actor queries), but this is largely workable.
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 gradedqualityFmaintenanceEnables 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.6537 npm5Apache 2.0
- AlicenseBqualityCmaintenanceEnables 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.-