From 71b32890f5ab279e2bed1fd28c0f4693cba3f45e Mon Sep 17 00:00:00 2001 From: Kathy Wu Date: Thu, 18 Dec 2025 16:06:13 -0800 Subject: [PATCH] fix: Only prepend "https://" to the MCP server url if it doesn't already have a scheme There isn't a consistent format for MCP server urls in the registry-- some customers add the https:// but others don't. To standardize, only prepend if it isn't there already. Co-authored-by: Kathy Wu PiperOrigin-RevId: 846451152 --- src/google/adk/tools/api_registry.py | 6 ++- tests/unittests/tools/test_api_registry.py | 52 +++++++++++++++++++++- 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/src/google/adk/tools/api_registry.py b/src/google/adk/tools/api_registry.py index 01c6c706..313fd6c4 100644 --- a/src/google/adk/tools/api_registry.py +++ b/src/google/adk/tools/api_registry.py @@ -102,9 +102,13 @@ class ApiRegistry: mcp_server_url = server["urls"][0] headers = self._get_auth_headers() + # Only prepend "https://" if the URL doesn't already have a scheme + if not mcp_server_url.startswith(("http://", "https://")): + mcp_server_url = "https://" + mcp_server_url + return McpToolset( connection_params=StreamableHTTPConnectionParams( - url="https://" + mcp_server_url, + url=mcp_server_url, headers=headers, ), tool_filter=tool_filter, diff --git a/tests/unittests/tools/test_api_registry.py b/tests/unittests/tools/test_api_registry.py index 6f1ebd42..4a114c51 100644 --- a/tests/unittests/tools/test_api_registry.py +++ b/tests/unittests/tools/test_api_registry.py @@ -18,6 +18,7 @@ from unittest.mock import create_autospec from unittest.mock import MagicMock from unittest.mock import patch +from google.adk.tools import api_registry from google.adk.tools.api_registry import ApiRegistry from google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPConnectionParams import httpx @@ -35,6 +36,14 @@ MOCK_MCP_SERVERS_LIST = { { "name": "test-mcp-server-no-url", }, + { + "name": "test-mcp-server-http", + "urls": ["http://mcp.server_http.com"], + }, + { + "name": "test-mcp-server-https", + "urls": ["https://mcp.server_https.com"], + }, ] } @@ -70,10 +79,12 @@ class TestApiRegistry(unittest.IsolatedAsyncioTestCase): api_registry_project_id=self.project_id, location=self.location ) - self.assertEqual(len(api_registry._mcp_servers), 3) + self.assertEqual(len(api_registry._mcp_servers), 5) self.assertIn("test-mcp-server-1", api_registry._mcp_servers) self.assertIn("test-mcp-server-2", api_registry._mcp_servers) self.assertIn("test-mcp-server-no-url", api_registry._mcp_servers) + self.assertIn("test-mcp-server-http", api_registry._mcp_servers) + self.assertIn("test-mcp-server-https", api_registry._mcp_servers) mock_client_instance.get.assert_called_once_with( f"https://cloudapiregistry.googleapis.com/v1beta/projects/{self.project_id}/locations/{self.location}/mcpServers", headers={ @@ -95,10 +106,12 @@ class TestApiRegistry(unittest.IsolatedAsyncioTestCase): api_registry_project_id=self.project_id, location=self.location ) - self.assertEqual(len(api_registry._mcp_servers), 3) + self.assertEqual(len(api_registry._mcp_servers), 5) self.assertIn("test-mcp-server-1", api_registry._mcp_servers) self.assertIn("test-mcp-server-2", api_registry._mcp_servers) self.assertIn("test-mcp-server-no-url", api_registry._mcp_servers) + self.assertIn("test-mcp-server-http", api_registry._mcp_servers) + self.assertIn("test-mcp-server-https", api_registry._mcp_servers) mock_client_instance.get.assert_called_once_with( f"https://cloudapiregistry.googleapis.com/v1beta/projects/{self.project_id}/locations/{self.location}/mcpServers", headers={ @@ -232,6 +245,41 @@ class TestApiRegistry(unittest.IsolatedAsyncioTestCase): ) self.assertEqual(toolset, MockMcpToolset.return_value) + def test_get_toolset_url_scheme(self): + params = [ + ("test-mcp-server-http", "http://mcp.server_http.com"), + ("test-mcp-server-https", "https://mcp.server_https.com"), + ] + for mock_server_name, mock_url in params: + with self.subTest(server_name=mock_server_name): + with ( + patch.object(httpx, "Client", autospec=True) as MockHttpClient, + patch.object( + api_registry, "McpToolset", autospec=True + ) as MockMcpToolset, + ): + mock_response = create_autospec(httpx.Response, instance=True) + mock_response.json.return_value = MOCK_MCP_SERVERS_LIST + mock_client_instance = MockHttpClient.return_value + mock_client_instance.__enter__.return_value = mock_client_instance + mock_client_instance.get.return_value = mock_response + + api_registry_instance = ApiRegistry( + api_registry_project_id=self.project_id, location=self.location + ) + + api_registry_instance.get_toolset(mock_server_name) + + MockMcpToolset.assert_called_once_with( + connection_params=StreamableHTTPConnectionParams( + url=mock_url, + headers={"Authorization": "Bearer mock_token"}, + ), + tool_filter=None, + tool_name_prefix=None, + header_provider=None, + ) + @patch("httpx.Client", autospec=True) async def test_get_toolset_server_not_found(self, MockHttpClient): mock_response = MagicMock()