Repository navigation
Python: Allow concurrent MCP calls with request-owned headers - #10147
Conversation
Code coverage overviewLanguages: Python Python / code-coverage/python
View coverage of the 3 most impacted files.
ℹ️ Calculations represent line coverage. Results may change as calculations are updated. Updated |
There was a problem hiding this comment.
🟡 Changes recommended
Critical lifecycle-barrier gaps can tear down sessions during active RPCs, and inherited header context can execute direct prompt calls under a stale identity.
2 open issues
What changed in this PR
This PR enables concurrent same-identity MCP HTTP calls in Python by replacing shared active headers with request-owned snapshots. It also coordinates session transitions and recovery with active operations.
Changes:
- Adds request-scoped headers, operation tracking, and separate admission and recovery timeout budgets.
- Updates Foundry Toolbox prompt handling, resource reads, and HTTP-client cleanup.
- Adds concurrency and lifecycle regression tests and documents the new behavior.
| File | Description |
|---|---|
skills/agent-framework-builder-python/references/integrations.md |
Documents MCP concurrency, ownership, and timeout semantics. |
python/packages/foundry_hosting/tests/test_toolbox.py |
Tests overlapping calls, token refresh, and shutdown coordination. |
python/packages/foundry_hosting/agent_framework_foundry_hosting/_toolbox.py |
Updates prompt identity handling, resource operations, and cleanup ordering. |
python/packages/core/tests/core/test_mcp.py |
Adapts recovery tests and verifies request-header snapshots. |
python/packages/core/tests/core/test_mcp_observability.py |
Updates recovery setup for connection-loss logging tests. |
python/packages/core/tests/core/test_mcp_http_auth.py |
Adds concurrency, identity-transition, timeout, cancellation, and recovery coverage. |
python/packages/core/tests/core/mcp_http_helpers.py |
Adds a deterministic HTTP request barrier for tests. |
python/packages/core/README.md |
Explains concurrency guarantees and separate timeout budgets. |
python/packages/core/AGENTS.md |
Records header-scoping and lifecycle coordination guidance. |
python/packages/core/agent_framework/_mcp.py |
Implements request snapshots, operation admission, shared recovery, and close-generation checks. |
Review effort: Balanced
There was a problem hiding this comment.
MAF Automated Review — Iteration 1
Result: Findings reported
Scope: full PR (1 commit(s)): 0693d64379ca
Model: gpt-5.6-sol
Overview
The change replaces mutable shared header state with owner-tagged request snapshots and adds strong lifecycle, cancellation, recovery, redirect, and identity-transition coverage. Direct tool, prompt, and Toolbox resource calls with the same effective identity can overlap while identity changes remain isolated. One residual admission path still serializes same-identity Agent.run() calls and can time out a concurrent run during a long MCP operation.
Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
1 verified finding remained after source verification (1 medium) across 1 file. Details are attached to the affected lines below.
Affected areas: python/packages/core/agent_framework/_mcp.py
|
I reproduced two edge cases on Resource reads during replacement initialization Connect under The read immediately raises Catalog pages surviving connection replacement During an explicit The completed discovery exposes Could we restart the complete catalog snapshot after replacing the connection, These are specific readiness/catalog-boundary cases; they don't argue against |
There was a problem hiding this comment.
MAF Automated Review — Iteration 2
Result: No findings
Scope: 1 net-new commit(s): 83cf19af70ca
Model: gpt-5.6-sol
Overview
This incremental commit fixes the previously reported same-identity Agent preparation serialization while extending lifecycle tracking to framework-owned static/client-header connections and separating direct-prompt identity resolution from generated-prompt runtime context. Request snapshots, identity reconciliation, exclusive lifecycle barriers, finally-based operation release, and focused concurrency, prompt, and Foundry Toolbox regressions provide concrete guardrails. No Critical, High, or Medium defect introduced by this review range remains supported after reconciliation.
Reviewed the supplied incremental change set across correctness, security/reliability, architecture, and failure behavior.
No publishable findings remained after source verification for this scope.
Jose Alvarez (jpalvarezl)
left a comment
There was a problem hiding this comment.
Overall, I like the request-owned direction. I have two robustness concerns and one documentation request:
-
_MCPHeaderScopedClienttagsstream,send, anddelete, but__getattr__silently delegates other request entry points to the underlying client. If a future MCP transport switches torequest()orpost(), the owner extension would not be added and the dynamic-header hook would skip the request without an obvious failure. Could we either wrap the central request path as well, or fail explicitly for untagged sending methods? A focused regression test through an alternate request method would also make this dependency clear. -
_MCPHTTPInvocation.activeis a boolean, so if the same invocation ever re-enters_http_operation(), the innerfinallywill clear it while the outer operation is still running. The current call flow may prevent that today, but the state machine relies on that invariant. Could we use an active-depth counter, or add an assertion and focused test proving same-invocation re-entry cannot happen? -
Could we carry over the ADR from #10142, or add an equivalent, explaining why request-owned snapshots were selected over call-level same-identity leases? The concurrency and lifecycle contract is subtle, particularly around nested callbacks, identity transitions, and exclusive operations, and recording those invariants would help future maintainers.
Pull request was closed
There was a problem hiding this comment.
MAF Automated Review — Iteration 3
Result: No findings
Scope: 15 net-new commit(s): df7d02bdc99c, e9292752c1ea, 18cd5903b902, 2fa7b9ab21be, 0c479365fca9, 83c719065840, 4ffc820cd62d, 082217287cb4, 6e770b95c033, d0e191cf4d3d, 44f5495c0851, 9db7efb0841b, 80d0cbf5bc30, 28163f5e23d2, ffaeb4f0269d
Model: gpt-5.6-sol
Overview
The change replaces mutable shared-header state with request-owned snapshots and short-lived operation leases, allowing same-identity MCP calls to overlap while preserving exclusive identity transitions and lifecycle teardown. Owner tags, redirect stripping, generation-fenced recovery, caller-owned connection checks, and extensive concurrency/cancellation tests provide concrete guardrails. No publishable Critical, High, or Medium defect introduced by the reviewed range remained after reconciliation.
Reviewed the supplied incremental change set across correctness, security/reliability, architecture, and failure behavior.
No publishable findings remained after source verification for this scope.
|
Addressed the robustness and ADR feedback and the resource/discovery repros in 9f5489d.
The selected MCP/Toolbox regressions and both packages’ five configured test checkers pass. Strict source typing, lint, and formatting also pass. The PR description now reflects the current implementation and commands. |
Release all 44 publishing workspace distributions with shipping changes since python-1.24.0, including the Python 3.10 removal. Use the approved minor bumps for Core/root, AG-UI, and Declarative, patch bumps for other changed stable integrations, and 261106 stamps for changed alpha/beta packages; no optional cohort-only bump. Update the Core standard-install cohort, apply strict API-based Core floors, and align exact hosting pins. Include the four Python Dependabot updates and the reviewed release batch manifest. Changelog includes the anticipated microsoft#10147 fix; the draft must wait for that PR to merge and be incorporated before release. Lab remains excluded from publication, with only its dependency lock updated.
* Bump Python package versions for 1.25.0 release Release all 44 publishing workspace distributions with shipping changes since python-1.24.0, including the Python 3.10 removal. Use the approved minor bumps for Core/root, AG-UI, and Declarative, patch bumps for other changed stable integrations, and 261106 stamps for changed alpha/beta packages; no optional cohort-only bump. Update the Core standard-install cohort, apply strict API-based Core floors, and align exact hosting pins. Include the four Python Dependabot updates and the reviewed release batch manifest. Changelog includes the anticipated microsoft#10147 fix; the draft must wait for that PR to merge and be incorporated before release. Lab remains excluded from publication, with only its dependency lock updated. * Fix SQL Server cancellation test exception-info narrowing * Retain deprecated declarative MCP cache parameter and correct release notes Accept legacy positive cache_max_size values with a deprecation warning, without restoring initialized-session caching. Keep per-invocation security isolation and the approved 1.5.0 version, document the compatibility behavior and remaining lifecycle migration, and extend real-protocol isolation tests for explicit legacy values. Remove the changelog claim and reference for still-open PR microsoft#9617. * Simplify deprecated MCP cache parameter handling and undo skill edits

