Wrapping an internal API as a tool is the easy part. Making that tool choosable is the work.
A model does not read your OpenAPI schema and infer intent. It picks from names and descriptions, under uncertainty, with a limited context window. Every ambiguity in that surface shows up as a wrong tool call in production.
Write descriptions for a new hire
A tool description should say what the tool does, when to use it, and when not
to. search is a guess. Search the documentation index by keyword; use this
before answering questions about product behaviour is a decision.
Include the failure modes. If a tool only works on files that were already listed, say so in the description instead of returning an error the model has to interpret.
Prefer fewer, coarser tools
Five tools with clear boundaries outperform thirty thin wrappers. Each tool costs context and adds a way to be wrong. If two tools are always called together, they are one tool.
Coarse tools also let you return less. A tool that returns a summary plus an identifier keeps the context small; a tool that returns an entire document fills the window and buries the next instruction.
Errors are part of the interface
The message a tool returns on failure is consumed by the model. Write it for
that reader: what went wrong, what was tried, and what to do next. A stack trace
wastes a turn. No matching record for id 1234; call list_records first costs
one line and usually fixes the run.
Treat tool results, not just tool definitions, as designed output.
The test is simple: give the tool set to someone unfamiliar with the codebase. If they cannot tell which tool to reach for, neither can the model.