An agent-ready API needs more than an MCP server

An MCP server can expose an API to an agent. The API still needs a contract that makes safe operation possible.

A person using a product interface sees warning copy and can notice an unexpected result. An agent sees a goal, a tool description, and an error. When the contract is vague, a capable agent will try plausible next steps quickly. The interface has to constrain the steps that are unsafe.

I have worked around enough external integrations to be careful with the claim that an API is documented. Documentation describes an intended path. Reliability depends on what a caller can prove, constrain, and recover from when that path breaks.

Five contract properties

| Property | What the contract should state | Why it matters | |---|---|---| | Side effects | Whether a call reads, reserves, creates, changes, or cancels | A tool name is not enough warning before a state change | | Idempotency | The caller-supplied key and outcome of a repeated call | Retries should not create a second shipment, payment, or record | | Bounded retrieval | Page limits, maximum result sets, freshness, and query cost | Search needs a data and cost boundary | | Typed failures | Stable error categories and permitted next actions | A caller needs to know when to retry, escalate, or stop | | Dry runs and compensation | What can be checked without mutation and how an action can be addressed | Approval needs an operational path after an error |

These are normal integration disciplines. Agentic workflows make their absence more visible because there is no human interpreter filling the gaps between documentation and behaviour.

State the effect in the contract

An agent-facing tool can expose its behaviour directly:

{
  "name": "hold_delivery",
  "effect": "state_change",
  "approval_required": true,
  "idempotency_key_required": true,
  "reversible_until": "2026-09-01T18:00:00Z",
  "dry_run_supported": true
}

The point is to give the calling layer enough deterministic information to refuse an unsafe call before model judgement becomes the deciding control.

Make failure actionable

A generic server error leaves an agent to improvise. A typed failure can name the permitted response:

{
  "code": "APPROVAL_REQUIRED",
  "retryable": false,
  "safe_next_actions": ["request_approval", "create_draft"],
  "correlation_id": "..."
}

A retryable timeout and an authorisation failure need different handling. The contract should make that distinction executable.

Before exposing an endpoint as an agent tool, I ask whether a caller can identify its effect, repeat it safely, limit its retrieval, interpret each failure, and recover from an approved action where recovery is possible. If the answer is no, the work is API design before it is MCP integration.