fast-agent-mcp 0.2.58__py3-none-any.whl → 0.3.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 fast-agent-mcp might be problematic. Click here for more details.

Files changed (233) hide show
  1. fast_agent/__init__.py +127 -0
  2. fast_agent/agents/__init__.py +36 -0
  3. {mcp_agent/core → fast_agent/agents}/agent_types.py +2 -1
  4. fast_agent/agents/llm_agent.py +217 -0
  5. fast_agent/agents/llm_decorator.py +486 -0
  6. mcp_agent/agents/base_agent.py → fast_agent/agents/mcp_agent.py +377 -385
  7. fast_agent/agents/tool_agent.py +168 -0
  8. {mcp_agent → fast_agent}/agents/workflow/chain_agent.py +43 -33
  9. {mcp_agent → fast_agent}/agents/workflow/evaluator_optimizer.py +31 -35
  10. {mcp_agent → fast_agent}/agents/workflow/iterative_planner.py +56 -47
  11. {mcp_agent → fast_agent}/agents/workflow/orchestrator_models.py +4 -4
  12. {mcp_agent → fast_agent}/agents/workflow/parallel_agent.py +34 -41
  13. {mcp_agent → fast_agent}/agents/workflow/router_agent.py +54 -39
  14. {mcp_agent → fast_agent}/cli/__main__.py +5 -3
  15. {mcp_agent → fast_agent}/cli/commands/check_config.py +95 -66
  16. {mcp_agent → fast_agent}/cli/commands/go.py +20 -11
  17. {mcp_agent → fast_agent}/cli/commands/quickstart.py +4 -4
  18. {mcp_agent → fast_agent}/cli/commands/server_helpers.py +1 -1
  19. {mcp_agent → fast_agent}/cli/commands/setup.py +64 -134
  20. {mcp_agent → fast_agent}/cli/commands/url_parser.py +9 -8
  21. {mcp_agent → fast_agent}/cli/main.py +36 -16
  22. {mcp_agent → fast_agent}/cli/terminal.py +2 -2
  23. {mcp_agent → fast_agent}/config.py +10 -2
  24. fast_agent/constants.py +8 -0
  25. {mcp_agent → fast_agent}/context.py +24 -19
  26. {mcp_agent → fast_agent}/context_dependent.py +9 -5
  27. fast_agent/core/__init__.py +17 -0
  28. {mcp_agent → fast_agent}/core/agent_app.py +39 -36
  29. fast_agent/core/core_app.py +135 -0
  30. {mcp_agent → fast_agent}/core/direct_decorators.py +12 -26
  31. {mcp_agent → fast_agent}/core/direct_factory.py +95 -73
  32. {mcp_agent → fast_agent/core}/executor/executor.py +4 -5
  33. {mcp_agent → fast_agent}/core/fastagent.py +32 -32
  34. fast_agent/core/logging/__init__.py +5 -0
  35. {mcp_agent → fast_agent/core}/logging/events.py +3 -3
  36. {mcp_agent → fast_agent/core}/logging/json_serializer.py +1 -1
  37. {mcp_agent → fast_agent/core}/logging/listeners.py +85 -7
  38. {mcp_agent → fast_agent/core}/logging/logger.py +7 -7
  39. {mcp_agent → fast_agent/core}/logging/transport.py +10 -11
  40. fast_agent/core/prompt.py +9 -0
  41. {mcp_agent → fast_agent}/core/validation.py +4 -4
  42. fast_agent/event_progress.py +61 -0
  43. fast_agent/history/history_exporter.py +44 -0
  44. {mcp_agent → fast_agent}/human_input/__init__.py +9 -12
  45. {mcp_agent → fast_agent}/human_input/elicitation_handler.py +26 -8
  46. {mcp_agent → fast_agent}/human_input/elicitation_state.py +7 -7
  47. {mcp_agent → fast_agent}/human_input/simple_form.py +6 -4
  48. {mcp_agent → fast_agent}/human_input/types.py +1 -18
  49. fast_agent/interfaces.py +228 -0
  50. fast_agent/llm/__init__.py +9 -0
  51. mcp_agent/llm/augmented_llm.py → fast_agent/llm/fastagent_llm.py +127 -218
  52. fast_agent/llm/internal/passthrough.py +137 -0
  53. mcp_agent/llm/augmented_llm_playback.py → fast_agent/llm/internal/playback.py +29 -25
  54. mcp_agent/llm/augmented_llm_silent.py → fast_agent/llm/internal/silent.py +10 -17
  55. fast_agent/llm/internal/slow.py +38 -0
  56. {mcp_agent → fast_agent}/llm/memory.py +40 -30
  57. {mcp_agent → fast_agent}/llm/model_database.py +35 -2
  58. {mcp_agent → fast_agent}/llm/model_factory.py +103 -77
  59. fast_agent/llm/model_info.py +126 -0
  60. {mcp_agent/llm/providers → fast_agent/llm/provider/anthropic}/anthropic_utils.py +7 -7
  61. fast_agent/llm/provider/anthropic/llm_anthropic.py +603 -0
  62. {mcp_agent/llm/providers → fast_agent/llm/provider/anthropic}/multipart_converter_anthropic.py +79 -86
  63. {mcp_agent/llm/providers → fast_agent/llm/provider/bedrock}/bedrock_utils.py +3 -1
  64. mcp_agent/llm/providers/augmented_llm_bedrock.py → fast_agent/llm/provider/bedrock/llm_bedrock.py +833 -717
  65. {mcp_agent/llm/providers → fast_agent/llm/provider/google}/google_converter.py +66 -14
  66. fast_agent/llm/provider/google/llm_google_native.py +431 -0
  67. mcp_agent/llm/providers/augmented_llm_aliyun.py → fast_agent/llm/provider/openai/llm_aliyun.py +6 -7
  68. mcp_agent/llm/providers/augmented_llm_azure.py → fast_agent/llm/provider/openai/llm_azure.py +4 -4
  69. mcp_agent/llm/providers/augmented_llm_deepseek.py → fast_agent/llm/provider/openai/llm_deepseek.py +10 -11
  70. mcp_agent/llm/providers/augmented_llm_generic.py → fast_agent/llm/provider/openai/llm_generic.py +4 -4
  71. mcp_agent/llm/providers/augmented_llm_google_oai.py → fast_agent/llm/provider/openai/llm_google_oai.py +4 -4
  72. mcp_agent/llm/providers/augmented_llm_groq.py → fast_agent/llm/provider/openai/llm_groq.py +14 -16
  73. mcp_agent/llm/providers/augmented_llm_openai.py → fast_agent/llm/provider/openai/llm_openai.py +133 -207
  74. mcp_agent/llm/providers/augmented_llm_openrouter.py → fast_agent/llm/provider/openai/llm_openrouter.py +6 -6
  75. mcp_agent/llm/providers/augmented_llm_tensorzero_openai.py → fast_agent/llm/provider/openai/llm_tensorzero_openai.py +17 -16
  76. mcp_agent/llm/providers/augmented_llm_xai.py → fast_agent/llm/provider/openai/llm_xai.py +6 -6
  77. {mcp_agent/llm/providers → fast_agent/llm/provider/openai}/multipart_converter_openai.py +125 -63
  78. {mcp_agent/llm/providers → fast_agent/llm/provider/openai}/openai_multipart.py +12 -12
  79. {mcp_agent/llm/providers → fast_agent/llm/provider/openai}/openai_utils.py +18 -16
  80. {mcp_agent → fast_agent}/llm/provider_key_manager.py +2 -2
  81. {mcp_agent → fast_agent}/llm/provider_types.py +2 -0
  82. {mcp_agent → fast_agent}/llm/sampling_converter.py +15 -12
  83. {mcp_agent → fast_agent}/llm/usage_tracking.py +23 -5
  84. fast_agent/mcp/__init__.py +43 -0
  85. {mcp_agent → fast_agent}/mcp/elicitation_factory.py +3 -3
  86. {mcp_agent → fast_agent}/mcp/elicitation_handlers.py +19 -10
  87. {mcp_agent → fast_agent}/mcp/gen_client.py +3 -3
  88. fast_agent/mcp/helpers/__init__.py +36 -0
  89. fast_agent/mcp/helpers/content_helpers.py +183 -0
  90. {mcp_agent → fast_agent}/mcp/helpers/server_config_helpers.py +8 -8
  91. {mcp_agent → fast_agent}/mcp/hf_auth.py +25 -23
  92. fast_agent/mcp/interfaces.py +93 -0
  93. {mcp_agent → fast_agent}/mcp/logger_textio.py +4 -4
  94. {mcp_agent → fast_agent}/mcp/mcp_agent_client_session.py +49 -44
  95. {mcp_agent → fast_agent}/mcp/mcp_aggregator.py +66 -115
  96. {mcp_agent → fast_agent}/mcp/mcp_connection_manager.py +16 -23
  97. {mcp_agent/core → fast_agent/mcp}/mcp_content.py +23 -15
  98. {mcp_agent → fast_agent}/mcp/mime_utils.py +39 -0
  99. fast_agent/mcp/prompt.py +159 -0
  100. mcp_agent/mcp/prompt_message_multipart.py → fast_agent/mcp/prompt_message_extended.py +27 -20
  101. {mcp_agent → fast_agent}/mcp/prompt_render.py +21 -19
  102. {mcp_agent → fast_agent}/mcp/prompt_serialization.py +46 -46
  103. fast_agent/mcp/prompts/__main__.py +7 -0
  104. {mcp_agent → fast_agent}/mcp/prompts/prompt_helpers.py +31 -30
  105. {mcp_agent → fast_agent}/mcp/prompts/prompt_load.py +8 -8
  106. {mcp_agent → fast_agent}/mcp/prompts/prompt_server.py +11 -19
  107. {mcp_agent → fast_agent}/mcp/prompts/prompt_template.py +18 -18
  108. {mcp_agent → fast_agent}/mcp/resource_utils.py +1 -1
  109. {mcp_agent → fast_agent}/mcp/sampling.py +31 -26
  110. {mcp_agent/mcp_server → fast_agent/mcp/server}/__init__.py +1 -1
  111. {mcp_agent/mcp_server → fast_agent/mcp/server}/agent_server.py +5 -6
  112. fast_agent/mcp/ui_agent.py +48 -0
  113. fast_agent/mcp/ui_mixin.py +209 -0
  114. fast_agent/mcp_server_registry.py +90 -0
  115. {mcp_agent → fast_agent}/resources/examples/data-analysis/analysis-campaign.py +5 -4
  116. {mcp_agent → fast_agent}/resources/examples/data-analysis/analysis.py +1 -1
  117. {mcp_agent → fast_agent}/resources/examples/mcp/elicitations/forms_demo.py +3 -3
  118. {mcp_agent → fast_agent}/resources/examples/mcp/elicitations/game_character.py +2 -2
  119. {mcp_agent → fast_agent}/resources/examples/mcp/elicitations/game_character_handler.py +1 -1
  120. {mcp_agent → fast_agent}/resources/examples/mcp/elicitations/tool_call.py +1 -1
  121. {mcp_agent → fast_agent}/resources/examples/mcp/state-transfer/agent_one.py +1 -1
  122. {mcp_agent → fast_agent}/resources/examples/mcp/state-transfer/agent_two.py +1 -1
  123. {mcp_agent → fast_agent}/resources/examples/researcher/researcher-eval.py +1 -1
  124. {mcp_agent → fast_agent}/resources/examples/researcher/researcher-imp.py +1 -1
  125. {mcp_agent → fast_agent}/resources/examples/researcher/researcher.py +1 -1
  126. {mcp_agent → fast_agent}/resources/examples/tensorzero/agent.py +2 -2
  127. {mcp_agent → fast_agent}/resources/examples/tensorzero/image_demo.py +3 -3
  128. {mcp_agent → fast_agent}/resources/examples/tensorzero/simple_agent.py +1 -1
  129. {mcp_agent → fast_agent}/resources/examples/workflows/chaining.py +1 -1
  130. {mcp_agent → fast_agent}/resources/examples/workflows/evaluator.py +3 -3
  131. {mcp_agent → fast_agent}/resources/examples/workflows/human_input.py +5 -3
  132. {mcp_agent → fast_agent}/resources/examples/workflows/orchestrator.py +1 -1
  133. {mcp_agent → fast_agent}/resources/examples/workflows/parallel.py +2 -2
  134. {mcp_agent → fast_agent}/resources/examples/workflows/router.py +5 -2
  135. fast_agent/resources/setup/.gitignore +24 -0
  136. fast_agent/resources/setup/agent.py +18 -0
  137. fast_agent/resources/setup/fastagent.config.yaml +44 -0
  138. fast_agent/resources/setup/fastagent.secrets.yaml.example +38 -0
  139. fast_agent/tools/elicitation.py +369 -0
  140. fast_agent/types/__init__.py +32 -0
  141. fast_agent/types/llm_stop_reason.py +77 -0
  142. fast_agent/ui/__init__.py +38 -0
  143. fast_agent/ui/console_display.py +1005 -0
  144. {mcp_agent/human_input → fast_agent/ui}/elicitation_form.py +17 -12
  145. mcp_agent/human_input/elicitation_forms.py → fast_agent/ui/elicitation_style.py +1 -1
  146. {mcp_agent/core → fast_agent/ui}/enhanced_prompt.py +96 -25
  147. {mcp_agent/core → fast_agent/ui}/interactive_prompt.py +330 -125
  148. fast_agent/ui/mcp_ui_utils.py +224 -0
  149. {mcp_agent → fast_agent/ui}/progress_display.py +2 -2
  150. {mcp_agent/logging → fast_agent/ui}/rich_progress.py +4 -4
  151. {mcp_agent/core → fast_agent/ui}/usage_display.py +3 -8
  152. {fast_agent_mcp-0.2.58.dist-info → fast_agent_mcp-0.3.0.dist-info}/METADATA +7 -7
  153. fast_agent_mcp-0.3.0.dist-info/RECORD +202 -0
  154. fast_agent_mcp-0.3.0.dist-info/entry_points.txt +5 -0
  155. fast_agent_mcp-0.2.58.dist-info/RECORD +0 -193
  156. fast_agent_mcp-0.2.58.dist-info/entry_points.txt +0 -6
  157. mcp_agent/__init__.py +0 -114
  158. mcp_agent/agents/agent.py +0 -92
  159. mcp_agent/agents/workflow/__init__.py +0 -1
  160. mcp_agent/agents/workflow/orchestrator_agent.py +0 -597
  161. mcp_agent/app.py +0 -175
  162. mcp_agent/core/__init__.py +0 -26
  163. mcp_agent/core/prompt.py +0 -191
  164. mcp_agent/event_progress.py +0 -134
  165. mcp_agent/human_input/handler.py +0 -81
  166. mcp_agent/llm/__init__.py +0 -2
  167. mcp_agent/llm/augmented_llm_passthrough.py +0 -232
  168. mcp_agent/llm/augmented_llm_slow.py +0 -53
  169. mcp_agent/llm/providers/__init__.py +0 -8
  170. mcp_agent/llm/providers/augmented_llm_anthropic.py +0 -718
  171. mcp_agent/llm/providers/augmented_llm_google_native.py +0 -496
  172. mcp_agent/llm/providers/sampling_converter_anthropic.py +0 -57
  173. mcp_agent/llm/providers/sampling_converter_openai.py +0 -26
  174. mcp_agent/llm/sampling_format_converter.py +0 -37
  175. mcp_agent/logging/__init__.py +0 -0
  176. mcp_agent/mcp/__init__.py +0 -50
  177. mcp_agent/mcp/helpers/__init__.py +0 -25
  178. mcp_agent/mcp/helpers/content_helpers.py +0 -187
  179. mcp_agent/mcp/interfaces.py +0 -266
  180. mcp_agent/mcp/prompts/__init__.py +0 -0
  181. mcp_agent/mcp/prompts/__main__.py +0 -10
  182. mcp_agent/mcp_server_registry.py +0 -343
  183. mcp_agent/tools/tool_definition.py +0 -14
  184. mcp_agent/ui/console_display.py +0 -790
  185. mcp_agent/ui/console_display_legacy.py +0 -401
  186. {mcp_agent → fast_agent}/agents/workflow/orchestrator_prompts.py +0 -0
  187. {mcp_agent/agents → fast_agent/cli}/__init__.py +0 -0
  188. {mcp_agent → fast_agent}/cli/constants.py +0 -0
  189. {mcp_agent → fast_agent}/core/error_handling.py +0 -0
  190. {mcp_agent → fast_agent}/core/exceptions.py +0 -0
  191. {mcp_agent/cli → fast_agent/core/executor}/__init__.py +0 -0
  192. {mcp_agent → fast_agent/core}/executor/task_registry.py +0 -0
  193. {mcp_agent → fast_agent/core}/executor/workflow_signal.py +0 -0
  194. {mcp_agent → fast_agent}/human_input/form_fields.py +0 -0
  195. {mcp_agent → fast_agent}/llm/prompt_utils.py +0 -0
  196. {mcp_agent/core → fast_agent/llm}/request_params.py +0 -0
  197. {mcp_agent → fast_agent}/mcp/common.py +0 -0
  198. {mcp_agent/executor → fast_agent/mcp/prompts}/__init__.py +0 -0
  199. {mcp_agent → fast_agent}/mcp/prompts/prompt_constants.py +0 -0
  200. {mcp_agent → fast_agent}/py.typed +0 -0
  201. {mcp_agent → fast_agent}/resources/examples/data-analysis/fastagent.config.yaml +0 -0
  202. {mcp_agent → fast_agent}/resources/examples/data-analysis/mount-point/WA_Fn-UseC_-HR-Employee-Attrition.csv +0 -0
  203. {mcp_agent → fast_agent}/resources/examples/mcp/elicitations/elicitation_account_server.py +0 -0
  204. {mcp_agent → fast_agent}/resources/examples/mcp/elicitations/elicitation_forms_server.py +0 -0
  205. {mcp_agent → fast_agent}/resources/examples/mcp/elicitations/elicitation_game_server.py +0 -0
  206. {mcp_agent → fast_agent}/resources/examples/mcp/elicitations/fastagent.config.yaml +0 -0
  207. {mcp_agent → fast_agent}/resources/examples/mcp/elicitations/fastagent.secrets.yaml.example +0 -0
  208. {mcp_agent → fast_agent}/resources/examples/mcp/state-transfer/fastagent.config.yaml +0 -0
  209. {mcp_agent → fast_agent}/resources/examples/mcp/state-transfer/fastagent.secrets.yaml.example +0 -0
  210. {mcp_agent → fast_agent}/resources/examples/researcher/fastagent.config.yaml +0 -0
  211. {mcp_agent → fast_agent}/resources/examples/tensorzero/.env.sample +0 -0
  212. {mcp_agent → fast_agent}/resources/examples/tensorzero/Makefile +0 -0
  213. {mcp_agent → fast_agent}/resources/examples/tensorzero/README.md +0 -0
  214. {mcp_agent → fast_agent}/resources/examples/tensorzero/demo_images/clam.jpg +0 -0
  215. {mcp_agent → fast_agent}/resources/examples/tensorzero/demo_images/crab.png +0 -0
  216. {mcp_agent → fast_agent}/resources/examples/tensorzero/demo_images/shrimp.png +0 -0
  217. {mcp_agent → fast_agent}/resources/examples/tensorzero/docker-compose.yml +0 -0
  218. {mcp_agent → fast_agent}/resources/examples/tensorzero/fastagent.config.yaml +0 -0
  219. {mcp_agent → fast_agent}/resources/examples/tensorzero/mcp_server/Dockerfile +0 -0
  220. {mcp_agent → fast_agent}/resources/examples/tensorzero/mcp_server/entrypoint.sh +0 -0
  221. {mcp_agent → fast_agent}/resources/examples/tensorzero/mcp_server/mcp_server.py +0 -0
  222. {mcp_agent → fast_agent}/resources/examples/tensorzero/mcp_server/pyproject.toml +0 -0
  223. {mcp_agent → fast_agent}/resources/examples/tensorzero/tensorzero_config/system_schema.json +0 -0
  224. {mcp_agent → fast_agent}/resources/examples/tensorzero/tensorzero_config/system_template.minijinja +0 -0
  225. {mcp_agent → fast_agent}/resources/examples/tensorzero/tensorzero_config/tensorzero.toml +0 -0
  226. {mcp_agent → fast_agent}/resources/examples/workflows/fastagent.config.yaml +0 -0
  227. {mcp_agent → fast_agent}/resources/examples/workflows/graded_report.md +0 -0
  228. {mcp_agent → fast_agent}/resources/examples/workflows/short_story.md +0 -0
  229. {mcp_agent → fast_agent}/resources/examples/workflows/short_story.txt +0 -0
  230. {mcp_agent → fast_agent/ui}/console.py +0 -0
  231. {mcp_agent/core → fast_agent/ui}/mermaid_utils.py +0 -0
  232. {fast_agent_mcp-0.2.58.dist-info → fast_agent_mcp-0.3.0.dist-info}/WHEEL +0 -0
  233. {fast_agent_mcp-0.2.58.dist-info → fast_agent_mcp-0.3.0.dist-info}/licenses/LICENSE +0 -0
