Skip to content

fix(mcp): send the request's headers when loading MCP resources - #7823

Closed
adityasingh2400 wants to merge 1 commit into
google:mainfrom
adityasingh2400:fix/mcp-resources-send-request-headers
Closed

adityasingh2400 wants to merge 1 commit into
google:mainfrom
adityasingh2400:fix/mcp-resources-send-request-headers

Conversation

@adityasingh2400

Copy link
Copy Markdown
Contributor

Please ensure you have read the contribution guide before creating a pull request.

Link to Issue or Description of Change

1. Link to an existing issue (if applicable):

Problem:
LoadMcpResourceTool called McpToolset.list_resources() and read_resource(name) without a context. McpToolset._build_headers only calls header_provider when it gets a context, and _get_auth_headers uses the context to look up the per-user credential (credential_key). So resources were fetched without the headers the toolset's tools are called with. On a server that authenticates requests, every resource call failed, and the failure was only logged as a warning: the model was never told the resources exist, and load_mcp_resource returned nothing.

Solution:
Pass tool_context as readonly_context to both calls, as get_tools already does. Resource requests now carry the same header_provider headers and user credential as tool calls, and they reuse the same pooled session.

Testing Plan

Unit Tests:

  • I have added or updated unit tests for my change.
  • All unit tests pass locally.

In tests/unittests/tools/test_load_mcp_resource_tool.py:

  • New test_process_llm_request_sends_request_headers: a real McpToolset with a header_provider and a mocked session manager. It asserts that the provider is called with the tool context and that every session is opened with its headers.
  • test_process_llm_request_with_prior_parts now expects read_resource("res1", readonly_context=tool_context).
# On main (before the fix)
AssertionError: expected call not found.   # read_resource got no readonly_context
AssertionError: assert []                   # header_provider never called
2 failed, 6 passed

# With the fix
$ pytest tests/unittests/tools/test_load_mcp_resource_tool.py tests/unittests/tools/mcp_tool
461 passed

pre-commit run passes on the changed files, and mypy reports no issues in load_mcp_resource_tool.py.

Manual End-to-End (E2E) Tests:

The test server is a streamable-HTTP MCPServer exposing resource handbook, behind middleware that returns 401 without Authorization: Bearer user-token. The client is a Runner with an LlmAgent holding McpToolset(StreamableHTTPConnectionParams(url=...), header_provider=lambda ctx: {"Authorization": "Bearer user-token"}, use_mcp_resources=True). The scripted model calls load_mcp_resource(resource_names=["handbook"]) and then answers. The setup is in #7822.

=== BEFORE (main) ===
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
=== AFTER (this PR) ===
resource list offered to the model: True
resource content attached: True
server-side 401s: 0

Tool listing worked in both runs, because get_tools already passes the context.

Checklist

  • I have read the CONTRIBUTING.md document.
  • I have performed a self-review of my own code.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have added tests that prove my fix is effective or that my feature works.
  • New and existing unit tests pass locally with my changes.
  • I have manually tested my changes end-to-end.
  • Any dependent changes have been merged and published in downstream modules.

Additional context

None.

LoadMcpResourceTool listed and read resources without passing the tool
context. McpToolset resolves header_provider and the per-user credential
from that context, so resources were fetched unauthenticated while the
same toolset's tools were not, and a server that authenticates requests
rejected every resource call. Pass tool_context to list_resources and
read_resource.

Fixes google#7822
copybara-service Bot pushed a commit that referenced this pull request Oct 30, 2026
Merge #7823

LoadMcpResourceTool now passes its tool context to McpToolset.list_resources and read_resource, so resource requests carry the header_provider headers and per-user credential that tool calls already send.

Fixes #7822

PiperOrigin-RevId: 1010833747
@adk-bot

adk-bot commented Oct 30, 2026

Copy link
Copy Markdown
Collaborator

Thank you @adityasingh2400 for your contribution! 🎉

Your changes have been successfully imported and merged via Copybara in commit 28d4975.

Closing this PR as the changes are now in the main branch.

@adk-bot adk-bot added the merged [Status] This PR is merged label Oct 30, 2026
@adk-bot adk-bot closed this Oct 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merged [Status] This PR is merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MCP resources are listed and read without the toolset's header_provider headers or user credential

3 participants