feat: mcpToolSearch config - #597
Merged
ericdallo merged 2 commits intoSep 11, 2026
Merged
Conversation
rschmukler
force-pushed
the
add-search-tools
branch
from
September 10, 2026 19:30
9f66c92 to
117f98c
Compare
rschmukler
marked this pull request as ready for review
September 10, 2026 19:31
ericdallo
reviewed
Sep 11, 2026
| tools (when (:tools model-capabilities) tools) | ||
| ;; Deferred tools stay callable but their schemas are withheld until the | ||
| ;; model loads them with eca__search_tools. | ||
| tools (when (:tools model-capabilities) |
Member
There was a problem hiding this comment.
I believe this will work only for the first request, when LLM enters the loop, and need to request again we will send all tools, cna you check that? worth a test for that too
ericdallo
requested changes
Sep 11, 2026
ericdallo
reviewed
Sep 11, 2026
| :skills [] | ||
| :extraConfigs [] | ||
| :disabledTools [] | ||
| :mcpToolSearch {:includePattern [] |
Member
There was a problem hiding this comment.
should we defer all by default? I believe cursor and others are doing this no? as I believe it helps for most cases
rschmukler
force-pushed
the
add-search-tools
branch
2 times, most recently
from
September 11, 2026 19:40
b162935 to
0d15c26
Compare
ericdallo
reviewed
Sep 11, 2026
Comment on lines
+5
to
+6
| - Add `mcpToolSearch` config to keep MCP tool schemas out of context until the LLM loads them with the new `eca__search_tools` tool. | ||
| - Fix deferred MCP tools being re-sent from the second request of a tool-call loop onward, undoing the context saving as soon as the model called any tool. |
Member
There was a problem hiding this comment.
I think we just need one single line of changelog
Every tool sent to the LLM costs context on every request: its
description plus its full input schema. With a few MCP servers
connected that is thousands of tokens the model rarely needs.
Add `mcpToolSearch`, which trades that upfront cost for an extra round
trip:
"mcpToolSearch": {
"deferAllWhenTotalTokensExceedPercentOfContext": 10,
"includePattern": [".*"],
"excludePattern": ["clojure-mcp"]
}
Matching MCP tools are deferred - their schemas are withheld and only a
compact catalog of names and truncated descriptions is rendered into the
system prompt. When the model needs one it calls the new
`eca__search_tools` tool, which ranks the deferred catalog against a
query, returns the matches with their input schemas, and records them on
the chat so they are sent as regular tools from then on.
A tool is deferred when the MCP definitions as a whole outgrow
`deferAllWhenTotalTokensExceedPercentOfContext` of the model context
window, or when it matches `includePattern`, and in both cases only if
it does not match `excludePattern`. That limit is a percentage rather
than a token count so one setting behaves sensibly on a 32k local model
and on a 1M one, and it is null by default: nothing is deferred until
asked for. Native tool definitions are left out of the total, so the
limit tracks what MCP actually adds.
Deferred tools are only withheld from the request payload; they stay
resolvable and callable throughout, so a tool call that arrives before
the search still executes.
Every provider rebuilds the next request of a tool-call loop from the
tool list its `on-tools-called` callback returns, shadowing the one the
initial payload filtered, so that list is filtered too. Without it
deferred schemas came back as soon as the model called any tool, which
is most of a turn. Wrapped in `sync-or-async-prompt!` rather than
`prompt!` because the sync path invokes the callback itself, without
going through it, and covered by an integration test asserting on the
continuation request.
Only MCP tools can be deferred. Native ECA tools are the agent's
baseline capabilities, so a catch-all pattern never takes them away -
use `disabledTools` to remove one of those. `eca__search_tools` is
likewise never deferred, and is only offered to the model when at least
one tool is actually deferred.
Pattern matching reuses the existing `disabledTools` engine rather than
introducing a third dialect alongside it and the exact-match approval
selectors: anchored Java regex against the builtin tool name or the
`server__tool` full name, or an exact server name for all of its tools.
That matcher is extracted as `tool-entry-matches?` and its regex
compilation is now memoized, which also lets it warn once when an entry
fails to compile - `*` is not a valid regex and was previously matched
literally in silence.
Configurable globally, per agent, and in agent markdown frontmatter,
where the object may be abbreviated to a list or string when only
`includePattern` is needed:
mcpToolSearch:
- github__.*
The static prompt cache signature now tracks the deferrable set
separately from the tool list, so changing the patterns mid-chat
rebuilds the catalog.
rschmukler
force-pushed
the
add-search-tools
branch
from
September 11, 2026 20:01
0d15c26 to
64220d4
Compare
ericdallo
approved these changes
Sep 11, 2026
ericdallo
enabled auto-merge
September 11, 2026 20:07
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Every tool sent to the LLM costs context on every request: its description plus its full input schema. With a few MCP servers connected that is thousands of tokens the model rarely needs.
Add
mcpToolSearch, which trades that upfront cost for an extra round trip:Matching MCP tools are deferred - their schemas are withheld and only a compact catalog of names and truncated descriptions is rendered into the system prompt. When the model needs one it calls the new
eca__search_toolstool, which ranks the deferred catalog against a query, returns the matches with their input schemas, and records them on the chat so they are sent as regular tools from then on.Deferred tools are only withheld from the request payload; they stay resolvable and callable throughout, so a tool call that arrives before the search still executes.
Only MCP tools can be deferred. Native ECA tools are the agent's baseline capabilities, so a catch-all pattern never takes them away - use
disabledToolsto remove one of those.eca__search_toolsis likewise never deferred, and is only offered to the model when at least one tool is actually deferred.Pattern matching reuses the existing
disabledToolsengine rather than introducing a third dialect alongside it and the exact-match approval selectors: anchored Java regex against the builtin tool name or theserver__toolfull name, or an exact server name for all of its tools. That matcher is extracted astool-entry-matches?and its regex compilation is now memoized, which also lets it warn once when an entry fails to compile -*is not a valid regex and was previously matched literally in silence.Configurable globally, per agent, and in agent markdown frontmatter, where the object may be abbreviated to a list or string when only
includePatternis needed:The static prompt cache signature now tracks the deferrable set separately from the tool list, so changing the patterns mid-chat rebuilds the catalog.