Skip to content

Python: FoundryToolbox forwards a stale x-agent-foundry-call-id after the first request #7690

Description

@westey-m

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

  1. Build a FoundryToolbox and attach it to a hosted agent.
  2. Bind a request context with call id CALL-1 and run the agent (this connects the session).
  3. Bind a request context with call id CALL-2 and run the agent again.
  4. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    pythonUsage: [Issues, PRs], Target: Python

    Type

    No type

    Projects

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions