Security Detections MCP

Search and map Sigma, Splunk, Elastic, KQL and other detection rules against MITRE ATT&CK

By Michael Haag (individual) TypeScript Remote (hosted) · Streamable HTTPLocal · stdio Security

57 popularity score ★ 524 ↓ 1.0k/wk

Connect your client

Remote (hosted)

Add in one click

Opens the app, which asks before it adds the server. Then replace each <NAME> in its settings with your value.

Or add it by command or config

Cursor~/.cursor/mcp.json
{
  "mcpServers": {
    "security-detections": {
      "url": "https://detect.michaelhaag.org/api/mcp/mcp",
      "headers": {
        "Authorization": "Bearer <SDMCP_TOKEN>"
      }
    }
  }
}
VS CodeVS Code MCP config
{
  "servers": {
    "security-detections": {
      "type": "http",
      "url": "https://detect.michaelhaag.org/api/mcp/mcp",
      "headers": {
        "Authorization": "Bearer <SDMCP_TOKEN>"
      }
    }
  }
}
Claude Codeterminal
claude mcp add --transport http security-detections https://detect.michaelhaag.org/api/mcp/mcp --header "Authorization: Bearer <SDMCP_TOKEN>"
Claude Desktopclaude_desktop_config.json
{
  "mcpServers": {
    "security-detections": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://detect.michaelhaag.org/api/mcp/mcp",
        "--header",
        "Authorization: Bearer <SDMCP_TOKEN>"
      ]
    }
  }
}
Codexterminal
export SDMCP_TOKEN="<SDMCP_TOKEN>" && codex mcp add security-detections --url https://detect.michaelhaag.org/api/mcp/mcp --bearer-token-env-var SDMCP_TOKEN
Local (npm)

Add in one click

Opens the app, which asks before it adds the server. Then replace each <NAME> in its settings with your value.

Or add it by command or config

It needs SIGMA_PATHS. Replace each <NAME> with your value.

Claude CodeTerminal
claude mcp add security-detections -e SIGMA_PATHS=<SIGMA_PATHS> -- npx -y security-detections-mcp
Claude Desktopclaude_desktop_config.json
{
  "mcpServers": {
    "security-detections": {
      "command": "npx",
      "args": [
        "-y",
        "security-detections-mcp"
      ],
      "env": {
        "SIGMA_PATHS": "<SIGMA_PATHS>"
      }
    }
  }
}
Cursor~/.cursor/mcp.json
{
  "mcpServers": {
    "security-detections": {
      "command": "npx",
      "args": [
        "-y",
        "security-detections-mcp"
      ],
      "env": {
        "SIGMA_PATHS": "<SIGMA_PATHS>"
      }
    }
  }
}
VS Code.vscode/mcp.json
{
  "servers": {
    "security-detections": {
      "type": "stdio",
      "command": "npx",
      "args": [
        "-y",
        "security-detections-mcp"
      ],
      "env": {
        "SIGMA_PATHS": "<SIGMA_PATHS>"
      }
    }
  }
}
Codex~/.codex/config.toml
[mcp_servers.security-detections]
command = "npx"
args = ["-y", "security-detections-mcp"]

[mcp_servers.security-detections.env]
SIGMA_PATHS = "<SIGMA_PATHS>"
Gemini CLITerminal
gemini mcp add --scope user -e SIGMA_PATHS=<SIGMA_PATHS> security-detections npx -- -y security-detections-mcp
Local (from source)

Add in one click

Opens the app, which asks before it adds the server. Then replace each <NAME> in its settings with your value.

Or add it by command or config

It needs SIGMA_PATHS. Replace each <NAME> with your value.

FirstTerminal
git clone https://github.com/MHaggis/Security-Detections-MCP.git
cd Security-Detections-MCP
npm install
npm run build
Claude CodeTerminal
claude mcp add security-detections -e SIGMA_PATHS=<SIGMA_PATHS> -- node '<ABSOLUTE_PATH_TO_CLONE>/dist/index.js'
Claude Desktopclaude_desktop_config.json
{
  "mcpServers": {
    "security-detections": {
      "command": "node",
      "args": [
        "<ABSOLUTE_PATH_TO_CLONE>/dist/index.js"
      ],
      "env": {
        "SIGMA_PATHS": "<SIGMA_PATHS>"
      }
    }
  }
}
Cursor~/.cursor/mcp.json
{
  "mcpServers": {
    "security-detections": {
      "command": "node",
      "args": [
        "<ABSOLUTE_PATH_TO_CLONE>/dist/index.js"
      ],
      "env": {
        "SIGMA_PATHS": "<SIGMA_PATHS>"
      }
    }
  }
}
VS Code.vscode/mcp.json
{
  "servers": {
    "security-detections": {
      "type": "stdio",
      "command": "node",
      "args": [
        "<ABSOLUTE_PATH_TO_CLONE>/dist/index.js"
      ],
      "env": {
        "SIGMA_PATHS": "<SIGMA_PATHS>"
      }
    }
  }
}
Codex~/.codex/config.toml
[mcp_servers.security-detections]
command = "node"
args = ["<ABSOLUTE_PATH_TO_CLONE>/dist/index.js"]

