crewai - ✅(Solved) Fix [BUG] MCPToolResolver does not log warning when native MCP config returns no tools [2 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
crewAIInc/crewAI#5116Fetched 2026-04-08 01:40:04
View on GitHub
Comments
1
Participants
2
Timeline
10
Reactions
0
Timeline (top)
cross-referenced ×4referenced ×4commented ×1labeled ×1

MCPToolResolver._resolve_native() silently returns an empty tool list when:

The MCP server returns no tools, or The tool_filter removes all tools.

The empty tools_list can trigger the error at tool_resolver.py", line 412:

for tool_def in tools_list:
                  ^^^^^^^^^^
UnboundLocalError: cannot access local variable 'tools_list' where it is not associated with a value

There is no warning logged, making it very hard for users to understand why their MCP server (Stdio / HTTP / SSE) is not providing any tools. In contrast, _resolve_external() (for HTTPS URLs) does log a clear warning:

No tools discovered from MCP server: {server_url}

Error Message

for tool_def in tools_list: ^^^^^^^^^^ UnboundLocalError: cannot access local variable 'tools_list' where it is not associated with a value

Root Cause

MCPToolResolver._resolve_native() silently returns an empty tool list when:

The MCP server returns no tools, or The tool_filter removes all tools.

The empty tools_list can trigger the error at tool_resolver.py", line 412:

for tool_def in tools_list:
                  ^^^^^^^^^^
UnboundLocalError: cannot access local variable 'tools_list' where it is not associated with a value

There is no warning logged, making it very hard for users to understand why their MCP server (Stdio / HTTP / SSE) is not providing any tools. In contrast, _resolve_external() (for HTTPS URLs) does log a clear warning:

No tools discovered from MCP server: {server_url}

Fix Action

Fixed

PR fix notes

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

Description (problem / solution / changelog)

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

Changed files

  • lib/crewai/src/crewai/mcp/tool_resolver.py (modified, +8/-0)
  • lib/crewai/tests/mcp/test_amp_mcp.py (modified, +112/-0)

PR #5130: fix(mcp): prevent UnboundLocalError and log warning when native MCP returns no tools

Description (problem / solution / changelog)

Closes #5116

Problem

MCPToolResolver._resolve_native() has two issues:

  1. UnboundLocalError: When the MCP server connection raises a RuntimeError that doesn't contain "cancel scope" or "task" in its message, the exception is silently swallowed (not re-raised). This leaves tools_list unassigned, causing UnboundLocalError: cannot access local variable 'tools_list' where it is not associated with a value at the iteration loop (line 412).

  2. No warning for empty tools: When the MCP server returns no tools (or tool_filter removes all tools), no warning is logged. In contrast, _resolve_external() logs a clear warning: "No tools discovered from MCP server: {server_url}".

Fix

  1. Re-raise unrecognized RuntimeError: Added raise at the end of the RuntimeError handler so that non-cancel-scope errors propagate instead of being silently swallowed.

  2. Log warning and return early: Added checks after getting tools_list and after tool filtering to log a warning and return ([], []) when no tools are available, matching _resolve_external() behavior.

Changes

  • lib/crewai/src/crewai/mcp/tool_resolver.py: +14 lines
<!-- CURSOR_SUMMARY -->

[!NOTE] Low Risk Low risk: small control-flow and logging changes in MCP native tool discovery; main impact is different error propagation and earlier returns when no tools are available.

Overview Fixes native MCP tool resolution to avoid silently swallowing unexpected RuntimeErrors during discovery (preventing an UnboundLocalError later) by re-raising unrecognized runtime errors.

Adds explicit empty-results handling: logs a warning and returns ([], []) when the MCP server returns no tools, and when tool_filter removes all tools, aligning behavior with external MCP resolution.

<sup>Written by Cursor Bugbot for commit 42cbee540559b0ea315f2b08873bfac4bfb80c6c. This will update automatically on new commits. Configure here.</sup>

<!-- /CURSOR_SUMMARY -->

Changed files

  • lib/crewai/src/crewai/mcp/tool_resolver.py (modified, +14/-0)

Code Example

for tool_def in tools_list:
                  ^^^^^^^^^^
UnboundLocalError: cannot access local variable 'tools_list' where it is not associated with a value

---

No tools discovered from MCP server: {server_url}

---

tools = []
            for tool_def in tools_list:
                tool_name = tool_def.get("name", "")
                original_tool_name = tool_def.get("original_name", tool_name)
                if not tool_name:
                    continue

---

Traceback (most recent call last):
  File ".../python3.12/site-packages/crewai/mcp/tool_resolver.py", line 412, in _resolve_native
    for tool_def in tools_list:
                    ^^^^^^^^^^
UnboundLocalError: cannot access local variable 'tools_list' where it is not associated with a value

---

if not tools_list:
                self._logger.log(
                    "warning",
                    f"No tools discovered from MCP server: {server_name}",
                )
                return cast(list[BaseTool], []), []
RAW_BUFFERClick to expand / collapse

Description

MCPToolResolver._resolve_native() silently returns an empty tool list when:

The MCP server returns no tools, or The tool_filter removes all tools.

The empty tools_list can trigger the error at tool_resolver.py", line 412:

for tool_def in tools_list:
                  ^^^^^^^^^^
UnboundLocalError: cannot access local variable 'tools_list' where it is not associated with a value

There is no warning logged, making it very hard for users to understand why their MCP server (Stdio / HTTP / SSE) is not providing any tools. In contrast, _resolve_external() (for HTTPS URLs) does log a clear warning:

No tools discovered from MCP server: {server_url}

Affected Code

File: crewai/mcp/tool_resolver.py Method: MCPToolResolver._resolve_native() (around line 412, right after tool filtering)

Steps to Reproduce

  1. Configure an agent with a native MCP server via MCPServerStdio, MCPServerHTTP, or MCPServerSSE that either has no tools or uses a tool_filter that returns nothing.
  2. Add it to the agent’s mcps list.
  3. Run the agent/task → zero tools are available and no warning appears in the logs.

Expected behavior

A clear warning should be logged when no tools are discovered after listing + filtering, exactly like the external resolver path. Instead of the current 500 Error.

Screenshots/Code snippets

            tools = []
            for tool_def in tools_list:
                tool_name = tool_def.get("name", "")
                original_tool_name = tool_def.get("original_name", tool_name)
                if not tool_name:
                    continue

Operating System

Ubuntu 20.04

Python Version

3.12

crewAI Version

latest

crewAI Tools Version

latest

Virtual Environment

Venv

Evidence

Traceback (most recent call last):
  File ".../python3.12/site-packages/crewai/mcp/tool_resolver.py", line 412, in _resolve_native
    for tool_def in tools_list:
                    ^^^^^^^^^^
UnboundLocalError: cannot access local variable 'tools_list' where it is not associated with a value

Possible Solution

            if not tools_list:
                self._logger.log(
                    "warning",
                    f"No tools discovered from MCP server: {server_name}",
                )
                return cast(list[BaseTool], []), []

Additional context

It's an apparent bug.

extent analysis

Fix Plan

To fix the issue, we need to add a check for an empty tools_list and log a warning message. Here are the steps:

  • Modify the MCPToolResolver._resolve_native() method to check if tools_list is empty.
  • If tools_list is empty, log a warning message indicating that no tools were discovered from the MCP server.
  • Return an empty list of tools to prevent the UnboundLocalError.

Example code:

if not tools_list:
    self._logger.log(
        "warning",
        f"No tools discovered from MCP server: {server_name}",
    )
    return [], []

This code should be added right after the tools_list is filtered.

Verification

To verify that the fix worked, you can:

  • Configure an agent with a native MCP server that has no tools or uses a tool_filter that returns nothing.
  • Run the agent/task and check the logs for the warning message.
  • Verify that the UnboundLocalError is no longer raised.

Extra Tips

  • Make sure to test the fix with different scenarios, such as an empty tools_list and a non-empty tools_list.
  • Consider adding additional logging or error handling to make the code more robust.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

A clear warning should be logged when no tools are discovered after listing + filtering, exactly like the external resolver path. Instead of the current 500 Error.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

crewai - ✅(Solved) Fix [BUG] MCPToolResolver does not log warning when native MCP config returns no tools [2 pull requests, 1 comments, 2 participants]