Developers
Resolute Security MCP server
Connect Claude, Cowork, or any MCP-compatible client to your real security and compliance posture. 37 org-scoped tools: 26 reads and 11 writes — read-only by default, writes behind an explicit OAuth consent, and honesty caps that keep an agent from ever inflating a measured score.
tools.resolute-security.com/api/mcpOverview
The MCP server is the same platform your dashboard reads, exposed over the Model Context Protocol (Streamable HTTP). Add the endpoint above to Claude, Cowork, or any MCP client and your agent can read posture scores, findings, framework readiness, evidence gaps, vendor risk, and your audit log — and, with your explicit consent, collect evidence and file findings back in. Connecting an agent to your posture is a Pro feature; every tool is scoped to the organization on the credential (no tool accepts an organizationId), and outputs pass a secret-redaction sweep at the wire.
This reference is generated from the same tool registry the server registers its tools from — the names, scopes, and parameters below cannot drift from what a connected agent sees. Each tool’s full description states plainly whether its numbers are MEASURED (exact counts, cached scan results) or estimated. New here? The AI & MCP guide walks through connecting step by step.
Authentication
Two credentials work, both Pro-gated and org-scoped:
- OAuth 2.1 + PKCE (recommended): the flow Claude and Cowork use. Your MCP client discovers the authorization server via
/.well-known/oauth-authorization-server, registers dynamically, and sends you to a browser consent screen. The token carries the organization you picked, the consenting user, and exactly the scopes you granted. smb_API keys: the same Bearer keys as the REST API, minted in Settings → API keys. A key is always read-only here: it is not a user, so it can never carry the write scope — by design.
Unauthenticated requests get a 401 whose WWW-Authenticate header points at the protected-resource metadata, so spec-compliant clients find the consent flow on their own.
Scopes & writes
Every connection is read-only by default. Write access is a deliberate, per-connection grant on the OAuth consent screen — and every one of the 11 write tools passes the same shared gate before it runs:
- Write scope required: read-only credentials (every API key, and any connection where you declined write) are rejected with
403 forbiddenbefore anything runs. - A real consenting user: writes are recorded as the user who authorized the connection — agent actions are attributable, never anonymous.
- Demo sandbox blocked: the public demo can browse but never mutate through an agent.
- Quota-metered: a per-organization daily write quota bounds a runaway loop; exhausting it returns a typed
quota_exceededwith a retry delay. - Provenance-stamped: everything an agent writes is audited
via:"mcp"and shows up under the “AI agent” filter in your activity log, with an AI-attested badge where it surfaces in the app. - One owner-only tool:
integration_sync_nowadditionally requires the org owner role, because a manual sync spends shared worker capacity and calls the provider’s API.
Honesty guarantees
An agent can read, suggest, and — with consent — collect. It can never single-handedly mark a control met, and it can never inflate compliance or insurance readiness. Finding triage (resolve / risk-accept) is note-gated and audited as agent activity. These caps are enforced in the compliance and insurance engines, not just written here:
- Profile facts an agent records are stored as attestations (source
mcp), never measurements. An agent-submitted “yes” on a framework control is stored as “partial” with an[attested:mcp]marker — a human confirms “met” in the app. - Insurance readiness excludesagent-attested facts entirely — an agent’s own writes can never inflate what it reads back — and attestations never satisfy a live-feed freshness gate.
- A finding an agent files can only lowera posture score, never raise one. Evidence an agent attaches never changes a control’s answer — deciding whether a control is met stays a human decision.
- Descriptions label their numbers: MEASURED means exact counts or cached scan results from the same engines the dashboard uses; anything estimated says so. An unstarted framework reports null readiness — never a fabricated number.
Tool reference
All 37 tools, grouped by domain. read tools work with any credential; write tools need the write scope on a user-authorized connection. Results are JSON text blocks; errors are typed (see Errors).
Posture — 4 tools
get_posture_scores
readCurrent security, compliance, and insurance posture scores for your organization.
No arguments — the organization always comes from your credential.
Full tool description (what a connected agent sees)
Current security, compliance, and insurance posture scores for your organization. MEASURED: each score is computed by the same pure scoring engine the dashboard uses (lib/scoring), from live scan results, finding counts, framework responses, MFA enrollment, and DMARC policy. A null score means there isn't enough data yet — never assume zero. No arguments; the org is taken from your API key.
get_posture_trend
readHow your posture scores have moved over time.
| Parameter | Type | Required | Description |
|---|---|---|---|
| daysAgo | integer (1–365) | no | Baseline age in days for the delta (default 7). |
| historyDays | integer (1–365) | no | History window length in days (default 60). |
Full tool description (what a connected agent sees)
How your posture scores have moved over time. Returns the latest-vs-prior delta plus a daily history window. MEASURED from stored daily snapshots (score_snapshots); if snapshots are sparse the delta uses the closest earlier snapshot. `daysAgo` sets the delta baseline (default 7); `historyDays` sets the history window (default 60).
get_next_actions
readYour ranked 'what to do next' list — the same engine that powers the dashboard's next-actions and the AI coach.
No arguments — the organization always comes from your credential.
Full tool description (what a connected agent sees)
Your ranked 'what to do next' list — the same engine that powers the dashboard's next-actions and the AI coach. MEASURED: derived from open findings + SLA state, failing insurance checklist items, in-progress frameworks, integration errors/gaps, overdue offboarding, and vendor signals. No arguments.
insurance_readiness_get
readYour cyber-insurance underwriting readiness: the twelve underwriter-checklist controls plus the impact-weighted readiness report (score 0–100, hedged band summary, gaps ranked by pointsAtStake, per-coverage roll-up, and the supplemental-application Q&A).
No arguments — the organization always comes from your credential.
Full tool description (what a connected agent sees)
Your cyber-insurance underwriting readiness: the twelve underwriter-checklist controls plus the impact-weighted readiness report (score 0–100, hedged band summary, gaps ranked by pointsAtStake, per-coverage roll-up, and the supplemental-application Q&A). Each control row separates what is MEASURED from what is ATTESTED: `auto` {state, reason, sources (fact keys), lastCollectedAt} is derived from live integration facts; `manualOverride` is the operator's attestation (null when none); `effective` is what the report scores (override wins). HONESTY, built in: the auto-fill deliberately EXCLUDES facts recorded via MCP attestation (source 'mcp') — an agent's own profile_fact_set writes can NEVER inflate what this tool reads back. A 'no-data' control counts as NOT met (you can't attest to what you can't evidence). The score is an internal readiness signal, not a carrier rating, and never promises a premium or a bind. READ-ONLY; internal source references are never returned. No arguments.
Findings — 4 tools
findings_list
readList your organization's findings with optional filters and cursor pagination.
| Parameter | Type | Required | Description |
|---|---|---|---|
| status | string | no | Comma-separated status filter. |
| severity | string | no | Severity floor: info|low|med|high|critical. |
| kind | string | no | — |
| source | string | no | — |
| q | string | no | Substring on title/description. |
| limit | integer (1–100) | no | — |
| cursor | string | no | nextCursor from a prior page. |
Full tool description (what a connected agent sees)
List your organization's findings with optional filters and cursor pagination. Filters match the findings board exactly: `status` (comma-separated: open,in_progress,resolved,risk_accepted,wont_fix), `severity` is a FLOOR (e.g. 'high' returns high+critical), plus `kind`, `source`, and `q` (substring on title/description). Pass `cursor` from a prior page's nextCursor to continue. Org-scoped; secrets and free-form metadata are never returned.
findings_get
readFetch a single finding by id, scoped to your organization.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string | yes | The finding's UUID. |
Full tool description (what a connected agent sees)
Fetch a single finding by id, scoped to your organization. Returns not_found (404) when the id doesn't exist OR belongs to another org — the two are indistinguishable on purpose. Secrets and free-form metadata are never returned.
finding_create
writeFILES an observed issue, risk, or gap as a tracked FINDING in the platform's unified findings list (the same list scans + integrations feed).
| Parameter | Type | Required | Description |
|---|---|---|---|
| title | string | yes | Short finding title (required). |
| severity | "info" | "low" | "med" | "high" | "critical" | yes | Severity of the finding. |
| description | string | no | What you observed (optional). |
| remediation | string | no | How to fix it; Markdown (optional). |
| controlRefs | object { framework, controlId }[] | no | Optional links to compliance controls, e.g. [{"framework":"cmmc","controlId":"3.1.1"}]. |
| ref | string | no | Stable id for this observation so re-filing updates (not duplicates) it. Defaults to a slug of the title. |
Full tool description (what a connected agent sees)
FILES an observed issue, risk, or gap as a tracked FINDING in the platform's unified findings list (the same list scans + integrations feed). Use it to record something you discovered while connected to OTHER sources — e.g. a misconfiguration seen via an M365/SharePoint MCP, or a risk noticed on a web page — so it becomes actionable and audit-trailed. HONESTY: record only what you actually observed; never invent a finding or inflate severity. It is stored with source "mcp" so it stays clearly distinguishable from a measured scan, and can be linked to compliance controls via controlRefs. REQUIRES THE "write" SCOPE (read-only connections are rejected); the org + author come from your credential, never an argument. Idempotent: re-filing with the same `ref` UPDATES the existing finding (and re-opens it if it had been resolved) instead of duplicating. `severity` is info|low|med|high|critical.
findings_update_status
writeMove 1–200 findings to a new lifecycle status (open | in_progress | resolved | risk_accepted | wont_fix) — the same transition rules as the findings board: terminal statuses stamp resolvedAt/resolvedBy/resolvedNote, re-activating clears them, and a finding already in the requested status is a no-op reported as applied.
| Parameter | Type | Required | Description |
|---|---|---|---|
| ids | string (uuid)[] | yes | Finding UUIDs to update (1..200). |
| status | "open" | "in_progress" | "resolved" | "risk_accepted" | "wont_fix" | yes | Target lifecycle status. |
| note | string | no | Justification (≤1000 chars). REQUIRED (non-empty) for resolved, risk_accepted, and wont_fix. |
Full tool description (what a connected agent sees)
Move 1–200 findings to a new lifecycle status (open | in_progress | resolved | risk_accepted | wont_fix) — the same transition rules as the findings board: terminal statuses stamp resolvedAt/resolvedBy/resolvedNote, re-activating clears them, and a finding already in the requested status is a no-op reported as applied. STRICTER THAN THE UI, on purpose: `note` is REQUIRED and must be non-empty for resolved, risk_accepted, and wont_fix — every terminal transition an agent makes carries an on-the-record justification. Ids are org-scoped in one query; an unknown or foreign id is reported not_found in its per-id outcome (indistinguishable on purpose). One audit row is written PER changed finding (finding.status_changed, previous→new, via:'mcp'). REQUIRES THE "write" SCOPE on a user-authorized connection; demo sandbox blocked; metered by the org-day MCP write quota. Returns {applied, notFound, invalid, outcomes[]}.
Compliance — 8 tools
framework_get_scorecard
readCMMC readiness scorecard for a level (L1 | L2 | L3).
| Parameter | Type | Required | Description |
|---|---|---|---|
| framework | "L1" | "L2" | "L3" | yes | CMMC level to score. |
Full tool description (what a connected agent sees)
CMMC readiness scorecard for a level (L1 | L2 | L3). MEASURED and EXACT: this is a count/ratio of control responses, NOT a weighted SPRS score — readiness is the share of controls answered 'yes' (met), and openGaps are controls answered 'no' or 'partial'. Controls with no answer count as unanswered, never as a gap. Reuses lib/cmmc/scorecard.computeScorecard over a read-only loader (no assessment is created). If you haven't started this level, every control is unanswered.
framework_get_assessment
readYour raw CMMC control responses for a level (L1 | L2 | L3), plus per-family progress.
| Parameter | Type | Required | Description |
|---|---|---|---|
| framework | "L1" | "L2" | "L3" | yes | CMMC level to read. |
Full tool description (what a connected agent sees)
Your raw CMMC control responses for a level (L1 | L2 | L3), plus per-family progress. MEASURED: returns each answered control's status (yes|partial|no) and notes, read-only — it never creates or modifies an assessment. Unanswered controls are simply absent. Use framework_get_scorecard for the rolled-up readiness number.
compliance_get_evidence_gaps
readPer-control evidence worklist for a framework — what proof is still needed.
| Parameter | Type | Required | Description |
|---|---|---|---|
| framework | "cmmc" | "soc2" | "iso27001" | "hipaa" | "pci" | "gdpr" | "csf" | yes | Compliance framework to inspect. |
| level | string | no | CMMC level (L1|L2|L3); ignored for non-CMMC frameworks. Defaults to L2. |
Full tool description (what a connected agent sees)
Per-control evidence worklist for a framework — what proof is still needed. MEASURED from current data and READ-ONLY: it does a write-free read of your existing assessment and NEVER creates one. If you haven't started a framework, every control is reported as 'unanswered' and the summary says so. HONESTY: a control counts as 'present' ONLY when it's answered 'yes' AND backed by at least one FRESH evidence row (within the 1-year freshness window); 'yes' with no proof is 'missing', and 'yes' with only old proof is 'aging'/'stale' — never implied satisfied without current evidence. Anything not answered 'yes' is an assessment gap ('unanswered'), surfaced separately from evidence gaps. `framework` is one of cmmc|soc2|iso27001|hipaa|pci|gdpr|csf; `level` (L1|L2|L3) applies to CMMC only and is ignored by the others. No file blobs or secrets are ever returned.
framework_list
readOne-glance overview of every compliance framework: whether your org has started it, an honest readiness percent, and a quick evidence-gap count.
No arguments — the organization always comes from your credential.
Full tool description (what a connected agent sees)
One-glance overview of every compliance framework: whether your org has started it, an honest readiness percent, and a quick evidence-gap count. MEASURED and READ-ONLY: each framework is resolved with a write-free assessment read (no assessment is ever created) and readiness reuses the SAME per-framework readiness engine the dashboard uses. An unstarted framework returns started=false and readinessPercent=null — never a fabricated number. gapCount counts controls answered 'yes' without fresh evidence PLUS controls not yet answered 'yes' (it matches compliance_get_evidence_gaps exactly). For CMMC, the readiness reflects the level you've actually started (preferring L2). No arguments; the org comes from your credential.
evidence_submit
writeATTACHES one piece of proof (a link, a note, and — for CMMC only — a file) to a single control in a framework's evidence library.
| Parameter | Type | Required | Description |
|---|---|---|---|
| framework | "cmmc" | "soc2" | "iso27001" | "hipaa" | "pci" | "gdpr" | "csf" | yes | Compliance framework to attach evidence under. |
| controlId | string | yes | Control id (CSF: subcategoryId; SOC 2: criterionId). |
| level | string | no | CMMC level (L1|L2|L3); CMMC only, default L2. |
| label | string | yes | Short description of the evidence (required). |
| url | string | no | Optional http(s) link to the evidence. |
| note | string | no | Optional longer description (stored as notes). |
| file | object { name, contentType, base64 } | no | CMMC ONLY: an uploaded file (PNG/JPG/WebP/PDF, ≤5 MB), base64-encoded. |
Full tool description (what a connected agent sees)
ATTACHES one piece of proof (a link, a note, and — for CMMC only — a file) to a single control in a framework's evidence library. HONESTY: this ONLY adds evidence. It does NOT change the control's answer, readiness, status, or score — deciding whether a control is "met" stays a human decision. It cannot edit or delete anything. REQUIRES THE "write" SCOPE: connect with write access allowed (read-only API keys and read-only connections are rejected). The evidence is recorded as added by the authorizing user, and the org comes from your credential (never an argument). `framework` is cmmc|soc2|iso27001|hipaa|pci|gdpr|csf. `controlId` is the control id (for CSF the subcategoryId, for SOC 2 the criterionId). `level` (L1|L2|L3) applies to CMMC only (default L2). `label` is a short description (required); `url` (http(s) only) and `note` are optional. `file` (name+contentType+base64) is CMMC ONLY and is size-/type-limited; file bytes are never returned. Idempotent: re-submitting the same (control, label) within 60s returns the existing evidence with deduped:true instead of creating a duplicate. Submitting evidence for a control you have not started will create that framework's assessment (then attach the evidence).
cmmc_export_package
readRender an assessor-ready CMMC artifact for a level (L1|L2|L3) and return it INLINE as text: `artifact` is 'ssp' (System Security Plan, markdown), 'poam' (Plan of Action & Milestones, CSV), or 'package' (SSP + POA&M combined markdown — the default; what you hand a C3PAO).
| Parameter | Type | Required | Description |
|---|---|---|---|
| level | "L1" | "L2" | "L3" | yes | CMMC level to export. |
| artifact | "ssp" | "poam" | "package" | no | Which artifact to render (default 'package'). |
Full tool description (what a connected agent sees)
Render an assessor-ready CMMC artifact for a level (L1|L2|L3) and return it INLINE as text: `artifact` is 'ssp' (System Security Plan, markdown), 'poam' (Plan of Action & Milestones, CSV), or 'package' (SSP + POA&M combined markdown — the default; what you hand a C3PAO). MEASURED and READ-ONLY: it renders your real control responses, evidence labels/links (file BLOBS are never embedded), CUI scope assets, and the POA&M columns are folded from your actual findings-board triage (due dates, owners, tracking status). The L2 SSP includes the estimated SPRS score computed per the DoD methodology — verify before submitting to SPRS. Resolution is write-free: if you haven't started the level, it returns started:false and an honest artifact showing every control unanswered — nothing is created and nothing is invented. Returns {artifact, level, started, contentType, filename, content}. The export is audit-logged.
framework_respond
writeRecord an answer (yes | partial | no) for ONE control in a compliance framework's assessment.
| Parameter | Type | Required | Description |
|---|---|---|---|
| framework | "cmmc" | "soc2" | "iso27001" | "hipaa" | "pci" | "gdpr" | "csf" | yes | Compliance framework to answer in. |
| controlId | string | yes | Control id (CSF: subcategoryId; SOC 2: criterionId). |
| level | string | no | CMMC level (L1|L2|L3); CMMC only, default L2. |
| status | "yes" | "partial" | "no" | yes | Your assessment. NOTE: 'yes' is stored as 'partial' (attestation cap). |
| notes | string | no | Context for the answer (≤2000 chars). |
| only_if_unanswered | boolean | no | Default true: an existing answer blocks the write. Pass false explicitly to overwrite. |
Full tool description (what a connected agent sees)
Record an answer (yes | partial | no) for ONE control in a compliance framework's assessment. HONESTY CAP, stated plainly: an agent-submitted 'yes' is STORED AS 'partial' with an "[attested:mcp]" note marker and capped:true in the result — an AI can record gaps and progress but can NEVER single-handedly mark a control met; a human confirms 'yes' in the app. 'partial' and 'no' are stored unchanged (they can only lower or hold readiness). OVERWRITE GUARD: by default an existing answer BLOCKS the write (only_if_unanswered defaults true); pass only_if_unanswered:false explicitly to replace it — the cap still applies. `framework` is cmmc|soc2|iso27001|hipaa|pci|gdpr|csf; `controlId` is validated against that framework's real catalog (CSF: subcategoryId; SOC 2: criterionId); `level` (L1|L2|L3) is CMMC-only, default L2. Answering a framework you haven't started creates its assessment (assessmentCreated:true). REQUIRES THE "write" SCOPE on a user-authorized connection; demo sandbox blocked; metered by the org-day MCP write quota. The answer is stored as updated by the authorizing user, and the write is audited via:'mcp' with requested vs stored status on record. Returns {requestedStatus, storedStatus, capped, previousStatus, assessmentCreated}.
cmmc_prefill_from_integrations
writedry-run by defaultRun the SAME 'Pre-fill from integrations' engine as the in-app button: for every CMMC control your connected integrations' MEASURED facts can support, suggest (dry-run) or record (apply:true) an answer, attaching the driving fact as evidence.
| Parameter | Type | Required | Description |
|---|---|---|---|
| level | "L1" | "L2" | "L3" | yes | CMMC level to pre-fill. |
| apply | boolean | no | Default false = dry-run (writes nothing). True records the suggestions. |
| controlIds | string[] | no | Optional allow-list of control ids to consider (narrows only). |
Full tool description (what a connected agent sees)
Run the SAME 'Pre-fill from integrations' engine as the in-app button: for every CMMC control your connected integrations' MEASURED facts can support, suggest (dry-run) or record (apply:true) an answer, attaching the driving fact as evidence. DRY-RUN BY DEFAULT: apply defaults to false and the dry-run writes NOTHING (read-only resolution — it will not even create the assessment); it returns the engine's suggestions verbatim ({controlId, status, factKey, rationale, attested}) plus wouldApply/skippedExisting counts. HONESTY, enforced by the engine and this tool: statuses come FROM THE ENGINE only (you may filter WHICH controls via controlIds, never choose a status); AI-attested facts are already capped to 'partial' by the engine (attested:true explains why); an apply SKIPS every control that already has an answer — it never overwrites a human, and there is no override parameter. apply:true REQUIRES THE "write" SCOPE on a user-authorized connection; demo sandbox blocked; metered by the org-day MCP write quota; ONE audit row (cmmc.prefilled_from_integrations, via:'mcp') with the counts. Applied answers are noted "[auto:integration] <rationale>". CMMC-only for now. `level` is L1|L2|L3.
Integrations — 2 tools
integrations_get_overview
readCross-integration overview for your organization: connection coverage by category, a health roll-up (healthy/stale/error) over connected sync providers, the signal each connection earns you, and a ranked 'connect next' list.
No arguments — the organization always comes from your credential.
Full tool description (what a connected agent sees)
Cross-integration overview for your organization: connection coverage by category, a health roll-up (healthy/stale/error) over connected sync providers, the signal each connection earns you, and a ranked 'connect next' list. MEASURED: health verdicts reuse the same freshness logic the dashboard uses. SECRETS REDACTED: encrypted credentials, tokens, and secrets are never returned. No arguments.
integration_sync_now
writeowner-onlyTrigger a manual data sync for ONE connected integration, by `provider` (the org's integration for that provider is resolved automatically — preferring a healthy connection, then a stuck one to retry) or by `integration_id`.
| Parameter | Type | Required | Description |
|---|---|---|---|
| provider | "m365" | "cloudflare" | "knowbe4" | "aws" | "snyk" | "github" | "google_workspace" | "clickup" | no | Provider whose integration to sync (resolved to the org's connection). |
| integration_id | string (uuid) | no | Exact integration UUID (alternative to provider). |
Full tool description (what a connected agent sees)
Trigger a manual data sync for ONE connected integration, by `provider` (the org's integration for that provider is resolved automatically — preferring a healthy connection, then a stuck one to retry) or by `integration_id`. Pass exactly one of the two. OWNER-ONLY — the org's role model has two roles, owner and member, and this is the first owner-gated tool: a manual sync consumes shared worker capacity and calls the provider's API, so it stays with owners (members get a 403). Also requires the "write" scope and a user-authorized (OAuth) connection; blocked for the demo sandbox; metered by the org-day MCP write quota. The trigger itself reuses the app's Sync-now path verbatim: only active|error integrations sync (pending/disconnected must finish reconnecting first), a 5-minute per-integration cool-down applies ({ok:false, reason:'cooldown', retryAfterMs} — not an error), and a time-bucketed job id dedups back-to-back triggers. HONESTY: this ENQUEUES a background job and returns immediately — there is no job-status tool; poll integrations_get_overview and watch the connection's freshness/health. Audited via:'mcp'.
Access reviews — 3 tools
access_review_get
readYour organization's user-access-review campaigns.
| Parameter | Type | Required | Description |
|---|---|---|---|
| campaign_id | string (uuid) | no | Campaign UUID for single-campaign detail. |
| status | "draft" | "active" | "completed" | no | Filter the campaign list by status (ignored with campaign_id). |
Full tool description (what a connected agent sees)
Your organization's user-access-review campaigns. Without `campaign_id`: an org-wide summary (total/active/overdue campaigns, pending items, last completion) plus every campaign with its live review progress; `status` (draft|active|completed) optionally filters that list. With `campaign_id`: one campaign's full detail — items ordered pending-first, each with subject email/name, source (m365|team), decision (pending|keep|revoke|flag), decision notes, reviewer, and review time. MEASURED with one caveat stated plainly: each item's `context` (isPrivilegedAdmin, isMfaRegistered, mfaMethodCount, accountEnabled, lastSignInAt, forwardingEnabled) is a SNAPSHOT taken when the campaign was created — it is NOT live M365 state and does not update as the tenant changes. READ-ONLY. Returns not_found (404) when the campaign id doesn't exist OR belongs to another org — indistinguishable on purpose.
access_review_campaign_start
writeCreate AND launch a user-access-review campaign: subjects are snapshotted from the chosen sources — 'm365' (the connected Microsoft 365 directory, with per-user risk context) and/or 'team' (this platform's own member roster); default is both — and each becomes a pending review item.
| Parameter | Type | Required | Description |
|---|---|---|---|
| name | string | yes | Campaign name, e.g. "Q3 2026 quarterly access review". |
| sources | ("m365" | "team")[] | no | Directories to snapshot (default: both). |
| due_date | string | no | Optional review deadline, "YYYY-MM-DD". |
| scope_notes | string | no | Optional free-form scope/reviewer guidance. |
Full tool description (what a connected agent sees)
Create AND launch a user-access-review campaign: subjects are snapshotted from the chosen sources — 'm365' (the connected Microsoft 365 directory, with per-user risk context) and/or 'team' (this platform's own member roster); default is both — and each becomes a pending review item. NOT IDEMPOTENT: every call creates a NEW campaign, so call access_review_get first and reuse an active campaign instead of stacking duplicates. itemCount is reported honestly — 0 means the chosen sources yielded no reviewable subjects (e.g. no active M365 integration), not a failure. The subject context is snapshotted at THIS moment and does not update afterwards. Requires the "write" scope on a user-authorized connection AND a Pro subscription; demo sandbox blocked; metered by the org-day MCP write quota. `due_date` is "YYYY-MM-DD" (optional); `scope_notes` is free-form reviewer guidance (optional). Audited via:'mcp'. Record decisions with access_review_record_decision.
access_review_record_decision
writeRecord the review decision for ONE campaign item: 'keep' (access is appropriate), 'revoke' (access should be removed), or 'flag' (needs human follow-up).
| Parameter | Type | Required | Description |
|---|---|---|---|
| item_id | string (uuid) | yes | The review item's UUID (from access_review_get). |
| decision | "keep" | "revoke" | "flag" | yes | keep | revoke | flag (no 'pending'). |
| notes | string | no | Justification; REQUIRED (non-empty) for revoke and flag. |
Full tool description (what a connected agent sees)
Record the review decision for ONE campaign item: 'keep' (access is appropriate), 'revoke' (access should be removed), or 'flag' (needs human follow-up). An agent cannot set an item back to 'pending' — that would erase a reviewer's work. `notes` (≤2000 chars) is REQUIRED and must be non-empty for 'revoke' and 'flag': the justification is what makes the review defensible to an auditor. LOAD-BEARING HONESTY: 'revoke' records the review VERDICT only — it does NOT deprovision, disable, or change the account anywhere; actual removal happens in the IdP (e.g. M365 admin center) and is verified by the next directory sync. Re-recording a decision overwrites the previous one (latest reviewer wins, stamped with your user). The campaign's findings are re-projected after each decision, and the fresh campaign progress is returned so you can see how much review remains. Unknown/foreign item id → not_found. Requires the "write" scope on a user-authorized connection; demo sandbox blocked; metered by the org-day MCP write quota. Audited via:'mcp'.
Monitoring — 4 tools
monitoring_list_domains
readEvery domain your organization monitors, with the score from its latest scan.
No arguments — the organization always comes from your credential.
Full tool description (what a connected agent sees)
Every domain your organization monitors, with the score from its latest scan. MEASURED: latestScore is the overall score of the most recent scan (null when a domain has never completed one). Org-scoped; no arguments.
dmarc_summary_per_domain
readAggregate DMARC posture for ONE policy domain over a recent window.
| Parameter | Type | Required | Description |
|---|---|---|---|
| policyDomain | string | yes | The policy domain to summarize (e.g. example.com). |
| daysBack | integer (1–365) | no | Look-back window in days (default 30). |
Full tool description (what a connected agent sees)
Aggregate DMARC posture for ONE policy domain over a recent window. MEASURED and READ-ONLY: rolls up stored DMARC aggregate reports into reportCount, the report date range, the most-recently published policy (p/sp/pct), message stats (total, aligned, alignmentPct), a disposition tally for failing mail, and the top 5 source IPs by failing-message count. `policyDomain` is required; `daysBack` (default 30, max 365) bounds the window. Message-level PII (header-from / envelope addresses, raw XML) is never returned. Returns a well-formed empty summary when there are no reports for that domain in-window.
monitoring_domain_get
readFetch a single monitored domain by id, scoped to your organization, with its latest-scan SUMMARY: overall score, scan status, completion time, plus isActive and alertsEnabled.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string | yes | The monitored domain's UUID. |
Full tool description (what a connected agent sees)
Fetch a single monitored domain by id, scoped to your organization, with its latest-scan SUMMARY: overall score, scan status, completion time, plus isActive and alertsEnabled. MEASURED and READ-ONLY. The full per-check scan-results blob is omitted — only the summary is returned. Returns not_found (404) when the id doesn't exist OR belongs to another org.
monitoring_rescan_now
writeEnqueue an immediate security rescan for ONE monitored domain (by its UUID from monitoring_list_domains).
| Parameter | Type | Required | Description |
|---|---|---|---|
| monitoredDomainId | string (uuid) | yes | The monitored domain's UUID. |
Full tool description (what a connected agent sees)
Enqueue an immediate security rescan for ONE monitored domain (by its UUID from monitoring_list_domains). Same rules as the app + API rescan path, exactly: org-scoped (unknown/foreign id → not_found), a shared per-domain 10-minute cool-down ({enqueued:false, reason:'cooldown', retryAfterSeconds} — not an error), and the org-day manual-rescan quota (20/day; typed quota_exceeded with retryAfterSeconds when exhausted) layered on top of the MCP write quota. Requires the "write" scope on a user-authorized connection; demo sandbox blocked. HONESTY: this ENQUEUES the scan and returns {enqueued:true, jobId, domain} — there is NO job-status tool; poll monitoring_domain_get for this domain and watch its latest-scan completion time advance (typically 1–3 minutes). Audited via:'mcp'.
Trust — 2 tools
questionnaire_answers_suggest
readDraft candidate answers for security-questionnaire questions from your org's own material — review before sending.
| Parameter | Type | Required | Description |
|---|---|---|---|
| questions | string[] | yes | The questionnaire questions to draft answers for. |
Full tool description (what a connected agent sees)
Draft candidate answers for security-questionnaire questions from your org's own material — review before sending. For each question (1–200 per call) it returns: `bestMatch`, the closest answer from your saved vendor-answer library (same Jaccard matcher and 0.3 threshold the questionnaire upload uses; below threshold → null — a fabricated answer is never returned), with the matched library question, saved answer, evidenceRef, and a MEASURED similarity score (token overlap, not semantic understanding); and `factSuggestions`, templated answer sentences derived from LIVE collected posture facts (e.g. MFA enrollment %, DMARC coverage), each naming its factKey, source, and keyword-match confidence. A fact suggestion only appears when the org has actually collected that fact. READ-ONLY: persists nothing — these are drafts for a human to review, edit, and send.
trust_access_grant_create
writeGrant a prospect access to your trust page's gated documents (SOC 2 report, ISO cert, pen test, …): issues a unique 30-day access link for their email and (by default) emails it to them — the same flow as the in-app 'Invite' button, including its per-org daily invite quota.
| Parameter | Type | Required | Description |
|---|---|---|---|
| string | yes | Recipient email (required; the grant is per-email). | |
| name | string | no | Recipient name (optional). |
| company | string | no | Recipient company (optional). |
| message | string | no | Personal note included in the invite email (optional). |
| send_email | boolean | no | Default true — email the link to the recipient. |
Full tool description (what a connected agent sees)
Grant a prospect access to your trust page's gated documents (SOC 2 report, ISO cert, pen test, …): issues a unique 30-day access link for their email and (by default) emails it to them — the same flow as the in-app 'Invite' button, including its per-org daily invite quota. The RAW LINK IS RETURNED EXACTLY ONCE in this result (shareUrl): the token is stored hashed and cannot be recovered later — only revoked and reissued. Grants are revocable any time from the trust admin page (Posture → Trust page). If the email send fails the grant still stands (emailSent:false + emailError) and you can deliver shareUrl yourself. Set send_email:false to skip the email and just get the link. Requires an existing trust page and THE "write" SCOPE on a user-authorized connection; demo sandbox blocked; metered by the org-day MCP write quota. Audited via:'mcp'.
Vendors — 3 tools
vendors_list
readEvery third-party vendor your organization tracks, best security score first.
No arguments — the organization always comes from your credential.
Full tool description (what a connected agent sees)
Every third-party vendor your organization tracks, best security score first. MEASURED: scores (0..100) are cached from the latest runScan() pass against each vendor's primary domain; a null score means 'not scanned yet', not zero. Org-scoped; no arguments.
vendor_get
readFetch a single tracked third-party vendor by id, scoped to your organization, with its sub-scores (overall/email/web/dns) and its attestation rollup (status: none|fresh|stale, last-attested date, daysStale past the annual mark).
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string | yes | The vendor's UUID. |
Full tool description (what a connected agent sees)
Fetch a single tracked third-party vendor by id, scoped to your organization, with its sub-scores (overall/email/web/dns) and its attestation rollup (status: none|fresh|stale, last-attested date, daysStale past the annual mark). MEASURED: scores are cached from the latest runScan() pass — a null score means 'not scanned yet', not zero. READ-ONLY. The full scan-results blob, free-form notes, and raw questionnaire responses are never returned. Returns not_found (404) when the id doesn't exist OR belongs to another org.
vendor_attestation_status
readPer-vendor attestation rollup for EVERY tracked vendor: {vendorId, vendorName, primaryDomain, attestationStatus, lastAttestedAt, daysStale}.
No arguments — the organization always comes from your credential.
Full tool description (what a connected agent sees)
Per-vendor attestation rollup for EVERY tracked vendor: {vendorId, vendorName, primaryDomain, attestationStatus, lastAttestedAt, daysStale}. MEASURED and READ-ONLY from the latest completed attestation per vendor. attestationStatus is 'none' (no attestation on file), 'fresh' (within 1 year), or 'stale' (older than 1 year — auditors expect a refresh); daysStale counts days past the 1-year mark (0 unless stale). Raw questionnaire answers are never returned. Org-scoped; no arguments.
Organization — 7 tools
policies_list
readList your organization's written policies (governance documents) with optional status filter and cursor pagination.
| Parameter | Type | Required | Description |
|---|---|---|---|
| status | string | no | Exact status filter: draft|active|archived. |
| limit | integer (1–100) | no | — |
| cursor | string | no | nextCursor from a prior page. |
Full tool description (what a connected agent sees)
List your organization's written policies (governance documents) with optional status filter and cursor pagination. MEASURED and READ-ONLY: a direct, org-scoped read of the policies table. Returns metadata only — id, title, one-line description, status (draft|active|archived), version, frameworks satisfied, owner email, template slug, review-interval days, and last-reviewed/created/updated timestamps. The full policy BODY is omitted here (it can be large) — use policies_get for one policy's body. Pass `cursor` from a prior page's nextCursor to continue.
policies_get
readFetch a single policy by id, scoped to your organization, INCLUDING its full markdown body (bodyMd).
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string | yes | The policy's UUID. |
Full tool description (what a connected agent sees)
Fetch a single policy by id, scoped to your organization, INCLUDING its full markdown body (bodyMd). MEASURED and READ-ONLY. Returns not_found (404) when the id doesn't exist OR belongs to another org — the two are indistinguishable on purpose (anti-enumeration). No secrets are returned.
team_members_list
readList the members of your organization: userId, email, name, org role, joinedAt, and mfaEnrolledAt (null = MFA not enrolled).
No arguments — the organization always comes from your credential.
Full tool description (what a connected agent sees)
List the members of your organization: userId, email, name, org role, joinedAt, and mfaEnrolledAt (null = MFA not enrolled). MEASURED and READ-ONLY from memberships joined to users. SECURITY: password hashes, the MFA secret, password-lockout/attempt counters, email-deliverability forensics, and notification preferences are NEVER returned — only identity, role, join time, and the MFA-enrollment signal. Org-scoped; no arguments.
org_profile_get
readYour organization's profile: name, slug, subscription status (a coarse plan signal), onboarding completion + goals, created date, and — when filled in — industry, size band, primary jurisdiction, privacy obligations, and profile notes.
No arguments — the organization always comes from your credential.
Full tool description (what a connected agent sees)
Your organization's profile: name, slug, subscription status (a coarse plan signal), onboarding completion + goals, created date, and — when filled in — industry, size band, primary jurisdiction, privacy obligations, and profile notes. MEASURED and READ-ONLY (organizations + company_profile). SECURITY: Stripe identifiers, Slack/generic webhook URLs and their signing secret, the inbound DMARC mailbox token, and the inline logo blob are NEVER returned. No arguments; the org comes from your credential.
profile_facts_list
readAuto-collected posture facts about your organization, keyed by a dotted fact key (e.g.
No arguments — the organization always comes from your credential.
Full tool description (what a connected agent sees)
Auto-collected posture facts about your organization, keyed by a dotted fact key (e.g. idp.mfa_enrolled_pct, endpoints.encrypted_pct): {factKey, value, source, collectedAt}. MEASURED and READ-ONLY from profile_facts — `value` is the latest typed value an integration (or manual entry) reported. The internal sourceRef is omitted. Org-scoped; no arguments.
audit_log_list
readYour organization's append-only audit trail, newest first, cursor-paginated.
| Parameter | Type | Required | Description |
|---|---|---|---|
| action | string | no | Exact action filter (e.g. user.signed_in). |
| daysBack | integer (1–365) | no | Only entries newer than this many days. |
| limit | integer (1–100) | no | — |
| cursor | string | no | nextCursor from a prior page. |
Full tool description (what a connected agent sees)
Your organization's append-only audit trail, newest first, cursor-paginated. MEASURED and READ-ONLY: each entry is {id, action, target, userEmail (resolved from userId; null for system actions or a deleted user), createdAt, metadata}. The free-form metadata is SECRET-REDACTED and capped to a handful of keys, so verbose or sensitive payloads can't leak. Optional filters: `action` (exact match, e.g. 'user.signed_in') and `daysBack` (max 365). Pass `cursor` from a prior page's nextCursor to continue.
profile_fact_set
writeRECORDS one organization posture fact (e.g.
| Parameter | Type | Required | Description |
|---|---|---|---|
| factKey | string | yes | The fact key, e.g. "idp.mfa_enrolled_pct". Prefer a key already returned by profile_facts_list. |
| value | string | number | boolean | yes | The fact value (string, number, or boolean). |
| sourceRef | string | no | Optional reference for where this came from (an integration id, a document name, etc.). |
| collectedAt | string | no | Optional ISO 8601 timestamp of when the fact was observed; defaults to now. |
Full tool description (what a connected agent sees)
RECORDS one organization posture fact (e.g. "MFA enforced for all users") into the org profile. It is stored as an ATTESTATION (source "mcp"): it surfaces in the profile and can SUGGEST "partial" readiness for the CMMC controls that fact maps to (a human still confirms), but it NEVER auto-confirms a control as "met", never satisfies a live-feed freshness gate, and is excluded from insurance auto-confirm. Use it to capture a fact you actually verified from another connected source (M365, an admin console, a document). REQUIRES THE "write" SCOPE; org comes from your credential. Idempotent on factKey (latest write wins). Prefer keys already in use — call profile_facts_list first to see them (e.g. "idp.mfa_enrolled_pct"); ad-hoc keys are stored but may not surface in the UI/evidence flow.
Errors
Tool failures return an MCP error result whose text is [code] message. The codes are a closed set:
| Code | HTTP analogue | Meaning |
|---|---|---|
| unauthorized | 401 | No valid credential. The 401 carries a WWW-Authenticate header pointing at the OAuth discovery documents, which is how MCP clients find the consent flow. |
| forbidden | 403 | Valid credential, disallowed action: a read-only credential calling a write tool, a non-owner calling an owner-only tool, a demo-sandbox write, or an org without an active Pro subscription. |
| not_found | 404 | The id doesn't exist in your organization. Cross-tenant ids return the same not_found on purpose (anti-enumeration) — you can't probe whether an id exists elsewhere. |
| invalid_request | 400 | Arguments failed a tool's own validation beyond the schema — e.g. a terminal finding transition without the required justification note. |
| quota_exceeded | 429 | The per-organization daily write quota (or a tool-specific quota, like manual rescans) is exhausted. The message includes how many seconds to wait. |
| internal | 500 | An unexpected server error. Details are logged server-side and never returned — no stack traces or raw database strings cross the wire. |
Prefer plain REST? See the API docs and webhooks. Questions or a missing tool? Get in touch.