[mcp_servers.security-detections.env]
SIGMA_PATHS = "<SIGMA_PATHS>"
Gemini CLITerminal
gemini mcp add --scope user -e SIGMA_PATHS=<SIGMA_PATHS> security-detections node -- '<ABSOLUTE_PATH_TO_CLONE>/dist/index.js'

Settings 9

SIGMA_PATHS Required: Comma-separated Sigma rule folders. At least one *_PATHS setting is needed, and any of the others below works instead.
SPLUNK_PATHS Optional: Splunk ESCU detection folders.
ELASTIC_PATHS Optional: Elastic detection rule folders.
KQL_PATHS Optional: KQL hunting query folders.
SUBLIME_PATHS Optional: Sublime Security rule folders.
CQL_HUB_PATHS Optional: CrowdStrike CQL Hub query folders.
JAMF_PROTECT_PATHS Optional: Jamf Protect analytic folders (macOS).
STORY_PATHS Optional: Splunk analytic story folders. For analytic story tools.
ATTACK_STIX_PATH Optional: Path to enterprise-attack.json for threat actor and software data. For threat actor tools.

What it does

Security Detections MCP builds a local SQLite index from detection rule repositories you clone yourself: Sigma, Splunk ESCU, Elastic, KQL hunting queries, Sublime, CrowdStrike CQL Hub and Jamf Protect analytics. An assistant can then search those rules and check them against MITRE ATT&CK. You might ask which rules cover T1059.001, what a ransomware profile would get past, or how well you cover a named threat actor once an ATT&CK STIX bundle is loaded.

There is more than lookup. It mines the indexed rules for query patterns and field names, drafts detection skeletons and Splunk risk-based alerting blocks, and exports ATT&CK Navigator layers. It also keeps a local knowledge graph of decisions and lessons, plus custom tables, saved queries and templates. Eleven prompts cover workflows like purple-team planning and CVE response, and resources such as detection://technique/{techniqueId} expose the same data. The llm_enhanced_analysis tool hands results to the client's own model through MCP sampling.

The README and the hosted guide both say 81 tools. Count the modules that src/tools/index.ts registers at the v3.3.0 tag and you get 80. The index lives at ~/.cache/security-detections-mcp/detections.sqlite (src/db/connection.ts) and is filled on first start from the folders in the *_PATHS settings.

The author also hosts a read-only subset at detect.michaelhaag.org: about 25 tools behind a personal sdmcp_ token, capped at 200 calls a day per token on the free tier.

What it needs

To run it yourselfNode.js 18+
Runs onmacOS, Windows, Linux
detect.michaelhaag.orgFree tierOnly for the hosted endpoint: a free account issues the sdmcp_ token. Running it locally needs no account
Also
  • Local clones of the detection rule repositories to index

Clone the rule repositories you want indexed (the README gives sparse git clone lines for SigmaHQ, Splunk security_content, Elastic detection-rules, Sublime and others) and point at least one *_PATHS setting at them. The package depends on the native better-sqlite3 module. Threat actor tools need ATT&CK's enterprise-attack.json, named in ATTACK_STIX_PATH. For the hosted endpoint, create a token at detect.michaelhaag.org. Claude Desktop reaches it through the mcp-remote bridge.

Limits

  • Limit With no *_PATHS folder set the server starts with an empty index, so search and coverage tools return nothing
  • Not covered Coverage reflects only the rule files you indexed, not what runs in your SIEM. No tool queries a SIEM
  • Limit Threat actor tools need ATTACK_STIX_PATH pointing at an ATT&CK enterprise-attack.json file
  • Limit llm_enhanced_analysis works only in clients that support MCP sampling
  • Limit rebuild_index deletes the whole database file, knowledge graph tables included, before indexing again. It asks for confirm or an elicitation answer first
  • Early release DETECTIONS_DB_PATH, which the README documents for choosing the database file, is read only on the main branch (src/db/paths.ts), not in the published package
  • Read only The hosted endpoint offers about 25 read-only tools, with no knowledge graph, custom tables or autonomous analysis
  • Rate limit Hosted free tier: 200 calls a day per token, reset at 00:00 UTC. The 5,000-call Pro tier is marked as coming soon

