Skip to content

fix: MCPToolResolver._resolve_native() UnboundLocalError when no tools found (#5116)#5118

Open
devin-ai-integration[bot] wants to merge 2 commits intomainfrom
devin/1774549543-fix-mcp-resolve-native-unbound-tools-list
Open

fix: MCPToolResolver._resolve_native() UnboundLocalError when no tools found (#5116)#5118
devin-ai-integration[bot] wants to merge 2 commits intomainfrom
devin/1774549543-fix-mcp-resolve-native-unbound-tools-list

Conversation

@devin-ai-integration
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot commented Mar 26, 2026

Summary

Fixes #5116. MCPToolResolver._resolve_native() raised UnboundLocalError on tools_list when:

  • The MCP server returned no tools
  • A tool_filter removed all tools
  • An inner RuntimeError was caught but didn't match the "cancel scope" / "task" conditions, silently swallowing the exception and leaving tools_list unassigned

Changes:

  1. Initialize tools_list: list[dict[str, Any]] = [] before the try block so it is always bound
  2. Add early return with a "warning" log when tools_list is empty after discovery + filtering — matching the existing behavior in _resolve_external()

Three new tests cover: empty server response, filter-removes-all, and swallowed RuntimeError.

Review & Testing Checklist for Human

  • Verify that silently returning empty tools (with warning) is acceptable for all swallowed RuntimeError paths (lines 367-381). Previously these crashed with UnboundLocalError; now they return ([], []). Consider whether some of these errors (e.g. a genuine connection failure whose message doesn't contain "cancel scope" or "task") should instead propagate to the caller rather than being silently degraded to an empty tool list.
  • Manual test: configure an agent with an MCP server (Stdio/HTTP/SSE) that either has no tools or uses a tool_filter returning nothing, run a task, and confirm a clear warning appears instead of a 500-level traceback.

Notes

  • The warning message format ("No tools discovered from MCP server: {server_name}") is intentionally consistent with the existing message in _resolve_external().
  • The unused asyncio import flagged in the initial review has been removed in a follow-up commit.

Link to Devin session: https://app.devin.ai/sessions/7bfda4a03b3b49e780771f30d635512f

… tools found

Fixes #5116. MCPToolResolver._resolve_native() could raise UnboundLocalError
when asyncio.run() raised a RuntimeError that didn't match the 'cancel scope'
or 'task' conditions — the exception was silently swallowed leaving tools_list
unbound.

Changes:
- Initialize tools_list to an empty list before the try block
- Add early return with warning log when tools_list is empty (matching
  the existing behavior in _resolve_external)

This covers three scenarios:
1. MCP server returns no tools
2. tool_filter removes all tools
3. RuntimeError swallowed without assigning tools_list

Co-Authored-By: João <joao@crewai.com>
@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

Prompt hidden (unlisted session)

@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

Co-Authored-By: João <joao@crewai.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] MCPToolResolver does not log warning when native MCP config returns no tools

0 participants