mcp-use 0.0.6__tar.gz → 1.0.0__tar.gz

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.

Files changed (39) hide show
  1. {mcp_use-0.0.6 → mcp_use-1.0.0}/PKG-INFO +63 -2
  2. {mcp_use-0.0.6 → mcp_use-1.0.0}/README.md +62 -1
  3. mcp_use-1.0.0/examples/multi_server_example.py +66 -0
  4. {mcp_use-0.0.6 → mcp_use-1.0.0}/mcp_use/agents/langchain_agent.py +62 -77
  5. {mcp_use-0.0.6 → mcp_use-1.0.0}/mcp_use/agents/mcpagent.py +34 -31
  6. {mcp_use-0.0.6 → mcp_use-1.0.0}/mcp_use/client.py +55 -42
  7. {mcp_use-0.0.6 → mcp_use-1.0.0}/pyproject.toml +1 -1
  8. mcp_use-1.0.0/static/image.jpg +0 -0
  9. mcp_use-0.0.6/static/mcpusegrass.png +0 -0
  10. {mcp_use-0.0.6 → mcp_use-1.0.0}/.github/workflows/publish.yml +0 -0
  11. {mcp_use-0.0.6 → mcp_use-1.0.0}/.github/workflows/tests.yml +0 -0
  12. {mcp_use-0.0.6 → mcp_use-1.0.0}/.gitignore +0 -0
  13. {mcp_use-0.0.6 → mcp_use-1.0.0}/.pre-commit-config.yaml +0 -0
  14. {mcp_use-0.0.6 → mcp_use-1.0.0}/LICENSE +0 -0
  15. {mcp_use-0.0.6 → mcp_use-1.0.0}/examples/airbnb_mcp.json +0 -0
  16. {mcp_use-0.0.6 → mcp_use-1.0.0}/examples/airbnb_use.py +0 -0
  17. {mcp_use-0.0.6 → mcp_use-1.0.0}/examples/blender_use.py +0 -0
  18. {mcp_use-0.0.6 → mcp_use-1.0.0}/examples/browser_mcp.json +0 -0
  19. {mcp_use-0.0.6 → mcp_use-1.0.0}/examples/browser_use.py +0 -0
  20. {mcp_use-0.0.6 → mcp_use-1.0.0}/examples/chat_example.py +0 -0
  21. {mcp_use-0.0.6 → mcp_use-1.0.0}/examples/filesystem_use.py +0 -0
  22. {mcp_use-0.0.6 → mcp_use-1.0.0}/mcp_use/__init__.py +0 -0
  23. {mcp_use-0.0.6 → mcp_use-1.0.0}/mcp_use/agents/__init__.py +0 -0
  24. {mcp_use-0.0.6 → mcp_use-1.0.0}/mcp_use/agents/base.py +0 -0
  25. {mcp_use-0.0.6 → mcp_use-1.0.0}/mcp_use/agents/prompts/default.py +0 -0
  26. {mcp_use-0.0.6 → mcp_use-1.0.0}/mcp_use/config.py +0 -0
  27. {mcp_use-0.0.6 → mcp_use-1.0.0}/mcp_use/connectors/__init__.py +0 -0
  28. {mcp_use-0.0.6 → mcp_use-1.0.0}/mcp_use/connectors/base.py +0 -0
  29. {mcp_use-0.0.6 → mcp_use-1.0.0}/mcp_use/connectors/http.py +0 -0
  30. {mcp_use-0.0.6 → mcp_use-1.0.0}/mcp_use/connectors/stdio.py +0 -0
  31. {mcp_use-0.0.6 → mcp_use-1.0.0}/mcp_use/connectors/websocket.py +0 -0
  32. {mcp_use-0.0.6 → mcp_use-1.0.0}/mcp_use/logging.py +0 -0
  33. {mcp_use-0.0.6 → mcp_use-1.0.0}/mcp_use/session.py +0 -0
  34. {mcp_use-0.0.6 → mcp_use-1.0.0}/mcp_use/task_managers/__init__.py +0 -0
  35. {mcp_use-0.0.6 → mcp_use-1.0.0}/mcp_use/task_managers/base.py +0 -0
  36. {mcp_use-0.0.6 → mcp_use-1.0.0}/mcp_use/task_managers/http.py +0 -0
  37. {mcp_use-0.0.6 → mcp_use-1.0.0}/mcp_use/task_managers/stdio.py +0 -0
  38. {mcp_use-0.0.6 → mcp_use-1.0.0}/mcp_use/task_managers/websocket.py +0 -0
  39. {mcp_use-0.0.6 → mcp_use-1.0.0}/tests/unit/test_placeholder.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-use