@@ -30,13 +30,13 @@ from mcp.types import (
30
30
  )
31
31
  from pydantic import FileUrl
32
32
 
33
- from mcp_agent.context_dependent import ContextDependent
34
- from mcp_agent.logging.logger import get_logger
35
- from mcp_agent.mcp.helpers.server_config_helpers import get_server_config
36
- from mcp_agent.mcp.sampling import sample
33
+ from fast_agent.context_dependent import ContextDependent
34
+ from fast_agent.core.logging.logger import get_logger
35
+ from fast_agent.mcp.helpers.server_config_helpers import get_server_config
36
+ from fast_agent.mcp.sampling import sample
37
37
 
38
38
  if TYPE_CHECKING:
39
- from mcp_agent.config import MCPServerSettings
39
+ from fast_agent.config import MCPServerSettings
40
40
 
41
41
  logger = get_logger(__name__)
42
42
 
@@ -88,6 +88,8 @@ class MCPAgentClientSession(ClientSession, ContextDependent):
88
88
  self.api_key: str | None = kwargs.pop("api_key", None)
89
89
  # Extract custom elicitation handler if provided
90
90
  custom_elicitation_handler = kwargs.pop("elicitation_handler", None)
91
+ # Extract optional context for ContextDependent mixin without passing it to ClientSession
92
+ self._context = kwargs.pop("context", None)
91
93
 
