upiterOne helps security teams investigate cloud assets, identities, vulnerabilities, and compliance risks across connected infrastructure. Query relationships between resources, identify misconfigurations and exposure paths, assess security posture, and retrieve evidence for audits and compliance frameworks.
Encrypted at rest, isolated from the model
Resolved from an AES-256-GCM vault at the moment of the call and attached to the request — the model never sees the secrets.
Try asking
List the account's alert rules, a page at a time, with each rule's polling interval, last evaluation times and latest alert. Rules are the configuration behind alerts; for the alerts themselves call `get-active-alerts`. Siblings: `get-rule-details` reads one rule in full, `list-rule-evaluations` lists a rule's runs. Vocabulary: rules, monitors, alert configuration. ## Paging Page with `cursor` set to `pageInfo.endCursor` while `pageInfo.hasNextPage` is true. ## Compliance rules `rules[].managedBy` is `'ccm'` for a rule named `CONTROL-TEST:<test name>`, otherwise `null`. JupiterOne Compliance (CCM) runs each control test as a rule, but this listing leaves CCM's rules out, so a page with no `'ccm'` row does not mean the account has no control tests. A control test's rule id is the `referencedRuleId` from `get-control`; `update-inline-question-rule` and `delete-rule` refuse such a rule. ## Why a rule fired `list-rules` → `list-rule-evaluations` (each run's `timestamp` and `rawDataDescriptors[].rawDataKey`) → `get-rule-evaluation-details` with the timestamp for the run's conditions and actions, or `get-rule-evaluation-query-results` with the `rawDataKey` for the entities it matched.
Read one alert rule in full by its id: queries, condition, actions, schedule, labels, tags, version and remediation steps. Call it before `update-inline-question-rule`, which needs every field sent back. Siblings: `list-rules` finds the id, `list-rule-evaluations` lists the rule's runs. Vocabulary: rule configuration, the query behind an alert, version. ## Compliance rules `managedBy` is `'ccm'` for a rule named `CONTROL-TEST:<test name>`, otherwise `null`. JupiterOne Compliance (CCM) runs each control test as a rule, hidden from this tool and from `list-rules`, so a control test's `referencedRuleId` from `get-control` comes back as not found here. Read that rule's runs with `list-rule-evaluations`, and the control and its tests with `get-control`. A CCM rule is changed through its control, never with `update-inline-question-rule` or `delete-rule`, which refuse it.
Run an alert rule now rather than at its next polling interval. The response carries only the evaluation's `id`, not its results: read the outcome with `list-rule-evaluations` and `get-rule-evaluation-details`. Vocabulary: run the rule now, trigger an evaluation, re-check.
Create an alert rule from an inline J1QL question: the query runs on a schedule and, when its condition holds, the actions fire (alert, email, Slack, Jira ticket, tag, webhook, S3). Test the query with `execute-j1ql-query` first; the rule stores it as written. Siblings: `update-inline-question-rule` replaces an existing rule, `get-rule-details` reads one, `list-rules` finds them, `evaluate-rule` runs one now. Vocabulary: rule, alert, monitor, notify, schedule, polling interval, condition, actions, labels. ## Payload - `question.queries[]`: each entry is `{name, query, version: "v1", includeDeleted: false}`. Name the primary query `query0`; the condition references it as `queries.query0.total`. - `specVersion`: `1`. - `operations[].when`: `{type: "FILTER", condition}`; condition `["AND", ["queries.query0.total", ">", 0]]`; `AND` or `OR`, operators `>`, `<`, `>=`, `<=`, `=`, `!=`. - `outputs`: `["alertLevel"]`. `templates`: `{}`. - `pollingInterval`: `ONE_DAY` unless the user asks for another. - `triggerActionsOnNewEntitiesOnly: true` for "new user" or "new resource" rules. `notifyOnFailure: true`. - Organise rules with `labels` (`{labelName, labelValue}`) and omit `tags`, a legacy string array the API still accepts. ## Actions Types: `SET_PROPERTY`, `CREATE_ALERT`, `SEND_EMAIL`, `TAG_ENTITIES`, `SEND_SLACK_MESSAGE`, `SEND_TO_S3`, `CREATE_JIRA_TICKET`, `WEBHOOK` and `FOR_EACH_ITEM`, which runs nested actions once per entity. Always include `CREATE_ALERT`. `SET_PROPERTY` on `alertLevel` takes `LOW`, `MEDIUM`, `HIGH`, `CRITICAL` or `INFO`. Slack, S3 and Jira actions need an `integrationInstanceId`: find the definition with `get-integration-definitions`, list instances with `get-integration-instances`, and ask the user which. Ask for recipients, channels, project and wording before writing an action that notifies someone. ## Refusals and response A `name` starting `CONTROL-TEST:` is refused with `lintCode: 'ccm-managed-rule'` (the prefix marks compliance control tests). A query that fails to parse returns the parser's suggestion and creates nothing. The response carries `rule.url`; give it to the user. Full reference: get-reference topic rule-authoring
Replace an existing inline-question rule's whole definition: name, query, condition, actions, schedule. Read it with `get-rule-details` first, change what you need and send every field back; an omitted field is an error, not "unchanged". Test a changed query with `execute-j1ql-query` first; the rule stores it as written. To stop a rule, set `pollingInterval: "DISABLED"` instead of deleting it. Siblings: `create-inline-question-rule` makes a new rule, `delete-rule` removes one. Vocabulary: edit rule, change recipients, disable, re-enable, version. ## Full replacement - `id` and the current `version` from `get-rule-details`; JupiterOne increments the version. - `specVersion` as read, normally `1`. - `resourceGroupId` and `remediationSteps` may be `null` but must be present. - `tags` is required here: pass back what `get-rule-details` returned, `[]` when none, and keep organisation in `labels`. - `question.queries` and `operations` take the create shape; `when` is `{type: "FILTER", condition: ["AND", ["queries.query0.total", ">", 0]]}`. ## Compliance rules JupiterOne Compliance (CCM) runs each control test as a rule named `CONTROL-TEST:<test name>`, hidden from `list-rules` and `get-rule-details`. The tool asks the graph whether a control test references the id and refuses with `lintCode: 'ccm-managed-rule'`; a `name` with the prefix is refused too. The change belongs on the control, which `get-control` reads. The response carries `ownershipCheck`: `'graph'` when the check ran and found no control test, `'skipped'` when it could not run and the update went ahead. ## Response `rule.url`; give it to the user. Full reference: get-reference topic rule-authoring
Delete an alert rule permanently: one built from an inline question or one that references a saved question. There is no undo and the configuration cannot be recovered, so confirm the `ruleId` against `list-rules` or `get-rule-details` and confirm with the user before calling. Alerts the rule already raised stay active. To stop a rule and keep its configuration and evaluation history, call `update-inline-question-rule` with `pollingInterval: "DISABLED"` instead. Vocabulary: delete, remove, retire a rule. ## Compliance rules JupiterOne Compliance (CCM) runs each control test as a rule named `CONTROL-TEST:<test name>`, owned by its control and hidden from `list-rules` and `get-rule-details`. Before deleting, the tool asks the graph whether a control test references the id and refuses if one does (`lintCode: 'ccm-managed-rule'`); `update-inline-question-rule` refuses to disable such a rule too. The change belongs on the control, which `get-control` reads. If the check cannot answer — the query failed, or `ruleId` is not a UUID — the delete is refused with `lintCode: 'ccm-ownership-unverified'` rather than risk breaking a control test; nothing was deleted, so retry or correct the id. ## Response `ruleId` as passed, `id` the backend confirmed deleted, and `ccmOwnership`: `'clear'` on a delete, `'managed'` or `'unverified'` on a refusal.
List a rule's evaluation runs, each with its `timestamp`, `outputs`, `tag` and `rawDataDescriptors[].rawDataKey`. `beginTimestamp` and `endTimestamp` are epoch milliseconds; `tag` filters the runs. Chain: `list-rules` → `list-rule-evaluations` → `get-rule-evaluation-details` with a run's `timestamp` for its conditions and actions, or `get-rule-evaluation-query-results` with its `rawDataKey` for the entities it matched. Vocabulary: evaluation history, when did the rule run, why did it fire.
Read one evaluation run of a rule: each query's status and duration, the condition verdict, and each action's status and logs. `timestamp` comes from `list-rule-evaluations`. For the entities the run matched, call `get-rule-evaluation-query-results` with that run's `rawDataKey` instead. Vocabulary: why did the rule fire, did the action run, evaluation log.
Return a signed URL for downloading a rule evaluation's raw result set, for a `rawDataKey` from `list-rule-evaluations`. Use it to hand the user a large result set; to read the rows here, call `get-rule-evaluation-query-results` instead. Vocabulary: download, export, raw results.
Return the entities a rule evaluation matched, from the `rawDataKey` in a run's `rawDataDescriptors` (`list-rule-evaluations`). For a compliance control test's evidence, the key is the `latestEvaluation.rawDataKey` that `get-control` returns for that test: the assets the test scored on its latest run. Siblings: `get-rule-evaluation-details` for the run's conditions and actions, `get-raw-data-download-url` for a signed link to the whole set. Vocabulary: matched entities, evidence, affected assets. ## Rows Rows are full entities, so a few dozen can be large; `limit` (1–250) cuts them, and a cut result carries `truncated: true` and `total`, the row count before the cut.
List the account's active alerts, each with its level, status, timestamps, the matched record count and the rule that raised it (`ruleId`, name, labels). Alerts are what rules produced; for the configuration behind one, call `get-rule-details` with its `ruleId`, or `list-rules`. `limit` caps the rows returned and `total` is the full active count. Vocabulary: alerts, open alerts, firing, severity, alert level.
List every dashboard in the account, personal and account-level, with `id`, `name`, `category` and `isJ1ManagedBoard`. Use it to find a `dashboardId`; `get-dashboard-details` reads one board. No parameters.
Create an empty dashboard, the first step of a build: `create-dashboard` → `create-dashboard-widget` once per widget → `update-dashboard` with `autoLayout`; a board left at default sizes is not finished. Default to a personal `User` dashboard unless asked otherwise. An account-level API token (`test-connection` reports `credential.type: "account_token"`) has no user, so it can only create `Account` dashboards; a `User` request is refused. Siblings: `get-dashboards` lists existing boards. Vocabulary: dashboard, board, insights. ## Response `id` is the `dashboardId` every later call takes; `url` opens the board, give it to the user.
Read one dashboard in full: its widgets with their queries and settings, and its `layouts` for all five breakpoints. Read it before `update-dashboard-widget` or a `layouts` merge, since both replace what they touch, and to confirm what `create-dashboard-widget` saved, since its response does not echo everything (`drilldownQuery`). `get-dashboards` finds the `dashboardId`.
Add one widget to an existing dashboard: J1QL queries drawn as a chart. The render contract is enforced: a query whose RETURN aliases are not the ones the chart type reads is rejected before anything is written, with a corrected query where one can be derived. Run the query through `execute-j1ql-query` first; an empty result still creates a widget, which renders blank. Siblings: `update-dashboard-widget` replaces a widget, `update-dashboard` arranges them, `delete-dashboard-widget` removes one. Vocabulary: widget, chart, pie, bar, line, number, table, matrix, graph, status, markdown. ## Columns by chart type - `number` → **Enforced: required `value`.** Exactly one column, per query; percentage mode is the one legitimately multi-query number widget. - `pie` → **Enforced: required `value`, and `name` too on a single-query pie.** The renderer groups slices by `name`: one query without it draws one slice labelled `undefined` summing every row. A multi-query pie labels each slice by its query name, so `name` is optional there. - `bar` → **Enforced: required `x`, `y`.** Stacking is one query per series on a shared `x` with `settings.bar.view: 'stacked'`, never several `y` columns. - `line` → **Enforced: required `y`.** `x` (position) and `line` (series split) are recommended. - `matrix` → **Enforced: required `x`, `y`.** `label` is optional and shown in each cell. - `table` → any aliases; add `ORDER BY` and `LIMIT` (250-row cap, no paging). - `graph` → **Enforced: the query must `RETURN TREE`.** Columns give it nothing to draw. - `status` → **Enforced: required `id`, on every query.** The first query is the roster and supplies the display fields (`displayName`, `iconWebLink`); each later query is one pass/fail check, and `id` is what correlates them. - `markdown` → `config.queries: []`; the body goes in `settings.markdown.text`. - `area` → accepted by the schema, refused by the tool: it renders nothing. Use `bar` or `line`. ## Settings and queries Always set `noResultMessage`; it is what lets a reader tell "nothing matched" from "broken". Settings nest under the chart type (`settings.bar.decimalLimit`); a key the service does not know is dropped silently on save, the write still succeeds, and `droppedSettingsKeys` names what was discarded. Each query may carry a `drilldownQuery`, validated like the widget query. A proportion is a percentage number widget: two queries each returning `count(x) AS value`, with `settings.number.showAsPercentage: true` and `numeratorQueryName` (one comma-joined string; a name matching no query is rejected before writing); set `includeNumeratorInTotal: true` only when the queries partition the population. Thresholds, labels and trend keys: see `widget-settings`. ## Response `renderPreflight` is measured after the write and never blocks it. The widget `id` is what `update-dashboard` lays out; `dashboardUrl` opens the board, give it to the user. An empty widget backed by a correct query is a finding; never broaden a filter to fill it. Build order: `create-dashboard` → `create-dashboard-widget` per widget → `update-dashboard` with `autoLayout`. Full reference: get-reference topic widget-types or widget-settings
Arrange the widgets on a dashboard: which are wide, their reading order, their grid positions. Call it after `create-dashboard` and the widgets; a board left at default sizes is not finished. Send exactly one of `autoLayout` (ordered widget ids with sizes; the server computes every breakpoint) or `layouts` (a hand-placed grid). Siblings: `update-dashboard-widget` changes a widget's content, not its place. Vocabulary: layout, grid, breakpoint, resize, arrange, columns, full width. ## autoLayout The grid has 12 columns; `small`, `medium`, `large` and `full` are 4, 6, 8 and 12 columns wide, default `medium`. Small screens render it as a single column. ```json { "dashboardId": "abc-123", "autoLayout": [{ "id": "w-1", "size": "full" }, { "id": "w-2", "size": "small" }, "w-3"] } ``` ## layouts `layouts` replaces the whole layout set; it is not a patch. All five breakpoints (`xs`, `sm`, `md`, `lg`, `xl`) are required: a widget omitted from a breakpoint's array loses its place there, and an omitted breakpoint becomes `[]`, which leaves that width unarranged. To change one widget, read the current `layouts` with `get-dashboard-details`, merge the change into that full set and send everything back. Each item is `{ i, x, y, w, h }`: `i` is the widget id, `x` and `y` the grid position, `w` and `h` the size in grid units. ## Response Widgets left out of the layout are removed from the grid and named in `omittedWidgets`; cells that overlap are reported in `layoutOverlaps`; `note` names any breakpoint left unarranged. Full reference: get-reference topic dashboard-layout
Replace an existing widget's whole definition: its query, title, chart type or settings. The `input` is the widget's new full state, so read the current widget with `get-dashboard-details`, apply the change to that object and send everything back; an omitted field is dropped, not kept. Siblings: `create-dashboard-widget` adds a widget, `update-dashboard` moves one, `delete-dashboard-widget` removes one. Vocabulary: edit widget, fix query, rename, chart type. ## Render contract The same gate as `create-dashboard-widget`: a query whose RETURN aliases are not the ones the chart type reads is rejected before anything is written, with a corrected query where one can be derived. Run a changed query through `execute-j1ql-query` first; an empty result still updates the widget, which renders blank. ## Response `resultCode`, `widgetId`, `dashboardUrl` and `renderPreflight`, measured after the write. The update returns no widget to compare against, so there is no `droppedSettingsKeys`; read back with `get-dashboard-details` to confirm the settings stored. Full reference: get-reference topic widget-types or widget-settings
Delete one widget from a dashboard: the recovery path for a widget created by mistake or no longer wanted. This is destructive and irreversible: confirm the `widgetId` with `get-dashboard-details`, and confirm with the user when the intent is ambiguous. To delete the whole board, use `delete-dashboard`. Vocabulary: remove widget, delete chart. ## Response `success`, `widgetId` and `dashboardUrl`. The widget also leaves the dashboard's layout; call `update-dashboard` with `autoLayout` to re-pack the remaining widgets.
Delete a dashboard and every widget on it. This is destructive and irreversible: confirm the `dashboardId` with `get-dashboards` or `get-dashboard-details`, and confirm with the user before calling. To remove one widget instead, use `delete-dashboard-widget`. Vocabulary: delete dashboard, remove board. The response is `success` with the `dashboardId` deleted.
List the integration definitions available to the account: the kinds of integration that can be configured (AWS, Azure, GitHub, Slack, Jira) and, with `includeConfig`, their configuration fields. Start here when another task needs an integration instance id, such as a Slack, Jira or S3 rule action: find the definitions whose `name` or `title` match the product, then list that definition's instances with `get-integration-instances`. When several definitions could fit, say how they differ and let the user choose. Vocabulary: integration, connector, definition, provider, Slack, Jira, AWS. ## Paging When `pageInfo.hasNextPage` is true, call again with `cursor` set to `pageInfo.endCursor`, and page through the whole list before choosing a definition. `includeConfig` is usually left out; the schemas are large.
List the integration instances configured in the account: the actual connections to external services (an AWS account, a GitHub organization, a Slack workspace), with their configuration, status and recent job information. Filter by `definitionId` from `get-integration-definitions`; without one the list spans every integration type. When another task needs an instance id, such as a rule action, ask the user which of the matching instances to use rather than choosing one. Vocabulary: integration instance, connection, configured integration, sync status. ## Paging When `pageInfo.hasNextPage` is true, call again with `cursor` set to `pageInfo.endCursor`.
List integration job runs with their status, timing and results, for one instance, several, a definition or a status. Use it to see whether an integration has synced lately or is failing; `get-integration-job` reads one run and `get-integration-events` its logs. Vocabulary: integration job, sync, run history, failed sync. ## Paging When `pageInfo.hasNextPage` is true, call again with `cursor` set to `pageInfo.endCursor`.
Return one integration job run: its status, start and end, whether steps were skipped, and the instance and definition it belongs to. Take the job id and its instance id from `get-integration-jobs`; `get-integration-events` reads the run's logs. Vocabulary: integration job, sync run, job status.
Return the events and logs of one integration job run, for troubleshooting a failed or partial sync: what each step did, what it skipped and the errors it raised. Take the job id and its instance id from `get-integration-jobs`. When `pageInfo.hasNextPage` is true, call again with `cursor` set to `pageInfo.endCursor`. Vocabulary: integration logs, job events, sync errors, troubleshooting.
Run a J1QL query against the account's asset graph and return its rows. Use it for any question about real inventory, findings, identities or relationships, and to prove a query before it goes into a widget or rule. Discover, then verify: `list-entity-types`, sample a type with `FIND <type> AS e RETURN e.* LIMIT 5`, then run the finished query and confirm it returns rows. Relationship direction filters nothing; filter on the edge's own properties (`rel.ingress = true`). `get-query-results` collects a query still running. J1QL reads FIND, WITH, THAT, RETURN, count, LIMIT and cursor. ## Syntax rules - The alias follows the WITH filter: `FIND Device WITH name ~= 'x' AS dev`. - String literals use single quotes. - WITH filters an entity's own properties (indexed); WHERE is for edge properties and cross-entity comparisons, and needs aliases. - Direction arrows follow the verb: `FIND User THAT HAS >> Device`. - `count` and other keywords cannot be aliases; write `AS total`. - `LIMIT` is at most 250; every query carries an aggregate or a `LIMIT`. Page with `cursor`, never `SKIP`. - SQL habits do not parse: `IN (...)` is `= ('a' OR 'b')` (`!=` excludes them all), `LIKE '%x%'` is `~= 'x'`, and `DISTINCT`, `GROUP BY` and `JOIN` do not exist; non-aggregated RETURN columns are the grouping keys. `*` is the only wildcard target; `ANY`, `ANYTHING` and `entity` parse and match nothing. `count(rel)` counts edges, `count(tar)` distinct targets; say which one you report. ## Result `type` is `list` (entities), `table` (named RETURN columns) or `tree` (`RETURN TREE`); `data` is an array of rows, or `{ vertices, edges }` for a tree. A non-empty `cursor` (`hasMore: true`) means another page: repeat the call with the identical query and the cursor; a page can hold zero rows while a cursor is present, so stop only on `hasMore: false`. `url` opens the result in the app; give it to the user. An `emptyResultDiagnosis` with a `correctedQuery` explains an empty result, such as a literal stored under another casing; run it before reporting a zero. ## Still running The call waits 10 seconds. `status: IN_PROGRESS` with a `resultsUrl` is not a failure: the query keeps running server-side. Keep working and collect it with `get-query-results`; do not re-issue it. An identical re-run within 5 minutes re-attaches to the job; results stay for about an hour. ## Errors Queries are parsed locally before they are sent; a syntax error returns at once with a suggestion, so fix and retry. A timeout or an aborted request is the server's 55-second deadline: move simple filters from WHERE into indexed WITH, lower the LIMIT, traverse fewer hops. ## Unified entities `UnifiedDevice`, `UnifiedIdentity` and `UnifiedVulnerability` are the deduplicated devices, identities and vulnerabilities and usually what the user means, so answer in unified terms. They relate only to their source entities; traverse through those for context. Full reference: get-reference topic j1ql-language or j1ql-discovery
Collect the result of a J1QL query that was still running when `execute-j1ql-query` returned `status: IN_PROGRESS` with a `resultsUrl`. A long-running query keeps executing server-side; this tool polls its handle, waits for completion and returns the same envelope `execute-j1ql-query` does. It redeems a handle, so it needs no account. A new or changed query goes through `execute-j1ql-query`. ## Outcomes - Finished: the standard query envelope. Continue any pagination through `execute-j1ql-query` with the `cursor`. - Still running: `status: IN_PROGRESS` with the same `resultsUrl`. Successful queries almost always finish within about 4 minutes; past about 13 minutes (the backend's full retry window) the query will not succeed, so abandon the handle and run a narrower query instead. - Failed server-side: the execution error. Narrow the query (indexed `WITH` filters, a smaller `LIMIT`, fewer traversals) and run it again with `execute-j1ql-query`. ## Handle lifetime The handle expires about an hour after the query started. If it expired or was lost, re-run the original query with `execute-j1ql-query`; an identical re-run within 5 minutes re-attaches to the same execution. Do not re-issue a query that is still running just to collect it.
List the entity classes and types the account's index holds, each with a count, as two maps: `classes` and `types`. Call it before writing a J1QL query, so the query names a class or type that exists: a query naming one the account does not hold returns nothing, and guessing names from memory is how that happens. It also shows what data the account holds and which integrations feed it. `execute-j1ql-query` runs the query; sampling a type's properties and values is a query, not this tool. Classes are TitleCase (`User`, `Finding`), types snake_case (`aws_instance`, `github_user`). ## What the list proves The counts come from a stored index, not from the graph: on a live tenant it disagreed with direct queries on counts and omitted types that queries returned. A type listed here exists; a type missing from it may still exist. When a type matters, confirm it directly with `FIND <type> AS e RETURN count(e) AS value`. Full reference: get-reference topic j1ql-discovery
Test the connection to JupiterOne and the caller's access to the target account, and report who the caller is: the credential type, the signed-in user's email and a summary of permissions. Call it at the start of a session, after an access error, or whenever it is unclear which sign-in or account is active. `list-accounts` lists every account a sign-in can reach; this tool checks one. ## Reading the result `credential.type` is `user`, `account_token` or `userless_token` (an API token with no user that could not be identified; `credential.lookup` says why, and none of its values means the token cannot act). Surface `user.email` to the user when there is any doubt about which sign-in is active. A `false` anywhere in `permissions` proves nothing: it summarises fine-grained RBAC rows, and callers with no rows at all write successfully every day. Use it to explain a denial after one happens, never to refuse an operation in advance. ## Failure A failed test returns an error whose text says why and what to do next. When the failure is an authorization rejection and account discovery is available, the text lists the accounts the sign-in can access. If tools take an `accountId`, retry with one of those; the connection itself needs no change. If the connection is pinned, the list carries each account's connector URL; relay it so the user can fix the connector's account binding. Do not loop on re-authentication: if the text says the pinned account is inaccessible, re-authenticating will not fix it.
List the JupiterOne accounts the authenticated user can access: each account's `accountId`, its `displayName` and, when the host can construct one, `mcpUrl`, a connector URL pinned to that account. Call it first when tools take an `accountId` the user has not named, and to map an account name, tenant or organization the user mentions to its `accountId`; pass the `accountId`, never the display name. `test-connection` checks access to one account; this lists memberships, which are not live access: an account still rejects the connection when access was revoked or disabled. ## Not authorized When a data tool returns "Not authorized", recovery depends on the connection. Tools take an `accountId`: retry with another `accountId` from this list; the connection itself is fine, so do not ask the user to change it. The connection is pinned (tools take no `accountId` and the error names the pinned account): give the user the `mcpUrl` of an account they can access so they can update the connector. ## Several accounts Each call to a tool that takes an `accountId` acts on one account. To work across several ("check this across all my accounts"), call this tool, then repeat the target tool once per `accountId` and aggregate the results.
Return one reference page; read it before writing a query, widget, rule or compliance answer that needs more than a tool description gives. Topics: `j1ql-language` (grammar, operators, examples), `j1ql-discovery` (finding types, properties, values and verbs), `widget-types` (chart types and their RETURN columns), `widget-settings` (settings keys by chart type), `dashboard-layout` (grid, breakpoints, autoLayout), `rule-authoring` (rule payloads, actions, templates), `compliance-model` (how CCM scores a control), `compliance-fields` (response field glossary). Read-only; needs no account.
Return JupiterOne's threat brief for one CVE: how dangerous it is, whether it is exploited in the wild or listed in a KEV catalog, whether the security ecosystem can detect it, and how fast CISA's directive says to remediate it. This is intelligence about the CVE itself; `check-threat-exposure` answers whether this account is affected, and `get-threat-trending` lists what is escalating now. Vocabulary: CVE, vulnerability, exploited, KEV, SSVC, EPSS, remediation, BOD 26-04, exposure, threat intelligence. ## Parameters - `assetExposure` resolves the remediation section to one branch; omitted, both branches come back when the directive's answer differs for public and internal assets, and one when it does not. - `detail: true` returns the full brief, a much larger payload; the raw reference URL lists (thousands of rows) are never included. The compact brief's `affectedProduct` (the join key for a product-presence search of the graph) is as complete as the full brief's, so do not spend the larger call looking for one. ## Reading the result `notes`, when present, carries the reading rules this brief needs (no product identity, or SSVC sources that disagree); pass them on with the answer. ## Outcomes `outcome` is one of four, and they are not interchangeable: - `found` — a brief was returned. This describes the lookup, not the CVE: it says nothing about whether the vulnerability is remediated anywhere. - `not_found` — a valid CVE id with no upstream record. - `invalid_input` — not a CVE identifier; no lookup was attempted. - `source_unavailable` — the upstream was unreachable, timed out or rate-limited. This is a retry state, never "no such CVE"; the id is preserved for the retry. ## Access Needs the account's VulnerabilityManagement entitlement and vulnerability read permission; without them the call returns an access-denied error. ## Example `{ "cveId": "CVE-2021-44228" }`
Return the ranked list of trending threats: CVEs that have recently escalated (newly exploited in the wild, weaponized, added to a KEV catalog, or a public PoC appeared), each with its escalation reason, affected vendor and product, commercial-scanner coverage gap and KEV additions. It says what is hot now, not whether this account is affected: pair it with `check-threat-exposure` (scanner match) or, for product presence, a J1QL search on the row's `affectedProduct`; `get-threat` briefs one CVE. Vocabulary: trending, CVE, exploited, KEV, weaponized, PoC, exposure, threat intelligence. ## Reading the result - The list is cached for about 30 minutes; `generatedAt` is the cache fill time of the instance that answered, so consecutive calls can differ. - List order is the ranking; the upstream caps it (25 rows today), usually all `act_now`. - `rowsWithoutProduct` counts rows with no `affectedProduct`, and the `note` says how to treat them; pass it on with the answer. - A product-presence search matches on text, so it also matches your own tooling: searching the graph for `artifactory` returns the container images of JupiterOne's integration for Artifactory, not a running server. Confirm matched entities are instances of the product, not code, images, pipelines or alarms named after it, before counting them as exposure. ## Access Needs the account's VulnerabilityManagement entitlement and vulnerability read permission; without them the call returns an access-denied error.
Answer, from this account's own graph, whether it is exposed to up to 25 CVEs: how many devices a vulnerability scanner has confirmed carry each one, a handle to drill into the affected assets, and whether any matched device is internet-facing. This is the direct, strict match on the unified vulnerability's `cveId`, so it sees only what a scanner has already fingerprinted for that CVE; `get-threat` briefs the CVE itself and `get-threat-trending` lists what is escalating. Vocabulary: exposure, exposed, affected, CVE, scanner, findings, KEV, internet-facing. ## Reading the result Key results off each one's `subjectId`, not position. `status` is `checked`, `invalid_input` or `unavailable`. - `checked` means the lookup ran and the count is real; it says nothing about remediation. Read the count. - `scannerConfirmedAssetCount: 0` does not mean "not affected": no scanner reported it, and absence of a finding is not evidence of absence. Render it as "none found". There is no not-found outcome: a CVE that does not exist and a real CVE with no findings both return `0`; only `get-threat` answers existence. - `unavailable` is not a zero count: the graph lookup failed or timed out, a retry state. Never collapse it into "0 affected". - `assetExposure: null` means unknown, not "not internet-facing"; it is set only when a matched device carries an exposure classification. - A count is only as fresh as the scanner behind it; a feed that stopped months ago still reports its last findings. Drill in and check when they were last observed, with `unifiedVulnerabilityId` (the `_id` of this account's `unified_entity` for the CVE): `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`. Keep the second hop restricted as shown, or control tests and alerts dominate it. - Ids are upper-cased before the lookup. ## Access Needs the account's VulnerabilityManagement entitlement and vulnerability read permission; without them the call returns an access-denied error. ## Example `{ "cveIds": ["CVE-2021-44228", "CVE-2023-4966"] }`
Return the account's compliance posture from JupiterOne Compliance (CCM): a scorecard per framework and, for one framework, its sections and failing requirements, plus attestations expiring soon or already lapsed. Answer posture questions from it rather than re-deriving pass/fail in J1QL. Siblings: `list-controls` for the controls behind a number, `get-control` for why one control passes or fails, `update-attestation` to renew an attestation. Vocabulary: compliance, framework, SOC 2, ISO 27001, requirements, controls, health, attestations, audit. ## Parameters `frameworkId` drills one framework and reads only its scorecard, faster on an account with many frameworks; `frameworkName` does the same by name, and both at once is an `invalid_input:` error. The expiry window bounds `expiringAttestations` only. ## Outcomes - `ok` — `frameworks: []` is a real answer: no CCM frameworks. - `ambiguous` — `frameworkName` matched several (`candidates`, up to 25); ask the user, or call again with that `id` as `frameworkId`. - `framework_not_found` — `frameworks` lists every framework without counts; take the id from there. - `frameworkResolution: "partial"` is a substring match: confirm the `name` with the user. `frameworksComplete: false` means the list stopped at its page limit. ## Reading the scorecard - `attested` counts every control with a valid attestation, failing ones too; it is not a subset of `passing`. - `null` counts mean not read, never zero (`statsIncomplete` names them). - `healthPct` is passing ÷ (passing + failing) requirements, `null` when none is evaluated. It ignores unevaluated requirements, so compare passing + failing with `requirements.total` before calling a framework healthy. `importStatus` other than `COMPLETE` means incomplete counts. - `controls.passingWithoutData`: CCM counts tests that saw no data as passing, so a high score can rest on tests that saw nothing. - An empty `failingRequirements` is real only when `failingControlsTruncated` is `false` and `requirementLookupsSkipped` is `0`; otherwise answer from `failingControls`. ## Attestations - `expiringAttestations` and `expiredAttestations` (not revoked, at most 50). The string `'unavailable'` in place of a list means it could not be read with these permissions, never that nothing expires. - An expired, unrevoked attestation fails its control until renewed with `update-attestation` or revoked, so answer "what expires" from both lists. - `expiringAttestationsScope: "account"` means the lists are not limited to the drilled framework. ## Warnings and links Pass `warnings` on with the answer. Give a framework's or control's `url` when you name it. ## Access Needs the Compliance (CCM) entitlement and control read permission; account-wide attestation lists also need CCM read-admin, or only they are `'unavailable'`. An access-denied error names the missing one; re-authenticating will not help. Full reference: get-reference topic compliance-fields or compliance-model
List JupiterOne Compliance (CCM) controls with the filters CCM's own controls view offers: status, state, framework, organizational unit, owner, attestation, catalog, MITRE technique and text search. Rows are compact (status, state, test counts, framework names) with no descriptions or test queries. Use it to find a control by name or identifier and to list what fails in a framework or org unit. Siblings: `get-compliance-summary` for framework numbers, `get-control` for one control's detail. Vocabulary: compliance, controls, failing, LIVE, org unit, owner, search, MITRE, audit. ## Filters - `status` on a non-LIVE control is left over from its last evaluation; add `states: ["LIVE"]` to list what fails now. - `orgUnit` selects controls whose tests touch an asset in the unit; a row's `status` stays the control's overall status. An id (a value with a colon) is used unchecked; a name is searched in up to 10 enabled namespaces. - `sort` by `LAST_EVALUATED_ON` with `DESC` lists never-evaluated controls (`null`) first; add `status: ["PASS", "FAIL"]` to leave them out. - A cursor works only with the exact filters of the call that returned it; a refused one is an error starting `cursor_rejected:` with the API's reason. - For a count rather than rows, run `execute-j1ql-query` with `FIND ccm_control WITH state = 'LIVE' AND status = 'FAIL' AS c RETURN count(c) AS value`. ## Outcomes - `ok` — `controls` is this page, `returned` its size. An empty list is a real answer. With `orgUnit`, the response adds `orgUnit` and `ouResolution` (`id`, `name` or `id_unverified`); an empty page behind `id_unverified` carries a `note`. - `ambiguous` — the `orgUnit` name matched several units; `candidates` lists up to 25, incomplete when `namespacesFailed` is above 0. Ask the user, or call again with one's `id`. - `org_unit_not_found` — no unit matched. `namespaces` lists what was searched (`failed: true` where it failed), `namespacesNotSearched` counts the rest, and `units` offers up to 10 per namespace. It is not proof the unit does not exist, and never "no failing controls"; when every search fails, the call is an error. ## Rows `status` is `PASS`, `FAIL` or `null` (never evaluated); `effectiveStatus` is `EFFECTIVE`, `NO_TESTS` or `NO_DATAPOINTS`; `failingTests` counts non-deleted failing tests; `frameworkNames` follows `frameworkIds`, `null` where unresolved. ## Access Needs the Compliance (CCM) entitlement and control read permission. CCM silently leaves out controls in resource groups the caller cannot read, and no read permission returns an empty list; a missing entitlement is an access-denied error that names it. ## Example `{ "frameworkId": "<frameworkId>", "status": ["FAIL"], "states": ["LIVE"] }` Full reference: get-reference topic compliance-fields
Return one JupiterOne Compliance (CCM) control with what explains its status: its tests and their latest evaluation, attestations, requirements, frameworks and `statusExplanation`. Look it up by `controlId`, `identifier` (such as `CC6.1`) or `controlName`. Use it for why a control fails, how to fix it (`control.remediation`) and how to get an exception (`control.exceptionProcess`); `list-controls` finds controls. Vocabulary: compliance, control, test, evidence, failing, attested, remediation, exception, audit. ## Parameters Exactly one of `controlId`, `identifier` or `controlName`; none or several is an `invalid_input:` error. `includeDeleted` adds deleted tests, never a deleted control. ## Outcomes - `found` — one match, or several with exactly one LIVE (`otherCandidates` lists the rest). - `not_found` — nothing matched, deleted included; the `note` says how to search. - `ambiguous` — several matched, not exactly one LIVE; `candidates` lists up to 25, incomplete when `searchComplete` is `false` (the search stops at 200 controls). Call again with one's `controlId`, or narrow with `list-controls`. ## Status - A failing test fails the control; an attestation never masks it. - An attestation passes a control only when no test has a status. - An expired, unrevoked attestation fails the control, whatever the tests say. - Only LIVE controls are evaluated; a test that saw no data still passes. `statusExplanation` is one of `not_live`, `failing_test`, `failing_expired_attestation`, `undetermined`, `passing_by_tests`, `passing_by_attestation`, `no_tests`, `no_datapoints`; `statusMeaning` explains it. `blockers` lists every cause; clear them all. `storedStatusStale: true`: CCM has not re-scored yet, so report `expectedStatus`. ## Tests - `resultsAre: "BAD"`: any row is a violation and fails the test. `"GOOD"`: rows are compliant and the test never fails, so zero rows is a pass on no data. `effective` is not a verdict. - What CCM scored: `get-rule-evaluation-query-results` with `latestEvaluation.rawDataKey`. What is true now: the test's own `query` through `execute-j1ql-query`, narrowed in its `WITH`, never a new query. ## Attestations and requirements `attestations: 'unavailable'` means not readable, never none; revoked ones never affect the status. Empty `requirements` or `frameworks` beside a skip reason means not read; `notes` says so. ## Access Needs the Compliance (CCM) entitlement and control read permission; a missing one returns an access-denied error that names it. Full reference: get-reference topic compliance-model or compliance-fields
Attest a JupiterOne Compliance (CCM) control: record that it is met by evidence no test can query (a policy, a review, a document) until a stated expiry. Attestations apply to LIVE controls only; one passes a control only when no test has a status, and never masks a failing test. Resolve the control id with `get-control` first. Siblings: `update-attestation` changes or renews one (an expired one too), `revoke-attestation` withdraws one. Vocabulary: compliance, attest, attestation, evidence, exception, compensating control, expiry, policy, audit. ## Parameters - `subject` is the duplicate key: an ACTIVE attestation on the control with the same subject (trimmed, ignoring case) is returned instead of a second one. - `expiresOn` must be in the future; a date alone is the end of that day, UTC. A date-time without `Z` or an offset, and a number below 1e12 (epoch seconds), are rejected. - A non-email `owner`, a non-http(s) `documentLink` or a quote in `controlId` is rejected before the tool runs. ## Outcomes - `created`, or `already_exists` when an ACTIVE attestation with this subject exists: it is returned, nothing was written, and a retry is safe; `requestedExpiresOnApplied: false` means its expiry stands. Both carry `attestation`, `control`, `blockers`, a `note` and `statusImpact`: - `blocked` — a failing test or an expired, unrevoked attestation keeps the control failing whatever is attested (`blockers` lists each). Do not call the control covered: fix the test, or renew or revoke the expired attestation. - `passes_by_attestation` — no test has a status and nothing blocks; the control passes once CCM re-scores it. - `already_passing` — a passing test already passes the control; the attestation changes nothing. - Refusals are errors starting with the outcome, `structuredContent.controlId` names the control, and nothing was created: `not_found`; `not_live` (no tool here changes a control's state, so tell the user rather than retrying); `invalid_input` (`expiresOn` fails the rules above); `interrupted` (the write was cut off at the 55-second limit and may have landed; the error says how to confirm before creating again). ## Read-back CCM reads lag its writes by up to a minute, so `get-control` can show no new attestation right after `created`; re-read after a pause, since a second create inside that window makes a duplicate. ## Access Needs the Compliance (CCM) entitlement and edit permission on the control's resource group; a missing one returns an access-denied error that names it. ## Example `{ "controlId": "<id>", "subject": "Log Management Policy v3", "expiresOn": "2027-06-30" }` Full reference: get-reference topic compliance-model
Change an existing attestation on a JupiterOne Compliance (CCM) control, most often to renew it with a later `expiresOn`; an expired attestation given a future expiry is active again, so renewing works before and after it lapses. Find the attestation `id` in `get-control` (`attestations`) or `get-compliance-summary` (`expiringAttestations`, `expiredAttestations`). Siblings: `create-attestation` records a new one, `revoke-attestation` withdraws one for good. Vocabulary: compliance, renew, extend, expiry, attestation, evidence, exception, audit. ## Parameters - At least one field to change; an omitted field is left as it is, and `null` clears `description`, `owner` or `documentLink`. - `expiresOn` must be in the future; a date alone is the end of that day, UTC. A date-time without `Z` or an offset, and a number below 1e12 (epoch seconds), are rejected. - `subject`: CCM accepts a subject another ACTIVE attestation on the control already has, but `create-attestation` finds an attestation by its subject, so keep each control's subjects distinct. ## Outcomes - `updated` — `attestation` as saved, `control` (`id`, `name`, `state`, `url`), `blockers`, a `note` naming each blocker, and `statusImpact` read after the write: `blocked` (a failing test, another expired attestation, this one still expired, or a control that is not LIVE, as `{ "type": "not_live" }`), `passes_by_attestation`, `already_passing`, or `unknown` (the control could not be read back in time; the update went through and does not need repeating, and `control` carries `id` and `url` only). `subjectCollision` names another ACTIVE attestation left with the same subject; rename one of them. - `not_found` — no attestation has this id and nothing changed; a normal result, not an error. A revoked attestation is gone for good and is `not_found` too: attest again with `create-attestation`. - Errors: `invalid_input:` (no field to change, or `expiresOn` fails the rules above; nothing was called) and `interrupted:` (the write was cut off at the 55-second limit and may have landed; read the attestation with `get-control` before repeating it). ## Access Needs the Compliance (CCM) entitlement and edit permission on the control's resource group; a missing one returns an access-denied error that names it. ## Example `{ "attestationId": "<id from get-control>", "expiresOn": "2028-06-30" }` Full reference: get-reference topic compliance-model
Withdraw an attestation on a JupiterOne Compliance (CCM) control. Revocation is permanent: a revoked attestation cannot be updated or reinstated, so confirm it with the user before calling, and use `update-attestation` to extend or correct one instead. Afterwards the control's status follows its tests and any other valid attestation. Find the `id` in `get-control` (`attestations`) or `get-compliance-summary` (`expiredAttestations`); `create-attestation` attests again later. Vocabulary: compliance, revoke, withdraw, attestation, exception, evidence, audit. ## Outcomes - `revoked` — `attestation`, `control` (`id`, `name`, `state`, `url`), `blockers`, a `note` saying what now decides the status, and `statusImpact` read after the revoke: - `no_longer_passing` — no passing test and no other valid attestation remain; once CCM re-scores the control, it is not evaluated. - `still_passing` — a passing test or another valid attestation keeps it passing. - `still_failing` — a failing test or another expired attestation keeps it failing; `blockers` lists them. - `now_passing` — the revoked attestation had expired, so a failure is cleared, and a passing test or another valid attestation passes the control once CCM re-scores it. - `no_longer_failing` — the revoked attestation had expired and nothing else passes the control; once re-scored, it is not evaluated. - `unknown` — the control could not be read back in time; the revoke went through and does not need repeating. - `not_found` — no attestation has this id and nothing changed; a normal result, not an error. An already revoked attestation is `not_found` too, so revoking the same id twice is harmless. - `interrupted:` (an error) — the write was cut off at the 55-second limit and may have landed; call again, and `not_found` confirms it. ## Access Needs the Compliance (CCM) entitlement and edit permission on the control's resource group; a missing one returns an access-denied error that names it. ## Example `{ "attestationId": "<id from get-control>" }` Full reference: get-reference topic compliance-model
One endpoint, the same key, whichever client you use.
~/Library/Application Support/Claude/claude_desktop_config.json (Mac) · %APPDATA%\Claude\claude_desktop_config.json (Windows)
Replace API_KEY with your own key.
Already have an "mcpServers" section in your config? Just add the server entry inside it.
Discovery, routing, credentials, tool scoping and execution logs all happen at the gateway→connections stay ACTIVE with no work from you
JupiterOne MCP runs through a gateway that holds the credentials, scopes the access and records every call.
Managed auth, hosted MCP servers, and every JupiterOne MCP tool your agent needs.
Free to start.