3
- Version: 0.0.6
3
+ Version: 1.0.0
4
4
  Summary: MCP Library for LLMs
5
5
  Author-email: Pietro Zullo <pietro.zullo@gmail.com>
6
6
  License: MIT
@@ -285,9 +285,70 @@ if __name__ == "__main__":
285
285
  asyncio.run(main())
286
286
  ```
287
287
 
288
+ # Multi-Server Support
289
+
290
+ MCP-Use supports working with multiple MCP servers simultaneously, allowing you to combine tools from different servers in a single agent. This is useful for complex tasks that require multiple capabilities, such as web browsing combined with file operations or 3D modeling.
291
+
292
+ ## Configuration
293
+
294
+ You can configure multiple servers in your configuration file:
295
+
296
+ ```json
297
+ {
298
+ "mcpServers": {
299
+ "airbnb": {
300
+ "command": "npx",
301
+ "args": ["-y", "@openbnb/mcp-server-airbnb", "--ignore-robots-txt"]
302
+ },
303
+ "playwright": {
304
+ "command": "npx",
305
+ "args": ["@playwright/mcp@latest"],
306
+ "env": {
307
+ "DISPLAY": ":1"
308
+ }
309
+ }
310
+ }
311
+ }
312
+ ```
313
+
314
+ ## Usage
315
+
316
+ The `MCPClient` class provides several methods for managing multiple servers:
317
+
318
+ ```python
319
+ import asyncio
320
+ from mcp_use import MCPClient, MCPAgent
321
+ from langchain_anthropic import ChatAnthropic
322
+
323
+ async def main():
324
+ # Create client with multiple servers
325
+ client = MCPClient.from_config_file("multi_server_config.json")
326
+
327
+ # Create agent with the client
328
+ agent = MCPAgent(
329
+ llm=ChatAnthropic(model="claude-3-5-sonnet-20240620"),
330
+ client=client
331
+ )
332
+
333
+ try:
334
+ # Run a query that uses tools from multiple servers
335
+ result = await agent.run(
336
+ "Search for a nice place to stay in Barcelona on Airbnb, "
337
+ "then use Google to find nearby restaurants and attractions."
338
+ )
339
+ print(result)
340
+ finally:
341
+ # Clean up all sessions
342
+ await client.close_all_sessions()
343
+
344
+ if __name__ == "__main__":
345
+ asyncio.run(main())
346
+ ```
347
+
288
348
  ## Roadmap
349
+
289
350
  <ul>
290
- <li>[ ] Multiple Servers at once </li>
351
+ <li>[x] Multiple Servers at once </li>
291
352
  <li>[ ] Test remote connectors (http, ws)</li>
292
353
  <li>[ ] ... </li>
293
354
  </ul>
@@ -246,9 +246,70 @@ if __name__ == "__main__":
246
246
  asyncio.run(main())
247
247
  ```
248
248
 
