A tool definition's `input_schema` is a JSON Schema object, and it does two jobs at once that are easy to conflate. The first job is mechanical: it constrains what the model is allowed to emit, so a call for `get_weather` cannot show up with `city` as a number or `units` set to a string nobody defined. The second job is communicative: the schema is the last piece of context the model reads before it decides what to write into each field, so every `description` you attach is a direct instruction, not documentation for a human reader who will never see it.
Most tool authors spend their effort on the top-level tool `description` -- what the tool does, when to call it -- and leave the individual `properties` bare, with a `type` and nothing else. That inverts where the leverage is. The top-level description tells the model whether to reach for the tool at all; the per-property description is what stops it from guessing the date format, the units, or which of three plausible IDs a `customer_id` field wants. A bare `"type": "string"` on a field named `date` is an invitation for the model to write `"tomorrow"`.
This lesson treats the schema as a design surface with real trade-offs, not a formality to satisfy a validator. Every keyword you add narrows the space of valid calls, documents intent to the model, and costs tokens on every single request -- three effects from one line of JSON, and the rest of this lesson is about spending that line well.