mcp-use 1.3.7__py3-none-any.whl → 1.3.9__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.

mcp_use/__init__.py CHANGED
@@ -25,7 +25,6 @@ __all__ = [
25
25
  "StdioConnector",
26
26
  "WebSocketConnector",
27
27
  "HttpConnector",
28
- "create_session_from_config",
29
28
  "load_config_file",
30
29
  "logger",
31
30
  "MCP_USE_DEBUG",
mcp_use/adapters/base.py CHANGED
@@ -91,14 +91,14 @@ class BaseAdapter(ABC):
91
91
 
92
92
  connector_tools = []
93
93
  # Now create tools for each MCP tool
94
- for tool in connector.tools:
94
+ for tool in await connector.list_tools():
95
95
  # Convert the tool and add it to the list if conversion was successful
96
96
  converted_tool = self._convert_tool(tool, connector)
97
97
  if converted_tool:
98
98
  connector_tools.append(converted_tool)
99
99
 
100
100
  # Convert resources to tools so that agents can access resource content directly
101
- resources_list = connector.resources or []
101
+ resources_list = await connector.list_resources() or []
102
102
  if resources_list:
103
103
  for resource in resources_list:
104
104
  converted_resource = self._convert_resource(resource, connector)
@@ -106,7 +106,7 @@ class BaseAdapter(ABC):
106
106
  connector_tools.append(converted_resource)
107
107
 
108
108
  # Convert prompts to tools so that agents can retrieve prompt content
109
- prompts_list = connector.prompts or []
109
+ prompts_list = await connector.list_prompts() or []
110
110
  if prompts_list:
111
111
  for prompt in prompts_list:
112
112
  converted_prompt = self._convert_prompt(prompt, connector)
@@ -21,6 +21,7 @@ from mcp.types import (
21
21
  from pydantic import BaseModel, Field, create_model
22
22
 
23
23
  from ..connectors.base import BaseConnector
24
+ from ..errors.error_formatting import format_error
24
25
  from ..logging import logger
25
26
  from .base import BaseAdapter
26
27
 
@@ -159,11 +160,11 @@ class LangChainAdapter(BaseAdapter):
159
160
  except Exception as e:
160
161
  # Log the exception for debugging
161
162
  logger.error(f"Error parsing tool result: {e}")
162
- return f"Error parsing result: {e!s}; Raw content: {tool_result.content!r}"
163
+ return format_error(e, tool=self.name, tool_content=tool_result.content)
163
164
 
164
165
  except Exception as e:
165
166
  if self.handle_tool_error:
166
- return f"Error executing MCP tool: {str(e)}"
167
+ return format_error(e, tool=self.name) # Format the error to make LLM understand it
167
168
  raise
168
169
 
169
170
  return McpToLangChainAdapter()
@@ -204,7 +205,7 @@ class LangChainAdapter(BaseAdapter):
204
205
  return content_decoded
205
206
  except Exception as e:
206
207
  if self.handle_tool_error:
207
- return f"Error reading resource: {str(e)}"
208
+ return format_error(e, tool=self.name) # Format the error to make LLM understand it
208
209
  raise
209
210
 
210
211
  return ResourceTool()
@@ -261,7 +262,7 @@ class LangChainAdapter(BaseAdapter):
261
262
  return result.messages
262
263
  except Exception as e:
263
264
  if self.handle_tool_error:
264
- return f"Error fetching prompt: {str(e)}"
265
+ return format_error(e, tool=self.name) # Format the error to make LLM understand it
265
266
  raise
266
267
 
267
268
  return PromptTool()
@@ -5,10 +5,10 @@ This module provides ready-to-use agent implementations
5
5
  that are pre-configured for using MCP tools.
6
6
  """
7
7
 
8
- from .base import BaseAgent
9
8
  from .mcpagent import MCPAgent
9
+ from .remote import RemoteAgent
10
10
 
11
11
  __all__ = [
12
- "BaseAgent",
13
12
  "MCPAgent",
13
+ "RemoteAgent",
14
14
  ]
@@ -8,6 +8,7 @@ to provide a simple interface for using MCP tools with different LLMs.
8
8
  import logging
9
9
  import time
10
10
  from collections.abc import AsyncGenerator, AsyncIterator
11
+ from typing import TypeVar
11
12
 
12
13
  from langchain.agents import AgentExecutor, create_tool_calling_agent
13
14
  from langchain.agents.output_parsers.tools import ToolAgentAction
@@ -20,6 +21,7 @@ from langchain_core.exceptions import OutputParserException
20
21
  from langchain_core.runnables.schema import StreamEvent
21
22
  from langchain_core.tools import BaseTool
22
23
  from langchain_core.utils.input import get_color_mapping
24
+ from pydantic import BaseModel
23
25
 
24
26
  from mcp_use.client import MCPClient
25
27
  from mcp_use.connectors.base import BaseConnector
@@ -31,9 +33,13 @@ from ..logging import logger
31
33
  from ..managers.server_manager import ServerManager
32
34
  from .prompts.system_prompt_builder import create_system_message
33
35
  from .prompts.templates import DEFAULT_SYSTEM_PROMPT_TEMPLATE, SERVER_MANAGER_SYSTEM_PROMPT_TEMPLATE
36
+ from .remote import RemoteAgent
34
37
 
35
38
  set_debug(logger.level == logging.DEBUG)
36
39
 
40
+ # Type variable for structured output
41
+ T = TypeVar("T", bound=BaseModel)
42
+
37
43
 
38
44
  class MCPAgent:
39
45
  """Main class for using MCP tools with various LLM providers.
@@ -44,7 +50,7 @@ class MCPAgent:
44
50
 
45
51
  def __init__(
46
52
  self,
47
- llm: BaseLanguageModel,
53
+ llm: BaseLanguageModel | None = None,
48
54
  client: MCPClient | None = None,
49
55
  connectors: list[BaseConnector] | None = None,
50
56
  max_steps: int = 5,
@@ -54,13 +60,17 @@ class MCPAgent:
54
60
  system_prompt_template: str | None = None, # User can still override the template
55
61
  additional_instructions: str | None = None,
56
62
  disallowed_tools: list[str] | None = None,
63
+ tools_used_names: list[str] | None = None,
57
64
  use_server_manager: bool = False,
58
65
  verbose: bool = False,
66
+ agent_id: str | None = None,
67
+ api_key: str | None = None,
68
+ base_url: str = "https://cloud.mcp-use.com",
59
69
  ):
60
70
  """Initialize a new MCPAgent instance.
61
71
 
62
72
  Args:
63
- llm: The LangChain LLM to use.
73
+ llm: The LangChain LLM to use. Not required if agent_id is provided for remote execution.
64
74
  client: The MCPClient to use. If provided, connector is ignored.
65
75
  connectors: A list of MCP connectors to use if client is not provided.
66
76
  max_steps: The maximum number of steps to take.
@@ -71,7 +81,23 @@ class MCPAgent:
71
81
  additional_instructions: Extra instructions to append to the system prompt.
72
82
  disallowed_tools: List of tool names that should not be available to the agent.
73
83
  use_server_manager: Whether to use server manager mode instead of exposing all tools.
84
+ agent_id: Remote agent ID for remote execution. If provided, creates a remote agent.
85
+ api_key: API key for remote execution. If None, checks MCP_USE_API_KEY env var.
86
+ base_url: Base URL for remote API calls.
74
87
  """
88
+ # Handle remote execution
89
+ if agent_id is not None:
90
+ self._remote_agent = RemoteAgent(agent_id=agent_id, api_key=api_key, base_url=base_url)
91
+ self._is_remote = True
92
+ return
93
+
94
+ self._is_remote = False
95
+ self._remote_agent = None
96
+
97
+ # Validate requirements for local execution
98
+ if llm is None:
99
+ raise ValueError("llm is required for local execution. For remote execution, provide agent_id instead.")
100
+
75
101
  self.llm = llm
76
102
  self.client = client
77
103
  self.connectors = connectors or []
@@ -81,6 +107,7 @@ class MCPAgent:
81
107
  self._initialized = False
82
108
  self._conversation_history: list[BaseMessage] = []
83
109
  self.disallowed_tools = disallowed_tools or []
110
+ self.tools_used_names = tools_used_names or []
84
111
  self.use_server_manager = use_server_manager
85
112
  self.verbose = verbose
86
113
  # System prompt configuration
@@ -307,8 +334,8 @@ class MCPAgent:
307
334
 
308
335
  async def _consume_and_return(
309
336
  self,
310
- generator: AsyncGenerator[tuple[AgentAction, str], str],
311
- ) -> str:
337
+ generator: AsyncGenerator[tuple[AgentAction, str] | str | T, None],
338
+ ) -> tuple[str | T, int]:
312
339
  """Consume the generator and return the final result.
313
340
 
314
341
  This method manually iterates through the generator to consume the steps.
@@ -319,20 +346,24 @@ class MCPAgent:
319
346
  generator: The async generator that yields steps and a final result.
320
347
 
321
348
  Returns:
322
- The final result from the generator.
349
+ A tuple of (final_result, steps_taken). final_result can be a string
350
+ for regular output or a Pydantic model instance for structured output.
323
351
  """
324
352
  final_result = ""
325
353
  steps_taken = 0
326
- tools_used_names = []
327
354
  async for item in generator:
328
- # If it's a string, it's the final result
355
+ # If it's a string, it's the final result (regular output)
329
356
  if isinstance(item, str):
330
357
  final_result = item
331
358
  break
359
+ # If it's not a tuple, it might be structured output (Pydantic model)
360
+ elif not isinstance(item, tuple):
361
+ final_result = item
362
+ break
332
363
  # Otherwise it's a step tuple, just consume it
333
- steps_taken += 1
334
- tools_used_names.append(item[0].tool)
335
- return final_result, steps_taken, tools_used_names
364
+ else:
365
+ steps_taken += 1
366
+ return final_result, steps_taken
336
367
 
337
368
  async def stream(
338
369
  self,
@@ -341,7 +372,8 @@ class MCPAgent:
341
372
  manage_connector: bool = True,
342
373
  external_history: list[BaseMessage] | None = None,
343
374
  track_execution: bool = True,
344
- ) -> AsyncGenerator[tuple[AgentAction, str] | str, None]:
375
+ output_schema: type[T] | None = None,
376
+ ) -> AsyncGenerator[tuple[AgentAction, str] | str | T, None]:
345
377
  """Run the agent and yield intermediate steps as an async generator.
346
378
 
347
379
  Args:
@@ -350,17 +382,48 @@ class MCPAgent:
350
382
  manage_connector: Whether to handle the connector lifecycle internally.
351
383
  external_history: Optional external history to use instead of the
352
384
  internal conversation history.
385
+ track_execution: Whether to track execution for telemetry.
386
+ output_schema: Optional Pydantic BaseModel class for structured output.
387
+ If provided, the agent will attempt structured output at finish points
388
+ and continue execution if required information is missing.
353
389
 
354
390
  Yields:
355
- Intermediate steps as (AgentAction, str) tuples, followed by the final result as a string.
391
+ Intermediate steps as (AgentAction, str) tuples, followed by the final result.
392
+ If output_schema is provided, yields structured output as instance of the schema.
356
393
  """
394
+ # Delegate to remote agent if in remote mode
395
+ if self._is_remote and self._remote_agent:
396
+ async for item in self._remote_agent.stream(
397
+ query, max_steps, manage_connector, external_history, track_execution, output_schema
398
+ ):
399
+ yield item
400
+ return
401
+
357
402
  result = ""
358
403
  initialized_here = False
359
404
  start_time = time.time()
360
- tools_used_names = []
361
405
  steps_taken = 0
362
406
  success = False
363
407
 
408
+ # Schema-aware setup for structured output
409
+ structured_llm = None
410
+ schema_description = ""
411
+ if output_schema:
412
+ query = self._enhance_query_with_schema(query, output_schema)
413
+ structured_llm = self.llm.with_structured_output(output_schema)
414
+ # Get schema description for feedback
415
+ schema_fields = []
416
+ try:
417
+ for field_name, field_info in output_schema.model_fields.items():
418
+ description = getattr(field_info, "description", "") or field_name
419
+ required = not hasattr(field_info, "default") or field_info.default is None
420
+ schema_fields.append(f"- {field_name}: {description} {'(required)' if required else '(optional)'}")
421
+
422
+ schema_description = "\n".join(schema_fields)
423
+ except Exception as e:
424
+ logger.warning(f"Could not extract schema details: {e}")
425
+ schema_description = f"Schema: {output_schema.__name__}"
426
+
364
427
  try:
365
428
  # Initialize if needed
366
429
  if manage_connector and not self._initialized:
@@ -449,7 +512,49 @@ class MCPAgent:
449
512
  if isinstance(next_step_output, AgentFinish):
450
513
  logger.info(f"✅ Agent finished at step {step_num + 1}")
451
514
  result = next_step_output.return_values.get("output", "No output generated")
452
- break
515
+
516
+ # If structured output is requested, attempt to create it
517
+ if output_schema and structured_llm:
518
+ try:
519
+ logger.info("🔧 Attempting structured output...")
520
+ structured_result = await self._attempt_structured_output(
521
+ result, structured_llm, output_schema, schema_description
522
+ )
523
+
524
+ # Add the final response to conversation history if memory is enabled
525
+ if self.memory_enabled:
526
+ self.add_to_history(AIMessage(content=f"Structured result: {structured_result}"))
527
+
528
+ logger.info("✅ Structured output successful")
529
+ success = True
530
+ yield structured_result
531
+ return
532
+
533
+ except Exception as e:
534
+ logger.warning(f"⚠️ Structured output failed: {e}")
535
+ # Continue execution to gather missing information
536
+ missing_info_prompt = f"""
537
+ The current result cannot be formatted into the required structure.
538
+ Error: {str(e)}
539
+
540
+ Current information: {result}
541
+
542
+ Please continue working to gather the missing information needed for:
543
+ {schema_description}
544
+
545
+ Focus on finding the specific missing details.
546
+ """
547
+
548
+ # Add this as feedback and continue the loop
549
+ inputs["input"] = missing_info_prompt
550
+ if self.memory_enabled:
551
+ self.add_to_history(HumanMessage(content=missing_info_prompt))
552
+
553
+ logger.info("🔄 Continuing execution to gather missing information...")
554
+ continue
555
+ else:
556
+ # Regular execution without structured output
557
+ break
453
558
 
