Skip to content

[bug]: agent dynamic tool discovery fails with enable_mcp_without_auth() #115

Open

Description

@gotsysdba

When an agent uses MCPToolBox for dynamic tool discovery, the tools are not created during load_component() they are discovered lazily at execution time via get_tools_async(). This call runs through the portal, where the _GLOBAL_ENABLED_MCP_WITHOUT_AUTH ContextVar has never been set, causing _validate_auth to raise.

Following a similar pattern to _ACTIVE_SPAN_STACK for _GLOBAL_ENABLED_MCP_WITHOUT_AUTH would resolve this.

Failure sequence

  1. Application calls enable_mcp_without_auth() [main async context]
  2. Application calls loader.load_component(agent) [main async context]
  3. MCPToolBox created, stores transport reference [no tool discovery yet]
  4. Agent conversation executes
  5. _collect_tools() → toolbox.get_tools_async()
  6. AsyncRuntime.call_async() → to_thread.run_sync() [worker thread, context copied]
  7. portal.call() [portal thread, SEPARATE context]
  8. get_server_tools_from_mcp_server() → MCPTool()
  9. _validate_auth() → _is_mcp_without_auth_enabled() [returns False — flag not set here]
  10. ValueError raised

Error output

ValueError: Using MCP servers without proper authentication is highly discouraged.
If you still want to use it, please call `enable_mcp_without_auth` before instantiating the MCPToolBox.

Activity

  1. gotsysdba commented on Mar 10, 2026

    @gotsysdba
    MemberAuthor

    This is issue is a bit complicated... depending on the original intention.


    If _GLOBAL_ENABLED_MCP_WITHOUT_AUTH is meant to be a per-request toggle (as it is now), then a modification is needed to ensure it is propagated between two boundries to resolve the original error while dynamically discovering tools:

    1. call_async() → worker thread: to_thread.run_sync spawns a new thread — currently it resets to False
    2. call() → portal task: portal.call dispatches into the BlockingPortal's background loop — a separate async context where it is again resets to False

    Implementing a fix for this allows multi-transport scenarios where one server needs auth and another doesn't; but does require the calling app to set enable_mcp_without_auth() on each request


    If there was no intention to make this per-request but rather per-process, then changing _GLOBAL_ENABLED_MCP_WITHOUT_AUTH from a ContextVar to a plain bool resolves the existing per-request boundry issues, eliminates the need for the calling app to set enable_mcp_without_auth() on each request but it breaks a auth/no-auth multi-transport scenario.


    Finally, _GLOBAL_ENABLED_MCP_WITHOUT_AUTH could potentially be changed to a per-transport flag where each transport carries its own settings allowing the auth/no-auth multi-transport scenario, no ContextVar or propagation issues; but this looks to be a much bigger change.

  2. gotsysdba commented on Mar 18, 2026

    @gotsysdba
    MemberAuthor

    Current workaround: instead of calling enable_mcp_without_auth before instantiating of the MCPToolBox, call before each execution.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions