mcp-use 0.1.0__py3-none-any.whl → 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of mcp-use might be problematic. Click here for more details.

@@ -0,0 +1,151 @@
1
+ """
2
+ Connection management for MCP implementations.
3
+
4
+ This module provides an abstract base class for different types of connection
5
+ managers used in MCP connectors.
6
+ """
7
+
8
+ import asyncio
9
+ from abc import ABC, abstractmethod
10
+ from typing import Generic, TypeVar
11
+
12
+ from ..logging import logger
13
+
14
+ # Type variable for connection types
15
+ T = TypeVar("T")
16
+
17
+
18
+ class ConnectionManager(Generic[T], ABC):
19
+ """Abstract base class for connection managers.
20
+
21
+ This class defines the interface for different types of connection managers
22
+ used with MCP connectors.
23
+ """
24
+
25
+ def __init__(self):
26
+ """Initialize a new connection manager."""
27
+ self._ready_event = asyncio.Event()
28
+ self._done_event = asyncio.Event()
29
+ self._exception: Exception | None = None
30
+ self._connection: T | None = None
31
+ self._task: asyncio.Task | None = None
32
+
33
+ @abstractmethod
34
+ async def _establish_connection(self) -> T:
35
+ """Establish the connection.
36
+
37
+ This method should be implemented by subclasses to establish
38
+ the specific type of connection needed.
39
+
40
+ Returns:
41
+ The established connection.
42
+
43
+ Raises:
44
+ Exception: If connection cannot be established.
45
+ """
46
+ pass
47
+
48
+ @abstractmethod
49
+ async def _close_connection(self, connection: T) -> None:
50
+ """Close the connection.
51
+
52
+ This method should be implemented by subclasses to close
53
+ the specific type of connection.
54
+
55
+ Args:
56
+ connection: The connection to close.
57
+ """
58
+ pass
59
+
60
+ async def start(self) -> T:
61
+ """Start the connection manager and establish a connection.
62
+
63
+ Returns:
64
+ The established connection.
65
+
66
+ Raises:
67
+ Exception: If connection cannot be established.
68
+ """
69
+ # Reset state
70
+ self._ready_event.clear()
71
+ self._done_event.clear()
72
+ self._exception = None
73
+
74
+ # Create a task to establish and maintain the connection
75
+ self._task = asyncio.create_task(
76
+ self._connection_task(), name=f"{self.__class__.__name__}_task"
77
+ )
78
+
79
+ # Wait for the connection to be ready or fail
80
+ await self._ready_event.wait()
81
+
82
+ # If there was an exception, raise it
83
+ if self._exception:
84
+ raise self._exception
85
+
86
+ # Return the connection
87
+ if self._connection is None:
88
+ raise RuntimeError("Connection was not established")
89
+ return self._connection
90
+
91
+ async def stop(self) -> None:
92
+ """Stop the connection manager and close the connection."""
93
+ if self._task and not self._task.done():
94
+ # Cancel the task
95
+ logger.debug(f"Cancelling {self.__class__.__name__} task")
96
+ self._task.cancel()
97
+
98
+ # Wait for it to complete
99
+ try:
100
+ await self._task
101
+ except asyncio.CancelledError:
102
+ logger.debug(f"{self.__class__.__name__} task cancelled successfully")
103
+ except Exception as e:
104
+ logger.warning(f"Error stopping {self.__class__.__name__} task: {e}")
105
+
106
+ # Wait for the connection to be done
107
+ await self._done_event.wait()
108
+ logger.debug(f"{self.__class__.__name__} task completed")
109
+
110
+ async def _connection_task(self) -> None:
111
+ """Run the connection task.
112
+
113
+ This task establishes and maintains the connection until cancelled.
114
+ """
115
+ logger.debug(f"Starting {self.__class__.__name__} task")
116
+ try:
117
+ # Establish the connection
118
+ self._connection = await self._establish_connection()
119
+ logger.debug(f"{self.__class__.__name__} connected successfully")
120
+
121
+ # Signal that the connection is ready
122
+ self._ready_event.set()
123
+
124
+ # Wait indefinitely until cancelled
125
+ try:
126
+ # This keeps the connection open until cancelled
127
+ await asyncio.Event().wait()
128
+ except asyncio.CancelledError:
129
+ # Expected when stopping
130
+ logger.debug(f"{self.__class__.__name__} task received cancellation")
131
+ pass
132
+
133
+ except Exception as e:
134
+ # Store the exception
135
+ self._exception = e
136
+ logger.error(f"Error in {self.__class__.__name__} task: {e}")
137
+
138
+ # Signal that the connection is ready (with error)
139
+ self._ready_event.set()
140
+
141
+ finally:
142
+ # Close the connection if it was established
143
+ if self._connection is not None:
144
+ try:
145
+ await self._close_connection(self._connection)
146
+ except Exception as e:
147
+ logger.warning(f"Error closing connection in {self.__class__.__name__}: {e}")
148
+ self._connection = None
149
+
150
+ # Signal that the connection is done
151
+ self._done_event.set()
@@ -0,0 +1,62 @@
1
+ """
2
+ HTTP connection management for MCP implementations.
3
+
4
+ This module provides a connection manager for HTTP-based MCP connections.
5
+ """
6
+
7
+ import aiohttp
8
+
9
+ from ..logging import logger
10
+ from .base import ConnectionManager
11
+
12
+
13
+ class HttpConnectionManager(ConnectionManager[aiohttp.ClientSession]):
14
+ """Connection manager for HTTP-based MCP connections.
15
+
16
+ This class handles the lifecycle of HTTP client sessions, ensuring proper
17
+ connection establishment and cleanup.
18
+ """
19
+
20
+ def __init__(
21
+ self,
22
+ base_url: str,
23
+ headers: dict[str, str] | None = None,
24
+ ):
25
+ """Initialize a new HTTP connection manager.
26
+
27
+ Args:
28
+ base_url: The base URL for HTTP requests
29
+ headers: Optional headers to include in all HTTP requests
30
+ """
31
+ super().__init__()
32
+ self.base_url = base_url.rstrip("/")
33
+ self.headers = headers or {}
34
+
35
+ async def _establish_connection(self) -> aiohttp.ClientSession:
36
+ """Establish an HTTP client session.
37
+
38
+ Returns:
39
+ The established HTTP client session
40
+
41
+ Raises:
42
+ Exception: If session cannot be established
43
+ """
44
+ logger.debug(f"Creating HTTP client session for: {self.base_url}")
45
+ try:
46
+ session = aiohttp.ClientSession(headers=self.headers)
47
+ return session
48
+ except Exception as e:
49
+ logger.error(f"Failed to create HTTP client session: {e}")
50
+ raise
51
+
52
+ async def _close_connection(self, connection: aiohttp.ClientSession) -> None:
53
+ """Close the HTTP client session.
54
+
55
+ Args:
56
+ connection: The HTTP client session to close
57
+ """
58
+ try:
59
+ logger.debug("Closing HTTP client session")
60
+ await connection.close()
61
+ except Exception as e:
62
+ logger.warning(f"Error closing HTTP client session: {e}")
@@ -0,0 +1,73 @@
1
+ """
2
+ StdIO connection management for MCP implementations.
3
+
4
+ This module provides a connection manager for stdio-based MCP connections
5
+ that ensures proper task isolation and resource cleanup.
6
+ """
7
+
8
+ import sys
9
+ from typing import Any, TextIO
10
+
11
+ from mcp import StdioServerParameters
12
+ from mcp.client.stdio import stdio_client
13
+
14
+ from ..logging import logger
15
+ from .base import ConnectionManager
16
+
17
+
18
+ class StdioConnectionManager(ConnectionManager[tuple[Any, Any]]):
19
+ """Connection manager for stdio-based MCP connections.
20
+
21
+ This class handles the proper task isolation for stdio_client context managers
22
+ to prevent the "cancel scope in different task" error. It runs the stdio_client
23
+ in a dedicated task and manages its lifecycle.
24
+ """
25
+
26
+ def __init__(
27
+ self,
28
+ server_params: StdioServerParameters,
29
+ errlog: TextIO = sys.stderr,
30
+ ):
31
+ """Initialize a new stdio connection manager.
32
+
33
+ Args:
34
+ server_params: The parameters for the stdio server
35
+ errlog: The error log stream
36
+ """
37
+ super().__init__()
38
+ self.server_params = server_params
39
+ self.errlog = errlog
40
+ self._stdio_ctx = None
41
+
42
+ async def _establish_connection(self) -> tuple[Any, Any]:
43
+ """Establish a stdio connection.
44
+
45
+ Returns:
46
+ A tuple of (read_stream, write_stream)
47
+
48
+ Raises:
49
+ Exception: If connection cannot be established.
50
+ """
51
+ # Create the context manager
52
+ self._stdio_ctx = stdio_client(self.server_params, self.errlog)
53
+
54
+ # Enter the context manager
55
+ read_stream, write_stream = await self._stdio_ctx.__aenter__()
56
+
57
+ # Return the streams
58
+ return (read_stream, write_stream)
59
+
60
+ async def _close_connection(self, connection: tuple[Any, Any]) -> None:
61
+ """Close the stdio connection.
62
+
63
+ Args:
64
+ connection: The connection to close (ignored, we use the context manager)
65
+ """
66
+ if self._stdio_ctx:
67
+ # Exit the context manager
68
+ try:
69
+ await self._stdio_ctx.__aexit__(None, None, None)
70
+ except Exception as e:
71
+ logger.warning(f"Error closing stdio context: {e}")
72
+ finally:
73
+ self._stdio_ctx = None
@@ -0,0 +1,63 @@
1
+ """
2
+ WebSocket connection management for MCP implementations.
3
+
4
+ This module provides a connection manager for WebSocket-based MCP connections.
5
+ """
6
+
7
+ import websockets
8
+ from websockets.client import WebSocketClientProtocol
9
+
10
+ from ..logging import logger
11
+ from .base import ConnectionManager
12
+
13
+
14
+ class WebSocketConnectionManager(ConnectionManager[WebSocketClientProtocol]):
15
+ """Connection manager for WebSocket-based MCP connections.
16
+
17
+ This class handles the lifecycle of WebSocket connections, ensuring proper
18
+ connection establishment and cleanup.
19
+ """
20
+
21
+ def __init__(
22
+ self,
23
+ url: str,
24
+ headers: dict[str, str] | None = None,
25
+ ):
26
+ """Initialize a new WebSocket connection manager.
27
+
28
+ Args:
29
+ url: The WebSocket URL to connect to
30
+ headers: Optional headers to include in the WebSocket connection
31
+ """
32
+ super().__init__()
33
+ self.url = url
34
+ self.headers = headers or {}
35
+
36
+ async def _establish_connection(self) -> WebSocketClientProtocol:
37
+ """Establish a WebSocket connection.
38
+
39
+ Returns:
40
+ The established WebSocket connection
41
+
42
+ Raises:
43
+ Exception: If connection cannot be established
44
+ """
45
+ logger.debug(f"Connecting to WebSocket: {self.url}")
46
+ try:
47
+ ws = await websockets.connect(self.url, extra_headers=self.headers)
48
+ return ws
49
+ except Exception as e:
50
+ logger.error(f"Failed to connect to WebSocket: {e}")
51
+ raise
52
+
53
+ async def _close_connection(self, connection: WebSocketClientProtocol) -> None:
54
+ """Close the WebSocket connection.
55
+
56
+ Args:
57
+ connection: The WebSocket connection to close
58
+ """
59
+ try:
60
+ logger.debug("Closing WebSocket connection")
61
+ await connection.close()
62
+ except Exception as e:
63
+ logger.warning(f"Error closing WebSocket connection: {e}")