Motivation & Context
Concurrent calls through one
FoundryToolboxor anMCPStreamableHTTPToolwith aheader_providercurrently serialize across the entire RPC, even when their effective headers are identical. Independent calls scheduled withasyncio.gather()therefore cannot overlap.Scope headers to each outgoing HTTP request and allow operations with the same effective header identity to share a session concurrently. Preserve isolation when identity changes, including discovery, recovery, and connection cleanup.
Description & Review Guide
request()path and rejects unsupported untagged sending methods. Invocation depth preserves outer activity during nested operation scopes. The existing MCP lifecycle ADR records these invariants and the design tradeoffs.request_timeoutalso bounds admission/reconciliation and recovery as separate budgets;Nonedisables those budgets. These are not end-to-end deadlines and do not wrap the admitted RPC or lifecycle cleanup. Calls still share server-side MCP session state, so applications must order state-dependent operations themselves.From
python/,.venv/bin/python -m pytest packages/core/tests/core/test_mcp.py packages/core/tests/core/test_mcp_http_auth.py packages/core/tests/core/test_mcp_observability.py packages/core/tests/core/test_mcp_skills.py packages/foundry_hosting/tests/test_toolbox.py --import-mode=importlib -m 'not integration' --tb=short --disable-warningspassed: 1,526 passed, 3 skipped, 2 deselected. Existing deprecation and telemetry warnings remain. This is the relevant regression selection, not a full-workspace unit sweep.From
python/,uv run --no-sync poe test-typing -P coreanduv run --no-sync poe test-typing -P foundry_hostingboth passed, including all five configured test checkers for each package.From the repository root,
uvx --from ruff==0.17.3 ruff check python/packages/core/agent_framework/_mcp.py python/packages/core/tests/core/test_mcp.py python/packages/core/tests/core/test_mcp_http_auth.py python/packages/core/tests/core/mcp_http_helpers.py python/packages/foundry_hosting/agent_framework_foundry_hosting/_toolbox.py python/packages/foundry_hosting/tests/test_toolbox.pyanduvx --from ruff==0.17.3 ruff format --check python/packages/core/agent_framework/_mcp.py python/packages/core/tests/core/test_mcp.py python/packages/core/tests/core/test_mcp_http_auth.py python/packages/core/tests/core/mcp_http_helpers.py python/packages/foundry_hosting/agent_framework_foundry_hosting/_toolbox.py python/packages/foundry_hosting/tests/test_toolbox.pyboth passed.From
python/,uvx --from pyright==1.1.414 pyright --pythonpath .venv/bin/python --project pyproject.toml packages/core/agent_framework/_mcp.py packages/foundry_hosting/agent_framework_foundry_hosting/_toolbox.pypassed, with no errors or warnings.Related Issue
No linked GitHub issue. Maintainer-directed implementation review; this is not presented as a trivial-change or repository-automation exception.
AI Assistance
AI assistance details: Copilot assisted with design, implementation, regression tests, documentation, and this PR description.
Contribution Checklist
breaking changelabel (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.