Engineering NotesTools and execution
185 tool definitions cost 99K tokens, so we list names and load picks

To give an agent a tool, you put that tool's definition, its name, description, and argument schema, into the request. The more MCP servers a customer connects, the more of those definitions there are. In one production installation, the 185 connected external MCP tools come to 99,232 tokens with every definition expanded and full descriptions, as counted by Anthropic's token counting API. Even if the user only asks "what were yesterday's sales?", those definitions go out with every model call.
So OwlAI doesn't expand most tool definitions up front. The system prompt carries a name list: each tool's name and a one-line summary. When the model picks names from the list and passes them to the tool that enables tools, only those definitions are expanded. The industry calls this deferred loading (on-demand loading). This post covers what we put in the name list so the model can choose well, and how we declare tools so that enabling one doesn't change the front of the request.
Send everything, let search pick, or cut the list
The simplest approach is to send every definition from the start. There is no enabling round trip, and the model can call any tool at any time. The cost is sending definitions that have nothing to do with the question, every time. A single definition isn't small either. The PowerPoint creation tool's definition is about 10KB, roughly 3,500 tokens. Office tools document the rejection conditions and usage of every argument, so they can't be trimmed short.
The second approach is tool search. With Anthropic's tool search tool, the model searches the tool catalog with a regular expression or natural language, and up to five matching tools (by default) are expanded. It keeps working at thousands of tools. But the model only sees tools its query matched. A tool whose description lacks the word the model thought of never becomes a candidate. OwlAI leaves the choice of tool to the model's judgment. So instead of search, we chose to let the model see every name and pick.
The third approach is to cut the list to the N most-used tools. The list length is bounded, but a tool that falls off the list can't be called at all. When one of those tools is needed, the model invents a similar name and calls that.
Database tools load up front; file and external tools are listed by name
The tools whose definitions are expanded from the start are fixed:
- Database query tools. Querying data is the product's main use, so these stay callable without an enabling round trip.
- System tools such as asking the user, widgets, schedules, and enabling tools.
- A few tools, such as web search, whose definitions are small enough that an enabling round trip would cost more than it saves.
File, office, and sandbox tools and external MCP tools appear only in the name list. In one production installation, the turn with the most tools had 83 tools expanded from the start and 212 announced only in the name list.
On a turn where the user names a connector with @server-name, that server's tools are expanded from the start. The user has already picked the connector, so there's no reason for another enabling round trip. This isn't guessing tools from the words in the question; it only follows what a person chose. Up to 60 tools are expanded per server. The rest stay in the name list and can still be enabled, and the truncated server and count are logged. Tools expanded this way stay enabled on later turns.
The name list includes every name and bounds the length of each entry
Every name-list tool the user can use appears by name. Instead, we bound how much space each entry takes:
- Each summary is cut at 300 characters.
- Up to six required argument names are appended.
- External MCP tools are grouped by server, and the description a server gives of itself appears once per group.
Summary length directly changes how well the model picks. With a 100-character cap, 33 of 55 name-list entries are truncated. The part that gets cut is usage: "read the guide first," "this argument is optional." In that state, sending the same office document request three times, the model called the tool by guesswork and failed to produce output all three times. On the same 55 entries, a 300-character cap adds about 586 tokens to the name list. That's less than one PowerPoint tool definition, and cheaper than the round trip of calling a tool wrong and calling it again.
Required argument names tell the model what order tools go in. One connector's search tool requires a site ID, and a different tool returns that ID. With only summaries in the list, the model enables the search tool alone and makes up a site ID. When the required argument names are visible, it enables the tool that returns the ID as well. It's a few names, so a few tokens per entry.
The model picks, and the enabling tool enables only exact names
The model passes the names it picked to the tool that enables tools. It can pass several at once, and the head of the list tells it to enable, in one call, both the tool that does the work and any tool that supplies its required arguments. An enabled tool can be called from the next step of the same turn and stays enabled until the conversation ends. On the next turn, it's enabled again from the saved list of enabled tools.
The enabling tool enables only tools whose names match exactly. Unknown names, names the user has no permission for, and names already expanded from the start come back in a failure list. Models often pass a connector's name instead of a tool name, and in that case the result lists the tool names that belong to that connector. This lookup also uses exact text matches, ignoring only case. Guess a similar-looking name and give the model a wrong candidate, and it enables that name as is. After receiving the candidates, the model decides again what to enable.
A tool that hasn't been enabled doesn't run. If the model calls a tool from the name list without enabling it, the executor answers "enable it first." That answer is different from "no such tool" and "the connector isn't connected." If all three came back as the same answer, the model would read a usable tool as a missing one and give up.
The name list doesn't widen permissions. When a tool is enabled, the executor reruns the user's permission checks, tool policy, and client capability check, and enables only tools that pass. When enabled tools are restored on the next turn, they go through the same checks, so a tool whose permission was removed in the meantime drops out. “Customers know their connector tools' risks, so tool policy is per install” covers which tools tool policy keeps out of the name list entirely, and “Tools copy the form and load the guide; models fill the arguments” covers how a task guide arrives along with an enabled tool.
Enabling a tool leaves the front of the request unchanged
Tool definitions and the system prompt sit at the front of the request. If a single character there changes, the conversation context after it can't be read from the cache and is recomputed (“One system prompt edit zeroes cache reads, so changing blocks go last”). If every enabled tool changed the front of the request, a mechanism meant to save tokens would raise costs instead.
So the name list keeps the same bytes for the whole conversation. Tools already enabled stay in the list. Removing an entry every time a tool was enabled would change the system prompt every time. Since an enabled tool staying in the list could lead the model to enable it again, the head of the list says "if a tool is already callable, call it; don't enable it again." The name list changes only when something happens outside the conversation: a tool enters or leaves the organization's tool list, or an administrator changes permissions.
How tool definitions are declared depends on the model:
| Models that accept hidden declarations | Other models | |
|---|---|---|
| Models | Claude Fable 5.1, Opus 5.5, Sonnet 5.5, Haiku 5.5 | Other Anthropic models, the OpenAI API, models served with vLLM |
| Initial declaration | Every tool, including name-list tools, with defer_loading on tools not yet enabled |
Only the tools expanded from the start |
| When a tool is enabled | Tools array unchanged; a system message saying "enable this tool" is appended to the end of the conversation context | The enabled tool's definition is added to the tools array |
| What changes | The very end of the conversation context | The tools array from that tool's position on |
A definition marked with defer_loading is sent in the request but enters the model's context folded. Expanding all 185 tools above takes 99,232 tokens; expanding one and folding the rest takes 1,352 (September 10, 2026, Anthropic token counting API). Enabling happens at the end of the conversation context rather than in the tools array, so the tools array is the same from the first request of the conversation to the last.
For models that don't accept hidden declarations, only the definitions of tools expanded from the start and tools already enabled are sent. Enabling a tool adds its definition to the tools array, and the array never shrinks within a conversation. The array is sorted by name when it's sent, so the same set of tools goes out as the same bytes regardless of the order they were enabled in (“One agent loop for every feature, with the differences in hooks”). The round in which a tool is enabled recomputes everything after that tool's position, but from the next round on the front of the request is the same again.
Design choices
The name list grows with the number of connected tools. In the installation above, applying the 300-character cap to external MCP tool summaries grew the name list from 29,771 to 36,814 characters. With thousands of tools, search is the right choice. While customers connect tools in the hundreds, we chose to let the model see every name and pick, and the per-entry length cap keeps the growth proportional to the tool count.
Summaries longer than 300 characters are truncated. For built-in tools, a regression test guards summary length, so lengthening a summary fails the test and forces a review of the cap. Descriptions sent by external MCP servers are cut to the same cap.
Enabling costs one round trip. A turn that creates a document goes through two rounds: enable, then call. That's the trade for not sending every definition from the start, and when the user names a server with @server, its tools are called directly without that round trip.
Folded definitions aren't free either. A folded definition's size grows with its description. With the 185 tools' descriptions cut at 200 characters, expanding one costs 764 tokens; with full descriptions, 1,352. We still keep the full descriptions. Enabling a tool expands the definition exactly as it was declared, so a shortened description is the description the model reads after enabling.
For models that don't accept hidden declarations, we accept the cache loss in the round where a tool is enabled. Hidden declarations and the enabling message only work if the model accepts them, and a model that doesn't rejects the request. If hiding worked but the enabling message were rejected, the tool could never be brought back. So we use them only on models where we've confirmed both with real calls.
Conversations on the playbook edit screen expand every definition from the start. Editing uses few tools, and edit mode doesn't offer the enabling tool at all.
If your agent's tool definitions have grown longer than the questions as you connect more MCP servers, start with a list that includes every name. Then check two things: whether enabling a tool leaves the bytes of the list and the tools array unchanged, and whether truncating summaries has cut off how to use the tools.
More in Tools and execution

Engineering Notes · Tools and execution
Rerunning a chat repeats its mistakes. Keep the steps and working SQL
Say a chat once went well: it pulled last week's sales from the database, grouped them by department, and built an Excel file.

Engineering Notes · Tools and execution
Tool calls a script makes still get permission and approval checks
Take a request like "For each issue opened last week, look up the customer's contract, and email the owner onl…

Engineering Notes · Tools and execution
Tools copy the form and load the guide; models fill the arguments
Making a quote from a company form takes two steps: copy the form to a new path, then fill in the copy.