92
94
  version = version("fast-agent-mcp") or "dev"
93
95
  fast_agent: Implementation = Implementation(name="fast-agent-mcp", version=version)
@@ -119,9 +121,9 @@ class MCPAgentClientSession(ClientSession, ContextDependent):
119
121
  # Try to resolve using factory
120
122
  elicitation_handler = None
121
123
  try:
122
- from mcp_agent.context import get_current_context
123
- from mcp_agent.core.agent_types import AgentConfig
124
- from mcp_agent.mcp.elicitation_factory import resolve_elicitation_handler
124
+ from fast_agent.agents.agent_types import AgentConfig
125
+ from fast_agent.context import get_current_context
126
+ from fast_agent.mcp.elicitation_factory import resolve_elicitation_handler
125
127
 
126
128
  context = get_current_context()
127
129
  if context and context.config:
@@ -141,7 +143,7 @@ class MCPAgentClientSession(ClientSession, ContextDependent):
141
143
  # Fallback to forms handler only if factory resolution wasn't attempted
142
144
  # If factory was attempted and returned None, respect that (means no elicitation capability)
143
145
  if elicitation_handler is None and not self.server_config:
144
- from mcp_agent.mcp.elicitation_handlers import forms_elicitation_handler
146
+ from fast_agent.mcp.elicitation_handlers import forms_elicitation_handler
145
147
 
