Typed Tools, Effects, Capabilities, Approvals, and Receipts
A model may suggest an action. It must never be the component that grants itself permission to perform that action.
Tool use crosses a boundary that ordinary text generation does not. A wrong answer may mislead a
reader; a wrong tool call can publish data, spend money, delete state, send a message, or change
production. JSON shape is necessary, but { "deployment": "api", "version": "v1" } being valid
does not answer:
- Is this the exact tool release that was reviewed?
- Does the current principal have this capability in this tenant?
- Is a rollback an allowed effect for this run?
- Did a human approve these exact parameters, or different ones?
- Can a retry safely repeat the operation?
- Did the effect happen when the network response was lost?
- Does the reported result match independently observable state?
The boundary in this chapter is:
untrusted model proposal │ ▼strict input schema + immutable ToolContract │ ▼grant ∩ tenant ∩ policy ∩ tool ∩ effect ∩ capabilities │ ▼exact, unexpired approval when risk requires it │ ▼authorization receipt ── denied calls stop here │ ▼isolated executor using scoped credentials │ ▼output + effect ID + before/after state + idempotency record │ ▼execution receipt ├── verified success ├── verified failure with no effect └── indeterminate ──► reconciliationThe runnable implementation is mosaic-tools::contract; its companion is
authorized_tool_receipt. The connected lab is
MP-23 · Authorized Tool Loop.
Learning objectives
Section titled “Learning objectives”By the end you will be able to:
- separate model proposal, deterministic authorization, execution, and effect verification;
- define a versioned tool contract with exact schema and executor identities;
- classify read-only, draft, external-write, and irreversible effects;
- grant capabilities rather than broad roles or access to an entire tool server;
- intersect tool, effect, capability, tenant, policy, expiry, and resource bounds;
- bind high-impact approval to exact parameters rather than a conversational summary;
- use idempotency keys without confusing duplicate suppression with transaction atomicity;
- distinguish verified success, verified no-effect failure, and indeterminate execution;
- issue independently replayable authorization and execution receipts;
- diagnose time-of-check/time-of-use, confused-deputy, stale-approval, and retry failures;
- isolate executor credentials from the model and untrusted evidence;
- design ordinary, boundary, mutation, replay, and reconciliation tests.
Prerequisites and dependency order
Section titled “Prerequisites and dependency order”Complete the run-envelope chapter first: tool authorization consumes its tenant, policy, budget, principal, and trace identities. Complete structured-output and semantic/evidence validation: arguments must be structurally valid, but retrieved text and model conclusions remain untrusted data. Complete the production chapters on authentication, tenancy, quotas, durable jobs, and idempotency because a production executor relies on those controls.
The order matters:
- define task behavior and non-goals;
- compile current identity, environment, policy, budgets, and grants;
- retrieve and validate evidence;
- let the model propose a typed call;
- authorize the exact call outside the model;
- execute through a restricted boundary;
- verify the outcome and reconcile uncertainty;
- evaluate completion from receipts and target truth.
Do not move authorization into the prompt. A system message saying “only use safe tools” expresses intent to a probabilistic component. It does not enforce access.
Completion artifact
Section titled “Completion artifact”Run:
cd rust/rust-ai-engineeringcargo test -p mosaic-tools contractcargo test -p mosaic-tools --example authorized_tool_receiptcargo run -q -p mosaic-tools --example authorized_tool_receiptPinned result:
baseline authorization authorizedbaseline execution verified_succeededmutation cases 10 / 10contract SHA-256 2ddf1a1f5c19567e5a23a64e597ab8cba52b7ad310e62b91d6d883ccc612216bgrant SHA-256 4fa44a27c40f5d4a968c3322cb919bd6398037ff0a852ac90f5be1c1f521aefeinvocation SHA-256 ef17073e7748b8a08a63298589b2dd2256b3bf0d4b7c5f7bc5d80a3197bbac9fauthorization-receipt SHA-256 d6f62f8e4c60d4f51579939cbe3a36dba682968af57ab6fc23e4739a13f0cedbexecution-receipt SHA-256 7734ebe018bd47bab7c4b588bf74ef12a505ad1cd2466a93835edba3a62fbdbbreport bytes 2,122report SHA-256 08c281cb7fdde28d181ed302c7587a491ceb478c112a1080c25dd3a1d9ed7099Fifteen focused module tests and two example tests cover strict decoding, invalid contract metadata, tool/effect/capability intersection, tenant/policy/expiry/contract drift, input bounds, idempotency, exact approvals, denied execution, executor and invocation drift, time and output bounds, complete write receipts, read-only effect claims, failed-no-effect claims, indeterminate outcomes, receipt replay, and stable mutation evidence.
The example writes:
target/labs/mp-23/2ddf1a1f5c19567e5a23a64e597ab8cba52b7ad310e62b91d6d883ccc612216b.jsonIntelligence and authority are different types
Section titled “Intelligence and authority are different types”The model is useful because it can interpret ambiguous intent and evidence. That capability does not make it an identity provider, policy engine, approval authority, transaction coordinator, or source of target-system truth.
Treat a tool call from a model as a proposal:
pub struct ToolInvocation { pub invocation_id: String, pub run_envelope_sha256: String, pub tenant_id: String, pub policy_sha256: String, pub tool_contract_sha256: String, pub input_sha256: String, pub input_bytes: usize, pub requested_at_unix_ms: u64, pub idempotency_key: Option<String>, pub approval: Option<ToolApproval>,}Every authority-bearing field must come from, or be checked against, trusted application state. The model may select a candidate tool and generate candidate arguments. It must not invent the tenant, principal grant, policy digest, approval, credential, or current time.
This is an instance of least privilege and per-request authorization. NIST’s zero-trust model emphasizes granular decisions for each resource request rather than implicit trust based on network location. An AI loop benefits from the same discipline: the fact that a model is already inside a run does not entitle it to every tool attached to the process.
Make a tool contract immutable and reviewable
Section titled “Make a tool contract immutable and reviewable”The reference contract contains:
pub struct ToolContract { pub schema_version: u32, pub contract_release: String, pub tool_name: String, pub executor_release: String, pub input_schema_sha256: String, pub output_schema_sha256: String, pub effect: ToolEffect, pub required_capabilities: Vec<ToolCapability>, pub idempotency: IdempotencyMode, pub reversible: bool, pub timeout_ms: u64, pub max_input_bytes: usize, pub max_output_bytes: usize,}The identity covers semantics, not only a display name. Two tools named execute_rollback are not
the same if their input schema, executor, effect, or required capabilities differ. Approval of the
old definition must not silently authorize a changed one.
The schema digests bind argument and result shape. The executor release binds the implementation expected to interpret those shapes. Limits make denial-of-service behavior part of the contract. The effect and idempotency fields make operational risk explicit and testable.
Use strict deserialization with unknown-field rejection. Tool definitions can change independently of application code, and descriptions themselves may contain untrusted instructions. Pin reviewed definitions, compare identities at execution time, and reject drift instead of accepting a best-effort match.
Contract identity is not authorization
Section titled “Contract identity is not authorization”A digest answers “which exact object?” It does not answer “who approved it?” Protect the object with authenticated storage, signed metadata where trust crosses systems, and access control. Receipts use digests so independent components can join exact inputs; they do not replace those components.
Classify effects before discussing permission
Section titled “Classify effects before discussing permission”The reference type is deliberately small:
pub enum ToolEffect { ReadOnly, CreatesDraft, ExternalWrite, Irreversible,}Read-only observes state without intentionally changing the target. Logging and billing may still occur, so “read-only” is about the declared business effect, not zero physical side effects. Protect sensitive reads against exfiltration and cross-tenant access.
Creates-draft writes a reversible, non-public object that still requires scope, retention, and cleanup. A draft email is safer than a sent email, but it may contain sensitive data and appear in another user’s workspace.
External-write changes durable or externally visible state. Feature flags, tickets, messages, deployments, payments, and file writes belong here even when a compensating action exists. “Reversible” means a tested compensating path exists; it does not mean reversal is free or perfect.
Irreversible includes effects whose prior state cannot be fully restored: publishing secrets, destroying encryption keys, sending money outside a recoverable ledger, or deleting the last copy. Require the strongest independent approval and prefer designs that introduce staging or delay.
Do not let the model choose the effect classification. It belongs to the reviewed contract. When
one operation can have different risk modes, define distinct tools or contracts. A single
manage_database(action: string) tool hides too much authority.
Capabilities should describe narrow powers
Section titled “Capabilities should describe narrow powers”The example rollback requires:
required_capabilities: vec![ ToolCapability::ReadDeployments, ToolCapability::ExecuteRollback,]The grant must contain every required capability, the exact tool name, and the effect class. These
checks are independent. Possessing ExecuteRollback must not authorize an unreviewed tool also
claiming that capability; an allowed tool must not silently escalate from read-only to write; a
write effect must not pass when one supporting read capability is absent.
Prefer capabilities that include resource and action scope:
deployment:read tenant=acme service=api environment=productiondeployment:rollback tenant=acme service=api max_versions=1The compact reference enum demonstrates the intersection, but production grants should bind resource selectors, environments, data classification, purpose, and conditions. Avoid wildcard server access. Do not give a tool process a cloud administrator credential merely because its public schema exposes one narrow action.
Re-evaluate the current grant per invocation
Section titled “Re-evaluate the current grant per invocation”The reference grant names:
- grant and principal identities;
- tenant and policy digest;
- allowed tool names;
- allowed effect classes;
- capabilities;
- expiry.
authorize_tool_call validates all inputs, then accumulates a stable set of violations. It checks:
- exact tool membership;
- effect membership;
- every required capability;
- tenant equality;
- policy equality;
- grant time validity;
- exact contract identity;
- input byte bound;
- idempotency mode;
- approval requirement and binding.
Do this immediately before dispatch. A plan created ten minutes ago does not preserve an expired or revoked grant. If authorization and execution are separate services, make the authorization receipt short-lived and single-purpose. The executor must verify it rather than trust a boolean from the caller.
The confused-deputy problem
Section titled “The confused-deputy problem”A privileged executor becomes a confused deputy when an unprivileged caller persuades it to use the executor’s authority for the caller’s target. Tenant and resource must therefore be derived from the authenticated request and authorized together. Never accept a tenant ID in model arguments and use it only to choose a credential.
Also scope outputs. A legitimate read tool can become an exfiltration deputy if the model can send its result to an unrelated external-write tool. Data classification and egress policy must survive the chain.
Approval must bind the action, not the conversation
Section titled “Approval must bind the action, not the conversation”For external and irreversible effects, the reference requires:
pub struct ToolApproval { pub approval_id: String, pub approver_principal_id: String, pub tenant_id: String, pub policy_sha256: String, pub tool_contract_sha256: String, pub input_sha256: String, pub effect: ToolEffect, pub expires_at_unix_ms: u64,}This prevents “I approved a rollback” from authorizing a different deployment, tenant, version, or tool release. Present the human with canonical, understandable parameters and effect preview. Hash the same canonical bytes that the executor will consume. If parameters change after approval, request a new approval.
The approver should be distinct from the proposing model and, for high risk, distinct from the requesting principal. Protect the approval store and audit its issuance. A model should reference an approval ID only after the application has retrieved and verified the object.
Approval is not a substitute for authorization. A manager may approve a rollback, but the current principal still needs the correct tenant/tool/effect/capability grant. Conversely, a broad grant does not remove the need for risk-based approval.
Prevent approval fatigue
Section titled “Prevent approval fatigue”If every harmless read produces a modal dialog, users learn to approve blindly. Classify actions and reserve human interruption for meaningful risk. Offer safe previews, staged drafts, bounded undo windows, and policy-approved automation for routine cases. Monitor unusual approval rates and repeated bypass attempts.
Idempotency is a logical-operation contract
Section titled “Idempotency is a logical-operation contract”An idempotency key identifies one intended operation across retries. The reference requires it for external and irreversible effects and verifies that the executor reports the same key.
The durable executor pattern is:
begin transaction look up (tenant, tool, idempotency_key) if completed with same input: return stored outcome if same key has different input: reject conflict if in progress: return status or coordinate one owner otherwise: create pending operation with input digestcommit
perform or enqueue effect through a fenced ownerrecord effect ID and observed statepublish stable terminal resultThe key must be scoped by tenant and operation family. Store the input digest so reuse with different parameters fails. Retain records for at least the maximum retry and reconciliation window.
Idempotency is not the same as atomicity. A process may change a remote system and crash before
recording success. The next caller then sees a pending or unknown operation. That is why the
outcome model needs Indeterminate.
HTTP defines idempotence in terms of the intended effect of repeated requests and explains why it enables automatic retry after a lost response. Application-level POST-style tool calls require an explicit equivalent contract; a random request ID that changes on every attempt does not provide it.
Authorization and execution need separate receipts
Section titled “Authorization and execution need separate receipts”The authorization receipt binds:
contract identitygrant identityinvocation identityauthorized or stable denial violationsThe execution receipt binds:
contract identityauthorization-receipt identityexecution-observation identityverified status or stable rejection violationsThis separation answers different questions:
- authorization: was dispatch permitted under the exact current inputs?
- execution verification: does the observed outcome satisfy the contract?
Never infer the second from the first. Never infer the first from a successful executor response. A misconfigured service might perform an unauthorized action; record it as a security incident, not a valid call.
The reference verifies stored receipts by recomputing them from original inputs. In a distributed system, add issuer identity, signature, issued time, nonce or sequence, key release, and retention policy. Keep secrets and raw sensitive payloads out of general logs; record content identities and authorized, access-controlled evidence locations.
Verify the effect, not only the response
Section titled “Verify the effect, not only the response”A successful external write requires:
- expected executor release;
- exact invocation identity;
- completion at or after request time;
- bounded non-empty output;
- an effect ID;
- before-state identity;
- after-state identity;
- the same idempotency key.
The effect ID should come from a durable target or operation ledger. Before/after state should be observed at a meaningful consistency level. For a deployment rollback, a command returning 200 is not enough: verify the target revision or rollout generation and, where behavior requires it, readiness and health.
For read-only calls, effect-shaped metadata is suspicious. For FailedNoEffect, an effect ID or
after-state claim is contradictory. The reference rejects both. Negative claims require evidence:
if the executor cannot prove no effect, use Indeterminate.
Reversibility needs its own proof
Section titled “Reversibility needs its own proof”reversible: true states a contract property; it does not prove a rollback will work now. Record
the compensating tool contract, required preconditions, tested recovery time, data-loss boundary,
and last exercise. Before a high-risk write, capture enough state for the compensating action
without exposing secrets.
Indeterminate is an honest terminal observation
Section titled “Indeterminate is an honest terminal observation”Consider:
- the executor sends a rollback to the deployment system;
- the target applies it;
- the connection closes before the executor receives the response.
The client observed failure. The target observed success. Retrying blindly may apply another
transition. Calling it FailedNoEffect is false.
The reference verifies an indeterminate observation and sets reconciliation_required: true.
Production reconciliation should:
- stop automatic retries that could repeat the effect;
- query the idempotency operation and target by stable identities;
- compare the target generation and relevant state with expected before/after states;
- classify verified success, verified no effect, or still indeterminate;
- publish a new reconciliation receipt linked to the original;
- escalate when the uncertainty deadline or risk threshold is exceeded.
Assign a reconciliation owner and deadline in the tool contract or policy. “Someone should check” is not an operational state.
Time-of-check/time-of-use failures
Section titled “Time-of-check/time-of-use failures”Authorization can be correct at time A and unsafe at execution time B:
- approval or grant expires;
- resource ownership changes;
- deployment advances to a newer generation;
- policy is revoked;
- target state no longer matches the preview;
- executor release changes;
- a feature flag is already modified by another actor.
Use optimistic preconditions such as resource version, ETag, database row version, or deployment generation inside the exact input. Check them atomically with the effect when possible. Otherwise, re-authorize or fail closed after meaningful delay. Do not let the executor reinterpret stale “latest” selectors.
Bind approvals to concrete targets: rollback deployment-42 from generation 8 to generation 7,
not rollback deployment-42 to previous. The latter changes meaning as state advances.
Tool schemas and descriptions are untrusted inputs
Section titled “Tool schemas and descriptions are untrusted inputs”Tool discovery protocols expose names, descriptions, annotations, and schemas to a model and client. A malicious or compromised server may:
- shadow a trusted tool name;
- place instructions in a description;
- change a schema after review;
- understate an effect;
- request secrets through an innocent-looking parameter;
- return content that instructs the model to call another tool;
- register a broad tool behind a narrow label.
Treat discovery metadata as supply-chain input. Maintain an allowlist, pin exact definitions, compare them with locally reviewed contracts, isolate servers, scope credentials per server and tool, validate every input/output at your boundary, and monitor definition drift. Protocol annotations can improve presentation, but they are not authority unless authenticated and trusted.
Isolate the executor
Section titled “Isolate the executor”The policy engine should not hand raw credentials to the model loop. The executor should receive a verified invocation and use a credential whose real permissions are no broader than necessary.
Useful isolation layers include:
- a separate process or service per risk domain;
- restricted filesystem and network access;
- per-tenant or exchangeable short-lived credentials;
- destination and method allowlists;
- bounded CPU, memory, output, duration, concurrency, retry, and chain depth;
- no inherited developer shell environment;
- secret redaction and controlled observability;
- durable idempotency and effect ledgers;
- a kill switch and draining behavior.
Arbitrary shell execution is not a general-purpose tool contract. If a product truly needs code execution, use an ephemeral sandbox with no ambient credentials, a mounted input manifest, resource limits, egress policy, output collection, and destruction receipt.
Rust implementation choices
Section titled “Rust implementation choices”The reference uses strict Serde types, enums for closed policy states, checked bounds, ordered sets,
and SHA-256 over stable JSON. Violations are accumulated in a BTreeSet, making denial order
deterministic. Invalid transport objects return ToolContractError; valid but unauthorized calls
produce a typed denial receipt.
Keep these categories separate:
malformed input -> cannot evaluatewell-formed denial -> evaluated and unauthorizedexecutor rejection -> authorized but observation violates contractverified no effect -> authorized execution failed, proven no effectindeterminate -> authorized execution outcome requires reconciliationverified success -> authorized and effect evidence satisfies contractDo not collapse them into one anyhow!("tool failed"). Callers need different retry, alert,
completion, and user-notification behavior.
For larger capability sets, compile grants into indexed representations but retain a canonical sorted form for identity. Use newtypes for tenant, policy, contract, operation, and digest IDs in a full implementation; the compact reference uses validated strings to keep the chapter focused.
Failure investigations
Section titled “Failure investigations”A denied tool reached the target
Section titled “A denied tool reached the target”Inspect dispatch code, executor authentication, authorization-receipt verification, tool-name
resolution, and alternate call paths. Search for a boolean approved field accepted from the
model. Contain by disabling the credential and target route. Add an integration test proving the
executor refuses missing, denied, expired, mutated, and wrong-audience receipts.
Approval existed, but parameters changed
Section titled “Approval existed, but parameters changed”Compare canonical input bytes and digests at preview, approval, invocation, and executor. Look for default insertion, key-order changes, “latest” resolution, Unicode normalization, unit conversion, or post-approval repair by the model. Approve the canonical executable object, not rendered prose.
A timeout caused a duplicate write
Section titled “A timeout caused a duplicate write”Trace the tenant/tool/idempotency tuple, input digest, operation records, transport attempts, target effect IDs, and generations. Determine whether the key changed or whether storage was written only after the remote effect. Repair the durable state machine and reconcile existing targets before re-enabling retries.
The receipt says success but state is wrong
Section titled “The receipt says success but state is wrong”Check who supplied before/after identities, what consistency level was read, whether an asynchronous rollout was mistaken for completion, and whether the target changed after observation. Add an independent postcondition and link its snapshot or generation.
A read tool leaked data through a write tool
Section titled “A read tool leaked data through a write tool”Follow classification and tenant labels across every intermediate object. Authorization of each call alone is insufficient when the chain violates information-flow policy. Add egress constraints, redaction, destination binding, and an adversarial cross-tool test.
Tool behavior changed without a code release
Section titled “Tool behavior changed without a code release”Compare discovery snapshot, schema, description, executor image, server certificate, dependency lock, and contract digest. Quarantine the changed tool. Do not update the pin automatically merely because the server reports a new definition.
Security and performance
Section titled “Security and performance”Measure security decisions as product behavior:
- denials by tool, effect, capability, tenant, policy, approval, and contract drift;
- approval request, rejection, expiry, and bypass-attempt rates;
- idempotency replays and conflicts;
- indeterminate outcomes, reconciliation latency, and unresolved age;
- unauthorized effects detected after execution;
- tool-definition drift and executor-release mismatch;
- cross-tenant attempts and unusual data egress;
- chain depth, retries, duration, bytes, cost, and concurrency.
For latency, separate deterministic local authorization from identity lookup, grant retrieval, approval retrieval, executor queue, target operation, postcondition observation, and receipt persistence. Authorization arithmetic should usually be tiny compared with remote work. Do not remove exact checks to optimize a path dominated by network latency.
Bound all collections and byte sizes before allocation. Avoid logging raw arguments by default. Cache immutable contracts by identity; cache grants only within their expiry/revocation model. Never cache a positive authorization without tenant, principal, policy, contract, input, effect, approval, and time conditions.
Alternatives and trade-offs
Section titled “Alternatives and trade-offs”- One broad agent credential: simple to prototype, unacceptable blast radius and weak attribution.
- Role-based authorization only: useful administration layer, often too coarse for per-tool, per-resource, per-effect decisions.
- Capability tokens: narrow and composable, require careful audience, delegation, expiry, and replay design.
- Human approval for every call: visible but slow and vulnerable to fatigue; classify risk.
- Plan approval: efficient for a stable batch, unsafe when later steps or parameters can change; bind each effect or a constrained signed plan.
- Transactional outbox: excellent when local database state and queued effects share one transaction; remote completion still needs idempotency and reconciliation.
- Saga compensation: useful for multi-step reversible workflows, not equivalent to atomicity and unsuitable for truly irreversible effects.
- Policy-as-code service: centralizes decisions and audit, but executor enforcement and exact input identity remain necessary.
Connected mini-project
Section titled “Connected mini-project”MP-23 · Authorized Tool Loop asks you to extend, attack, measure, and defend the reference rollback boundary. The supplied ten mutations cover tool and capability denial, tenant and contract drift, missing idempotency and approval, stale approval parameters, incomplete effects, retry-key drift, and indeterminate execution.
The lab deliberately uses a deterministic local observation. Its lesson is the control plane around any executor—HTTP API, database, shell sandbox, media pipeline, browser, robot, or payment service.
Exercises
Section titled “Exercises”Recall
Section titled “Recall”- Why is a model tool call a proposal rather than authorization?
- What changes when a read-only tool becomes an external write?
- Why check tool, effect, and capability independently?
- What must an approval bind?
- Why does a timeout not prove no effect?
- What does an idempotency key fail to guarantee?
- Why are authorization and execution receipts separate?
- How can a read tool participate in data exfiltration?
Implementation
Section titled “Implementation”- Add resource selectors to
ToolGrantand prove cross-resource denial. - Bind an authorization receipt to an executor audience and maximum dispatch time.
- Add a signed approval envelope with key rotation and replay tests.
- Implement a durable idempotency state machine with pending, succeeded, no-effect, and unknown states.
- Add compare-and-swap target generation to the rollback input.
- Add a reconciliation receipt that resolves an indeterminate observation.
- Implement read-only output classification and an egress policy for a message-sending tool.
- Add contract-discovery snapshot comparison and quarantine on drift.
- Use property tests to prove denial is monotonic when capabilities are removed.
- Add a sandboxed code-execution contract with explicit mounts, egress, and resource ceilings.
Failure laboratory
Section titled “Failure laboratory”Mutate schema version, executor release, tool name, effect, capability, tenant, policy, grant expiry, contract digest, input size, idempotency key, approval tenant/policy/contract/input/effect/expiry, authorization decision, observation invocation, completion time, output size, effect ID, before/after state, and receipt bytes. Predict malformed, denied, rejected, verified, or reconciliation-required before running each case.
Design
Section titled “Design”Design a multimodal publishing tool that converts an approved image/video generation into a public campaign. Separate rights and consent validation, content-policy decision, asset digest, target account, caption and destination, budget, draft creation, human preview, final publish approval, idempotent upload, public URL observation, deletion/rollback capability, and receipts. Explain which stages can be retried and which can become indeterminate.
Solution guidance
Section titled “Solution guidance”For resource-scoped capabilities, intersect structured predicates; do not concatenate strings and perform prefix checks. Include normalized resource identity in the grant, invocation, approval, and target precondition.
For durable idempotency, insert the operation record before contacting the target and enforce a
unique key on (tenant, tool_contract, idempotency_key). Same key and same input returns the
existing operation; same key and different input is a conflict. A pending record after a crash
routes to reconciliation, not immediate repetition.
For monotonic denial, generate valid grants, remove one allowed dimension, and assert that an unauthorized result never becomes authorized. Adding capability alone should not bypass tool, effect, tenant, policy, approval, or time checks.
For publishing, use distinct draft and publish contracts. Approval of a draft must not authorize publication. Bind the final approval to exact asset bytes, caption, account, audience, spend, and destination.
Check your understanding
Section titled “Check your understanding”- Which component supplies trusted tenant and policy identity?
- What exact fields change a tool contract’s meaning?
- Who classifies the effect?
- Can an allowed capability authorize an unlisted tool?
- Can a human approval replace the principal grant?
- What prevents post-approval argument repair?
- What key scopes one logical retryable operation?
- When may an executor claim
FailedNoEffect? - What evidence is required for a successful write?
- Who owns an indeterminate outcome?
- Which precondition prevents stale “previous version” resolution?
- Why are tool descriptions a supply-chain input?
- What must the executor verify independently?
- Which data may be safe to digest but unsafe to log?
- What metrics reveal approval or retry control failure?
Completion checklist
Section titled “Completion checklist”- Tool calls are treated as untrusted proposals.
- Contracts bind schema, executor, effect, capabilities, bounds, and retry semantics.
- Unknown fields and unsupported releases fail closed.
- Effect classification is reviewed outside the model.
- Grants are principal-, tenant-, policy-, tool-, effect-, capability-, and time-scoped.
- Resource scope and data classification are added in production.
- High-impact approvals bind exact canonical parameters and expire.
- The executor cannot access model-selected ambient credentials.
- External/irreversible effects use durable, input-bound idempotency.
- Authorization occurs immediately before dispatch and is independently enforced.
- Successful writes include effect and before/after evidence.
- Verified failure, verified success, and indeterminate remain distinct.
- Reconciliation has an owner, deadline, target query, and linked receipt.
- Target generations or equivalent preconditions prevent stale execution.
- Contracts, grants, invocations, approvals, observations, and receipts are replayable.
- Tool discovery and definition drift are pinned and monitored.
- Cross-tool information flow and confused deputies are tested.
- Ordinary, boundary, mutation, replay, security, timeout, and recovery tests pass.
- Authorization, executor, reconciliation, approval, retry, cost, and security metrics exist.
- MP-23’s build–break–measure–defend evidence is complete.
Authoritative references
Section titled “Authoritative references”- NIST, SP 800-207: Zero Trust Architecture
- IETF, RFC 9110 §9.2.2: Idempotent Methods
- OWASP, AI Agent Security Cheat Sheet
- OWASP, MCP Security Cheat Sheet
- OWASP, Authorization Cheat Sheet
- Model Context Protocol, Tools specification
mosaic-tools::contract,authorized_tool_receipt, and MP-23 · Authorized Tool Loop