mcp-defender-xdr

An MCP server that exposes Microsoft Defender XDR — Advanced Hunting KQL, incidents, and alerts — to Claude. Read-only, certificate auth, multi-tenant.

View on GitHub →

What it does

Three read-only tools against the Defender for Endpoint / Graph Security APIs: run an Advanced Hunting KQL query, list and read incidents, list and read alerts. Each tool takes an optional tenant parameter. Omit it and the call goes to the default tenant. Name a tenant from the config to switch. Pass "*" to run the same query across every configured tenant. The server runs locally over stdio and plugs into Claude Desktop or Claude Code with the standard MCP config. Auth is OAuth 2.0 client credentials with an X.509 certificate per tenant — no shared client secrets.

Why I built it

As a cyber lead at Propulsion, I spend time managing events across multiple Microsoft tenants at the same time. Microsoft Defender’s UI is single-tenant per session, so the pivots are manual: switch tenant, re-run the KQL, copy a host name into a new tab, open the incident, back to KQL. The Graph API does all of this already — wrapping it isn’t where the work is. The work is what makes it safe to point a model at a tenant: certificate auth instead of a shared client secret, a tenants config that refuses to load with the wrong file permissions, every Graph response treated as untrusted before it goes back into the prompt. Most of the time on this went into the auth and the trust boundary, not the tools themselves.

Status

v0.1.0 shipped 2026-05-12, MIT. v0.2 adds per-tool audit logging and starts on the OWASP MCP Top 10 — tool description integrity and KQL result sanitization first.

Threat model

Read-only by construction — the three Graph permissions are all `*.Read.All`, so nothing the model invokes can change tenant state. Auth is OAuth 2.0 client credentials with an X.509 certificate per App Registration; no shared client secrets, no on-behalf-of flow. The multi-tenant JSON config refuses to load if its POSIX permissions are looser than `0600`. Every Graph response is treated as untrusted before it goes back to the model. The wider OWASP MCP Top 10 surface — tool poisoning, confused deputy, indirect prompt injection — comes in v0.2 and v0.3; v0.1 ships the read-only base those controls sit on top of.