microsoft / microsoft/agent-framework

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

Open
#7,690 1 comment 0 reactions 1 assignee View on GitHub

@TaoChenOSU is already working on this.

Since Aug 18, 2026.

python
Dominant language
Python
Stars
13.6k
Forks
2.3k
Avg merge
2d 45m
Merged PRs (30d)
358

Description

### 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`

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.