SentinelOne API Patterns — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited SentinelOne API Patterns (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
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:
Authentication requires a Service User token from the SentinelOne Management Console:
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"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 |
{
"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"
}
}
}
}The Purple MCP server requires Python and uv/uvx:
# Install uv (Python package manager)
curl -LsSf https://astral.sh/uv/install.sh | sh
# Verify installation
uvx --version
# Test the MCP server
uvx --from git+https://github.com/Sentinel-One/purple-mcp.git purple-mcp --helpNote: This is a Python package, not Node.js. Useuvx, notnpx.
| Tool | Description | Parameters |
|---|---|---|
purple_ai | Natural language cybersecurity assistant for threat investigation and PowerQuery generation | query (required) - natural language question or investigation prompt |
| 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) |
| 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) |
| 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) |
| 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 |
| 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) |
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 |
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 |
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 100Best 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.
SentinelOne enforces rate limits on API calls. The Purple MCP server does not expose specific rate limit headers, but:
| 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 |
uvx --version returns a versionpython3 --version is availableuvx --from git+https://github.com/Sentinel-One/purple-mcp.git purple-mcp --helphttps:// and the full domainlist_alerts with limit=1 to verify connectivitypurple_ai for investigation before diving into specific tools~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.