146
148
  elicitation_handler = forms_elicitation_handler
147
149
 
@@ -157,7 +159,7 @@ class MCPAgentClientSession(ClientSession, ContextDependent):
157
159
  def _should_enable_auto_sampling(self) -> bool:
158
160
  """Check if auto_sampling is enabled at the application level."""
159
161
  try:
160
- from mcp_agent.context import get_current_context
162
+ from fast_agent.context import get_current_context
161
163
 
162
164
  context = get_current_context()
163
165
  if context and context.config:
@@ -190,12 +192,16 @@ class MCPAgentClientSession(ClientSession, ContextDependent):
190
192
  return result
191
193
  except Exception as e:
192
194
  # Handle connection errors cleanly
195
+ # Looking at the MCP SDK, this should probably handle MCPError
193
196
  from anyio import ClosedResourceError
194
-
197
+
195
198
  if isinstance(e, ClosedResourceError):
196
199
  # Show clean offline message and convert to ConnectionError
197
- from mcp_agent import console
198
- console.console.print(f"[dim red]MCP server {self.session_server_name} offline[/dim red]")
200
+ from fast_agent.ui import console
201
+
202
+ console.console.print(
203
+ f"[dim red]MCP server {self.session_server_name} offline[/dim red]"
204
+ )
199
205
  raise ConnectionError(f"MCP server {self.session_server_name} offline") from e
