From 7dbe1b8b59b8c5cf06e833df0ea3c2fff8c20429 Mon Sep 17 00:00:00 2001 From: Vladimir Blagojevic Date: Mon, 21 Apr 2025 12:06:19 +0200 Subject: [PATCH 01/10] Deprecate SSEServerInfo base_url --- .../tools/mcp/mcp_tool.py | 49 +++++++++++++++---- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py b/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py index 8f8e3eaf14..9f6edcbf7a 100644 --- a/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py +++ b/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py @@ -351,16 +351,31 @@ class SSEClient(MCPClient): MCP client that connects to servers using SSE transport. """ - def __init__(self, base_url: str, token: str | None = None, timeout: int = 5) -> None: + def __init__(self, url: str | None = None, base_url: str | None = None, token: str | None = None, timeout: int = 5) -> None: """ Initialize an SSE MCP client. - :param base_url: Base URL of the server + :param url: Full URL of the server (including /sse endpoint) + :param base_url: Base URL of the server (deprecated, use url instead) :param token: Authentication token for the server (optional) :param timeout: Connection timeout in seconds """ super().__init__() - self.base_url: str = base_url.rstrip("/") # Remove any trailing slashes + if url is None and base_url is None: + raise ValueError("Either url or base_url must be provided") + if url is not None and base_url is not None: + raise ValueError("Only one of url or base_url should be provided") + + if base_url is not None: + import warnings + warnings.warn( + "base_url is deprecated and will be removed in a future version. Use url instead.", + DeprecationWarning, + stacklevel=2, + ) + self.url = f"{base_url.rstrip('/')}/sse" # Remove any trailing slashes and add /sse + else: + self.url = url self.token: str | None = token self.timeout: int = timeout @@ -371,12 +386,11 @@ async def connect(self) -> list[Tool]: :returns: List of available tools on the server :raises MCPConnectionError: If connection to the server fails """ - sse_url = f"{self.base_url}/sse" headers = {"Authorization": f"Bearer {self.token}"} if self.token else None sse_transport = await self.exit_stack.enter_async_context( - sse_client(sse_url, headers=headers, timeout=self.timeout) + sse_client(self.url, headers=headers, timeout=self.timeout) ) - return await self._initialize_session_with_transport(sse_transport, f"HTTP server at {self.base_url}") + return await self._initialize_session_with_transport(sse_transport, f"HTTP server at {self.url}") @dataclass @@ -432,22 +446,39 @@ class SSEServerInfo(MCPServerInfo): """ Data class that encapsulates SSE MCP server connection parameters. - :param base_url: Base URL of the MCP server + :param url: Full URL of the MCP server (including /sse endpoint) + :param base_url: Base URL of the MCP server (deprecated, use url instead) :param token: Authentication token for the server (optional) :param timeout: Connection timeout in seconds """ - base_url: str + url: str | None = None + base_url: str | None = None # deprecated token: str | None = None timeout: int = 30 + def __post_init__(self): + """Validate that either url or base_url is provided.""" + if self.url is None and self.base_url is None: + raise ValueError("Either url or base_url must be provided") + if self.url is not None and self.base_url is not None: + raise ValueError("Only one of url or base_url should be provided") + def create_client(self) -> MCPClient: """ Create an SSE MCP client. :returns: Configured HttpMCPClient instance """ - return SSEClient(self.base_url, self.token, self.timeout) + if self.base_url is not None: + import warnings + warnings.warn( + "base_url is deprecated and will be removed in a future version. Use url instead.", + DeprecationWarning, + stacklevel=2, + ) + return SSEClient(base_url=self.base_url, token=self.token, timeout=self.timeout) + return SSEClient(url=self.url, token=self.token, timeout=self.timeout) @dataclass From 56ef24e737f599bebee071b7a2c08175f5fe6835 Mon Sep 17 00:00:00 2001 From: Vladimir Blagojevic Date: Mon, 21 Apr 2025 12:21:08 +0200 Subject: [PATCH 02/10] Lint and mypy --- .../tools/mcp/mcp_tool.py | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py b/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py index 9f6edcbf7a..a6680a5098 100644 --- a/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py +++ b/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py @@ -351,7 +351,9 @@ class SSEClient(MCPClient): MCP client that connects to servers using SSE transport. """ - def __init__(self, url: str | None = None, base_url: str | None = None, token: str | None = None, timeout: int = 5) -> None: + def __init__( + self, url: str | None = None, base_url: str | None = None, token: str | None = None, timeout: int = 5 + ) -> None: """ Initialize an SSE MCP client. @@ -362,19 +364,23 @@ def __init__(self, url: str | None = None, base_url: str | None = None, token: s """ super().__init__() if url is None and base_url is None: - raise ValueError("Either url or base_url must be provided") - if url is not None and base_url is not None: - raise ValueError("Only one of url or base_url should be provided") + message = "Either url or base_url must be provided" + raise ValueError(message) + if url and base_url: + message = "Only one of url or base_url should be provided" + raise ValueError(message) - if base_url is not None: + if base_url: import warnings + warnings.warn( "base_url is deprecated and will be removed in a future version. Use url instead.", DeprecationWarning, stacklevel=2, ) self.url = f"{base_url.rstrip('/')}/sse" # Remove any trailing slashes and add /sse - else: + elif url: + # Always true here in this branch but mypy doesn't know that self.url = url self.token: str | None = token self.timeout: int = timeout @@ -460,9 +466,11 @@ class SSEServerInfo(MCPServerInfo): def __post_init__(self): """Validate that either url or base_url is provided.""" if self.url is None and self.base_url is None: - raise ValueError("Either url or base_url must be provided") + message = "Either url or base_url must be provided" + raise ValueError(message) if self.url is not None and self.base_url is not None: - raise ValueError("Only one of url or base_url should be provided") + message = "Only one of url or base_url should be provided" + raise ValueError(message) def create_client(self) -> MCPClient: """ @@ -472,6 +480,7 @@ def create_client(self) -> MCPClient: """ if self.base_url is not None: import warnings + warnings.warn( "base_url is deprecated and will be removed in a future version. Use url instead.", DeprecationWarning, From 07113d99fa1bd31db64613ba0cce9d676fd98d78 Mon Sep 17 00:00:00 2001 From: Vladimir Blagojevic Date: Mon, 21 Apr 2025 14:18:51 +0200 Subject: [PATCH 03/10] Leave base_url field until deprecation removed --- .../mcp/src/haystack_integrations/tools/mcp/mcp_tool.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py b/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py index a6680a5098..c57f4b9eeb 100644 --- a/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py +++ b/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py @@ -382,6 +382,8 @@ def __init__( elif url: # Always true here in this branch but mypy doesn't know that self.url = url + + self.base_url = base_url # leave this here for backwards compatibility (and remove in future) self.token: str | None = token self.timeout: int = timeout From 3c9e9b63a145ab0b5fffdcec355ead65d5a5108f Mon Sep 17 00:00:00 2001 From: Vladimir Blagojevic Date: Mon, 21 Apr 2025 14:36:37 +0200 Subject: [PATCH 04/10] Add unit test, final touches --- .../tools/mcp/mcp_tool.py | 20 ++++++++++--------- integrations/mcp/tests/test_mcp_tool.py | 20 +++++++++++++++++++ 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py b/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py index c57f4b9eeb..2bc675571e 100644 --- a/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py +++ b/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py @@ -467,20 +467,14 @@ class SSEServerInfo(MCPServerInfo): def __post_init__(self): """Validate that either url or base_url is provided.""" - if self.url is None and self.base_url is None: + if not self.url and not self.base_url: message = "Either url or base_url must be provided" raise ValueError(message) - if self.url is not None and self.base_url is not None: + if self.url and self.base_url: message = "Only one of url or base_url should be provided" raise ValueError(message) - def create_client(self) -> MCPClient: - """ - Create an SSE MCP client. - - :returns: Configured HttpMCPClient instance - """ - if self.base_url is not None: + if self.base_url: import warnings warnings.warn( @@ -488,6 +482,14 @@ def create_client(self) -> MCPClient: DeprecationWarning, stacklevel=2, ) + + def create_client(self) -> MCPClient: + """ + Create an SSE MCP client. + + :returns: Configured HttpMCPClient instance + """ + if self.base_url: return SSEClient(base_url=self.base_url, token=self.token, timeout=self.timeout) return SSEClient(url=self.url, token=self.token, timeout=self.timeout) diff --git a/integrations/mcp/tests/test_mcp_tool.py b/integrations/mcp/tests/test_mcp_tool.py index e42866cca2..b56bbc647d 100644 --- a/integrations/mcp/tests/test_mcp_tool.py +++ b/integrations/mcp/tests/test_mcp_tool.py @@ -132,6 +132,26 @@ def test_http_server_info_serde(self): assert new_info.token == "test-token" assert new_info.timeout == 45 + def test_url_base_url_validation(self): + """Test validation of url and base_url parameters.""" + # Test with neither url nor base_url + with pytest.raises(ValueError, match="Either url or base_url must be provided"): + SSEServerInfo() + + # Test with both url and base_url + with pytest.raises(ValueError, match="Only one of url or base_url should be provided"): + SSEServerInfo(url="http://example.com/sse", base_url="http://example.com") + + # Test with only url + server_info = SSEServerInfo(url="http://example.com/sse") + assert server_info.url == "http://example.com/sse" + assert server_info.base_url is None + + # Test with only base_url (deprecated but supported) + with pytest.warns(DeprecationWarning, match="base_url is deprecated"): + server_info = SSEServerInfo(base_url="http://example.com") + assert server_info.base_url == "http://example.com" # Should preserve original base_url + def test_stdio_server_info_serde(self): """Test serialization/deserialization of StdioServerInfo.""" server_info = StdioServerInfo(command="python", args=["-m", "mcp_server_time"], env={"TEST_ENV": "value"}) From 9ee6cecd1b8c3525648602f0fc80f43e4d7bac8e Mon Sep 17 00:00:00 2001 From: Vladimir Blagojevic Date: Mon, 28 Apr 2025 15:08:18 +0200 Subject: [PATCH 05/10] Update example --- .../mcp/src/haystack_integrations/tools/mcp/mcp_tool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py b/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py index 2bc675571e..aa6aace472 100644 --- a/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py +++ b/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py @@ -535,7 +535,7 @@ class MCPTool(Tool): # Create tool instance tool = MCPTool( name="add", - server_info=SSEServerInfo(base_url="http://localhost:8000") + server_info=SSEServerInfo(url="http://localhost:8000/sse") ) # Use the tool From b224aa423b1c9e3466ff36ff855248c393a7ac9a Mon Sep 17 00:00:00 2001 From: Vladimir Blagojevic Date: Mon, 28 Apr 2025 15:35:31 +0200 Subject: [PATCH 06/10] More URL checks, better error reporting --- .../tools/mcp/mcp_tool.py | 10 +++++++ .../tools/mcp/mcp_toolset.py | 26 +++++++++++++++---- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py b/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py index aa6aace472..dcf02100b0 100644 --- a/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py +++ b/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py @@ -16,6 +16,7 @@ from haystack.core.serialization import generate_qualified_class_name, import_class_by_name from haystack.tools import Tool from haystack.tools.errors import ToolInvocationError +from haystack.utils.url_validation import is_valid_http_url from mcp import ClientSession, StdioServerParameters, types from mcp.client.sse import sse_client @@ -475,6 +476,10 @@ def __post_init__(self): raise ValueError(message) if self.base_url: + if not is_valid_http_url(self.base_url): + message = f"Invalid base_url: {self.base_url}" + raise ValueError(message) + import warnings warnings.warn( @@ -483,6 +488,11 @@ def __post_init__(self): stacklevel=2, ) + if self.url: + if not is_valid_http_url(self.url): + message = f"Invalid url: {self.url}" + raise ValueError(message) + def create_client(self) -> MCPClient: """ Create an SSE MCP client. diff --git a/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_toolset.py b/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_toolset.py index df0bd15994..d7bb358e87 100644 --- a/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_toolset.py +++ b/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_toolset.py @@ -3,6 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 from typing import Any +from urllib.parse import urlparse import httpx from exceptiongroup import ExceptionGroup @@ -88,7 +89,7 @@ class MCPToolset(Toolset): # Create the toolset with an SSE connection sse_toolset = MCPToolset( - server_info=SSEServerInfo(base_url="http://some-remote-server.com:8000"), + server_info=SSEServerInfo(url="http://some-remote-server.com:8000/sse"), tool_names=["add", "subtract"] # Only include specific tools ) @@ -175,7 +176,8 @@ def invoke_tool(**kwargs) -> Any: except Exception as e: if isinstance(self.server_info, SSEServerInfo): - base_message = f"Failed to connect to SSE server at {self.server_info.base_url}" + url = self.server_info.url or self.server_info.base_url + base_message = f"Failed to connect to SSE server at {url}" checks = ["1. The server is running"] # Check for ConnectError in exception group or direct exception @@ -184,10 +186,24 @@ def invoke_tool(**kwargs) -> Any: ) if has_connect_error: - port = self.server_info.base_url.split(":")[-1] - checks.append(f"2. The address and port are correct (attempted port: {port})") + # Use urlparse to reliably get scheme, hostname, and port + parsed_url = urlparse(url) + port_str = "" + if parsed_url.port: + port_str = str(parsed_url.port) + elif parsed_url.scheme == "http": + port_str = "80 (default)" + elif parsed_url.scheme == "https": + port_str = "443 (default)" + else: + port_str = "unknown (scheme not http/https or missing)" # Or handle more schemes if needed + + # Ensure hostname is handled correctly (it might be None) + hostname_str = str(parsed_url.hostname) if parsed_url.hostname else "" + message = f"2. The address '{hostname_str}' and port '{port_str}' are correct" + checks.append(message) checks.append("3. There are no firewall or network connectivity issues") - message = f"{base_message}. Please check if:\n" + "\n".join(checks) + message = f"{base_message}. Please check if:\n" + "\\n".join(checks) else: message = f"{base_message}: {e}" elif isinstance(self.server_info, StdioServerInfo): # stdio connection From 9f737b46193331cde7cce5c60ccb576fba532fce Mon Sep 17 00:00:00 2001 From: Vladimir Blagojevic Date: Mon, 28 Apr 2025 15:47:19 +0200 Subject: [PATCH 07/10] Simplify internals --- .../tools/mcp/mcp_tool.py | 44 ++++--------------- integrations/mcp/tests/test_mcp_tool.py | 2 +- 2 files changed, 10 insertions(+), 36 deletions(-) diff --git a/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py b/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py index dcf02100b0..a2b2b47cd5 100644 --- a/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py +++ b/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py @@ -352,41 +352,16 @@ class SSEClient(MCPClient): MCP client that connects to servers using SSE transport. """ - def __init__( - self, url: str | None = None, base_url: str | None = None, token: str | None = None, timeout: int = 5 - ) -> None: + def __init__(self, server_info: "SSEServerInfo") -> None: """ - Initialize an SSE MCP client. + Initialize an SSE MCP client using server configuration. - :param url: Full URL of the server (including /sse endpoint) - :param base_url: Base URL of the server (deprecated, use url instead) - :param token: Authentication token for the server (optional) - :param timeout: Connection timeout in seconds + :param server_info: Configuration object containing URL, token, timeout, etc. """ super().__init__() - if url is None and base_url is None: - message = "Either url or base_url must be provided" - raise ValueError(message) - if url and base_url: - message = "Only one of url or base_url should be provided" - raise ValueError(message) - - if base_url: - import warnings - - warnings.warn( - "base_url is deprecated and will be removed in a future version. Use url instead.", - DeprecationWarning, - stacklevel=2, - ) - self.url = f"{base_url.rstrip('/')}/sse" # Remove any trailing slashes and add /sse - elif url: - # Always true here in this branch but mypy doesn't know that - self.url = url - - self.base_url = base_url # leave this here for backwards compatibility (and remove in future) - self.token: str | None = token - self.timeout: int = timeout + self.url: str = server_info.url or f"{server_info.base_url}/sse" + self.token: str | None = server_info.token + self.timeout: int = server_info.timeout async def connect(self) -> list[Tool]: """ @@ -497,11 +472,10 @@ def create_client(self) -> MCPClient: """ Create an SSE MCP client. - :returns: Configured HttpMCPClient instance + :returns: Configured SSEClient instance """ - if self.base_url: - return SSEClient(base_url=self.base_url, token=self.token, timeout=self.timeout) - return SSEClient(url=self.url, token=self.token, timeout=self.timeout) + # Pass the validated SSEServerInfo instance directly + return SSEClient(server_info=self) @dataclass diff --git a/integrations/mcp/tests/test_mcp_tool.py b/integrations/mcp/tests/test_mcp_tool.py index e5d595ae16..1eef41ca16 100644 --- a/integrations/mcp/tests/test_mcp_tool.py +++ b/integrations/mcp/tests/test_mcp_tool.py @@ -177,7 +177,7 @@ def test_create_client(self): http_client = http_info.create_client() stdio_client = stdio_info.create_client() - assert http_client.base_url == "http://example.com" + assert http_client.url == "http://example.com/sse" assert stdio_client.command == "python" From fec96533b8fe627bc02b1129531f5f9a16faa913 Mon Sep 17 00:00:00 2001 From: Vladimir Blagojevic Date: Mon, 28 Apr 2025 16:05:01 +0200 Subject: [PATCH 08/10] Minor simplification --- .../tools/mcp/mcp_tool.py | 21 +++++++++++-------- .../tools/mcp/mcp_toolset.py | 5 ++--- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py b/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py index a2b2b47cd5..2d288b3e9b 100644 --- a/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py +++ b/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py @@ -5,6 +5,7 @@ import asyncio import concurrent.futures import threading +import warnings from abc import ABC, abstractmethod from collections.abc import Coroutine from contextlib import AsyncExitStack @@ -359,7 +360,10 @@ def __init__(self, server_info: "SSEServerInfo") -> None: :param server_info: Configuration object containing URL, token, timeout, etc. """ super().__init__() - self.url: str = server_info.url or f"{server_info.base_url}/sse" + + # in post_init we validate the url and set the url field so it is guaranteed to be valid + # safely ignore the mypy warning here + self.url: str = server_info.url # type: ignore[assignment] self.token: str | None = server_info.token self.timeout: int = server_info.timeout @@ -447,26 +451,25 @@ def __post_init__(self): message = "Either url or base_url must be provided" raise ValueError(message) if self.url and self.base_url: - message = "Only one of url or base_url should be provided" - raise ValueError(message) + message = "Only one of url or base_url should be provided, if both are provided, base_url will be ignored" + warnings.warn(message, DeprecationWarning, stacklevel=2) if self.base_url: if not is_valid_http_url(self.base_url): message = f"Invalid base_url: {self.base_url}" raise ValueError(message) - import warnings - warnings.warn( "base_url is deprecated and will be removed in a future version. Use url instead.", DeprecationWarning, stacklevel=2, ) + # from now on only use url for the lifetime of the SSEServerInfo instance, never base_url + self.url = f"{self.base_url.rstrip('/')}/sse" - if self.url: - if not is_valid_http_url(self.url): - message = f"Invalid url: {self.url}" - raise ValueError(message) + elif not is_valid_http_url(self.url): + message = f"Invalid url: {self.url}" + raise ValueError(message) def create_client(self) -> MCPClient: """ diff --git a/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_toolset.py b/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_toolset.py index d7bb358e87..93928b84b9 100644 --- a/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_toolset.py +++ b/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_toolset.py @@ -176,8 +176,7 @@ def invoke_tool(**kwargs) -> Any: except Exception as e: if isinstance(self.server_info, SSEServerInfo): - url = self.server_info.url or self.server_info.base_url - base_message = f"Failed to connect to SSE server at {url}" + base_message = f"Failed to connect to SSE server at {self.server_info.url}" checks = ["1. The server is running"] # Check for ConnectError in exception group or direct exception @@ -187,7 +186,7 @@ def invoke_tool(**kwargs) -> Any: if has_connect_error: # Use urlparse to reliably get scheme, hostname, and port - parsed_url = urlparse(url) + parsed_url = urlparse(self.server_info.url) port_str = "" if parsed_url.port: port_str = str(parsed_url.port) From 05f671d9fbf4608e1ad921248ca60dcad4265990 Mon Sep 17 00:00:00 2001 From: Vladimir Blagojevic Date: Mon, 28 Apr 2025 16:08:59 +0200 Subject: [PATCH 09/10] Small test fix --- integrations/mcp/tests/test_mcp_tool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrations/mcp/tests/test_mcp_tool.py b/integrations/mcp/tests/test_mcp_tool.py index 1eef41ca16..cf6d106a42 100644 --- a/integrations/mcp/tests/test_mcp_tool.py +++ b/integrations/mcp/tests/test_mcp_tool.py @@ -139,7 +139,7 @@ def test_url_base_url_validation(self): SSEServerInfo() # Test with both url and base_url - with pytest.raises(ValueError, match="Only one of url or base_url should be provided"): + with pytest.warns(DeprecationWarning, match="base_url is deprecated"): SSEServerInfo(url="http://example.com/sse", base_url="http://example.com") # Test with only url From 143a9bbd99d902f939fa8c96091ebbac1ebcdfc8 Mon Sep 17 00:00:00 2001 From: Vladimir Blagojevic Date: Mon, 5 May 2025 15:51:13 +0200 Subject: [PATCH 10/10] PR feedback --- .../mcp/src/haystack_integrations/tools/mcp/mcp_tool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py b/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py index 2d288b3e9b..68f1bf7de0 100644 --- a/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py +++ b/integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py @@ -475,7 +475,7 @@ def create_client(self) -> MCPClient: """ Create an SSE MCP client. - :returns: Configured SSEClient instance + :returns: Configured MCPClient instance """ # Pass the validated SSEServerInfo instance directly return SSEClient(server_info=self)