JupiterOne AI Integration (MCP Server)
The JupiterOne Model Context Protocol (MCP) Server enables AI assistants like Claude (on claude.ai and Claude Desktop), Claude Code, Cursor, and Amazon Kiro to interact directly with your JupiterOne account using natural language.
Prerequisites
- Active JupiterOne account with API access
- JupiterOne API key and account ID
- Node.js version 20 or higher (for local server only)
- AI assistant with MCP support (Claude on claude.ai, Claude Desktop, Claude Code, Cursor IDE, ChatGPT, GitHub Copilot, Continue.dev, Cline, Devin Desktop (formerly Windsurf), Amazon Kiro, etc.)
Installation Methods
Install from the Claude connector directory (easiest)
JupiterOne is published in the Claude connector directory. If you use Claude, this is the fastest path — there is no JSON to edit and no URL to construct.
- Open claude.ai/directory/jupiterone.
- Click Connect and choose your JupiterOne region.
- Sign in to JupiterOne, then approve the consent screen — it lists what the connector will be allowed to do before anything is granted.
The directory connector uses JupiterOne's hosted remote server, so it requires no local installation and stays on the current release automatically.
The directory connector is not tied to one account. If your sign-in can reach more than one, ask Claude to "list my JupiterOne accounts" — every tool acts on one account per call, and list-accounts returns each account you can use along with its accountId.
Have an AI set this up for you
If you'd rather not edit JSON by hand, copy the prompt below and paste it into your AI assistant. It will ask for the credentials it needs and walk you through the install.
Preview the prompt
Help me install the JupiterOne MCP server in this client. The setup docs are at https://docs.jupiterone.io/integrations/jupiterone-mcp-server.
- Ask whether I want the remote (OAuth, recommended) or local (API key) deployment.
- If local, ask me for my JupiterOne API key and account ID. My account ID can be found at https://docs.jupiterone.io/features/admin/admin-settings#account-management — this is the account ID, not the vanity domain.
- Show me the JSON to add to your MCP config file. If a config already exists, preserve existing servers and merge mine in.
- Tell me how to restart and verify the server is connected.
Manual setup
The JupiterOne MCP Server can be configured in two ways:
Option 1: Remote HTTP Server (Recommended)
Use JupiterOne's hosted MCP server without local installation:
- URL Format:
https://your-account-id-here.mcp.<REGION>.jupiterone.io/mcp - Example:
https://j1dev.mcp.us.jupiterone.io/mcp - Authentication: OAuth-based authentication with JupiterOne login
Replace <REGION> with us or eu based on your JupiterOne instance. The examples in this guide use us.
The remote HTTP server option:
- Requires no local installation
- Handles authentication through JupiterOne's OAuth flow
- Automatically stays up-to-date with the latest features
- Works across different machines without setup
Option 2: Local Server (stdio)
Install and run the MCP server locally using npx:
npx @jupiterone/jupiterone-mcp
Or install globally for repeated use:
npm install -g @jupiterone/jupiterone-mcp
Configuration
Get Your Credentials
For Remote Server (Option 1)
- Account ID: Found in Account Management
- Region: Your JupiterOne instance region (e.g.,
us,eu)
For Local Server (Option 2)
- API Key: Navigate to Settings → User API Tokens in JupiterOne and create a new API key
- Account ID: Found in Account Management or by running:
find jupiterone_account as x return x.accountId
- Local Server: Uses API key authentication and runs within the context of the user, respecting RBAC configuration
- Remote Server: Uses OAuth authentication through JupiterOne login, automatically applying your user permissions
- Remote Server with an API token: For unattended agents and scheduled workflows that cannot complete a sign-in. See API tokens for agentic workflows.
AI Platform Setup
- Claude Desktop
- Claude Code
- Cursor IDE
- GitHub Copilot
- Continue.dev
- Cline (VS Code Extension)
- Devin Desktop
- Amazon Kiro
Configuration file location:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
Local server
Edit the configuration file above and add:
Local Server Configuration:
{
"mcpServers": {
"jupiterone": {
"command": "npx",
"args": ["-y", "@jupiterone/jupiterone-mcp"],
"env": {
"JUPITERONE_API_KEY": "your-api-key-here",
"JUPITERONE_ACCOUNT_ID": "your-account-id-here"
}
}
}
}
Restart Claude Desktop.
Remote server
In the Claude Desktop App:
- Navigate to Settings → Connectors.
- Click Add custom connector at the bottom of the section.
- Set the title to
JupiterOneand the URL tohttps://your-account-id-here.mcp.us.jupiterone.io/mcp. - Click Add and complete the OAuth sign-in.
Claude Code supports MCP via CLI command or config file.
Option A — CLI (recommended)
For the local server:
claude mcp add jupiterone -- npx -y @jupiterone/jupiterone-mcp \
--env JUPITERONE_API_KEY=your-api-key-here \
--env JUPITERONE_ACCOUNT_ID=your-account-id-here
For the remote server:
claude mcp add --transport http jupiterone https://your-account-id-here.mcp.us.jupiterone.io/mcp
Option B — Config file
Edit ~/.claude.json (user-level) or create .mcp.json in your project root (project-level, can be checked into source control):
Local Server Configuration:
{
"mcpServers": {
"jupiterone": {
"command": "npx",
"args": ["-y", "@jupiterone/jupiterone-mcp"],
"env": {
"JUPITERONE_API_KEY": "your-api-key-here",
"JUPITERONE_ACCOUNT_ID": "your-account-id-here"
}
}
}
}
Remote Server Configuration:
{
"mcpServers": {
"jupiterone": {
"url": "https://your-account-id-here.mcp.us.jupiterone.io/mcp"
}
}
}
Replace us with eu if your JupiterOne instance is in the EU region.
Run /mcp inside Claude Code to verify the server is connected.
- Open Cursor Settings (⌘+, on Mac, Ctrl+, on Windows).
- Navigate to Features → Model Context Protocol.
- Add configuration based on your chosen method:
Local Server Configuration:
{
"mcpServers": {
"jupiterone": {
"command": "npx",
"args": ["-y", "@jupiterone/jupiterone-mcp"],
"env": {
"JUPITERONE_API_KEY": "your-api-key-here",
"JUPITERONE_ACCOUNT_ID": "your-account-id-here"
}
}
}
}
Remote Server Configuration:
{
"mcpServers": {
"jupiterone": {
"url": "https://your-account-id-here.mcp.us.jupiterone.io/mcp"
}
}
}
Replace us with eu if your JupiterOne instance is in the EU region.
- Restart Cursor.
If you've previously connected to JupiterOne or need to switch accounts:
- In Cursor Settings, navigate to Features → Model Context Protocol.
- Expand the Tools enabled section for the JupiterOne MCP server.
- Click the Logout button at the top.
- Restart Cursor to reauthenticate with your JupiterOne account.
GitHub Copilot MCP support is generally available in Visual Studio Code, JetBrains, Eclipse, and Xcode. The MCP servers in Copilot policy is disabled by default and must be enabled by an organization or enterprise administrator before Copilot can connect to JupiterOne.
- Create
.vscode/mcp.jsonin your project root. - Add configuration based on your chosen method.
Local Server Configuration:
{
"servers": {
"jupiterone": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@jupiterone/jupiterone-mcp"],
"env": {
"JUPITERONE_API_KEY": "your-api-key-here",
"JUPITERONE_ACCOUNT_ID": "your-account-id-here"
}
}
}
}
Remote Server Configuration:
{
"servers": {
"jupiterone": {
"type": "http",
"url": "https://your-account-id-here.mcp.us.jupiterone.io/mcp"
}
}
}
- Click Start in the gutter of
.vscode/mcp.jsonto launch the server. - Open Copilot Chat, select Agent mode, and click the tools icon to confirm JupiterOne tools are listed.
For details, see the GitHub Copilot MCP documentation.
- Open Continue.dev settings.
- Navigate to MCP configuration.
- Add configuration based on your chosen method:
Local Server Configuration:
{
"mcpServers": {
"jupiterone": {
"command": "npx",
"args": ["-y", "@jupiterone/jupiterone-mcp"],
"env": {
"JUPITERONE_API_KEY": "your-api-key-here",
"JUPITERONE_ACCOUNT_ID": "your-account-id-here"
}
}
}
}
Remote Server Configuration:
{
"mcpServers": {
"jupiterone": {
"url": "https://your-account-id-here.mcp.us.jupiterone.io/mcp"
}
}
}
Replace us with eu if your JupiterOne instance is in the EU region.
- Install the Cline extension from the VS Code marketplace.
- Open VS Code settings (⌘+, on Mac, Ctrl+, on Windows).
- Search for "Cline MCP".
- Add configuration based on your chosen method:
Local Server Configuration:
{
"mcpServers": {
"jupiterone": {
"command": "npx",
"args": ["-y", "@jupiterone/jupiterone-mcp"],
"env": {
"JUPITERONE_API_KEY": "your-api-key-here",
"JUPITERONE_ACCOUNT_ID": "your-account-id-here"
}
}
}
}
Remote Server Configuration:
{
"mcpServers": {
"jupiterone": {
"url": "https://your-account-id-here.mcp.us.jupiterone.io/mcp"
}
}
}
Replace us with eu if your JupiterOne instance is in the EU region.
Windsurf was rebranded as Devin Desktop by Cognition in June 2026. Existing installs received the change as an over-the-air update, and the configuration file path still uses the original windsurf directory name.
- Open Devin Settings → Cascade → MCP Servers, or click the MCPs icon in the top-right menu of the Cascade panel.
- Open the raw configuration file,
~/.codeium/windsurf/mcp_config.json. - Add configuration based on your chosen method:
Local Server Configuration:
{
"mcpServers": {
"jupiterone": {
"command": "npx",
"args": ["-y", "@jupiterone/jupiterone-mcp"],
"env": {
"JUPITERONE_API_KEY": "your-api-key-here",
"JUPITERONE_ACCOUNT_ID": "your-account-id-here"
}
}
}
}
Remote Server Configuration:
{
"mcpServers": {
"jupiterone": {
"url": "https://your-account-id-here.mcp.us.jupiterone.io/mcp"
}
}
}
Replace us with eu if your JupiterOne instance is in the EU region.
- Restart Devin Desktop.
-
Locate or create your Kiro MCP configuration file:
- Workspace (project-specific):
.kiro/settings/mcp.jsonin your project root - User (global):
~/.kiro/settings/mcp.json
Workspace settings override user settings when both define the same server.
- Workspace (project-specific):
-
Add configuration based on your chosen method.
Local Server Configuration:
{
"mcpServers": {
"jupiterone": {
"command": "npx",
"args": ["-y", "@jupiterone/jupiterone-mcp"],
"env": {
"JUPITERONE_API_KEY": "your-api-key-here",
"JUPITERONE_ACCOUNT_ID": "your-account-id-here"
},
"disabled": false,
"autoApprove": []
}
}
}
Remote Server Configuration:
{
"mcpServers": {
"jupiterone": {
"url": "https://your-account-id-here.mcp.us.jupiterone.io/mcp",
"disabled": false,
"autoApprove": []
}
}
}
-
Save the file. Kiro applies
autoApproveanddisabledToolschanges immediately, but you must restart Kiro to register a newly added server. -
Verify the connection by opening Kiro's Output panel and selecting Kiro - MCP Logs.
Kiro supports stdio and HTTP transports natively but does not currently support SSE.
Verify Installation
Once configured, test the connection by asking your AI assistant:
"List my JupiterOne integrations"
A successful response confirms the MCP server is connected and authenticated. If you receive an error or no response, see Troubleshooting.
What You Can Do
The MCP server provides 55 tools spanning query execution, asset criticality, threat intelligence, compliance status, authoring and attestations, alert monitoring, rules management, dashboard management, integration monitoring, and account discovery. Ask your AI assistant questions in natural language — it selects the right tool and, when a query is needed, writes the J1QL for you.
Prompt Templates by Use Case
Copy any prompt below and paste it into your AI assistant. Where a prompt produces a J1QL query, the query is shown so you can learn the syntax or adapt it.
- Asset Inventory
- Asset Criticality
- Identity & Access
- Vulnerabilities
- Threat Intelligence
- Compliance (CCM)
- Alerts & Dashboards
- Integrations
| Prompt | J1QL the AI generates |
|---|---|
| "How many cloud instances do I have, broken down by provider?" | Find Host with _integrationType != undefined as h return h._integrationType as Provider, count(h) as Total |
| "List all data stores that are not encrypted" | Find DataStore with encrypted != true |
| "Show me all resources without a data classification tag" | Find (Host|DataStore) with classification = undefined |
| "Which S3 buckets are publicly accessible?" | Find aws_s3_bucket with classification = 'Public' OR bucketPolicy.public = true |
| "Find all hosts that have not been scanned in the last 30 days" | Find Host that !has Assessment with _createdOn > date.now-30days |
| Prompt | J1QL the AI generates |
|---|---|
| "Which assets are in our most critical level?" | Find * with j1.normalizedCriticality = 0 limit 250 |
| "How many assets are in each criticality level?" | Find * with j1.criticality != undefined as e return e.j1.criticality as level, count(e) as total |
| "Show open vulnerabilities on devices in our two most critical levels, highest risk first" | Find UnifiedVulnerability as uv that is Vulnerability with open = true that has (Host|Device) that is UnifiedDevice with j1.normalizedCriticality <= 1 as ud return ud.displayName as device, ud.j1.criticality as level, j1.riskScore(uv, ud) as score order by score desc limit 25 |
| "Set up asset criticality for our account" | Uses get-graph-context to see what the account holds, execute-j1ql-query to prove each level's query, then update-asset-criticality with the levels and their queries |
| "Put our production databases in the most critical level" | Uses get-asset-criticality, proves the new query with execute-j1ql-query, then update-asset-criticality with upsertQueries |
| "Rename the High value level to Tier 1" | Uses get-asset-criticality for the level's slug, then update-asset-criticality with the full levels list; the result says how rules and widgets filtering on that level are affected |
| Prompt | J1QL the AI generates |
|---|---|
| "Who has admin access across all providers?" | Find AccessRole with admin = true as role that assigned User as user return user.displayName, role.displayName, role._integrationType |
| "Find users with MFA disabled" | Find User with mfaEnabled != true |
| "Which service accounts have not been rotated in 90 days?" | Find AccessKey with createdOn < date.now-90days as key return key.displayName, key._integrationType, key.createdOn |
| "List new hires from the last 12 months" | Find employee with _createdOn > date.now-12months |
| "Find all users who can assume a role in a production account" | Find User that assigned AccessRole that assigned Account with tag.Production = true |
| Prompt | J1QL the AI generates |
|---|---|
| "Show me all critical vulnerabilities from the last 7 days" | Find Finding with severity = 'critical' and _createdOn > date.now-7days as f return f.displayName, f.severity, f.numericSeverity |
| "Which applications have open vulnerabilities?" | Find Application as app that has Vulnerability as vuln return app.displayName, vuln.displayName, vuln.severity |
| "Are there any hosts with both public exposure and critical vulnerabilities?" | Find Host with publicIpAddress != undefined that has Finding with severity = 'critical' |
| "Find vulnerabilities that have been open for more than 30 days" | Find Vulnerability with _createdOn < date.now-30days and open = true |
| "Count open findings by severity" | Find Finding with open = true as f return f.severity as Severity, count(f) as total |
| Prompt | J1QL the AI generates |
|---|---|
| "What's the threat brief for CVE-2021-44228?" | Uses get-threat tool directly |
| "What CVEs are trending right now?" | Uses get-threat-trending tool directly |
| "Am I exposed to Log4Shell?" | Uses check-threat-exposure tool directly |
| "Check my exposure to everything trending this week" | Uses get-threat-trending then check-threat-exposure with the returned CVE IDs |
| "Which of my devices carry CVE-2021-44228?" | check-threat-exposure returns a unifiedVulnerabilityId, then Find * with _id = '<unifiedVulnerabilityId>' that relates to Finding as f that relates to (Host|Device|Domain) as a return a.displayName, a._type, f._type, f._beginOn order by f._beginOn desc limit 50 |
| Prompt | J1QL the AI generates |
|---|---|
| "How is our SOC 2 posture, section by section?" | Uses get-compliance-summary to find the framework, then calls it again with that frameworkId |
| "Which controls are failing for the Platform team's org unit?" | Uses list-controls tool with the status filter set to FAIL and orgUnit set to the org unit's name |
| "Why is control 3.14 failing, and which assets are affected?" | Uses get-control with identifier, then get-rule-evaluation-query-results with the failing test's rawDataKey |
| "Attest control 3.14 with our Log Management Policy, expiring 2027-06-30" | Uses get-control to resolve the control, then create-attestation |
| "Renew the attestations expiring this month for another year" | Uses get-compliance-summary to find expiring attestations, then update-attestation with a later expiresOn |
| "Do we already cover PCI DSS 4.0, or can we import it?" | Uses check-compliance-coverage, then import-framework with the returned source and sourceId |
| "Build a framework from our internal security policy, with a test for each control" | Uses the Author a compliance framework prompt: create-framework, create-requirements, create-controls or link-controls, then execute-j1ql-query to prove each query and create-control-test |
| "Run the draft controls' tests and promote the ones that pass" | Uses evaluate-controls, get-control for each result, then transition-controls for the controls you choose |
| "Exempt these three decommissioned hosts from the MFA control test" | Uses get-control for the test, get-rule-evaluation-query-results for the asset ids, then create-exemptions |
| "Find the control with the failing S3 logging test" | Uses list-controls with search, reading testNameMatches |
| Prompt | J1QL the AI generates |
|---|---|
| "Get all active alerts" | Uses get-active-alerts tool directly |
| "List all my alert rules" | Uses list-rules tool directly |
| "Create a rule that fires when a new critical vulnerability is found" | Uses create-inline-question-rule tool with a Finding query |
| "Show me the Slack message that rule would post before you save it" | Uses preview-rule-actions with the draft rule, then create-inline-question-rule |
| "Show my dashboards" | Uses get-dashboards tool directly |
| "Create a dashboard tracking my biggest security risks" | Uses create-dashboard + create-dashboard-widget tools |
| Prompt | J1QL the AI generates |
|---|---|
| "List my JupiterOne integrations" | Uses get-integration-instances tool directly |
| "Which integrations failed their last run?" | Uses get-integration-jobs tool with status filter |
| "Show me the event log for the latest AWS integration job" | Uses get-integration-jobs then get-integration-events tools |
| "What integration types are available?" | Uses get-integration-definitions tool directly |
| "Is my CrowdStrike integration healthy?" | Uses get-integration-instances then get-integration-jobs tools |
For the full J1QL language reference, including traversals, aggregations, and filtering, see the J1QL documentation.
Available Tools
The MCP server exposes the following tools. Your AI assistant selects the right tool automatically based on your question.
Query Execution
| Tool | Description |
|---|---|
execute-j1ql-query | Execute any J1QL query. Supports variables, cursor-based pagination, deleted entity inclusion, scope filters, and query flags. A query that reads asset criticality also returns your account's levels and the filters that select each. |
get-query-results | Retrieve results of a long-running query. Use when execute-j1ql-query returns status: "IN_PROGRESS" with a resultsUrl. |
get-graph-context | Where your assistant starts before writing J1QL: the entity classes and types your account holds, each with a count, and your asset criticality levels with the filters that select each. Called list-entity-types before 2.9.0. |
Asset Criticality
These tools read and change your account's asset criticality setup: the ordered levels that classify assets by business impact, and the J1QL queries that fill them. Reading the setup needs Assets: Admin, Vulnerabilities: Admin or full admin; changing it needs Assets: Admin with Shared: Graph Data: Read, or full admin. The Asset criticality page in the app needs Assets: Admin.
| Tool | Description |
|---|---|
get-asset-criticality | Your setup: each level, most critical first, with its value on assets (j1.criticality), its rank (j1.normalizedCriticality, 0 most critical), its risk-score multiplier, how many assets carry it, the J1QL queries that fill it and a ready query for its assets; plus the latest runs that applied the setup. |
update-asset-criticality | Set up asset criticality or change it in one call: add, rename, reorder or remove levels (2–6), and create, change, move or remove the queries that fill them (up to 50). Every query is checked before anything is saved: it must return the complete set of its level's assets, so no LIMIT or SKIP, in at most 1,024 characters, and a plain filter such as FIND DataStore WITH tag.PCI = true has its RETURN added. Reports how many assets each saved query matches now and what the change does to assets: a renamed level's new value, renumbered ranks, levels left without a query, and how rules and widgets filtering on a changed level are affected. Repeating a call is safe. Risk-score multipliers are not changed. |
Your assistant sees the levels without these tools. get-graph-context returns them, a J1QL query that reads j1.criticality or j1.normalizedCriticality returns them beside its rows, and MCP clients that read resources can read them from jupiterone://asset-criticality. These need only permission to read graph data. A query that filters on a value no level has and returns nothing comes back with the levels and, when the value plainly names one, a corrected query.
Reading a criticality result. The setup is saved at once, but only a run writes levels onto assets. Runs happen every hour and after each save. A save's run waits for any run still in progress or still applying its changes, and starts no sooner than 15 minutes after the last run started; one run changes at most 100,000 assets and leaves the rest to the next. Until a run that started after the save completes, asset counts, queries, rules and widgets see the levels as they were: a new or renamed level's value matches nothing yet, and a rank selects the level that held it before. get-asset-criticality sets runPending when its counts may trail the setup, and counts in valuesOutsideLevels the assets still carrying a renamed or removed level's old value; a save has reached assets once runs lists a COMPLETE run that started after it. The match count update-asset-criticality reports for a query is what the next run applies, not what assets carry yet. not_configured means the account has no levels, so an empty result on j1.criticality means "not classified", never "no critical assets". read_failed means the setup could not be read in time; call again.
Threat Intelligence
These tools require the Vulnerability Management entitlement on your account plus vulnerability read permission. Without them the tools return an access-denied message naming the entitlement.
| Tool | Description |
|---|---|
get-threat | Threat brief for a single CVE — severity, exploitation status, KEV listing, remediation window, and the affected vendor and product. Returns a compact decision-first summary by default; detail: true returns the full brief including CPE footprint, threat-actor techniques, and detection tooling. |
get-threat-trending | The ranked list of currently trending CVEs — newly exploited in the wild, weaponized, added to a KEV catalog, or a public proof-of-concept appeared. Cached with roughly a 30-minute TTL. |
check-threat-exposure | Whether your own graph is exposed to given CVEs, 1–25 per call. Returns the scanner-confirmed device count, a handle for drilling into the affected assets, and whether any matched device is internet-facing. |
Reading an exposure result. A count of 0 means no scanner reported the CVE — render it as "none found", not "not affected", and note that a CVE that does not exist and a real CVE with no findings both return 0. A status of unavailable is a retry state, not a zero count. An assetExposure of null means unknown, not "not internet-facing". A count is only as fresh as the scanner behind it, so drill into the affected assets before acting on one.
Compliance (CCM)
These tools require the Continuous Control Monitoring entitlement on your account plus control read permission. Creating, editing, or revoking an attestation also needs edit permission on the control, and listing attestations across the whole account needs CCM read-admin. Without them the tools return an access-denied message that leads with the reason JupiterOne gave, such as the missing entitlement.
| Tool | Description |
|---|---|
get-compliance-summary | Scorecard of every CCM framework — control and requirement counts, passing and failing controls, attested controls (every control with a valid attestation, passing or failing), and a health percentage. Pass a frameworkId or a frameworkName to score that framework alone and add per-section stats, its failing controls, and the failing requirements with their failing controls; add includeRequirements for its full requirementList. Pass frameworkIds (1–25) to score a chosen set in one read. Also lists framework imports in flight (importJobs), active attestations expiring within attestationsExpiringWithinDays (default 30), and the expired attestations nobody revoked, which fail their controls now. |
list-controls | The controls status view with its filters: search, status, states, effectiveness, hasValidAttestation, owner, catalogs, mitreTechniques, frameworkId, source, and orgUnit (an org unit's display name, or its id as <namespace>:<uuid>). Returns compact rows — status, state, effectiveness, attested, owner, test counts, why a failing control fails (failReason), and framework names — with sorting and cursor paging (limit default 50, max 250). Controls whose test names contain the search text come back separately in testNameMatches. |
get-control | One control by controlId, identifier, or controlName: its frameworks and requirements, its control tests with each test's latest evaluation, its attestations, a statusExplanation that says why it passes or fails, and blockers, every cause that fails it. An identifier or name that matches several controls returns the one live control when there is exactly one, and otherwise up to 25 candidates, each with its frameworks, instead of a guess. A test's rawDataKey feeds get-rule-evaluation-query-results to list the affected assets, and each test lists its exemptions with the group id revoke-exemptions takes. |
create-attestation | Record an attestation on a live control, with a subject, an expiresOn in the future (YYYY-MM-DD for the end of that day in UTC, a date-time with a time zone, or epoch milliseconds), and an optional markdown description, owner email, and documentLink. Refuses controls that are not live. If an active attestation with the same subject already exists, returns it instead of creating a duplicate. Reports a statusImpact: whether the control now passes on the attestation, already passed on a test, or stays failing because a failing test or an expired attestation blocks it. |
update-attestation | Edit an attestation's subject, description, expiry, owner, or document link. Extending expiresOn renews an attestation, before or after it lapses. Reports the same statusImpact as create-attestation. |
revoke-attestation | Revoke an attestation. Permanent: the control reverts to whatever its tests and any remaining valid attestations say, and the result reports that statusImpact. Repeating a revoke is harmless. To extend an attestation instead, use update-attestation. |
check-compliance-coverage | Whether a standard is loaded, importable from JupiterOne's library, or absent (verdict: covered, partial, importable, not_covered), and which existing controls already address a topic, as reuse candidates for link-controls. The first call for any question that names a standard, benchmark or control topic. |
import-framework | Queue a prebuilt library framework (CIS benchmarks, SOC 2, ISO 27001, NIST, PCI DSS, DORA) by its source and sourceId. A framework already loaded or already importing is reported, not duplicated. Imported controls land in DRAFT; get-compliance-summary shows the job in importJobs. |
create-framework | Create an empty framework for a custom compliance program from a title and description, the first step of incremental authoring. |
create-requirements | Add 1–50 requirements to a framework in one batch, each with the standard's identifier and wording, a section and a priority; requirements the framework already has come back as already_exists. |
create-controls | Create 1–25 controls under one requirement in a batch, in your own words and identifiers. A control with the same name anywhere in the account is reported instead of duplicated, for link-controls. Controls land in DRAFT. |
link-controls | Attach 1–25 existing controls, JupiterOne-managed or your own, to a requirement so they count toward it instead of creating duplicates. A requirement created moments ago that CCM cannot link to yet is reported not_ready, with nothing written. |
update-control | Change a control's name, description, identifier, catalog, owner, remediation, exception process, MITRE technique or resource group, and the requirements it serves (requirementIds with set, add or remove; set cannot be empty). Never its state or its tests. A description or resource group can be replaced but not cleared. |
create-control-test | Add one J1QL test to a control with resultsAre GOOD or BAD. The query is parsed and run before it is saved, and the rows it returns now are reported so you can judge it before it counts. A query that cannot run is refused with the fix, and nothing is saved. |
update-control-test | Change a test's query, verdict, name or description, with the same parse and run for a changed query. |
delete-control-test | Remove a test from a control, reporting its last result. On a LIVE control it keeps a failing test and the last test, since removing either would change the control's score without fixing anything. |
transition-controls | Move 1–25 controls, or every DRAFT and REVIEW control of a framework, between DRAFT, REVIEW, LIVE and RETIRED in a batch, with each transition, skip and refusal reported, and moves cut off by the time limit listed in interrupted. Only LIVE controls count toward a scorecard. |
evaluate-controls | Run the tests of 1–25 controls now instead of waiting for the daily run: how a draft proves its tests before promotion. Results arrive in minutes and are read with get-control. |
delete-control | Delete a control created by mistake while authoring. Accepted only for a DRAFT control that has never been scored or attested (revoked attestations included); anything else is refused with a next step that fits its state, such as retiring a LIVE control with transition-controls, which keeps its history. |
create-exemptions | Exempt 1–50 specific assets from a control test, with an exemptionReason (risk accepted, not applicable, false positive, compensating control), a justification and an optional expiry. An asset carries one exemption per test, so a filing replaces any earlier one and lists it in replaced. |
revoke-exemptions | Withdraw exemptions on a control test by decision (groupId), by asset, or both; the assets fail the test again on its next run. A revoke is a hard delete, and by asset alone it removes whatever exemption those assets carry, so prefer the groupId. |
Reading a compliance result. Every framework and control in a result carries a url to its page in the JupiterOne app, and your assistant gives that link when it names one. A status of unavailable on an attestation list means it could not be read, because of your permissions or, in get-control, the time budget — not that there are none. A summary's warnings are sentences to pass on with the answer, each naming what the response could not confirm. A null count on a scorecard means it was not read, never zero. When CCM has not yet re-scored a control, get-control sets storedStatusStale and gives the expectedStatus. A pass flagged passingWithoutData rests on tests whose queries saw no data: CCM counts it as passing, but it is not evidence the control is met. A health percentage covers evaluated requirements only, so compare passing plus failing requirements with the total before calling a framework healthy. CCM's reads trail a write by a few seconds, occasionally up to a minute, so a control may not show a new attestation straight after create-attestation succeeds. Re-read after a pause instead of creating it again. An attestation write that went through is never reported as an error. An interrupted error means the write may have landed, so check before repeating it. A read_failed error means a read the write needed did not finish in time and nothing was written, so calling again is safe.
Alert Monitoring
| Tool | Description |
|---|---|
get-active-alerts | List currently active alerts, with optional limit (1–1000). |
Rules Management
| Tool | Description |
|---|---|
list-rules | List all rules in the account, with optional limit. |
get-rule-details | Get full details of a specific rule by ID. |
create-inline-question-rule | Create a new inline question-based rule with queries, operations, and actions. Refuses names that start CONTROL-TEST:, which CCM reserves for its control tests. |
update-inline-question-rule | Update an existing inline question rule. Refuses rules that CCM runs for its control tests. |
preview-rule-actions | Show what a saved or draft rule's actions would send — the Slack message, Jira ticket, email or webhook body — rendered against a 10-row sample of its current query results, without sending or saving anything. Slack actions show the whole post: rule name, description, severity, timestamp and body. Flags what would fail or mislead: a Slack body over the 1,500-character limit, a missing description, malformed email recipients, an unknown template function, and template reads that found no data, including ones used in a condition that print nothing. fixtures renders against rows you supply instead of running a query, and loopRows renders a FOR_EACH_ITEM loop's actions for up to 10 rows. Needs permission to create or update rules. |
delete-rule | Delete an alert rule. Irreversible, and it does not dismiss alerts the rule already raised. Refuses rules that CCM runs for its control tests. |
evaluate-rule | Trigger on-demand evaluation of a specific rule. |
list-rule-evaluations | Get historical evaluation data for a rule, with optional time range filtering and an optional limit on the number of runs. |
get-rule-evaluation-details | Get detailed evaluation results including query output, condition results, and action results, with what each action produced outside JupiterOne, such as the link to a posted Slack message. |
get-rule-evaluation-query-results | Get the actual query results from a rule evaluation, with an optional limit of up to 250 rows. A cut result carries truncated: true and total. For a CCM control test's evidence, use the rawDataKey that get-control returns. format: "downloadUrl" returns a signed link to download the whole set instead of rows. |
Dashboard Management
| Tool | Description |
|---|---|
get-dashboards | List all dashboards in your account. |
create-dashboard | Create a new dashboard. |
get-dashboard-details | Get full dashboard information including widgets and layouts. |
update-dashboard | Update an existing dashboard's layout. |
create-dashboard-widget | Add a widget to a dashboard. |
update-dashboard-widget | Update an existing widget's query, title, or chart type. |
delete-dashboard | Delete an entire dashboard and all its widgets. |
delete-dashboard-widget | Delete a single widget from a dashboard. |
Integration Management
| Tool | Description |
|---|---|
get-integration-definitions | List available integration types, optionally including configuration fields. |
get-integration-instances | List configured integration instances, optionally filtered by definition. |
get-integration-jobs | List integration jobs filtered by status, instance, or definition, or read one job by integrationJobId and integrationInstanceId. |
get-integration-events | Get events for a specific integration job, with pagination. |
Account Management
| Tool | Description |
|---|---|
test-connection | Test connectivity and return account information and permissions. |
list-accounts | List JupiterOne accounts the authenticated user can access, each with its accountId, display name, and mcpUrl — the connector URL that pins that account. Use it to find the right account when a connector points at one you cannot reach. |
get-reference | Read one reference manual on demand: j1ql-language, j1ql-discovery, widget-types, widget-settings, dashboard-layout, rule-authoring, rule-templates, compliance-model, compliance-fields, framework-authoring or asset-criticality. Tool descriptions carry each tool's contract and point here for the full reference. |
Known Limitations
- Deletes cover rules, dashboards and draft compliance controls only:
delete-rule,delete-dashboard,delete-dashboard-widget,delete-controlanddelete-control-testare the only delete operations, andrevoke-attestationandrevoke-exemptionsare the other irreversible ones. Integrations, entities, and other resources cannot be deleted through the MCP server. Write and delete tools are annotated (readOnlyHint/destructiveHint) so MCP clients can prompt for approval before running them. - Rule previews never send:
preview-rule-actionsrenders a rule's actions against a sample of current results; it cannot send a test Slack message, file a test Jira ticket or call a webhook, and it renders every action as if the rule's condition held. Lists in a preview show at most 10 rows,{{alertWebLink}}renders a sample link, and parameter values render as[REDACTED PARAMETER]. - Asset criticality changes reach assets on a run:
update-asset-criticalitysaves the setup at once, but only a run writes levels onto assets, every hour and after each save, and a large change spans several runs. Renaming a level changes itsj1.criticalityvalue, and adding, removing or reordering levels renumbersj1.normalizedCriticality. Once a run applies the change, a rule or widget filtering on the old value matches nothing, and one filtering on the old rank selects whichever level holds that rank. Risk-score multipliers are set in the app's risk configuration, not through the MCP server. - Deleting a rule does not dismiss its alerts: alerts the rule already raised stay active after the rule is gone, and the rule's configuration cannot be recovered. To stop a rule firing while keeping its configuration and evaluation history, ask for its polling interval to be set to
DISABLEDinstead of deleting it. - Control-test rules belong to CCM: CCM runs each control test as an internal rule named
CONTROL-TEST:<test name>.list-rulesnever lists these rules, andget-rule-detailsreports one as internal, to be read throughget-controlon its control.create-inline-question-ruleandupdate-inline-question-rulerefuse a name with that prefix.update-inline-question-ruleanddelete-rulealso refuse any rule that a control test references, including a change to its polling interval, because editing or deleting one breaks the control test. Change the test on its control instead.
The MCP server consumes your JupiterOne API rate limit quota. Each operation counts against your API rate limits. Monitor your usage to avoid hitting limits during critical operations.
Troubleshooting
URL uses your vanity domain instead of your account ID
The remote server URL must use your account ID, not your vanity domain (the custom subdomain like acme.app.us.jupiterone.io). If you see authentication or "account not found" errors with the remote server, double-check the URL.
Find your account ID in Account Management — it is listed separately from the Vanity URL.
Server does not appear in your client
- Confirm your JSON config is valid (a single trailing comma will cause silent failure).
- Restart your AI client. Most clients only load MCP config on startup.
- Check the client's MCP log:
- Claude Desktop:
~/Library/Logs/Claude/mcp*.log(macOS) or%APPDATA%\Claude\logs\mcp*.log(Windows) - Cursor: Output panel → "Cursor MCP"
- VS Code (Copilot/Cline): Output panel → relevant extension
- Kiro: Output panel → "Kiro - MCP Logs"
- Claude Code: run
/mcpinside the session
- Claude Desktop:
npx or command not found errors
The local server requires Node.js 20+ on your PATH. Run node --version in the same shell your client uses. On macOS, GUI apps may not inherit your shell's PATH; use an absolute path to npx (find it with which npx) in the config.
OAuth flow fails for the remote server
Sign out of your JupiterOne account in your browser, then retry the OAuth handshake.
A query comes back as status: "IN_PROGRESS"
This is not an error. Heavy graph traversals can outlive a single tool call, so the query keeps running on the server and the response carries a resultsUrl handle. Your assistant should call get-query-results with that handle to collect the results — it does not need to run the query again.
- Queries that succeed almost always finish within about 4 minutes.
- Past roughly 13 minutes a query will not complete. Narrow it — indexed
WITHfilters, a smallerLIMIT, fewer traversals — and run it again. - The handle expires about an hour after the query started. Re-running an identical query within about 5 minutes re-attaches to the same execution instead of starting over.
If your assistant keeps re-issuing execute-j1ql-query instead of using the handle, it restarts the query from scratch each time. Tell it to call get-query-results with the resultsUrl it was given.
A valid query is rejected as a syntax error (local server)
The local server checks J1QL against a copy of the platform's query grammar that is bundled when the package is published, so syntax mistakes come back instantly instead of costing a round-trip. A significantly out-of-date install can therefore reject syntax that a newer query service would accept.
Update the package first: npx picks up the newest version on each run, and a global install updates with npm install -g @jupiterone/jupiterone-mcp. If you need to bypass the local check in the meantime, set JUPITERONE_SKIP_QUERY_VALIDATION to 1 in your MCP client config — the backend still validates every query.
{
"mcpServers": {
"jupiterone": {
"command": "npx",
"args": ["-y", "@jupiterone/jupiterone-mcp"],
"env": {
"JUPITERONE_API_KEY": "your-api-key-here",
"JUPITERONE_ACCOUNT_ID": "your-account-id-here",
"JUPITERONE_SKIP_QUERY_VALIDATION": "1"
}
}
}
}
This applies to the local server only. The remote server always runs the current release, so its grammar cannot fall behind.
Hitting API rate limits
Each MCP query consumes JupiterOne API quota. See API rate limiting for limits and recommendations.
FAQ
Data Residency & Processing
The JupiterOne MCP Server is available in two deployment modes. The local server runs on your machine and uses your API key to fetch data on demand from JupiterOne's cloud — data never passes through any centralized JupiterOne MCP host. The remote HTTP server is hosted by JupiterOne in the same region as your account and authenticates via OAuth; data residency follows the same regional principles as standard JupiterOne API access. In both modes, retrieved data is forwarded to your AI assistant's LLM provider (e.g., Anthropic, OpenAI) per your client's configuration.
LLM Compatibility & Data Handling
The MCP Server integrates with any AI assistant that supports the Model Context Protocol (MCP), including Claude on claude.ai, Claude Desktop, Claude Code, Cursor IDE, ChatGPT, GitHub Copilot, Continue.dev, Cline, Devin Desktop (formerly Windsurf), and Amazon Kiro. Once the server is running and configured, your assistant can use natural language to request security data, which is fetched from JupiterOne and passed to the LLM for interpretation. This means data such as asset inventories, vulnerability reports, or alert summaries can be included in AI prompts, depending on what you query. It's important to treat this as a form of third-party data sharing—ensure your selected assistant has appropriate enterprise security practices in place.
Connecting from your own code (Python and other languages)
The remote server speaks standard MCP over HTTP, so any MCP client library connects to it — including the official Python and TypeScript SDKs. There is no separate JupiterOne Python client; you use whichever MCP library your language already provides. Point it at https://<accountId>.mcp.<region>.jupiterone.io/mcp and send the header Authorization: Bearer <token>. See API tokens for agentic workflows for creating the token and building the URL. Node.js is required only to run the local server — it is not needed to connect from your own code. Note that the Python client is the JupiterOne REST API SDK, not an MCP client; it does not connect to the MCP Server.
Privacy, Logging & Data Sharing
Your API key (local server) or OAuth session (remote server) governs all access, and data is only transmitted in response to your assistant's specific queries. JupiterOne does not store the results of your queries, your query parameters, or action payloads.
For operational monitoring, the remote server records sanitized, non-sensitive usage telemetry — such as which tool ran and whether it succeeded — with query content redacted. The local server keeps this telemetry on your own machine and sends nothing to JupiterOne.
Separately, your AI assistant may log conversations or prompts on its own platform, just as it would during typical usage. To manage exposure, review your LLM provider's data retention and privacy terms, and consider using enterprise or self-hosted models for sensitive environments.
For JupiterOne's formal data-handling commitments — including data collection, retention, storage, and third-party processors — see the Privacy Policy, Data Processing Addendum, and Subprocessors in the Legal & Security Hub. For privacy questions, contact privacy@jupiterone.com.
Access Control & Security Enforcement
Data access through the MCP Server is governed entirely by the credentials you provide. The local server inherits all access controls from the user role attached to the API key; the remote server inherits them from the OAuth-authenticated user, or from the API token when you connect with one. AI assistants can only retrieve what your account has permission to access. You can further restrict access by scoping the API key, adjusting user roles, or disabling individual MCP tools. You retain full control over when the server runs and what it can access — turning off the server or removing its configuration from your assistant completely disables AI access.
Rate Limits & Quotas
Every request made through the MCP Server counts against your JupiterOne API rate limit. This includes queries for asset data, alerts, dashboards, or integrations. Frequent use through an AI assistant could impact your rate quota if not monitored. We recommend reviewing your API usage regularly—especially when enabling assistants for broad or high-frequency queries—to avoid service slowdowns.
Deployment, Support & Customer Control
The JupiterOne MCP Server can be deployed either locally on your machine or accessed through JupiterOne's hosted remote server. The local server runs entirely in your environment with no persistent connections; the remote server connects securely through OAuth authentication and is hosted in the same region as your account. You can disable either at any time by stopping the local process or removing your AI assistant's MCP configuration. For assistance or onboarding, reach out to your CSM or email support@jupiterone.com.
Release notes
- What's new in MCP 2.8 and 2.9 — rule action previews before a rule is saved, and asset criticality: two tools to read and change your levels, which your assistant also sees whenever it writes a query, rule or dashboard;
list-entity-typesrenamedget-graph-context - What's new in MCP 2.7 — fifteen compliance authoring tools: coverage check, library import, incremental framework building, control tests with proof, evaluation and promotion, exemptions, and two guided prompts; two tools folded into their siblings
- What's new in MCP 2.5 — six Continuous Control Monitoring (CCM) tools for compliance status and attestations, a guard on the rules CCM runs for its control tests, and access-denied messages that lead with the reason
- What's new in MCP 2.0 — the 2026-07-28 protocol revision, a cacheable tool list, accurate query result schemas, and the Node.js 20 requirement for the local server
- What's new in MCP 1.0 — the first generally available release: 24 tools, hardened OAuth on the remote server, structured output, and the 1.x point releases that took it to 28 tools
Support
For technical support or questions, email support@jupiterone.com. Existing customers can also reach their Customer Success Manager or use their standard JupiterOne support channels.