Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
dbee2f0
Updated mcp to 2.x (websocket optional is part of the core now)
jpalvarezl Sep 30, 2026
6532629
Added client test for agents as mcp_servers
jpalvarezl Sep 30, 2026
9cbf4ed
More casing fixes
jpalvarezl Sep 30, 2026
f42fe1f
Unit tests for legacy and v2 MCP server
jpalvarezl Sep 30, 2026
215d465
Using MCPError in samples for consistency with internal behaviour
jpalvarezl Sep 30, 2026
b215045
Migrated test_mcp to use new types
jpalvarezl Sep 30, 2026
9f30e29
collection for test_mcp
jpalvarezl Sep 30, 2026
e00abb4
collection passes for test_mcp_observability and test_mcp_skills
jpalvarezl Sep 30, 2026
33e61b9
Migrated message_handler
jpalvarezl Oct 1, 2026
c6f177c
deprecated MCPWebsocketTool
jpalvarezl Oct 1, 2026
db0af2e
deprecated MCPWebsocketTool, part 2
jpalvarezl Oct 1, 2026
29f3b1b
documentation updates
jpalvarezl Oct 1, 2026
dc86593
Moved transport setup to mcp.Client, added test for v2. Needs legacy …
jpalvarezl Oct 2, 2026
2697e80
Added legacy handshake unit test
jpalvarezl Oct 5, 2026
d70cb89
Added ADR for mcp v2
jpalvarezl Oct 5, 2026
2527fe3
Added tool/call mock and assertions
jpalvarezl Oct 5, 2026
a1cd038
Adjusted sampling capabilities test
jpalvarezl Oct 5, 2026
3f82747
removing ClientSession references in favour of using mcp.Client
jpalvarezl Oct 5, 2026
1266aa1
Assert preserve headers
jpalvarezl Oct 5, 2026
c5355aa
Added session negotiation tests
jpalvarezl Oct 5, 2026
2cc24d3
Sampling capabilities
jpalvarezl Oct 5, 2026
f043c00
ADR update
jpalvarezl Oct 5, 2026
e3775e0
MCPStdio test
jpalvarezl Oct 5, 2026
bdb7bad
basic tools support completed
jpalvarezl Oct 6, 2026
8522ca0
test cleanup
jpalvarezl Oct 6, 2026
a840613
Added support for ResourceLink for prompts
jpalvarezl Oct 6, 2026
3a4b24d
fixed and tested skill support
jpalvarezl Oct 6, 2026
e57fc3b
ADR and agents update
jpalvarezl Oct 6, 2026
45d7611
Added MCP client as a private field, set usage precedence 1st mcp_cli…
jpalvarezl Oct 7, 2026
2041a83
Prompt migrated to use mcp_client -> session
jpalvarezl Oct 7, 2026
202be25
Migrated list/tools and list/prompts
jpalvarezl Oct 7, 2026
b527812
Made protocol seam explicit with _MCPConnection
jpalvarezl Oct 7, 2026
aad4ace
Migrated skills
jpalvarezl Oct 7, 2026
236c4a7
Toolbox migration
jpalvarezl Oct 7, 2026
9fd7bc7
using right method for security labels
jpalvarezl Oct 7, 2026
3e98b01
legacy and modern MRTR validated
jpalvarezl Oct 7, 2026
7a18ca9
logging migrated
jpalvarezl Oct 7, 2026
0eca700
caching behaviour validated
jpalvarezl Oct 7, 2026
e7bcc0a
Update MCP v2 samples and docs
jpalvarezl Oct 7, 2026
c3572ca
Test coverage for caching and documentation updates
jpalvarezl Oct 8, 2026
14fca46
fixed issue with headers leaking through shared http_client
jpalvarezl Oct 8, 2026
73f7f98
Removed MCP Tasks to start work on new mcp v2 API
jpalvarezl Oct 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/decisions/0033-feature-usage-bitmask-user-agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ The detailed mechanism is in [SPEC-004](../specs/004-feature-usage-telemetry.md)
the per-language bit tables are in
[feature-usage-bit-registry.md](../specs/feature-usage-bit-registry.md).

