Skip to content

Python: Apply header_provider headers to the MCP initialize handshake#7080

Draft
efranken wants to merge 2 commits into
microsoft:mainfrom
efranken:mcp-header-provider-initialize
Draft

Python: Apply header_provider headers to the MCP initialize handshake#7080
efranken wants to merge 2 commits into
microsoft:mainfrom
efranken:mcp-header-provider-initialize

Conversation

@efranken

@efranken efranken commented Jul 12, 2026

Copy link
Copy Markdown

Motivation & Context

MCPStreamableHTTPTool.header_provider only fires inside call_tool(). But the MCP initialize handshake happens earlier, during connect()/__aenter__() (_connect_on_owner), so servers that require auth on initialize (e.g. Azure AI Search MCP endpoints) get an immediate 401 before header_provider ever runs. The same gap affects load_tools()/load_prompts() when they run during the same connect pass.

Description & Review Guide

Major changes

  • Override _connect_on_owner on MCPStreamableHTTPTool to seed the _mcp_call_headers ContextVar from header_provider({}) before delegating to super()._connect_on_owner(...), the same pattern call_tool() already uses.
  • If header_provider raises on an empty dict (e.g. an implementation written only against call_tool()'s contract, like the existing mcp_api_key_auth.py sample), the exception is caught and logged rather than failing the connection. A real auth failure still surfaces via the server's own rejection of initialize, this only guards the opportunistic best-effort call.
  • Added regression tests: headers reach initialize(), the ContextVar doesn't leak past connect(), and a raising header_provider doesn't break connect().

Impact

  • header_provider now also applies to initialize, load_tools, and load_prompts during connect, not just call_tool(). No public API changes; existing header_provider implementations keep working unmodified.

Outstanding question: Is seeding headers for the whole _connect_on_owner call correct, or should it be scoped tighter to just session.initialize()?

AI assistance was used after several hours of research to ensure fix is inline with existing patterns.

Related Issue

Fixes #7079

Contribution Checklist

  • The code builds clean without any errors or warnings
  • All unit tests pass, and I have added new tests where possible
  • The PR follows the Contribution Guidelines
  • This PR is linked to an issue and there is no other open PR for this issue (see Related Issue above).
  • This is not a breaking change. If it is a breaking change, add the breaking change label (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.

MCPStreamableHTTPTool.header_provider was only invoked from call_tool(), so
servers that require auth on initialize() (e.g. Azure AI Search MCP endpoints)
rejected the connection with a 401 before header_provider ever ran. The same
gap affected load_tools()/load_prompts() calls issued during the same connect
pass.

Seed the _mcp_call_headers contextvar in an override of _connect_on_owner()
before delegating to the base implementation, mirroring the existing
call_tool() pattern. header_provider is invoked with {} at connect time since
no per-call kwargs exist yet; if that raises, the exception is logged and the
connection proceeds without headers rather than failing outright, since a
genuine auth failure still surfaces via the server's own rejection of
initialize().

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 12, 2026 20:30
@giles17 giles17 added the python Usage: [Issues, PRs], Target: Python label Jul 12, 2026
@efranken

Copy link
Copy Markdown
Author

@efranken please read the following Contributor License Agreement(CLA). If you agree with the CLA, please reply with the following information.

@microsoft-github-policy-service agree [company="{your company}"]

Options:

  • (default - no company specified) I have sole ownership of intellectual property rights to my Submissions and I am not making Submissions in the course of work for my employer.
@microsoft-github-policy-service agree
  • (when company given) I am making Submissions in the course of work for my employer (or my employer has intellectual property rights in my Submissions by contract or applicable law). I have permission from my employer to make Submissions and enter into this Agreement on behalf of my employer. By signing below, the defined term “You” includes me and my employer.
@microsoft-github-policy-service agree company="Microsoft"

Contributor License Agreement

@microsoft-github-policy-service agree

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes an authentication gap in the Python MCP HTTP tool by ensuring MCPStreamableHTTPTool.header_provider is applied during the MCP initialize handshake (and related connect-time loading), not only during call_tool(). This enables connecting to MCP servers that require auth headers on initialize (e.g., Azure AI Search MCP endpoints) without failing early with 401s.

Changes:

  • Seed the _mcp_call_headers ContextVar from header_provider({}) for the duration of _connect_on_owner(), so initialize() (and connect-time load_tools / load_prompts) can use the same header injection mechanism as call_tool().
  • Make connect-time header_provider({}) best-effort: exceptions are caught/logged and the connection proceeds without injected headers.
  • Add regression tests verifying headers are visible during initialize(), no contextvar leakage occurs after connect(), and a raising header_provider does not break connect().

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
python/packages/core/agent_framework/_mcp.py Apply header_provider-derived headers during connect/initialize by seeding _mcp_call_headers inside _connect_on_owner().
python/packages/core/tests/core/test_mcp.py Add regression tests covering connect-time header seeding, contextvar cleanup, and error-tolerant header_provider behavior.

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

Labels

python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: [Bug]: header_provider not applied to MCP initialize() request

3 participants