Manages connection to a single MCP server (STDIO or URL-based) with timeout handling.
| 120 | |
| 121 | |
| 122 | class MCPServerConnection: |
| 123 | """Manages connection to a single MCP server (STDIO or URL-based) with timeout handling.""" |
| 124 | |
| 125 | def __init__( |
| 126 | self, |
| 127 | name: str, |
| 128 | connection_type: ConnectionType = "stdio", |
| 129 | # STDIO params |
| 130 | command: str | None = None, |
| 131 | args: list[str] | None = None, |
| 132 | env: dict[str, str] | None = None, |
| 133 | # URL-based params |
| 134 | url: str | None = None, |
| 135 | headers: dict[str, str] | None = None, |
| 136 | # Timeout overrides (per-server) |
| 137 | connect_timeout: float | None = None, |
| 138 | execute_timeout: float | None = None, |
| 139 | sse_read_timeout: float | None = None, |
| 140 | ): |
| 141 | self.name = name |
| 142 | self.connection_type = connection_type |
| 143 | # STDIO |
| 144 | self.command = command |
| 145 | self.args = args or [] |
| 146 | self.env = env or {} |
| 147 | # URL-based |
| 148 | self.url = url |
| 149 | self.headers = headers or {} |
| 150 | # Timeout settings (per-server overrides) |
| 151 | self.connect_timeout = connect_timeout |
| 152 | self.execute_timeout = execute_timeout |
| 153 | self.sse_read_timeout = sse_read_timeout |
| 154 | # Connection state |
| 155 | self.session: ClientSession | None = None |
| 156 | self.exit_stack: AsyncExitStack | None = None |
| 157 | self.tools: list[MCPTool] = [] |
| 158 | |
| 159 | def _get_connect_timeout(self) -> float: |
| 160 | """Get effective connect timeout.""" |
| 161 | return self.connect_timeout or _default_timeout_config.connect_timeout |
| 162 | |
| 163 | def _get_sse_read_timeout(self) -> float: |
| 164 | """Get effective SSE read timeout.""" |
| 165 | return self.sse_read_timeout or _default_timeout_config.sse_read_timeout |
| 166 | |
| 167 | def _get_execute_timeout(self) -> float: |
| 168 | """Get effective execute timeout.""" |
| 169 | return self.execute_timeout or _default_timeout_config.execute_timeout |
| 170 | |
| 171 | async def connect(self) -> bool: |
| 172 | """Connect to the MCP server with timeout protection.""" |
| 173 | connect_timeout = self._get_connect_timeout() |
| 174 | |
| 175 | try: |
| 176 | self.exit_stack = AsyncExitStack() |
| 177 | |
| 178 | # Wrap connection with timeout |
| 179 | async with asyncio.timeout(connect_timeout): |
no outgoing calls