An API designed for humans has documentation, examples, a support channel, and a developer who will read three paragraphs to work out which endpoint to call. An API designed for an agent has one description string, read once, in a list alongside forty others, with no ability to ask a follow-up question.
That string is the interface. Everything else about the tool, the implementation quality, the data behind it, the latency, is downstream of whether the model picked it in the first place and filled its arguments correctly.
Most tool integrations that behave badly are not broken. They are being selected at the wrong times, or selected correctly and called with arguments the model guessed because the schema did not tell it what to put there.
The description is the interface
Selection is a reading task. A model choosing among available tools reads names and descriptions, compares them to the request in front of it, and picks. There is no runtime experimentation, no reading of the implementation, no institutional memory of which tool worked last time.
Which means a description has to do a specific job, and it is not the job that documentation does. Documentation describes what a thing is. A tool description has to answer a different question: given this request, is this the right tool, and if not, which characteristic rules it out.
Practically, a good description states what question the tool answers, what geographic or temporal or entity scope it covers, and what it explicitly does not do. That last part is undervalued. A description that says the tool returns building attributes within a bounding box and does not cover interior layout or occupancy prevents an entire class of misselection, because the model can rule it out for occupancy questions without trying.
Coverage limits belong in the description too, not in a doc site. A tool that only has data for certain countries and does not say so will be selected for every country, and the resulting empty responses look to the model like the absence of the thing rather than the absence of coverage. That confusion propagates into the final answer as a factual claim about the world.
Length has a real cost, since every description occupies context on every request, but the failure mode of over-brevity is worse than the failure mode of a slightly long description. A tool that is never correctly selected costs its full description length and returns nothing.
Naming conventions
Names carry more selection weight than their size suggests, because they are read first and they anchor the interpretation of everything after.
A namespace prefix is worth the characters. When a model sees a dozen tools with a shared prefix, it learns they belong to one system with consistent conventions, and it stops confusing them with similarly named tools from another provider. Without a prefix, two systems that both offer something called search create a persistent ambiguity that no amount of description quality fixes.
The more consequential rule is to name the answer, not the implementation. Internal names describe how the thing works: the table it reads, the service it proxies, the algorithm it runs. A model has no idea what any of that means. A tool named after a job it does is selectable. A tool named after the pipeline stage that produces it is not.
Some patterns worth holding to: - Use a verb that reflects the operation type, and use it consistently. Get for a single known entity, search or list for a set, compute for something derived. - Avoid near-synonyms across a toolset. If one tool uses find and another uses lookup for the same kind of operation, the distinction reads as meaningful when it is not. - Do not encode version numbers or internal service names in the tool name. Those are deployment details and they leak into the model's reasoning as if they were semantic. - Keep singular and plural honest. A name ending in a plural should return a collection, always, including when the collection has one member.
Granularity, and the misselection it causes
Deciding how many tools to expose is the design decision with the largest effect on selection quality, and it does not have a general answer.
Too coarse is the more obvious failure. One tool that takes a free-text query and does everything shifts all the disambiguation into the argument, which means the model must guess a query format it has never seen. It also makes the description useless for selection, because a tool that does everything cannot be ruled out for anything.
Too fine is the failure that actually happens more often, and it is worse because it looks like good design. Splitting one concept across several near-identical tools, one per source or per variant, produces a set of descriptions that differ in a clause. A model reading them has to make a distinction that the descriptions barely support, and it will make it wrong a meaningful fraction of the time. Worse, the wrong choice usually returns a plausible answer rather than an error, so nothing surfaces the mistake.
The rule that holds up: split tools when the answer is genuinely different, not when the implementation is different. If two tools answer the same question from different sources, that is one tool with a source parameter, or one tool that decides internally and reports which source it used. If two tools answer questions a user would phrase differently and act on differently, they are two tools.
When a split cannot be avoided, make the distinguishing characteristic the first clause of both descriptions rather than a qualifier at the end. Models weight the beginning of a description heavily, and a difference buried in the third sentence is a difference that will not be read.
Parameter schemas as a contract
The model has to fill the arguments alone, with no examples in front of it and no way to probe. Whatever the schema fails to specify, the model will invent, and it will invent something reasonable that happens to be wrong.
Units are the classic case. A parameter named radius accepts a number and the model supplies one. Whether that number was meant as metres, kilometres, or degrees is not recoverable from the name, and each interpretation produces a query that runs successfully and returns the wrong area. Put the unit in the parameter description every time, without exception, even where it seems obvious. Better still, put the unit in the parameter name.
Ranges belong in the schema rather than the description, because a schema constraint is enforced and a description is advisory. Minimum and maximum on numbers, enumerations on anything with a fixed set of valid values, and pattern constraints on formatted strings. An enumerated parameter is dramatically more reliable than a free string, because the model can see the valid values rather than guessing at the vocabulary.
Defaults do more work than they appear to. Every optional parameter without a default is a decision pushed onto the model, and the model will make it based on nothing. A sensible default on every optional parameter reduces the number of things that can go wrong per call, and the right default is almost always the conservative one: the smaller radius, the shorter time window, the smaller page size.
Required parameters should be genuinely required. A schema that marks six parameters as required when three would suffice produces failed calls when the model does not have values for the other three, and the model will then invent them rather than abandon the call. Requiring less and defaulting more converts a class of hard failures into a class of merely suboptimal calls.
Finally, name coordinate and identifier parameters unambiguously. Latitude and longitude ordering is a genuine ambiguity in the world, and a parameter list that accepts two bare numbers will receive them in both orders. Separate named parameters remove the problem entirely.
Declaring latency and cost
A runtime orchestrating tool calls has budgets: a wall-clock limit before the user gives up, a token limit on the context, sometimes a monetary limit. It cannot plan against those budgets if every tool looks equally cheap.
Declaring expected latency, even coarsely, changes planning behaviour. A tool marked as typically returning in well under a second is one a planner can call speculatively. A tool marked as taking many seconds, or as running asynchronously and returning a handle, is one that gets called once, deliberately, after the cheap options have narrowed the question. Without that signal, a planner treats them identically and either times out or serialises unnecessarily.
Cost declarations matter in the same way. If a tool triggers a paid third-party lookup, or spends compute that scales with the requested area, that fact belongs where the caller can see it before calling. Cost that scales with a parameter is worth stating explicitly, because it tells the caller which parameter to keep small.
Response size is the third budget and the one most often ignored. A tool that can return a very large payload should say so, and should offer a parameter that bounds it, so a caller working with limited context can ask for less rather than discovering the problem after the response has already consumed the window.
None of this needs to be precise. Order of magnitude is enough to change behaviour, and an honest coarse figure is better than a precise one that goes stale.
Response size discipline
A tool response does not arrive in a vacuum. It lands in the model's context and competes with everything else there, including the original request, the conversation, and the reasoning the model still has to do. A large response does not merely cost tokens, it degrades the quality of the thinking that follows it.
The discipline is to return the answer, not the record. Internal representations accumulate identifiers, timestamps, source keys, nested metadata, and provenance structures, all of which are essential to the system and irrelevant to the question. Stripping them is not lossy if the fields removed were never going to affect the answer.
Some specific reductions that pay for themselves: round numeric outputs to the precision the measurement actually supports rather than to float precision, since fifteen digits of a value that is good to two is pure noise. Omit fields that are null rather than including them empty. Flatten nesting that exists for storage reasons. Replace repeated identical metadata across array elements with a single header. Return the top results with an explicit total count rather than everything.
Pagination deserves a default, not just a parameter. A tool that returns everything by default will occasionally return an enormous result and destroy the caller's context, and the caller had no way to anticipate it. Defaulting to a bounded page with a clear indication that more exists puts the decision back in the caller's hands.
What should never be stripped is the information that qualifies the answer: the confidence, the coverage caveat, the age of the data. Those are small and they are the difference between a figure a consumer can use responsibly and a bare number.
Evaluating selection
Tool descriptions are prompt engineering with a deployment pipeline, and they degrade the same way prompts do. A wording change made to clarify one case shifts behaviour in five others, and nothing surfaces it.
The countermeasure is a fixed question set: a list of realistic requests with the correct tool, and correct arguments, recorded for each. Run it whenever a description, a name, or a schema changes. It does not need to be large to be useful, but it needs to be fixed, because the value comes from comparing runs.
The set should be deliberately unbalanced towards the hard cases. Requests that sit between two tools. Requests that should select nothing at all, because refusing to call is a correct outcome and a toolset that never refuses is over-eager. Requests phrased in the vocabulary a real user would use rather than the vocabulary the description uses, since matching the description's own words is a test of nothing.
Two failure classes are worth tracking separately. Wrong tool selected is usually a naming or granularity problem. Right tool selected with wrong arguments is a schema problem. They have different fixes, and pooling them into one accuracy figure hides which one is happening.
The description that costs the least to fix
The most expensive tool design mistake is not a bad description, which can be rewritten in an afternoon. It is a granularity decision, because tool boundaries end up encoded in every agent that integrated against them, and changing them breaks callers that were working.
So the sequence that survives contact: get the boundaries right first and accept a rough description, because boundaries are expensive to change and descriptions are cheap. Ship the smallest set of tools that covers the surface, watch which ones get misselected, and split only when a real distinction has proved itself in the traces. A toolset that grew by splitting under evidence is almost always more selectable than one that was enumerated up front from the shape of the backend.