Python: Add MCP channel for agent-framework-hosting#6700
Python: Add MCP channel for agent-framework-hosting#6700eavanvalkenburg wants to merge 3 commits into
Conversation
- Add agent-framework-hosting-mcp package with MCPChannel that exposes an AgentFrameworkHost as a Streamable-HTTP MCP server, allowing any MCP client to invoke the agent as a single tool - MCPChannel mounts a FastMCP server on the host's Starlette app and routes call_tool requests through the channel pipeline (run_hook, context providers, history providers) - Rich content conversion via _content_to_mcp and _value_to_mcp: handles text, reasoning, data, URI, function_result, and error content types from AF responses into MCP TextContent/ImageContent - Streaming: MCP progress notifications dispatched while consuming ResponseStream; final tool result assembled from get_final_response() - Test layout uses tests/hosting_mcp/ (no tests/__init__.py) - Remove old [tool.mypy] section and mypy poe task; remove empty [dependency-groups] section; remove stale mypy-only type: ignore comments that pyright reports as unnecessary - Update uv.lock, pyproject.toml workspace sources, and PACKAGE_STATUS.md Fixes microsoft#6592 Refs microsoft#6265 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds a new Python hosting channel package (agent-framework-hosting-mcp) that exposes an AgentFrameworkHost target as a single MCP tool over Streamable HTTP, including content conversion utilities and end-to-end tests.
Changes:
- Introduces
MCPChannelimplementation that mounts an MCP Streamable HTTP transport and routes tool calls through the hosting pipeline. - Adds unit/integration-style tests exercising in-memory MCP sessions and a real Streamable HTTP round-trip via an in-process ASGI server.
- Wires the new package into the Python workspace and documents/package-status it as alpha.
Reviewed changes
Copilot reviewed 8 out of 9 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| python/pyproject.toml | Adds agent-framework-hosting-mcp to the Python workspace. |
| python/packages/hosting-mcp/agent_framework_hosting_mcp/_channel.py | Implements MCPChannel, MCP tool registration, streaming progress notifications, and content conversion. |
| python/packages/hosting-mcp/agent_framework_hosting_mcp/init.py | Exports MCPChannel and package __version__. |
| python/packages/hosting-mcp/tests/hosting_mcp/test_channel.py | Adds tests for tool listing, call routing, streaming aggregation, content conversion, and Streamable HTTP invocation. |
| python/packages/hosting-mcp/README.md | Documents how to host an agent with the MCP channel and the tool I/O shape. |
| python/packages/hosting-mcp/pyproject.toml | Defines the new package metadata, dependencies, and tooling config. |
| python/packages/hosting-mcp/LICENSE | Adds MIT license file for the new package. |
| python/PACKAGE_STATUS.md | Registers the new package as alpha. |
There was a problem hiding this comment.
Automated Code Review
Reviewers: 5 | Confidence: 60%
✓ Correctness
No actionable issues found in this dimension.
✓ Security Reliability
No actionable issues found in this dimension.
✓ Test Coverage
The test suite provides solid coverage of the happy path, content conversion, hooks, and an end-to-end HTTP integration test. Two notable test coverage gaps exist: (1) no test exercises error propagation when the hosted target raises an exception during
_invoke_tool, so it's unverified whether the channel returns a graceful MCP error or crashes the session; (2) the MCP progress notification path (_send_progress) is never exercised because no test supplies aprogressToken, leaving that production logic untested.
✓ Failure Modes
The MCPChannel implementation is well-structured with appropriate failure handling: input validation with early error returns, best-effort progress notifications, and proper content conversion fallbacks. The response_hook integration with the streaming path is correctly handled through the hosting framework's _HostResponseStream. One minor lifecycle concern exists around the startup/shutdown context manager pattern, but it's unlikely to trigger in practice.
✗ Design Approach
The new MCP channel is close, but it currently ignores the MCP tool name on
call_tool. Because the handler always forwards to_invoke_tool, a client can invoke any arbitrary tool name and still execute the hosted agent, which is a protocol-level correctness issue for a server that advertises a single named tool.
Flagged Issues
-
python/packages/hosting-mcp/agent_framework_hosting_mcp/_channel.py:303-305advertises exactly one tool vialist_tools()but never validates the incomingnameincall_tool(), so a request likecall_tool("does-not-exist", {"input": "hello"})will still run the hosted agent instead of failing as an unknown-tool call.
Automated review by eavanvalkenburg's agents
|
Flagged issue
Source: automated DevFlow PR review |
- Validate requested tool name in call_tool and return an MCP error for
unknown tools instead of invoking the hosted target
- Raise minimum mcp dependency to >=1.24.0 to align with other MCP
integrations and Streamable HTTP usage in this repo
- Harden MCP tests for strict typing:
- add typed helper for TextContent extraction instead of union attr access
- add helper that narrows channel._server before creating in-memory
MCP client sessions
- shape _HostedAgent fake to satisfy SupportsAgentRun protocol
- Add regression test for unknown tool-name rejection
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…mcp sample Channel fixes: - Replace getattr(update, 'text', None) streaming pattern with update.contents iteration; extract text items for progress notifications - Add _strip_options_hook as default when run_hook=None, matching the ResponsesChannel pattern so untrusted callers cannot inject options - Update _hook type annotation to ChannelRunHook (non-optional) - Update run_hook docstring to document default behaviour Tests: - Update _FakeStream to populate contents from text chunks - Add stream_updates param to _FakeContext for injecting mixed-content updates - Add test: non-text content in stream updates is not forwarded as progress - Add test: default hook strips options when no run_hook is supplied Sample (local_mcp/): - app.py: WeatherAgent behind MCPChannel with run_hook and FileHistoryProvider - call_client.py: outer Agent consuming the hosted agent via MCPStreamableHTTPTool - pyproject.toml, README.md Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Motivation & Context
Adds Model Context Protocol (MCP) support for the
agent-framework-hostingstack, allowing anAgentFrameworkHostto be exposed as an MCP server. Any MCP-compatible client or orchestrator can then invoke the hosted agent as a single tool over Streamable HTTP.This is part of the channel-by-channel split of the hosting work tracked in #6265.
Description & Review Guide
Major changes:
agent-framework-hosting-mcppackage —MCPChannelthat:call_toolrequests through the full channel pipeline (run_hook, context providers, history providers)_content_to_mcpand_value_to_mcp: text, reasoning, data, URI, function_result, and error content all map to appropriate MCPTextContent/ImageContent/EmbeddedResourceitemsResponseStream; finalCallToolResultassembled fromget_final_response()session_id(when provided) is used as the AF isolation key; omittedsession_idrequests are treated as sessionless.Test layout already uses
tests/hosting_mcp/with no__init__.py; tests exercise the full Streamable HTTP round-trip usingmcp.client.streamable_httpand an in-process uvicorn serverImpact: New alpha package with no changes to existing packages. Adds
agent-framework-hosting-mcpto the workspace and lockfile. Removed stale mypy-specific# type: ignorecomments flagged as unnecessary by pyright.Reviewer focus: content-type mapping completeness in
_content_to_mcp/_value_to_mcp, MCP progress notification correctness, tool descriptor schema generation.Related Issue
Fixes #6592
Refs #6265
Contribution Checklist