SentinelOne Purple MCP Tools & API Patterns
Overview
SentinelOne provides the Purple MCP server for AI tool integration with the Singularity XDR platform. The MCP server is a Python package installed via uvx from GitHub. It exposes 23 tools covering Purple AI, alerts, vulnerabilities, misconfigurations, asset inventory, and PowerQuery threat hunting. All tools are read-only -- they support investigation and reporting but cannot modify, remediate, or take action on any resources.
The Purple MCP server has a dual API architecture:
- GraphQL API - Used for Purple AI, alerts, vulnerabilities, and misconfigurations
- REST API - Used for asset inventory
Anti-triggers
- "SentinelOne endpoint" meaning a machine. This skill's
endpoint
is an HTTP route; a workstation, server, or agent is
sentinelone-inventory.
- Writing or running an actual query. This skill covers filter and
pagination mechanics only — PowerQuery execution is
sentinelone-threat-hunting, and natural-language investigation is
sentinelone-purple-ai.
Connection & Authentication
Service User Token
Authentication requires a Service User token from the SentinelOne Management Console:
- Navigate to Policy & Settings > User Management > Service Users
- Create a Service User with appropriate Account or Site scope
- Generate an API token
CRITICAL: The token must be Account or Site level. Global-level tokens are rejected by the Purple MCP server and will return authentication errors.
Environment Variables:
| Variable |
Description |
PURPLEMCP_CONSOLE_TOKEN / SENTINELONE_TOKEN |
Service User API token |
PURPLEMCP_CONSOLE_BASE_URL / SENTINELONE_BASE_URL |
Console URL (e.g., https://your-console.sentinelone.net) |
export SENTINELONE_TOKEN="your-service-user-token"
export SENTINELONE_BASE_URL="https://your-console.sentinelone.net"
Transport Modes
The Purple MCP server supports three transport modes:
| Mode |
Flag |
Description |
Use Case |
| stdio |
--mode stdio |
Standard input/output |
Claude Desktop, local usage (recommended) |
| SSE |
--mode sse |
Server-Sent Events over HTTP |
Remote/shared access |
| Streamable HTTP |
--mode streamable-http |
HTTP with streaming |
Production deployments |
Claude Desktop Configuration
{
"mcpServers": {
"sentinelone": {
"command": "uvx",
"args": [
"--from", "git+https://github.com/Sentinel-One/purple-mcp.git",
"purple-mcp",
"--mode", "stdio"
],
"env": {
"PURPLEMCP_CONSOLE_TOKEN": "YOUR_SERVICE_USER_TOKEN",
"PURPLEMCP_CONSOLE_BASE_URL": "https://your-console.sentinelone.net"
}
}
}
}
Installation Requirements
The Purple MCP server requires Python and uv/uvx:
Install uv (Python package manager) following the official
instructions at https://docs.astral.sh/uv/getting-started/installation/
(e.g. pip install uv, or your OS package manager).
# Verify installation
uvx --version
# Test the MCP server
uvx --from git+https://github.com/Sentinel-One/purple-mcp.git purple-mcp --help
Note: This is a Python package, not Node.js. Use uvx, not npx.
Complete MCP Tool Reference
Purple AI Tools
| Tool |
Description |
Parameters |
purple_ai |
Natural language cybersecurity assistant for threat investigation and PowerQuery generation |
query (required) - natural language question or investigation prompt |
Alert Tools (GraphQL)
| Tool |
Description |
Parameters |
get_alert |
Get a single alert by ID |
alertId (required) |
list_alerts |
List alerts with filters |
severity, status, viewType, limit, cursor, sortBy, sortOrder |
search_alerts |
Search alerts with GraphQL filters |
filters (fieldId/filterType/values), limit, cursor |
get_alert_notes |
Get notes/comments on an alert |
alertId (required) |
get_alert_history |
Get timeline of changes for an alert |
alertId (required) |
Vulnerability Tools (GraphQL)
| Tool |
Description |
Parameters |
get_vulnerability |
Get a single vulnerability by ID |
vulnerabilityId (required) |
list_vulnerabilities |
List vulnerabilities with filters |
severity, status, limit, cursor, sortBy, sortOrder |
search_vulnerabilities |
Search vulnerabilities with GraphQL filters |
filters (fieldId/filterType/values), limit, cursor |
get_vulnerability_notes |
Get notes on a vulnerability |
vulnerabilityId (required) |
get_vulnerability_history |
Get timeline of changes for a vulnerability |
vulnerabilityId (required) |
Misconfiguration Tools (GraphQL)
| Tool |
Description |
Parameters |
get_misconfiguration |
Get a single misconfiguration by ID |
misconfigurationId (required) |
list_misconfigurations |
List misconfigurations with filters |
severity, status, viewType, limit, cursor, sortBy, sortOrder |
search_misconfigurations |
Search misconfigurations with GraphQL filters |
filters (fieldId/filterType/values), limit, cursor |
get_misconfiguration_notes |
Get notes on a misconfiguration |
misconfigurationId (required) |
get_misconfiguration_history |
Get timeline of changes for a misconfiguration |
misconfigurationId (required) |
Inventory Tools (REST)
| Tool |
Description |
Parameters |
get_inventory_item |
Get a single inventory item by ID |
itemId (required) |
list_inventory_items |
List inventory items with filters |
surface, limit, offset, sortBy, sortOrder |
search_inventory_items |
Search inventory with REST filters |
filters, surface, limit, offset |
PowerQuery / Data Lake Tools
| Tool |
Description |
Parameters |
powerquery |
Execute a PowerQuery against the Singularity Data Lake |
query (required), fromDate, toDate |
get_timestamp_range |
Get the available time range for PowerQuery data |
None |
iso_to_unix_timestamp |
Convert an ISO 8601 timestamp to Unix epoch milliseconds |
timestamp (required) |
Dual API Architecture
GraphQL API (Alerts, Vulnerabilities, Misconfigurations, Purple AI)
The GraphQL API uses a filter-based query model:
Filter Structure:
{
"fieldId": "severity",
"filterType": "EQUALS",
"values": ["CRITICAL"]
}
Filter Types:
| Filter Type |
Description |
Example |
EQUALS |
Exact match |
{"fieldId": "severity", "filterType": "EQUALS", "values": ["CRITICAL"]} |
CONTAINS |
Substring match |
{"fieldId": "name", "filterType": "CONTAINS", "values": ["ransomware"]} |
IN |
Match any in list |
{"fieldId": "status", "filterType": "IN", "values": ["NEW", "IN_PROGRESS"]} |
NOT_EQUALS |
Negation |
{"fieldId": "status", "filterType": "NOT_EQUALS", "values": ["RESOLVED"]} |
Pagination: Cursor-based. Use the cursor value from the response to fetch the next page.
Sorting:
| Parameter |
Values |
sortBy |
Varies by resource (e.g., severity, detectedAt, status) |
sortOrder |
ASC, DESC |
REST API (Inventory)
The REST API uses offset-based pagination with filter parameters:
Filter Types:
| Type |
Description |
Example |
| Exact match |
Direct value comparison |
surface=ENDPOINT |
| Contains |
Substring matching |
name__contains=server |
| Range |
Numeric/date ranges |
lastSeen__gte=2026-01-01 |
| ID list |
Match multiple IDs |
ids=id1,id2,id3 |
| Negation |
Exclude matches |
status__ne=INACTIVE |
Pagination:
| Parameter |
Description |
Default |
limit |
Results per page |
50 |
offset |
Skip N results |
0 |
PowerQuery Language
IMPORTANT: PowerQuery is SentinelOne's Scalyr-based pipeline query language. It is NOT Splunk SPL, SQL, KQL, or Elasticsearch Query DSL.
PowerQuery uses a pipeline syntax with filters and aggregations:
EventType = "Process Creation" AND TgtProcName = "powershell.exe"
| columns SrcProcName, TgtProcName, TgtProcCmdLine, EndpointName
| limit 100
Best practice: Use the purple_ai tool with a natural language description of what you want to find, and it will generate the correct PowerQuery syntax. Then execute the generated query with the powerquery tool.
Rate Limiting
SentinelOne enforces rate limits on API calls. The Purple MCP server does not expose specific rate limit headers, but:
- Space out requests when iterating over large datasets
- Use pagination to limit result sizes
- If you receive rate limit errors, wait 30-60 seconds before retrying
- Filter server-side to reduce total API calls
Error Handling
Common Errors
| Error |
Cause |
Resolution |
| 401 Unauthorized |
Invalid or expired token |
Regenerate Service User token |
| 403 Forbidden |
Global-level token used |
Use Account or Site-level token instead |
| Tool not found |
MCP server not connected |
Verify uvx installation and environment variables |
| Invalid query |
Malformed PowerQuery syntax |
Use purple_ai to generate correct syntax |
| Resource not found |
Invalid ID |
Verify the resource ID exists |
| Timeout |
Query too broad or Data Lake overloaded |
Narrow time range or add filters |
Troubleshooting MCP Connection
- Verify uvx - Ensure
uvx --version returns a version
- Check Python - Ensure
python3 --version is available
- Test manually - Run
uvx --from git+https://github.com/Sentinel-One/purple-mcp.git purple-mcp --help
- Verify token - Ensure the token is Account or Site level, not Global
- Check console URL - Must include
https:// and the full domain
- Test with a simple call - Try
list_alerts with limit=1 to verify connectivity
Best Practices
- Use Account/Site tokens - Never use Global-level tokens; they will be rejected
- Start with Purple AI - Use
purple_ai for investigation before diving into specific tools
- Use cursor pagination - For GraphQL tools, use the cursor from each response to fetch subsequent pages
- Scope to clients - When reviewing a specific client's security, filter by site or account
- Time-bound queries - Always set time ranges for PowerQuery to avoid scanning the entire Data Lake
- Cache inventory data - Endpoint and asset data changes less frequently than alerts
- Triage by severity - Always start with CRITICAL and HIGH severity items
- Document findings - Use alert notes and history to build investigation timelines
Related Skills
1---2name: sentinelone-api-patterns3description: The SentinelOne Purple MCP server and the APIs behind it: uvx installation and transport modes, Service User token levels, the 23 read-only tools organized by domain, and the dual GraphQL (cursor pagination) / REST (offset pagination) architecture with its differing filter syntaxes, rate limits, and error causes.4---56# SentinelOne Purple MCP Tools & API Patterns78## Overview910SentinelOne provides the Purple MCP server for AI tool integration with the Singularity XDR platform. The MCP server is a Python package installed via `uvx` from GitHub. It exposes 23 tools covering Purple AI, alerts, vulnerabilities, misconfigurations, asset inventory, and PowerQuery threat hunting. All tools are **read-only** -- they support investigation and reporting but cannot modify, remediate, or take action on any resources.1112The Purple MCP server has a dual API architecture:13- **GraphQL API** - Used for Purple AI, alerts, vulnerabilities, and misconfigurations14- **REST API** - Used for asset inventory1516## Anti-triggers1718- **"SentinelOne endpoint" meaning a machine.** This skill's `endpoint`19 is an HTTP route; a workstation, server, or agent is20 `sentinelone-inventory`.21- **Writing or running an actual query.** This skill covers filter and22 pagination mechanics only — PowerQuery execution is23 `sentinelone-threat-hunting`, and natural-language investigation is24 `sentinelone-purple-ai`.2526## Connection & Authentication2728### Service User Token2930Authentication requires a Service User token from the SentinelOne Management Console:31321. Navigate to **Policy & Settings > User Management > Service Users**332. Create a Service User with appropriate Account or Site scope343. Generate an API token3536> **CRITICAL:** The token must be **Account** or **Site** level. **Global-level tokens are rejected** by the Purple MCP server and will return authentication errors.3738**Environment Variables:**3940| Variable | Description |41|----------|-------------|42| `PURPLEMCP_CONSOLE_TOKEN` / `SENTINELONE_TOKEN` | Service User API token |43| `PURPLEMCP_CONSOLE_BASE_URL` / `SENTINELONE_BASE_URL` | Console URL (e.g., `https://your-console.sentinelone.net`) |4445```bash46export SENTINELONE_TOKEN="your-service-user-token"47export SENTINELONE_BASE_URL="https://your-console.sentinelone.net"48```4950### Transport Modes5152The Purple MCP server supports three transport modes:5354| Mode | Flag | Description | Use Case |55|------|------|-------------|----------|56| stdio | `--mode stdio` | Standard input/output | Claude Desktop, local usage (recommended) |57| SSE | `--mode sse` | Server-Sent Events over HTTP | Remote/shared access |58| Streamable HTTP | `--mode streamable-http` | HTTP with streaming | Production deployments |5960### Claude Desktop Configuration6162```json63{64 "mcpServers": {65 "sentinelone": {66 "command": "uvx",67 "args": [68 "--from", "git+https://github.com/Sentinel-One/purple-mcp.git",69 "purple-mcp",70 "--mode", "stdio"71 ],72 "env": {73 "PURPLEMCP_CONSOLE_TOKEN": "YOUR_SERVICE_USER_TOKEN",74 "PURPLEMCP_CONSOLE_BASE_URL": "https://your-console.sentinelone.net"75 }76 }77 }78}79```8081### Installation Requirements8283The Purple MCP server requires Python and `uv`/`uvx`:8485Install `uv` (Python package manager) following the official86instructions at https://docs.astral.sh/uv/getting-started/installation/87(e.g. `pip install uv`, or your OS package manager).8889```bash90# Verify installation91uvx --version9293# Test the MCP server94uvx --from git+https://github.com/Sentinel-One/purple-mcp.git purple-mcp --help95```9697> **Note:** This is a Python package, not Node.js. Use `uvx`, not `npx`.9899## Complete MCP Tool Reference100101### Purple AI Tools102103| Tool | Description | Parameters |104|------|-------------|------------|105| `purple_ai` | Natural language cybersecurity assistant for threat investigation and PowerQuery generation | `query` (required) - natural language question or investigation prompt |106107### Alert Tools (GraphQL)108109| Tool | Description | Parameters |110|------|-------------|------------|111| `get_alert` | Get a single alert by ID | `alertId` (required) |112| `list_alerts` | List alerts with filters | `severity`, `status`, `viewType`, `limit`, `cursor`, `sortBy`, `sortOrder` |113| `search_alerts` | Search alerts with GraphQL filters | `filters` (fieldId/filterType/values), `limit`, `cursor` |114| `get_alert_notes` | Get notes/comments on an alert | `alertId` (required) |115| `get_alert_history` | Get timeline of changes for an alert | `alertId` (required) |116117### Vulnerability Tools (GraphQL)118119| Tool | Description | Parameters |120|------|-------------|------------|121| `get_vulnerability` | Get a single vulnerability by ID | `vulnerabilityId` (required) |122| `list_vulnerabilities` | List vulnerabilities with filters | `severity`, `status`, `limit`, `cursor`, `sortBy`, `sortOrder` |123| `search_vulnerabilities` | Search vulnerabilities with GraphQL filters | `filters` (fieldId/filterType/values), `limit`, `cursor` |124| `get_vulnerability_notes` | Get notes on a vulnerability | `vulnerabilityId` (required) |125| `get_vulnerability_history` | Get timeline of changes for a vulnerability | `vulnerabilityId` (required) |126127### Misconfiguration Tools (GraphQL)128129| Tool | Description | Parameters |130|------|-------------|------------|131| `get_misconfiguration` | Get a single misconfiguration by ID | `misconfigurationId` (required) |132| `list_misconfigurations` | List misconfigurations with filters | `severity`, `status`, `viewType`, `limit`, `cursor`, `sortBy`, `sortOrder` |133| `search_misconfigurations` | Search misconfigurations with GraphQL filters | `filters` (fieldId/filterType/values), `limit`, `cursor` |134| `get_misconfiguration_notes` | Get notes on a misconfiguration | `misconfigurationId` (required) |135| `get_misconfiguration_history` | Get timeline of changes for a misconfiguration | `misconfigurationId` (required) |136137### Inventory Tools (REST)138139| Tool | Description | Parameters |140|------|-------------|------------|141| `get_inventory_item` | Get a single inventory item by ID | `itemId` (required) |142| `list_inventory_items` | List inventory items with filters | `surface`, `limit`, `offset`, `sortBy`, `sortOrder` |143| `search_inventory_items` | Search inventory with REST filters | `filters`, `surface`, `limit`, `offset` |144145### PowerQuery / Data Lake Tools146147| Tool | Description | Parameters |148|------|-------------|------------|149| `powerquery` | Execute a PowerQuery against the Singularity Data Lake | `query` (required), `fromDate`, `toDate` |150| `get_timestamp_range` | Get the available time range for PowerQuery data | None |151| `iso_to_unix_timestamp` | Convert an ISO 8601 timestamp to Unix epoch milliseconds | `timestamp` (required) |152153## Dual API Architecture154155### GraphQL API (Alerts, Vulnerabilities, Misconfigurations, Purple AI)156157The GraphQL API uses a filter-based query model:158159**Filter Structure:**160161```json162{163 "fieldId": "severity",164 "filterType": "EQUALS",165 "values": ["CRITICAL"]166}167```168169**Filter Types:**170171| Filter Type | Description | Example |172|-------------|-------------|---------|173| `EQUALS` | Exact match | `{"fieldId": "severity", "filterType": "EQUALS", "values": ["CRITICAL"]}` |174| `CONTAINS` | Substring match | `{"fieldId": "name", "filterType": "CONTAINS", "values": ["ransomware"]}` |175| `IN` | Match any in list | `{"fieldId": "status", "filterType": "IN", "values": ["NEW", "IN_PROGRESS"]}` |176| `NOT_EQUALS` | Negation | `{"fieldId": "status", "filterType": "NOT_EQUALS", "values": ["RESOLVED"]}` |177178**Pagination:** Cursor-based. Use the `cursor` value from the response to fetch the next page.179180**Sorting:**181182| Parameter | Values |183|-----------|--------|184| `sortBy` | Varies by resource (e.g., `severity`, `detectedAt`, `status`) |185| `sortOrder` | `ASC`, `DESC` |186187### REST API (Inventory)188189The REST API uses offset-based pagination with filter parameters:190191**Filter Types:**192193| Type | Description | Example |194|------|-------------|---------|195| Exact match | Direct value comparison | `surface=ENDPOINT` |196| Contains | Substring matching | `name__contains=server` |197| Range | Numeric/date ranges | `lastSeen__gte=2026-01-01` |198| ID list | Match multiple IDs | `ids=id1,id2,id3` |199| Negation | Exclude matches | `status__ne=INACTIVE` |200201**Pagination:**202203| Parameter | Description | Default |204|-----------|-------------|---------|205| `limit` | Results per page | 50 |206| `offset` | Skip N results | 0 |207208## PowerQuery Language209210> **IMPORTANT:** PowerQuery is SentinelOne's Scalyr-based pipeline query language. It is **NOT** Splunk SPL, SQL, KQL, or Elasticsearch Query DSL.211212PowerQuery uses a pipeline syntax with filters and aggregations:213214```215EventType = "Process Creation" AND TgtProcName = "powershell.exe"216| columns SrcProcName, TgtProcName, TgtProcCmdLine, EndpointName217| limit 100218```219220**Best practice:** Use the `purple_ai` tool with a natural language description of what you want to find, and it will generate the correct PowerQuery syntax. Then execute the generated query with the `powerquery` tool.221222## Rate Limiting223224SentinelOne enforces rate limits on API calls. The Purple MCP server does not expose specific rate limit headers, but:225226- Space out requests when iterating over large datasets227- Use pagination to limit result sizes228- If you receive rate limit errors, wait 30-60 seconds before retrying229- Filter server-side to reduce total API calls230231## Error Handling232233### Common Errors234235| Error | Cause | Resolution |236|-------|-------|------------|237| 401 Unauthorized | Invalid or expired token | Regenerate Service User token |238| 403 Forbidden | Global-level token used | Use Account or Site-level token instead |239| Tool not found | MCP server not connected | Verify uvx installation and environment variables |240| Invalid query | Malformed PowerQuery syntax | Use `purple_ai` to generate correct syntax |241| Resource not found | Invalid ID | Verify the resource ID exists |242| Timeout | Query too broad or Data Lake overloaded | Narrow time range or add filters |243244### Troubleshooting MCP Connection2452461. **Verify uvx** - Ensure `uvx --version` returns a version2472. **Check Python** - Ensure `python3 --version` is available2483. **Test manually** - Run `uvx --from git+https://github.com/Sentinel-One/purple-mcp.git purple-mcp --help`2494. **Verify token** - Ensure the token is Account or Site level, not Global2505. **Check console URL** - Must include `https://` and the full domain2516. **Test with a simple call** - Try `list_alerts` with `limit=1` to verify connectivity252253## Best Practices2542551. **Use Account/Site tokens** - Never use Global-level tokens; they will be rejected2562. **Start with Purple AI** - Use `purple_ai` for investigation before diving into specific tools2573. **Use cursor pagination** - For GraphQL tools, use the cursor from each response to fetch subsequent pages2584. **Scope to clients** - When reviewing a specific client's security, filter by site or account2595. **Time-bound queries** - Always set time ranges for PowerQuery to avoid scanning the entire Data Lake2606. **Cache inventory data** - Endpoint and asset data changes less frequently than alerts2617. **Triage by severity** - Always start with CRITICAL and HIGH severity items2628. **Document findings** - Use alert notes and history to build investigation timelines263264## Related Skills265266- [Purple AI](../purple-ai/SKILL.md) - Natural language threat investigation267- [Alerts](../alerts/SKILL.md) - Unified alert management268- [Vulnerabilities](../vulnerabilities/SKILL.md) - Vulnerability tracking and remediation269- [Misconfigurations](../misconfigurations/SKILL.md) - Cloud security posture management270- [Inventory](../inventory/SKILL.md) - Asset inventory271- [Threat Hunting](../threat-hunting/SKILL.md) - PowerQuery and Data Lake queries