454
559
  # If it's actions/steps, add to intermediate steps and yield them
455
560
  intermediate_steps.extend(next_step_output)
@@ -459,7 +564,7 @@ class MCPAgent:
459
564
  yield agent_step
460
565
  action, observation = agent_step
461
566
  tool_name = action.tool
462
- tools_used_names.append(tool_name)
567
+ self.tools_used_names.append(tool_name)
463
568
  tool_input_str = str(action.tool_input)
464
569
  # Truncate long inputs for readability
465
570
  if len(tool_input_str) > 100:
@@ -498,15 +603,37 @@ class MCPAgent:
498
603
  logger.warning(f"⚠️ Agent stopped after reaching max iterations ({steps})")
499
604
  result = f"Agent stopped after reaching the maximum number of steps ({steps})."
500
605
 
501
- # Add the final response to conversation history if memory is enabled
502
- if self.memory_enabled:
606
+ # If structured output was requested but not achieved, attempt one final time
607
+ if output_schema and structured_llm and not success:
608
+ try:
609
+ logger.info("🔧 Final attempt at structured output...")
610
+ structured_result = await self._attempt_structured_output(
611
+ result, structured_llm, output_schema, schema_description
612
+ )
613
+
614
+ # Add the final response to conversation history if memory is enabled
615
+ if self.memory_enabled:
616
+ self.add_to_history(AIMessage(content=f"Structured result: {structured_result}"))
617
+
618
+ logger.info("✅ Final structured output successful")
619
+ success = True
620
+ yield structured_result
621
+ return
622
+
623
+ except Exception as e:
624
+ logger.error(f"❌ Final structured output attempt failed: {e}")
625
+ raise RuntimeError(f"Failed to generate structured output after {steps} steps: {str(e)}") from e
626
+
627
+ if self.memory_enabled and not output_schema:
503
628
  self.add_to_history(AIMessage(content=result))
504
629
 
505
630
  logger.info(f"🎉 Agent execution complete in {time.time() - start_time} seconds")
506
- success = True
631
+ if not success:
632
+ success = True
507
633
 
508
- # Yield the final result as a string
509
- yield result
634
+ # Yield the final result (only for non-structured output)
635
+ if not output_schema:
636
+ yield result
510
637
 
511
638
  except Exception as e:
512
639
  logger.error(f"❌ Error running query: {e}")
@@ -548,8 +675,8 @@ class MCPAgent:
548
675
  manage_connector=manage_connector,
549
676
  external_history_used=external_history is not None,
550
677
  steps_taken=steps_taken,
551
- tools_used_count=len(tools_used_names),
552
- tools_used_names=tools_used_names,
678
+ tools_used_count=len(self.tools_used_names),
679
+ tools_used_names=self.tools_used_names,
553
680
  response=result,
554
681
  execution_time_ms=execution_time_ms,
555
682
  error_type=None if success else "execution_error",
@@ -567,11 +694,13 @@ class MCPAgent:
567
694
  max_steps: int | None = None,
568
695
  manage_connector: bool = True,
569
696
  external_history: list[BaseMessage] | None = None,