249
+ # Multi-Server Support
250
+
251
+ MCP-Use supports working with multiple MCP servers simultaneously, allowing you to combine tools from different servers in a single agent. This is useful for complex tasks that require multiple capabilities, such as web browsing combined with file operations or 3D modeling.
252
+
253
+ ## Configuration
254
+
255
+ You can configure multiple servers in your configuration file:
256
+
257
+ ```json
258
+ {
259
+ "mcpServers": {
260
+ "airbnb": {
261
+ "command": "npx",
262
+ "args": ["-y", "@openbnb/mcp-server-airbnb", "--ignore-robots-txt"]
263
+ },
264
+ "playwright": {
265
+ "command": "npx",
266
+ "args": ["@playwright/mcp@latest"],
267
+ "env": {
268
+ "DISPLAY": ":1"
269
+ }
270
+ }
271
+ }
272
+ }
273
+ ```
274
+
275
+ ## Usage
276
+
277
+ The `MCPClient` class provides several methods for managing multiple servers:
278
+
279
+ ```python
280
+ import asyncio
281
+ from mcp_use import MCPClient, MCPAgent
282
+ from langchain_anthropic import ChatAnthropic
283
+
284
+ async def main():
285
+ # Create client with multiple servers
286
+ client = MCPClient.from_config_file("multi_server_config.json")
287
+
288
+ # Create agent with the client
289
+ agent = MCPAgent(
290
+ llm=ChatAnthropic(model="claude-3-5-sonnet-20240620"),
291
+ client=client
292
+ )
293
+
294
+ try:
295
+ # Run a query that uses tools from multiple servers
296
+ result = await agent.run(
297
+ "Search for a nice place to stay in Barcelona on Airbnb, "
298
+ "then use Google to find nearby restaurants and attractions."
299
+ )
300
+ print(result)
301
+ finally:
302
+ # Clean up all sessions
303
+ await client.close_all_sessions()
304
+
305
+ if __name__ == "__main__":
306
+ asyncio.run(main())
307
+ ```
308
+
249
309
  ## Roadmap
310
+
250
311
  <ul>
251
- <li>[ ] Multiple Servers at once </li>
312
+ <li>[x] Multiple Servers at once </li>
252
313
  <li>[ ] Test remote connectors (http, ws)</li>
253
314
  <li>[ ] ... </li>
254
315
  </ul>
@@ -0,0 +1,66 @@
1
+ """
2
+ Example demonstrating how to use MCPClient with multiple servers.
3
+
4
+ This example shows how to:
5
+ 1. Configure multiple MCP servers
6
+ 2. Create and manage sessions for each server
7
+ 3. Use tools from different servers in a single agent
8
+ """
9
+
10
+ import asyncio
11
+
12
+ from dotenv import load_dotenv
13
+ from langchain_anthropic import ChatAnthropic
14
+
15
+ from mcp_use import MCPAgent, MCPClient
16
+
17
+
18
+ async def run_multi_server_example():
19
+ """Run an example using multiple MCP servers."""
20
+ # Load environment variables
21
+ load_dotenv()
22
+
23
+ # Create a configuration with multiple servers
24
+ config = {
25
+ "mcpServers": {
26
+ "airbnb": {
27
+ "command": "npx",
28
+ "args": ["-y", "@openbnb/mcp-server-airbnb", "--ignore-robots-txt"],
29
+ },
30
+ "playwright": {
31
+ "command": "npx",
32
+ "args": ["@playwright/mcp@latest"],
33
+ "env": {"DISPLAY": ":1"},
34
+ },
35
+ "filesystem": {
36
+ "command": "npx",
37
+ "args": [
38
+ "-y",
39
+ "@modelcontextprotocol/server-filesystem",
40
+ "/home/pietro/projects/mcp-use/",
41
+ ],
42
+ },
43
+ }
44
+ }
45
+
46
+ # Create MCPClient with the multi-server configuration
47
+ client = MCPClient.from_dict(config)
48
+
49
+ # Create LLM
50
+ llm = ChatAnthropic(model="claude-3-5-sonnet-20240620")
51
+
52
+ # Create agent with the client
53
+ agent = MCPAgent(llm=llm, client=client, max_steps=30)
54
+
55
+ # Example 1: Using tools from different servers in a single query
56
+ result = await agent.run(
57
+ "Search for a nice place to stay in Barcelona on Airbnb, "
58
+ "then use Google to find nearby restaurants and attractions."
59
+ "Write the result in the current directory in restarant.txt",
60
+ max_steps=30,
61
+ )
62
+ print(result)
63
+
64
+
65
+ if __name__ == "__main__":
66
+ asyncio.run(run_multi_server_example())
@@ -78,7 +78,7 @@ class LangChainAgent:
78
78
 
