# Purple AI MCP Server

> Draft · awaiting review.

> Read-only MCP server for the SentinelOne Singularity platform: Purple AI, data-lake PowerQuery, alerts, vulnerabilities, misconfigurations and inventory.

- Badge: `reach 3 · not run yet`
- Type: MCP server; tier: not run yet
- Tasks: Alert triage, Threat intel enrichment; mission: Defensive; works with: Any MCP client, Claude Code, Codex
- Source: https://github.com/Sentinel-One/purple-mcp, pinned to `07d4992` (v0.7.0), licence MIT
- Last checked: 2026-10-21; next check: 2027-01-19; method v0.1, reach-v0.1

## At a glance

- **What it is:** Purple AI MCP Server is an MCP server that lets any MCP client access SentinelOne services. An MCP server is a program that gives your AI client extra tools; the client's model decides when to call them.
- **Made for:** Exposes the SentinelOne platform to AI clients through the Model Context Protocol. +2 more
- **Runs:** On your machine, started by your AI client. Other modes: streamable-http or sse (on your machine, as a service with a network port); Docker image (in a container on your machine). Listens only in an optional mode: In the container, sse and streamable-http modes bind 0.0.0.0 on port 8000 by default, with no sign-in (no sign-in); 3 listeners in all.
- **Sends data to:** SentinelOne console (always), SentinelOne Purple AI (by default), Singularity Data Lake API (by default), cve.circl.lu (by default), VirusTotal (if you turn it on), Pydantic Logfire (if you turn it on), GitHub Sentinel-One/purple-mcp (by default). Other connections not ruled out: read in the documentation and the cited code, not searched in full.
- **Can change things:** No changing, deleting or command-running capability among the groups read.
- **Needs:** Needs a SentinelOne account to obtain the console token · Needs a console or Service User token with Account or Site scope, not Global, set as PURPLEMCP_CONSOLE_TOKEN · Needs PURPLEMCP_CONSOLE_BASE_URL set to the HTTPS console URL · +3 more

Profile read at commit `07d4992` on 2026-10-25; every fact cites a file and line at that commit.

## What it does

