diff --git a/packages/toolbox-core/README.md b/packages/toolbox-core/README.md index 60daf7580..4f57e4a01 100644 --- a/packages/toolbox-core/README.md +++ b/packages/toolbox-core/README.md @@ -58,12 +58,29 @@ The core package provides a framework-agnostic way to interact with your Toolbox - [Loading Tools](https://mcp-toolbox.dev/documentation/connect-to/toolbox-sdks/python-sdk/core/#loading-tools) - [Invoking Tools](https://mcp-toolbox.dev/documentation/connect-to/toolbox-sdks/python-sdk/core/#invoking-tools) - [Synchronous Usage](https://mcp-toolbox.dev/documentation/connect-to/toolbox-sdks/python-sdk/core/#synchronous-usage) +- [Protocol Negotiation](#protocol-negotiation) - [Use With Langraph](https://mcp-toolbox.dev/documentation/connect-to/toolbox-sdks/python-sdk/core/#use-with-langgraph) + - [Client to Server Authentication](https://mcp-toolbox.dev/documentation/connect-to/toolbox-sdks/python-sdk/core/#client-to-server-authentication) - [Authenticating Tools](https://mcp-toolbox.dev/documentation/connect-to/toolbox-sdks/python-sdk/core/#authenticating-tools) - [Binding Parameter Values](https://mcp-toolbox.dev/documentation/connect-to/toolbox-sdks/python-sdk/core/#parameter-binding) - [OpenTelemetry](https://mcp-toolbox.dev/documentation/connect-to/toolbox-sdks/python-sdk/core/#opentelemetry) +## Protocol Negotiation + +By default, the client negotiates the newest protocol version supported by the server. You can provide a custom list of supported protocols to restrict negotiation to specific versions or a single version. Ensure you pass the [`Protocol`](src/toolbox_core/protocol.py) enum constants. Both `Protocol.MCP_LATEST` and `Protocol.MCP_DRAFT` are supported as well. + +```py +from toolbox_core import ToolboxClient, Protocol + +async def main(): + async with ToolboxClient( + "http://127.0.0.1:5000", + protocol=[Protocol.MCP_LATEST, Protocol.MCP_DRAFT] + ) as toolbox: + pass +``` + # Contributing diff --git a/packages/toolbox-core/src/toolbox_core/client.py b/packages/toolbox-core/src/toolbox_core/client.py index b2224eedc..faf8eeec1 100644 --- a/packages/toolbox-core/src/toolbox_core/client.py +++ b/packages/toolbox-core/src/toolbox_core/client.py @@ -53,12 +53,14 @@ def __init__( client_name: Optional[str], client_version: Optional[str], telemetry_enabled: bool, + supported_protocols: Optional[list[str]] = None, ): self._url = url self._session = session self._client_name = client_name self._client_version = client_version self._telemetry_enabled = telemetry_enabled + self._supported_protocols = supported_protocols self._active_transport = self._create_transport(protocol) def _create_transport(self, protocol: Protocol) -> ITransport: @@ -71,6 +73,7 @@ def _create_transport(self, protocol: Protocol) -> ITransport: self._client_name, self._client_version, telemetry_enabled=self._telemetry_enabled, + supported_protocols=self._supported_protocols, ) case Protocol.MCP_v20251125: return McpHttpTransportV20251125( @@ -80,6 +83,7 @@ def _create_transport(self, protocol: Protocol) -> ITransport: self._client_name, self._client_version, telemetry_enabled=self._telemetry_enabled, + supported_protocols=self._supported_protocols, ) case Protocol.MCP_v20250618: return McpHttpTransportV20250618( @@ -89,6 +93,7 @@ def _create_transport(self, protocol: Protocol) -> ITransport: self._client_name, self._client_version, telemetry_enabled=self._telemetry_enabled, + supported_protocols=self._supported_protocols, ) case Protocol.MCP_v20250326: return McpHttpTransportV20250326( @@ -98,6 +103,7 @@ def _create_transport(self, protocol: Protocol) -> ITransport: self._client_name, self._client_version, telemetry_enabled=self._telemetry_enabled, + supported_protocols=self._supported_protocols, ) case Protocol.MCP_v20241105: return McpHttpTransportV20241105( @@ -107,6 +113,7 @@ def _create_transport(self, protocol: Protocol) -> ITransport: self._client_name, self._client_version, telemetry_enabled=self._telemetry_enabled, + supported_protocols=self._supported_protocols, ) case _: raise ValueError(f"Unsupported MCP protocol version: {protocol}") @@ -166,7 +173,7 @@ def __init__( client_headers: Optional[ Mapping[str, Union[Callable[[], str], Callable[[], Awaitable[str]], str]] ] = None, - protocol: Protocol = Protocol.MCP, + protocol: Union[Protocol, list[Protocol], list[str]] = Protocol.MCP, client_name: Optional[str] = None, client_version: Optional[str] = None, telemetry_enabled: bool = False, @@ -188,13 +195,40 @@ def __init__( telemetry_enabled: Whether to enable OpenTelemetry tracing and metrics. (Default: False) """ + if isinstance(protocol, list): + if not protocol: + raise ValueError("protocol list cannot be empty") + user_protocols = [ + p.value if isinstance(p, Protocol) else str(p) for p in protocol + ] + + supported_mcp_versions = Protocol.get_supported_mcp_versions() + for p in user_protocols: + if p not in supported_mcp_versions: + raise ValueError( + f"Invalid protocol version '{p}'. Must be one of: {supported_mcp_versions}" + ) + + user_protocols_set = set(user_protocols) + # Intersect with the globally sorted list to strictly enforce newest-to-oldest ordering + supported_protocols = [ + v for v in supported_mcp_versions if v in user_protocols_set + ] + if not supported_protocols: + raise ValueError("No supported protocols found in the provided list") + initial_protocol = Protocol(supported_protocols[0]) + else: + supported_protocols = None + initial_protocol = protocol + self.__transport = _McpTransportProxy( url, session, - protocol, + initial_protocol, client_name, client_version, telemetry_enabled, + supported_protocols, ) self.__client_headers = client_headers if client_headers is not None else {} diff --git a/packages/toolbox-core/src/toolbox_core/mcp_transport/transport_base.py b/packages/toolbox-core/src/toolbox_core/mcp_transport/transport_base.py index 735ae9066..9ffc2ebc8 100644 --- a/packages/toolbox-core/src/toolbox_core/mcp_transport/transport_base.py +++ b/packages/toolbox-core/src/toolbox_core/mcp_transport/transport_base.py @@ -42,6 +42,7 @@ def __init__( client_name: Optional[str] = None, client_version: Optional[str] = None, telemetry_enabled: bool = False, + supported_protocols: Optional[list[str]] = None, ): self._mcp_base_url = f"{base_url}/mcp/" self._protocol_version = protocol.value @@ -50,6 +51,9 @@ def __init__( self._client_name = client_name self._client_version = client_version self._telemetry_enabled = telemetry.resolve_telemetry_enabled(telemetry_enabled) + self._supported_protocols = ( + supported_protocols or Protocol.get_supported_mcp_versions() + ) self._tracer: Optional[telemetry.Tracer] = None self._operation_duration_histogram: Optional[telemetry.Histogram] = None diff --git a/packages/toolbox-core/src/toolbox_core/mcp_transport/v20250618/mcp.py b/packages/toolbox-core/src/toolbox_core/mcp_transport/v20250618/mcp.py index 2ea3ee636..35f759346 100644 --- a/packages/toolbox-core/src/toolbox_core/mcp_transport/v20250618/mcp.py +++ b/packages/toolbox-core/src/toolbox_core/mcp_transport/v20250618/mcp.py @@ -75,7 +75,7 @@ async def _send_request( err_val = json_resp["error"] if isinstance(err_val, dict) and err_val.get("code") == -32004: server_supported = err_val.get("data", {}).get("supported", []) - client_supported = Protocol.get_supported_mcp_versions() + client_supported = self._supported_protocols mutually_supported = [ v for v in client_supported if v in server_supported ] diff --git a/packages/toolbox-core/src/toolbox_core/mcp_transport/v20251125/mcp.py b/packages/toolbox-core/src/toolbox_core/mcp_transport/v20251125/mcp.py index 4a0e8d876..bf365dece 100644 --- a/packages/toolbox-core/src/toolbox_core/mcp_transport/v20251125/mcp.py +++ b/packages/toolbox-core/src/toolbox_core/mcp_transport/v20251125/mcp.py @@ -75,7 +75,7 @@ async def _send_request( err_val = json_resp["error"] if isinstance(err_val, dict) and err_val.get("code") == -32004: server_supported = err_val.get("data", {}).get("supported", []) - client_supported = Protocol.get_supported_mcp_versions() + client_supported = self._supported_protocols mutually_supported = [ v for v in client_supported if v in server_supported ] diff --git a/packages/toolbox-core/src/toolbox_core/mcp_transport/v20260618/mcp.py b/packages/toolbox-core/src/toolbox_core/mcp_transport/v20260618/mcp.py index 866249733..f7511e2e5 100644 --- a/packages/toolbox-core/src/toolbox_core/mcp_transport/v20260618/mcp.py +++ b/packages/toolbox-core/src/toolbox_core/mcp_transport/v20260618/mcp.py @@ -88,7 +88,7 @@ async def _send_request( "supported", [] ) - client_supported = Protocol.get_supported_mcp_versions() + client_supported = self._supported_protocols mutually_supported = [ v for v in client_supported if v in server_supported ] @@ -131,7 +131,7 @@ async def _send_request( err_val = json_resp["error"] if isinstance(err_val, dict) and err_val.get("code") == -32004: server_supported = err_val.get("data", {}).get("supported", []) - client_supported = Protocol.get_supported_mcp_versions() + client_supported = self._supported_protocols mutually_supported = [ v for v in client_supported if v in server_supported ] diff --git a/packages/toolbox-core/tests/conftest.py b/packages/toolbox-core/tests/conftest.py index 2e500752e..823e0f86e 100644 --- a/packages/toolbox-core/tests/conftest.py +++ b/packages/toolbox-core/tests/conftest.py @@ -29,6 +29,8 @@ from google.auth import compute_engine from google.cloud import secretmanager, storage +from tests.constants import TOOLBOX_SERVER_URL_DRAFT, TOOLBOX_SERVER_URL_STABLE + #### Define Utility Functions def get_env_var(key: str) -> str: @@ -187,7 +189,7 @@ def toolbox_server(toolbox_version: str, tools_file_path: str) -> Generator[None @pytest.fixture( - params=["http://localhost:5000", "http://localhost:5001"], scope="session" + params=[TOOLBOX_SERVER_URL_STABLE, TOOLBOX_SERVER_URL_DRAFT], scope="session" ) def toolbox_server_url(request) -> str: return request.param @@ -201,13 +203,13 @@ def patch_toolbox_client_url(toolbox_server_url): original_init = ToolboxClient.__init__ original_sync_init = ToolboxSyncClient.__init__ - def new_init(self, url="http://localhost:5000", *args, **kwargs): - if url == "http://localhost:5000": + def new_init(self, url=TOOLBOX_SERVER_URL_STABLE, *args, **kwargs): + if url == TOOLBOX_SERVER_URL_STABLE: url = toolbox_server_url original_init(self, url, *args, **kwargs) - def new_sync_init(self, url="http://localhost:5000", *args, **kwargs): - if url == "http://localhost:5000": + def new_sync_init(self, url=TOOLBOX_SERVER_URL_STABLE, *args, **kwargs): + if url == TOOLBOX_SERVER_URL_STABLE: url = toolbox_server_url original_sync_init(self, url, *args, **kwargs) diff --git a/packages/toolbox-core/tests/constants.py b/packages/toolbox-core/tests/constants.py new file mode 100644 index 000000000..701f830e6 --- /dev/null +++ b/packages/toolbox-core/tests/constants.py @@ -0,0 +1,16 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +TOOLBOX_SERVER_URL_STABLE = "http://localhost:5000" +TOOLBOX_SERVER_URL_DRAFT = "http://localhost:5001" diff --git a/packages/toolbox-core/tests/test_client.py b/packages/toolbox-core/tests/test_client.py index e28bb03a1..5466760d0 100644 --- a/packages/toolbox-core/tests/test_client.py +++ b/packages/toolbox-core/tests/test_client.py @@ -21,6 +21,7 @@ import pytest from aiohttp import web +from tests.constants import TOOLBOX_SERVER_URL_STABLE from toolbox_core.client import ToolboxClient from toolbox_core.itransport import ITransport from toolbox_core.protocol import ( @@ -814,7 +815,7 @@ def test_toolbox_client_no_warning_on_mcp(): with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") - client = ToolboxClient("http://localhost:5000", protocol=Protocol.MCP) + client = ToolboxClient(TOOLBOX_SERVER_URL_STABLE, protocol=Protocol.MCP) assert len(w) == 0 @@ -825,6 +826,33 @@ def test_toolbox_client_no_warning_on_explicit_mcp_version(): warnings.simplefilter("always") client = ToolboxClient( - "http://localhost:5000", protocol=Protocol.MCP_v20251125 + TOOLBOX_SERVER_URL_STABLE, protocol=Protocol.MCP_v20251125 ) assert len(w) == 0 + + +def test_toolbox_client_custom_protocols(): + """Test that custom protocols array is correctly parsed and sorted.""" + with patch("toolbox_core.client._McpTransportProxy") as mock_proxy: + client = ToolboxClient( + TOOLBOX_SERVER_URL_STABLE, + protocol=[Protocol.MCP_v20241105, Protocol.MCP_DRAFT, "2025-06-18"], + ) + mock_proxy.assert_called_once() + args, kwargs = mock_proxy.call_args + + # 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"] + + +def test_toolbox_client_custom_protocols_invalid(): + """Test that custom protocols array raises error on invalid inputs.""" + import pytest + + with pytest.raises(ValueError, match="protocol list cannot be empty"): + ToolboxClient(TOOLBOX_SERVER_URL_STABLE, protocol=[]) + + with pytest.raises(ValueError, match="Invalid protocol version 'invalid-version'"): + ToolboxClient(TOOLBOX_SERVER_URL_STABLE, protocol=["invalid-version"]) diff --git a/packages/toolbox-core/tests/test_e2e.py b/packages/toolbox-core/tests/test_e2e.py index 0b926e178..7ed28a3e9 100644 --- a/packages/toolbox-core/tests/test_e2e.py +++ b/packages/toolbox-core/tests/test_e2e.py @@ -19,6 +19,7 @@ import pytest_asyncio from pydantic import ValidationError +from tests.constants import TOOLBOX_SERVER_URL_STABLE from toolbox_core.client import ToolboxClient from toolbox_core.protocol import Protocol from toolbox_core.tool import ToolboxTool @@ -28,7 +29,7 @@ @pytest_asyncio.fixture(scope="function") async def toolbox(): """Creates a ToolboxClient instance shared by all tests in this module.""" - toolbox = ToolboxClient("http://localhost:5000", protocol=Protocol.MCP) + toolbox = ToolboxClient(TOOLBOX_SERVER_URL_STABLE, protocol=Protocol.MCP) try: yield toolbox finally: @@ -112,7 +113,7 @@ async def test_run_tool_wrong_param_type(self, get_n_rows_tool: ToolboxTool): async def test_load_and_run_tool_with_telemetry(self, telemetry_enabled: bool): """Load and invoke a tool with telemetry_enabled=True/False.""" async with ToolboxClient( - "http://localhost:5000", + TOOLBOX_SERVER_URL_STABLE, protocol=Protocol.MCP, telemetry_enabled=telemetry_enabled, ) as toolbox: diff --git a/packages/toolbox-core/tests/test_e2e_mcp.py b/packages/toolbox-core/tests/test_e2e_mcp.py index 7ffb3ddfa..5a47e181c 100644 --- a/packages/toolbox-core/tests/test_e2e_mcp.py +++ b/packages/toolbox-core/tests/test_e2e_mcp.py @@ -19,6 +19,7 @@ import pytest_asyncio from pydantic import ValidationError +from tests.constants import TOOLBOX_SERVER_URL_DRAFT, TOOLBOX_SERVER_URL_STABLE from toolbox_core.client import ToolboxClient from toolbox_core.protocol import Protocol from toolbox_core.tool import ToolboxTool @@ -30,7 +31,7 @@ ) async def toolbox(request): """Creates a ToolboxClient instance shared by all tests in this module.""" - toolbox = ToolboxClient("http://localhost:5000", protocol=Protocol(request.param)) + toolbox = ToolboxClient(TOOLBOX_SERVER_URL_STABLE, protocol=Protocol(request.param)) try: yield toolbox finally: @@ -100,8 +101,8 @@ async def test_run_tool_missing_params(self, get_n_rows_tool: ToolboxTool): async def test_protocol_fallback_e2e(self, toolbox_server_url: str): """Tests that a client using MCP_DRAFT can fallback to an older protocol against a server that doesn't support the draft version.""" - # The E2E server currently does not support DRAFT 2026 on port 5000, so this will trigger a fallback. - # However, port 5001 does support DRAFT 2026. + # The stable server currently does not support DRAFT 2026, so this will trigger a fallback. + # However, the draft server does support DRAFT 2026. async with ToolboxClient( toolbox_server_url, protocol=Protocol.MCP_DRAFT ) as client: @@ -109,7 +110,7 @@ async def test_protocol_fallback_e2e(self, toolbox_server_url: str): response = await tool(num_rows="1") assert "row1" in response # Verify that fallback occurred by checking the transport's final protocol version - if "5001" in toolbox_server_url: + if toolbox_server_url == TOOLBOX_SERVER_URL_DRAFT: assert ( client._ToolboxClient__transport._protocol_version == Protocol.MCP_DRAFT.value @@ -472,9 +473,9 @@ async def test_run_tool_with_wrong_map_value_type(self, toolbox: ToolboxClient): @pytest.mark.asyncio @pytest.mark.usefixtures("toolbox_server") -async def test_mcp_default_protocol(): +async def test_mcp_default_protocol(toolbox_server_url: str): """Verify that omitting the protocol argument defaults correctly and works.""" - async with ToolboxClient("http://localhost:5000") as client: + async with ToolboxClient(toolbox_server_url) as client: tool = await client.load_tool("get-n-rows") response = await tool(num_rows="1") assert "row1" in response @@ -482,11 +483,47 @@ async def test_mcp_default_protocol(): @pytest.mark.asyncio @pytest.mark.usefixtures("toolbox_server") -async def test_mcp_draft_fallback(): +async def test_mcp_draft_fallback(toolbox_server_url: str): """Verify that explicitly using MCP_DRAFT against a server that doesn't support it falls back successfully.""" + async with ToolboxClient(toolbox_server_url, protocol=Protocol.MCP_DRAFT) as client: + tool = await client.load_tool("get-n-rows") + response = await tool(num_rows="1") + assert "row1" in response + + +@pytest.mark.asyncio +@pytest.mark.usefixtures("toolbox_server") +async def test_mcp_latest_protocol(toolbox_server_url: str): + """Verify that explicitly using MCP_LATEST works successfully.""" async with ToolboxClient( - "http://localhost:5000", protocol=Protocol.MCP_DRAFT + toolbox_server_url, protocol=Protocol.MCP_LATEST ) as client: tool = await client.load_tool("get-n-rows") response = await tool(num_rows="1") assert "row1" in response + assert ( + client._ToolboxClient__transport._protocol_version + == Protocol.MCP_LATEST.value + ) + + +@pytest.mark.asyncio +@pytest.mark.usefixtures("toolbox_server") +async def test_mcp_custom_protocols_list(toolbox_server_url: str): + """Verify that passing a list of protocols with MCP_LATEST and MCP_DRAFT works successfully.""" + async with ToolboxClient( + toolbox_server_url, protocol=[Protocol.MCP_DRAFT, Protocol.MCP_LATEST] + ) as client: + tool = await client.load_tool("get-n-rows") + response = await tool(num_rows="1") + assert "row1" in response + if toolbox_server_url == TOOLBOX_SERVER_URL_STABLE: + assert ( + client._ToolboxClient__transport._protocol_version + == Protocol.MCP_LATEST.value + ) + else: + assert ( + client._ToolboxClient__transport._protocol_version + == Protocol.MCP_DRAFT.value + ) diff --git a/packages/toolbox-core/tests/test_sync_e2e.py b/packages/toolbox-core/tests/test_sync_e2e.py index a306cedc2..4d26bc1e6 100644 --- a/packages/toolbox-core/tests/test_sync_e2e.py +++ b/packages/toolbox-core/tests/test_sync_e2e.py @@ -14,6 +14,7 @@ import pytest +from tests.constants import TOOLBOX_SERVER_URL_STABLE from toolbox_core.sync_client import ToolboxSyncClient from toolbox_core.sync_tool import ToolboxSyncTool @@ -22,7 +23,7 @@ @pytest.fixture(scope="module") def toolbox(): """Creates a ToolboxSyncClient instance shared by all tests in this module.""" - toolbox = ToolboxSyncClient("http://localhost:5000") + toolbox = ToolboxSyncClient(TOOLBOX_SERVER_URL_STABLE) try: yield toolbox finally: diff --git a/packages/toolbox-langchain/src/toolbox_langchain/async_client.py b/packages/toolbox-langchain/src/toolbox_langchain/async_client.py index 8d389d8c2..5f516c22a 100644 --- a/packages/toolbox-langchain/src/toolbox_langchain/async_client.py +++ b/packages/toolbox-langchain/src/toolbox_langchain/async_client.py @@ -17,6 +17,7 @@ from aiohttp import ClientSession from toolbox_core.client import ToolboxClient as ToolboxCoreClient +from typing import Any, Sequence from toolbox_core.protocol import Protocol from .async_tools import AsyncToolboxTool @@ -35,7 +36,7 @@ def __init__( client_headers: Optional[ Mapping[str, Union[Callable[[], str], Callable[[], Awaitable[str]], str]] ] = None, - protocol: Protocol = Protocol.MCP, + protocol: Protocol | Sequence[Protocol] = Protocol.MCP, telemetry_enabled: bool = False, ): """ diff --git a/packages/toolbox-langchain/src/toolbox_langchain/client.py b/packages/toolbox-langchain/src/toolbox_langchain/client.py index e0f607303..633cc70a4 100644 --- a/packages/toolbox-langchain/src/toolbox_langchain/client.py +++ b/packages/toolbox-langchain/src/toolbox_langchain/client.py @@ -16,6 +16,7 @@ from typing import Any, Awaitable, Callable, Mapping, Optional, Union from warnings import warn +from typing import Any, Sequence from toolbox_core.protocol import Protocol from toolbox_core.sync_client import ToolboxSyncClient as ToolboxCoreSyncClient @@ -31,7 +32,7 @@ def __init__( client_headers: Optional[ Mapping[str, Union[Callable[[], str], Callable[[], Awaitable[str]], str]] ] = None, - protocol: Protocol = Protocol.MCP, + protocol: Protocol | Sequence[Protocol] = Protocol.MCP, telemetry_enabled: bool = False, ) -> None: """ diff --git a/packages/toolbox-llamaindex/src/toolbox_llamaindex/async_client.py b/packages/toolbox-llamaindex/src/toolbox_llamaindex/async_client.py index e38563ee0..150a2ff2a 100644 --- a/packages/toolbox-llamaindex/src/toolbox_llamaindex/async_client.py +++ b/packages/toolbox-llamaindex/src/toolbox_llamaindex/async_client.py @@ -17,6 +17,7 @@ from aiohttp import ClientSession from toolbox_core.client import ToolboxClient as ToolboxCoreClient +from typing import Any, Sequence from toolbox_core.protocol import Protocol from .async_tools import AsyncToolboxTool @@ -35,7 +36,7 @@ def __init__( client_headers: Optional[ Mapping[str, Union[Callable[[], str], Callable[[], Awaitable[str]], str]] ] = None, - protocol: Protocol = Protocol.MCP, + protocol: Protocol | Sequence[Protocol] = Protocol.MCP, telemetry_enabled: bool = False, ): """ diff --git a/packages/toolbox-llamaindex/src/toolbox_llamaindex/client.py b/packages/toolbox-llamaindex/src/toolbox_llamaindex/client.py index 8cd7d16ce..6f3e63b0d 100644 --- a/packages/toolbox-llamaindex/src/toolbox_llamaindex/client.py +++ b/packages/toolbox-llamaindex/src/toolbox_llamaindex/client.py @@ -16,6 +16,7 @@ from typing import Any, Awaitable, Callable, Mapping, Optional, Union from warnings import warn +from typing import Any, Sequence from toolbox_core.protocol import Protocol from toolbox_core.sync_client import ToolboxSyncClient as ToolboxCoreSyncClient from toolbox_core.sync_tool import ToolboxSyncTool @@ -32,7 +33,7 @@ def __init__( client_headers: Optional[ Mapping[str, Union[Callable[[], str], Callable[[], Awaitable[str]], str]] ] = None, - protocol: Protocol = Protocol.MCP, + protocol: Protocol | Sequence[Protocol] = Protocol.MCP, telemetry_enabled: bool = False, ) -> None: """