Skip to content

fix: inject deferred MCP tools into system prompt and lift selectSearch cap - #343

Open
OliverZou wants to merge 1 commit into
usewhale:mainfrom
OliverZou:fix/mcp-tools-lost
Open

fix: inject deferred MCP tools into system prompt and lift selectSearch cap#343
OliverZou wants to merge 1 commit into
usewhale:mainfrom
OliverZou:fix/mcp-tools-lost

Conversation

@OliverZou

Copy link
Copy Markdown
Contributor

Summary

Two issues left the agent blind to available MCP tools:

  1. The system prompt had no visibility into which MCP tools exist. The <available-deferred-tools> block was only surfaced inside tool_search responses, so the agent could not discover MCP tools without first knowing to call tool_search — a discoverability deadlock.

  2. tool_search capped exact-name (select:) queries at maxSearchResults=5, silently dropping the rest even when the user explicitly named them.

Fixes:

  • Inject <available-deferred-tools> into every turn via a dynamic system block so the agent always knows what MCP tools are available.
  • Cap the block at 4000 characters (newline-boundary truncation) with an omission notice so many tools don't blow up the prompt.
  • Remove the maxSearchResults cap from selectSearch so select: queries return every requested tool, not just the first five.
  • Show all tool names (not just the first five) in tool_search no-match hints, aligning with the new system-prompt visibility.
  • Add tests for the new render path, selectSearch cap removal, truncation behavior, and updated hint format.

Validation

  • Local test-windows — 7/7 packages pass
  • Focused tests — all relevant suites pass
  • Linux CI — deferred to GitHub Actions

User-visible impact

  • System prompt: each turn now includes an <available-deferred-tools> block listing all connected MCP tools.
  • tool_search no-match hints: now show all tool names with a total count, no more silent truncation to five.
  • tool_search select: queries: no longer capped at 5 results.

Breaking changes

None.

Notes

  • The 4000-character cap prevents system-prompt blowup when many MCP tools are registered.
  • Test coverage added in deferred_test.go, mcp_runtime_test.go, and catalog_mcp_test.go.

…ch cap

Two issues left the agent blind to available MCP tools:

1. The system prompt had no visibility into which MCP tools exist. The
   <available-deferred-tools> block was only surfaced inside tool_search
   responses, so the agent could not discover MCP tools without first
   knowing to call tool_search — a discoverability deadlock.

2. tool_search capped exact-name (select:) queries at maxSearchResults=5,
   silently dropping the rest even when the user explicitly named them.

Fixes:
- Inject <available-deferred-tools> into every turn via a dynamic system
  block so the agent always knows what MCP tools are available.
- Cap the block at 4000 characters (newline-boundary truncation) with an
  omission notice so many tools don't blow up the prompt.
- Remove the maxSearchResults cap from selectSearch so select: queries
  return every requested tool, not just the first five.
- Show all tool names (not just the first five) in tool_search no-match
  hints, aligning with the new system-prompt visibility.
- Add tests for the new render path, selectSearch cap removal, truncation
  behavior, and updated hint format.
@OliverZou
OliverZou force-pushed the fix/mcp-tools-lost branch from 70956fc to 36054dc Compare July 18, 2026 17:38
@shayne-snap

Copy link
Copy Markdown
Contributor

Sorry for the late review, and thank you for putting this fix together. I have now gone through the implementation and left a few inline comments below.

Comment thread internal/app/runtime.go
agent.WithHookRunner(a.hookRunner),
agent.WithExtraSystemBlocks(pluginBlocks...),
agent.WithDynamicSystemBlocksForTurn(a.workflowDynamicSystemBlock),
agent.WithDynamicSystemBlocks(func() string { return a.renderDeferredToolsBlock() }),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WithDynamicSystemBlocks replaces a.dynamicSystemBlocks instead of appending to it, so this call drops the workflowDynamicSystemBlock registered on the previous line. That removes the workflow runtime guidance, authoring rules, and prompt catalog from every turn. I reproduced this with an option-composition test: the deferred-tools block remains, but the workflow block is missing. Could we register both renderers in a single WithDynamicSystemBlocksForTurn call, or otherwise make the option composition append safely, and add a regression test that asserts both blocks are present?

longLine := strings.Repeat("x", availableDeferredToolsMaxChars+100)
block := "<available-deferred-tools>\n[server: test]\n mcp__test__tool — " + longLine + "\n</available-deferred-tools>"

// Apply the same truncation logic as renderDeferredToolsBlock.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test duplicates the truncation algorithm instead of calling renderDeferredToolsBlock, so it can stay green even if the production implementation regresses. Could we build a catalog whose rendered output exceeds the limit and assert against the actual method result? That would also let the test verify the reported omitted count and the real output-size behavior.

Comment thread internal/mcp/deferred.go
if len(results) >= maxSearchResults {
break
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changes exact select: queries to return an unbounded number of explicitly requested tools, but the tool_search schema still says that the tool returns up to five matching tools. Could we update that description to clarify that only keyword and must-have searches are capped, while select: returns every requested match?

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.

2 participants