A Model Context Protocol (MCP) server for security investigation, threat intelligence, vulnerability management, and response workflows across Microsoft Defender XDR and Microsoft Defender for Endpoint (MDE).
Built in Rust with the official rmcp SDK (v3), the server exposes Microsoft Graph Security and Defender for Endpoint APIs through a domain-oriented catalog of up to 10 action-based tools:
- 6 read-only tools (always exposed):
defender_hunting,defender_ti,defender_incidents_alerts,defender_machines,defender_vulnerabilities,defender_forensics. - 4 mutating tools (disabled by default, gated by explicit category flags):
defender_response: Live Response commands, library files, investigation packages, file quarantine (--enable-live-response).defender_device_response: device containment, scans, tags, machine actions (--enable-device-response); device offboarding additionally requires--enable-offboarding.defender_indicators: custom indicator management and batch operations (--enable-indicators).defender_triage: alert and incident status, classification, assignment, and comments (--enable-triage).
--read-only hides every mutating tool from tools/list and rejects calls locally before any upstream request.
Security warning Mutating response tools can isolate endpoints, terminate processes, modify firewall rules, run scripts, manage custom block indicators, and alter security alerts. Destructive tools require interactive human confirmation via MCP elicitation unless explicitly disabled for automated workflows (
--disable-human-confirmation).defender_forensicsdownloads investigation packages and retrieved files to the local quarantine directory. Files are written with mode0600and never executed; analyze them only in an isolated environment. The HTTP transport has no built-in TLS or client authentication. Binding beyond127.0.0.1requires an authenticated reverse proxy, VPN, or equivalent trusted network boundary. Over HTTP in user authentication mode, all connected clients act with the signed-in user's privileges.
The server implements 10 domain-oriented action tools partitioned across two upstream API scopes:
flowchart TD
Client["MCP Client (LLM)"]
Server["microsoft-defender-mcp-server<br/>(in-memory token cache)"]
Graph["Microsoft Graph API<br/>(Advanced Hunting, TI, XDR Alerts/Incidents/Triage)"]
MDE["Defender for Endpoint API<br/>(Machines, TVM, Alerts, Response, Indicators)"]
Client -->|"MCP protocol (stdio / HTTP)"| Server
Server -->|"Graph Scope / Delegated Scopes"| Graph
Server -->|"MDE Scope / Delegated Scopes"| MDE
| # | Tool | Kind | Listed when | Annotations (readOnly / destructive) |
Key Actions |
|---|---|---|---|---|---|
| 1 | defender_hunting |
Read-only | Always | true / false |
run (KQL queries) |
| 2 | defender_ti |
Read-only | Always | true / false |
39 TI lookups (profiles, articles, hosts, SSL, WHOIS, CVEs), plus custom_indicator_list |
| 3 | defender_incidents_alerts |
Read-only | Always | true / false |
xdr_alert_*, xdr_incident_*, endpoint_alert_*, *_related_alerts |
| 4 | defender_machines |
Read-only | Always | true / false |
machine_*, find_by_tag, find_by_ip, machine_alerts, machine_vulnerabilities, machine_missing_kbs, statistics |
| 5 | defender_vulnerabilities |
Read-only | Always | true / false |
software_*, vulnerability_*, recommendation_*, remediation_*, exposure_score |
| 6 | defender_forensics |
Read-only | Always | true / false |
machine_action_*, get_investigation_package_sas_url, download_*, investigation_*, library_file_list, live_response_get_result |
| 7 | defender_response |
Mutating | --enable-live-response |
false / true |
collect_investigation_package, stop_and_quarantine_file, live_response_run, upload_library_file, library_file_delete |
| 8 | defender_device_response |
Mutating | --enable-device-response |
false / true |
isolate, unisolate, restrict_app_execution, unrestrict_app_execution, run_av_scan, start_investigation, cancel_machine_action, tag_add, tag_remove, set_device_value, offboard (requires --enable-offboarding) |
| 9 | defender_indicators |
Mutating | --enable-indicators |
false / true |
submit (create/update), delete, batch_delete |
| 10 | defender_triage |
Mutating | --enable-triage |
false / false |
endpoint_alert_update, endpoint_alert_batch_update, endpoint_alert_comment, xdr_alert_update, xdr_alert_comment, xdr_incident_update, xdr_incident_comment |
Under --read-only, tools 7–10 are hidden from tools/list and rejected locally.
The server also publishes five investigation playbooks as MCP prompts (prompts/list, prompts/get). Each returns read-only guidance, with KQL, for the tools above. Prompts never call Defender themselves, and they are available in every mode, including --read-only. Clients usually surface them as slash commands, for example /ms_defender:ioc_sweep_skill.
| Prompt | Arguments | What it returns |
|---|---|---|
kql_hunting_skill |
goal (optional) |
Advanced hunting workflow, table cheat sheet, performance and correctness rules, examples, and pivots to the other tools |
ioc_sweep_skill |
indicators (required), lookback |
Indicators refanged and classified (SHA256/SHA1/MD5, IP, domain, URL) into a ready-to-run union sweep, then a drill-down and correlation plan |
incident_investigation_skill |
incident_id (required) |
Evidence, device timelines, entry point, scope and report for one XDR incident |
compromised_user_skill |
account (required), lookback |
Alerts, sign-ins, phishing, cloud-app activity (inbox rules, consents, MFA changes) and endpoint logons for one account |
persistence_hunt_skill |
device, lookback |
Run keys, scheduled tasks, services, WMI subscriptions, startup folders and LOLBin abuse, ranked by prevalence |
lookback takes values such as 24h or 7d (default 7d, at most 30d). Arguments are validated before they are placed in KQL; a value that does not fit returns invalid_params.
Authoritative Schemas: Every tool publishes its complete JSON schema, parameter constraints, and security annotations via the standard MCP
tools/listprotocol endpoint.
The server supports two authentication modes via --auth-mode <app|user>:
-
Application Authentication (
--auth-mode app, default):- Uses Entra ID OAuth 2.0
client_credentials. - Requires
AZURE_TENANT_ID,AZURE_CLIENT_ID, andAZURE_CLIENT_SECRET. - Requests audience scopes
{audience}/.default(https://graph.microsoft.com/.defaultandhttps://api.securitycenter.microsoft.com/.default).
- Uses Entra ID OAuth 2.0
-
Delegated User Sign-In (
--auth-mode user):- Uses interactive browser sign-in with PKCE (OAuth 2.0 authorization code flow) or device code flow fallback (
--sign-in-flow <auto|browser|device-code>). - Requires
AZURE_TENANT_IDandAZURE_CLIENT_ID.AZURE_CLIENT_SECRETis ignored and never read. - Prerequisites for Public Client App Registration:
- In Entra ID App Registrations, under Authentication, register a Mobile and desktop applications redirect URI:
http://localhost(or enable "Allow public client flows" under Advanced settings). - Grant admin consent or user consent for required delegated permissions.
- In Entra ID App Registrations, under Authentication, register a Mobile and desktop applications redirect URI:
- Performs sign-in at server startup before any MCP requests are accepted.
- Token scopes are requested dynamically based on enabled categories (under
--read-only, no write-named scopes are requested). - Tokens and refresh tokens are cached strictly in memory; no credential material is ever written to disk or the OS keychain.
- Refreshes tokens silently in the background before expiry using single-flight synchronization.
- Uses interactive browser sign-in with PKCE (OAuth 2.0 authorization code flow) or device code flow fallback (
Security Notice for HTTP Transport in User Mode: When using
--transport httpwith--auth-mode user, every connected MCP client shares the single authenticated identity established at startup. For per-analyst attribution, run one server instance per analyst bound to localhost or isolated network namespaces.
| Category | Application Permission (--auth-mode app) |
Delegated Scope (--auth-mode user) |
Defender Role Permission (User Mode) |
|---|---|---|---|
| Read (Endpoint) | Machine.Read.All, Alert.Read.All, Vulnerability.Read.All, Software.Read.All, SecurityRecommendation.Read.All, Score.Read.All, RemediationTasks.Read.All, User.Read.All |
Corresponding *.Read scopes, plus User.Read.All |
View data |
| Read (Graph) | ThreatHunting.Read.All, ThreatIntelligence.Read.All, SecurityAlert.Read.All, SecurityIncident.Read.All |
Same names (delegated) | Entra Security Reader, or Defender Unified RBAC role with equivalent read |
| Reads Needing Write-Named Scopes | Machine.ReadWrite.All, Alert.ReadWrite.All, Ti.ReadWrite.All, Library.Manage |
Machine.ReadWrite, Alert.ReadWrite, Ti.ReadWrite, Library.Manage (not requested under --read-only) |
View data |
Live Response (defender_response) |
Machine.LiveResponse, Machine.CollectForensics, Machine.StopAndQuarantine, Library.Manage |
Same names | Live response capabilities; Alerts investigation; Active remediation actions |
Device Response (defender_device_response) |
Machine.Isolate, Machine.RestrictExecution, Machine.Scan, Machine.ReadWrite.All, Alert.ReadWrite.All |
Machine.Isolate, Machine.RestrictExecution, Machine.Scan, Machine.ReadWrite, Alert.ReadWrite |
Active remediation actions (isolate, restrict, scan, investigate); Manage security settings (tags, device value) |
Offboarding (defender_device_response offboard) |
Machine.Offboard |
Machine.Offboard |
Turn off capabilities / offboard |
Indicators (defender_indicators) |
Ti.ReadWrite.All |
Ti.ReadWrite |
Active remediation actions (manage indicators) |
Triage (defender_triage) |
Alert.ReadWrite.All, SecurityAlert.ReadWrite.All, SecurityIncident.ReadWrite.All |
Alert.ReadWrite, SecurityAlert.ReadWrite.All, SecurityIncident.ReadWrite.All |
Alerts investigation; Entra Security Operator |
defender_hunting:run:ThreatHunting.Read.All(Graph). Upstream limits: 100,000 rows, 50 MB payload, ~3-minute timeout.
defender_ti:- Intel profiles, articles, host infrastructure, SSL certs, WHOIS, DNS, CVE vulnerabilities:
ThreatIntelligence.Read.All(Graph; requires active Defender TI license). custom_indicator_list:Ti.ReadWrite(MDE). Not requested in user mode under--read-only.
- Intel profiles, articles, host infrastructure, SSL certs, WHOIS, DNS, CVE vulnerabilities:
defender_incidents_alerts:xdr_alert_list,xdr_alert_get:SecurityAlert.Read.All(Graph).xdr_incident_list,xdr_incident_get:SecurityIncident.Read.All(Graph).endpoint_alert_list,endpoint_alert_get,ip_related_alerts,domain_related_alerts,user_related_alerts:Alert.Read.All(MDE;Alert.ReadWrite.Allalso accepted).file_related_alerts:Alert.ReadWrite.All(MDE).
defender_machines:machine_list,machine_get,find_by_tag:Machine.Read.All(MDE).logged_on_users,user_related_machines:User.Read.All(MDE).installed_software:Software.Read.All(MDE).security_recommendations:SecurityRecommendation.Read.All(MDE).find_by_ip:Machine.Read.All(MDE). Accepts timestamps up to 30 days old.machine_alerts:Alert.ReadWrite/Alert.ReadWrite.All(MDE).machine_vulnerabilities:Vulnerability.Read.All(MDE).machine_missing_kbs:Software.Read.All(MDE).ip_statistics:Ip.Read.All(MDE).domain_statistics:URL.Read.All(MDE).file_get,file_statistics:File.Read.All(MDE).domain_related_machines,file_related_machines:Machine.ReadWrite.All(MDE).
defender_vulnerabilities:- Software inventory and missing KBs:
Software.Read.All(MDE). - Vulnerabilities:
Vulnerability.Read.All(MDE). - Recommendations:
SecurityRecommendation.Read.All(MDE). - Remediation tasks:
RemediationTasks.Read.All(MDE). - Exposure score:
Score.Read.All(MDE).
- Software inventory and missing KBs:
defender_forensics:machine_action_list,machine_action_get_status:Machine.Read.All(MDE).get_investigation_package_sas_url,download_investigation_package:Machine.ReadWrite.All(MDE).download_quarantined_file:Machine.ReadWrite.All/Machine.LiveResponse(MDE).live_response_get_result:Machine.ReadWrite.AllorMachine.LiveResponse(MDE; requires Live Response enabled).investigation_list,investigation_get:Alert.ReadWrite/Alert.ReadWrite.All(MDE).library_file_list:Library.Manage(MDE).
defender_response:collect_investigation_package:Machine.CollectForensics(MDE).stop_and_quarantine_file:Machine.StopAndQuarantine(MDE).live_response_run:Machine.LiveResponse(MDE).upload_library_file,library_file_delete:Library.Manage(MDE).
defender_device_response:isolate,unisolate:Machine.Isolate(MDE).restrict_app_execution,unrestrict_app_execution:Machine.RestrictExecution(MDE).run_av_scan:Machine.Scan(MDE).start_investigation:Alert.ReadWrite.All(MDE).cancel_machine_action:Machine.ReadWrite.All(MDE).tag_add,tag_remove,set_device_value:Machine.ReadWrite.All(MDE).offboard:Machine.Offboard(MDE).
defender_indicators:submit,delete,batch_delete:Ti.ReadWrite.All/Ti.ReadWrite(MDE).
defender_triage:endpoint_alert_update,endpoint_alert_batch_update,endpoint_alert_comment:Alert.ReadWrite.All/Alert.ReadWrite(MDE).xdr_alert_update,xdr_alert_comment:SecurityAlert.ReadWrite.All(Graph).xdr_incident_update,xdr_incident_comment:SecurityIncident.ReadWrite.All(Graph).
Install the pre-published crate directly from crates.io:
cargo install microsoft-defender-mcp-server --lockedThis installs the executable:
microsoft-defender-mcp-server
Ensure Cargo's binary installation directory (typically ~/.cargo/bin) is in your system PATH.
Alternatively, build from source with an up-to-date Rust toolchain that supports the Rust 2024 edition:
# Clone the repository
git clone https://github.com/bitbytelabio/microsoft-defender-mcp.git
cd microsoft-defender-mcp
# Build release binary using locked dependencies
cargo build --release --lockedThe compiled binary will be located at:
target/release/microsoft-defender-mcp-server
Credentials come from environment variables. Every server option is a CLI flag with an environment-variable fallback; a flag on the command line overrides its environment variable. Run microsoft-defender-mcp-server --help for the full list.
| Variable | --auth-mode app |
--auth-mode user |
Description |
|---|---|---|---|
AZURE_TENANT_ID |
Required | Required | Microsoft Entra ID Directory (tenant) ID (GUID or verified domain). |
AZURE_CLIENT_ID |
Required | Required | Application (client) ID registered in Entra ID (GUID). |
AZURE_CLIENT_SECRET |
Required | Ignored | Application client secret string. Ignored in user mode. |
RUST_LOG |
Optional | Optional | Tracing log level filter (e.g. info, debug, warn; default: info). |
| Flag | Environment variable | Default | Description |
|---|---|---|---|
--transport <stdio|http> |
TRANSPORT |
stdio |
MCP transport. |
--bind-address <ADDR> |
BIND_ADDRESS |
127.0.0.1:8000 |
Socket address for HTTP transport. A non-loopback address prints a security warning to stderr. |
--allowed-hosts <HOSTS> |
DEFENDER_ALLOWED_HOSTS |
loopback names | Comma-separated Host header values the HTTP transport accepts (DNS-rebinding protection), e.g. mcp-defender,mcp-defender:8000 behind a Kubernetes Service. * turns the check off; use it only behind an authenticated proxy. |
--read-only |
DEFENDER_READ_ONLY |
false |
Hide all mutating tools from discovery and reject mutating calls locally. In user mode, requests only read scopes. Overrides all enablement flags. |
--enable-live-response |
DEFENDER_ENABLE_LIVE_RESPONSE |
false |
Enable defender_response (Live Response, library file upload/delete, investigation packages, quarantine). |
--allowed-commands <LIST> |
DEFENDER_LIVE_RESPONSE_ALLOWED_COMMANDS |
(all) | Comma-separated Live Response command allowlist: PutFile, RunScript, GetFile. |
--enable-device-response |
DEFENDER_ENABLE_DEVICE_RESPONSE |
false |
Enable defender_device_response (isolate, unisolate, restrict apps, scan, investigate, tags, device value). |
--enable-offboarding |
DEFENDER_ENABLE_OFFBOARDING |
false |
Add offboard action to defender_device_response (requires --enable-device-response). |
--enable-indicators |
DEFENDER_ENABLE_INDICATORS |
false |
Enable defender_indicators (submit, delete, batch_delete custom indicators). |
--enable-triage |
DEFENDER_ENABLE_TRIAGE |
false |
Enable defender_triage (alert and incident updates and comments). |
--disable-human-confirmation |
DEFENDER_DISABLE_HUMAN_CONFIRMATION |
false |
Skip interactive human confirmation prompt for destructive actions. Prints a startup warning and marks audit logs turned_off. |
--audit-log <PATH> |
DEFENDER_AUDIT_LOG |
(per-user state dir) | Path of the append-only JSON Lines mutation audit file. |
--auth-mode <app|user> |
DEFENDER_AUTH_MODE |
app |
Authentication mode: app (client credentials) or user (delegated sign-in). |
--sign-in-flow <auto|browser|device-code> |
DEFENDER_SIGN_IN_FLOW |
auto |
Sign-in flow when --auth-mode user is selected. |
--quarantine-dir <DIR> |
DEFENDER_QUARANTINE_DIR |
./quarantine_artifacts |
Where defender_forensics stages downloads (created with mode 0700). |
GRAPH_BASE_URL: Overrideshttps://graph.microsoft.com/v1.0(used for mock server testing).DEFENDER_ENDPOINT_BASE_URL: Overrideshttps://api.securitycenter.microsoft.com(used for mock server testing).DEFENDER_AUTHORITY_BASE_URL: Overrideshttps://login.microsoftonline.comfor the token, devicecode, and authorize endpoints in both auth modes.- Debug builds only (ignored in release builds):
DEFENDER_TEST_ELICITATION_TIMEOUT_MSshortens the 300-second confirmation timeout,DEFENDER_TEST_SLOW_DOWN_MSreplaces the 5-second device-codeslow_downback-off, andDEFENDER_TEST_BROWSER_CMDreplaces the browser launcher for the sign-in URL.
Stdio transport is the default mode, optimal for local MCP client runners (such as desktop AI assistants and local agent runtimes). Tracing diagnostic logs are written exclusively to stderr, leaving stdout clean for JSON-RPC MCP framing.
export AZURE_TENANT_ID="00000000-0000-0000-0000-000000000000"
export AZURE_CLIENT_ID="11111111-1111-1111-1111-111111111111"
export AZURE_CLIENT_SECRET="your-azure-client-secret"
./target/release/microsoft-defender-mcp-serverStreamable HTTP transport allows hosting the MCP server over HTTP SSE/POST at the /mcp endpoint.
export AZURE_TENANT_ID="00000000-0000-0000-0000-000000000000"
export AZURE_CLIENT_ID="11111111-1111-1111-1111-111111111111"
export AZURE_CLIENT_SECRET="your-azure-client-secret"
export TRANSPORT="http"
export BIND_ADDRESS="127.0.0.1:8000"
./target/release/microsoft-defender-mcp-serverEndpoint exposed:
http://127.0.0.1:8000/mcp
The built-in HTTP server provides no encryption (TLS) or inbound client authentication.
- By default, bind to the local loopback interface
127.0.0.1. - If binding to external interfaces (
0.0.0.0), you MUST place the endpoint behind an authenticated reverse proxy (e.g., Nginx, Envoy, Caddy with mTLS or OAuth validation) or a private VPN boundary.
Add the server to your MCP client configuration (e.g., claude_desktop_config.json or client settings).
{
"mcpServers": {
"microsoft-defender": {
"command": "/absolute/path/to/microsoft-defender-mcp/target/release/microsoft-defender-mcp-server",
"env": {
"AZURE_TENANT_ID": "00000000-0000-0000-0000-000000000000",
"AZURE_CLIENT_ID": "11111111-1111-1111-1111-111111111111",
"AZURE_CLIENT_SECRET": "your-azure-client-secret"
}
}
}
}{
"mcpServers": {
"microsoft-defender": {
"command": "/absolute/path/to/microsoft-defender-mcp/target/release/microsoft-defender-mcp-server",
"env": {
"AZURE_TENANT_ID": "00000000-0000-0000-0000-000000000000",
"AZURE_CLIENT_ID": "11111111-1111-1111-1111-111111111111",
"AZURE_CLIENT_SECRET": "your-azure-client-secret",
"DEFENDER_ENABLE_LIVE_RESPONSE": "true",
"DEFENDER_LIVE_RESPONSE_ALLOWED_COMMANDS": "GetFile,RunScript"
}
}
}
}Enabling Live Response also enables library upload and result-link retrieval. The command allowlist narrows only Live Response runs; it is not an upload allowlist.
Six domain tools, no mutating surface:
{
"mcpServers": {
"microsoft-defender": {
"command": "/absolute/path/to/microsoft-defender-mcp/target/release/microsoft-defender-mcp-server",
"args": ["--read-only", "--quarantine-dir", "/secure/quarantine"],
"env": {
"AZURE_TENANT_ID": "00000000-0000-0000-0000-000000000000",
"AZURE_CLIENT_ID": "11111111-1111-1111-1111-111111111111",
"AZURE_CLIENT_SECRET": "your-azure-client-secret"
}
}
}
}{
"mcpServers": {
"microsoft-defender": {
"command": "/absolute/path/to/microsoft-defender-mcp/target/release/microsoft-defender-mcp-server",
"args": ["--auth-mode", "user", "--sign-in-flow", "auto"],
"env": {
"AZURE_TENANT_ID": "00000000-0000-0000-0000-000000000000",
"AZURE_CLIENT_ID": "11111111-1111-1111-1111-111111111111"
}
}
}
}Every destructive tool action requires explicit operator approval before dispatching any request upstream:
- Protected Tools:
defender_response,defender_device_response, anddefender_indicators. - Non-Destructive Tool:
defender_triageactions update triage metadata and comments and do not trigger confirmation prompts. - Interaction Protocol: The server issues an MCP
Formelicitation request displaying the tool, action, target identifiers, and justification reason. Only an explicit user acceptance (confirm: true) proceeds. - Failure Handling: If the MCP client lacks elicitation support, or the user declines, cancels, or times out (300 s), the call is rejected locally.
- Automated Pipelines: To run without human prompts in trusted automation, pass
--disable-human-confirmation(DEFENDER_DISABLE_HUMAN_CONFIRMATION=true). A startup warning is printed tostderrand audit records recordconfirmation: "turned_off".
Every mutating attempt is recorded in an append-only JSON Lines (.jsonl) audit file:
The audit log path is determined in order:
- CLI flag
--audit-log <PATH>or environment variableDEFENDER_AUDIT_LOG. - Unix:
$XDG_STATE_HOME/microsoft-defender-mcp/audit.jsonl. - Unix fallback:
$HOME/.local/state/microsoft-defender-mcp/audit.jsonl. - Windows:
%LOCALAPPDATA%\microsoft-defender-mcp\audit.jsonl. - Default fallback:
./microsoft-defender-mcp-audit.jsonl.
The parent directory is created with permissions 0700 and the audit file is opened/created with permissions 0600 (user read/write only).
- Before any upstream request is made, an
intentrecord is flushed to disk. If writing fails, the call is immediately rejected withaudit_unavailableand no upstream call is dispatched. - After the upstream response returns, an
outcomerecord is appended. - Calls rejected locally (due to validation, read-only enforcement, or declined confirmation) produce a single
finalrecord. - Under no circumstances are tokens, client secrets, auth codes, device codes, or PKCE verifiers logged.
The following objects are the params portion of MCP tools/call requests. Tool responses use structured JSON.
Executes read-only KQL queries across Microsoft Defender XDR unified event tables (DeviceProcessEvents, DeviceNetworkEvents, EmailEvents, IdentityLogonEvents, etc.).
{
"name": "defender_hunting",
"arguments": {
"action": "run",
"query": "DeviceProcessEvents | where Timestamp > ago(7d) | where FileName =~ 'powershell.exe' | project Timestamp, DeviceName, AccountName, ProcessCommandLine | take 50",
"timespan": "P7D"
}
}- Timespan: Defaults to
P30D(30 days). Accepts ISO 8601 duration/interval representations (e.g.,P7D,P90D, or explicit start/end ISO intervals). Queryable history depends on tenant event retention policies. - Client Limits: Queries are locally validated (non-empty, <= 128 KB, cannot begin with management dot
.). Upstream limits enforce a maximum of 100,000 rows, 50 MB response payload, and approximately 3-minute execution limit. The server HTTP client uses a 210-second timeout to accommodate long-running analytical queries.
Retrieves correlated security incidents aggregating signals across Identity, Endpoint, Cloud Apps, and Email.
{
"name": "defender_incidents_alerts",
"arguments": {
"action": "xdr_incident_list",
"filter": "severity eq 'high' and status eq 'active'",
"top": 25,
"skip": 0
}
}Lists installed software applications and versions discovered on an enrolled endpoint device.
{
"name": "defender_machines",
"arguments": {
"action": "installed_software",
"machine_id": "1e50020e54d31e974e64f8c14828114be2880017"
}
}Human Authorization Required:
defender_responseis listed only with--enable-live-response(DEFENDER_ENABLE_LIVE_RESPONSE=true). Each call asks the human user to confirm through an MCP elicitation prompt unless the server runs with--disable-human-confirmation.
Uploads a script to the shared Defender for Endpoint Live Response library.
{
"name": "defender_response",
"arguments": {
"action": "upload_library_file",
"file_name": "collect_triage.ps1",
"file_content": "Get-Process | Export-Csv -Path C:\\temp\\processes.csv -NoTypeInformation",
"description": "Triage script for incident response process collection",
"parameters_description": "No parameters required",
"override_if_exists": true
}
}Validation: file_name must be a bare basename without directory separators. File content must be valid UTF-8 up to 20 MiB. description doubles as the audited justification for this action, so it must contain at least 10 characters after trimming.
Dispatches ordered remediation commands to an active machine.
{
"name": "defender_response",
"arguments": {
"action": "live_response_run",
"machine_id": "1e50020e54d31e974e64f8c14828114be2880017",
"comment": "Executing forensic process collection for incident INC-10492",
"commands": [
{
"type": "RunScript",
"params": [
{ "key": "ScriptName", "value": "collect_triage.ps1" }
]
},
{
"type": "GetFile",
"params": [
{ "key": "Path", "value": "C:\\temp\\processes.csv" }
]
}
]
}
}Validation: commands supports up to 20 ordered items. comment must contain at least 10 Unicode characters after trimming leading and trailing whitespace. If the target device is offline, commands can remain queued by the upstream service for up to 2 hours.
Fetches the SAS download URL for the output of a completed RunScript or GetFile command.
{
"name": "defender_forensics",
"arguments": {
"action": "live_response_get_result",
"action_id": "3b2e7a10-4491-4d3f-912a-8c011e4bf312",
"command_index": 1
}
}Validation: command_index must be zero or positive (>= 0).
Collect an investigation package (mutating; requires --enable-live-response and human approval), poll the action, then stage the archive locally:
{ "name": "defender_response", "arguments": { "action": "collect_investigation_package", "machine_id": "1e5bc9d7e413ddd7902c2932e418702b84d0cc07", "comment": "Incident 4124 triage: suspicious PowerShell" } }
{ "name": "defender_forensics", "arguments": { "action": "machine_action_get_status", "action_id": "7327b54fd718525cbca07dacde913b5ac3c85673" } }
{ "name": "defender_forensics", "arguments": { "action": "download_investigation_package", "action_id": "7327b54fd718525cbca07dacde913b5ac3c85673" } }The download response reports the staged file:
{
"status": "Downloaded",
"file_path": "/secure/quarantine/investigation_package_7327b54fd718525cbca07dacde913b5ac3c85673.zip",
"file_size_bytes": 14258900,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"source_action_id": "7327b54fd718525cbca07dacde913b5ac3c85673"
}- If the package is not ready, the tool returns
httpStatus: 404with the action's currentstatus; retry once it isSucceeded.getPackageUriis rate-limited upstream to 2 calls/minute. - Malware samples: the public API has no "download quarantined file by SHA-1" endpoint (that is portal-only). Retrieve a file with a Live Response
GetFilecommand, then calldownload_quarantined_filewith the run'saction_id, thecommand_indexof theGetFilecommand, and optionallysha1to name the archivequarantine_{sha1}.zip. destination_dirmay name a relative subdirectory inside the quarantine directory; absolute paths and..are rejected. SAS URLs are fetched without the bearer token, a partial download is deleted on failure, and staged files are never executed.
- Microsoft Graph list endpoints:
topdefaults to 50, maximum 1,000. - Defender for Endpoint list endpoints:
topdefaults to 50, maximum 10,000. - Skip offset: Range
0to100,000. - No Auto-Paging: The server does not auto-follow
@odata.nextLink. It preserves the link in the raw response; request subsequent pages explicitly with the pagination parameters supported by that tool.
- Hostnames: Max 253 characters; internal whitespace, control characters, slashes, and dot navigation segments (
.or..) are rejected. - Identifiers & Entity Keys: Dynamically percent-encoded to RFC 3986 unreserved standards before inclusion in URI path segments.
- Look-back Hours: Statistics endpoints accept
look_back_hoursbetween 1 and 720 hours (up to 30 days; default 720).
- Success: Returns the upstream JSON in MCP
structuredContent;rmcpalso supplies a JSON text content item for compatible clients. - Client/Input Validation Failures: Emits standard MCP protocol errors (
invalid_params) containing the specific validation failure message. - API & Service Errors: Emits tool-level errors (
isError: true) with structured problem details:Standardized HTTP error mappings:{ "error": "Permission denied for: /api/machines. Ensure the application registration has the required permissions and the tenant has appropriate licenses.", "httpStatus": 403 }400: Bad request / invalid upstream query parameters.401: Authentication failure (invalid client ID, secret, or tenant ID).403: Permission denied (missing application permission or missing tenant license).404: Target resource ID not found.429: Rate limit exceeded (client should wait before retrying).504: Upstream timeout (query too complex or timespan too broad).
The test suite uses local loopback HTTP services and synthetic fixtures; it does not require or contact a Microsoft tenant.
cargo fmt --all -- --check
cargo check --workspace --locked
cargo clippy --all-targets --workspace --locked -- -D warnings
cargo test --workspace --locked
cargo build --release --lockedThe test matrix exercises:
- OData serialization and Graph/MDE parameter bounds.
- RFC 3986 path-segment encoding and traversal defenses.
- KQL, IP, hostname, hash, filename, and Unicode-boundary validation.
- Mutation category gating (
live_response,device_response,offboarding,indicators,triage). - Interactive human confirmation via MCP elicitation and
--disable-human-confirmation. - Append-only mutation audit logging, mode 0600 file creation, and fail-closed guarantees.
- Delegated user sign-in: PKCE browser flow, device code flow, in-memory token cache, single-flight renewal.
- Upstream success parsing and HTTP error-status preservation through real loopback requests.
- Domain catalog tool surface (6 read-only, up to 10 total) and their exact safety annotations.
--read-onlyenforcement end to end over MCP stdio: mutating tools hidden and rejected withread_only_violation.- CLI flags, environment fallbacks, and flag-over-environment precedence.
- Forensic staging:
0700/0600permissions, SHA-256 digests, package-not-ready reporting, and quarantine-directory confinement.
Breaking change. Release 1.0.0 removes granular mode, the --tool-mode flag, and the DEFENDER_TOOL_MODE variable.
- A client that calls any removed granular tool name gets the standard MCP unknown-tool error. No alias or redirect exists.
- Each capability is reached by calling the domain tool with the listed
action. - The response payload is the same upstream JSON that the granular tool returned.
| Removed granular tool | Domain tool | action |
|---|---|---|
defender_advanced_hunting_run |
defender_hunting |
run |
defender_ti_intel_profiles_list |
defender_ti |
intel_profiles_list |
defender_ti_intel_profile_get |
defender_ti |
intel_profile_get |
defender_ti_intel_profile_indicators_list |
defender_ti |
intel_profile_indicators_list |
defender_ti_intel_profile_indicator_get |
defender_ti |
intel_profile_indicator_get |
defender_ti_intel_profile_indicators_global_list |
defender_ti |
intel_profile_indicators_global_list |
defender_ti_articles_list |
defender_ti |
articles_list |
defender_ti_article_get |
defender_ti |
article_get |
defender_ti_article_indicators_list |
defender_ti |
article_indicators_list |
defender_ti_article_indicator_get |
defender_ti |
article_indicator_get |
defender_ti_article_indicators_global_list |
defender_ti |
article_indicators_global_list |
defender_ti_host_get |
defender_ti |
host_get |
defender_ti_host_reputation_get |
defender_ti |
host_reputation_get |
defender_ti_host_components_list |
defender_ti |
host_components_list |
defender_ti_host_component_get |
defender_ti |
host_component_get |
defender_ti_host_cookies_list |
defender_ti |
host_cookies_list |
defender_ti_host_cookie_get |
defender_ti |
host_cookie_get |
defender_ti_host_ports_list |
defender_ti |
host_ports_list |
defender_ti_host_port_get |
defender_ti |
host_port_get |
defender_ti_host_trackers_list |
defender_ti |
host_trackers_list |
defender_ti_host_tracker_get |
defender_ti |
host_tracker_get |
defender_ti_host_subdomains_list |
defender_ti |
host_subdomains_list |
defender_ti_host_ssl_certs_list |
defender_ti |
host_ssl_certs_list |
defender_ti_host_whois_get |
defender_ti |
host_whois_get |
defender_ti_host_whois_history_list |
defender_ti |
host_whois_history_list |
defender_ti_host_pairs_list |
defender_ti |
host_pairs_list |
defender_ti_host_pair_get |
defender_ti |
host_pair_get |
defender_ti_host_child_pairs_list |
defender_ti |
host_child_pairs_list |
defender_ti_host_parent_pairs_list |
defender_ti |
host_parent_pairs_list |
defender_ti_host_passive_dns_list |
defender_ti |
host_passive_dns_list |
defender_ti_host_passive_dns_reverse_list |
defender_ti |
host_passive_dns_reverse_list |
defender_ti_ssl_certs_list |
defender_ti |
ssl_certs_list |
defender_ti_ssl_cert_get |
defender_ti |
ssl_cert_get |
defender_ti_ssl_cert_related_hosts_list |
defender_ti |
ssl_cert_related_hosts_list |
defender_ti_whois_records_list |
defender_ti |
whois_records_list |
defender_ti_whois_record_get |
defender_ti |
whois_record_get |
defender_ti_passive_dns_get |
defender_ti |
passive_dns_get |
defender_ti_vulnerability_get |
defender_ti |
vulnerability_get |
defender_ti_vulnerability_components_list |
defender_ti |
vulnerability_components_list |
defender_ti_vulnerability_component_get |
defender_ti |
vulnerability_component_get |
defender_endpoint_machine_list |
defender_machines |
machine_list |
defender_endpoint_machine_get |
defender_machines |
machine_get |
defender_endpoint_machine_logged_on_users |
defender_machines |
logged_on_users |
defender_endpoint_machine_find_by_tag |
defender_machines |
find_by_tag |
defender_endpoint_machine_list_software |
defender_machines |
installed_software |
defender_endpoint_machine_security_recommendations |
defender_machines |
security_recommendations |
defender_endpoint_software_list |
defender_vulnerabilities |
software_list |
defender_endpoint_software_get |
defender_vulnerabilities |
software_get |
defender_endpoint_software_machines |
defender_vulnerabilities |
software_machines |
defender_endpoint_software_vulnerabilities |
defender_vulnerabilities |
software_vulnerabilities |
defender_endpoint_software_missing_kbs |
defender_vulnerabilities |
software_missing_kbs |
defender_endpoint_software_distribution |
defender_vulnerabilities |
software_distribution |
defender_endpoint_vulnerability_list |
defender_vulnerabilities |
vulnerability_list |
defender_endpoint_vulnerability_get_by_cve |
defender_vulnerabilities |
vulnerability_get_by_cve |
defender_endpoint_vulnerability_get_machines |
defender_vulnerabilities |
vulnerability_get_machines |
defender_endpoint_vulnerability_get_by_machine_software |
defender_vulnerabilities |
vulnerability_get_by_machine_software |
defender_endpoint_recommendation_list |
defender_vulnerabilities |
recommendation_list |
defender_endpoint_recommendation_get |
defender_vulnerabilities |
recommendation_get |
defender_endpoint_recommendation_machines |
defender_vulnerabilities |
recommendation_machines |
defender_endpoint_recommendation_vulnerabilities |
defender_vulnerabilities |
recommendation_vulnerabilities |
defender_endpoint_recommendation_by_software |
defender_vulnerabilities |
recommendation_by_software |
defender_endpoint_remediation_list |
defender_vulnerabilities |
remediation_list |
defender_endpoint_remediation_get |
defender_vulnerabilities |
remediation_get |
defender_endpoint_remediation_exposed_devices |
defender_vulnerabilities |
remediation_exposed_devices |
defender_endpoint_exposure_score |
defender_vulnerabilities |
exposure_score |
defender_endpoint_exposure_score_by_machine_groups |
defender_vulnerabilities |
exposure_score_by_machine_groups |
defender_endpoint_ip_statistics |
defender_machines |
ip_statistics |
defender_endpoint_ip_related_alerts |
defender_incidents_alerts |
ip_related_alerts |
defender_endpoint_domain_statistics |
defender_machines |
domain_statistics |
defender_endpoint_domain_related_machines |
defender_machines |
domain_related_machines |
defender_endpoint_domain_related_alerts |
defender_incidents_alerts |
domain_related_alerts |
defender_endpoint_file_get |
defender_machines |
file_get |
defender_endpoint_file_statistics |
defender_machines |
file_statistics |
defender_endpoint_file_related_machines |
defender_machines |
file_related_machines |
defender_endpoint_file_related_alerts |
defender_incidents_alerts |
file_related_alerts |
defender_endpoint_user_related_alerts |
defender_incidents_alerts |
user_related_alerts |
defender_endpoint_user_related_machines |
defender_machines |
user_related_machines |
defender_endpoint_alert_list |
defender_incidents_alerts |
endpoint_alert_list |
defender_endpoint_alert_get |
defender_incidents_alerts |
endpoint_alert_get |
defender_endpoint_machine_action_list |
defender_forensics |
machine_action_list |
defender_endpoint_machine_action_get_status |
defender_forensics |
machine_action_get_status |
defender_xdr_alert_list |
defender_incidents_alerts |
xdr_alert_list |
defender_xdr_alert_get |
defender_incidents_alerts |
xdr_alert_get |
defender_xdr_incident_list |
defender_incidents_alerts |
xdr_incident_list |
defender_xdr_incident_get |
defender_incidents_alerts |
xdr_incident_get |
defender_library_file_upload |
defender_response |
upload_library_file |
defender_endpoint_live_response_run |
defender_response |
live_response_run |
defender_endpoint_live_response_get_result |
defender_forensics |
live_response_get_result |
- Model Context Protocol: Tools Specification
- Microsoft Graph: Advanced Hunting API
- Microsoft Graph: Security API Overview & Quotas
- Microsoft Graph: Alerts v2 API
- Microsoft Graph: Incidents API
- Microsoft Defender for Endpoint: Run Live Response API
- Microsoft Defender for Endpoint: Upload File to Library API
- Microsoft Defender for Endpoint: Get Live Response Result Download Link
- Microsoft Defender for Endpoint: API Permission Reference
Licensed under the MIT license declared in Cargo.toml.