Repository navigation
Description
🔴 Required Information
Describe the Bug:
With McpToolset(use_mcp_resources=True), MCP resources are listed and read without the headers the toolset sends for tool calls. McpToolset._build_headers resolves header_provider and the per-user credential (credential_key) from the request context. LoadMcpResourceTool calls list_resources() and read_resource(name) without passing any context, so on any server that authenticates requests, resources fail while tools from the same toolset work.
The failure is only logged as a warning ("Failed to list MCP resources …" / "Failed to read MCP resource …"). The model is never told the resources exist, and load_mcp_resource calls return nothing.
Steps to Reproduce:
- Run a streamable-HTTP MCP server that exposes a resource and returns 401 without
Authorization: Bearer user-token. - Give an
LlmAgentanMcpToolset(connection_params=StreamableHTTPConnectionParams(url=...), header_provider=lambda ctx: {"Authorization": "Bearer user-token"}, use_mcp_resources=True). - Run a turn in which the model calls
load_mcp_resource(resource_names=["handbook"]).
Expected Behavior:
The resource list goes into the instructions, and the resource content is attached after the call, using the same headers as the toolset's tools.
Observed Behavior:
Failed to list MCP resources: Failed to create MCP session: ... Server returned an error response
Failed to list MCP resources: Failed to create MCP session: ... Server returned an error response
Failed to read MCP resource 'handbook': Failed to create MCP session: ... Server returned an error response
resource list offered to the model: False
resource content attached: False
server-side 401s: 3
Environment Details:
- ADK Library Version (pip show google-adk): 2.13.0 (also on
mainat 58332a2) - Desktop OS: macOS
- Python Version (python -V): 3.11.16
Model Information:
- Are you using LiteLLM: No
- Which model is being used: a scripted
BaseLlm(the bug is in the tool, not the model)
🟡 Optional Information
Additional Context:
src/google/adk/tools/load_mcp_resource_tool.py, _append_resources_to_llm_request:
resource_names = await self._mcp_toolset.list_resources()
...
contents = await self._mcp_toolset.read_resource(resource_name)Both methods accept readonly_context. McpToolset._build_headers only calls header_provider when one is passed, and _get_auth_headers uses it to look up credential_key. get_tools already passes it, which is why tools work.
Minimal Reproduction Code:
# Server: MCPServer with @server.resource("docs://handbook", name="handbook"),
# served by streamable_http_app() behind middleware that returns 401 without
# "Authorization: Bearer user-token".
toolset = McpToolset(
connection_params=StreamableHTTPConnectionParams(url="http://127.0.0.1:8799/mcp"),
header_provider=lambda ctx: {"Authorization": "Bearer user-token"},
use_mcp_resources=True,
)
agent = LlmAgent(name="assistant", model=scripted_model, tools=[toolset])
# scripted_model calls load_mcp_resource(resource_names=["handbook"]) and then answers.How often has this issue occurred?:
- Always (100%)
Activity
fix: send the request's headers when loading MCP resources