Blog
MCP

Published Updated

Shouryamaan and Arag

How to Design MCP Tools That AI Agents Can Use Reliably

Read as Markdown

Reliable MCP tools have distinct task names, bounded inputs, structured outputs, stable errors, downstream authorization, and safe write behavior. They are tested as a set because tool-selection failures often come from overlap between two individually valid definitions.

Start with selection-only evaluations. They reveal ambiguity without letting a mistaken call touch a backend.

Give each tool one job

Use a verb and object that match the user's task. get_order_status is clearer than query_order_service. Avoid generic names such as execute, manage, process, or run_query unless the broad capability is intentional and tightly restricted.

The description should answer:

  1. What result does the tool produce?
  2. When should the model use it?
  3. When should the model use another tool or no tool?
  4. What external effect can it have?

The task-level API guide shows a weak and strong contract side by side.

Keep inputs small and constrained

Use JSON Schema to express required fields, enums, formats, lengths, and numeric bounds. Prefer a stable resource ID to a free-text description when the user or previous tool already identified the resource.

Do not ask the model for values the server can derive from authenticated context. Tenant ID, user ID, and provider credentials usually belong to the session or server, not the tool arguments.

For a mutation, accept an operation or idempotency key when the backend contract requires one. Do not generate a fresh key inside an automatic retry, because that turns the retry into a new operation.

Return a result for the next decision

The current MCP tools specification supports an optional output schema and structuredContent. It recommends returning a text representation too for compatible clients.

Return a bounded shape with the authoritative fields the agent needs next:

{
  "deploymentId": "dep_1842",
  "state": "pending",
  "statusUrl": "/deployments/dep_1842",
  "retryAfterSeconds": 10
}

Do not return complete provider responses by default. They often contain unstable fields, internal identifiers, excessive text, or secrets.

Separate protocol and domain errors

Use protocol errors when the MCP request itself is invalid or the server cannot process it. Return isError: true with a stable domain error when the tool executed and the business action failed.

Useful domain errors tell the caller what to do:

Error Next action
invalid_resource_id Correct the argument
not_authorized Stop and request access
approval_required Present the exact action to the user
operation_in_progress Poll the returned operation
rate_limited Wait until the returned time
upstream_unavailable Retry only if the operation contract permits it

Never include stack traces, database messages, or credentials in model-visible errors.

Enforce authorization behind the tool

The server should authenticate the client and represented user. The downstream API should authorize that identity against the tenant, resource, and action. A tool list is not an access-control list.

The MCP authentication guide covers audience-bound access tokens and separate upstream credentials.

Make writes safe to repeat

For every tool that creates, updates, sends, spends, or deletes:

  • define one logical operation identifier;
  • store or reconcile its result;
  • reject conflicting reuse;
  • document unknown outcomes after timeout;
  • place approval before consequential execution;
  • prefer reversible deletion when the backend supports it.

A client retry and a server retry can multiply. Decide which layer owns the retry and record every attempt under one operation.

Treat annotations as display hints

MCP tool annotations can describe read-only, destructive, idempotent, or open-world behavior. Clients must not trust annotations from an untrusted server. Use them to improve presentation, while enforcing the same facts in code.

Evaluate selection and execution separately

Selection tests freeze the visible toolset and ask the model which tool it would call. Include:

  • clear positive tasks for every tool;
  • near-miss tasks for the closest pair;
  • requests missing required context;
  • requests that should call no tool;
  • adversarial content inside retrieved data.

Execution tests call the selected tool with valid, invalid, unauthorized, repeated, and interrupted requests. Record the tool name, arguments after redaction, policy decision, operation ID, result class, and duration.

The wrong-tool debugging guide explains how to use those traces when a selection test fails.

Start with the complete tool list

Export the list exactly as the model sees it. Reading tool files one by one hides collisions. Rank pairs by shared nouns, verbs, descriptions, and argument shapes, then write near-miss tasks for the closest pair.

The prompt below builds that evaluation set without invoking a single tool.