Purple AI MCP Server is an MCP server that lets any MCP client access SentinelOne services. (README.md#L11)

Made for (the author says):

- Exposes the SentinelOne platform to AI clients through the Model Context Protocol. (README.md#L15)
- Lets an analyst ask security questions and investigate threats through SentinelOne Purple AI. (README.md#L17)
- Answers questions about endpoints, cloud resources, identities and network devices in the SentinelOne asset inventory. (README.md#L22)

Documented uses:

- Investigate and triage SentinelOne alerts, including their notes, history and auto-investigation reports [Alert triage] (src/purple_mcp/tools/alerts.py#L72)
- Enrich indicators of compromise with VirusTotal data for hashes, URLs, domains and IPs [Threat intel enrichment] (src/purple_mcp/tools/threat_intelligence.py#L75)
- Generate PowerQueries with Purple AI for threat hunting and run them against the data lake [Detection engineering] (src/purple_mcp/tools/purple_ai.py#L65)
- Track CVEs and vulnerability findings recorded in the SentinelOne console [Vulnerability prioritization] (README.md#L20)

Not for (the author says):

- The author describes the server as read-only: it is not meant to change the account or any objects in it. (README.md#L26)
- The purple_ai tool description states that Purple AI cannot modify configurations or interact with endpoints directly. (src/purple_mcp/tools/purple_ai.py#L73)

## What it can do

| Group | What it covers | Effect | On by default |
|---|---|---|---|
| Purple AI | purple_ai sends a natural-language security question to SentinelOne Purple AI and returns its answer, which can include a generated PowerQuery. (src/purple_mcp/server.py#L142) | reads | yes |
| Data Lake | powerquery runs a PowerQuery over Singularity Data Lake events for a start and end time; get_timestamp_range builds the time range. (README.md#L226) | reads | yes |
| Alerts | get_alert, list_alerts, search_alerts, get_alert_notes, get_alert_history and get_alert_investigation_report read alerts, notes, timelines and auto-investigation reports. (src/purple_mcp/server.py#L146-151) | reads | yes |
| Vulnerabilities | get, list and search vulnerabilities and read their notes and history from the console's XSPM vulnerability findings. (README.md#L238-242) | reads | yes |
| Misconfigurations | get, list and search misconfigurations and read their notes and history from the console's XSPM misconfiguration findings. (README.md#L246-250) | reads | yes |
| Asset Inventory | get_inventory_item, list_inventory_items and search_inventory_items read assets by surface type, with fetch_fields presets MINIMAL, STANDARD or ALL. (README.md#L254-256) | reads | yes |
| CVE Search (External) | cve_search_by_id, cve_search_by_vendor and cve_database_status query the public CIRCL cve-search service without an API key. (README.md#L267-271) | reads | yes |
| Threat Intelligence (External) | Seven threat_intel_* tools look up file hashes, URLs, domains and IPs, file relationships, sandbox behaviour and Intelligence search on VirusTotal. (README.md#L277-286) | reads | no |
| purple_utils | iso_to_unix_timestamp converts ISO 8601 datetimes to UNIX milliseconds for the date filters of the search tools. (src/purple_mcp/server.py#L144-145) |  | yes |

## How it runs

A Python FastMCP server (purple-mcp) runs on the user's machine over stdio, or over SSE or streamable HTTP via uvicorn; its tools call SentinelOne console GraphQL/REST and SDL APIs over HTTPS, plus cve.circl.lu and VirusTotal. (src/purple_mcp/server.py#L139)

- Starts: On your machine, started by your AI client. The MCP client starts purple-mcp through uvx and talks to it over stdio, the default mode. (README.md#L42)
- Can also run: On your machine, as a service with a network port (streamable-http or sse, switch `--mode streamable-http`). Runs as an HTTP service in streamable-http or sse mode on port 8000 to serve several clients. (README.md#L202)
- Can also run: In a container on your machine (Docker image, switch `MCP_MODE`). A Dockerfile and docker-compose.yml run the server in a container; MCP_MODE selects stdio, sse or streamable-http. (Dockerfile#L55)
- Your AI client: **MCP client configuration**: The client's mcpServers entry launches purple-mcp via uvx and passes the console token and console URL as env values. (README.md#L131-140)
- Your machine: **purple-mcp server**: FastMCP server process that registers the tools and runs over stdio, or via uvicorn for SSE and HTTP. (src/purple_mcp/server.py#L139)
- Outside your machine: **SentinelOne console API**: Console GraphQL endpoints for Purple AI, alerts, misconfigurations and vulnerabilities, and the REST asset inventory API. (src/purple_mcp/config.py#L481)
- Outside your machine: **Singularity Data Lake API**: SDL API at the console URL plus /sdl, or at a dedicated PURPLEMCP_SDL_BASE_URL, that runs PowerQuery jobs. (src/purple_mcp/config.py#L541)
- Outside your machine: **cve.circl.lu**: Public CVE API that answers the three CVE tools. (src/purple_mcp/libs/cve/config.py#L30)
- Outside your machine: **VirusTotal API**: VirusTotal API v3, reached through the vt-py client with the user's API key, for the threat-intel tools. (src/purple_mcp/libs/threat_intelligence/client.py#L156)
- Listens: In sse or streamable-http mode uvicorn listens on localhost:8000; other hosts are refused unless --allow-remote-access is given.: this machine only (loopback), no sign-in, in an optional mode (src/purple_mcp/cli.py#L333-337)
- Listens: In the container, sse and streamable-http modes bind 0.0.0.0 on port 8000 by default, with no sign-in.: all network interfaces, no sign-in, in an optional mode (docker-entrypoint.sh#L18)
- Listens: The purple-mcp-proxy nginx service publishes ports 80 and 443; its PURPLEMCP_AUTH_TOKEN falls back to the placeholder your-secure-token-here.: all network interfaces, sign-in required, in an optional mode (docker-compose.yml#L104-113)
- Sends data to SentinelOne console (vendor API, always): Sends GraphQL and REST requests with the console token to read alerts, vulnerabilities, misconfigurations and inventory. (README.md#L89)
- Sends data to SentinelOne Purple AI (vendor API, by default): purple_ai posts the question, a session ID and optional console scope IDs to the Purple AI GraphQL endpoint of the console. (src/purple_mcp/libs/purple_ai/client.py#L281-286)
- Sends data to Singularity Data Lake API (vendor API, by default): powerquery submits a PowerQuery job with POST /v2/api/queries using the console token and polls it for results. (src/purple_mcp/libs/sdl/sdl_query_client.py#L250-254)
- Sends data to cve.circl.lu (other, by default): The CVE tools send the CVE ID, vendor or product to cve.circl.lu without an API key. (src/purple_mcp/libs/cve/config.py#L30)
- Sends data to VirusTotal (other, if you turn it on): With PURPLEMCP_VT_API_KEY set, the threat-intel tools send hashes, URLs, domains, IPs and search queries to VirusTotal. (src/purple_mcp/libs/threat_intelligence/client.py#L225)
- Sends data to Pydantic Logfire (telemetry, if you turn it on): With PURPLEMCP_LOGFIRE_TOKEN set, traces of outgoing HTTP calls, server requests and log records go to Pydantic Logfire. (src/purple_mcp/observability.py#L58)
- Sends data to GitHub Sentinel-One/purple-mcp (download, by default): The documented uvx command fetches purple-mcp from the GitHub repository Sentinel-One/purple-mcp to run it. (README.md#L42)

## What you need

- Account: Needs a SentinelOne account to obtain the console token. (deploy/aws_agentcore/BEDROCK_AGENTCORE_DEPLOYMENT.md#L5)
- Credentials: Needs a console or Service User token with Account or Site scope, not Global, set as PURPLEMCP_CONSOLE_TOKEN. (README.md#L82-83)
- Setting: Needs PURPLEMCP_CONSOLE_BASE_URL set to the HTTPS console URL. (README.md#L295)
- Runtime: Needs Python 3.11 or later. (pyproject.toml#L6)
- Other tools: Needs uv, whose uvx command fetches and runs the server. (README.md#L34-35)
- Credentials: The threat-intel tools need a VirusTotal API key in PURPLEMCP_VT_API_KEY; threat_intel_search needs a Premium API key. (README.md#L285-288)
- Installer: The quick start installs uv by piping the astral.sh install script into sh. (README.md#L34-35)
- Installer: The documented uvx commands and client configurations run the server from the repository's default branch without a pinned version. (README.md#L42)
- Installer: The README recommends pinning a commit hash (git+...@<commit-hash>) for production or security-sensitive environments. (README.md#L47)

## Limits and risks

- Has no built-in authentication; network-exposed deployments rely on a reverse proxy or load balancer placed in front of it. (README.md#L75)
- The author advises against exposing the server on a network, because anyone who reaches it could use the configured SentinelOne account. (README.md#L215-216)
- The container entrypoint adds --allow-remote-access itself for any non-loopback MCP_HOST, so the CLI's loopback refusal does not take effect in Docker. (docker-entrypoint.sh#L33-36)
- Without PURPLEMCP_SDL_CONSOLE_ACCOUNT_IDS, PowerQueries run across all accounts the token can reach. (README.md#L305-308)
- The server supports tokens with access to a single Account or Site; several sites need separate server instances with their own tokens. (README.md#L83-85)
- HTTP modes serve an unauthenticated /health route that returns {"status": "ok"}. (src/purple_mcp/server.py#L179-182)
- PURPLEMCP_DEBUG_UNSAFE_LOGGING=1 writes queries and payloads to the logs; the author limits it to secured, time-boxed debugging. (SECURITY.md#L163-164)
- The project is maintained by SentinelOne with the community but is stated not to be an official SentinelOne product. (README.md#L381-382)
- SECURITY.md states that the MCP tools can execute privileged actions through upstream APIs, and that exposing tool endpoints without authentication or rate limiting invites abuse. (SECURITY.md#L27-28)
- One console token is loaded at startup and used for every request, so all clients of a shared HTTP instance act with the same tenant credentials. (SECURITY.md#L96-99)
- TLS verification is on by default. The skip_tls_verify flag is refused when PURPLEMCP_ENV is unset or release, and allowed with warnings for testing, staging and development. (SECURITY.md#L70-76)
- In docker-compose.yml the SSE service publishes port 8000 on the host and is set to restart: unless-stopped. (docker-compose.yml#L23-25)
- The powerquery tool description tells the client's model to use purple_ai to write PowerQueries and to run a user-supplied PowerQuery exactly as sent. (src/purple_mcp/tools/sdl.py#L42-44)
- In the data lake the server submits its own PowerQuery job, polls it for results and deletes the job when done; these are the data-lake client's only POST and DELETE requests. (src/purple_mcp/libs/sdl/sdl_query_client.py#L49-52)

## Rights in plain language

- Declared: files 0 (reads only files you give it), network 3 (can tunnel or exfiltrate), secrets 2 (reads broad tokens or the environment).
- Code: reach 3 (privileged): network 3 (can tunnel or exfiltrate), secrets 2 (reads broad tokens or the environment), persistence 3 (adds autostart, users or keys); unknown: approval.
- Lab: not run yet.

Why three columns? Declarations are often incomplete and scanners can be bypassed, so we run each tool once and compare.

## Privilege Reach

Reach level 3 (privileged).

| Right | Declared | Code | Lab |
|---|---|---|---|
| Files: where does it read and write? | 0 reads only files you give it | 1 reads outside the project | not run yet |
| Network: whom does it talk to? | 3 can tunnel or exfiltrate | 3 can tunnel or exfiltrate | not run yet |
| Execution: what does it run? | not declared | 0 runs no programs | not run yet |
| Secrets: which credentials does it touch? | 2 reads broad tokens or the environment | 2 reads broad tokens or the environment | not run yet |
| Persistence: what survives the run? | not declared | 3 adds autostart, users or keys | not run yet |
| Approval: does it ask before acting? | not declared | ? unknown | not run yet |

0 contained · 1 scoped · 2 open · 3 privileged · ? no evidence · 0 never means safe

## Install

### Upstream

Quoted from `README.md#L42` at the pinned commit (not a command to copy): `uvx --from git+https://github.com/Sentinel-One/purple-mcp.git purple-mcp --mode=stdio`


### Run it with least privilege

- note: `derived from the code, not tested in the lab; run over stdio, or bind the HTTP modes to localhost behind an authenticating proxy, use an Account- or Site-scoped token, and leave the VirusTotal and Logfire keys unset unless needed`

- derived, not tested: proposed from the code analysis

## Lab runs

Not run yet.

## Questions and answers

**Why compare declared, code and lab?**

Declarations are often incomplete and scanners can be bypassed, so we run each tool once and compare.

**What rights does Purple AI MCP Server declare?**

files 0 (reads only files you give it), network 3 (can tunnel or exfiltrate), secrets 2 (reads broad tokens or the environment).

**What does its code suggest?**

reach 3 (privileged): network 3 (can tunnel or exfiltrate), secrets 2 (reads broad tokens or the environment), persistence 3 (adds autostart, users or keys); unknown: approval.

**What did it use when it ran in the lab?**

not run yet.

**Was it tried, and when?**

Not yet (tier listed).

**What changed since the last check?**

Upstream last pushed 2026-09-22; 0 release(s) since the pinned version.

**How do I run it with least privilege?**

Derived, not tested: note: derived from the code, not tested in the lab; run over stdio, or bind the HTTP modes to localhost behind an authenticating proxy, use an Account- or Site-scoped token, and leave the VirusTotal and Logfire keys unset unless needed

Method: https://readbeforerun.ai/method/
