diff --git a/python/packages/autogen-ext/pyproject.toml b/python/packages/autogen-ext/pyproject.toml index e20c0dae92f2..cad7139a7ce1 100644 --- a/python/packages/autogen-ext/pyproject.toml +++ b/python/packages/autogen-ext/pyproject.toml @@ -112,6 +112,11 @@ semantic-kernel-all = [ rich = ["rich>=13.9.4"] +mcp = [ + "mcp>=1.1.3", + "json-schema-to-pydantic>=0.2.2" +] + [tool.hatch.build.targets.wheel] packages = ["src/autogen_ext"] diff --git a/python/packages/autogen-ext/src/autogen_ext/tools/mcp/__init__.py b/python/packages/autogen-ext/src/autogen_ext/tools/mcp/__init__.py new file mode 100644 index 000000000000..83d76fcad502 --- /dev/null +++ b/python/packages/autogen-ext/src/autogen_ext/tools/mcp/__init__.py @@ -0,0 +1,13 @@ +from ._config import McpServerParams, SseServerParams, StdioServerParams +from ._factory import mcp_server_tools +from ._sse import SseMcpToolAdapter +from ._stdio import StdioMcpToolAdapter + +__all__ = [ + "StdioMcpToolAdapter", + "StdioServerParams", + "SseMcpToolAdapter", + "SseServerParams", + "McpServerParams", + "mcp_server_tools", +] diff --git a/python/packages/autogen-ext/src/autogen_ext/tools/mcp/_base.py b/python/packages/autogen-ext/src/autogen_ext/tools/mcp/_base.py new file mode 100644 index 000000000000..cf905800d6b2 --- /dev/null +++ b/python/packages/autogen-ext/src/autogen_ext/tools/mcp/_base.py @@ -0,0 +1,101 @@ +from abc import ABC +from typing import Any, Generic, Type, TypeVar + +from autogen_core import CancellationToken +from autogen_core.tools import BaseTool +from json_schema_to_pydantic import create_model +from mcp import Tool +from pydantic import BaseModel + +from ._config import McpServerParams +from ._session import create_mcp_server_session + +TServerParams = TypeVar("TServerParams", bound=McpServerParams) + + +class McpToolAdapter(BaseTool[BaseModel, Any], ABC, Generic[TServerParams]): + """ + Base adapter class for MCP tools to make them compatible with AutoGen. + + Args: + server_params (TServerParams): Parameters for the MCP server connection. + tool (Tool): The MCP tool to wrap. + """ + + component_type = "tool" + + def __init__(self, server_params: TServerParams, tool: Tool) -> None: + self._tool = tool + self._server_params = server_params + + # Extract name and description + name = tool.name + description = tool.description or "" + + # Create the input model from the tool's schema + input_model = create_model(tool.inputSchema) + + # Use Any as return type since MCP tool returns can vary + return_type: Type[Any] = object + + super().__init__(input_model, return_type, name, description) + + async def run(self, args: BaseModel, cancellation_token: CancellationToken) -> Any: + """ + Run the MCP tool with the provided arguments. + + Args: + args (BaseModel): The arguments to pass to the tool. + cancellation_token (CancellationToken): Token to signal cancellation. + + Returns: + Any: The result of the tool execution. + + Raises: + Exception: If the operation is cancelled or the tool execution fails. + """ + kwargs = args.model_dump() + + try: + async with create_mcp_server_session(self._server_params) as session: + await session.initialize() + + if cancellation_token.is_cancelled(): + raise Exception("Operation cancelled") + + result = await session.call_tool(self._tool.name, kwargs) # type: ignore + + if result.isError: + raise Exception(f"MCP tool execution failed: {result.content}") + + return result.content + except Exception as e: + raise Exception(str(e)) from e + + @classmethod + async def from_server_params(cls, server_params: TServerParams, tool_name: str) -> "McpToolAdapter[TServerParams]": + """ + Create an instance of McpToolAdapter from server parameters and tool name. + + Args: + server_params (TServerParams): Parameters for the MCP server connection. + tool_name (str): The name of the tool to wrap. + + Returns: + McpToolAdapter[TServerParams]: An instance of McpToolAdapter. + + Raises: + ValueError: If the tool with the specified name is not found. + """ + async with create_mcp_server_session(server_params) as session: + await session.initialize() + + tools_response = await session.list_tools() + matching_tool = next((t for t in tools_response.tools if t.name == tool_name), None) + + if matching_tool is None: + raise ValueError( + f"Tool '{tool_name}' not found, available tools: {', '.join([t.name for t in tools_response.tools])}" + ) + + return cls(server_params=server_params, tool=matching_tool) diff --git a/python/packages/autogen-ext/src/autogen_ext/tools/mcp/_config.py b/python/packages/autogen-ext/src/autogen_ext/tools/mcp/_config.py new file mode 100644 index 000000000000..3f140587d30e --- /dev/null +++ b/python/packages/autogen-ext/src/autogen_ext/tools/mcp/_config.py @@ -0,0 +1,22 @@ +from typing import Any, TypeAlias + +from mcp import StdioServerParameters +from pydantic import BaseModel + + +class StdioServerParams(StdioServerParameters): + """Parameters for connecting to an MCP server over STDIO.""" + + pass + + +class SseServerParams(BaseModel): + """Parameters for connecting to an MCP server over SSE.""" + + url: str + headers: dict[str, Any] | None = None + timeout: float = 5 + sse_read_timeout: float = 60 * 5 + + +McpServerParams: TypeAlias = StdioServerParams | SseServerParams diff --git a/python/packages/autogen-ext/src/autogen_ext/tools/mcp/_factory.py b/python/packages/autogen-ext/src/autogen_ext/tools/mcp/_factory.py new file mode 100644 index 000000000000..9035eab7ad4b --- /dev/null +++ b/python/packages/autogen-ext/src/autogen_ext/tools/mcp/_factory.py @@ -0,0 +1,88 @@ +from ._config import McpServerParams, SseServerParams, StdioServerParams +from ._session import create_mcp_server_session +from ._sse import SseMcpToolAdapter +from ._stdio import StdioMcpToolAdapter + + +async def mcp_server_tools( + server_params: McpServerParams, +) -> list[StdioMcpToolAdapter | SseMcpToolAdapter]: + """Creates a list of MCP tool adapters that can be used with AutoGen agents. + + This factory function connects to an MCP server and returns adapters for all available tools. + The adapters can be directly assigned to an AutoGen agent's tools list. + + Args: + server_params (McpServerParams): Connection parameters for the MCP server. + Can be either StdioServerParams for command-line tools or + SseServerParams for HTTP/SSE services. + + Returns: + list[StdioMcpToolAdapter | SseMcpToolAdapter]: A list of tool adapters ready to use + with AutoGen agents. + + Examples: + Create an agent that can use all tools from a local filesystem MCP server: + + .. code-block:: python + + import asyncio + from pathlib import Path + from autogen_ext.models.openai import OpenAIChatCompletionClient + from autogen_ext.tools.mcp import StdioServerParams, mcp_server_tools + from autogen_agentchat.agents import AssistantAgent + from autogen_core import CancellationToken + + + async def main() -> None: + # Setup server params for local filesystem access + desktop = str(Path.home() / "Desktop") + server_params = StdioServerParams( + command="npx.cmd", args=["-y", "@modelcontextprotocol/server-filesystem", desktop] + ) + + # Get all available tools from the server + tools = await mcp_server_tools(server_params) + + # Create an agent that can use all the tools + agent = AssistantAgent( + name="file_manager", + model_client=OpenAIChatCompletionClient(model="gpt-4"), + tools=tools, # Assign all tools to the agent + ) + + # The agent can now use any of the filesystem tools + await agent.run(task="Create a file called test.txt with some content", cancellation_token=CancellationToken()) + + + if __name__ == "__main__": + asyncio.run(main()) + + Or connect to a remote MCP service over SSE: + + .. code-block:: python + + from autogen_ext_mcp.tools import SseServerParams, mcp_server_tools + + + async def main() -> None: + # Setup server params for remote service + server_params = SseServerParams(url="https://api.example.com/mcp", headers={"Authorization": "Bearer token"}) + + # Get all available tools + tools = await mcp_server_tools(server_params) + + # Create an agent with all tools + agent = AssistantAgent(name="tool_user", model_client=OpenAIChatCompletionClient(model="gpt-4"), tools=tools) + + For more examples and detailed usage, see the samples directory in the package repository. + """ + async with create_mcp_server_session(server_params) as session: + await session.initialize() + + tools = await session.list_tools() + + if isinstance(server_params, StdioServerParams): + return [StdioMcpToolAdapter(server_params=server_params, tool=tool) for tool in tools.tools] + elif isinstance(server_params, SseServerParams): + return [SseMcpToolAdapter(server_params=server_params, tool=tool) for tool in tools.tools] diff --git a/python/packages/autogen-ext/src/autogen_ext/tools/mcp/_session.py b/python/packages/autogen-ext/src/autogen_ext/tools/mcp/_session.py new file mode 100644 index 000000000000..964a5c9f77cf --- /dev/null +++ b/python/packages/autogen-ext/src/autogen_ext/tools/mcp/_session.py @@ -0,0 +1,23 @@ +from contextlib import asynccontextmanager +from typing import AsyncGenerator + +from mcp import ClientSession +from mcp.client.sse import sse_client +from mcp.client.stdio import stdio_client + +from ._config import McpServerParams, SseServerParams, StdioServerParams + + +@asynccontextmanager +async def create_mcp_server_session( + server_params: McpServerParams, +) -> AsyncGenerator[ClientSession, None]: + """Create an MCP client session for the given server parameters.""" + if isinstance(server_params, StdioServerParams): + async with stdio_client(server_params) as (read, write): + async with ClientSession(read_stream=read, write_stream=write) as session: + yield session + elif isinstance(server_params, SseServerParams): + async with sse_client(**server_params.model_dump()) as (read, write): + async with ClientSession(read_stream=read, write_stream=write) as session: + yield session diff --git a/python/packages/autogen-ext/src/autogen_ext/tools/mcp/_sse.py b/python/packages/autogen-ext/src/autogen_ext/tools/mcp/_sse.py new file mode 100644 index 000000000000..7b875649a4f4 --- /dev/null +++ b/python/packages/autogen-ext/src/autogen_ext/tools/mcp/_sse.py @@ -0,0 +1,104 @@ +from autogen_core import Component +from mcp import Tool +from pydantic import BaseModel +from typing_extensions import Self + +from ._base import McpToolAdapter +from ._config import SseServerParams + + +class SseMcpToolAdapterConfig(BaseModel): + """Configuration for the MCP tool adapter.""" + + server_params: SseServerParams + tool: Tool + + +class SseMcpToolAdapter( + McpToolAdapter[SseServerParams], + Component[SseMcpToolAdapterConfig], +): + """ + Allows you to wrap an MCP tool running over Server-Sent Events (SSE) and make it available to AutoGen. + + This adapter enables using MCP-compatible tools that communicate over HTTP with SSE + with AutoGen agents. Common use cases include integrating with remote MCP services, + cloud-based tools, and web APIs that implement the Model Context Protocol (MCP). + + Args: + server_params (SseServerParameters): Parameters for the MCP server connection, + including URL, headers, and timeouts + tool (Tool): The MCP tool to wrap + + Examples: + Use a remote translation service that implements MCP over SSE to create tools + that allow AutoGen agents to perform translations: + + .. code-block:: python + + import asyncio + from autogen_ext.models.openai import OpenAIChatCompletionClient + from autogen_ext.tools.mcp import SseMcpToolAdapter, SseServerParams + from autogen_agentchat.agents import AssistantAgent + from autogen_agentchat.ui import Console + from autogen_core import CancellationToken + + + async def main() -> None: + # Create server params for the remote MCP service + server_params = SseServerParams( + url="https://api.example.com/mcp", + headers={"Authorization": "Bearer your-api-key", "Content-Type": "application/json"}, + timeout=30, # Connection timeout in seconds + ) + + # Get the translation tool from the server + adapter = await SseMcpToolAdapter.from_server_params(server_params, "translate") + + # Create an agent that can use the translation tool + model_client = OpenAIChatCompletionClient(model="gpt-4") + agent = AssistantAgent( + name="translator", + model_client=model_client, + tools=[adapter], + system_message="You are a helpful translation assistant.", + ) + + # Let the agent translate some text + await Console( + agent.run_stream(task="Translate 'Hello, how are you?' to Spanish", cancellation_token=CancellationToken()) + ) + + + if __name__ == "__main__": + asyncio.run(main()) + + """ + + component_config_schema = SseMcpToolAdapterConfig + component_provider_override = "autogen_ext.tools.mcp.SseMcpToolAdapter" + + def __init__(self, server_params: SseServerParams, tool: Tool) -> None: + super().__init__(server_params=server_params, tool=tool) + + def _to_config(self) -> SseMcpToolAdapterConfig: + """ + Convert the adapter to its configuration representation. + + Returns: + SseMcpToolAdapterConfig: The configuration of the adapter. + """ + return SseMcpToolAdapterConfig(server_params=self._server_params, tool=self._tool) + + @classmethod + def _from_config(cls, config: SseMcpToolAdapterConfig) -> Self: + """ + Create an instance of SseMcpToolAdapter from its configuration. + + Args: + config (SseMcpToolAdapterConfig): The configuration of the adapter. + + Returns: + SseMcpToolAdapter: An instance of SseMcpToolAdapter. + """ + return cls(server_params=config.server_params, tool=config.tool) diff --git a/python/packages/autogen-ext/src/autogen_ext/tools/mcp/_stdio.py b/python/packages/autogen-ext/src/autogen_ext/tools/mcp/_stdio.py new file mode 100644 index 000000000000..d581502ca14c --- /dev/null +++ b/python/packages/autogen-ext/src/autogen_ext/tools/mcp/_stdio.py @@ -0,0 +1,112 @@ +from autogen_core import Component +from mcp import Tool +from pydantic import BaseModel +from typing_extensions import Self + +from ._base import McpToolAdapter +from ._config import StdioServerParams + + +class StdioMcpToolAdapterConfig(BaseModel): + """Configuration for the MCP tool adapter.""" + + server_params: StdioServerParams + tool: Tool + + +class StdioMcpToolAdapter( + McpToolAdapter[StdioServerParams], + Component[StdioMcpToolAdapterConfig], +): + """Allows you to wrap an MCP tool running over STDIO and make it available to AutoGen. + + This adapter enables using MCP-compatible tools that communicate over standard input/output + with AutoGen agents. Common use cases include wrapping command-line tools and local services + that implement the Model Context Protocol (MCP). + + Args: + server_params (StdioServerParams): Parameters for the MCP server connection, + including command to run and its arguments + tool (Tool): The MCP tool to wrap + + Examples: + Use the FileSystem MCP server to create tools that allow AutoGen agents to interact + with the local filesystem: + + .. code-block:: python + + import asyncio + from pathlib import Path + from autogen_ext.models.openai import OpenAIChatCompletionClient + from autogen_ext.tools.mcp import StdioMcpToolAdapter, StdioServerParams + from autogen_agentchat.agents import AssistantAgent + from autogen_agentchat.ui import Console + from autogen_core import CancellationToken + + + async def main() -> None: + # Get desktop path cross-platform + desktop_path = str(Path.home() / "Desktop") + + # Create server params for the FileSystem MCP server + server_params = StdioServerParams( + command="npx.cmd", # Use npx on Windows + args=[ + "-y", + "@modelcontextprotocol/server-filesystem", + desktop_path, + ], + ) + + # Get all available tools from the server + tools = await mcp_server_tools(server_params) + + # Create an agent that can use the filesystem tools + model_client = OpenAIChatCompletionClient(model="gpt-4") + agent = AssistantAgent( + name="file_manager", + model_client=model_client, + tools=tools, + ) + + # Let the agent create and write to a file + await Console( + agent.run_stream( + task="Create a file called 'hello.txt' with the content 'Hello, World!'", + cancellation_token=CancellationToken(), + ) + ) + + + if __name__ == "__main__": + asyncio.run(main()) + + """ + + component_config_schema = StdioMcpToolAdapterConfig + component_provider_override = "autogen_ext.tools.mcp.StdioMcpToolAdapter" + + def __init__(self, server_params: StdioServerParams, tool: Tool) -> None: + super().__init__(server_params=server_params, tool=tool) + + def _to_config(self) -> StdioMcpToolAdapterConfig: + """ + Convert the adapter to its configuration representation. + + Returns: + StdioMcpToolAdapterConfig: The configuration of the adapter. + """ + return StdioMcpToolAdapterConfig(server_params=self._server_params, tool=self._tool) + + @classmethod + def _from_config(cls, config: StdioMcpToolAdapterConfig) -> Self: + """ + Create an instance of StdioMcpToolAdapter from its configuration. + + Args: + config (StdioMcpToolAdapterConfig): The configuration of the adapter. + + Returns: + StdioMcpToolAdapter: An instance of StdioMcpToolAdapter. + """ + return cls(server_params=config.server_params, tool=config.tool) diff --git a/python/packages/autogen-ext/tests/tools/test_mcp_tools.py b/python/packages/autogen-ext/tests/tools/test_mcp_tools.py new file mode 100644 index 000000000000..7af9933d3a94 --- /dev/null +++ b/python/packages/autogen-ext/tests/tools/test_mcp_tools.py @@ -0,0 +1,271 @@ +from unittest.mock import AsyncMock, MagicMock + +import pytest +from autogen_core import CancellationToken +from autogen_ext.tools.mcp import ( + SseMcpToolAdapter, + SseServerParams, + StdioMcpToolAdapter, + StdioServerParams, +) +from json_schema_to_pydantic import create_model +from mcp import ClientSession, Tool + + +@pytest.fixture +def sample_tool() -> Tool: + return Tool( + name="test_tool", + description="A test tool", + inputSchema={ + "type": "object", + "properties": {"test_param": {"type": "string"}}, + "required": ["test_param"], + }, + ) + + +@pytest.fixture +def sample_server_params() -> StdioServerParams: + return StdioServerParams(command="echo", args=["test"]) + + +@pytest.fixture +def sample_sse_tool() -> Tool: + return Tool( + name="test_sse_tool", + description="A test SSE tool", + inputSchema={ + "type": "object", + "properties": {"test_param": {"type": "string"}}, + "required": ["test_param"], + }, + ) + + +@pytest.fixture +def mock_sse_session() -> AsyncMock: + session = AsyncMock(spec=ClientSession) + session.initialize = AsyncMock() + session.call_tool = AsyncMock() + session.list_tools = AsyncMock() + return session + + +@pytest.fixture +def mock_session() -> AsyncMock: + session = AsyncMock(spec=ClientSession) + session.initialize = AsyncMock() + session.call_tool = AsyncMock() + session.list_tools = AsyncMock() + return session + + +@pytest.fixture +def mock_tool_response() -> MagicMock: + response = MagicMock() + response.isError = False + response.content = {"result": "test_output"} + return response + + +@pytest.fixture +def cancellation_token() -> CancellationToken: + return CancellationToken() + + +def test_adapter_config_serialization(sample_tool: Tool, sample_server_params: StdioServerParams) -> None: + """Test that adapter can be saved to and loaded from config.""" + original_adapter = StdioMcpToolAdapter(server_params=sample_server_params, tool=sample_tool) + config = original_adapter.dump_component() + loaded_adapter = StdioMcpToolAdapter.load_component(config) + + # Test that the loaded adapter has the same properties + assert loaded_adapter.name == "test_tool" + assert loaded_adapter.description == "A test tool" + + # Verify schema structure + schema = loaded_adapter.schema + assert "parameters" in schema, "Schema must have parameters" + params_schema = schema["parameters"] + assert isinstance(params_schema, dict), "Parameters must be a dict" + assert "type" in params_schema, "Parameters must have type" + assert "required" in params_schema, "Parameters must have required fields" + assert "properties" in params_schema, "Parameters must have properties" + + # Compare schema content + assert params_schema["type"] == sample_tool.inputSchema["type"] + assert params_schema["required"] == sample_tool.inputSchema["required"] + assert ( + params_schema["properties"]["test_param"]["type"] == sample_tool.inputSchema["properties"]["test_param"]["type"] + ) + + +@pytest.mark.asyncio +async def test_mcp_tool_execution( + sample_tool: Tool, + sample_server_params: StdioServerParams, + mock_session: AsyncMock, + mock_tool_response: MagicMock, + cancellation_token: CancellationToken, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """Test that adapter properly executes tools through ClientSession.""" + mock_context = AsyncMock() + mock_context.__aenter__.return_value = mock_session + monkeypatch.setattr( + "autogen_ext.tools.mcp._base.create_mcp_server_session", + lambda *args, **kwargs: mock_context, # type: ignore + ) + + mock_session.call_tool.return_value = mock_tool_response + + adapter = StdioMcpToolAdapter(server_params=sample_server_params, tool=sample_tool) + result = await adapter.run( + args=create_model(sample_tool.inputSchema)(**{"test_param": "test"}), + cancellation_token=cancellation_token, + ) + + assert result == mock_tool_response.content + mock_session.initialize.assert_called_once() + mock_session.call_tool.assert_called_once() + + +@pytest.mark.asyncio +async def test_adapter_from_server_params( + sample_tool: Tool, + sample_server_params: StdioServerParams, + mock_session: AsyncMock, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """Test that adapter can be created from server parameters.""" + mock_context = AsyncMock() + mock_context.__aenter__.return_value = mock_session + monkeypatch.setattr( + "autogen_ext.tools.mcp._base.create_mcp_server_session", + lambda *args, **kwargs: mock_context, # type: ignore + ) + + mock_session.list_tools.return_value.tools = [sample_tool] + + adapter = await StdioMcpToolAdapter.from_server_params(sample_server_params, "test_tool") + + assert isinstance(adapter, StdioMcpToolAdapter) + assert adapter.name == "test_tool" + assert adapter.description == "A test tool" + + # Verify schema structure + schema = adapter.schema + assert "parameters" in schema, "Schema must have parameters" + params_schema = schema["parameters"] + assert isinstance(params_schema, dict), "Parameters must be a dict" + assert "type" in params_schema, "Parameters must have type" + assert "required" in params_schema, "Parameters must have required fields" + assert "properties" in params_schema, "Parameters must have properties" + + # Compare schema content + assert params_schema["type"] == sample_tool.inputSchema["type"] + assert params_schema["required"] == sample_tool.inputSchema["required"] + assert ( + params_schema["properties"]["test_param"]["type"] == sample_tool.inputSchema["properties"]["test_param"]["type"] + ) + + +@pytest.mark.asyncio +async def test_sse_adapter_config_serialization(sample_sse_tool: Tool) -> None: + """Test that SSE adapter can be saved to and loaded from config.""" + params = SseServerParams(url="http://test-url") + original_adapter = SseMcpToolAdapter(server_params=params, tool=sample_sse_tool) + config = original_adapter.dump_component() + loaded_adapter = SseMcpToolAdapter.load_component(config) + + # Test that the loaded adapter has the same properties + assert loaded_adapter.name == "test_sse_tool" + assert loaded_adapter.description == "A test SSE tool" + + # Verify schema structure + schema = loaded_adapter.schema + assert "parameters" in schema, "Schema must have parameters" + params_schema = schema["parameters"] + assert isinstance(params_schema, dict), "Parameters must be a dict" + assert "type" in params_schema, "Parameters must have type" + assert "required" in params_schema, "Parameters must have required fields" + assert "properties" in params_schema, "Parameters must have properties" + + # Compare schema content + assert params_schema["type"] == sample_sse_tool.inputSchema["type"] + assert params_schema["required"] == sample_sse_tool.inputSchema["required"] + assert ( + params_schema["properties"]["test_param"]["type"] + == sample_sse_tool.inputSchema["properties"]["test_param"]["type"] + ) + + +@pytest.mark.asyncio +async def test_sse_tool_execution( + sample_sse_tool: Tool, + mock_sse_session: AsyncMock, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """Test that SSE adapter properly executes tools through ClientSession.""" + params = SseServerParams(url="http://test-url") + mock_context = AsyncMock() + mock_context.__aenter__.return_value = mock_sse_session + + mock_sse_session.call_tool.return_value = MagicMock(isError=False, content={"result": "test_output"}) + + monkeypatch.setattr( + "autogen_ext.tools.mcp._base.create_mcp_server_session", + lambda *args, **kwargs: mock_context, # type: ignore + ) + + adapter = SseMcpToolAdapter(server_params=params, tool=sample_sse_tool) + result = await adapter.run( + args=create_model(sample_sse_tool.inputSchema)(**{"test_param": "test"}), + cancellation_token=CancellationToken(), + ) + + assert result == mock_sse_session.call_tool.return_value.content + mock_sse_session.initialize.assert_called_once() + mock_sse_session.call_tool.assert_called_once() + + +@pytest.mark.asyncio +async def test_sse_adapter_from_server_params( + sample_sse_tool: Tool, + mock_sse_session: AsyncMock, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """Test that SSE adapter can be created from server parameters.""" + params = SseServerParams(url="http://test-url") + mock_context = AsyncMock() + mock_context.__aenter__.return_value = mock_sse_session + monkeypatch.setattr( + "autogen_ext.tools.mcp._base.create_mcp_server_session", + lambda *args, **kwargs: mock_context, # type: ignore + ) + + mock_sse_session.list_tools.return_value.tools = [sample_sse_tool] + + adapter = await SseMcpToolAdapter.from_server_params(params, "test_sse_tool") + + assert isinstance(adapter, SseMcpToolAdapter) + assert adapter.name == "test_sse_tool" + assert adapter.description == "A test SSE tool" + + # Verify schema structure + schema = adapter.schema + assert "parameters" in schema, "Schema must have parameters" + params_schema = schema["parameters"] + assert isinstance(params_schema, dict), "Parameters must be a dict" + assert "type" in params_schema, "Parameters must have type" + assert "required" in params_schema, "Parameters must have required fields" + assert "properties" in params_schema, "Parameters must have properties" + + # Compare schema content + assert params_schema["type"] == sample_sse_tool.inputSchema["type"] + assert params_schema["required"] == sample_sse_tool.inputSchema["required"] + assert ( + params_schema["properties"]["test_param"]["type"] + == sample_sse_tool.inputSchema["properties"]["test_param"]["type"] + ) diff --git a/python/uv.lock b/python/uv.lock index 87c5320f0343..b5db14ba03f7 100644 --- a/python/uv.lock +++ b/python/uv.lock @@ -1,18 +1,34 @@ version = 1 requires-python = ">=3.10, <3.13" resolution-markers = [ - "python_full_version >= '3.12.4' and sys_platform == 'darwin'", - "python_full_version >= '3.12' and python_full_version < '3.12.4' and sys_platform == 'darwin'", - "python_full_version >= '3.12.4' and platform_machine == 'aarch64' and sys_platform == 'linux'", - "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine == 'aarch64' and sys_platform == 'linux'", - "(python_full_version >= '3.12.4' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.12.4' and sys_platform != 'darwin' and sys_platform != 'linux')", - "(python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.12' and python_full_version < '3.12.4' and sys_platform != 'darwin' and sys_platform != 'linux')", - "python_full_version == '3.11.*' and sys_platform == 'darwin'", - "python_full_version == '3.11.*' and platform_machine == 'aarch64' and sys_platform == 'linux'", - "(python_full_version == '3.11.*' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version == '3.11.*' and sys_platform != 'darwin' and sys_platform != 'linux')", - "python_full_version < '3.11' and sys_platform == 'darwin'", - "python_full_version < '3.11' and platform_machine == 'aarch64' and sys_platform == 'linux'", - "(python_full_version < '3.11' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version < '3.11' and sys_platform != 'darwin' and sys_platform != 'linux')", + "python_full_version >= '3.12.4' and platform_system == 'Darwin' and sys_platform == 'darwin'", + "python_full_version >= '3.12.4' and platform_system != 'Darwin' and sys_platform == 'darwin'", + "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_system == 'Darwin' and sys_platform == 'darwin'", + "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_system != 'Darwin' and sys_platform == 'darwin'", + "python_full_version >= '3.12.4' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'linux'", + "python_full_version >= '3.12.4' and platform_machine == 'aarch64' and platform_system != 'Linux' and sys_platform == 'linux'", + "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'linux'", + "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine == 'aarch64' and platform_system != 'Linux' and sys_platform == 'linux'", + "(python_full_version >= '3.12.4' and platform_machine != 'aarch64' and platform_system == 'Darwin' and sys_platform == 'linux') or (python_full_version >= '3.12.4' and platform_system == 'Darwin' and sys_platform != 'darwin' and sys_platform != 'linux')", + "python_full_version >= '3.12.4' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux'", + "(python_full_version >= '3.12.4' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'linux') or (python_full_version >= '3.12.4' and platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux') or (python_full_version >= '3.12.4' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')", + "(python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine != 'aarch64' and platform_system == 'Darwin' and sys_platform == 'linux') or (python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_system == 'Darwin' and sys_platform != 'darwin' and sys_platform != 'linux')", + "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux'", + "(python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'linux') or (python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux') or (python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')", + "python_full_version == '3.11.*' and platform_system == 'Darwin' and sys_platform == 'darwin'", + "python_full_version == '3.11.*' and platform_system != 'Darwin' and sys_platform == 'darwin'", + "python_full_version == '3.11.*' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'linux'", + "python_full_version == '3.11.*' and platform_machine == 'aarch64' and platform_system != 'Linux' and sys_platform == 'linux'", + "(python_full_version == '3.11.*' and platform_machine != 'aarch64' and platform_system == 'Darwin' and sys_platform == 'linux') or (python_full_version == '3.11.*' and platform_system == 'Darwin' and sys_platform != 'darwin' and sys_platform != 'linux')", + "python_full_version == '3.11.*' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux'", + "(python_full_version == '3.11.*' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'linux') or (python_full_version == '3.11.*' and platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux') or (python_full_version == '3.11.*' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')", + "python_full_version < '3.11' and platform_system == 'Darwin' and sys_platform == 'darwin'", + "python_full_version < '3.11' and platform_system != 'Darwin' and sys_platform == 'darwin'", + "python_full_version < '3.11' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'linux'", + "python_full_version < '3.11' and platform_machine == 'aarch64' and platform_system != 'Linux' and sys_platform == 'linux'", + "(python_full_version < '3.11' and platform_machine != 'aarch64' and platform_system == 'Darwin' and sys_platform == 'linux') or (python_full_version < '3.11' and platform_system == 'Darwin' and sys_platform != 'darwin' and sys_platform != 'linux')", + "python_full_version < '3.11' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux'", + "(python_full_version < '3.11' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'linux') or (python_full_version < '3.11' and platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux') or (python_full_version < '3.11' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')", ] [manifest] @@ -26,15 +42,7 @@ members = [ "component-schema-gen", "magentic-one-cli", ] -overrides = [ - { name = "aiofiles", specifier = ">=24.1.0" }, - { name = "chainlit", specifier = ">=2.0.1" }, - { name = "httpx", specifier = ">=0.27.0" }, - { name = "tenacity", specifier = ">=9.0.0" }, -] - -[manifest.dependency-groups] -dev = [ +requirements = [ { name = "chainlit" }, { name = "cookiecutter" }, { name = "grpcio-tools", specifier = "~=1.70.0" }, @@ -56,6 +64,12 @@ dev = [ { name = "tomli-w" }, { name = "typer" }, ] +overrides = [ + { name = "aiofiles", specifier = ">=24.1.0" }, + { name = "chainlit", specifier = ">=2.0.1" }, + { name = "httpx", specifier = ">=0.27.0" }, + { name = "tenacity", specifier = ">=9.0.0" }, +] [[package]] name = "accelerate" @@ -371,9 +385,13 @@ name = "async-timeout" version = "4.0.3" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version < '3.11' and sys_platform == 'darwin'", - "python_full_version < '3.11' and platform_machine == 'aarch64' and sys_platform == 'linux'", - "(python_full_version < '3.11' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version < '3.11' and sys_platform != 'darwin' and sys_platform != 'linux')", + "python_full_version < '3.11' and platform_system == 'Darwin' and sys_platform == 'darwin'", + "python_full_version < '3.11' and platform_system != 'Darwin' and sys_platform == 'darwin'", + "python_full_version < '3.11' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'linux'", + "python_full_version < '3.11' and platform_machine == 'aarch64' and platform_system != 'Linux' and sys_platform == 'linux'", + "(python_full_version < '3.11' and platform_machine != 'aarch64' and platform_system == 'Darwin' and sys_platform == 'linux') or (python_full_version < '3.11' and platform_system == 'Darwin' and sys_platform != 'darwin' and sys_platform != 'linux')", + "python_full_version < '3.11' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux'", + "(python_full_version < '3.11' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'linux') or (python_full_version < '3.11' and platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux') or (python_full_version < '3.11' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')", ] sdist = { url = "https://files.pythonhosted.org/packages/87/d6/21b30a550dafea84b1b8eee21b5e23fa16d010ae006011221f33dcd8d7f8/async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f", size = 8345 } wheels = [ @@ -385,9 +403,13 @@ name = "async-timeout" version = "5.0.1" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version == '3.11.*' and sys_platform == 'darwin'", - "python_full_version == '3.11.*' and platform_machine == 'aarch64' and sys_platform == 'linux'", - "(python_full_version == '3.11.*' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version == '3.11.*' and sys_platform != 'darwin' and sys_platform != 'linux')", + "python_full_version == '3.11.*' and platform_system == 'Darwin' and sys_platform == 'darwin'", + "python_full_version == '3.11.*' and platform_system != 'Darwin' and sys_platform == 'darwin'", + "python_full_version == '3.11.*' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'linux'", + "python_full_version == '3.11.*' and platform_machine == 'aarch64' and platform_system != 'Linux' and sys_platform == 'linux'", + "(python_full_version == '3.11.*' and platform_machine != 'aarch64' and platform_system == 'Darwin' and sys_platform == 'linux') or (python_full_version == '3.11.*' and platform_system == 'Darwin' and sys_platform != 'darwin' and sys_platform != 'linux')", + "python_full_version == '3.11.*' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux'", + "(python_full_version == '3.11.*' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'linux') or (python_full_version == '3.11.*' and platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux') or (python_full_version == '3.11.*' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')", ] sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274 } wheels = [ @@ -611,6 +633,10 @@ magentic-one = [ { name = "pillow" }, { name = "playwright" }, ] +mcp = [ + { name = "json-schema-to-pydantic" }, + { name = "mcp" }, +] openai = [ { name = "aiofiles" }, { name = "openai" }, @@ -694,10 +720,12 @@ requires-dist = [ { name = "graphrag", marker = "extra == 'graphrag'", specifier = ">=1.0.1" }, { name = "grpcio", marker = "extra == 'grpc'", specifier = "~=1.70.0" }, { name = "ipykernel", marker = "extra == 'jupyter-executor'", specifier = ">=6.29.5" }, + { name = "json-schema-to-pydantic", marker = "extra == 'mcp'", specifier = ">=0.2.2" }, { name = "langchain-core", marker = "extra == 'langchain'", specifier = "~=0.3.3" }, { name = "markitdown", marker = "extra == 'file-surfer'", specifier = ">=0.0.1a2" }, { name = "markitdown", marker = "extra == 'magentic-one'", specifier = ">=0.0.1a2" }, { name = "markitdown", marker = "extra == 'web-surfer'", specifier = ">=0.0.1a2" }, + { name = "mcp", marker = "extra == 'mcp'", specifier = ">=1.1.3" }, { name = "nbclient", marker = "extra == 'jupyter-executor'", specifier = ">=0.10.2" }, { name = "openai", marker = "extra == 'openai'", specifier = ">=1.52.2" }, { name = "openai-whisper", marker = "extra == 'video-surfer'" }, @@ -1199,7 +1227,7 @@ name = "click" version = "8.1.8" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "(platform_machine != 'aarch64' and platform_system == 'Windows' and sys_platform == 'linux') or (platform_system == 'Windows' and sys_platform != 'darwin' and sys_platform != 'linux')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 } wheels = [ @@ -1599,7 +1627,7 @@ name = "docker" version = "7.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pywin32", marker = "sys_platform == 'win32'" }, + { name = "pywin32", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, { name = "requests" }, { name = "urllib3" }, ] @@ -2585,7 +2613,7 @@ name = "humanfriendly" version = "10.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyreadline3", marker = "sys_platform == 'win32'" }, + { name = "pyreadline3", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/cc/3f/2c29224acb2e2df4d2046e4c73ee2662023c58ff5b113c4c1adac0886c43/humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc", size = 360702 } wheels = [ @@ -2651,7 +2679,7 @@ name = "ipykernel" version = "6.29.5" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "appnope", marker = "sys_platform == 'darwin'" }, + { name = "appnope", marker = "(platform_machine != 'aarch64' and platform_system == 'Darwin') or (platform_system == 'Darwin' and sys_platform != 'linux')" }, { name = "comm" }, { name = "debugpy" }, { name = "ipython" }, @@ -2675,7 +2703,7 @@ name = "ipython" version = "8.31.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, { name = "decorator" }, { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "jedi" }, @@ -2811,6 +2839,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fd/2d/79a46330c4b97ee90dd403fb0d267da7b25b24d7db604c5294e5c57d5f7c/json_repair-0.30.3-py3-none-any.whl", hash = "sha256:63bb588162b0958ae93d85356ecbe54c06b8c33f8a4834f93fa2719ea669804e", size = 18951 }, ] +[[package]] +name = "json-schema-to-pydantic" +version = "0.2.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/13/87/af1870beea329744a759349b972b309f8c95ae21e986e387e19733b85cc9/json_schema_to_pydantic-0.2.2.tar.gz", hash = "sha256:685db8d93aa29ccd257b2803fcd9a956c527e5fb108a523cbfe8cac1239b3785", size = 34158 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/25/8d/3c738e4b4b041269c4a506544b90e9ba924bbd800c8d496ed3e5a6da0265/json_schema_to_pydantic-0.2.2-py3-none-any.whl", hash = "sha256:01b82d234f2b482a273e117e29d063b6b86021a250035873d6eec4b85b70e64d", size = 11396 }, +] + [[package]] name = "jsonpatch" version = "1.33" @@ -2933,7 +2973,7 @@ version = "5.7.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "platformdirs" }, - { name = "pywin32", marker = "platform_python_implementation != 'PyPy' and sys_platform == 'win32'" }, + { name = "pywin32", marker = "(platform_machine != 'aarch64' and platform_python_implementation != 'PyPy' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_python_implementation != 'PyPy' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, { name = "traitlets" }, ] sdist = { url = "https://files.pythonhosted.org/packages/00/11/b56381fa6c3f4cc5d2cf54a7dbf98ad9aa0b339ef7a601d6053538b079a7/jupyter_core-5.7.2.tar.gz", hash = "sha256:aa5f8d32bbf6b431ac830496da7392035d6f61b4f54872f15c4bd2a9c3f536d9", size = 87629 } @@ -3568,8 +3608,8 @@ name = "loguru" version = "0.7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "win32-setctime", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, + { name = "win32-setctime", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3a/05/a1dae3dffd1116099471c643b8924f5aa6524411dc6c63fdae648c4f1aca/loguru-0.7.3.tar.gz", hash = "sha256:19480589e77d47b8d85b2c827ad95d49bf31b0dcde16593892eb51dd18706eb6", size = 63559 } wheels = [ @@ -3852,6 +3892,23 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca", size = 9899 }, ] +[[package]] +name = "mcp" +version = "1.1.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "httpx" }, + { name = "httpx-sse" }, + { name = "pydantic" }, + { name = "sse-starlette" }, + { name = "starlette" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f7/60/66ebfd280b197f9a9d074c9e46cb1ac3186a32d12e6bd0425c24fe7cf7e8/mcp-1.1.3.tar.gz", hash = "sha256:af11018b8e9153cdd25f3722ec639fe7a462c00213a330fd6f593968341a9883", size = 57903 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b8/08/cfcfa13e41f8d27503c51a8cbf1939d720073ace92469d08655bb5de1b24/mcp-1.1.3-py3-none-any.whl", hash = "sha256:71462d6cd7c06c14689dfcf110ff22286ba1b608cfc3515c0a5cbe33d131731a", size = 36997 }, +] + [[package]] name = "mdit-py-plugins" version = "0.4.2" @@ -4342,7 +4399,7 @@ name = "nvidia-cudnn-cu12" version = "9.1.0.70" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "nvidia-cublas-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "nvidia-cublas-cu12", marker = "(platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'linux') or (platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/9f/fd/713452cd72343f682b1c7b9321e23829f00b842ceaedcda96e742ea0b0b3/nvidia_cudnn_cu12-9.1.0.70-py3-none-manylinux2014_x86_64.whl", hash = "sha256:165764f44ef8c61fcdfdfdbe769d687e06374059fbb388b6c89ecb0e28793a6f", size = 664752741 }, @@ -4353,7 +4410,7 @@ name = "nvidia-cufft-cu12" version = "11.2.1.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'linux') or (platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/7a/8a/0e728f749baca3fbeffad762738276e5df60851958be7783af121a7221e7/nvidia_cufft_cu12-11.2.1.3-py3-none-manylinux2014_aarch64.whl", hash = "sha256:5dad8008fc7f92f5ddfa2101430917ce2ffacd86824914c82e28990ad7f00399", size = 211422548 }, @@ -4374,9 +4431,9 @@ name = "nvidia-cusolver-cu12" version = "11.6.1.9" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "nvidia-cublas-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, - { name = "nvidia-cusparse-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, - { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "nvidia-cublas-cu12", marker = "(platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'linux') or (platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "nvidia-cusparse-cu12", marker = "(platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'linux') or (platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'linux') or (platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/46/6b/a5c33cf16af09166845345275c34ad2190944bcc6026797a39f8e0a282e0/nvidia_cusolver_cu12-11.6.1.9-py3-none-manylinux2014_aarch64.whl", hash = "sha256:d338f155f174f90724bbde3758b7ac375a70ce8e706d70b018dd3375545fc84e", size = 127634111 }, @@ -4388,7 +4445,7 @@ name = "nvidia-cusparse-cu12" version = "12.3.1.170" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'linux') or (platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/96/a9/c0d2f83a53d40a4a41be14cea6a0bf9e668ffcf8b004bd65633f433050c0/nvidia_cusparse_cu12-12.3.1.170-py3-none-manylinux2014_aarch64.whl", hash = "sha256:9d32f62896231ebe0480efd8a7f702e143c98cfaa0e8a76df3386c1ba2b54df3", size = 207381987 }, @@ -5070,7 +5127,7 @@ name = "portalocker" version = "2.10.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pywin32", marker = "sys_platform == 'win32'" }, + { name = "pywin32", marker = "(platform_machine != 'aarch64' and platform_system == 'Windows' and sys_platform == 'linux') or (platform_system == 'Windows' and sys_platform != 'darwin' and sys_platform != 'linux')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ed/d3/c6c64067759e87af98cc668c1cc75171347d0f1577fab7ca3749134e3cd4/portalocker-2.10.1.tar.gz", hash = "sha256:ef1bf844e878ab08aee7e40184156e1151f228f103aa5c6bd0724cc330960f8f", size = 40891 } wheels = [ @@ -5242,7 +5299,7 @@ version = "3.2.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, - { name = "tzdata", marker = "sys_platform == 'win32'" }, + { name = "tzdata", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e0/f2/954b1467b3e2ca5945b83b5e320268be1f4df486c3e8ffc90f4e4b707979/psycopg-3.2.4.tar.gz", hash = "sha256:f26f1346d6bf1ef5f5ef1714dd405c67fb365cfd1c6cea07de1792747b167b92", size = 156109 } wheels = [ @@ -5616,7 +5673,7 @@ name = "pytest" version = "8.3.4" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "iniconfig" }, { name = "packaging" }, @@ -6588,7 +6645,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "alabaster" }, { name = "babel" }, - { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, { name = "docutils" }, { name = "imagesize" }, { name = "jinja2" }, @@ -6793,6 +6850,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/dd/b1/3af5104b716c420e40a6ea1b09886cae3a1b9f4538343875f637755cae5b/sqlmodel-0.0.22-py3-none-any.whl", hash = "sha256:a1ed13e28a1f4057cbf4ff6cdb4fc09e85702621d3259ba17b3c230bfb2f941b", size = 28276 }, ] +[[package]] +name = "sse-starlette" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "starlette" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/a4/80d2a11af59fe75b48230846989e93979c892d3a20016b42bb44edb9e398/sse_starlette-2.2.1.tar.gz", hash = "sha256:54470d5f19274aeed6b2d473430b08b4b379ea851d953b11d7f1c4a2c118b419", size = 17376 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/e0/5b8bd393f27f4a62461c5cf2479c75a2cc2ffa330976f9f00f5f6e4f50eb/sse_starlette-2.2.1-py3-none-any.whl", hash = "sha256:6410a3d3ba0c89e7675d4c273a301d64649c03a5ef1ca101f10b47f895fd0e99", size = 10120 }, +] + [[package]] name = "stack-data" version = "0.6.3" @@ -7162,21 +7232,21 @@ dependencies = [ { name = "fsspec" }, { name = "jinja2" }, { name = "networkx" }, - { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, + { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, + { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, + { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, + { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, + { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, + { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, + { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, + { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, + { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, + { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, + { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, { name = "setuptools", marker = "python_full_version >= '3.12'" }, { name = "sympy" }, - { name = "triton", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "triton", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, { name = "typing-extensions" }, ] wheels = [ @@ -7217,7 +7287,7 @@ name = "tqdm" version = "4.67.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "(platform_machine != 'aarch64' and platform_system == 'Windows' and sys_platform == 'linux') or (platform_system == 'Windows' and sys_platform != 'darwin' and sys_platform != 'linux')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737 } wheels = [ @@ -7266,7 +7336,7 @@ version = "0.28.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, - { name = "cffi", marker = "(implementation_name != 'pypy' and os_name == 'nt' and platform_machine != 'aarch64' and sys_platform == 'linux') or (implementation_name != 'pypy' and os_name == 'nt' and sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "cffi", marker = "(implementation_name != 'pypy' and os_name == 'nt' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'linux') or (implementation_name != 'pypy' and os_name == 'nt' and platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux') or (implementation_name != 'pypy' and os_name == 'nt' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')" }, { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "idna" }, { name = "outcome" },