GRC Oversight
Developer docs

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.

Setup

Mint a token, then connect

01

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 read scope, 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, and list_review_schedules.
  • Allow action tools additionally grants the action scope, which also registers 7 more tools — draft_remediation, open_finding, draft_policy, propose_risk_treatment, draft_questionnaire_answer, propose_access_review_decision, and request_exception. All action tools are propose-only except open_finding and request_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.

02

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/json

A 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.

Client config

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.

Read tools

Direct, tenant-scoped answers

list_controlsscope: read

Controls across the org's entitled frameworks, each with a computed status. Optionally filter by framework (id or name substring) or status.

Parameters

  • framework string, optional

    Framework id or a case-insensitive name substring to filter to.

  • status "PASS" | "FAIL" | "WARNING" | "NOT_TESTED" | "NO_TESTS", optional

    Only 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: read

Framework-level readiness rollups for the org (pass/fail/warning/not-tested/no-tests counts and percent ready). Optionally narrow to one framework.

Parameters

  • framework string, optional

    Framework 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: read

Tests 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

  • includeWarnings boolean, optional

    Also 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: read

Recent evidence items for the org (source type, created time, linked test result), scoped strictly by the evidence's orgId.

Parameters

  • limit number (1–100), optional

    Max items to return. Defaults to 25.

  • sourceType string, optional

    Exact 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: read

Natural-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

  • query string (min length 1), required

    The natural-language question.

  • limit number (1–25), optional

    Max 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: read

The 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

  • status string, optional

    e.g. IDENTIFIED, MITIGATED, ACCEPTED, TRANSFERRED.

  • category string, optional

    e.g. ACCESS, AVAILABILITY, VENDOR, PEOPLE.

  • limit number (1–100), optional

    Max 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: read

The org's third-party risk register, each with its latest SOC 2 / risk assessment if one exists. Optionally filter by status or criticality.

Parameters

  • status string, optional

    e.g. ACTIVE, UNDER_REVIEW, INACTIVE.

  • criticality string, optional

    e.g. LOW, MEDIUM, HIGH, CRITICAL.

  • limit number (1–100), optional

    Max 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: read

The org's policy library: title, version, active flag, review cadence, and approval quorum.

Parameters

  • isActive boolean, optional

    Filter to only active or only inactive policies.

  • limit number (1–100), optional

    Max 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: read

Internal findings open for triage, optionally filtered by status or severity.

Parameters

  • status string, optional

    e.g. OPEN, IN_PROGRESS, RESOLVED, DISMISSED.

  • severity string, optional

    e.g. LOW, MEDIUM, HIGH, CRITICAL.

  • limit number (1–100), optional

    Max 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: read

Without 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

  • campaignId string, optional

    Return decisions for this campaign instead of the campaign list.

  • status string, optional

    Campaign status filter, used only when campaignId is omitted.

  • limit number (1–100), optional

    Max 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: read

Without questionnaireId: the org's uploaded security questionnaires with answer-approval progress. With one: its individual question/answer rows.

Parameters

  • questionnaireId string, optional

    Return question/answer rows for this questionnaire instead of the list.

  • limit number (1–100), optional

    Max 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: read

The org's own trust-center document library across all visibilities. This is the authenticated org-internal view, not the public gated trust page.

Parameters

  • visibility string, optional

    e.g. PUBLIC, NDA_GATED, PRIVATE.

  • limit number (1–100), optional

    Max 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: read

Connected integrations with asset compliance rollups, plus an evidence-provenance breakdown by source system, for audit/traceability context.

Parameters

  • limit number (1–100), optional

    Max 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: read

Employee security-awareness training obligations (the "people" surface this schema has a real model for): course, status, due date, completion.

Parameters

  • status string, optional

    e.g. ASSIGNED, IN_PROGRESS, COMPLETED, OVERDUE.

  • courseId string, optional

    Filter to assignments of one course.

  • limit number (1–100), optional

    Max 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: read

The 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", optional

    Filter to one risk tier.

  • status "PLANNED" | "ACTIVE" | "RETIRED", optional

    Filter to one lifecycle status.

  • limit number (1–100), optional

    Max 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: read

The org's exception register: time-boxed waivers of a control/requirement/policy/risk, with status and expiry.

Parameters

  • status "DRAFT" | "APPROVED" | "EXPIRED" | "REVOKED", optional

    Filter to one status.

  • scopeType "CONTROL" | "REQUIREMENT" | "POLICY" | "RISK", optional

    Filter to one scope type.

  • limit number (1–100), optional

    Max 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: read

The 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

  • subjectType string, optional

    e.g. RISK, POLICY, CONTROL, VENDOR, ACCESS_REVIEW, EXCEPTION, ASSET.

  • overdueOnly boolean, optional

    Only return schedules whose next review date has passed.

  • limit number (1–100), optional

    Max 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" }
    ]
  }
}
Action tools

Propose-only, approval-gated

Only registered on tokens with the action scope. Neither tool mutates a connected external system.

draft_remediationscope: action

Returns 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

  • controlId string, optional

    A control id in this org's activated frameworks.

  • testId string, optional

    A test id mapped to this org's activated-framework controls.

  • note string, optional

    Extra 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: action

Creates 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

  • title string (min length 1), required

    Finding title.

  • severity "LOW" | "MEDIUM" | "HIGH" | "CRITICAL", optional

    Defaults to MEDIUM if omitted or unrecognized.

  • description string, optional

    Optional free-text description.

  • source "scan" | "test" | "integration" | "manual", optional

    Defaults to "manual" if omitted or unrecognized.

  • controlId string, optional

    Optional link to a (global) control.

  • testResultId string, optional

    Optional 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: action

Returns 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

  • topic string (min length 1), required

    The policy topic to draft.

  • controlId string, optional

    Grounding control id, if any (must be in an activated framework).

  • note string, optional

    Extra 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: action

Returns 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

  • riskId string (min length 1), required

    A risk id belonging to this org.

  • note string, optional

    Extra 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: action

Returns 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

  • questionAnswerId string, optional

    Existing QuestionAnswer id to draft for.

  • questionText string, optional

    Raw question text, used if questionAnswerId is omitted.

  • limit number (1–25), optional

    Max 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: action

Returns a PROPOSED approve/revoke recommendation for one access under review. Persists nothing — a human records the real AccessReviewDecision row in-app.

Parameters

  • reviewId string (min length 1), required

    An AccessReview id belonging to this org.

  • targetEmail string (min length 1), required

    The access under review, by email.

  • recommendation "APPROVED" | "REVOKED", optional

    Defaults to APPROVED if omitted or unrecognized.

  • rationale string, optional

    Optional 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: action

Creates 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

  • title string (min length 1), required

    Exception title.

  • justification string (min length 1), required

    Why the exception is needed.

  • scopeType "CONTROL" | "REQUIREMENT" | "POLICY" | "RISK", required

    What kind of thing this exception waives.

  • scopeId string (min length 1), required

    Id of the control/requirement/policy/risk.

  • requestedById string (min length 1), required

    User id of the requester; must belong to this org.

  • compensatingControls string, optional

    Optional description of compensating controls in place.

  • expiresAt string, optional

    Optional 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.