From 65fa1733164d9329f9d81091d5baa59dc5b29200 Mon Sep 17 00:00:00 2001 From: Anubhav Dhawan Date: Sat, 25 Jul 2026 00:59:29 +0530 Subject: [PATCH] feat(core): promote MCP draft protocol to official 2026-07-28 version --- .../toolbox-core/src/toolbox_core/client.py | 6 ++--- .../toolbox_core/mcp_transport/__init__.py | 4 ++-- .../{v20260618 => v20260728}/mcp.py | 4 ++-- .../{v20260618 => v20260728}/types.py | 0 .../toolbox-core/src/toolbox_core/protocol.py | 11 +++++----- .../tests/mcp_transport/test_v20241105.py | 8 +++---- .../tests/mcp_transport/test_v20250326.py | 8 +++---- .../tests/mcp_transport/test_v20250618.py | 8 +++---- .../tests/mcp_transport/test_v20251125.py | 8 +++---- .../{test_v20260618.py => test_v20260728.py} | 22 +++++++++---------- packages/toolbox-core/tests/test_client.py | 8 +++---- packages/toolbox-core/tests/test_protocol.py | 2 +- 12 files changed, 45 insertions(+), 44 deletions(-) rename packages/toolbox-core/src/toolbox_core/mcp_transport/{v20260618 => v20260728}/mcp.py (99%) rename packages/toolbox-core/src/toolbox_core/mcp_transport/{v20260618 => v20260728}/types.py (100%) rename packages/toolbox-core/tests/mcp_transport/{test_v20260618.py => test_v20260728.py} (97%) diff --git a/packages/toolbox-core/src/toolbox_core/client.py b/packages/toolbox-core/src/toolbox_core/client.py index b16138afb..eb9b4d221 100644 --- a/packages/toolbox-core/src/toolbox_core/client.py +++ b/packages/toolbox-core/src/toolbox_core/client.py @@ -30,7 +30,7 @@ McpHttpTransportV20250326, McpHttpTransportV20250618, McpHttpTransportV20251125, - McpHttpTransportV20260618, + McpHttpTransportV20260728, ) from .protocol import Protocol, ToolSchema from .tool import ToolboxTool @@ -66,8 +66,8 @@ def __init__( def _create_transport(self, protocol: Protocol) -> ITransport: self._current_protocol = protocol match protocol: - case Protocol.MCP_DRAFT: - return McpHttpTransportV20260618( + case Protocol.MCP_v20260728 | Protocol.MCP_DRAFT | Protocol.MCP_v2026_DRAFT: + return McpHttpTransportV20260728( self._url, self._session, protocol, diff --git a/packages/toolbox-core/src/toolbox_core/mcp_transport/__init__.py b/packages/toolbox-core/src/toolbox_core/mcp_transport/__init__.py index ca5d0217f..bbd5476f2 100644 --- a/packages/toolbox-core/src/toolbox_core/mcp_transport/__init__.py +++ b/packages/toolbox-core/src/toolbox_core/mcp_transport/__init__.py @@ -16,12 +16,12 @@ from .v20250326.mcp import McpHttpTransportV20250326 from .v20250618.mcp import McpHttpTransportV20250618 from .v20251125.mcp import McpHttpTransportV20251125 -from .v20260618.mcp import McpHttpTransportV20260618 +from .v20260728.mcp import McpHttpTransportV20260728 __all__ = [ "McpHttpTransportV20241105", "McpHttpTransportV20250326", "McpHttpTransportV20250618", "McpHttpTransportV20251125", - "McpHttpTransportV20260618", + "McpHttpTransportV20260728", ] diff --git a/packages/toolbox-core/src/toolbox_core/mcp_transport/v20260618/mcp.py b/packages/toolbox-core/src/toolbox_core/mcp_transport/v20260728/mcp.py similarity index 99% rename from packages/toolbox-core/src/toolbox_core/mcp_transport/v20260618/mcp.py rename to packages/toolbox-core/src/toolbox_core/mcp_transport/v20260728/mcp.py index 91c8f26f4..c44ac0bc5 100644 --- a/packages/toolbox-core/src/toolbox_core/mcp_transport/v20260618/mcp.py +++ b/packages/toolbox-core/src/toolbox_core/mcp_transport/v20260728/mcp.py @@ -28,8 +28,8 @@ ReceiveResultT = TypeVar("ReceiveResultT", bound=BaseModel) -class McpHttpTransportV20260618(_McpHttpTransportBase): - """Transport for the MCP draft Request-Metadata (v2026-06-18) protocol.""" +class McpHttpTransportV20260728(_McpHttpTransportBase): + """Transport for the MCP draft Request-Metadata (v2026-07-28) protocol.""" async def _send_request( self, diff --git a/packages/toolbox-core/src/toolbox_core/mcp_transport/v20260618/types.py b/packages/toolbox-core/src/toolbox_core/mcp_transport/v20260728/types.py similarity index 100% rename from packages/toolbox-core/src/toolbox_core/mcp_transport/v20260618/types.py rename to packages/toolbox-core/src/toolbox_core/mcp_transport/v20260728/types.py diff --git a/packages/toolbox-core/src/toolbox_core/protocol.py b/packages/toolbox-core/src/toolbox_core/protocol.py index 350e0251f..f1ae0ce8e 100644 --- a/packages/toolbox-core/src/toolbox_core/protocol.py +++ b/packages/toolbox-core/src/toolbox_core/protocol.py @@ -51,17 +51,18 @@ class Protocol(str, Enum): MCP_v20250326 = "2025-03-26" MCP_v20241105 = "2024-11-05" MCP_v20251125 = "2025-11-25" - MCP_v2026_DRAFT = "DRAFT-2026-v1" + MCP_v20260728 = "2026-07-28" + MCP_v2026_DRAFT = "2026-07-28" - MCP = MCP_v20251125 - MCP_LATEST = MCP_v20251125 - MCP_DRAFT = MCP_v2026_DRAFT + MCP = MCP_v20260728 + MCP_LATEST = MCP_v20260728 + MCP_DRAFT = MCP_v20260728 @staticmethod def get_supported_mcp_versions() -> list[str]: """Returns a list of supported MCP protocol versions.""" return [ - Protocol.MCP_DRAFT.value, + Protocol.MCP_v20260728.value, Protocol.MCP_v20251125.value, Protocol.MCP_v20250618.value, Protocol.MCP_v20250326.value, diff --git a/packages/toolbox-core/tests/mcp_transport/test_v20241105.py b/packages/toolbox-core/tests/mcp_transport/test_v20241105.py index 3fd11d7cb..7a0c58bc3 100644 --- a/packages/toolbox-core/tests/mcp_transport/test_v20241105.py +++ b/packages/toolbox-core/tests/mcp_transport/test_v20241105.py @@ -172,7 +172,7 @@ async def test_version_negotiation_raises_fallback(self, transport): "error": { "code": -32022, "message": "Unsupported protocol version", - "data": {"supported": ["DRAFT-2026-v1"]}, + "data": {"supported": ["2026-07-28"]}, }, } @@ -193,7 +193,7 @@ def get_result_model(self): with pytest.raises(ProtocolNegotiationError) as exc_info: await transport._send_request("url", TestRequest()) - assert exc_info.value.negotiated_version == "DRAFT-2026-v1" + assert exc_info.value.negotiated_version == "2026-07-28" assert transport._session.post.call_count == 1 async def test_version_negotiation_raises_fallback_200_ok(self, transport): @@ -210,7 +210,7 @@ async def test_version_negotiation_raises_fallback_200_ok(self, transport): "error": { "code": -32022, "message": "Unsupported protocol version", - "data": {"supported": ["DRAFT-2026-v1"]}, + "data": {"supported": ["2026-07-28"]}, }, } @@ -231,7 +231,7 @@ def get_result_model(self): with pytest.raises(ProtocolNegotiationError) as exc_info: await transport._send_request("url", TestRequest()) - assert exc_info.value.negotiated_version == "DRAFT-2026-v1" + assert exc_info.value.negotiated_version == "2026-07-28" assert transport._session.post.call_count == 1 async def test_version_negotiation_empty_intersection(self, transport): diff --git a/packages/toolbox-core/tests/mcp_transport/test_v20250326.py b/packages/toolbox-core/tests/mcp_transport/test_v20250326.py index e34fba549..921d3aa47 100644 --- a/packages/toolbox-core/tests/mcp_transport/test_v20250326.py +++ b/packages/toolbox-core/tests/mcp_transport/test_v20250326.py @@ -190,7 +190,7 @@ async def test_version_negotiation_raises_fallback(self, transport): "error": { "code": -32022, "message": "Unsupported protocol version", - "data": {"supported": ["DRAFT-2026-v1"]}, + "data": {"supported": ["2026-07-28"]}, }, } @@ -211,7 +211,7 @@ def get_result_model(self): with pytest.raises(ProtocolNegotiationError) as exc_info: await transport._send_request("url", TestRequest()) - assert exc_info.value.negotiated_version == "DRAFT-2026-v1" + assert exc_info.value.negotiated_version == "2026-07-28" assert transport._session.post.call_count == 1 async def test_version_negotiation_raises_fallback_200_ok(self, transport): @@ -228,7 +228,7 @@ async def test_version_negotiation_raises_fallback_200_ok(self, transport): "error": { "code": -32022, "message": "Unsupported protocol version", - "data": {"supported": ["DRAFT-2026-v1"]}, + "data": {"supported": ["2026-07-28"]}, }, } @@ -249,7 +249,7 @@ def get_result_model(self): with pytest.raises(ProtocolNegotiationError) as exc_info: await transport._send_request("url", TestRequest()) - assert exc_info.value.negotiated_version == "DRAFT-2026-v1" + assert exc_info.value.negotiated_version == "2026-07-28" assert transport._session.post.call_count == 1 async def test_version_negotiation_empty_intersection(self, transport): diff --git a/packages/toolbox-core/tests/mcp_transport/test_v20250618.py b/packages/toolbox-core/tests/mcp_transport/test_v20250618.py index bd2c6eb9b..aeebcd546 100644 --- a/packages/toolbox-core/tests/mcp_transport/test_v20250618.py +++ b/packages/toolbox-core/tests/mcp_transport/test_v20250618.py @@ -189,7 +189,7 @@ async def test_version_negotiation_raises_fallback(self, transport): "error": { "code": -32022, "message": "Unsupported protocol version", - "data": {"supported": ["DRAFT-2026-v1"]}, + "data": {"supported": ["2026-07-28"]}, }, } @@ -210,7 +210,7 @@ def get_result_model(self): with pytest.raises(ProtocolNegotiationError) as exc_info: await transport._send_request("url", TestRequest()) - assert exc_info.value.negotiated_version == "DRAFT-2026-v1" + assert exc_info.value.negotiated_version == "2026-07-28" assert transport._session.post.call_count == 1 async def test_version_negotiation_raises_fallback_200_ok(self, transport): @@ -227,7 +227,7 @@ async def test_version_negotiation_raises_fallback_200_ok(self, transport): "error": { "code": -32022, "message": "Unsupported protocol version", - "data": {"supported": ["DRAFT-2026-v1"]}, + "data": {"supported": ["2026-07-28"]}, }, } @@ -248,7 +248,7 @@ def get_result_model(self): with pytest.raises(ProtocolNegotiationError) as exc_info: await transport._send_request("url", TestRequest()) - assert exc_info.value.negotiated_version == "DRAFT-2026-v1" + assert exc_info.value.negotiated_version == "2026-07-28" assert transport._session.post.call_count == 1 async def test_version_negotiation_empty_intersection(self, transport): diff --git a/packages/toolbox-core/tests/mcp_transport/test_v20251125.py b/packages/toolbox-core/tests/mcp_transport/test_v20251125.py index 60b342e92..a37fa47a6 100644 --- a/packages/toolbox-core/tests/mcp_transport/test_v20251125.py +++ b/packages/toolbox-core/tests/mcp_transport/test_v20251125.py @@ -189,7 +189,7 @@ async def test_version_negotiation_raises_fallback(self, transport): "error": { "code": -32022, "message": "Unsupported protocol version", - "data": {"supported": ["DRAFT-2026-v1"]}, + "data": {"supported": ["2026-07-28"]}, }, } @@ -210,7 +210,7 @@ def get_result_model(self): with pytest.raises(ProtocolNegotiationError) as exc_info: await transport._send_request("url", TestRequest()) - assert exc_info.value.negotiated_version == "DRAFT-2026-v1" + assert exc_info.value.negotiated_version == "2026-07-28" assert transport._session.post.call_count == 1 async def test_version_negotiation_raises_fallback_200_ok(self, transport): @@ -227,7 +227,7 @@ async def test_version_negotiation_raises_fallback_200_ok(self, transport): "error": { "code": -32022, "message": "Unsupported protocol version", - "data": {"supported": ["DRAFT-2026-v1"]}, + "data": {"supported": ["2026-07-28"]}, }, } @@ -248,7 +248,7 @@ def get_result_model(self): with pytest.raises(ProtocolNegotiationError) as exc_info: await transport._send_request("url", TestRequest()) - assert exc_info.value.negotiated_version == "DRAFT-2026-v1" + assert exc_info.value.negotiated_version == "2026-07-28" assert transport._session.post.call_count == 1 async def test_version_negotiation_empty_intersection(self, transport): diff --git a/packages/toolbox-core/tests/mcp_transport/test_v20260618.py b/packages/toolbox-core/tests/mcp_transport/test_v20260728.py similarity index 97% rename from packages/toolbox-core/tests/mcp_transport/test_v20260618.py rename to packages/toolbox-core/tests/mcp_transport/test_v20260728.py index 00a5f1e12..e0115b0ee 100644 --- a/packages/toolbox-core/tests/mcp_transport/test_v20260618.py +++ b/packages/toolbox-core/tests/mcp_transport/test_v20260728.py @@ -19,8 +19,8 @@ from aiohttp import ClientSession from aioresponses import aioresponses -from toolbox_core.mcp_transport.v20260618 import types -from toolbox_core.mcp_transport.v20260618.mcp import McpHttpTransportV20260618 +from toolbox_core.mcp_transport.v20260728 import types +from toolbox_core.mcp_transport.v20260728.mcp import McpHttpTransportV20260728 from toolbox_core.protocol import ManifestSchema, Protocol @@ -68,7 +68,7 @@ async def transport(request, mocker): mocker.patch("toolbox_core.mcp_transport.telemetry.record_operation_duration") mocker.patch("toolbox_core.mcp_transport.telemetry.record_session_duration") mock_session = AsyncMock(spec=ClientSession) - transport = McpHttpTransportV20260618( + transport = McpHttpTransportV20260728( "http://fake-server.com", session=mock_session, protocol=Protocol.MCP_DRAFT, @@ -79,7 +79,7 @@ async def transport(request, mocker): @pytest.mark.asyncio -class TestMcpHttpTransportV20260618: +class TestMcpHttpTransportV20260728: # --- Request Sending Tests (Standard + Header) --- @@ -128,7 +128,7 @@ def get_result_model(self): call_args = transport._session.post.call_args headers = call_args.kwargs["headers"] - assert headers["MCP-Protocol-Version"] == "DRAFT-2026-v1" + assert headers["MCP-Protocol-Version"] == "2026-07-28" assert headers["Mcp-Method"] == "method" assert "Mcp-Name" not in headers @@ -242,7 +242,7 @@ async def test_version_negotiation_raises_fallback(self, transport): "error": { "code": -32022, "message": "Unsupported protocol version", - "data": {"supported": ["DRAFT-2026-v1"]}, + "data": {"supported": ["2026-07-28"]}, }, } @@ -263,7 +263,7 @@ def get_result_model(self): with pytest.raises(ProtocolNegotiationError) as exc_info: await transport._send_request("url", TestRequest()) - assert exc_info.value.negotiated_version == "DRAFT-2026-v1" + assert exc_info.value.negotiated_version == "2026-07-28" assert transport._session.post.call_count == 1 async def test_version_negotiation_raises_fallback_200_ok(self, transport): @@ -280,7 +280,7 @@ async def test_version_negotiation_raises_fallback_200_ok(self, transport): "error": { "code": -32022, "message": "Unsupported protocol version", - "data": {"supported": ["DRAFT-2026-v1"]}, + "data": {"supported": ["2026-07-28"]}, }, } @@ -301,7 +301,7 @@ def get_result_model(self): with pytest.raises(ProtocolNegotiationError) as exc_info: await transport._send_request("url", TestRequest()) - assert exc_info.value.negotiated_version == "DRAFT-2026-v1" + assert exc_info.value.negotiated_version == "2026-07-28" assert transport._session.post.call_count == 1 async def test_version_negotiation_empty_intersection(self, transport): @@ -357,7 +357,7 @@ async def test_tools_list_success(self, transport, mocker): async def test_tools_list_with_toolset_name_and_query_params(self, mocker): """Test listing tools with a toolset name when base_url contains query parameters.""" mock_session = AsyncMock(spec=ClientSession) - transport = McpHttpTransportV20260618( + transport = McpHttpTransportV20260728( "http://fake-server.com?proj=xyz&env=prod", session=mock_session, protocol=Protocol.MCP_DRAFT, @@ -499,7 +499,7 @@ async def test_result_meta_parsing_server_info(self, transport): types.ListToolsRequest( params=types.ListToolsRequestParams( field_meta=types.MCPMeta( - protocol_version="DRAFT-2026-v1", + protocol_version="2026-07-28", client_info=types.Implementation(name="test", version="1.0"), client_capabilities=types.ClientCapabilities(), ) diff --git a/packages/toolbox-core/tests/test_client.py b/packages/toolbox-core/tests/test_client.py index 405558c9a..5907da4a9 100644 --- a/packages/toolbox-core/tests/test_client.py +++ b/packages/toolbox-core/tests/test_client.py @@ -263,7 +263,7 @@ async def test_load_tool_protocol_fallback_success(test_tool_str): # We need to mock the transports that client.py will instantiate with ( - patch("toolbox_core.client.McpHttpTransportV20260618") as mock_2026_cls, + patch("toolbox_core.client.McpHttpTransportV20260728") as mock_2026_cls, patch("toolbox_core.client.McpHttpTransportV20250618") as mock_2025_cls, ): @@ -307,7 +307,7 @@ async def test_load_tool_protocol_fallback_infinite_loop_prevention(test_tool_st from toolbox_core.exceptions import ProtocolNegotiationError with ( - patch("toolbox_core.client.McpHttpTransportV20260618") as mock_2026_cls, + patch("toolbox_core.client.McpHttpTransportV20260728") as mock_2026_cls, patch("toolbox_core.client.McpHttpTransportV20250618") as mock_2025_cls, patch("toolbox_core.client.McpHttpTransportV20241105") as mock_2024_cls, ): @@ -820,7 +820,7 @@ async def test_client_init_with_client_info(): def test_toolbox_client_no_warning_on_mcp(): """Test that initializing ToolboxClient with Protocol.MCP issues NO DeprecationWarning.""" # Mock the transport to avoid actual connection attempts or MCP version warnings - with patch("toolbox_core.client.McpHttpTransportV20251125") as mock_transport: + with patch("toolbox_core.client.McpHttpTransportV20260728") as mock_transport: with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") @@ -853,7 +853,7 @@ def test_toolbox_client_custom_protocols(): # Check initial_protocol assert args[2] == Protocol.MCP_DRAFT # Check supported_protocols (must be sorted from newest to oldest) - assert args[6] == ["DRAFT-2026-v1", "2025-06-18", "2024-11-05"] + assert args[6] == ["2026-07-28", "2025-06-18", "2024-11-05"] def test_toolbox_client_custom_protocols_invalid(): diff --git a/packages/toolbox-core/tests/test_protocol.py b/packages/toolbox-core/tests/test_protocol.py index 3c50b3225..2ba182ed9 100644 --- a/packages/toolbox-core/tests/test_protocol.py +++ b/packages/toolbox-core/tests/test_protocol.py @@ -78,7 +78,7 @@ def test_get_supported_mcp_versions(): sorted from newest to oldest. """ expected_versions = [ - "DRAFT-2026-v1", + "2026-07-28", "2025-11-25", "2025-06-18", "2025-03-26",