Describe the bug
FoundryToolbox connects its MCP session lazily on the first agent run and reuses that
connection for the lifetime of the toolbox. Because of how the MCP streamable-HTTP client is
structured, every subsequent POST is issued from the connect-time task context — so
get_request_context() inside httpx.Auth.auth_flow resolves to the first request's context,
and later requests forward a stale x-agent-foundry-call-id.
To Reproduce
- Build a
FoundryToolbox and attach it to a hosted agent.
- Bind a request context with call id
CALL-1 and run the agent (this connects the session).
- Bind a request context with call id
CALL-2 and run the agent again.
- Inspect the outbound headers on the second run's toolbox POSTs.
Observed: the second run still sends x-agent-foundry-call-id: CALL-1.
Expected: it sends CALL-2.
Root cause
mcp/client/streamable_http.py creates a task group at connect time and starts post_writer via
tg.start_soon (~lines 647/659), so all POSTs run in the task context captured at connect. The
call id is carried by a plain ContextVar in
azure/ai/agentserver/core/_request_context.py that is re-set per request, and a ContextVar
set in one task is not visible to a task started earlier from a different context. So the value
cannot cross that boundary no matter where it is read.
This also means the natural fix (reading the context inside auth_flow) does not work — I verified
that empirically; the auth flow observes only the connect-time value.
Impact
Scoped, but real. The service currently accepts the stale id — I confirmed that reading both
skill://index.json and a skill's SKILL.md succeeds even with a deliberately bogus call id —
so this does not break toolbox calls today. It does mean that any server-side use of the call id
(request correlation, tracing, per-call policy) attributes every toolbox call after the first to
the first request of the process.
The same pattern is present in the official sample
python/samples/04-hosting/foundry-hosted-agents/responses/foundry_toolbox_mcp_skills, so it is
not specific to a caller's wiring.
Expected behavior
Toolbox requests should carry the call id of the request that triggered them. That likely requires
either establishing the MCP session per request, or propagating the per-request context across the
connect-time task boundary explicitly rather than relying on ContextVar inheritance.
Platform
- Language: Python
- Package:
agent-framework-foundry-hosting
Describe the bug
FoundryToolboxconnects its MCP session lazily on the first agent run and reuses thatconnection for the lifetime of the toolbox. Because of how the MCP streamable-HTTP client is
structured, every subsequent POST is issued from the connect-time task context — so
get_request_context()insidehttpx.Auth.auth_flowresolves to the first request's context,and later requests forward a stale
x-agent-foundry-call-id.To Reproduce
FoundryToolboxand attach it to a hosted agent.CALL-1and run the agent (this connects the session).CALL-2and run the agent again.Observed: the second run still sends
x-agent-foundry-call-id: CALL-1.Expected: it sends
CALL-2.Root cause
mcp/client/streamable_http.pycreates a task group at connect time and startspost_writerviatg.start_soon(~lines 647/659), so all POSTs run in the task context captured at connect. Thecall id is carried by a plain
ContextVarinazure/ai/agentserver/core/_request_context.pythat is re-setper request, and aContextVarset in one task is not visible to a task started earlier from a different context. So the value
cannot cross that boundary no matter where it is read.
This also means the natural fix (reading the context inside
auth_flow) does not work — I verifiedthat empirically; the auth flow observes only the connect-time value.
Impact
Scoped, but real. The service currently accepts the stale id — I confirmed that reading both
skill://index.jsonand a skill'sSKILL.mdsucceeds even with a deliberately bogus call id —so this does not break toolbox calls today. It does mean that any server-side use of the call id
(request correlation, tracing, per-call policy) attributes every toolbox call after the first to
the first request of the process.
The same pattern is present in the official sample
python/samples/04-hosting/foundry-hosted-agents/responses/foundry_toolbox_mcp_skills, so it isnot specific to a caller's wiring.
Expected behavior
Toolbox requests should carry the call id of the request that triggered them. That likely requires
either establishing the MCP session per request, or propagating the per-request context across the
connect-time task boundary explicitly rather than relying on
ContextVarinheritance.Platform
agent-framework-foundry-hosting