200
206
  else:
201
207
  logger.error(f"send_request failed: {str(e)}")
@@ -206,7 +212,7 @@ class MCPAgentClientSession(ClientSession, ContextDependent):
206
212
  Can be overridden by subclasses to handle a notification without needing
207
213
  to listen on the message stream.
208
214
  """
209
- logger.info(
215
+ logger.debug(
210
216
  "_received_notification: notification=",
211
217
  data=notification.model_dump(),
212
218
  )
@@ -245,86 +251,85 @@ class MCPAgentClientSession(ClientSession, ContextDependent):
245
251
  except Exception as e:
246
252
  logger.error(f"Error in tool list changed callback: {e}")
247
253
 
254
+ # TODO -- decide whether to make this override type safe or not (modify SDK)
248
255
  async def call_tool(
249
- self,
250
- name: str,
251
- arguments: dict | None = None,
252
- _meta: dict | None = None,
253
- **kwargs
256
+ self, name: str, arguments: dict | None = None, _meta: dict | None = None, **kwargs
254
257
  ) -> CallToolResult:
255
258
  """Call a tool with optional metadata support."""
256
259
  if _meta:
257
260
  from mcp.types import RequestParams
258
-
261
+
259
262
  # Safe merge - preserve existing meta fields like progressToken
260
- existing_meta = kwargs.get('meta')
263
+ existing_meta = kwargs.get("meta")
261
264
  if existing_meta:
262
- meta_dict = existing_meta.model_dump() if hasattr(existing_meta, 'model_dump') else {}
265
+ meta_dict = (
266
+ existing_meta.model_dump() if hasattr(existing_meta, "model_dump") else {}
267
+ )
263
268
  meta_dict.update(_meta)
264
269
  meta_obj = RequestParams.Meta(**meta_dict)
265
270
  else:
266
271
  meta_obj = RequestParams.Meta(**_meta)
267
-
272
+
268
273
  # Create CallToolRequestParams without meta, then add _meta via model_dump
269
274
  params = CallToolRequestParams(name=name, arguments=arguments)
270
275
  params_dict = params.model_dump(by_alias=True)
271
276
  params_dict["_meta"] = meta_obj.model_dump()
272
-
277
+
273
278
  # Create request with proper types
274
279
  request = CallToolRequest(
275
- method="tools/call",
276
- params=CallToolRequestParams.model_validate(params_dict)
280
+ method="tools/call", params=CallToolRequestParams.model_validate(params_dict)
277
281
  )
278
-
282
+
279
283
  return await self.send_request(request, CallToolResult)
280
284
  else:
281
285
  return await super().call_tool(name, arguments, **kwargs)
282
286
 
283
- async def read_resource(self, uri: str, _meta: dict | None = None, **kwargs) -> ReadResourceResult:
287
+ async def read_resource(
288
+ self, uri: str, _meta: dict | None = None, **kwargs
289
+ ) -> ReadResourceResult:
284
290
  """Read a resource with optional metadata support."""
285
291
  if _meta:
286
292
  from mcp.types import RequestParams
287
-
293
+
288
294
  # Safe merge - preserve existing meta fields like progressToken
289
- existing_meta = kwargs.get('meta')
295
+ existing_meta = kwargs.get("meta")
290
296
  if existing_meta:
291
- meta_dict = existing_meta.model_dump() if hasattr(existing_meta, 'model_dump') else {}
297
+ meta_dict = (
298
+ existing_meta.model_dump() if hasattr(existing_meta, "model_dump") else {}
299
+ )
292
300
  meta_dict.update(_meta)
293
301
  meta_obj = RequestParams.Meta(**meta_dict)
294
302
  else:
295
303
  meta_obj = RequestParams.Meta(**_meta)
296
-
304
+
297
305
  request = ReadResourceRequest(
298
- method="resources/read",
299
- params=ReadResourceRequestParams(uri=uri, meta=meta_obj)
306
+ method="resources/read", params=ReadResourceRequestParams(uri=uri, meta=meta_obj)
300
307
  )
301
308
  return await self.send_request(request, ReadResourceResult)
302
309
  else:
303
310
  return await super().read_resource(uri, **kwargs)
304
311
 
305
312
  async def get_prompt(
306
- self,
307
- name: str,
308
- arguments: dict | None = None,
309
- _meta: dict | None = None,
310
- **kwargs
313
+ self, name: str, arguments: dict | None = None, _meta: dict | None = None, **kwargs
311
314
  ) -> GetPromptResult:
312
315
  """Get a prompt with optional metadata support."""
313
316
  if _meta:
314
317
  from mcp.types import RequestParams
315
-
318
+
316
319
  # Safe merge - preserve existing meta fields like progressToken
317
- existing_meta = kwargs.get('meta')
320
+ existing_meta = kwargs.get("meta")
318
321
  if existing_meta:
319
- meta_dict = existing_meta.model_dump() if hasattr(existing_meta, 'model_dump') else {}
322
+ meta_dict = (
323
+ existing_meta.model_dump() if hasattr(existing_meta, "model_dump") else {}
324
+ )
320
325
  meta_dict.update(_meta)
321
326
  meta_obj = RequestParams.Meta(**meta_dict)
322
327
  else:
323
328
  meta_obj = RequestParams.Meta(**_meta)
324
-
329
+
325
330
  request = GetPromptRequest(
326
331
  method="prompts/get",
327
- params=GetPromptRequestParams(name=name, arguments=arguments, meta=meta_obj)
332
+ params=GetPromptRequestParams(name=name, arguments=arguments, meta=meta_obj),
328
333
  )
329
334
  return await self.send_request(request, GetPromptResult)
330
335
  else:
@@ -23,16 +23,16 @@ from mcp.types import (
23
23
  from opentelemetry import trace
24
24
  from pydantic import AnyUrl, BaseModel, ConfigDict
25
25
 
26
- from mcp_agent.context_dependent import ContextDependent
27
- from mcp_agent.event_progress import ProgressAction
28
- from mcp_agent.logging.logger import get_logger
29
- from mcp_agent.mcp.common import SEP, create_namespaced_name, is_namespaced_name
30
- from mcp_agent.mcp.gen_client import gen_client
31
- from mcp_agent.mcp.mcp_agent_client_session import MCPAgentClientSession
32
- from mcp_agent.mcp.mcp_connection_manager import MCPConnectionManager
26
+ from fast_agent.context_dependent import ContextDependent
27
+ from fast_agent.core.logging.logger import get_logger
28
+ from fast_agent.event_progress import ProgressAction
29
+ from fast_agent.mcp.common import SEP, create_namespaced_name, is_namespaced_name
30
+ from fast_agent.mcp.gen_client import gen_client
31
+ from fast_agent.mcp.mcp_agent_client_session import MCPAgentClientSession
32
+ from fast_agent.mcp.mcp_connection_manager import MCPConnectionManager
33
33
 
34
34
  if TYPE_CHECKING:
35
- from mcp_agent.context import Context
35
+ from fast_agent.context import Context
36
36
 
37
37
 
38
38
  logger = get_logger(__name__) # This will be replaced per-instance when agent_name is available
@@ -84,7 +84,7 @@ class MCPAggregator(ContextDependent):
84
84
  self._persistent_connection_manager = self.context._connection_manager
85
85
 
86
86
  # Import the display component here to avoid circular imports
87
- from mcp_agent.ui.console_display import ConsoleDisplay
87
+ from fast_agent.ui.console_display import ConsoleDisplay
88
88
 
89
89
  # Initialize the display component
90
90
  self.display = ConsoleDisplay(config=self.context.config)
@@ -99,14 +99,16 @@ class MCPAggregator(ContextDependent):
99
99
  def __init__(
100
100
  self,
101
101
  server_names: List[str],
102
- connection_persistence: bool = True, # Default to True for better stability
102
+ connection_persistence: bool = True,
103
103
  context: Optional["Context"] = None,
104
104
  name: str = None,
105
+ config: Optional[Any] = None, # Accept the agent config for elicitation_handler access
105
106
  **kwargs,
106
107
  ) -> None:
107
108
  """
