MCP 2.7 Release Notes
Release date: October 2026
MCP 2.7 lets your assistant build a compliance program in Continuous Control Monitoring (CCM), not only read one. Fifteen new tools cover the whole authoring flow: check whether a standard is already covered, import a prebuilt framework or create a custom one, add its requirements and controls, write and prove each control test, run the tests, promote the controls to LIVE, and exempt the assets a test should not count. Two tools from the integration and rule groups fold into their siblings, so the server goes from 39 tools to 52, 21 of them for compliance.
Everything an assistant authors lands in DRAFT. Nothing counts toward a scorecard until you, or the assistant on your instruction, promote it with transition-controls. That is the one rule the whole release is built around: the assistant can do all of the work, and you decide when it goes live.
Remote server users: no. The hosted server runs 2.7, so the new tools appear in your connector's tool list. A client that caches the tool list picks them up when it next refreshes it.
Local server users: nothing beyond your usual update. npx @jupiterone/jupiterone-mcp picks up 2.7 on its next run. A global install updates with npm install -g @jupiterone/jupiterone-mcp.
If something of yours calls get-integration-job or get-raw-data-download-url by name, those two names are gone. See Two tools folded into their siblings.
If you built percentage Number widgets through the MCP before 2.6.2, check the figures they show. See Percentage widgets (2.6.2).
What is new in MCP 2.7
MCP 2.7 adds fifteen compliance tools and updates the six that came in MCP 2.5. Together they cover all of CCM that an assistant works with: reading status, recording attestations, and authoring and running a framework.
| Tools | In 2.7 | What it means for you |
|---|---|---|
Coverage checkcheck-compliance-coverage | New | Before assessing a standard by hand or creating anything, your assistant learns whether the framework is loaded, importable from JupiterOne's library, or absent, and which existing controls already address a topic |
Library importimport-framework | New | A prebuilt framework (CIS benchmarks, SOC 2, ISO 27001, NIST, PCI DSS, DORA) is queued for import by its library id; the summary shows the job while it runs |
Framework buildingcreate-framework, create-requirements, create-controls, link-controls, update-control | New | A custom framework is built one reviewed layer at a time, in your own wording and identifiers, reusing the controls you already have instead of duplicating them |
Control testscreate-control-test, update-control-test, delete-control-test | New | Each test's J1QL is parsed and run before it is saved, so you see what it matches today before it counts; a query the engine rejects is refused |
Evaluate and promoteevaluate-controls, transition-controls | New | Drafts prove their tests on demand, and a batch of controls, or a whole framework, moves between DRAFT, REVIEW, LIVE and RETIRED with every hop explained |
Scoped deletedelete-control | New | A control created by mistake while authoring is removed; one that has been scored or attested keeps its history, and the refusal says what to do instead |
Exemptionscreate-exemptions, revoke-exemptions | New | Specific assets are exempted from a control test with a reason, a justification and an optional expiry, and a filing reports any earlier exemption it replaced |
Compliance statusget-compliance-summary, list-controls, get-control | Updated | The summary scores a chosen set of frameworks, lists a framework's requirements and shows imports in flight; list-controls says why each failing control fails and finds controls by test name; get-control lists each test's exemptions and flags tests whose last run failed |
Attestationscreate-attestation, update-attestation, revoke-attestation | Updated | A control that is not LIVE is refused with the way to promote it (transition-controls), and a failed call names the step that failed |
Across the whole release:
| Change | What it means for you |
|---|---|
| Two guided prompts | Author a compliance framework and Promote a compliance framework walk the assistant through the flow; clients that support Skills over MCP get the same text as skills |
| Safe to repeat | Every write checks what already exists first, so repeating a call reports already_exists or already_linked instead of making a second copy. A call cut off by a time limit says whether anything was written; see Retries, time limits and partial runs |
| Errors that name the phase | A compliance call that fails mid-read says which read failed and how long each phase took, so the next call can be narrowed |
| Two tools folded | get-integration-job becomes a parameter of get-integration-jobs; get-raw-data-download-url becomes format: "downloadUrl" on get-rule-evaluation-query-results |
Check coverage before you build
check-compliance-coverage is the first call for any question that names a standard, benchmark or control topic. Given a framework name or fragment ("CIS AWS", "SOC 2", "PCI DSS 4") it reports a verdict:
covered: LIVE controls with tests exist for it.partial: controls exist but are DRAFT, REVIEW or without tests.draftCountsays how many are drafts, which is why a framework can read "0 passing, 0 failing" on the scorecard.importable: not loaded, but JupiterOne's library has it.importable[]carries thesourceandsourceIdthatimport-frameworktakes.not_covered: nothing matched.
Given a topic ("MFA for console users", "S3 encryption") it lists up to 25 existing controls that address it, with their state, status, test count and frameworks. These are reuse candidates: a control can serve several requirements and frameworks, so link-controls attaches one to a new requirement instead of creating a duplicate. An empty list means nothing matched the words given, not that no related control exists, so the assistant tries another phrasing before creating.
Import a prebuilt framework
import-framework queues one of JupiterOne's library frameworks by its source (J1 or UCF) and sourceId, as the coverage check reports them. The backend runs the import as a job. The response says the job is queued; a framework already loaded comes back as already_exists with its id and link, and one already importing as import_in_progress. Neither writes anything, so a repeat is harmless.
While the job runs, get-compliance-summary lists it in importJobs[] with its status and, if it failed, the backend's message. Imported controls arrive in DRAFT, like everything else the assistant authors, and are promoted with transition-controls.
Build a custom framework one layer at a time
For a standard the library does not carry, or an internal program, the assistant builds the framework incrementally and shows you each layer before the next:
create-frameworkcreates the empty framework from a title and description. A framework with the same title already exists? The tool returns it asalready_existsinstead of a second one.create-requirementsadds a batch of 1 to 50 requirements: each with the standard's own identifier and wording, grouped by section and ranked by priority. Requirements the framework already has, by identifier or title, come back asalready_exists; nothing is duplicated.create-controlsadds a batch of 1 to 25 controls under one requirement, in your words and identifiers. A control with the same name anywhere in the account comes back asalready_existswith its state and frameworks, and the way to use it for this requirement islink-controls, which attaches up to 25 existing controls, JupiterOne-managed or your own, to a requirement.update-controlchanges a control's fields (name, description, identifier, catalog, owner, remediation, exception process, MITRE technique, resource group) and the requirements it serves:requirementIdswithset,addorremove.setcannot be empty, since that would detach the control from every framework; detach withremove. A description or resource group can be replaced but not cleared.
link-controls and update-control check that CCM can see each requirement they add before writing. An id that does not exist is requirement_not_found. A requirement created moments ago that CCM cannot link to yet is not_ready, with nothing written; the same call works a minute later.
Each batch reports one outcome per item (created, already_exists, or refused with the backend's reason), the counts, and a nextStep. A batch the server's time limit cut short says what was left. create-requirements checks for duplicates against CCM itself, so it can be repeated as is. create-controls checks against data that trails a create by up to a minute, so it returns nextInputs holding only the items it never reached, and the assistant resends just those.
Everything lands in DRAFT and is excluded from every scorecard until it is LIVE.
Write a test and see what it matches
A control test is one J1QL query plus whether its rows are GOOD (compliant assets; the test never fails, and zero rows is a pass on no data) or BAD (violations; any row fails the test). create-control-test adds one test to a control. Before saving it, the tool parses the query locally and, when it parses, runs it once within the call's budget. The response reports the rows it returned now, whether it saw any data, and whether the run happened (ran, skipped_deadline or error with a hint). It is there so you can judge the query on today's data before it counts: a GOOD test with zero rows proves nothing, and a BAD test with rows will fail the control once it is LIVE.
A query that cannot run is refused with invalid_input, and nothing is saved: a syntax error, a query that returns an alias from a negated (THAT !) step, or a run the query engine rejects outright. structuredContent.suggestion carries the fix, a ready-to-run query when the server knows it. A run that failed for any other reason does not block the create, but the test checks nothing until its query runs, and CCM scores the control from its other tests meanwhile, so the response's nextStep says how to find and fix the error. A query that names an entity type the account does not hold is saved, but reported as effective: false: it will pass on no data until the data exists.
update-control-test changes a test's query, verdict, name or description, with the same parse and run for a changed query. delete-control-test removes a test created by mistake or made obsolete by another.
Prove the drafts, then promote
evaluate-controls runs the tests of 1 to 25 controls now instead of waiting for the daily run. Results take minutes and are read with get-control. On a DRAFT or REVIEW control the tests gain a status while the control itself stays unscored: get-control reports statusExplanation: "not_live" together with testsRan, testsPassing and testsFailing, the proof a draft carries before promotion. On a LIVE control the status follows the tests as before.
transition-controls moves controls between lifecycle states in a batch, by controlIds (1 to 25) or for a whole frameworkId (every control in one of fromStates, which defaults to DRAFT and REVIEW; with controlIds, fromStates is optional). CCM enforces the order DRAFT → REVIEW → LIVE, so a promotion from DRAFT to LIVE is made as two hops. RETIRED is accepted only with explicit ids, and a path that would pass through LIVE on the way to another state, such as retiring a draft, is not taken: promote to LIVE first if that is the intent. Every move is decided on the state CCM holds for the control at that moment, so a control already promoted is never sent back a step. The response lists each hop that was transitioned, what was skipped (already in the state, outside fromStates, a path through LIVE, not found, or an invalid transition) and what was refused with the backend's reason. The live-controls limit is enforced here: a refusal names the limit with its own numbers and stops the rest of the batch. A batch not finished within the call's budget reports remaining, lists the controls in remainingControlIds, and returns nextInputs, the calls that finish it: a control the call moved comes back by id with only the state it was left in, and a framework pass comes back as the framework, checked again control by control. A move the time limit cut off is listed in interrupted[]: it may still land, so wait about a minute and read those controls with get-control until their state stops changing before making their follow-up call.
Which state to go to is your decision. The description of each state is in the tool, and the Promote a compliance framework prompt walks through it.
Delete a mistake, retire the rest
delete-control is a hard delete: the control and its tests are removed and any attestations on it are purged. It is accepted only for a DRAFT control that has never been scored and never attested, revoked attestations included. Anything else returns not_deletable with the reason (state, was_live or has_attestations) and a nextStep that fits the control's state:
- LIVE: retire it with
transition-controlsto RETIRED, which keeps its history. - REVIEW: move it back to DRAFT with
transition-controls, then delete it if it was never LIVE. - DRAFT with history: leave it as a DRAFT, which is never scored, or detach it from its requirements with
update-control.
A control under the wrong requirement is moved with update-control, not deleted.
delete-control-test removes a test, and reports the deleted test's last result. On a LIVE control it keeps two tests: a failing one, whose removal would let the control pass on its next run, and the last one, whose removal would clear the control's status. Fix the query with update-control-test, exempt the assets with create-exemptions, or move the control to REVIEW first if the test really should go.
Exempt the assets a test should not count
create-exemptions exempts specific assets from a control test so they stop failing it: a risk the organisation accepts, an asset the test does not apply to, a false positive, or one covered by a compensating control. One call records one decision for 1 to 50 assets, taken from the test's latest evaluation rows, with an exemptionReason, a justification an auditor can read, and an optional expiry. The assets' ids come from get-rule-evaluation-query-results on the test's latest rawDataKey, which get-control returns.
The exemption applies to evaluations of the query it was filed against, so a changed query needs a new evaluation before exemptions are eligible, and create-exemptions says so when it is too early.
An asset carries one exemption per test, so filing it again replaces the earlier one, whoever filed it. The response lists what it replaced in replaced[] (group id, reason, expiry and author), and the tool is marked as destructive so your client can ask before it runs.
revoke-exemptions withdraws exemptions on a test by decision (the groupId returned on create), 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. Filing the same assets again moves them to the new call's groupId, so check the test's exemptions on get-control before relying on an older group id. get-control lists each test's exemptions, with their group ids, reasons, status and expiry.
An attestation covers a whole control; an exemption covers assets within one test.
Retries, time limits and partial runs
An assistant repeats calls, and the hosted server stops any call at 55 seconds. The authoring tools are built so neither leaves you guessing what happened:
- Repeating a call does not duplicate. Every write first checks what already exists. A repeat reports
already_exists(frameworks, requirements, controls, tests) oralready_linkedinstead of making a second copy. CCM's search data trails a create by up to a minute, so after a batch cut shortcreate-controlsreturnsnextInputsholding only the items it never reached, and the assistant resends just those. read_failedmeans nothing was written. A read the write depends on, such as the duplicate check or the control the test belongs to, did not finish within 20 seconds. The tool stops before writing; call again.- A cut-off read says so. If the 55-second limit lands while a tool is still reading, the error reads "while reading
<phase>, before anything was written", and calling again is safe. interruptedmeans the write may have landed. The limit cut off the write itself. Read the object back (get-controlfor controls, tests, exemptions and attestations,get-compliance-summaryfor frameworks and imports) before repeating it.- Batches report each item. A batch the time limit cut short lists what it did per item and what it did not reach, with
remainingand thenextInputsthat finish it.transition-controlslists moves that were cut off ininterrupted[], andevaluate-controlsmarks runs that may already be queued, to read back before queueing again.
Two guided prompts
Two prompts are registered with the server, and the same text is served as Skills over MCP to clients that support the skills extension:
- Author a compliance framework (
author-compliance-framework) takes the standard's name and, optionally, where its text comes from, and walks the assistant through coverage check, import or incremental build, test authoring with proof, and the hand-off to review. It never promotes. - Promote a compliance framework (
promote-compliance-framework) takes a framework and walks through evaluating its drafts, reading the results, explaining each state, and transitioning the controls you choose.
The framework-authoring manual, read on demand through get-reference, carries the full reference for the flow: the lifecycle, what each outcome means, the exemption model, and the recipes.
Summary and list improvements
- A chosen set of frameworks.
get-compliance-summarytakesframeworkIds(1 to 25) and scores only those, in one counts read instead of one per framework in the account. Ids that match no framework come back inframeworkIdsNotFoundwith a warning. - A framework's requirement list.
includeRequirementswith a drilled framework addsrequirementList[](id, identifier, title, section, priority), critical first, then by section and identifier. It is the listcreate-controlsandlink-controlstake requirement ids from.requirementListSkippedsays when it could not be read. - Imports in flight.
importJobs[]lists framework imports running or failed, with the backend's message on failure. - Why a control fails. Each
list-controlsrow with status FAIL carries afailReason:failing_test,no_failing_test(a LIVE control with no failing test, which an expired attestation or a status CCM has not re-scored explains, asget-controlshows),not_live, ortests_unread. - Search by test name.
searchonlist-controlsstill reads control name, description, identifier and id; controls whose test names contain the text now come back separately intestNameMatches, failing tests first, withtestNameSearchsaying whether the search ran or why not. - Tests whose runs fail.
get-controlcounts tests whose latest evaluation failed (failedEvaluationTests) and says why it matters: CCM leaves a test with no result out of the control's score, so the control can pass while that test checks nothing. - Errors that name the phase. A compliance call that fails mid-read now reads
<context> (failed in <phase>): <message>, with the phases finished so far and their milliseconds at the end, so the next call can be narrowed by that phase. The attestation tools report their phases too. - Attesting a control that is not LIVE.
create-attestationstill refuses it withnot_live, and now says how to fix it: promote the control withtransition-controls(it then counts against the live-controls limit), then attest.
Two tools folded into their siblings
Two tools whose whole job was a parameter of a sibling are gone, and their names are no longer in the tool list:
| Removed | Use instead |
|---|---|
get-integration-job | get-integration-jobs with integrationJobId and integrationInstanceId, which returns that run alone as a one-row list in the same row shape |
get-raw-data-download-url | get-rule-evaluation-query-results with format: "downloadUrl", which returns the signed link for the whole set instead of rows |
An assistant picks the new form up from the tool list. Only a script or a saved workflow that calls the old names needs changing.
Query and list fixes
- A negated step cannot be returned. A query that returns an alias declared on or after a negated step, such as
FIND qualys_host THAT !HAS qualys_host_finding AS h RETURN h, always failed in the query engine: the negated step matches what is absent, so the alias binds to nothing.execute-j1ql-query, the widget and rule tools and the control-test tools now refuse it before it runs. When the alias can only mean the first entity, the refusal carries the query rewritten to return it,FIND qualys_host AS h THAT !HAS qualys_host_finding RETURN h. Filtering or ordering by a negated step works as before. - List sizes the API accepts.
get-integration-jobstakes asizeof up to 100 andlist-rule-evaluationsalimitof up to 250, the most each API returns. Larger values used to fail with a validation error after the call.
Access and permissions
The authoring tools are available on every connection, and JupiterOne checks access on each call.
- Every compliance tool needs the Continuous Control Monitoring entitlement on the account and control read permission.
- Writes need edit permission on the control's resource group; creating or importing a framework needs framework create permission.
- Exemptions need edit permission on the control the test belongs to.
An access-denied error names the missing entitlement or permission; re-authenticating will not help, and an account admin can grant it.
Getting started
Remote server: nothing to do. Your connector already runs 2.7.
Local server: restart your AI client. npx picks up the new version automatically.
Verify the upgrade. Ask your assistant:
"Test my JupiterOne connection"
test-connection reports the package version alongside your identity and permissions. Then try:
"Do we already cover PCI DSS 4.0, or can we import it?"
More prompts are in the Compliance (CCM) tab of the prompt templates, and every tool is listed under Available Tools. For CCM itself, see Continuous Control Monitoring and the custom framework JSON upload for the UI path. For the previous compliance release, see What's new in MCP 2.5.