Skip to content

Python: .NET/Python: Isolate declarative MCP client sessions by workflow - #8662

Open
Vincent Biret (baywet) wants to merge 65 commits into
mainfrom
fix/mcp-workflow-session-isolation
Open

Vincent Biret (baywet) wants to merge 65 commits into
mainfrom
fix/mcp-workflow-session-isolation

Conversation

@baywet

Copy link
Copy Markdown
Member

Motivation & Context

The default declarative MCP handlers cached connected clients by endpoint, label, connection name, and headers. When one handler instance served multiple workflow sessions, those sessions could therefore reuse the same stateful MCP protocol session. This change fixes the MCP client session isolation/cache scoping bug while preserving session continuity within one workflow session and the existing endpoint, header, label, and connection isolation.

Description & Review Guide

  • What are the major changes? Added framework-owned workflow session identity to the Python invocation contract and a workflow-scoped .NET handler contract, propagated trusted session IDs from workflow execution contexts, and included that identity in default MCP client cache keys. Added regression coverage for separate workflows, same-workflow continuation, cache-key discrimination, and concurrent cache creation.
  • What is the impact of these changes? Separate workflow sessions no longer share a stateful MCP protocol session through a shared default handler. Calls within the same workflow session continue to reuse the cached MCP client when all existing cache identity dimensions also match. Custom handlers using the existing .NET contract remain compatible.
  • What do you want reviewers to focus on? Please review the workflow-owned scope propagation and the compatibility behavior for custom handlers and direct unscoped handler calls.

Related Issue

No public issue is available for this MCP client session isolation/cache scoping bug.