108
109
  :param server_names: A list of server names to connect to.
109
110
  :param connection_persistence: Whether to maintain persistent connections to servers (default: True).
111
+ :param config: Optional agent config containing elicitation_handler and other settings.
110
112
  Note: The server names must be resolvable by the gen_client function, and specified in the server registry.
111
113
  """
112
114
  super().__init__(
@@ -117,6 +119,7 @@ class MCPAggregator(ContextDependent):
117
119
  self.server_names = server_names
118
120
  self.connection_persistence = connection_persistence
119
121
  self.agent_name = name
122
+ self.config = config # Store the config for access in session factory
120
123
  self._persistent_connection_manager: MCPConnectionManager = None
121
124
 
122
125
  # Set up logger with agent name in namespace if available
@@ -186,10 +189,6 @@ class MCPAggregator(ContextDependent):
186
189
  ) -> "MCPAggregator":
187
190
  """
188
191
  Factory method to create and initialize an MCPAggregator.
189
- Use this instead of constructor since we need async initialization.
190
- If connection_persistence is True, the aggregator will maintain a
191
- persistent connection to the servers for as long as this aggregator is around.
192
- By default we do not maintain a persistent connection.
193
192
  """
194
193
 
195
194
  logger.info(f"Creating MCPAggregator with servers: {server_names}")
@@ -211,6 +210,47 @@ class MCPAggregator(ContextDependent):
211
210
  logger.error(f"Error creating MCPAggregator: {e}")
212
211
  await instance.__aexit__(None, None, None)
213
212
 
213
+ def _create_session_factory(self, server_name: str):
214
+ """
215
+ Create a session factory function for the given server.
216
+ This centralizes the logic for creating MCPAgentClientSession instances.
217
+
218
+ Args:
219
+ server_name: The name of the server to create a session for
220
+
221
+ Returns:
222
+ A factory function that creates MCPAgentClientSession instances
223
+ """
224
+
225
+ def session_factory(read_stream, write_stream, read_timeout, **kwargs):
226
+ # Get agent's model and name from config if available
227
+ agent_model: str | None = None
228
+ agent_name: str | None = None
229
+ elicitation_handler = None
230
+ api_key: str | None = None
231
+
232
+ # Access config directly if it was passed from BaseAgent
233
+ if self.config:
234
+ agent_model = self.config.model
235
+ agent_name = self.config.name
236
+ elicitation_handler = self.config.elicitation_handler
237
+ api_key = self.config.api_key
238
+
239
+ return MCPAgentClientSession(
240
+ read_stream,
241
+ write_stream,
242
+ read_timeout,
243
+ server_name=server_name,
244
+ agent_model=agent_model,
245
+ agent_name=agent_name,
246
+ api_key=api_key,
247
+ elicitation_handler=elicitation_handler,
248
+ tool_list_changed_callback=self._handle_tool_list_changed,
249
+ **kwargs, # Pass through any additional kwargs like server_config
250
+ )
251
+
252
+ return session_factory
253
+
214
254
  async def load_servers(self) -> None:
215
255
  """
216
256
  Discover tools from each server in parallel and build an index of namespaced tool names.
@@ -238,39 +278,8 @@ class MCPAggregator(ContextDependent):
238
278
  },
239
279
  )
240
280
 