With no *_PATHS folder set the server still starts but its index is empty, so search and coverage tools return nothing. Coverage reflects only the rules you downloaded and indexed, not what runs in your SIEM. Threat actor tools need ATTACK_STIX_PATH. llm_enhanced_analysis needs a client with MCP sampling. The hosted endpoint has only about 25 read-only tools (no knowledge graph, custom tables or autonomous analysis) and stops at 200 calls a day per token on the free tier, resetting at 00:00 UTC.

Who it suits

Detection engineers and SOC or purple-team analysts who keep open rule sets locally and want an assistant to search them, find ATT&CK gaps or draft new rules. Run it locally for the full tool set and offline use. The hosted endpoint suits quick read-only lookups without cloning rule repositories. It reads rule files and does not query or change a live SIEM. Its README pairs it with the same author's mitre-attack-mcp, which we also list, for ATT&CK data itself.

Tools 60 of 80

41 only read, 14 change things, 5 can delete or overwrite. A ? marks an optional parameter.

search
Full-text search over every indexed detection field, 50 results unless limit is set (up to 500)query: stringlimit?: numbersource_type?: enum
get_by_id
Fetch one detection by its IDid: string
get_raw_yaml
Return the original rule file text for a detectionid: string
list_all
Page through all indexed detections, 100 at a time by defaultlimit?: numberoffset?: number
list_by_source
Filter detections by format, such as sigma, splunk_escu or elasticsource_type: enumlimit?: numberoffset?: number
list_by_mitre
Detections mapped to an ATT&CK technique IDtechnique_id: stringlimit?: numberoffset?: number
list_by_mitre_tactic
Detections for an ATT&CK tactic such as persistencetactic: enumlimit?: numberoffset?: number
list_by_cve
Detections that reference a given CVEcve_id: stringlimit?: numberoffset?: number
list_by_severity
Filter detections by severity levellevel: enumlimit?: numberoffset?: number
list_by_logsource
Filter Sigma rules by log source category, product or servicecategory?: stringproduct?: stringservice?: stringlimit?: numberoffset?: number
list_by_analytic_story
Splunk detections that belong to an analytic storystory: stringlimit?: numberoffset?: number
get_stats
Counts of indexed detections by source and other facets
rebuild_index deletes
Delete the database file and index the configured folders again, after a confirmationconfirm?: booleanskip_elicitation?: boolean
analyze_coverage
Summarise coverage by tactic, top techniques and weak areassource_type?: enum
identify_gaps
List uncovered techniques for a threat profile such as ransomwarethreat_profile: enumsource_type?: enum
suggest_detections
Ideas for new detections for one techniquetechnique_id: stringsource_type?: enum
get_coverage_summary
Short per-tactic coverage percentagessource_type?: enum
get_top_gaps
The most significant uncovered techniques for a threat profilethreat_profile: enum
compare_sources
Compare how each detection format covers a topictopic: stringlimit_per_source?: number
smart_compare
Compare sources on a topic or technique in one calltopic: string
generate_navigator_layer
Produce an ATT&CK Navigator layer JSON for coveragename: stringdescription?: stringsource_type?: enumtactic?: enumseverity?: enum
analyze_procedure_coverage
Break one technique's coverage down by behaviourtechnique_id: stringsource_type?: enuminclude_query_snippets?: boolean
compare_procedure_coverage
Compare behaviour-level coverage across sourcestechnique_id: stringsources?: array
list_actors
List threat actors loaded from ATT&CK STIX datasearch?: stringlimit?: number
get_actor_profile
Show one threat actor's techniques and softwareactor_name: string
analyze_actor_coverage
Measure detection coverage against one threat actoractor_name: stringsource_type?: enuminclude_navigator_layer?: boolean
compare_actor_coverage
Compare coverage across several threat actorsactor_names: arraysource_type?: enum
search_stories
Search Splunk analytic storiesquery: stringlimit?: number
get_story
Fetch one analytic storyname: string
get_query_patterns
Common query patterns learned from indexed rules for a techniquetechnique_id: stringsource_type?: enum
get_field_reference
Fields seen in rules for a data model or sourcedata_model: string
get_macro_reference
Splunk macros used across the indexed rulesfilter?: string
find_similar_detections
Find rules that resemble a given descriptiondescription: stringtechnique_id?: stringsource_type?: enumlimit?: number
suggest_detection_template
Draft a detection skeleton from learned patternstechnique_id: stringdescription: stringdata_model?: stringdetection_type?: enumplatform?: enum
generate_rba_structure
Draft a Splunk risk-based alerting block for a detectiondetection_type: enumseverity: enumdescription: stringfields_available?: array
extract_patterns changes
Mine the index for query patterns and store themforce?: boolean
learn_from_feedback changes
Record corrections so later suggestions use themfeedback_type: enumoriginal: stringcorrected: stringcontext?: string
save_query changes
Store a query result under a name, with an optional expiryname: stringquery_type: stringdata: objectttl_minutes?: number
save_template changes
Save a reusable query templatename: stringtemplate: stringdescription?: string
run_template
Run a saved template with parametersname: stringparams?: object
delete_template deletes
Remove a saved templatename: string
create_entity changes
Add a node to the local knowledge graphname: stringentity_type: string
create_relation changes
Link two knowledge graph nodes with a reasonfrom_entity: stringto_entity: stringrelation_type: stringreasoning: stringconfidence?: number
add_observation changes
Attach a note to a knowledge graph nodeentity_name: stringobservation: stringsource?: stringconfidence?: number
delete_entity deletes
Remove a knowledge graph nodename: string
delete_observation deletes
Remove one note from a nodeobservation_id: string
search_knowledge
Search the stored knowledge graphquery: stringlimit?: number
log_decision changes
Store an analysis decision with its reasoningdecision_type: stringcontext: stringdecision: stringreasoning: stringentities_involved?: arrayoutcome?: stringsession_id?: string
add_learning changes
Store a lesson for later sessionslearning_type: stringtitle: stringinsight: stringevidence?: stringapplications?: string
get_relevant_decisions
Recall past decisions that match a contextcontext_query: stringdecision_type?: stringsession_id?: stringlimit?: number
get_learnings
Recall stored lessons for a tasktask_query: stringlearning_type?: stringlimit?: numbermark_applied?: boolean
create_table changes
Create a custom table in the local databasename: stringdescription: stringcolumns: array
insert_row changes
Add a row to a custom tabletable_name: stringdata: objectrow_id?: string
query_table
Read rows from a custom table with filterstable_name: stringwhere?: objectselect?: arrayorder_by?: arraylimit?: number
list_tables
List custom and built-in tablesinclude_prebuilt?: boolean
drop_table deletes
Delete a custom table, with confirm settable_name: stringconfirm: boolean
auto_analyze_coverage changes
Run coverage analysis for several threat profiles and store the resultsthreat_profiles?: arraystore_results?: booleananalysis_name?: stringsession_id?: string
auto_gap_report changes
Build a gap report with recommendations and store itreport_name?: stringcompare_sources?: booleaninclude_recommendations?: booleanpriority_tactics?: arraysession_id?: string
auto_compare_sources changes
Compare sources across key techniques and store the findingstechniques_to_compare?: arrayfocus_tactic?: stringinclude_quality_analysis?: booleansession_id?: string
llm_enhanced_analysis
Ask the client's model, through MCP sampling, to interpret detection dataanalysis_type: stringthreat_profile?: stringtechniques?: arraycustom_context?: string