570
- ) -> str:
697
+ output_schema: type[T] | None = None,
698
+ ) -> str | T:
571
699
  """Run a query using the MCP tools and return the final result.
572
700
 
573
701
  This method uses the streaming implementation internally and returns
574
- the final result after consuming all intermediate steps.
702
+ the final result after consuming all intermediate steps. If output_schema
703
+ is provided, the agent will be schema-aware and return structured output.
575
704
 
576
705
  Args:
577
706
  query: The query to run.
@@ -582,19 +711,47 @@ class MCPAgent:
582
711
  for managing the connector lifecycle.
583
712
  external_history: Optional external history to use instead of the
584
713
  internal conversation history.
714
+ output_schema: Optional Pydantic BaseModel class for structured output.
715
+ If provided, the agent will attempt to return an instance of this model.
585
716
 
586
717
  Returns:
587
- The result of running the query.
718
+ The result of running the query as a string, or if output_schema is provided,
719
+ an instance of the specified Pydantic model.
720
+
721
+ Example:
722
+ ```python
723
+ # Regular usage
724
+ result = await agent.run("What's the weather like?")
725
+
726
+ # Structured output usage
727
+ from pydantic import BaseModel, Field
728
+
729
+ class WeatherInfo(BaseModel):
730
+ temperature: float = Field(description="Temperature in Celsius")
731
+ condition: str = Field(description="Weather condition")
732
+
733
+ weather: WeatherInfo = await agent.run(
734
+ "What's the weather like?",
735
+ output_schema=WeatherInfo
736
+ )
737
+ ```
588
738
  """
739
+ # Delegate to remote agent if in remote mode
740
+ if self._is_remote and self._remote_agent:
741
+ return await self._remote_agent.run(query, max_steps, manage_connector, external_history, output_schema)
742
+
589
743
  success = True
590
744
  start_time = time.time()
591
- generator = self.stream(query, max_steps, manage_connector, external_history, track_execution=False)
745
+
746
+ generator = self.stream(
747
+ query, max_steps, manage_connector, external_history, track_execution=False, output_schema=output_schema
748
+ )
592
749
  error = None
593
750
  steps_taken = 0
594
- tools_used_names = []
595
751
  result = None
596
752
  try:
597
- result, steps_taken, tools_used_names = await self._consume_and_return(generator)
753
+ result, steps_taken = await self._consume_and_return(generator)
754
+
598
755
  except Exception as e:
599
756
  success = False
600
757
  error = str(e)
@@ -618,15 +775,79 @@ class MCPAgent:
618
775
  manage_connector=manage_connector,
619
776
  external_history_used=external_history is not None,
620
777
  steps_taken=steps_taken,
621
- tools_used_count=len(tools_used_names),
622
- tools_used_names=tools_used_names,
623
- response=result,
778
+ tools_used_count=len(self.tools_used_names),
779
+ tools_used_names=self.tools_used_names,
780
+ response=str(result),
624
781
  execution_time_ms=int((time.time() - start_time) * 1000),
625
782
  error_type=error,
626
783
  conversation_history_length=len(self._conversation_history),
627
784
  )
628
785
  return result
629
786
 
