<!-- Canonical: https://lucioduran.com/blog/agent-tool-execution-authorization-idempotency-reconciliation
Language: en
Content-SHA256: 822432e299ce2e8a3dd2008efdbf57e10e5dcc76c149b432c5797b4c82394b29
-->

Agentic AI

# Agents that write to production: authorization, idempotency, and reconciliation

2026-10-147 min read

Lucio Durán
Engineering Manager & AI Solutions Architect

Also available in: [Español](<https://lucioduran.com/es/blog/agent-tool-execution-authorization-idempotency-reconciliation>)

## The timeout did not read your system prompt

An agent proposes updating a record. The API applies the change, and the connection breaks before returning a response. The agent sees an error and tries again. The dashboard shows two successful calls. The business receives two effects.

The probabilistic component selected an action. The deterministic component failed to execute it correctly. Switching models may produce a more elegant explanation of the same incident.

**A write tool needs an execution protocol that survives retries, concurrency, and lost responses.** Here I propose one for an agent modifying operational configuration. The examples are illustrative designs, with no production results attributed to them.

## Separate proposal, authorization, and execution

The model produces a proposal. A control service normalizes it, binds it to the authenticated identity, and decides whether it is allowed. An executor applies one specific operation and records the outcome.

```text
user request
  -> model proposal
  -> validation and policy
  -> immutable authorized action
  -> executor
  -> receipt or reconciliation
```

Tool descriptions guide the model. Policy is enforced in code at the boundary where the effect occurs. “Use only when appropriate” in a prompt is not a particularly auditable access control.

Each delegation receives the intersection of user, service, and task permissions. A subagent may have less authority than its parent. Creating a child grants no additional authority.

## MCP covers part of the contract

The [July 2026 MCP authorization specification](<https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization>) defines authorization for HTTP transports and resource-bound tokens. Its [security guidance](<https://modelcontextprotocol.io/docs/2026-07-28/tutorials/security/security_best_practices>) prohibits token passthrough and describes confused deputy risks.

Above that layer, the application still has a domain question to answer: may this user change this attribute of this resource under these conditions? A valid server token does not automatically answer all of that.

For example, ` inventory.write ` could allow editing stock at one warehouse without granting access to another tenant or permitting arbitrary adjustment sizes. Policy may also require review for particular operations. The service owns those limits, independently of the explanation attached to the tool call.

## Authorize exactly what will execute

The service turns the proposal into an immutable record. This JSON shows conceptual fields; the identifiers are fictional:

```json
{
  "operationId": "op_example_01",
  "principalId": "user_example",
  "tenantId": "tenant_example",
  "tool": "inventory.set_available",
  "resource": "warehouse_example/item_example",
  "arguments": { "available": 18 },
  "expectedVersion": 42,
  "policyVersion": "inventory-policy-v3",
  "authorizationId": "authz_example_01",
  "expiresAt": "2026-10-14T18:05:00Z"
}
```

The server generates ` operationId ` and obtains identity and tenant from the authenticated session. A canonical representation of the action can produce a digest binding authorization to the tool, resource, arguments, and preconditions. A hash alone does not prove who authorized anything: the record belongs in trusted storage or must travel with verifiable authenticity.

When policy requires human approval, the interface shows the concrete change and its scope. Approving “fix the problem” does not authorize whatever write the model later finds convenient.

The executor checks expiry and revocation before applying a pending operation. Changing arguments invalidates the coverage of the old authorization. A relevant policy change triggers reevaluation. A confirmed receipt remains available even after the permission that enabled the action expires.

## Close the gap between reading and writing

In this example, the agent read inventory version 42. Another operation creates version 43 before execution. Applying the original proposal without its precondition can overwrite information the agent never saw.

Storage must compare and modify atomically. In HTTP, [` If-Match `](<https://www.rfc-editor.org/rfc/rfc9110.html#section-13.1.1>) can condition a write on a strong ETag. A false precondition prevents the change; the server may respond with ` 412 `.

In a custom implementation, I would use an update conditioned on tenant, identifier, and version, within the transaction that records the operation's result. If no row matches, the action needs a fresh read and decision. Checking the version with a ` GET ` and following it with an unconditional ` PUT ` leaves the race open.

A version rejection is not an invitation to replace ` 42 ` with ` 43 ` and continue. The action's meaning may have changed. Automation needs an explicit conflict-resolution rule or must return the decision to the user.

## A state machine that admits uncertainty

I propose these states for the operation record:

| State | What we know | Permitted next step |
| --- | --- | --- |
| ` proposed ` | Candidate arguments exist | Validate and authorize |
| ` authorized ` | The exact action is permitted | Claim execution before expiry |
| ` executing ` | An executor started the attempt | Await a receipt or investigate |
| ` succeeded ` | Confirmation of the effect exists | Return the existing receipt |
| ` rejected ` | The operation was denied before the effect | Report the reason |
| ` unknown ` | The effect may have occurred | Reconcile before deciding |

A timeout, broken connection, or dead process may produce ` unknown `. Labeling everything ` failed ` makes retry policy dangerous. “I received no confirmation” contains less information than “it did not happen.” The database should understand that distinction too.

The key ` (tenantId, operationId) ` identifies an authorized intent. The ledger prevents simultaneous claims and retains the receipt. The model does not mint a new identity whenever it receives the same error.

## The boundary of the local transaction

The [Amazon Builders' Library](<https://aws.amazon.com/builders-library/making-retries-safe-with-idempotent-APIs/>) describes APIs with reusable request identifiers and rejection when the same identity arrives with different parameters. The applicable lesson is preserving intent across retries.

For a write to your own database, deduplication and mutation can share a transaction. With an external API, your local ledger does not control the remote commit. This is the part diagrams tend to hide underneath an arrow.

An outbox can atomically store delivery intent alongside local state. Delivery can still repeat. The receiver needs idempotency support or an operation that is safe to repeat under a documented contract.

If the provider retains keys for a limited period, recovery must respect that window. Reusing a key after expiry could execute again. An expired local lease also does not prove that the previous worker stopped acting; receiver-side guarantees are needed, such as deduplication or fencing where supported.

## Reconcile by operation, not by resemblance

The reconciler queries the remote receipt using operation identity. If it finds a confirmed effect, it records it in the ledger. If it establishes that no effect occurred and the contract permits retrying, it reuses the same identity within the valid window.

Seeing inventory at 18 does not prove our write happened. Another operation could have produced that value. Evidence must attribute the effect to the specific request.

When a provider offers neither deduplication nor reliable lookup, uncertainty may require human intervention. Compensation is another operation with permissions, failures, and possible concurrent effects. A sent email does not return to the outbox because somebody wrote ` rollback() `.

## What I would require before enabling autonomy

I would exercise failures before sending, after the remote effect, and before persisting the receipt. I would add concurrent workers, expired authorizations, changed resources, altered parameters, and keys beyond retention.

The report would show uncertain operations, duplicate effects, rejected writes, and reconciliation time. Acceptance criteria are specific to each operation and provider. Guarantees end where the enforceable contract ends.

My requirement for an autonomous write tool is concrete: **explain who authorized what, against which version, how many times it was attempted, and what evidence confirms the effect**. If that explanation is missing, distributed systems work remains. The prompt can wait.

Related reading: [function calling and orchestration](<https://lucioduran.com/blog/llm-function-calling-tool-use-patterns>) and [event sourcing and event records](<https://lucioduran.com/blog/event-sourcing-cqrs-production-lessons>).

## Frequently asked questions

### Does a valid JSON Schema make a tool safe?

No. The schema can constrain request structure, but the executor must check identity, permissions, resource, preconditions, and operational limits.

### Does an idempotency key guarantee exactly one execution?

Not by itself. The system producing the effect must enforce deduplication with known guarantees. Key scope, retention, and handling of pending operations also matter.

### What if an external API supports neither deduplication nor operation lookup?

Treat an uncertain result as a case for manual reconciliation or redesign the integration. Automatically retrying a write can duplicate the effect.

## Tips

1. Tenant and identity come from authenticated context. Never from a field the model can invent.
2. A timeout leaves an operation uncertain. Preserve its identity until the external effect is reconciled.
3. Approval is bound to arguments, resource, and version. Changing any of them requires reevaluating authorization.

- agentic-ai
- tool-execution
- mcp
- authorization
- idempotency
- distributed-systems
- reconciliation

[Back to Blog](<https://lucioduran.com/blog>)
