This is the second part of the MCP server guide. Part 1 — issuing an agent token, scopes, delegation, and connecting each client — is here: https://help.auditbadger.com/hc/auditbadger-help-center/articles/1775898378-mcp-server-connect-ai-assistants-to-humadroid Part 3 — attaching files, rate and workload limits, error codes, and lifecycle notifications — is here: https://help.auditbadger.com/hc/auditbadger-help-center/articles/1790025903-mcp-server-files-limits-and-errors
The tools
The server lists 21 tools. That is deliberately small: a long tool list crowds out a model's attention, and some clients silently drop the tail of one. Most of what the server can do is not a tool of its own — 68 reads and 59 proposal operations sit behind two gateways, read and propose, which take the thing you want by key. The assistant fetches the schema for one key on request.
You never need to memorise any of this. The assistant discovers it, and the server's instructions tell it how the pieces fit together. Here is the shape.
Reads (68)
Thirteen have a tool of their own, the ones nearly every session needs: whoami, describe_operations, describe_reads, list_available_operations, operation_companion, list_projects / get_project, list_controls / get_control, list_documents / get_document, and list_change_sets / get_change_set.
Every other read runs through read, which takes the read's key and that read's own input:
{"key": "list_risks", "input": {"limit": 50}}
A key is not a tool. list_risks, list_vendors, list_risk_scoring_methods, and every other name in the catalogue below that is not one of the thirteen above exists only as a key for read. Calling one as a tool of its own never reaches AuditBadger's validation: the client shows its generic unknown-tool error — in most clients MCP error -32602: Invalid params, with Tool not found: <name> in the error's data, which some clients hide. That message is not a schema problem and no arguments fix it. The schema describe_reads returns for a key is the shape of read's input, not of a tool named after the key.
describe_reads returns the version, description, input schema, and output schema for up to ten keys in one call. An assistant calls it before a key's first use, and again if a read call comes back invalid_request — that refusal names the field that broke the rule.
Every read returns current state plus an observed version for each resource. Two reads legitimately return different observed versions for the same record: each fingerprints its own projection, answering "has what this read shows changed?", not "has the row changed?". Only the versions returned by the operation companion (the operation_companion tool, or the operation's paired read) are valid in a proposal — every read envelope says so in capability.operation_companion_required_for_mutation. Hand those back when proposing, and if the record moved in between, the proposal is refused as stale instead of overwriting someone's work.
The catalogue, by key — the thirteen listed tools are in it too, and every other name is called through read:
-
Orientation:
whoami,list_available_operations,describe_operations,describe_reads,operation_companion,get_project_posture -
Projects and controls:
list_projects/get_project(both report the framework and the setup facts;get_projectwithinclude: ["onboarding_questions"]adds the wizard questions and the answers that give the project its context, andinclude: ["posture"]embeds the posture aggregate),list_sections/get_section,list_controls/get_control(controls report their notes and whether notes and status are directly editable, so a register audit is one list call) -
Audit readiness:
get_audit_readiness(the verdict, the per-domain status, and what must close first),list_audit_readiness_gaps -
Evidence:
list_evidence/get_evidence,list_collection_sources/get_collection_source -
Documents:
list_documents/get_document,list_document_assignments -
Risks:
list_risks/get_risk,get_risk_assessment_context,list_treatment_actions/get_treatment_action -
Checks:
list_checks/get_check,list_check_acceptances/get_check_acceptance -
Vendors:
list_vendors/get_vendor(each vendor also reports its vendor type, the answers to that type's questions, its evidence checklist, any open "needs review" flags and the risks the type suggested),list_assurance_reviews/get_assurance_review -
Business continuity:
list_business_continuity_processes/get_business_continuity_process, and the same pair forplansandexercises -
Assets:
list_physical_assets/get_physical_asset, the same fordigitalandinfrastructure, pluslist_asset_relationshipsandlist_asset_reference_data -
ISMS workbook:
get_isms_workbook,list_workbook_requirements/get_workbook_requirement,list_security_objectives/get_security_objective,list_management_reviews/get_management_review, andlist_management_review_input_candidates -
People:
list_people/get_person,list_employment_types/get_employment_type -
Reference vocabularies:
list_data_classification_levels(documents access),list_risk_scoring_methods/get_risk_scoring_method(risks access) -
Pipeline:
list_users,list_change_sets/get_change_set,list_staged_uploads/get_staged_upload
A readiness check is proposed, not run: an assistant that sees stale proposes readiness.run_create and you approve it. One check per project per day: a second proposal that day answers with the run you already have.
vendor.update can give a vendor its type (vendor_type_key, or "" to remove it). Answering that type's questions is part of recording a review: vendor.record_assurance_review carries the answers (vendor_type_facts, a list of {key, value}) and decides each piece of evidence the type expects (checklist_decisions, a list of {requirement_key, state, note} where the state is auto, upload or not_applicable, and not_applicable needs the note that explains it). The review keeps what it was recorded with, and get_assurance_review returns that snapshot. Read the vendor first: the questions and requirement keys are your account's own vendor type, and anything else is refused with the valid keys named.
document.mark_reviewed records that a published policy was re-read and still stands: it moves the next review date instead of republishing an unchanged copy. It only ever records "no changes" — if the policy needs rewriting, the assistant proposes document.create_version. Give it a next_review_date when the document has no review cadence of its own.
Control reads report whether in-app AI implementation notes still await a person's approval, without returning the private notes. ISMS requirement reads report the same pending/approved state for AI-prefilled narratives; the requirement's ordinary reviewed state identifies the approving person and time. A manual edit after approval makes the text human-authored again.
Proposing a change (59 operations)
propose turns one registered operation into a one-item change set for review. It takes:
-
operation_key— which operation:control.create,risk.assess,document.publish,evidence.create, and so on.describe_operationswith that key returns the schema forparams, andlist_available_operationssays which of them this token may propose against a given record. -
idempotency_key— reuse it to replay a submission safely rather than to make a second one -
title— names the proposal, not the record -
rationale— optional: what the assistant concluded and why -
params— the operation's own fields -
observed_versions— the versionsoperation_companionreturned for the record about to change -
source_refs— where the information came from,[]for internal-only work -
compliance_project_id— required for a project-scoped operation and refused for an account-scoped one;describe_operationsreports which each is
{
"operation_key": "control.update_implementation_notes",
"idempotency_key": "b2e1…",
"title": "Refresh access-control notes after policy review",
"params": {"control_id": "…", "implementation_notes": "…"},
"observed_versions": {"…": "…"},
"source_refs": [],
"compliance_project_id": "…"
}
43 of the 59 operations are bulk-safe: reversible bookkeeping a reviewer can approve together. The other 16 need explicit judgment and must be decided one at a time, because they are the moments where a person is asserting something to an auditor, or handing somebody authority over somebody else:
-
risk.assess,risk.update_treatment,risk.create_treatment_action -
control.update_implementation -
document.publish,document.mark_reviewed -
evidence.submit -
vendor.record_assurance_review -
check_acceptance.create -
asset.unlink_infrastructure -
isms.requirement.mark_reviewed -
isms.security_objective.create,isms.security_objective.update,isms.security_objective.record_review -
isms.management_review.complete -
people.person.set_manager
Two of those go further. document.publish and isms.management_review.complete are the only operations that reach an action the server otherwise refuses outright, so neither is ever eligible for the per-token delegation described in part 1: a signed-in person confirms the item, whatever the token is allowed to approve.
Lifecycle tools (3)
-
submit_change_set— propose several related changes as one set, with dependencies between items where one needs another to land first -
cancel_change_set— withdraw a proposal the assistant no longer stands behind -
approve_change_set— only usable when you have enabled the per-token delegation described in part 1
Upload tools (2)
request_upload_url and complete_staged_upload. See Attaching files in part 3.
Feedback (1)
send_feedback — the one tool that acts immediately. It emails product feedback — a bug, a missing capability, a place the assistant got stuck — to the AuditBadger team. It needs no scope, goes through no review, and changes nothing in your account.
What changed on 2026-09-19
Until that date the server listed 138 tools: one per read, one per operation named after it (risk_assess, control_create, and so on), and six aliases carried over from the retired /mcp endpoint (create_vendor, update_vendor, update_control, update_control_implementation, update_document_content, record_vendor_assurance_review). All of those are gone, and nothing the server can do went with them: the same 68 reads and the same 59 operations are there, reached by key through read and propose.
Assistants pick this up by themselves, because a client reads the tool list again in every session. Only a saved prompt that names a removed tool needs your attention, and the fix is to name the operation instead of the tool:
-
control_createbecomesproposewithoperation_key: "control.create". Every focused tool was named after its operation with the dots turned into underscores, so the key is recoverable from the old name;whoamialso lists every operation the token may propose. -
create_vendorisvendor.create,update_vendorisvendor.update,update_controliscontrol.update_metadata,update_document_contentisdocument.update_content, andrecord_vendor_assurance_reviewisvendor.record_assurance_review. -
update_control_implementationwas always two things: notes arecontrol.update_implementation_notes, status iscontrol.update_implementation, and the status one is a judgment call decided on its own. -
A read without a tool is
readwith its key:{"key": "list_risks"}.list_evidencesis the one old name with a shim — calling it answers with its replacement (readwithkey: "list_evidence") rather than a bare error.
Any other removed name produces the client's ordinary "unknown tool" message — MCP error -32602: Invalid params in most clients — and an assistant that sees one finds propose and read in the list it has just read. An older copy of this guide, or a client that cached the old tool list, can still name a read as a tool; the name is the key, and read is the tool.
A worked example
Suppose you ask an assistant: "Our access-control policy has been in draft since the review. Check whether the control it covers is still marked unimplemented, and fix the notes."
1. It reads.
list_documents finds the policy. get_control returns the control and its implementation notes. Then, because it intends to propose, the assistant calls operation_companion for control.update_implementation_notes on that control — the companion's observed_versions are the ones a proposal must carry.
2. It proposes.
propose with operation_key: "control.update_implementation_notes" and:
-
idempotency_key: a fresh UUID -
title: "Refresh access-control notes after policy review" -
rationale: what it concluded and why -
params: the new notes -
observed_versions: the versions the operation companion returned -
source_refs: a reference to the policy document it read -
compliance_project_id: the project
The receipt comes back with a change_set_id, state proposed, and a review_path. Nothing has changed yet.
Note what it did not do: implementation status is control.update_implementation, an explicit-judgment operation. An assistant that decides a control is implemented is asserting a compliance fact, so that comes to you as its own decision even inside a bigger set.
3. You review.
The change set appears in your review queue, and you get a notification. The item shows the before and after, the assistant's rationale, and the source it cites. You approve it, reject it with a note, or leave it — proposals expire on their own within 14 days by default.
4. It polls.
get_change_set returns the state and, per item, an outcome code and a next_action telling the assistant what to do: await_review (nothing to do yet), await_apply (decided, queued), none (done, or permanently refused), repropose (read again and try once more — this is what a stale version gets), or retry.
A set ends in applied, partially_applied, rejected, failed, cancelled, or expired. Per item, the application state is applied or one of failed_precondition, failed_validation, failed_infrastructure, skipped_dependency_rejected, skipped_dependency_failed.
5. The audit log records it.
Account Settings, Security, Audit Logs. The entry carries the agent channel, the token, the change set, and you as the approver.
A second example: onboarding a new employment type
"We are taking on contractors. Create a contractor employment type, require the handbook of it, and move Ada onto it."
read with key: "list_employment_types" shows the type does not exist, and list_documents — a listed tool — finds the published handbook. Then three proposals, in order: people.employment_type.create with the name, people.employment_type.link_documents naming the handbook, and people.person.set_employment_type naming Ada and the new type. There is no compliance_project_id — these are account-scoped.
Approving the third one does what the settings screen does: Ada is asked to acknowledge every document her new employment type requires, and to sign every contract it carries, inside the same operation. The receipt tells you how many assignments that created. Withdrawing a requirement later, with people.employment_type.unlink_documents, does not take those obligations back — the operation says so in describe_operations, because cancelling what somebody already owes is a separate decision a person makes on the web.
The assistant cannot invite Ada, change her role or email, set her joining or leaving date, deactivate her, or acknowledge a document on her behalf. Those are not operations at all — there is no key to propose them with.