787
+ async def _attempt_structured_output(
788
+ self, raw_result: str, structured_llm, output_schema: type[T], schema_description: str
789
+ ) -> T:
790
+ """Attempt to create structured output from raw result with validation."""
791
+ format_prompt = f"""
792
+ Please format the following information according to the specified schema.
793
+ Extract and structure the relevant information from the content below.
794
+
795
+ Required schema fields:
796
+ {schema_description}
797
+
798
+ Content to format:
799
+ {raw_result}
800
+
801
+ Please provide the information in the requested structured format.
802
+ If any required information is missing, you must indicate this clearly.
803
+ """
804
+
805
+ structured_result = await structured_llm.ainvoke(format_prompt)
806
+
807
+ try:
808
+ for field_name, field_info in output_schema.model_fields.items():
809
+ required = not hasattr(field_info, "default") or field_info.default is None
810
+ if required:
811
+ value = getattr(structured_result, field_name, None)
812
+ if value is None or (isinstance(value, str) and not value.strip()):
813
+ raise ValueError(f"Required field '{field_name}' is missing or empty")
814
+ if isinstance(value, list) and len(value) == 0:
815
+ raise ValueError(f"Required field '{field_name}' is an empty list")
816
+ except Exception as e:
817
+ logger.debug(f"Validation details: {e}")
818
+ raise # Re-raise to trigger retry logic
819
+
820
+ return structured_result
821
+
822
+ def _enhance_query_with_schema(self, query: str, output_schema: type[T]) -> str:
823
+ """Enhance the query with schema information to make the agent aware of required fields."""
824
+ schema_fields = []
825
+
826
+ try:
827
+ for field_name, field_info in output_schema.model_fields.items():
828
+ description = getattr(field_info, "description", "") or field_name
829
+ required = not hasattr(field_info, "default") or field_info.default is None
830
+ schema_fields.append(f"- {field_name}: {description} {'(required)' if required else '(optional)'}")
831
+
832
+ schema_description = "\n".join(schema_fields)
833
+ except Exception as e:
834
+ logger.warning(f"Could not extract schema details: {e}")
835
+ schema_description = f"Schema: {output_schema.__name__}"
836
+
837
+ # Enhance the query with schema awareness
838
+ enhanced_query = f"""
839
+ {query}
840
+
841
+ IMPORTANT: Your response must include sufficient information to populate the following structured output:
842
+
843
+ {schema_description}
844
+
845
+ Make sure you gather ALL the required information during your task execution.
846
+ If any required information is missing, continue working to find it.
847
+ """
848
+
849
+ return enhanced_query
850
+
630
851
  async def _generate_response_chunks_async(
631
852
  self,
632
853
  query: str,
@@ -749,6 +970,11 @@ class MCPAgent:
749
970
 
750
971
  async def close(self) -> None:
751
972
  """Close the MCP connection with improved error handling."""
973
+ # Delegate to remote agent if in remote mode
974
+ if self._is_remote and self._remote_agent:
975
+ await self._remote_agent.close()
976
+ return
977
+
752
978
  logger.info("🔌 Closing agent and cleaning up resources...")
753
979
  try:
754
980
  # Clean up the agent first
@@ -17,27 +17,25 @@ Thought: I now know the final answer
17
17
  Final Answer: the final answer to the original input question"""
18
18
 
19
19
 
20
- SERVER_MANAGER_SYSTEM_PROMPT_TEMPLATE = """You are a helpful assistant designed to interact with MCP
21
- (Model Context Protocol) servers. You can manage connections to different servers and use the tools
22
- provided by the currently active server.
23
-
24
- Important: The available tools change depending on which server is active.
25
- If a request requires tools not listed below (e.g., file operations, web browsing,
26
- image manipulation), you MUST first connect to the appropriate server using
27
- 'connect_to_mcp_server'.
28
- Use 'list_mcp_servers' to find the relevant server if you are unsure.
29
- Only after successfully connecting and seeing the new tools listed in
30
- the response should you attempt to use those server-specific tools.
31
- Before attempting a task that requires specific tools, you should
32
- ensure you are connected to the correct server and aware of its
33
- available tools. If unsure, use 'list_mcp_servers' to see options
34
- or 'get_active_mcp_server' to check the current connection.
35
-
36
- When you connect to a server using 'connect_to_mcp_server',
37
- you will be informed about the new tools that become available.
38
- You can then use these server-specific tools in subsequent steps.
39
-
40
- Here are the tools *currently* available to you (this list includes server management tools and will
41
- change when you connect to a server):
20
+ SERVER_MANAGER_SYSTEM_PROMPT_TEMPLATE = """You are a helpful assistant designed
21
+ to interact with MCP (Model Context Protocol) servers. You can manage connections
22
+ to different servers and use the tools provided by the currently active server.
23
+
24
+ Important: The available tools change dynamically based on which server is active.
25
+
26
+ - When you connect to a server using 'connect_to_mcp_server', that server's tools are automatically added to
27
+ your available tools with their full schemas
28
+ - When you disconnect using 'disconnect_from_mcp_server', the server's tools are removed from your available tools
29
+ - The tool list below will automatically update when you connect/disconnect from servers
30
+
31
+ If a request requires tools not currently listed below (e.g., file operations, web browsing, image manipulation),
32
+ you MUST first connect to the appropriate server using 'connect_to_mcp_server'. Use 'list_mcp_servers' to find
33
+ available servers if you are unsure which one to connect to.
34
+
35
+ After connecting to a server, you can immediately use its tools - they will be directly available to you with their
36
+ proper schemas and validation. No additional steps are needed.
37
+
38
+ Here are the tools currently available to you (this list dynamically updates when
39
+ connecting/disconnecting from servers):
42
40
  {tool_descriptions}
43
41
  """