241
- # Create a wrapper to capture the parameters for the client session
242
- def session_factory(read_stream, write_stream, read_timeout, **kwargs):
243
- # Get agent's model and name if this aggregator is part of an agent
244
- agent_model: str | None = None
245
- agent_name: str | None = None
246
- elicitation_handler = None
247
- api_key: str | None = None
248
-
249
- # Check if this aggregator is part of an Agent (which has config)
250
- # Import here to avoid circular dependency
251
- from mcp_agent.agents.base_agent import BaseAgent
252
-
253
- if isinstance(self, BaseAgent):
254
- agent_model = self.config.model
255
- agent_name = self.config.name
256
- elicitation_handler = self.config.elicitation_handler
257
- api_key = self.config.api_key
258
-
259
- return MCPAgentClientSession(
260
- read_stream,
261
- write_stream,
262
- read_timeout,
263
- server_name=server_name,
264
- agent_model=agent_model,
265
- agent_name=agent_name,
266
- api_key=api_key,
267
- elicitation_handler=elicitation_handler,
268
- tool_list_changed_callback=self._handle_tool_list_changed,
269
- **kwargs, # Pass through any additional kwargs like server_config
270
- )
271
-
272
281
  await self._persistent_connection_manager.get_server(
273
- server_name, client_session_factory=session_factory
282
+ server_name, client_session_factory=self._create_session_factory(server_name)
274
283
  )
275
284
 
276
285
  logger.info(
@@ -313,46 +322,15 @@ class MCPAggregator(ContextDependent):
313
322
 
314
323
  if self.connection_persistence:
315
324
  server_connection = await self._persistent_connection_manager.get_server(
316
- server_name, client_session_factory=MCPAgentClientSession
325
+ server_name, client_session_factory=self._create_session_factory(server_name)
317
326
  )
318
327
  tools = await fetch_tools(server_connection.session, server_name)
319
328
  prompts = await fetch_prompts(server_connection.session, server_name)
320
329
  else:
321
- # Create a factory function for the client session
322
- def create_session(read_stream, write_stream, read_timeout, **kwargs):
323
- # Get agent's model and name if this aggregator is part of an agent
324
- agent_model: str | None = None
325
- agent_name: str | None = None
326
- elicitation_handler = None
327
- api_key: str | None = None
328
-
329
- # Check if this aggregator is part of an Agent (which has config)
330
- # Import here to avoid circular dependency
331
- from mcp_agent.agents.base_agent import BaseAgent
332
-
333
- if isinstance(self, BaseAgent):
334
- agent_model = self.config.model
335
- agent_name = self.config.name
336
- elicitation_handler = self.config.elicitation_handler
337
- api_key = self.config.api_key
338
-
339
- return MCPAgentClientSession(
340
- read_stream,
341
- write_stream,
342
- read_timeout,
343
- server_name=server_name,
344
- agent_model=agent_model,
345
- agent_name=agent_name,
346
- api_key=api_key,
347
- elicitation_handler=elicitation_handler,
348
- tool_list_changed_callback=self._handle_tool_list_changed,
349
- **kwargs, # Pass through any additional kwargs like server_config
350
- )
351
-
352
330
  async with gen_client(
353
331
  server_name,
354
332
  server_registry=self.context.server_registry,
355
- client_session_factory=create_session,
333
+ client_session_factory=self._create_session_factory(server_name),
356
334
  ) as client:
357
335
  tools = await fetch_tools(client, server_name)
358
336
  prompts = await fetch_prompts(client, server_name)
@@ -410,7 +388,7 @@ class MCPAggregator(ContextDependent):
410
388
 
411
389
  try:
412
390
  server_conn = await self._persistent_connection_manager.get_server(
413
- server_name, client_session_factory=MCPAgentClientSession
391
+ server_name, client_session_factory=self._create_session_factory(server_name)
414
392
  )
415
393
  # server_capabilities is a property, not a coroutine
416
394
  return server_conn.server_capabilities
@@ -516,7 +494,7 @@ class MCPAggregator(ContextDependent):
516
494
  # Get metadata from context for tool, resource, and prompt calls
517
495
  metadata = None
518
496
  if method_name in ["call_tool", "read_resource", "get_prompt"]:
519
- from mcp_agent.llm.augmented_llm import _mcp_metadata_var
497
+ from fast_agent.llm.fastagent_llm import _mcp_metadata_var
520
498
 
521
499
  metadata = _mcp_metadata_var.get()
522
500
 
@@ -549,7 +527,7 @@ class MCPAggregator(ContextDependent):
549
527
  try:
550
528
  if self.connection_persistence:
551
529
  server_connection = await self._persistent_connection_manager.get_server(
552
- server_name, client_session_factory=MCPAgentClientSession
530
+ server_name, client_session_factory=self._create_session_factory(server_name)
553
531
  )
554
532
  return await try_execute(server_connection.session)
555
533
  else:
@@ -576,7 +554,7 @@ class MCPAggregator(ContextDependent):
576
554
  return result
577
555
  except ConnectionError:
578
556
  # Server offline - attempt reconnection
579
- from mcp_agent import console
557
+ from fast_agent.ui import console
580
558
 
581
559
  console.console.print(
582
560
  f"[dim yellow]MCP server {server_name} reconnecting...[/dim yellow]"
@@ -591,7 +569,8 @@ class MCPAggregator(ContextDependent):
591
569
  await asyncio.sleep(0.1)
592
570
 
593
571
  server_connection = await self._persistent_connection_manager.get_server(
594
- server_name, client_session_factory=MCPAgentClientSession
572
+ server_name,
573
+ client_session_factory=self._create_session_factory(server_name),
595
574
  )
596
575
  result = await try_execute(server_connection.session)
597
576
  else:
@@ -1069,39 +1048,11 @@ class MCPAggregator(ContextDependent):
1069
1048
 
1070
1049
  async with self._refresh_lock:
1071
1050
  try:
1072
- # Create a factory function that will include our parameters
1073
- def create_session(read_stream, write_stream, read_timeout):
1074
- # Get agent name if available
1075
- agent_model: str | None = None
1076
- agent_name: str | None = None
1077
- elicitation_handler = None
1078
- api_key: str | None = None
1079
-
1080
- # Import here to avoid circular dependency
1081
- from mcp_agent.agents.base_agent import BaseAgent
1082
-
1083
- if isinstance(self, BaseAgent):
1084
- agent_model = self.config.model
1085
- agent_name = self.config.name
1086
- elicitation_handler = self.config.elicitation_handler
1087
- api_key = self.config.api_key
1088
-
1089
- return MCPAgentClientSession(
1090
- read_stream,
1091
- write_stream,
1092
- read_timeout,
1093
- server_name=server_name,
1094
- agent_model=agent_model,
1095
- agent_name=agent_name,
1096
- api_key=api_key,
1097
- elicitation_handler=elicitation_handler,
1098
- tool_list_changed_callback=self._handle_tool_list_changed,
1099
- )
1100
-
1101
1051
  # Fetch new tools from the server
1102
1052
  if self.connection_persistence:
1103
1053
  server_connection = await self._persistent_connection_manager.get_server(
1104
- server_name, client_session_factory=create_session
1054
+ server_name,
1055
+ client_session_factory=self._create_session_factory(server_name),
1105
1056
  )
1106
1057
  tools_result = await server_connection.session.list_tools()
1107
1058
  new_tools = tools_result.tools or []
@@ -1109,7 +1060,7 @@ class MCPAggregator(ContextDependent):
1109
1060
  async with gen_client(
1110
1061
  server_name,
1111
1062
  server_registry=self.context.server_registry,
1112
- client_session_factory=create_session,
1063
+ client_session_factory=self._create_session_factory(server_name),
1113
1064
  ) as client:
1114
1065
  tools_result = await client.list_tools()
1115
1066
  new_tools = tools_result.tools or []
@@ -26,17 +26,17 @@ from mcp.client.stdio import (
26
26
  from mcp.client.streamable_http import GetSessionIdCallback, streamablehttp_client
27
27
  from mcp.types import JSONRPCMessage, ServerCapabilities
28
28
 
29
- from mcp_agent.config import MCPServerSettings
30
- from mcp_agent.context_dependent import ContextDependent
31
- from mcp_agent.core.exceptions import ServerInitializationError
32
- from mcp_agent.event_progress import ProgressAction
33
- from mcp_agent.logging.logger import get_logger
34
- from mcp_agent.mcp.logger_textio import get_stderr_handler
35
- from mcp_agent.mcp.mcp_agent_client_session import MCPAgentClientSession
29
+ from fast_agent.config import MCPServerSettings
30
+ from fast_agent.context_dependent import ContextDependent
31
+ from fast_agent.core.exceptions import ServerInitializationError
32
+ from fast_agent.core.logging.logger import get_logger
33
+ from fast_agent.event_progress import ProgressAction
34
+ from fast_agent.mcp.logger_textio import get_stderr_handler
35
+ from fast_agent.mcp.mcp_agent_client_session import MCPAgentClientSession
36
36
 
37
37
  if TYPE_CHECKING:
38
- from mcp_agent.context import Context
39
- from mcp_agent.mcp_server_registry import InitHookCallable, ServerRegistry
38
+ from fast_agent.context import Context
39
+ from fast_agent.mcp_server_registry import ServerRegistry
40
40
 
41
41
  logger = get_logger(__name__)
42
42
 
@@ -88,13 +88,11 @@ class ServerConnection:
88
88
  [MemoryObjectReceiveStream, MemoryObjectSendStream, timedelta | None],
89
89
  ClientSession,
90
90
  ],
91
- init_hook: Optional["InitHookCallable"] = None,
92
91
  ) -> None:
93
92
  self.server_name = server_name
94
93
  self.server_config = server_config
95
94
  self.session: ClientSession | None = None
96
95
  self._client_session_factory = client_session_factory
97
- self._init_hook = init_hook
98
96
  self._transport_context_factory = transport_context_factory
99
97
  # Signal that session is fully up and initialized
100
98
  self._initialized_event = Event()
@@ -137,9 +135,6 @@ class ServerConnection:
137
135
 
138
136
  self.server_capabilities = result.capabilities
139
137
  # If there's an init hook, run it
140
- if self._init_hook:
141
- logger.info(f"{self.server_name}: Executing init hook.")
142
- self._init_hook(self.session, self.server_config.auth)
143
138
 
144
139
  # Now the session is ready for use
145
140
  self._initialized_event.set()
@@ -305,13 +300,15 @@ class MCPConnectionManager(ContextDependent):
305
300
  """Suppress MCP library's 'Error in sse_reader' messages."""
306
301
  if self._mcp_sse_filter_added:
307
302
  return
308
-
303
+
309
304
  import logging
310
-
305
+
311
306
  class MCPSSEErrorFilter(logging.Filter):
312
307
  def filter(self, record):
313
- return not (record.name == "mcp.client.sse" and "Error in sse_reader" in record.getMessage())
314
-
308
+ return not (
309
+ record.name == "mcp.client.sse" and "Error in sse_reader" in record.getMessage()
310
+ )
311
+
315
312
  mcp_sse_logger = logging.getLogger("mcp.client.sse")
316
313
  mcp_sse_logger.addFilter(MCPSSEErrorFilter())
317
314
  self._mcp_sse_filter_added = True
@@ -323,7 +320,6 @@ class MCPConnectionManager(ContextDependent):
323
320
  [MemoryObjectReceiveStream, MemoryObjectSendStream, timedelta | None],
324
321
  ClientSession,
325
322
  ],
