You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Support per-run headers for MCP server calls #1969
Allow specifying HTTP headers for the MCP server for each run invocation, not only at initialization time. In multi-user or multi-tenant environments it’s often necessary to attach user-specific or session-specific headers (e.g., auth token, user-id, tenant-id) for each agent run.
Problem
Currently, the SDK supports configuring the MCP server client (URL, transport, static headers) at initialization. But if you need different headers per run (for example, different user tokens or metadata when the same agent is shared among users), there’s no direct hook to override or supply headers with each Runner.run() or Runner.run_streamed() invocation.
Proposed behaviour
Extend the Runner run() and run_streamed() methods to accept a new parameter (for example mcp_headers: dict[str, str] | None) that allows specifying HTTP headers for the MCP server just for that run.
Supports multi-user / multi-tenant scenarios where many users share an agent or MCP connection but need per-request credentials or context headers.
Avoids needing to recreate the MCP client for each user or each run just to change headers.
Simplifies agent orchestration when per-run metadata (e.g., user-id, request id) must be sent to the MCP server for authorization, analytics, or routing.
Backward compatibility & notes
If mcp_headers is not provided, behaviour remains unchanged (use init‐level headers).
The new parameter is optional, so existing code continues working without change.
Performance impact is minimal — just header injection per request.
Thanks for the idea, but this design does not work when a developer would like to pass the custom header only to MCP server A while having multiple MCP servers (A, B, C ...) for the agent. Attaching custom headers to an MCP server instance when initializing an Agent may work but I haven't verified if this approach works well:
# this is pseudo code; it does not yet workagent=Agent(
name="Assistant",
mcp_servers=[mcp_server.with_headers({
"X-User-ID": "123",
})],
)
I've thought more about this. Remote MCP servers often need authorization headers and similar credentials when establishing a connection. Therefore, passing these headers during the initialization of MCP server clients is the correct way to include them. Changing the headers later would require disconnecting the current session and reconnecting with a new set of headers. So, I believe the most practical solution is to create new MCP servers each time your app receives a user request.
@seratch I see your point. However, initializing a new MCP server for each user request introduces noticeable latency due to connection setup, which increases the time to first token. Maintaining a persistent connection and updating request headers dynamically could reduce this overhead.
What are the common practices here — do people typically cache server instances to avoid this, or just accept the added latency? I’m open to better approaches or suggestions. Thanks!
I've checked the underlying official MCP SDK's code too. Your app has to pass required custom headers when establishing a connection to a remote MCP server, so it's not feasible to override some of the headers for each tool call. If you have different authorization header for each user request, connecting to a remote MCP server per request is the only way to utilize the tools. If you need to pass only user ID etc., you may want to consider enhancing the backend MCP server to accept those data as part of request parameters.
"Your app has to pass required custom headers when establishing a connection to a remote MCP server, so it's not feasible to override some of the headers for each tool call."
However, with Streamable HTTP transport, each call_tool() invocation results in a new HTTP POST request over the established SSE stream. Technically, these per-request headers could be injected at the HTTP request level, not the connection level.
# Current: Static headers set at initializationmcp_server=MCPServerStreamableHttp(
params={
"url": "https://mcp.example.com/mcp",
"headers": {
"Authorization": "Bearer org-static-token", # Connection-level"X-Org-ID": "org-123"# Connection-level
}
}
)
# Desired: Per-request headers injected at tool call time# Request 1: User Aawaitsession.call_tool("list_devices", {...})
# HTTP headers: Authorization + X-Org-ID + X-Auth-Token: user-a-token# Request 2: User B awaitsession.call_tool("list_devices", {...})
# HTTP headers: Authorization + X-Org-ID + X-Auth-Token: user-b-token
Each call_tool() makes a fresh HTTP POST to the /mcp endpoint, so headers could theoretically be modified per-call without reconnecting the SSE stream.
Why Per-Request Connection is Problematic. Creating new MCP connections per-request causes:
~400-700ms latency penalty per request (connection establishment)
TCP connection exhaustion under load (thousands of users)
Resource overhead (one HTTP client per request vs singleton)
Our Current Workaround
We're exploring using contextvars + [httpx.Auth] to inject headers dynamically:
This makes per-request connections impractical for production multi-tenant deployment.
Questions
Is per-request header injection technically feasible for Streamable HTTP transport (since each tool call = new HTTP request). Or is there an MCP protocol constraint I'm missing?
Would the SDK consider supporting this via:
Option A: extra_headers parameter in [call_tool()]
Option B: Callback function to provide headers per-request
Option C: Context-based header injection (reading from [RunContextWrapper])
Are there other multi-tenant users with similar needs?
Related Use Cases
Multi-tenant SaaS where users share agent infrastructure
Per-user authorization/auditing requirements
Rate limiting per user (not per org)
User-specific data isolation enforced by MCP server
Would appreciate any guidance on whether this is feasible or if we should proceed with the workaround approach.
@damianoneill Thanks for sharing details. Two things I wanted to mention:
IIUC, it seems the underlying official MCP SDK does not allow passing headers for tool calls. If my observation here is not correct, technically it may be feasible to customize the headers per tool call
MCP servers may dynamically change the list of tools in response to list-tools call based on passed headers (especially authorization header); in this scenario, changing headers only for a tool call may result in a runtime permission error (e.g., this user is not allowed to call this tool; tool not found etc.)
If these issues could be resolved in a nice way, there is no reason to avoid this enhancement on our side.
Hi @seratch, thank you for the thoughtful response.
You mentioned:
"IIUC, it seems the underlying official MCP SDK does not allow passing headers for tool calls."
This is technically correct - the current SDK doesn't have a call_tool(..., extra_headers={}) parameter. However, I've filed a feature request in the python-sdk repository to add this capability:
This follows the precedent of read_timeout_seconds which was added for per-request timeout configuration (Issue #600). The implementation would merge connection-level headers with per-request headers at the HTTP transport layer without affecting the MCP protocol itself.
If this feature is accepted upstream, it would enable openai-agents-python to expose per-request headers naturally.
If Issue modelcontextprotocol/python-sdk#1509 is accepted, the feature could be extended to list_tools for per-request headers which should address your concerns regarding dynamic tool lists.
Once I know more on 1509, I'll drop a note on this ticket.
Ideally we could define tools as callable functions returning a configured tool that take RunContextWrapper so that tools could be configured at runtime with context, instead of a static tool.
PydanticAI implements it this way and it's pretty handy!
Activity
seratch commentedon Oct 21, 2025
Thanks for the idea, but this design does not work when a developer would like to pass the custom header only to MCP server A while having multiple MCP servers (A, B, C ...) for the agent. Attaching custom headers to an MCP server instance when initializing an Agent may work but I haven't verified if this approach works well:
seratch commentedon Oct 21, 2025
I've thought more about this. Remote MCP servers often need authorization headers and similar credentials when establishing a connection. Therefore, passing these headers during the initialization of MCP server clients is the correct way to include them. Changing the headers later would require disconnecting the current session and reconnecting with a new set of headers. So, I believe the most practical solution is to create new MCP servers each time your app receives a user request.
p-arndt commentedon Oct 21, 2025
@seratch I see your point. However, initializing a new MCP server for each user request introduces noticeable latency due to connection setup, which increases the time to first token. Maintaining a persistent connection and updating request headers dynamically could reduce this overhead.
What are the common practices here — do people typically cache server instances to avoid this, or just accept the added latency? I’m open to better approaches or suggestions. Thanks!
seratch commentedon Oct 22, 2025
I've checked the underlying official MCP SDK's code too. Your app has to pass required custom headers when establishing a connection to a remote MCP server, so it's not feasible to override some of the headers for each tool call. If you have different authorization header for each user request, connecting to a remote MCP server per request is the only way to utilize the tools. If you need to pass only user ID etc., you may want to consider enhancing the backend MCP server to accept those data as part of request parameters.
damianoneill commentedon Oct 23, 2025
Hi @seratch I hope your keeping well.
I'd like to revisit this for a specific use case that differs from the discussion above.
Our Architecture
We're using MCPServerStreamableHttp with a singleton connection pattern:
X-Auth-Tokenheader for authorization@seratch stated:
However, with Streamable HTTP transport, each
call_tool()invocation results in a new HTTP POST request over the established SSE stream. Technically, these per-request headers could be injected at the HTTP request level, not the connection level.Each
call_tool()makes a fresh HTTP POST to the/mcpendpoint, so headers could theoretically be modified per-call without reconnecting the SSE stream.Why Per-Request Connection is Problematic. Creating new MCP connections per-request causes:
Our Current Workaround
We're exploring using contextvars + [httpx.Auth] to inject headers dynamically:
Our application serves thousands of concurrent users, and the per-request connection
approach would require:
This makes per-request connections impractical for production multi-tenant deployment.
Questions
Related Use Cases
Would appreciate any guidance on whether this is feasible or if we should proceed with the workaround approach.
As always, thanks for your time.
Damian.
damianoneill commentedon Oct 23, 2025
Should add @seratch happy to contribute code if this is considered for planned new feature.
seratch commentedon Oct 23, 2025
@damianoneill Thanks for sharing details. Two things I wanted to mention:
If these issues could be resolved in a nice way, there is no reason to avoid this enhancement on our side.
damianoneill commentedon Oct 23, 2025
Hi @seratch, thank you for the thoughtful response.
You mentioned:
This is technically correct - the current SDK doesn't have a
call_tool(..., extra_headers={})parameter. However, I've filed a feature request in the python-sdk repository to add this capability:Issue: modelcontextprotocol/python-sdk#1509
The proposal adds an extra_headers parameter to ClientSession.call_tool():
This follows the precedent of read_timeout_seconds which was added for per-request timeout configuration (Issue #600). The implementation would merge connection-level headers with per-request headers at the HTTP transport layer without affecting the MCP protocol itself.
If this feature is accepted upstream, it would enable openai-agents-python to expose per-request headers naturally.
If Issue modelcontextprotocol/python-sdk#1509 is accepted, the feature could be extended to
list_toolsfor per-request headers which should address your concerns regarding dynamic tool lists.Once I know more on 1509, I'll drop a note on this ticket.
Thanks again,
Damian.
beall49 commentedon Oct 23, 2025
Just chiming in for support, this is a feature (per-run headers for auth) that would be super helpful for my group.
github-actions commentedon Oct 31, 2025
This issue is stale because it has been open for 7 days with no activity.
github-actions commentedon Nov 3, 2025
This issue was closed because it has been inactive for 3 days since being marked as stale.
hayescode commentedon Nov 26, 2025
Ideally we could define tools as callable functions returning a configured tool that take RunContextWrapper so that tools could be configured at runtime with context, instead of a static tool.
PydanticAI implements it this way and it's pretty handy!
https://ai.pydantic.dev/toolsets/#preparing-tool-definitions
DeoLeung commentedon Dec 1, 2025
+1, and better expose a way to inject meta as well into
call_tooldamianoneill commentedon Dec 1, 2025
@everyone this MR is blocked on the underlying sdk - modelcontextprotocol/python-sdk#1509 I've had a MR open for over a month at modelcontextprotocol/python-sdk#1515 without review. If anyone knows anybody on the python-sdk that could help with the review that would be really useful.
Thanks,
Damian.
wangxj03 commentedon Jan 8, 2026
+1 very nice feature. hope modelcontextprotocol/python-sdk#1509 will be accepted soon 🙏