Skip to content

fix(mcp): honour deferred flag from transport_config - #794

Open
jaaacki wants to merge 1 commit into
iOfficeAI:mainfrom
jaaacki:fix/honour-deferred-from-transport-config
Open

fix(mcp): honour deferred flag from transport_config#794
jaaacki wants to merge 1 commit into
iOfficeAI:mainfrom
jaaacki:fix/honour-deferred-from-transport-config

Conversation

@jaaacki

@jaaacki jaaacki commented Aug 6, 2026

Copy link
Copy Markdown

Fixes #793.

Problem

ToolSearch can never return a result. crates/aion-tools/src/tool_search.rs filters on .filter(|d| d.deferred), but every MCP server is built with deferred: Some(false), so the set is always empty — while aionrs still registers ToolSearchTool unconditionally (crates/aion-agent/src/bootstrap.rs:361) and the system prompt still tells the model that deferred tools exist.

Models that follow that instruction loop on it. Measured across ~20 sessions on 2.1.50: glm-5.2 made 204 ToolSearch calls for 17 real tool calls; gpt-5.5 made 0.

aionrs supports the flag per server (McpServerConfig::deferred, defaulting to true when omitted) and honours it in crates/aion-mcp/src/tool_proxy.rs:135. The capability is fully implemented in the engine — the host just never lets a value through.

Change

Read deferred from the same transport_config JSON that command / args / env / url / headers already come from:

let deferred = value.get("deferred").and_then(|v| v.as_bool()).unwrap_or(false);

and use it in the three McpServerConfig constructions inside row_to_mcp_server_config.

  • No default change. An absent key still yields false, so current behaviour is byte-identical for every existing server. Nothing is opted in implicitly.
  • Scoped deliberately. Only row_to_mcp_server_config (DB-configured servers). session_server_to_mcp_server_config takes a typed transport enum with nowhere to carry the flag, and team_mcp_to_config is an internal server where non-deferred looks intentional — both left untouched.

Tests

Two added next to the existing row_to_mcp_server_config test:

  • row_to_mcp_server_config_defaults_deferred_to_false — absent key stays false
  • row_to_mcp_server_config_honours_explicit_deferred"deferred": true comes through

Why it matters

With this, an operator can defer large MCP servers so their tools become name-only stubs retrievable through ToolSearch, instead of every schema entering the system prompt on every turn. On a deployment with ~1,300 tools across 12 servers, that is the difference between a subset being reachable and all of them.

Note

I don't have a Rust toolchain on this machine, so this has not been compiled or tested locally — the diff is mechanical and the tests reuse the existing make_row / test_broadcaster helpers, but please let CI confirm. Happy to adjust scope (e.g. plumb the flag through the session/team paths too) if you'd prefer.

Every MCP server was constructed with deferred: Some(false), so no tool was
ever marked deferred. ToolSearch filters tool_defs on .filter(|d| d.deferred),
so it always matched an empty set and returned "No deferred tools matching"
regardless of query, tool count, or how the server was installed.

aionrs supports the flag per server (McpServerConfig::deferred, defaulting to
true when omitted) and registers ToolSearchTool unconditionally, so the feature
was reachable in the engine but never enabled by the host.

Read the flag from the same transport_config JSON that command/args/env/url/
headers already come from. An absent key still yields false, so existing
behaviour is unchanged; an explicit true opts a server in.

Scoped to row_to_mcp_server_config (DB-configured servers). Session-scoped and
internal team servers are left as-is.

Refs iOfficeAI#793
@jaaacki

jaaacki commented Aug 7, 2026

Copy link
Copy Markdown
Author

Heads-up: the CI workflow on this PR is sitting at action_required (first-time-contributor gate), so nothing has actually run upstream yet. I reproduced ci.yml locally to verify the change in the meantime — rust:1.95.0, RUSTFLAGS=-D warnings, against branch tip 2ce0cc39:

  • fmt (cargo fmt --all -- --check) — ✅ clean
  • clippy (cargo clippy --workspace -- -D warnings) — ✅ clean
  • both new tests — ✅ pass (row_to_mcp_server_config_defaults_deferred_to_false, row_to_mcp_server_config_honours_explicit_deferred)
  • The only failures I hit were container artifacts (8 GB OOM on aws-sdk-bedrock; chmod-000 / kill-tree tests that need a normal VM) in modules unrelated to this diff — and the full suite is green on main, so I'd expect the same here.

No Cargo.* changes, so audit is N/A. Happy to plumb deferred through the session/team paths too if you'd prefer — left them untouched on purpose. If a maintainer can approve the workflow run, CI can have the final word.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ToolSearch always returns nothing: deferred is hardcoded false for every MCP server

1 participant