Contribution Checklist

  • The code builds clean without any errors or warnings
  • All unit tests pass, and I have added new tests where possible
  • The PR follows the Contribution Guidelines
  • This PR is linked to an issue and there is no other open PR for this issue (see Related Issue above).
  • This is not a breaking change. If it is a breaking change, add the breaking change label (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 7ed91283-cb21-49a7-98f4-b1c088d0b6b6
Copilot AI balanced review requested due to automatic review settings September 22, 2026 18:08
@agent-framework-automation agent-framework-automation Bot added documentation Usage: [Issues, PRs], Target: documentation in the code base and learn docs python Usage: [Issues, PRs], Target: Python .NET Usage: [Issues, PRs], Target: .Net labels Sep 22, 2026
@agent-framework-automation agent-framework-automation Bot added the workflows Usage: [Issues, PRs], Target: Workflows label Sep 22, 2026
@github-actions github-actions Bot changed the title .NET/Python: Isolate declarative MCP client sessions by workflow .NET: .NET/Python: Isolate declarative MCP client sessions by workflow Sep 22, 2026
@github-actions github-actions Bot changed the title .NET: .NET/Python: Isolate declarative MCP client sessions by workflow Python: .NET/Python: Isolate declarative MCP client sessions by workflow Sep 22, 2026

This comment was marked as outdated.

@github-code-quality

github-code-quality Bot commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor

Code coverage overview

Languages: Python, C#

Python / code-coverage/python

main 9127b89 fix/mcp-workflow-ses... fde8d77 +/-
92% 92% 0%
View coverage of the 10 most impacted files.
File main 9127b89 fix/mcp-workflow-ses... fde8d77 +/-
packages/declar..._mcp_handler.py 98% 96% -2%
packages/declar...cutors_tools.py 99% 98% -1%
packages/declar...arative_base.py 93% 93% 0%
packages/declar...tive_builder.py 99% 99% 0%
packages/core/a...lows/_runner.py 98% 99% +1%
packages/core/a...ws/_workflow.py 94% 95% +1%
packages/core/a...flows/_agent.py 91% 92% +1%
packages/declar...xecutors_mcp.py 91% 92% +1%
packages/declar...utors_agents.py 91% 93% +2%
packages/core/a...low_executor.py 87% 89% +2%

C# / code-coverage/dotnet

main d12e4e9 fix/mcp-workflow-ses... fde8d77 +/-
86% 86% 0%
View coverage of the 8 most impacted files.
File main d12e4e9 fix/mcp-workflow-ses... fde8d77 +/-
/home/runner/wo...SessionStore.cs 100% 53% -47%
/home/runner/wo...unnerContext.cs 92% 92% 0%
/home/runner/wo...kflowContext.cs 81% 82% +1%
/home/runner/wo...pToolHandler.cs 88% 91% +3%
/home/runner/wo...rocessRunner.cs 91% 94% +3%
/home/runner/wo...pChatManager.cs 61% 64% +3%
/home/runner/wo...HostExecutor.cs 83% 86% +3%
/home/runner/wo...kflowBinding.cs 90% 93% +3%

ℹ️ Calculations represent line coverage. Results may change as calculations are updated.


Updated October 16, 2026 19:38 UTC

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAF Automated Review — Iteration 1

Result: Findings reported
Scope: full PR (1 commit(s)): bb9e92b189ed
Model: gpt-5.6-sol-fast

Overview

The change adds workflow identity to both default MCP cache keys while preserving the existing endpoint, label, connection, and header dimensions, and its regression tests cover normal isolation, continuation, and same-key creation coalescing. Provider-backed calls also retain their per-invocation lifecycle and shutdown guards. Two residual gaps remain: the .NET compatibility fallback is scoped to a reusable workflow object rather than an execution session, and Python's completed-entry LRU does not bound the now-per-workflow set of concurrent connection attempts.

Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
2 verified findings remained after source verification (2 medium) across 2 files. Details are attached to the affected lines below.

Affected areas: dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Interpreter/DeclarativeWorkflowContext.cs, python/packages/declarative/agent_framework_declarative/_workflows/_mcp_handler.py

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread python/packages/declarative/tests/test_default_mcp_tool_handler.py Fixed
Comment thread python/packages/declarative/tests/test_default_mcp_tool_handler.py Fixed

This comment was marked as outdated.

@baywet

Copy link
Copy Markdown
Member Author

Addressed the latest review summary item about .NET global client lock contention in current branch changes: cache misses now reserve/coalesce an in-flight creation under _clientLock, run CreateClientAsync outside the global lock, and publish/evict under the lock afterward. Added NoProvider_ConcurrentWorkflowSessionCreations_DoNotSerializeHandshakeAsync to cover concurrent workflow handshakes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 89548cb9-9583-47c1-a00f-675aebf810f8
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 48ae509d-294c-4bf5-864d-81baecbae204
@baywet

Copy link
Copy Markdown
Member Author

Addressed the response-only continuation identity finding from the review summary in d6c9526. WorkflowAgent no longer replaces the saved identity in either response-only branch; fresh-input turns still select their supplied agent identity. Four regressions restore a paused Question or RequestExternalInput checkpoint into a new workflow/AgentSession in streaming and non-streaming modes: all failed the downstream MCP scope-equality assertion before the change and pass afterward, without replaying the first tool call. The broader MCP/external-input/core-workflow run passes 1,797 cases (6 skipped, 1 expected failure). This commit also removes the unsupported Task.WaitAsync call from the new .NET regression; net472 compilation and all 48 net10.0 lifetime tests pass.

Comment thread python/pyproject.toml Outdated
@@ -1 +1,3 @@
#nullable enable
Microsoft.Agents.AI.Workflows.IWorkflowSessionContext

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

westey (@westey-m) I'm not sure adding an interface here instead of using type assertions is the best approach, what do you think?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaving this open for maintainer guidance on interface-based workflow session identity versus concrete type assertions. The latest fixes and main merge do not change this interface or its public API baseline.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 48ae509d-294c-4bf5-864d-81baecbae204
output_messages_path = _get_output_path(self._action_def, "messages")
output_result_path = _get_output_path(self._action_def, "result")

workflow_session_id = getattr(original_request, "workflow_session_id", None)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eduard van Valkenburg (@eavanvalkenburg) this seems to be using reflection to get the information. Not sure if that's ok in the project?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaving this open for maintainer guidance. The pending external-input repair does not change the existing attribute lookup in this approval path; it uses a typed request field for the new external-input scope data.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Cross-run isolation remains unresolved, and checkpoint identity and cancellation-sensitive client lifetimes require human validation.

1 open finding

🧠 Review effort: Balanced

Comment thread python/scripts/dependencies/tests/test_meta_package_install.py Outdated
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 48ae509d-294c-4bf5-864d-81baecbae204

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Python continuation scope gaps and legacy checkpoint handling leave isolation and upgrade compatibility unresolved.

3 open findings
1 resolved since last review

🧠 Review effort: Balanced

…nuations

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 48ae509d-294c-4bf5-864d-81baecbae204
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 48ae509d-294c-4bf5-864d-81baecbae204

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Cross-language resource lifetimes and checkpoint migration require human validation, with recovery and CI coverage gaps still unresolved.

2 open findings
3 resolved since last review

🧠 Review effort: Balanced

Comment thread .github/workflows/python-tests.yml Outdated
Apply the response batch policy before restoring stored or embedded continuations and include queued responses when validating new submissions. Run built-wheel selection regressions explicitly in an isolated Windows test environment.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 48ae509d-294c-4bf5-864d-81baecbae204
Comment thread python/packages/core/agent_framework/_workflows/_runner_context.py

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Nested checkpoint rejection can leave partially restored state, and the cross-language lifecycle changes require maintainer review.

1 open finding
2 resolved since last review

🧠 Review effort: Balanced

Comment thread python/packages/core/agent_framework/_workflows/_runner.py Outdated
Validate each embedded workflow with its own policy on a detached candidate before replacing parent, child, or executor state. Share snapshot validation between preflight and restore, and retain migration metadata only after the complete tree passes validation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 48ae509d-294c-4bf5-864d-81baecbae204

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Cross-language lifetime and checkpoint changes need maintainer review, with a cancellation-safety issue still unresolved.

1 open finding
1 resolved since last review

🧠 Review effort: Balanced

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Cross-runtime lifecycle and checkpoint migration changes require maintainer review, with nested response-validation gaps still unresolved.

3 open findings

🧠 Review effort: Balanced

Comment thread python/packages/core/agent_framework/_workflows/_runner.py Outdated
Comment thread python/packages/core/agent_framework/_workflows/_workflow.py Outdated
Complete failed MCP connection cleanup before releasing its cache slot, and preflight nested responses using child pending requests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: ee49ffae-d04c-4453-a2e2-446cf720e160
Comment thread python/packages/declarative/tests/test_default_mcp_tool_handler.py
Comment thread python/packages/declarative/tests/test_default_mcp_tool_handler.py

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Delegated response validation can mutate pending request origins before a later sibling rejects the batch.

1 open finding
3 resolved since last review

🧠 Review effort: Balanced

Comment thread python/packages/core/agent_framework/_workflows/_workflow.py Outdated
Validate detached response batches throughout the workflow tree before applying migrations to live pending requests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: ee49ffae-d04c-4453-a2e2-446cf720e160

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Cross-runtime lifecycle changes and nested checkpoint recovery need human validation, including the unresolved wrapped-response preflight gap.

1 open finding
1 resolved since last review

🧠 Review effort: Balanced

Comment thread python/packages/core/agent_framework/_workflows/_runner_context.py
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ee49ffae-d04c-4453-a2e2-446cf720e160
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ee49ffae-d04c-4453-a2e2-446cf720e160

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Cross-language resource lifetimes, cancellation handling, and nested checkpoint migration require final maintainer validation.

0 open findings

1 resolved since last review

🧠 Review effort: Balanced

Restore package manifests, lockfile, and installation CI to main. Remove package-installation tests and the unreleased Core version claim.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 69fba54c-3d5c-4d7d-909f-8db1f7c467dd

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Cross-runtime session ownership, concurrent cleanup, and nested checkpoint migration require final human review.

0 open findings

🧠 Review effort: Balanced

This branch was successfully deployed

2 active deployments
integration — fde8d779 Deployed Oct 16, 2026 by baywet via dotnet-foundry-hosted-it #30599
github-app-auth — fde8d779 Deployed Oct 16, 2026 by baywet via add_label #25639
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Usage: [Issues, PRs], Target: documentation in the code base and learn docs .NET Usage: [Issues, PRs], Target: .Net python Usage: [Issues, PRs], Target: Python workflows Usage: [Issues, PRs], Target: Workflows

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants