ToolDefinition, callback signatures, type inference, defaults, and return types.
Start with a model-friendly tool
A good tool is narrow enough for a model to choose correctly. Give the tool a clear name, describe when to use it, validate every input with Zod, and return the smallest useful result.get_inventory_item is easier for a model to choose than inventoryFindByPrimaryKey.
Describe inputs with Zod
Use Zod schemas for all tool inputs. The server validates the incoming arguments before your handler runs, and TypeScript infers the handler parameter type from the schema..describe() text that tells the model what value to provide. Use defaults for ordinary behavior, but keep defaults visible when they affect cost, safety, or output size.
Add tool annotations
Tool annotations tell clients and models how risky a tool is. Set the main behavior hints explicitly, especially for tools exposed to ChatGPT or MCP catalogs.readOnlyHint: false for tools that create, update, delete, send, purchase, deploy, or otherwise change state. Use destructiveHint: true when the change can remove data or is hard to undo.
Add idempotentHint when retry behavior matters. Set it to true only when repeating the same call has the same effect as running it once.
Return the right kind of result
Prefer raw MCPCallToolResult shapes. Deprecated response helpers still work for upgrades, but new code should return the wire envelopes directly.
See Response Helpers for the deprecated-helper migration table and Response helpers API reference for signatures.
Return views from tools
Bind a view on the tool definition, then return a plainCallToolResult with view props in structuredContent and model-facing text in content. The deprecated widget() helper builds the same envelope.
The view.name value must match a view under resources/ (or your views directory).
content. The view reads structuredContent via useToolContext(). See MCP Apps for view workflow guidance.
Use ctx for request-aware tools
The second callback argument, usually named ctx, exposes per-call authentication, request-scoped client metadata and capability checks, elicitation, progress, and logging.
ctx.auth only for verified identity from server authentication. Values returned by ctx.client.info(), ctx.client.capabilities(), ctx.client.extension(), and ctx.client.user() are self-reported by the client for the current request. user() normalizes optional OpenAI-specific _meta hints; even its subject, conversation, and organization identifiers are unverified and must never be used for access control.
See the Tool context API reference for every ctx method, field, capability check, log level, and return type.
Handle tool failures deliberately
Return{ isError: true, content: […] } when the tool ran but the requested operation could not complete. Throw only for unexpected failures that should be treated as server errors.
Test a tool locally
Run the development server and call the tool from the Inspector.http://localhost:3000/mcp/inspector, select the tool, enter test arguments, and verify both success and failure cases.
Next steps
Tools API reference
Look up tool definitions, callback signatures, inferred types, and return
shapes.
Response Helpers
Choose the right helper for text, JSON, errors, resources, media, and
widgets.
MCP Apps
Return interactive widgets from tool results.
Authentication
Add verified user identity to protected tools.