326
- init_hook: Optional["InitHookCallable"] = None,
327
323
  ) -> ServerConnection:
328
324
  """
329
325
  Connect to a server and return a RunningServer instance that will persist
@@ -359,7 +355,7 @@ class MCPConnectionManager(ContextDependent):
359
355
  elif config.transport == "sse":
360
356
  # Suppress MCP library error spam
361
357
  self._suppress_mcp_sse_errors()
362
-
358
+
363
359
  return _add_none_to_context(
364
360
  sse_client(
365
361
  config.url,
@@ -377,7 +373,6 @@ class MCPConnectionManager(ContextDependent):
377
373
  server_config=config,
378
374
  transport_context_factory=transport_context_factory,
379
375
  client_session_factory=client_session_factory,
380
- init_hook=init_hook or self.server_registry.init_hooks.get(server_name),
381
376
  )
382
377
 
383
378
  async with self._lock:
@@ -395,7 +390,6 @@ class MCPConnectionManager(ContextDependent):
395
390
  self,
396
391
  server_name: str,
397
392
  client_session_factory: Callable,
398
- init_hook: Optional["InitHookCallable"] = None,
399
393
  ) -> ServerConnection:
400
394
  """
401
395
  Get a running server instance, launching it if needed.
@@ -416,7 +410,6 @@ class MCPConnectionManager(ContextDependent):
416
410
  server_conn = await self.launch_server(
417
411
  server_name=server_name,
418
412
  client_session_factory=client_session_factory,
419
- init_hook=init_hook,
420
413
  )
421
414
 
422
415
  # Wait until it's fully initialized, or an error occurs