[GH-ISSUE #4421] MCP server exposes all 34 tools unconditionally — ~430KB+ tool-schema overhead on every request #1757

Closed
opened 2026-10-16 21:09:53 +00:00 by bsakaguchi · 3 comments
Owner

Originally created by @hj01857655 on GitHub (Oct 16, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/4421

Problem

rea-agents@6.5.0 MCP server exposes all 34 tools at once, unconditionally. Every tool carries a large JSON schema, and the combined tools array is sent on every chat-completion request — regardless of whether any rea tool is actually invoked that turn.

Measured impact

Proxying a client (Claude Code) through a 2api bridge to Qwen3.8-Flash, a single request showed:

prompt_tokens: 314267   (314K tokens, context full)

Breaking the request body down, the top-level tools array was the dominant consumer:

segment size
tools array (67 tools total, 34 of them mcp__rea__*) ~430KB+ (dump truncated mid-schema; real request larger)
other messages ~110KB

The 34 rea tool schemas alone are roughly 100K+ tokens of static overhead per turn, before any conversation history. In a long reverse-engineering session this forces the host agent into repeated overflow-compaction: observed overflow_compacted up to (3/3) — the request wouldn't fit even after three compaction passes, because the tools array is re-sent every turn and cannot be compacted away.

The 34 tools currently injected (all mcp__rea__*):

address_name, address_to_file_offset, analyze_function,
analyze_javascript_application, analyze_swift_types, analyze_web_bundle,
annotate_native_function, batch_decompile, binary_overview, binary_session,
build_call_path, build_reconstruction_obligation_ledger,
capture_adb_screen, capture_browser_scenario, capture_electron_scenario,
capture_native_ui_scenario, capture_process_scenario, capture_web_screenshot,
close_binary, close_frida_session, close_gdb_session, close_rizin_debug_session,
collect_adb_bugreport, comment,
compare_application_versions, compare_artifacts, compare_bundles, compare_functions,
compare_javascript_export_shapes, compare_managed_members, compare_process_captures,
compare_source_to_bundle, compare_wasm_interfaces, compare_web_captures

Request

Some way to avoid paying the full 34-tool schema cost every turn. A few options, any one would help a lot:

  1. Lazy / on-demand tool registration — only advertise a tool after the client first calls it (or via a list_tools/enable_tool handshake).
  2. Tool grouping / sub-servers — split into smaller MCP servers (e.g. rea-binary, rea-capture, rea-compare, rea-web) so clients can attach only what they need.
  3. Configurable tool subset — a flag/env/CLI option to enable only a named group of tools (e.g. rea mcp --tools binary,decompile) so the schema set is bounded.

Right now the only workaround is to detach the rea MCP server entirely when not actively doing RE, which defeats the point of having it attached.

Environment

  • rea-agents@6.5.0 (latest)
  • Node 26 (also tested 22.x sandbox)
  • Client: Claude Code via 2api bridge → Qwen3.8-Flash
Originally created by @hj01857655 on GitHub (Oct 16, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/4421 ## Problem `rea-agents@6.5.0` MCP server exposes **all 34 tools at once, unconditionally**. Every tool carries a large JSON schema, and the combined `tools` array is sent on **every** chat-completion request — regardless of whether any rea tool is actually invoked that turn. ## Measured impact Proxying a client (Claude Code) through a 2api bridge to `Qwen3.8-Flash`, a single request showed: ``` prompt_tokens: 314267 (314K tokens, context full) ``` Breaking the request body down, the top-level `tools` array was the dominant consumer: | segment | size | |---|---| | `tools` array (67 tools total, **34 of them `mcp__rea__*`**) | **~430KB+** (dump truncated mid-schema; real request larger) | | other messages | ~110KB | The 34 rea tool schemas alone are roughly **100K+ tokens of static overhead per turn**, before any conversation history. In a long reverse-engineering session this forces the host agent into repeated overflow-compaction: observed `overflow_compacted` up to **(3/3)** — the request wouldn't fit even after three compaction passes, because the `tools` array is re-sent every turn and **cannot be compacted away**. The 34 tools currently injected (all `mcp__rea__*`): ``` address_name, address_to_file_offset, analyze_function, analyze_javascript_application, analyze_swift_types, analyze_web_bundle, annotate_native_function, batch_decompile, binary_overview, binary_session, build_call_path, build_reconstruction_obligation_ledger, capture_adb_screen, capture_browser_scenario, capture_electron_scenario, capture_native_ui_scenario, capture_process_scenario, capture_web_screenshot, close_binary, close_frida_session, close_gdb_session, close_rizin_debug_session, collect_adb_bugreport, comment, compare_application_versions, compare_artifacts, compare_bundles, compare_functions, compare_javascript_export_shapes, compare_managed_members, compare_process_captures, compare_source_to_bundle, compare_wasm_interfaces, compare_web_captures ``` ## Request Some way to avoid paying the full 34-tool schema cost every turn. A few options, any one would help a lot: 1. **Lazy / on-demand tool registration** — only advertise a tool after the client first calls it (or via a `list_tools`/`enable_tool` handshake). 2. **Tool grouping / sub-servers** — split into smaller MCP servers (e.g. `rea-binary`, `rea-capture`, `rea-compare`, `rea-web`) so clients can attach only what they need. 3. **Configurable tool subset** — a flag/env/CLI option to enable only a named group of tools (e.g. `rea mcp --tools binary,decompile`) so the schema set is bounded. Right now the only workaround is to detach the rea MCP server entirely when not actively doing RE, which defeats the point of having it attached. ## Environment - `rea-agents@6.5.0` (latest) - Node 26 (also tested 22.x sandbox) - Client: Claude Code via 2api bridge → Qwen3.8-Flash
Author
Owner

@pablodiazjorge commented on GitHub (Oct 16, 2026):

This looks like Claude Code's tool search being turned off by the proxy, which may give you a workaround today. With a non-Anthropic ANTHROPIC_BASE_URL, Claude Code disables tool search and logs [ToolSearch:optimistic] disabled: ANTHROPIC_BASE_URL=… is not a first-party Anthropic host. It then sends every MCP schema with each request instead of deferring them. Setting ENABLE_TOOL_SEARCH=true in Claude Code's environment turns it back on, as long as the backend accepts it.

I measured this today for rea-lab, with Claude Code 2.1.296 against DeepSeek's Anthropic-compatible API and rea 6.4.0, on a trivial run (reply OK, no tools):

Setup Input tokens of the first request
Without rea 5,745
With rea, tool search off 127,161
With rea, ENABLE_TOOL_SEARCH=true 7,903

DeepSeek accepted it: the agent loaded rea's schemas on demand and its calls worked. I have not tried a Qwen bridge, so whether your backend handles the deferred tools is the open question.

Your dump was truncated, so the list stops at compare_web_captures; rea 6.4.0 advertises 153 tools, and 6.5.0 likely more, which fits the size you saw. The longer-term fix of advertising fewer tools is being discussed in #3246.

<!-- gh-comment-id:6210628794 --> @pablodiazjorge commented on GitHub (Oct 16, 2026): This looks like Claude Code's tool search being turned off by the proxy, which may give you a workaround today. With a non-Anthropic `ANTHROPIC_BASE_URL`, Claude Code disables tool search and logs `[ToolSearch:optimistic] disabled: ANTHROPIC_BASE_URL=… is not a first-party Anthropic host`. It then sends every MCP schema with each request instead of deferring them. Setting `ENABLE_TOOL_SEARCH=true` in Claude Code's environment turns it back on, as long as the backend accepts it. I measured this today for [rea-lab](https://github.com/pablodiazjorge/rea-lab), with Claude Code 2.1.296 against DeepSeek's Anthropic-compatible API and rea 6.4.0, on a trivial run (reply OK, no tools): | Setup | Input tokens of the first request | |---|---| | Without rea | 5,745 | | With rea, tool search off | 127,161 | | With rea, `ENABLE_TOOL_SEARCH=true` | 7,903 | DeepSeek accepted it: the agent loaded rea's schemas on demand and its calls worked. I have not tried a Qwen bridge, so whether your backend handles the deferred tools is the open question. Your dump was truncated, so the list stops at `compare_web_captures`; rea 6.4.0 advertises 153 tools, and 6.5.0 likely more, which fits the size you saw. The longer-term fix of advertising fewer tools is being discussed in #3246.
Author
Owner

@hj01857655 commented on GitHub (Oct 16, 2026):

Closing as duplicate of #3246, which already proposes REA_MCP_TOOL_FAMILIES (per-family tool scoping) and has measured data for this exact proxied / non-Anthropic-backend scenario. Folded the data point from here (314K prompt_tokens via a 2api bridge → Qwen3.8-Flash, ~430KB+ tools array, overflow_compacted 3/3) into a comment on #3246.

<!-- gh-comment-id:6210634483 --> @hj01857655 commented on GitHub (Oct 16, 2026): Closing as duplicate of #3246, which already proposes `REA_MCP_TOOL_FAMILIES` (per-family tool scoping) and has measured data for this exact proxied / non-Anthropic-backend scenario. Folded the data point from here (314K prompt_tokens via a 2api bridge → Qwen3.8-Flash, ~430KB+ tools array, overflow_compacted 3/3) into a comment on #3246.
Author
Owner

@hj01857655 commented on GitHub (Oct 16, 2026):

Duplicate of #3246 — see comment above.

<!-- gh-comment-id:6210635272 --> @hj01857655 commented on GitHub (Oct 16, 2026): Duplicate of #3246 — see comment above.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#1757
No description provided.