MCP Server🔗
rsigma mcp serve runs a Model Context Protocol server that gives any MCP-aware agent (Cursor, Claude Code, and others) a structured tool surface over the rsigma Sigma toolchain. Instead of shelling out to the CLI and scraping text, an agent calls typed tools and gets back machine-readable JSON: ASTs, lint findings with spans and fix availability, evaluation matches, backend queries, and field inventories.
The server is gated behind the opt-in mcp Cargo feature. Build from source with --features mcp; the prebuilt binaries and Docker image (built with --all-features) include it.
Why an MCP server🔗
A detection engineer working with an agent wants a grounded write-lint-evaluate loop: the agent drafts a rule, the linter tells it exactly what is wrong (with the spec rule id and whether a safe fix exists), it evaluates the rule against sample events to confirm it fires, and it converts the rule to the target backend. Every step returns structured data the agent can reason over, and nothing requires the agent to parse human-formatted CLI output.
Transport🔗
The server speaks JSON-RPC over stdio: stdin and stdout are the transport, so the server keeps stdout clean and sends any diagnostics to stderr. You normally run it under an MCP client, not interactively.
--rules-dir sets a default root so an agent can pass path arguments relative to a rules tree. --lint-config points the lint_rules tool at a .rsigma-lint.yml (disabled rules, severity overrides, extra tag namespaces).
Client setup🔗
Cursor🔗
Add an entry to your mcp.json (project .cursor/mcp.json or the global one):
{
"mcpServers": {
"rsigma": {
"command": "rsigma",
"args": ["mcp", "serve", "--rules-dir", "/path/to/rules"]
}
}
}
Claude Code🔗
Either way the client launches rsigma mcp serve as a subprocess and talks to it over stdio.
Tool reference🔗
Every tool accepts either inline content (yaml, condition, events) or a file path, never both. Path arguments resolve against --rules-dir when relative. Outputs are JSON with an ok flag plus tool-specific fields. Content errors (a rule that fails to parse, a backend that cannot represent a rule) come back inside a successful response as { "ok": false, ... } so the agent can read and act on them; only malformed requests return MCP errors.
| Tool | Input | Output |
|---|---|---|
parse_rule | yaml or path | AST as JSON, plus rule/correlation/filter counts and parse errors. |
parse_condition | condition | The parsed condition expression tree. |
lint_rules | yaml or file/dir path | Findings per file: lint rule id, severity, message, 1-indexed line, fixable, and the fix title. |
validate_rules | yaml or file/dir path, pipelines, resolve_sources | Parse + compile + correlation-reference results, with per-rule compile errors. |
evaluate_events | rules (yaml/path), events (events array or events_path NDJSON), pipelines, match_detail, enrichers/enrichers_path | Matches with event_index, a summary of detection/correlation counts. With enrichers the matches are run through an enrichment pipeline first. |
convert_rules | rules, target, format, pipelines, options, skip_unsupported | Backend queries per rule, plus errors and warnings. |
list_backends | (none) | Conversion targets with their formats and correlation methods. |
list_fields | rules, pipelines, include_filters | Each referenced field with the rules and source kinds that use it. |
resolve_pipeline | pipeline (builtin name or path), resolve_sources | Pipeline name, priority, transformation count, dynamic sources. |
list_builtin_pipelines | (none) | The builtin pipelines (ecs_windows, fibratus_windows, sysmon). |
fix_rules | yaml or file path, lint_rules, write | Applies safe auto-fixes; returns the fixed YAML and applied/failed/skipped-unsafe counts. write: true (path only) persists to disk. |
Resources🔗
The server exposes read-only MCP resources so an agent can ground itself on the exact vocabulary without spending tool calls:
| URI | Contents |
|---|---|
rsigma://lint/catalogue | The full lint catalogue (75 rules) as JSON: id, default severity, fix disposition, one-line description. |
rsigma://reference/modifiers | Sigma field modifiers with descriptions. |
rsigma://reference/mitre-tactics | MITRE ATT&CK tactics with descriptions. |
Enrichment🔗
evaluate_events accepts an optional enrichers (inline YAML/JSON) or enrichers_path. The config follows the daemon's enrichers schema (template, http, command primitives with kind-aware template namespaces); the matches are enriched before being returned. Because the loader validates the config (including template-namespace checks) and surfaces failures as structured errors, the tool doubles as an enricher-config validator. lookup enrichers are not available here because they need the daemon's dynamic-source cache.
Example calls🔗
Parse a rule:
{ "name": "parse_rule", "arguments": { "yaml": "title: Whoami\nlogsource:\n category: process_creation\ndetection:\n sel:\n CommandLine|contains: whoami\n condition: sel\n" } }
Evaluate it against an event:
{
"name": "evaluate_events",
"arguments": {
"yaml": "title: Whoami\nlogsource:\n category: process_creation\ndetection:\n sel:\n CommandLine|contains: whoami\n condition: sel\nlevel: medium\n",
"events": [ { "CommandLine": "cmd /c whoami" } ],
"match_detail": "summary"
}
}
Convert it to PostgreSQL:
{ "name": "convert_rules", "arguments": { "path": "windows/proc.yml", "target": "postgres", "format": "view" } }
The agentic loop🔗
A productive pattern an agent can run end to end:
- Draft a rule and call
parse_ruleto confirm it is structurally valid. - Lint with
lint_rules; for each finding, theruleid andfixableflag tell the agent whether to apply a known-safe correction or rewrite by hand. - Evaluate with
evaluate_eventsagainst a handful of positive and negative sample events to confirm the rule fires where expected and stays quiet otherwise.match_detail: "summary"(or"full") explains why each event matched. - Validate the whole set with
validate_rules(optionally withpipelines) before shipping. - Convert with
convert_rulesto the deployment backend.
HTTP deployment🔗
For remote agents, serve over the Streamable HTTP transport instead of stdio with --http <addr> (the MCP endpoint is mounted at /mcp):
- Auth.
--auth-token <token>(orRSIGMA_MCP_AUTH_TOKEN) requires a static bearer token on every request; requests withoutAuthorization: Bearer <token>get401. The token is compared in constant time and is flag/env-only (never read from config files). - TLS.
--tls-cert/--tls-keyterminate TLS in-process using the same rustls loader as the daemon (requires a build with thedaemon-tlsfeature). Alternatively terminate TLS at a sidecar proxy and bind plaintext with--allow-plaintext. - Plaintext safety. Binding plaintext on a non-loopback address is refused unless
--allow-plaintextis set.
The --http, --lint-config, and --rules-dir settings also resolve from the layered config (mcp section) and the RSIGMA_MCP__* environment layer (for example RSIGMA_MCP__HTTP_ADDR=127.0.0.1:9100); the auth token stays flag/env-only.
See also🔗
rsigma mcp servefor the flag reference.- Configuration for the
mcp.*config keys. - Linting Rules for the lint vocabulary the
lint_rulestool reports. - Rule Conversion for what
convert_rulesproduces. - Feature Flags for the
mcpfeature.