The tool definition is a contract between you and the model. The most underrated field in that contract is the description — the prose that tells the model when and why to use this tool. Production teams routinely under-invest in descriptions and over-invest in fancy schemas. The model selects tools by reading descriptions, not by reading your hopes.
Schema-wise, every modern provider speaks JSON Schema with minor dialectic differences. The shape that always works is: {"type": "object", "properties": {…}, "required": [...]} with each property carrying its own type and a one-line description. Use enum for closed sets ("status": one of open|closed|in_progress). Use format for things like dates and emails — most providers do not enforce them, but they bias the model toward producing valid output.
Three rules for descriptions, learned the hard way:
- Tool description: when, not what. "Get current weather for a city" is a definition. "Use this when the user asks about today's weather, temperature, or whether it will rain in a named city" is a contract.
- Parameter descriptions: format and edge cases. Not just "city name" — "city name in English; for cities with translations like 'Seoul' use the romanized form, not '서울'." That is the description that prevents the most common failure mode.
- Required is required. If a parameter is required to answer correctly, mark it required. Optional parameters get omitted half the time and the model never asks; required ones get a structured re-ask if missing.
Schema design is a writing problem disguised as an engineering problem. The schema is correct when a colleague who has never seen your codebase can read the tool definition and predict, with 90% accuracy, what the tool does and when the model will pick it.