Not all tools are equal. A read tool — list orders, look up a customer, fetch a price — has no consequences if the model calls it ten times by accident. A write tool — issue a refund, send an email, schedule a deploy — can ruin somebody's day if the model gets enthusiastic. The protocol does not protect you from this distinction; you have to build it in.
The first habit is category by name. Read tools should sound like queries: search_orders, get_customer, list_invoices. Write tools should sound like verbs with a target: refund_order, send_email, schedule_deploy. Naming is one of the few signals the model sees from across the schema; using verbs for writes is a quiet bias toward correctness.
The second habit is idempotency keys for write tools. If a network blip causes the same write to be called twice, the system should detect it and refuse the duplicate. Most APIs you would call already support this (Stripe's Idempotency-Key, for example); your tool should accept and forward such a key generated from the conversation context.
The third habit is human-in-the-loop on the dangerous edge. For irreversible writes — money out, messages sent, infrastructure changed — the right pattern is a two-step tool: propose_refund returns a structured proposal, the agent shows it to the human, and only after explicit approval does the agent call execute_refund with the proposal ID. The protocol gives you the structured proposal; you owe the user the approval.
This is also the lens MCP brings explicitly: the spec marks tools that may have effects on the world and asks clients to surface that to users. The lens is identical to what good API designers were already doing; MCP just made it part of the contract.