Resources 12

detection://stats
Index statistics
detection://coverage
Coverage summary
detection://gaps/ransomware
Ransomware coverage gaps
detection://gaps/apt
APT coverage gaps
detection://top-covered
Best covered techniques
detection://sources/comparison
Coverage compared by source
knowledge://graph/summary
Knowledge graph summary
knowledge://decisions/recent
Recently logged decisions
knowledge://learnings/all
All stored lessons
detection://technique/{techniqueId}
Detections for one technique
detection://actor/{actorName}
One threat actor's profile
knowledge://entity/{entityName}
One knowledge graph node

Prompts 11

ransomware-readiness-assessment
Walk through detection coverage against ransomware behaviour
apt-threat-emulation
Plan an emulation of an APT group mapped to your detections
purple-team-exercise
Design a purple-team exercise for a tactic or technique
soc-investigation-assist
Gather detections and context for an alert or indicator
detection-engineering-sprint
Plan a sprint of prioritised detection work
executive-security-briefing
Summarise detection posture for a board, CISO or CTO
cve-response-assessment
Check coverage for a CVE or named vulnerability
data-source-gap-analysis
Compare needed data sources with what the detections use
detection-quality-review
Review the quality of detections for one technique
threat-landscape-sync
Line detection priorities up with current threats for an industry
detection-coverage-diff
Compare your coverage against a set of threats

Similar servers