WebMCP

WebMCP gives the agent capabilities. LoadGuard decides what can change.

The page registers a small capability surface through document.modelContext. The agent gets structured planning tools, but approval authority remains outside WebMCP and is enforced server-side.

Connected contract

7 tools

No approval tool is registered. The human approval control lives in the LoadGuard UI and records the exact staged proposal hash.

Consequence tiers

The tool surface is deliberately narrow

Read only

Inspect current state, constraints, and audit events without changing proposals or active load.

  • get_load_state
  • get_package_constraints
  • get_action_ledger

Candidate state

Create, validate, and stage proposal snapshots that remain separate from active truck state.

  • create_load_plan
  • validate_load_plan
  • stage_load_plan

Operational

Request execution of an already approved proposal. The database still decides whether it is allowed.

  • commit_load_plan

Tool inventory

Exactly seven tools are exposed

ToolPurposeConsequence
get_load_stateInspect truck stateREAD ONLY
get_package_constraintsInspect package constraintsREAD ONLY
create_load_planBuild candidate planCANDIDATE
validate_load_planValidate candidateCANDIDATE
stage_load_planStage immutable proposalCANDIDATE
commit_load_planApply approved proposalOPERATIONAL
get_action_ledgerInspect audit eventsREAD ONLY

Contract

The tool submits intent. Authority evaluates it.

Commit accepts

commit_load_plan({
  "proposal_id": "PLAN_PROPOSAL_UUID"
})

Commit does not accept

commit_load_plan({
  "coordinates": "...",
  "approval": true,
  "force": true
})

Approve proposal and reject proposal are not WebMCP capabilities.

This asymmetry is deliberate. The agent can ask for execution, but the application and database verify whether the operator already authorized that exact staged plan.

Expected responses

The boundary is observable

Before approval

{
  "ok": false,
  "code": "APPROVAL_REQUIRED",
  "status": "STAGED"
}

After approval

{
  "ok": true,
  "status": "EXECUTED",
  "state_revision": 2
}

Replay

{
  "ok": false,
  "code": "ALREADY_EXECUTED",
  "status": "EXECUTED"
}