79
79
  def __init__(
80
80
  self,
81
- connector: BaseConnector,
81
+ connectors: list[BaseConnector],
82
82
  llm: BaseLanguageModel,
83
83
  max_steps: int = 5,
84
84
  system_message: str | None = None,
@@ -91,7 +91,7 @@ class LangChainAgent:
91
91
  max_steps: The maximum number of steps to take.
92
92
  system_message: Optional custom system message to use.
93
93
  """
94
- self.connector = connector
94
+ self.connectors = connectors
95
95
  self.llm = llm
96
96
  self.max_steps = max_steps
97
97
  self.system_message = system_message or self.DEFAULT_SYSTEM_MESSAGE
@@ -139,67 +139,70 @@ class LangChainAgent:
139
139
  Returns:
140
140
  A list of LangChain tools created from MCP tools.
141
141
  """
142
- tools = self.connector.tools
143
- local_connector = self.connector
144
-
145
- # Wrap MCP tools into LangChain tools
146
142
  langchain_tools: list[BaseTool] = []
147
- for tool in tools:
148
- # Define adapter class to convert MCP tool to LangChain format
149
- class McpToLangChainAdapter(BaseTool):
150
- name: str = tool.name or "NO NAME"
151
- description: str = tool.description or ""
152
- # Convert JSON schema to Pydantic model for argument validation
153
- args_schema: type[BaseModel] = jsonschema_to_pydantic(
154
- self.fix_schema(tool.inputSchema) # Apply schema conversion
155
- )
156
- connector: BaseConnector = local_connector
157
- handle_tool_error: bool = True
158
-
159
- def _run(self, **kwargs: Any) -> NoReturn:
160
- """Synchronous run method that always raises an error.
161
-
162
- Raises:
163
- NotImplementedError: Always raises this error because MCP tools
164
- only support async operations.
165
- """
166
- raise NotImplementedError("MCP tools only support async operations")
167
-
168
- async def _arun(self, **kwargs: Any) -> Any:
169
- """Asynchronously execute the tool with given arguments.
170
-
171
- Args:
172
- kwargs: The arguments to pass to the tool.
173
-
174
- Returns:
175
- The result of the tool execution.
176
-
177
- Raises:
178
- ToolException: If tool execution fails.
179
- """
180
- logger.info(f'MCP tool: "{self.name}" received input: {kwargs}')
181
-
182
- try:
183
- tool_result: CallToolResult = await self.connector.call_tool(
184
- self.name, kwargs
185
- )
143
+
144
+ for connector in self.connectors:
145
+ tools = connector.tools
146
+ local_connector = connector
147
+
148
+ # Wrap MCP tools into LangChain tools
149
+ for tool in tools:
150
+ # Define adapter class to convert MCP tool to LangChain format
151
+ class McpToLangChainAdapter(BaseTool):
152
+ name: str = tool.name or "NO NAME"
153
+ description: str = tool.description or ""
154
+ # Convert JSON schema to Pydantic model for argument validation
155
+ args_schema: type[BaseModel] = jsonschema_to_pydantic(
156
+ self.fix_schema(tool.inputSchema) # Apply schema conversion
157
+ )
158
+ connector: BaseConnector = local_connector
159
+ handle_tool_error: bool = True
160
+
161
+ def _run(self, **kwargs: Any) -> NoReturn:
162
+ """Synchronous run method that always raises an error.
163
+
164
+ Raises:
165
+ NotImplementedError: Always raises this error because MCP tools
166
+ only support async operations.
167
+ """
168
+ raise NotImplementedError("MCP tools only support async operations")
169
+
170
+ async def _arun(self, **kwargs: Any) -> Any:
171
+ """Asynchronously execute the tool with given arguments.
172
+
173
+ Args:
174
+ kwargs: The arguments to pass to the tool.
175
+
176
+ Returns:
177
+ The result of the tool execution.
178
+
179
+ Raises:
180
+ ToolException: If tool execution fails.
181
+ """
182
+ logger.info(f'MCP tool: "{self.name}" received input: {kwargs}')
183
+
186
184
  try:
187
- # Use the helper function to parse the result
188
- return _parse_mcp_tool_result(tool_result)
189
- except Exception as e:
190
- # Log the exception for debugging
191
- logger.error(f"Error parsing tool result: {e}")
192
- # Shortened line:
193
- return (
194
- f"Error parsing result: {e!s}; Raw content: {tool_result.content!r}"
185
+ tool_result: CallToolResult = await self.connector.call_tool(
186
+ self.name, kwargs
195
187
  )
188
+ try:
189
+ # Use the helper function to parse the result
190
+ return _parse_mcp_tool_result(tool_result)
191
+ except Exception as e:
192
+ # Log the exception for debugging
193
+ logger.error(f"Error parsing tool result: {e}")
194
+ # Shortened line:
195
+ return (
196
+ f"Error parsing result: {e!s};"
197
+ f" Raw content: {tool_result.content!r}"
198
+ )
196
199
 
197
- except Exception as e:
198
- if self.handle_tool_error:
199
- return f"Error executing MCP tool: {str(e)}"
200
- raise
200
+ except Exception as e:
201
+ if self.handle_tool_error:
202
+ return f"Error executing MCP tool: {str(e)}"
203
+ raise
201
204
 
202
- langchain_tools.append(McpToLangChainAdapter())
205
+ langchain_tools.append(McpToLangChainAdapter())
203
206
 
204
207
  # Log available tools for debugging
205
208
  logger.info(f"Available tools: {[tool.name for tool in langchain_tools]}")
@@ -256,25 +259,7 @@ class LangChainAgent:
256
259
  if chat_history is None:
257
260
  chat_history = []
258
261
 
259
- # Add a hint to use tools for queries about current information
260
- enhanced_query = query
261
- if any(
262
- keyword in query.lower()
263
- for keyword in [
264
- "weather",
265
- "current",
266
- "today",
267
- "now",
268
- "latest",
269
- "news",
270
- "price",
271
- "stock",
272
- ]
273
- ):
274
- # Just log this, don't modify the query
275
- logger.info("Query involves current information that may benefit from tool use")
276
-
277
262
  # Invoke with all required variables
278
- result = await self.agent.ainvoke({"input": enhanced_query, "chat_history": chat_history})
263
+ result = await self.agent.ainvoke({"input": query, "chat_history": chat_history})
279
264
 
280
265
  return result["output"]
@@ -31,7 +31,7 @@ class MCPAgent:
31
31
  self,
32
32
  llm: BaseLanguageModel,
33
33
  client: MCPClient | None = None,
34
- connector: BaseConnector | None = None,
34
+ connectors: list[BaseConnector] | None = None,
35
35
  server_name: str | None = None,
36
36
  max_steps: int = 5,
37
37
  auto_initialize: bool = False,
@@ -45,7 +45,7 @@ class MCPAgent:
45
45
  Args:
46
46
  llm: The LangChain LLM to use.
47
47
  client: The MCPClient to use. If provided, connector is ignored.
48
- connector: The MCP connector to use if client is not provided.
48
+ connectors: A list of MCP connectors to use if client is not provided.
49
49
  server_name: The name of the server to use if client is provided.
50
50
  max_steps: The maximum number of steps to take.
51
51
  auto_initialize: Whether to automatically initialize the agent when run is called.
@@ -56,7 +56,7 @@ class MCPAgent:
56
56
  """
57
57
  self.llm = llm
58
58
  self.client = client
59
- self.connector = connector
59
+ self.connectors = connectors
60
60
  self.server_name = server_name
61
61
  self.max_steps = max_steps
62
62
  self.auto_initialize = auto_initialize
@@ -70,34 +70,35 @@ class MCPAgent:
70
70
  self.additional_instructions = additional_instructions
71
71
 
72
72
  # Either client or connector must be provided
73
- if not client and not connector:
73
+ if not client and len(connectors) == 0:
74
74
  raise ValueError("Either client or connector must be provided")
75
75
 
76
76
  self._agent: LangChainAgent | None = None
77
- self._session: MCPSession | None = None
77
+ self._sessions: dict[str, MCPSession] | None = None
78
78
  self._system_message: SystemMessage | None = None
79
79
 
80
80
  async def initialize(self) -> None:
81
81
  """Initialize the MCP client and agent."""
82
82
  # If using client, get or create a session
83
83
  if self.client:
84
- try:
85
- self._session = self.client.get_session(self.server_name)
86
- except ValueError:
87
- self._session = await self.client.create_session(self.server_name)
88
- connector_to_use = self._session.connector
84
+ # First try to get existing sessions
85
+ self._sessions = self.client.get_all_active_sessions()
86
+
87
+ # If no active sessions exist, create new ones
88
+ if not self._sessions:
89
+ self._sessions = await self.client.create_all_sessions()
90
+ connectors_to_use = [session.connector for session in self._sessions.values()]
89
91
  else:
90
92
  # Using direct connector
91
- connector_to_use = self.connector
92
- await connector_to_use.connect()
93
- await connector_to_use.initialize()
94
-
93
+ connectors_to_use = self.connectors
94
+ await [c_to_use.connect() for c_to_use in connectors_to_use]
95
+ await [c_to_use.initialize() for c_to_use in connectors_to_use]
95
96
  # Create the system message based on available tools
96
- await self._create_system_message(connector_to_use)
97
+ await self._create_system_message(connectors_to_use)
97
98
 
98
99
  # Create the agent
99
100
  self._agent = LangChainAgent(
100
- connector=connector_to_use,
101
+ connectors=connectors_to_use,
101
102
  llm=self.llm,
102
103
  max_steps=self.max_steps,
103
104
  system_message=(self._system_message.content if self._system_message else None),
@@ -107,7 +108,7 @@ class MCPAgent:
107
108
  await self._agent.initialize()
108
109
  self._initialized = True
109
110
 
110
- async def _create_system_message(self, connector: BaseConnector) -> None:
111
+ async def _create_system_message(self, connectors: list[BaseConnector]) -> None:
111
112
  """Create the system message based on available tools.
112
113
 
113
114
  Args:
@@ -119,15 +120,17 @@ class MCPAgent:
119
120
  return
120
121
 
121
122
  # Otherwise, build the system prompt from the template and tool descriptions
122
- tools = connector.tools
123
-
124
- # Generate tool descriptions
125
123
  tool_descriptions = []
126
- for tool in tools:
127
- # Escape curly braces in the description by doubling them
128
- # (sometimes e.g. blender mcp they are used in the description)
129
- description = f"- {tool.name}: {tool.description.replace('{', '{{').replace('}', '}}')}"
130
- tool_descriptions.append(description)
124
+ for connector in connectors:
125
+ tools = connector.tools
126
+ # Generate tool descriptions
127
+ for tool in tools:
128
+ # Escape curly braces in the description by doubling them
129
+ # (sometimes e.g. blender mcp they are used in the description)
130
+ description = (
131
+ f"- {tool.name}: {tool.description.replace('{', '{{').replace('}', '}}')}"
132
+ )
133
+ tool_descriptions.append(description)
131
134
 
132
135
  # Format the system prompt template with tool descriptions
133
136
  system_prompt = self.system_prompt_template.format(
@@ -140,7 +143,6 @@ class MCPAgent:
140
143
 
141
144
  # Create the system message
142
145
  self._system_message = SystemMessage(content=system_prompt)
143
- logger.info(f"Created system message with {len(tools)} tool descriptions")
144
146
 
145
147
  def get_conversation_history(self) -> list[BaseMessage]:
146
148
  """Get the current conversation history.
@@ -290,14 +292,15 @@ class MCPAgent:
290
292
  self._agent = None
291
293
 
292
294
  # If using client with session, close the session through client
293
- if self.client and self._session:
295
+ if self.client and self._sessions:
294
296
  logger.debug("Closing session through client")
295
- await self.client.close_session(self.server_name)
297
+ await self.client.close_all_sessions()
296
298
  self._session = None
297
299
  # If using direct connector, disconnect
298
- elif self.connector:
299
- logger.debug("Disconnecting connector")
300
- await self.connector.disconnect()
300
+ elif self.connectors:
301
+ for connector in self.connectors:
302
+ logger.debug("Disconnecting connector")
303
+ await connector.disconnect()
301
304
 
302
305
  self._initialized = False
303
306
  logger.info("Agent closed successfully")
@@ -32,7 +32,7 @@ class MCPClient:
32
32
  """
33
33
  self.config: dict[str, Any] = {}
34
34
  self.sessions: dict[str, MCPSession] = {}
35
- self.active_session: str | None = None
35
+ self.active_sessions: list[str] = []
36
36
 
37
37
  # Load configuration if provided
38
38
  if config is not None:
@@ -84,9 +84,9 @@ class MCPClient:
84
84
  if "mcpServers" in self.config and name in self.config["mcpServers"]:
85
85
  del self.config["mcpServers"][name]
86
86
 
87
- # If we removed the active session, set active_session to None
88
- if name == self.active_session:
89
- self.active_session = None
87
+ # If we removed an active session, remove it from active_sessions
88
+ if name in self.active_sessions:
89
+ self.active_sessions.remove(name)
90
90
 
91
91
  def get_server_names(self) -> list[str]:
92
92
  """Get the list of configured server names.
@@ -105,17 +105,11 @@ class MCPClient:
105
105
  with open(filepath, "w") as f:
106
106
  json.dump(self.config, f, indent=2)
107
107
 
108
- async def create_session(
109
- self,
110
- server_name: str | None = None,
111
- auto_initialize: bool = True,
112
- ) -> MCPSession:
108
+ async def create_session(self, server_name: str, auto_initialize: bool = True) -> MCPSession:
113
109
  """Create a session for the specified server.
114
110
 
115
111
  Args:
116
112
  server_name: The name of the server to create a session for.
117
- If None, uses the first available server.
118
- auto_initialize: Whether to automatically initialize the session.
119
113
 
120
114
  Returns:
121
115
  The created MCPSession.
@@ -128,10 +122,6 @@ class MCPClient:
128
122
  if not servers:
129
123
  raise ValueError("No MCP servers defined in config")
130
124
 
131
- # If server_name not specified, use the first one
132
- if not server_name:
133
- server_name = next(iter(servers.keys()))
134
-
135
125
  if server_name not in servers:
136
126
  raise ValueError(f"Server '{server_name}' not found in config")
137
127
 
@@ -140,57 +130,80 @@ class MCPClient:
140
130
 
141
131
  # Create the session
142
132
  session = MCPSession(connector)
143
- self.sessions[server_name] = session
144
-
145
- # Make this the active session
146
- self.active_session = server_name
147
-
148
- # Initialize if requested
149
133
  if auto_initialize:
150
134
  await session.initialize()
135
+ self.sessions[server_name] = session
136
+
137
+ # Add to active sessions
138
+ if server_name not in self.active_sessions:
139
+ self.active_sessions.append(server_name)
151
140
 
152
141
  return session
153
142
 
154
- def get_session(self, server_name: str | None = None) -> MCPSession:
143
+ async def create_all_sessions(
144
+ self,
145
+ auto_initialize: bool = True,
146
+ ) -> dict[str, MCPSession]:
147
+ """Create a session for the specified server.
148
+
149
+ Args:
150
+ auto_initialize: Whether to automatically initialize the session.
151
+
152
+ Returns:
153
+ The created MCPSession. If server_name is None, returns the first created session.
154
+
155
+ Raises:
156
+ ValueError: If no servers are configured or the specified server doesn't exist.
157
+ """
158
+ # Get server config
159
+ servers = self.config.get("mcpServers", {})
160
+ if not servers:
161
+ raise ValueError("No MCP servers defined in config")
162
+
163
+ # Create sessions for all servers
164
+ for name in servers:
165
+ session = await self.create_session(name, auto_initialize)
166
+ if auto_initialize:
167
+ await session.initialize()
168
+
169
+ return self.sessions
170
+
171
+ def get_session(self, server_name: str) -> MCPSession:
155
172
  """Get an existing session.
156
173
 
157
174
  Args:
158
175
  server_name: The name of the server to get the session for.
159
- If None, uses the active session.
176
+ If None, uses the first active session.
160
177
 
161
178
  Returns:
162
179
  The MCPSession for the specified server.
163
180
 
164
181
  Raises:
165
- ValueError: If no active session exists or the specified session doesn't exist.
182
+ ValueError: If no active sessions exist or the specified session doesn't exist.
166
183
  """
167
- if server_name is None:
168
- if self.active_session is None:
169
- raise ValueError("No active session")
170
- server_name = self.active_session
171
-
172
184
  if server_name not in self.sessions:
173
185
  raise ValueError(f"No session exists for server '{server_name}'")
174
186
 
175
187
  return self.sessions[server_name]
176
188
 
177
- async def close_session(self, server_name: str | None = None) -> None:
189
+ def get_all_active_sessions(self) -> dict[str, MCPSession]:
190
+ """Get all active sessions.
191
+
192
+ Returns:
193
+ Dictionary mapping server names to their MCPSession instances.
194
+ """
195
+ return {name: self.sessions[name] for name in self.active_sessions if name in self.sessions}
196
+
197
+ async def close_session(self, server_name: str) -> None:
178
198
  """Close a session.
179
199
 
180
200
  Args:
181
201
  server_name: The name of the server to close the session for.
182
- If None, uses the active session.
202
+ If None, uses the first active session.
183
203
 
184
204
  Raises:
185
- ValueError: If no active session exists or the specified session doesn't exist.
205
+ ValueError: If no active sessions exist or the specified session doesn't exist.
186
206
  """
187
- # Determine which server to close
188
- if server_name is None:
189
- if self.active_session is None:
190
- logger.warning("No active session to close")
191
- return
192
- server_name = self.active_session
193
-
194
207
  # Check if the session exists
195
208
  if server_name not in self.sessions:
196
209
  logger.warning(f"No session exists for server '{server_name}', nothing to close")
@@ -209,9 +222,9 @@ class MCPClient:
209
222
  # Remove the session regardless of whether disconnect succeeded
210
223
  del self.sessions[server_name]
211
224
 
212
- # If we closed the active session, set active_session to None
213
- if server_name == self.active_session:
214
- self.active_session = None
225
+ # Remove from active_sessions
226
+ if server_name in self.active_sessions:
227
+ self.active_sessions.remove(server_name)
215
228
 
216
229
  async def close_all_sessions(self) -> None:
217
230
  """Close all active sessions.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mcp-use"
3
- version = "0.0.6"
3
+ version = "1.0.0"
4
4
  description = "MCP Library for LLMs"
5
5
  authors = [
6
6
  {name = "Pietro Zullo", email = "pietro.zullo@gmail.com"}
Binary file
Binary file
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes