mcp-hayabusa
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-hayabusascan 4794_DSRM_password_change_t1098.evtx for high severity"
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.
mcp-hayabusa
An MCP server with two layers: it wraps the Hayabusa CLI, exposing a scan_evtx tool for analyzing Windows EVTX event log files and a get_hayabusa_rules tool for browsing its detection rule set; and it doubles as a detection-engineering knowledge base, exposing a curated Sigma rule set and MITRE ATT&CK technique/coverage lookups as detection:// resources, an analyze_coverage tool for querying that coverage directly (by technique ID or by tactic), and a suggest_rule tool that, for an uncovered technique, surfaces MITRE's own suggested detection approach and can scaffold a rule template into ./rules/.
Requirements
Python 3.10+ (uses the
X | Nonetype-hint syntax)The
mcplibrary (pip install -r requirements.txt)The Hayabusa CLI, extracted to
./hayabusa/(see Setup below)The MITRE ATT&CK Enterprise STIX bundle, extracted to
./attack/(see Setup below) — only required for thedetection://attack/techniques/{technique_id}resource and theanalyze_coverage/suggest_ruletools
Related MCP server: mcp-hayabusa
Setup
pip install -r requirements.txt
python scripts/download_hayabusa.pydownload_hayabusa.py detects your OS/architecture, downloads the matching release asset from Hayabusa's latest GitHub release, and extracts it into ./hayabusa/ (binary, rules/, config/). This directory is gitignored — re-run the script after cloning, or whenever you want to pick up a newer Hayabusa release.
Optional, for manual testing:
python scripts/download_sample_evtx.pyDownloads one real attack-technique sample (4794_DSRM_password_change_t1098.evtx) from EVTX-ATTACK-SAMPLES into ./samples/ (also gitignored).
Required for the detection://attack/techniques/{technique_id} resource and the analyze_coverage/suggest_rule tools:
python scripts/download_attack_data.pyDownloads the MITRE ATT&CK Enterprise STIX bundle (~50MB) from attack-stix-data into ./attack/enterprise-attack.json (gitignored). Re-run it whenever you want to pick up a newer ATT&CK release — the server caches the parsed data in memory for the life of the process, so restart server.py afterward to pick up the change.
Running the server
python server.pyThe server communicates over stdio, so it's meant to be launched by an MCP client (e.g. Claude Code), not run interactively. With no client attached, it reads EOF from stdin and exits immediately — that's expected, not a bug.
To register it with Claude Code locally, add it to .mcp.json at the project root:
{
"mcpServers": {
"hayabusa": {
"command": "python",
"args": ["server.py"],
"cwd": "C:/path/to/mcp-hayabusa"
}
}
}MCP server definitions aren't read from settings.json/settings.local.json (those are for permissions/hooks/env) — .mcp.json is the file Claude Code actually checks. It's gitignored here because cwd is an absolute, machine-specific path; each collaborator creates their own.
Registering with Claude Desktop
Claude Desktop uses a separate config file from .mcp.json, and doesn't support a cwd key, so pass an absolute path to server.py in args instead:
{
"mcpServers": {
"hayabusa": {
"command": "python",
"args": ["C:/path/to/mcp-hayabusa/server.py"]
}
}
}Finding the right file to edit takes a bit of care on Windows:
On a standard (non-Store) install, it's
%APPDATA%\Claude\claude_desktop_config.json.On the MSIX-packaged Store build, Windows redirects the app's
%APPDATA%to a virtualized path — editing%APPDATA%\Claude\...from outside the app (e.g. a terminal) touches an inert file the app never reads. The real file is%LOCALAPPDATA%\Packages\<Claude package ID>\LocalCache\Roaming\Claude\claude_desktop_config.json. Check%LOCALAPPDATA%\Packagesfor a folder starting withClaude_if you're not sure which build you have.
Fully quit and relaunch Claude Desktop after editing (not just close the window). Per-server connection logs land in logs\mcp-server-hayabusa.log next to the config file — check there first if a server shows as disconnected; it logs the exact command/args/cwd used to launch it and any stderr from the process.
The scan_evtx tool
scan_evtx(
file_path: str,
min_severity: str | None = None,
rule_filter: str | None = None,
output_format: str = "summary",
max_results: int | None = None,
) -> dictParameter | Required | Description |
| yes | Path to the |
| no | Minimum severity to include: |
| no | Case-insensitive substring matched against each finding's rule title (e.g. |
| no |
|
| no | Caps the number of findings returned. |
Success response
{
"file": "samples/4794_DSRM_password_change_t1098.evtx",
"min_severity": null,
"rule_filter": null,
"output_format": "summary",
"count": 1,
"returned": 1,
"truncated": false,
"findings": [
{
"Timestamp": "2017-06-09 15:21:26.968 -04:00",
"RuleTitle": "Password Change on Directory Service Restore Mode (DSRM) Account",
"Level": "high",
"Computer": "2016dc.hqcorp.local",
"EventID": 4794,
"RecordID": 3139859
}
]
}count is the total matching findings after rule_filter (before any max_results cap); returned is how many are actually in findings; truncated is true if max_results cut the list short. Pass output_format="full" to get every field Hayabusa produced (Channel, Details, ExtraFieldInfo, RuleID, etc.) instead of the trimmed summary shape shown above.
Error response
Every failure mode returns {"error": "..."} (plus stderr/returncode where applicable) instead of raising:
Situation | Example error |
File doesn't exist |
|
Invalid |
|
Invalid |
|
Invalid |
|
Hayabusa binary missing |
|
Hayabusa exits non-zero |
|
Scan takes too long |
|
Output unparseable |
|
The get_hayabusa_rules tool
get_hayabusa_rules(keyword: str | None = None, max_results: int | None = 50) -> dictLists detection rules from the local ./hayabusa/rules/ checkout (~5,000 Sigma + Hayabusa-native rules) — useful for discovering what rules exist, and their exact titles/tags, before scanning (e.g. to pick a value for scan_evtx's rule_filter).
Parameter | Required | Description |
| no | Case-insensitive substring matched against each rule's title, description, and tags. |
| no | Caps the number of rules returned. Defaults to |
Success response
{
"keyword": "mimikatz",
"count": 24,
"returned": 24,
"truncated": false,
"rules": [
{
"title": "Mimikatz Use",
"id": "06d71506-7beb-4f22-8888-e2e5e2ca7fd8",
"level": null,
"status": "test",
"ruletype": "sigma",
"tags": ["attack.s0002", "attack.lateral-movement", "attack.t1003.002"],
"description": "This method detects mimikatz keywords in different Eventlogs..."
}
]
}Rule fields are extracted with a lightweight line-scan, not a full YAML parser (see Notes below), so level/status/tags/description are null/empty when a given rule doesn't define that field at the top level.
Error response
Situation | Example error |
Rules directory missing |
|
Invalid |
|
Detection engineering knowledge base resources
Alongside the two tools above, the server exposes a curated Sigma rule set (./rules/, checked into git — distinct from the full ./hayabusa/rules/ checkout used by get_hayabusa_rules) and MITRE ATT&CK lookups as four detection:// MCP resources. Resources are browsable/discoverable rather than invoked with arguments, and a not-found lookup raises an MCP ResourceError instead of returning a {"error": ...} dict (that convention is tool-specific — see the scan_evtx/get_hayabusa_rules sections above). Two more tools wrap this same data: analyze_coverage for direct technique/tactic coverage queries, and suggest_rule for turning an uncovered technique into a detection suggestion (and optionally a rule scaffold) — see their own sections below.
detection://rules
Lists all rules in ./rules/ (currently 33: hand-authored plus a curated selection copied from upstream SigmaHQ/sigma, covering credential-access, lateral-movement, persistence, and (via one Azure AD rule) cloud identity techniques).
{
"count": 33,
"rules": [
{
"rule_name": "lsass_process_access",
"title": "Suspicious Process Access to LSASS Memory",
"id": "fe41d923-d63b-45bb-8c85-bbfb6886b6b3",
"level": "high",
"status": "test",
"tags": ["attack.credential-access", "attack.t1003.001", "attack.s0002"],
"techniques": ["T1003.001"],
"description": "Detects non-standard processes requesting access to lsass.exe with access"
}
]
}detection://rules/{rule_name}
Returns one rule's raw YAML content, looked up by filename stem (case-insensitive, extension optional — lsass_process_access, lsass_process_access.yml, and LSASS_Process_Access all resolve the same file). Raises if rule_name doesn't match any file in ./rules/.
detection://rules/by-technique/{technique_id}
Lists rules tagged with a given ATT&CK technique ID (case-insensitive, T prefix optional — t1003.001 and T1003.001 are equivalent). An unmatched technique returns count: 0, not an error.
{
"technique_id": "T1021.002",
"count": 2,
"rules": [ /* ... matching rule summaries, same shape as detection://rules ... */ ]
}detection://attack/techniques/{technique_id}
Looks up a technique in the downloaded MITRE ATT&CK data and cross-references it against ./rules/ in one call: what the technique is, whether we detect it, and how well.
{
"technique_id": "T1003.001",
"name": "LSASS Memory",
"description": "Adversaries may attempt to access credential material stored in the process memory of the Local Security Authority Subsystem Service (LSASS)...",
"is_subtechnique": true,
"url": "https://attack.mitre.org/techniques/T1003/001",
"rules": [ /* ... matching rule summaries ... */ ],
"rule_count": 3,
"coverage": "covered"
}coverage is one of:
Value | Meaning |
| At least one rule is tagged with this exact technique ID. |
| No exact-match rule, but the parent technique (for a sub-technique ID) or a sibling sub-technique (for a parent ID) is covered — related detection logic may catch some, but not all, variants. |
| Nothing in |
Raises if the ATT&CK data hasn't been downloaded yet (run scripts/download_attack_data.py first) or if technique_id isn't a real ATT&CK technique.
The analyze_coverage tool
analyze_coverage(target: str) -> dictA tool (not a resource) that answers the same "what's our coverage?" question as detection://attack/techniques/{technique_id}, but takes either a single technique ID or a whole tactic, and — for a tactic — reports coverage across every technique in it in one call, rather than requiring one lookup per technique. Combines the same two sources as the detection:// resources above: the downloaded ATT&CK STIX data and the curated ./rules/ Sigma set.
Parameter | Required | Description |
| yes | Either an ATT&CK technique ID ( |
Success response — technique
{
"target_type": "technique",
"technique_id": "T1558.003",
"name": "Kerberoasting",
"tactics": ["credential-access"],
"coverage": "covered",
"rule_count": 2,
"rules": [ /* ... matching rule summaries, same shape as detection://rules ... */ ]
}Success response — tactic
{
"target_type": "tactic",
"tactic": "Credential Access",
"technique_count": 67,
"covered_count": 16,
"partial_count": 18,
"gap_count": 33,
"covered": [ {"technique_id": "T1003.001", "name": "LSASS Memory", "rule_count": 3}, "..." ],
"partial": [ /* same shape as covered */ ],
"gaps": [ /* same shape, rule_count is always 0 */ ]
}coverage (technique form) and each technique's bucket placement (tactic form) use the same covered/partial/gap logic documented under detection://attack/techniques/{technique_id} above.
Error response
Like scan_evtx/get_hayabusa_rules (and unlike the detection:// resources), failures return {"error": ...} rather than raising:
Situation | Example error |
Empty/blank |
|
ATT&CK data not downloaded |
|
Unknown technique ID |
|
Unrecognized tactic name |
|
The suggest_rule tool
suggest_rule(technique_id: str, create_template: bool = False) -> dictChecks coverage for a single ATT&CK technique the same way analyze_coverage/detection://attack/techniques/{technique_id} do. If it's already "covered", returns the existing rules and stops. Otherwise, surfaces MITRE's own suggested detection approach (when one exists) and, optionally, scaffolds a starting-point rule file into ./rules/.
MITRE's detection guidance comes from the ATT&CK STIX bundle itself, not from ./rules/: newer ATT&CK data links each technique to one or more "detection strategies," each carrying one or more "analytics" — a human-written description of what to look for, plus candidate log sources. Not every technique has one; when a technique has none, suggestion.mitre_analytics is an empty list and suggestion.notes says so.
Parameter | Required | Description |
| yes | An ATT&CK technique ID, e.g. |
| no | If |
Success response — already covered
{
"technique_id": "T1003.001",
"name": "LSASS Memory",
"coverage": "covered",
"existing_rules": [ /* ... matching rule summaries, same shape as detection://rules ... */ ],
"message": "Already covered by ./rules/ — no suggestion needed."
}Success response — gap or partial, with a suggestion
{
"technique_id": "T1552.006",
"name": "Group Policy Preferences",
"coverage": "gap",
"related_rules": [ /* rules covering a parent/sibling technique, if any */ ],
"suggestion": {
"mitre_analytics": [
{
"name": "Analytic 1075",
"description": "Correlates file enumeration of XML files in the SYSVOL share with suspicious process execution that decodes or reads encrypted credentials embedded in Group Policy Preference files...",
"log_sources": [
{"name": "WinEventLog:Sysmon", "channel": "EventCode=11"},
{"name": "WinEventLog:Security", "channel": "EventCode=5145"}
]
}
],
"notes": "MITRE-published analytics above are a starting point for a Sigma rule's detection: block."
},
"template_created": false,
"template_path": null
}With create_template=true, template_created is true and template_path holds the new file's path relative to the project root (e.g. "rules\\suggested_t1552_006_group_policy_preferences.yml"). The generated file has status: experimental, an empty selection: {} in its detection: block, and inline TODO comments — it's a scaffold, not a working rule.
Important caveat: coverage everywhere in this project (detection://, analyze_coverage, suggest_rule itself) is purely tag-derived — it has no concept of whether a rule's detection logic actually does anything. The moment a template is written, it carries the technique's tag, so a second call for the same technique will report coverage: "covered" and return the empty template as an "existing rule" — even though selection: {} matches nothing. Treat generated templates as placeholders that need real detection logic before they should count as real coverage.
Error response
Situation | Example error |
Unknown technique ID |
|
ATT&CK data not downloaded |
|
Template file already exists |
|
Testing
python tests/test_scan_evtx.pyA manual script (not a pytest suite) that exercises the original two tools: scan_evtx against the sample downloaded by download_sample_evtx.py (default/full output_format, min_severity, rule_filter, max_results, and error cases), and get_hayabusa_rules against the local rule set (default cap, keyword filtering, and error cases). It does not cover the detection:// resources, analyze_coverage, or suggest_rule — those were verified manually via mcp.read_resource() / direct calls.
Notes
Severity filtering is delegated to Hayabusa's own
-m/--min-levelflag rather than reimplemented in Python;rule_filter,output_format, andmax_resultshave no Hayabusa CLI equivalent, so they're applied as post-processing in Python.Output parsing uses Hayabusa's
-L/JSONL mode. Hayabusa's default-o(non--L) output is pretty-printed JSON objects concatenated with no array wrapper — not valid JSON or JSONL — so-Lis required for reliable parsing.get_hayabusa_rulesparses rule YAML with regex line-scanning instead of a full YAML parser, to avoid adding a PyYAML dependency for what's just a fuzzy listing tool — Hayabusa itself does the real YAML parsing when a rule is actually used to scan../rules/is a deliberately curated cross-section of upstream Sigma, not a full mirror (~4,700 files across all platforms) — that was considered and rejected: it would duplicate./hayabusa/rules/, blow up repo size, and (given./rules/'s flat, non-hayabusa/sigma-subdirectory layout) risk filename collisions in the by-stem rule lookup.The MITRE ATT&CK STIX bundle (~50MB) is parsed once and cached in memory for the server process's lifetime, not re-parsed per request — it's static data that doesn't change while the server runs.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Flicense-qualityCmaintenanceEnables an LLM client to scan Windows event log files (EVTX) for suspicious activity using Hayabusa, and browse its detection rules directly in conversation.Last updated
- Flicense-qualityBmaintenanceEnables scanning Windows EVTX event log files with Hayabusa, returning structured detection results through an MCP tool.Last updated
- AlicenseAqualityBmaintenanceEnables MCP clients to run Hayabusa detection scans over Windows event log (.evtx) files for forensic analysis and threat hunting.Last updated2MIT
- Flicense-qualityCmaintenanceEnables EVTX (Windows Event Log) analysis via Hayabusa, providing tools to scan event logs and retrieve detection rules.Last updated
Related MCP Connectors
Security scanner for MCP servers. Detect vulnerabilities, prompt injection, and tool poisoning.
An MCP server that let you interact with Cycloid.io Internal Development Portal and Platform
A paid remote MCP for ClawManager, built to return verdicts, receipts, usage logs, and audit-ready J
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/baobao26/mcp-hayabusa'
If you have feedback or need assistance with the MCP directory API, please join our Discord server