MCP server reference
Every tool this server actually exposes (parameters, scopes, and example request/response shapes) plus token setup and copy-paste client config for Claude and Cursor.
Mint a token, then connect
Create a token in Settings
Go to /settings/api-tokens (an ADMIN can create/revoke; other roles can view). Give it a name and choose whether to allow action tools:
- Read only (default) grants the
readscope, which registers all 17 read tools —list_controls,control_status,failing_tests,get_evidence,query_compliance,list_risks,list_vendors,list_policies,list_findings,list_access_reviews,list_questionnaires,list_trust_center_docs,list_integrations,list_training_assignments,list_ai_systems,list_exceptions, andlist_review_schedules. - Allow action tools additionally grants the
actionscope, which also registers 7 more tools —draft_remediation,open_finding,draft_policy,propose_risk_treatment,draft_questionnaire_answer,propose_access_review_decision, andrequest_exception. All action tools are propose-only exceptopen_findingandrequest_exception, which each write a single internal row for human triage/approval; the scope only controls whether a tool exists for that token, not whether it can mutate anything external (it never can).
The full plaintext token (prefixed gro_) is shown exactly once at creation. Copy it immediately. The token list afterward only ever shows a non-secret prefix, its scopes, and a last-used timestamp; revoking it takes effect immediately.
Call the MCP endpoint
The server is a single Streamable HTTP MCP endpoint at POST /api/mcpon your site's domain. Authenticate with a Bearer header:
Authorization: Bearer gro_...
Content-Type: application/jsonA missing, malformed, invalid, or revoked token returns a JSON-RPC auth error over HTTP 401. Every tool call is scoped to the org the token belongs to. The org id is never taken from the request body.
Copy-paste MCP config
Replace YOUR-DOMAIN with your site's domain and YOUR_TOKEN with a token from /settings/api-tokens.
Claude Desktop / Claude Code
{
"mcpServers": {
"grc-oversight": {
"type": "http",
"url": "https://YOUR-DOMAIN/api/mcp",
"headers": { "Authorization": "Bearer YOUR_TOKEN" }
}
}
}Claude Desktop: Settings -> Developer -> Edit config, then restart. Claude Code: add the same block under mcpServers in .mcp.json (project) or your user MCP config.
Cursor
{
"mcpServers": {
"grc-oversight": {
"url": "https://YOUR-DOMAIN/api/mcp",
"headers": { "Authorization": "Bearer YOUR_TOKEN" }
}
}
}Cursor: Settings -> MCP -> Add new MCP server, or edit ~/.cursor/mcp.json directly with the block above.
Direct, tenant-scoped answers
list_controlsscope: readControls across the org's entitled frameworks, each with a computed status. Optionally filter by framework (id or name substring) or status.
Parameters
frameworkstring, optionalFramework id or a case-insensitive name substring to filter to.
status"PASS" | "FAIL" | "WARNING" | "NOT_TESTED" | "NO_TESTS", optionalOnly return controls currently in this status.
Example request
{
"name": "list_controls",
"arguments": { "framework": "SOC 2", "status": "FAIL" }
}Example response shape
{
"content": [{ "type": "text", "text": "1 control(s):\n[FAIL] SOC 2 CC6.1: Encryption at rest" }],
"structuredContent": {
"controls": [
{
"id": "ctl_...",
"code": "CC6.1",
"title": "Encryption at rest",
"framework": "SOC 2",
"status": "FAIL"
}
]
}
}If the org has no activated frameworks, or the framework filter matches nothing, this returns an empty result rather than a fabricated list.
control_statusscope: readFramework-level readiness rollups for the org (pass/fail/warning/not-tested/no-tests counts and percent ready). Optionally narrow to one framework.
Parameters
frameworkstring, optionalFramework id or a case-insensitive name substring to filter to.
Example request
{
"name": "control_status",
"arguments": { "framework": "ISO 27001" }
}Example response shape
{
"content": [{ "type": "text", "text": "ISO 27001: 82% ready (41 pass / 3 fail / 2 warning / 5 not-tested / 0 no-tests of 51)" }],
"structuredContent": {
"frameworks": [
{
"framework": "ISO 27001",
"readinessPct": 82,
"pass": 41,
"fail": 3,
"warning": 2,
"notTested": 5,
"noTests": 0,
"total": 51
}
]
}
}failing_testsscope: readTests whose latest result is FAIL (and WARNING when includeWarnings is set) for controls in the org's entitled frameworks. This is the "what is broken now" view.
Parameters
includeWarningsboolean, optionalAlso include tests whose latest result is WARNING, not just FAIL.
Example request
{
"name": "failing_tests",
"arguments": { "includeWarnings": true }
}Example response shape
{
"content": [{ "type": "text", "text": "1 failing test(s):\n[FAIL] Encryption-at-rest scan (affects SOC 2 CC6.1)" }],
"structuredContent": {
"tests": [
{
"testId": "tst_...",
"testName": "Encryption-at-rest scan",
"status": "FAIL",
"executedAt": "2026-06-30T12:00:00.000Z",
"affectedControls": ["SOC 2 CC6.1"],
"outputDetails": null
}
]
}
}Tests that have never run are reported as not-tested, not failing. They will not appear here.
get_evidencescope: readRecent evidence items for the org (source type, created time, linked test result), scoped strictly by the evidence's orgId.
Parameters
limitnumber (1–100), optionalMax items to return. Defaults to 25.
sourceTypestring, optionalExact match filter, e.g. MANUAL_UPLOAD, AUTOMATED_SCAN, INTEGRATION.
Example request
{
"name": "get_evidence",
"arguments": { "limit": 10, "sourceType": "AUTOMATED_SCAN" }
}Example response shape
{
"content": [{ "type": "text", "text": "1 evidence item(s):\n2026-06-30T12:00:00.000Z [AUTOMATED_SCAN] Encryption-at-rest scan (PASS)" }],
"structuredContent": {
"evidence": [
{
"id": "ev_...",
"sourceType": "AUTOMATED_SCAN",
"createdAt": "2026-06-30T12:00:00.000Z",
"hasFile": true,
"test": "Encryption-at-rest scan",
"testStatus": "PASS"
}
]
}
}query_compliancescope: readNatural-language query over the org's compliance graph. Uses semantic search over the org's own knowledge chunks when embeddings are configured, always falls back to keyword search over entitled controls, and optionally summarizes with the LLM when configured, grounded only in retrieved matches, never fabricated.
Parameters
querystring (min length 1), requiredThe natural-language question.
limitnumber (1–25), optionalMax matches to retrieve/cite. Defaults to 8.
Example request
{
"name": "query_compliance",
"arguments": { "query": "What covers encryption at rest?", "limit": 5 }
}Example response shape
{
"content": [{ "type": "text", "text": "Encryption at rest is covered by SOC 2 CC6.1...\n\nSources:\n[1] (control) SOC 2 CC6.1: Encryption at rest..." }],
"structuredContent": {
"matches": [
{ "kind": "control", "ref": "SOC 2 CC6.1", "text": "Encryption at rest..." }
],
"summarized": true
}
}If no frameworks are activated and no matches are found, the tool says so explicitly instead of guessing. "summarized" is false when no LLM is configured; the raw matches are still returned as citations.
list_risksscope: readThe org's risk register: title, likelihood/impact, inherent and residual scores, and owner. Ordered by inherent score, then newest first. Optionally filter by status or category.
Parameters
statusstring, optionale.g. IDENTIFIED, MITIGATED, ACCEPTED, TRANSFERRED.
categorystring, optionale.g. ACCESS, AVAILABILITY, VENDOR, PEOPLE.
limitnumber (1–100), optionalMax items to return. Defaults to 25.
Example request
{
"name": "list_risks",
"arguments": { "status": "IDENTIFIED", "limit": 5 }
}Example response shape
{
"content": [{ "type": "text", "text": "1 risk(s):\n[IDENTIFIED] Vendor concentration risk (inherent 12, residual 6) — VENDOR" }],
"structuredContent": {
"risks": [
{
"id": "rsk_...",
"title": "Vendor concentration risk",
"status": "IDENTIFIED",
"category": "VENDOR",
"likelihood": 3,
"impact": 4,
"inherentScore": 12,
"residualScore": 6,
"reviewedAt": "2026-05-01T00:00:00.000Z",
"owner": { "name": "Jane Doe", "email": "[email protected]" }
}
]
}
}list_vendorsscope: readThe org's third-party risk register, each with its latest SOC 2 / risk assessment if one exists. Optionally filter by status or criticality.
Parameters
statusstring, optionale.g. ACTIVE, UNDER_REVIEW, INACTIVE.
criticalitystring, optionale.g. LOW, MEDIUM, HIGH, CRITICAL.
limitnumber (1–100), optionalMax items to return. Defaults to 25.
Example request
{
"name": "list_vendors",
"arguments": { "criticality": "HIGH" }
}Example response shape
{
"content": [{ "type": "text", "text": "1 vendor(s):\n[ACTIVE] Acme Cloud (HIGH, INFRASTRUCTURE) — last assessment: PASS (LOW)" }],
"structuredContent": {
"vendors": [
{
"id": "vnd_...",
"name": "Acme Cloud",
"status": "ACTIVE",
"criticality": "HIGH",
"category": "INFRASTRUCTURE",
"website": "https://acme.example",
"latestAssessment": { "soc2Status": "PASS", "riskRating": "LOW", "reportExpiresAt": "2027-01-01T00:00:00.000Z" }
}
]
}
}list_policiesscope: readThe org's policy library: title, version, active flag, review cadence, and approval quorum.
Parameters
isActiveboolean, optionalFilter to only active or only inactive policies.
limitnumber (1–100), optionalMax items to return. Defaults to 25.
Example request
{
"name": "list_policies",
"arguments": { "isActive": true }
}Example response shape
{
"content": [{ "type": "text", "text": "1 polic(y/ies):\n[ACTIVE] Information Security Policy v3 (review: ANNUAL)" }],
"structuredContent": {
"policies": [
{
"id": "pol_...",
"title": "Information Security Policy",
"version": 3,
"isActive": true,
"reviewCadence": "ANNUAL",
"approvedAt": "2026-01-10T00:00:00.000Z",
"approvalQuorum": 2,
"createdAt": "2025-01-10T00:00:00.000Z"
}
]
}
}list_findingsscope: readInternal findings open for triage, optionally filtered by status or severity.
Parameters
statusstring, optionale.g. OPEN, IN_PROGRESS, RESOLVED, DISMISSED.
severitystring, optionale.g. LOW, MEDIUM, HIGH, CRITICAL.
limitnumber (1–100), optionalMax items to return. Defaults to 25.
Example request
{
"name": "list_findings",
"arguments": { "status": "OPEN" }
}Example response shape
{
"content": [{ "type": "text", "text": "1 finding(s):\n[HIGH/OPEN] S3 bucket policy allows public read (source: scan)" }],
"structuredContent": {
"findings": [
{ "id": "fnd_...", "title": "S3 bucket policy allows public read", "severity": "HIGH", "status": "OPEN", "source": "scan" }
]
}
}Fails soft: returns an empty state (not an error) if the Finding model has not yet been provisioned in this deployment.
list_access_reviewsscope: readWithout campaignId: the org's access-review campaigns with completion counts. With campaignId: the individual reviewer decisions inside that campaign (scoped to campaigns owned by this org).
Parameters
campaignIdstring, optionalReturn decisions for this campaign instead of the campaign list.
statusstring, optionalCampaign status filter, used only when campaignId is omitted.
limitnumber (1–100), optionalMax items to return. Defaults to 25.
Example request
{
"name": "list_access_reviews",
"arguments": { "status": "ACTIVE" }
}Example response shape
{
"content": [{ "type": "text", "text": "1 campaign(s):\n[ACTIVE] Q2 2026 Access Review (due 2026-06-30) — 12/40 reviews complete" }],
"structuredContent": {
"campaigns": [
{ "id": "arc_...", "name": "Q2 2026 Access Review", "period": "Q2 2026", "status": "ACTIVE", "dueDate": "2026-06-30T00:00:00.000Z", "totalReviews": 40, "completedReviews": 12 }
]
}
}A campaignId for another tenant returns "not found", never another org's decisions.
list_questionnairesscope: readWithout questionnaireId: the org's uploaded security questionnaires with answer-approval progress. With one: its individual question/answer rows.
Parameters
questionnaireIdstring, optionalReturn question/answer rows for this questionnaire instead of the list.
limitnumber (1–100), optionalMax items to return. Defaults to 25.
Example request
{
"name": "list_questionnaires",
"arguments": {}
}Example response shape
{
"content": [{ "type": "text", "text": "1 questionnaire(s):\n[IN_PROGRESS] acme-security-questionnaire.xlsx — 8/20 answers approved" }],
"structuredContent": {
"questionnaires": [
{ "id": "sq_...", "fileName": "acme-security-questionnaire.xlsx", "status": "IN_PROGRESS", "createdAt": "2026-06-01T00:00:00.000Z", "completedAt": null, "totalQuestions": 20, "approvedQuestions": 8 }
]
}
}list_trust_center_docsscope: readThe org's own trust-center document library across all visibilities. This is the authenticated org-internal view, not the public gated trust page.
Parameters
visibilitystring, optionale.g. PUBLIC, NDA_GATED, PRIVATE.
limitnumber (1–100), optionalMax items to return. Defaults to 25.
Example request
{
"name": "list_trust_center_docs",
"arguments": { "visibility": "PUBLIC" }
}Example response shape
{
"content": [{ "type": "text", "text": "1 document(s):\n[PUBLIC] SOC 2 Type II Report (Audit Report) — soc2-report.pdf" }],
"structuredContent": {
"documents": [
{ "id": "trd_...", "title": "SOC 2 Type II Report", "category": "Audit Report", "visibility": "PUBLIC", "fileName": "soc2-report.pdf", "createdAt": "2026-04-01T00:00:00.000Z" }
]
}
}list_integrationsscope: readConnected integrations with asset compliance rollups, plus an evidence-provenance breakdown by source system, for audit/traceability context.
Parameters
limitnumber (1–100), optionalMax items to return. Defaults to 25.
Example request
{
"name": "list_integrations",
"arguments": {}
}Example response shape
{
"content": [{ "type": "text", "text": "1 integration(s):\n[CONNECTED] AWS — 42 asset(s), 3 failing compliance\n\nEvidence by source system:\nAWS: 18 evidence item(s)" }],
"structuredContent": {
"integrations": [
{ "id": "int_...", "type": "AWS", "status": "CONNECTED", "lastSyncedAt": "2026-07-06T00:00:00.000Z", "assetsTotal": 42, "assetsFailing": 3 }
],
"evidenceBySourceSystem": [{ "sourceSystem": "AWS", "_count": { "_all": 18 } }]
}
}list_training_assignmentsscope: readEmployee security-awareness training obligations (the "people" surface this schema has a real model for): course, status, due date, completion.
Parameters
statusstring, optionale.g. ASSIGNED, IN_PROGRESS, COMPLETED, OVERDUE.
courseIdstring, optionalFilter to assignments of one course.
limitnumber (1–100), optionalMax items to return. Defaults to 25.
Example request
{
"name": "list_training_assignments",
"arguments": { "status": "OVERDUE" }
}Example response shape
{
"content": [{ "type": "text", "text": "1 assignment(s):\n[OVERDUE] [email protected] — Security Awareness 2026 (due 2026-06-01)" }],
"structuredContent": {
"assignments": [
{ "id": "trn_...", "employeeEmail": "[email protected]", "employeeName": "Jane Doe", "status": "OVERDUE", "source": "manual", "dueAt": "2026-06-01T00:00:00.000Z", "completedAt": null, "score": null, "course": { "title": "Security Awareness 2026" } }
]
}
}list_ai_systemsscope: readThe org's AI system inventory (ISO 42001 / EU AI Act register): vendor, purpose, risk tier, and human-oversight flag.
Parameters
riskTier"MINIMAL" | "LIMITED" | "HIGH" | "UNACCEPTABLE", optionalFilter to one risk tier.
status"PLANNED" | "ACTIVE" | "RETIRED", optionalFilter to one lifecycle status.
limitnumber (1–100), optionalMax items to return. Defaults to 25.
Example request
{
"name": "list_ai_systems",
"arguments": { "riskTier": "HIGH" }
}Example response shape
{
"content": [{ "type": "text", "text": "1 AI system(s):\n[HIGH/ACTIVE] Support Copilot (Zendesk AI) — NO human oversight" }],
"structuredContent": {
"aiSystems": [
{ "id": "ais_...", "name": "Support Copilot", "vendor": "Zendesk AI", "purpose": "Customer support drafting", "status": "ACTIVE", "riskTier": "HIGH", "isThirdParty": true, "dataTypes": ["CUSTOMER_PII"], "humanOversight": false, "lastReviewedAt": "2026-03-01T00:00:00.000Z" }
]
}
}list_exceptionsscope: readThe org's exception register: time-boxed waivers of a control/requirement/policy/risk, with status and expiry.
Parameters
status"DRAFT" | "APPROVED" | "EXPIRED" | "REVOKED", optionalFilter to one status.
scopeType"CONTROL" | "REQUIREMENT" | "POLICY" | "RISK", optionalFilter to one scope type.
limitnumber (1–100), optionalMax items to return. Defaults to 25.
Example request
{
"name": "list_exceptions",
"arguments": { "status": "DRAFT" }
}Example response shape
{
"content": [{ "type": "text", "text": "1 exception(s):\n[DRAFT] Waive MFA for service account (CONTROL) — expires 2026-09-01" }],
"structuredContent": {
"exceptions": [
{ "id": "exc_...", "title": "Waive MFA for service account", "scopeType": "CONTROL", "scopeId": "ctl_...", "status": "DRAFT", "approvedAt": null, "expiresAt": "2026-09-01T00:00:00.000Z", "reviewedAt": null }
]
}
}list_review_schedulesscope: readThe org's recurring review-cycle queue across all reviewable subject types (risk, policy, control, vendor, access review, exception, asset). Optionally show only overdue schedules.
Parameters
subjectTypestring, optionale.g. RISK, POLICY, CONTROL, VENDOR, ACCESS_REVIEW, EXCEPTION, ASSET.
overdueOnlyboolean, optionalOnly return schedules whose next review date has passed.
limitnumber (1–100), optionalMax items to return. Defaults to 25.
Example request
{
"name": "list_review_schedules",
"arguments": { "overdueOnly": true }
}Example response shape
{
"content": [{ "type": "text", "text": "1 schedule(s):\n[VENDOR] vnd_... — QUARTERLY, next due 2026-04-01 (OVERDUE)" }],
"structuredContent": {
"schedules": [
{ "id": "rvs_...", "subjectType": "VENDOR", "subjectId": "vnd_...", "cadence": "QUARTERLY", "nextReviewAt": "2026-04-01T00:00:00.000Z", "lastReviewedAt": "2026-01-01T00:00:00.000Z" }
]
}
}Propose-only, approval-gated
Only registered on tokens with the action scope. Neither tool mutates a connected external system.
draft_remediationscope: actionReturns a PROPOSED remediation for a control or a failing test. Persists nothing and touches no customer system. It is grounded in the real control/test row when an LLM is configured, otherwise a structured stub built from real data. Requires exactly one of controlId or testId.
Parameters
controlIdstring, optionalA control id in this org's activated frameworks.
testIdstring, optionalA test id mapped to this org's activated-framework controls.
notestring, optionalExtra context to ground the draft.
Example request
{
"name": "draft_remediation",
"arguments": { "controlId": "ctl_...", "note": "We use RDS, not self-managed Postgres." }
}Example response shape
{
"content": [{ "type": "text", "text": "PROPOSED REMEDIATION (not applied, requires human approval)\nSubject: SOC 2 CC6.1: Encryption at rest\n\n1. Enable RDS storage encryption...\n2. ...\n3. Re-run the associated test and capture the passing result as evidence." }],
"structuredContent": {
"subject": "SOC 2 CC6.1: Encryption at rest",
"proposal": "1. Enable RDS storage encryption...\n2. ...",
"applied": false,
"requiresApproval": true
}
}Requires the "action" scope. A read-only token cannot even see this tool registered. Never mutates a connected system on its own.
open_findingscope: actionCreates ONE internal Finding row for human triage. The only action tool that writes, and it writes only to GRC Oversight's own Finding table, never to an external system. Fails soft (returns a clear "not yet available" result, does not throw) if the Finding model is not provisioned in this deployment.
Parameters
titlestring (min length 1), requiredFinding title.
severity"LOW" | "MEDIUM" | "HIGH" | "CRITICAL", optionalDefaults to MEDIUM if omitted or unrecognized.
descriptionstring, optionalOptional free-text description.
source"scan" | "test" | "integration" | "manual", optionalDefaults to "manual" if omitted or unrecognized.
controlIdstring, optionalOptional link to a (global) control.
testResultIdstring, optionalOptional link to a test result. Must belong to this org; otherwise the call is rejected and nothing is created.
Example request
{
"name": "open_finding",
"arguments": {
"title": "S3 bucket policy allows public read",
"severity": "HIGH",
"source": "scan"
}
}Example response shape
{
"content": [{ "type": "text", "text": "Opened finding \"S3 bucket policy allows public read\" (severity HIGH, source scan) for triage." }],
"structuredContent": { "created": true, "id": "fnd_...", "severity": "HIGH", "source": "scan" }
}Requires the "action" scope. If testResultId does not belong to the calling org, the tool returns { created: false, reason: "test_result_not_found" } rather than creating anything.
draft_policyscope: actionReturns a PROPOSED policy document for a topic, optionally grounded in a real control. Persists nothing — a human authors/saves the real Policy row in-app.
Parameters
topicstring (min length 1), requiredThe policy topic to draft.
controlIdstring, optionalGrounding control id, if any (must be in an activated framework).
notestring, optionalExtra context to ground the draft.
Example request
{
"name": "draft_policy",
"arguments": { "topic": "Acceptable use of AI coding assistants" }
}Example response shape
{
"content": [{ "type": "text", "text": "PROPOSED POLICY DRAFT (not saved, requires human review)\nTopic: Acceptable use of AI coding assistants\n\n1. Purpose...\n2. Scope...\n3. Policy statements...\n4. Enforcement and review cadence: ANNUAL" }],
"structuredContent": {
"topic": "Acceptable use of AI coding assistants",
"proposal": "1. Purpose...\n2. Scope...\n3. Policy statements...",
"applied": false,
"requiresApproval": true
}
}Requires the "action" scope. Never marks anything as adopted or signed — that happens in-app.
propose_risk_treatmentscope: actionReturns a PROPOSED treatment plan (mitigate/accept/transfer/avoid) for an existing risk. Persists nothing — a human updates the real Risk row (status, mitigation notes, residual scores) in-app.
Parameters
riskIdstring (min length 1), requiredA risk id belonging to this org.
notestring, optionalExtra context to ground the proposal.
Example request
{
"name": "propose_risk_treatment",
"arguments": { "riskId": "rsk_...", "note": "We've added SSO enforcement since this was last scored." }
}Example response shape
{
"content": [{ "type": "text", "text": "PROPOSED RISK TREATMENT (not applied, requires human decision)\nRisk: Vendor concentration risk\n\nRecommendation: MITIGATE\n1. ...\n2. ..." }],
"structuredContent": {
"riskId": "rsk_...",
"proposal": "Recommendation: MITIGATE\n1. ...\n2. ...",
"applied": false,
"requiresApproval": true
}
}Requires the "action" scope. Only proposes against risks scoped to this org; never claims the risk is already treated.
draft_questionnaire_answerscope: actionReturns a PROPOSED answer for a questionnaire question, grounded in the org's real knowledge chunks/controls when available (via the same retrieval as query_compliance). Persists nothing — finalAnswer/isApproved are set by a human in-app.
Parameters
questionAnswerIdstring, optionalExisting QuestionAnswer id to draft for.
questionTextstring, optionalRaw question text, used if questionAnswerId is omitted.
limitnumber (1–25), optionalMax grounding matches to retrieve. Defaults to 5.
Example request
{
"name": "draft_questionnaire_answer",
"arguments": { "questionText": "Do you encrypt data at rest?" }
}Example response shape
{
"content": [{ "type": "text", "text": "PROPOSED ANSWER (not saved as final, requires human approval)\nQuestion: Do you encrypt data at rest?\n\nYes — all data at rest is encrypted using AES-256 [1]..." }],
"structuredContent": {
"questionText": "Do you encrypt data at rest?",
"proposal": "Yes — all data at rest is encrypted using AES-256 [1]...",
"groundedOn": 2,
"applied": false,
"requiresApproval": true
}
}Requires the "action" scope. One of questionAnswerId or questionText must be provided. If no grounding context is found and no LLM is configured, the draft says so explicitly rather than guessing.
propose_access_review_decisionscope: actionReturns a PROPOSED approve/revoke recommendation for one access under review. Persists nothing — a human records the real AccessReviewDecision row in-app.
Parameters
reviewIdstring (min length 1), requiredAn AccessReview id belonging to this org.
targetEmailstring (min length 1), requiredThe access under review, by email.
recommendation"APPROVED" | "REVOKED", optionalDefaults to APPROVED if omitted or unrecognized.
rationalestring, optionalOptional free-text justification.
Example request
{
"name": "propose_access_review_decision",
"arguments": {
"reviewId": "arv_...",
"targetEmail": "[email protected]",
"recommendation": "REVOKED",
"rationale": "No longer with the company."
}
}Example response shape
{
"content": [{ "type": "text", "text": "PROPOSED ACCESS REVIEW DECISION (not recorded, requires human sign-off)\nSystem: Okta\nTarget: [email protected]\nRecommendation: REVOKED\nRationale: No longer with the company." }],
"structuredContent": {
"reviewId": "arv_...",
"targetEmail": "[email protected]",
"recommendation": "REVOKED",
"rationale": "No longer with the company.",
"applied": false,
"requiresApproval": true
}
}Requires the "action" scope. The reviewId must belong to an AccessReview owned by this org.
request_exceptionscope: actionCreates ONE internal Exception row in DRAFT status for human approval — a time-boxed waiver of a control/requirement/policy/risk. Never creates an APPROVED exception; only a human approves it in-app.
Parameters
titlestring (min length 1), requiredException title.
justificationstring (min length 1), requiredWhy the exception is needed.
scopeType"CONTROL" | "REQUIREMENT" | "POLICY" | "RISK", requiredWhat kind of thing this exception waives.
scopeIdstring (min length 1), requiredId of the control/requirement/policy/risk.
requestedByIdstring (min length 1), requiredUser id of the requester; must belong to this org.
compensatingControlsstring, optionalOptional description of compensating controls in place.
expiresAtstring, optionalOptional ISO date string for the proposed expiry.
Example request
{
"name": "request_exception",
"arguments": {
"title": "Waive MFA for legacy service account",
"justification": "Vendor system does not support MFA; migration ticketed.",
"scopeType": "CONTROL",
"scopeId": "ctl_...",
"requestedById": "usr_...",
"expiresAt": "2026-09-01"
}
}Example response shape
{
"content": [{ "type": "text", "text": "Requested exception \"Waive MFA for legacy service account\" (status DRAFT — awaiting human approval), proposed expiry 2026-09-01." }],
"structuredContent": {
"created": true,
"exception": { "id": "exc_...", "title": "Waive MFA for legacy service account", "status": "DRAFT", "expiresAt": "2026-09-01T00:00:00.000Z" },
"applied": false,
"requiresApproval": true
}
}Requires the "action" scope. This is the second action tool (besides open_finding) that writes: it validates requestedById and, for POLICY/RISK scopes, scopeId against this org before creating a single DRAFT-status row.
Ready to connect your AI client?
Mint a token in Settings and drop the config above into your client.