### Amendment: MCP WebSocket transport

As of the MCP Python SDK v2 migration, `MCPWebsocketTool` is a deprecated
compatibility symbol because upstream removed WebSocket transport. The examples
below record the public surface considered when this ADR was accepted; the
currently supported MCP transports are stdio and Streamable HTTP.

## Decision Drivers

- **Transparency** — openly documented, human-decodable, user-controllable. No
Expand Down
284 changes: 284 additions & 0 deletions docs/decisions/0045-python-mcp-v2-client-lifecycle.md

Large diffs are not rendered by default.

4 changes: 0 additions & 4 deletions python/PACKAGE_STATUS.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,6 @@ listed below.
- `agent-framework-core`: experimental harness APIs for background agents, file access, looping,
memory, and file-backed todo storage under `agent_framework/_harness/`

#### `MCP_LONG_RUNNING_TASKS`

- `agent-framework-core`: `MCPTaskOptions` from `agent_framework/_mcp.py`

#### `MCP_SKILLS`

- `agent-framework-core`: `MCPSkillResource`, `MCPSkill`, and `MCPSkillsSource` from
Expand Down
26 changes: 15 additions & 11 deletions python/packages/core/AGENTS.md

Large diffs are not rendered by default.

2 changes: 0 additions & 2 deletions python/packages/core/agent_framework/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,6 @@
"._mcp": (
"MCPStdioTool",
"MCPStreamableHTTPTool",
"MCPTaskOptions",
"MCPWebsocketTool",
"SamplingApprovalCallback",
),
Expand Down Expand Up @@ -559,7 +558,6 @@
"MCPSkillsSource",
"MCPStdioTool",
"MCPStreamableHTTPTool",
"MCPTaskOptions",
"MCPWebsocketTool",
"MemoryContextProvider",
"MemoryFileStore",
Expand Down
2 changes: 0 additions & 2 deletions python/packages/core/agent_framework/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@ from ._in_memory import InMemoryCollection, InMemoryStore
from ._mcp import (
MCPStdioTool,
MCPStreamableHTTPTool,
MCPTaskOptions,
MCPWebsocketTool,
SamplingApprovalCallback,
)
Expand Down Expand Up @@ -514,7 +513,6 @@ __all__ = [
"MCPSkillsSource",
"MCPStdioTool",
"MCPStreamableHTTPTool",
"MCPTaskOptions",
"MCPWebsocketTool",
"MemoryContextProvider",
"MemoryFileStore",
Expand Down
69 changes: 29 additions & 40 deletions python/packages/core/agent_framework/_agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -1881,8 +1881,9 @@ def as_mcp_server(
"""
try:
from mcp import types
from mcp.server import ServerRequestContext
from mcp.server.lowlevel import Server
from mcp.shared.exceptions import McpError
from mcp.shared.exceptions import MCPError
except ModuleNotFoundError as exc:
raise ModuleNotFoundError(
"`mcp` is required to use `Agent.as_mcp_server()`. Please install `mcp`."
Expand All @@ -1891,55 +1892,51 @@ def as_mcp_server(

server_args: dict[str, Any] = {
"name": server_name,
"version": version,
"instructions": instructions,
}

if version is not None:
server_args["version"] = version

if lifespan:
server_args["lifespan"] = lifespan
if kwargs:
server_args.update(kwargs)

server: Server[Any] = Server(**server_args)

agent_tool = self.as_tool(name=self._get_agent_name())

async def _log(level: types.LoggingLevel, data: Any) -> None:
"""Log a message to the server and logger."""
def _log(level: types.LoggingLevel, data: Any) -> None:
"""Log a message to logger."""
# Log to the local logger
logger.log(LOG_LEVEL_MAPPING[level], data)
if server and server.request_context and server.request_context.session:
try:
await server.request_context.session.send_log_message(level=level, data=data)
except Exception as e:
logger.error("Failed to send log message to server: %s", e)

@server.list_tools()
async def _list_tools() -> list[types.Tool]:

async def _list_tools( # ruff:ignore[unused-async]
_ctx: ServerRequestContext[dict[str, Any]], _params: types.PaginatedRequestParams | None
) -> types.ListToolsResult:
"""List all tools in the agent."""
schema = agent_tool.parameters()

tool = types.Tool(
name=agent_tool.name,
description=agent_tool.description,
inputSchema=schema,
input_schema=schema,
)

await _log(level="debug", data=f"Agent tool: {agent_tool}")
return [tool]
_log(level="debug", data=f"Agent tool: {agent_tool}")
return types.ListToolsResult(tools=[tool])

@server.call_tool()
async def _call_tool(
name: str, arguments: dict[str, Any]
) -> Sequence[types.TextContent | types.ImageContent | types.AudioContent | types.EmbeddedResource]:
_ctx: ServerRequestContext[dict[str, Any]], params: types.CallToolRequestParams
) -> types.CallToolResult:
"""Call a tool in the agent."""
await _log(level="debug", data=f"Calling tool with args: {arguments}")
arguments = params.arguments or {}
name = params.name
_log(level="debug", data=f"Calling tool with args: {arguments}")

if name != agent_tool.name:
raise McpError(
error=types.ErrorData(
code=types.INTERNAL_ERROR,
message=f"Tool {name} not found",
),
raise MCPError(
code=types.INTERNAL_ERROR,
message=f"Tool {name} not found",
)

# Create an instance of the input model with the arguments
Expand All @@ -1949,17 +1946,15 @@ async def _call_tool(
)
result = await agent_tool.invoke(arguments=args_instance)
except Exception as e:
raise McpError(
error=types.ErrorData(
code=types.INTERNAL_ERROR,
message=f"Error calling tool {name}: {e}",
),
raise MCPError(
code=types.INTERNAL_ERROR,
message=f"Error calling tool {name}: {e}",
) from e

# Convert result to MCP content.
# Currently only text items are forwarded over MCP; rich content
# (images, audio) is not yet supported in the MCP server path.
mcp_content: list[types.TextContent | types.ImageContent | types.EmbeddedResource] = []
mcp_content: list[types.ContentBlock] = []
for c in result:
if c.type == "text" and c.text:
mcp_content.append(types.TextContent(type="text", text=c.text))
Expand All @@ -1968,15 +1963,9 @@ async def _call_tool(
"MCP server does not yet forward rich content (images, audio) "
"in tool results. Rich content items will be omitted."
)
return mcp_content or [types.TextContent(type="text", text="")]

@server.set_logging_level()
async def _set_logging_level(level: types.LoggingLevel) -> None:
"""Set the logging level for the server."""
logger.setLevel(LOG_LEVEL_MAPPING[level])
# emit this log with the new minimum level
await _log(level=level, data=f"Log level set to {level}")
return types.CallToolResult(content=mcp_content)

server: Server[Any] = Server(**server_args, on_list_tools=_list_tools, on_call_tool=_call_tool)
return server

def _get_agent_name(self) -> str:
Expand Down
1 change: 0 additions & 1 deletion python/packages/core/agent_framework/_feature_stage.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ class ExperimentalFeature(str, Enum):
FOUNDRY_PREVIEW_TOOLS = "FOUNDRY_PREVIEW_TOOLS"
FUNCTIONAL_WORKFLOWS = "FUNCTIONAL_WORKFLOWS"
HARNESS = "HARNESS"
MCP_LONG_RUNNING_TASKS = "MCP_LONG_RUNNING_TASKS"
MCP_SKILLS = "MCP_SKILLS"
PROGRESSIVE_TOOLS = "PROGRESSIVE_TOOLS"
SESSION_STORE = "SESSION_STORE"
Expand Down
Loading
Loading