fast-agent-mcp 0.4.7__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.
Files changed (261) hide show
  1. fast_agent/__init__.py +183 -0
  2. fast_agent/acp/__init__.py +19 -0
  3. fast_agent/acp/acp_aware_mixin.py +304 -0
  4. fast_agent/acp/acp_context.py +437 -0
  5. fast_agent/acp/content_conversion.py +136 -0
  6. fast_agent/acp/filesystem_runtime.py +427 -0
  7. fast_agent/acp/permission_store.py +269 -0
  8. fast_agent/acp/server/__init__.py +5 -0
  9. fast_agent/acp/server/agent_acp_server.py +1472 -0
  10. fast_agent/acp/slash_commands.py +1050 -0
  11. fast_agent/acp/terminal_runtime.py +408 -0
  12. fast_agent/acp/tool_permission_adapter.py +125 -0
  13. fast_agent/acp/tool_permissions.py +474 -0
  14. fast_agent/acp/tool_progress.py +814 -0
  15. fast_agent/agents/__init__.py +85 -0
  16. fast_agent/agents/agent_types.py +64 -0
  17. fast_agent/agents/llm_agent.py +350 -0
  18. fast_agent/agents/llm_decorator.py +1139 -0
  19. fast_agent/agents/mcp_agent.py +1337 -0
  20. fast_agent/agents/tool_agent.py +271 -0
  21. fast_agent/agents/workflow/agents_as_tools_agent.py +849 -0
  22. fast_agent/agents/workflow/chain_agent.py +212 -0
  23. fast_agent/agents/workflow/evaluator_optimizer.py +380 -0
  24. fast_agent/agents/workflow/iterative_planner.py +652 -0
  25. fast_agent/agents/workflow/maker_agent.py +379 -0
  26. fast_agent/agents/workflow/orchestrator_models.py +218 -0
  27. fast_agent/agents/workflow/orchestrator_prompts.py +248 -0
  28. fast_agent/agents/workflow/parallel_agent.py +250 -0
  29. fast_agent/agents/workflow/router_agent.py +353 -0
  30. fast_agent/cli/__init__.py +0 -0
  31. fast_agent/cli/__main__.py +73 -0
  32. fast_agent/cli/commands/acp.py +159 -0
  33. fast_agent/cli/commands/auth.py +404 -0
  34. fast_agent/cli/commands/check_config.py +783 -0
  35. fast_agent/cli/commands/go.py +514 -0
  36. fast_agent/cli/commands/quickstart.py +557 -0
  37. fast_agent/cli/commands/serve.py +143 -0
  38. fast_agent/cli/commands/server_helpers.py +114 -0
  39. fast_agent/cli/commands/setup.py +174 -0
  40. fast_agent/cli/commands/url_parser.py +190 -0
  41. fast_agent/cli/constants.py +40 -0
  42. fast_agent/cli/main.py +115 -0
  43. fast_agent/cli/terminal.py +24 -0
  44. fast_agent/config.py +798 -0
  45. fast_agent/constants.py +41 -0
  46. fast_agent/context.py +279 -0
  47. fast_agent/context_dependent.py +50 -0
  48. fast_agent/core/__init__.py +92 -0
  49. fast_agent/core/agent_app.py +448 -0
  50. fast_agent/core/core_app.py +137 -0
  51. fast_agent/core/direct_decorators.py +784 -0
  52. fast_agent/core/direct_factory.py +620 -0
  53. fast_agent/core/error_handling.py +27 -0
  54. fast_agent/core/exceptions.py +90 -0
  55. fast_agent/core/executor/__init__.py +0 -0
  56. fast_agent/core/executor/executor.py +280 -0
  57. fast_agent/core/executor/task_registry.py +32 -0
  58. fast_agent/core/executor/workflow_signal.py +324 -0
  59. fast_agent/core/fastagent.py +1186 -0
  60. fast_agent/core/logging/__init__.py +5 -0
  61. fast_agent/core/logging/events.py +138 -0
  62. fast_agent/core/logging/json_serializer.py +164 -0
  63. fast_agent/core/logging/listeners.py +309 -0
  64. fast_agent/core/logging/logger.py +278 -0
  65. fast_agent/core/logging/transport.py +481 -0
  66. fast_agent/core/prompt.py +9 -0
  67. fast_agent/core/prompt_templates.py +183 -0
  68. fast_agent/core/validation.py +326 -0
  69. fast_agent/event_progress.py +62 -0
  70. fast_agent/history/history_exporter.py +49 -0
  71. fast_agent/human_input/__init__.py +47 -0
  72. fast_agent/human_input/elicitation_handler.py +123 -0
  73. fast_agent/human_input/elicitation_state.py +33 -0
  74. fast_agent/human_input/form_elements.py +59 -0
  75. fast_agent/human_input/form_fields.py +256 -0
  76. fast_agent/human_input/simple_form.py +113 -0
  77. fast_agent/human_input/types.py +40 -0
  78. fast_agent/interfaces.py +310 -0
  79. fast_agent/llm/__init__.py +9 -0
  80. fast_agent/llm/cancellation.py +22 -0
  81. fast_agent/llm/fastagent_llm.py +931 -0
  82. fast_agent/llm/internal/passthrough.py +161 -0
  83. fast_agent/llm/internal/playback.py +129 -0
  84. fast_agent/llm/internal/silent.py +41 -0
  85. fast_agent/llm/internal/slow.py +38 -0
  86. fast_agent/llm/memory.py +275 -0
  87. fast_agent/llm/model_database.py +490 -0
  88. fast_agent/llm/model_factory.py +388 -0
  89. fast_agent/llm/model_info.py +102 -0
  90. fast_agent/llm/prompt_utils.py +155 -0
  91. fast_agent/llm/provider/anthropic/anthropic_utils.py +84 -0
  92. fast_agent/llm/provider/anthropic/cache_planner.py +56 -0
  93. fast_agent/llm/provider/anthropic/llm_anthropic.py +796 -0
  94. fast_agent/llm/provider/anthropic/multipart_converter_anthropic.py +462 -0
  95. fast_agent/llm/provider/bedrock/bedrock_utils.py +218 -0
  96. fast_agent/llm/provider/bedrock/llm_bedrock.py +2207 -0
  97. fast_agent/llm/provider/bedrock/multipart_converter_bedrock.py +84 -0
  98. fast_agent/llm/provider/google/google_converter.py +466 -0
  99. fast_agent/llm/provider/google/llm_google_native.py +681 -0
  100. fast_agent/llm/provider/openai/llm_aliyun.py +31 -0
  101. fast_agent/llm/provider/openai/llm_azure.py +143 -0
  102. fast_agent/llm/provider/openai/llm_deepseek.py +76 -0
  103. fast_agent/llm/provider/openai/llm_generic.py +35 -0
  104. fast_agent/llm/provider/openai/llm_google_oai.py +32 -0
  105. fast_agent/llm/provider/openai/llm_groq.py +42 -0
  106. fast_agent/llm/provider/openai/llm_huggingface.py +85 -0
  107. fast_agent/llm/provider/openai/llm_openai.py +1195 -0
  108. fast_agent/llm/provider/openai/llm_openai_compatible.py +138 -0
  109. fast_agent/llm/provider/openai/llm_openrouter.py +45 -0
  110. fast_agent/llm/provider/openai/llm_tensorzero_openai.py +128 -0
  111. fast_agent/llm/provider/openai/llm_xai.py +38 -0
  112. fast_agent/llm/provider/openai/multipart_converter_openai.py +561 -0
  113. fast_agent/llm/provider/openai/openai_multipart.py +169 -0
  114. fast_agent/llm/provider/openai/openai_utils.py +67 -0
  115. fast_agent/llm/provider/openai/responses.py +133 -0
  116. fast_agent/llm/provider_key_manager.py +139 -0
  117. fast_agent/llm/provider_types.py +34 -0
  118. fast_agent/llm/request_params.py +61 -0
  119. fast_agent/llm/sampling_converter.py +98 -0
  120. fast_agent/llm/stream_types.py +9 -0
  121. fast_agent/llm/usage_tracking.py +445 -0
  122. fast_agent/mcp/__init__.py +56 -0
  123. fast_agent/mcp/common.py +26 -0
  124. fast_agent/mcp/elicitation_factory.py +84 -0
  125. fast_agent/mcp/elicitation_handlers.py +164 -0
  126. fast_agent/mcp/gen_client.py +83 -0
  127. fast_agent/mcp/helpers/__init__.py +36 -0
  128. fast_agent/mcp/helpers/content_helpers.py +352 -0
  129. fast_agent/mcp/helpers/server_config_helpers.py +25 -0
  130. fast_agent/mcp/hf_auth.py +147 -0
  131. fast_agent/mcp/interfaces.py +92 -0
  132. fast_agent/mcp/logger_textio.py +108 -0
  133. fast_agent/mcp/mcp_agent_client_session.py +411 -0
  134. fast_agent/mcp/mcp_aggregator.py +2175 -0
  135. fast_agent/mcp/mcp_connection_manager.py +723 -0
  136. fast_agent/mcp/mcp_content.py +262 -0
  137. fast_agent/mcp/mime_utils.py +108 -0
  138. fast_agent/mcp/oauth_client.py +509 -0
  139. fast_agent/mcp/prompt.py +159 -0
  140. fast_agent/mcp/prompt_message_extended.py +155 -0
  141. fast_agent/mcp/prompt_render.py +84 -0
  142. fast_agent/mcp/prompt_serialization.py +580 -0
  143. fast_agent/mcp/prompts/__init__.py +0 -0
  144. fast_agent/mcp/prompts/__main__.py +7 -0
  145. fast_agent/mcp/prompts/prompt_constants.py +18 -0
  146. fast_agent/mcp/prompts/prompt_helpers.py +238 -0
  147. fast_agent/mcp/prompts/prompt_load.py +186 -0
  148. fast_agent/mcp/prompts/prompt_server.py +552 -0
  149. fast_agent/mcp/prompts/prompt_template.py +438 -0
  150. fast_agent/mcp/resource_utils.py +215 -0
  151. fast_agent/mcp/sampling.py +200 -0
  152. fast_agent/mcp/server/__init__.py +4 -0
  153. fast_agent/mcp/server/agent_server.py +613 -0
  154. fast_agent/mcp/skybridge.py +44 -0
  155. fast_agent/mcp/sse_tracking.py +287 -0
  156. fast_agent/mcp/stdio_tracking_simple.py +59 -0
  157. fast_agent/mcp/streamable_http_tracking.py +309 -0
  158. fast_agent/mcp/tool_execution_handler.py +137 -0
  159. fast_agent/mcp/tool_permission_handler.py +88 -0
  160. fast_agent/mcp/transport_tracking.py +634 -0
  161. fast_agent/mcp/types.py +24 -0
  162. fast_agent/mcp/ui_agent.py +48 -0
  163. fast_agent/mcp/ui_mixin.py +209 -0
  164. fast_agent/mcp_server_registry.py +89 -0
  165. fast_agent/py.typed +0 -0
  166. fast_agent/resources/examples/data-analysis/analysis-campaign.py +189 -0
  167. fast_agent/resources/examples/data-analysis/analysis.py +68 -0
  168. fast_agent/resources/examples/data-analysis/fastagent.config.yaml +41 -0
  169. fast_agent/resources/examples/data-analysis/mount-point/WA_Fn-UseC_-HR-Employee-Attrition.csv +1471 -0
  170. fast_agent/resources/examples/mcp/elicitations/elicitation_account_server.py +88 -0
  171. fast_agent/resources/examples/mcp/elicitations/elicitation_forms_server.py +297 -0
  172. fast_agent/resources/examples/mcp/elicitations/elicitation_game_server.py +164 -0
  173. fast_agent/resources/examples/mcp/elicitations/fastagent.config.yaml +35 -0
  174. fast_agent/resources/examples/mcp/elicitations/fastagent.secrets.yaml.example +17 -0
  175. fast_agent/resources/examples/mcp/elicitations/forms_demo.py +107 -0
  176. fast_agent/resources/examples/mcp/elicitations/game_character.py +65 -0
  177. fast_agent/resources/examples/mcp/elicitations/game_character_handler.py +256 -0
  178. fast_agent/resources/examples/mcp/elicitations/tool_call.py +21 -0
  179. fast_agent/resources/examples/mcp/state-transfer/agent_one.py +18 -0
  180. fast_agent/resources/examples/mcp/state-transfer/agent_two.py +18 -0
  181. fast_agent/resources/examples/mcp/state-transfer/fastagent.config.yaml +27 -0
  182. fast_agent/resources/examples/mcp/state-transfer/fastagent.secrets.yaml.example +15 -0
  183. fast_agent/resources/examples/researcher/fastagent.config.yaml +61 -0
  184. fast_agent/resources/examples/researcher/researcher-eval.py +53 -0
  185. fast_agent/resources/examples/researcher/researcher-imp.py +189 -0
  186. fast_agent/resources/examples/researcher/researcher.py +36 -0
  187. fast_agent/resources/examples/tensorzero/.env.sample +2 -0
  188. fast_agent/resources/examples/tensorzero/Makefile +31 -0
  189. fast_agent/resources/examples/tensorzero/README.md +56 -0
  190. fast_agent/resources/examples/tensorzero/agent.py +35 -0
  191. fast_agent/resources/examples/tensorzero/demo_images/clam.jpg +0 -0
  192. fast_agent/resources/examples/tensorzero/demo_images/crab.png +0 -0
  193. fast_agent/resources/examples/tensorzero/demo_images/shrimp.png +0 -0
  194. fast_agent/resources/examples/tensorzero/docker-compose.yml +105 -0
  195. fast_agent/resources/examples/tensorzero/fastagent.config.yaml +19 -0
  196. fast_agent/resources/examples/tensorzero/image_demo.py +67 -0
  197. fast_agent/resources/examples/tensorzero/mcp_server/Dockerfile +25 -0
  198. fast_agent/resources/examples/tensorzero/mcp_server/entrypoint.sh +35 -0
  199. fast_agent/resources/examples/tensorzero/mcp_server/mcp_server.py +31 -0
  200. fast_agent/resources/examples/tensorzero/mcp_server/pyproject.toml +11 -0
  201. fast_agent/resources/examples/tensorzero/simple_agent.py +25 -0
  202. fast_agent/resources/examples/tensorzero/tensorzero_config/system_schema.json +29 -0
  203. fast_agent/resources/examples/tensorzero/tensorzero_config/system_template.minijinja +11 -0
  204. fast_agent/resources/examples/tensorzero/tensorzero_config/tensorzero.toml +35 -0
  205. fast_agent/resources/examples/workflows/agents_as_tools_extended.py +73 -0
  206. fast_agent/resources/examples/workflows/agents_as_tools_simple.py +50 -0
  207. fast_agent/resources/examples/workflows/chaining.py +37 -0
  208. fast_agent/resources/examples/workflows/evaluator.py +77 -0
  209. fast_agent/resources/examples/workflows/fastagent.config.yaml +26 -0
  210. fast_agent/resources/examples/workflows/graded_report.md +89 -0
  211. fast_agent/resources/examples/workflows/human_input.py +28 -0
  212. fast_agent/resources/examples/workflows/maker.py +156 -0
  213. fast_agent/resources/examples/workflows/orchestrator.py +70 -0
  214. fast_agent/resources/examples/workflows/parallel.py +56 -0
  215. fast_agent/resources/examples/workflows/router.py +69 -0
  216. fast_agent/resources/examples/workflows/short_story.md +13 -0
  217. fast_agent/resources/examples/workflows/short_story.txt +19 -0
  218. fast_agent/resources/setup/.gitignore +30 -0
  219. fast_agent/resources/setup/agent.py +28 -0
  220. fast_agent/resources/setup/fastagent.config.yaml +65 -0
  221. fast_agent/resources/setup/fastagent.secrets.yaml.example +38 -0
  222. fast_agent/resources/setup/pyproject.toml.tmpl +23 -0
  223. fast_agent/skills/__init__.py +9 -0
  224. fast_agent/skills/registry.py +235 -0
  225. fast_agent/tools/elicitation.py +369 -0
  226. fast_agent/tools/shell_runtime.py +402 -0
  227. fast_agent/types/__init__.py +59 -0
  228. fast_agent/types/conversation_summary.py +294 -0
  229. fast_agent/types/llm_stop_reason.py +78 -0
  230. fast_agent/types/message_search.py +249 -0
  231. fast_agent/ui/__init__.py +38 -0
  232. fast_agent/ui/console.py +59 -0
  233. fast_agent/ui/console_display.py +1080 -0
  234. fast_agent/ui/elicitation_form.py +946 -0
  235. fast_agent/ui/elicitation_style.py +59 -0
  236. fast_agent/ui/enhanced_prompt.py +1400 -0
  237. fast_agent/ui/history_display.py +734 -0
  238. fast_agent/ui/interactive_prompt.py +1199 -0
  239. fast_agent/ui/markdown_helpers.py +104 -0
  240. fast_agent/ui/markdown_truncator.py +1004 -0
  241. fast_agent/ui/mcp_display.py +857 -0
  242. fast_agent/ui/mcp_ui_utils.py +235 -0
  243. fast_agent/ui/mermaid_utils.py +169 -0
  244. fast_agent/ui/message_primitives.py +50 -0
  245. fast_agent/ui/notification_tracker.py +205 -0
  246. fast_agent/ui/plain_text_truncator.py +68 -0
  247. fast_agent/ui/progress_display.py +10 -0
  248. fast_agent/ui/rich_progress.py +195 -0
  249. fast_agent/ui/streaming.py +774 -0
  250. fast_agent/ui/streaming_buffer.py +449 -0
  251. fast_agent/ui/tool_display.py +422 -0
  252. fast_agent/ui/usage_display.py +204 -0
  253. fast_agent/utils/__init__.py +5 -0
  254. fast_agent/utils/reasoning_stream_parser.py +77 -0
  255. fast_agent/utils/time.py +22 -0
  256. fast_agent/workflow_telemetry.py +261 -0
  257. fast_agent_mcp-0.4.7.dist-info/METADATA +788 -0
  258. fast_agent_mcp-0.4.7.dist-info/RECORD +261 -0
  259. fast_agent_mcp-0.4.7.dist-info/WHEEL +4 -0
  260. fast_agent_mcp-0.4.7.dist-info/entry_points.txt +7 -0
  261. fast_agent_mcp-0.4.7.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,48 @@
1
+ """
2
+ MCP Agent with UI support using mixin pattern.
3
+
4
+ This module provides a concrete agent class that combines McpAgent
5
+ with UI functionality through the mixin pattern.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from typing import TYPE_CHECKING, Any
11
+
12
+ from fast_agent.agents import McpAgent
13
+ from fast_agent.mcp.ui_mixin import McpUIMixin
14
+
15
+ if TYPE_CHECKING:
16
+ from fast_agent.context import Context
17
+
18
+
19
+ class McpAgentWithUI(McpUIMixin, McpAgent):
20
+ """
21
+ MCP Agent with UI resource handling capabilities.
22
+
23
+ This class combines the base McpAgent functionality with UI resource
24
+ processing using the mixin pattern. It's a clean, type-safe way to add
25
+ UI functionality without the complexity of wrapper classes.
26
+
27
+ Usage:
28
+ agent = McpAgentWithUI(config, context=context, ui_mode="auto")
29
+ """
30
+
31
+ def __init__(
32
+ self,
33
+ config,
34
+ context: "Context | None" = None,
35
+ ui_mode: str = "auto",
36
+ **kwargs: Any,
37
+ ) -> None:
38
+ """
39
+ Initialize the agent with UI capabilities.
40
+
41
+ Args:
42
+ config: Agent configuration
43
+ context: Application context
44
+ ui_mode: UI mode - "disabled", "enabled", or "auto"
45
+ **kwargs: Additional arguments passed to parent classes
46
+ """
47
+ # Initialize both parent classes with the ui_mode parameter
48
+ super().__init__(config=config, context=context, ui_mode=ui_mode, **kwargs)
@@ -0,0 +1,209 @@
1
+ """
2
+ MCP UI Mixin - Clean mixin pattern for MCP UI functionality.
3
+
4
+ This module provides a mixin class that can be combined with McpAgent
5
+ to add UI resource handling without modifying the base agent implementation.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from typing import TYPE_CHECKING, Sequence
11
+
12
+ from mcp.types import CallToolResult, ContentBlock, EmbeddedResource
13
+
14
+ from fast_agent.constants import MCP_UI
15
+ from fast_agent.ui.mcp_ui_utils import open_links_in_browser, ui_links_from_channel
16
+
17
+ if TYPE_CHECKING:
18
+ from rich.text import Text
19
+
20
+ from fast_agent.types import PromptMessageExtended
21
+
22
+
23
+ class McpUIMixin:
24
+ """
25
+ Mixin that adds MCP-UI resource handling to any agent.
26
+
27
+ This mixin can be combined with any agent class to add UI resource
28
+ extraction and display functionality. It overrides run_tools to
29
+ intercept tool results and extract UI resources.
30
+
31
+ Usage:
32
+ class MyAgentWithUI(McpUIMixin, McpAgent):
33
+ def __init__(self, *args, ui_mode: str = "auto", **kwargs):
34
+ super().__init__(*args, **kwargs)
35
+ self._ui_mode = ui_mode
36
+ """
37
+
38
+ def __init__(self, *args, ui_mode: str = "auto", **kwargs):
39
+ """Initialize the mixin with UI mode configuration."""
40
+ super().__init__(*args, **kwargs)
41
+ self._ui_mode: str = ui_mode
42
+ self._pending_ui_resources: list[ContentBlock] = []
43
+
44
+ def set_ui_mode(self, mode: str) -> None:
45
+ """
46
+ Set the UI mode for handling MCP-UI resources.
47
+
48
+ Args:
49
+ mode: One of "disabled", "enabled", or "auto"
50
+ """
51
+ if mode not in ("disabled", "enabled", "auto"):
52
+ mode = "auto"
53
+ self._ui_mode = mode
54
+
55
+ async def run_tools(self, request: "PromptMessageExtended") -> "PromptMessageExtended":
56
+ """
57
+ Override run_tools to extract and handle UI resources.
58
+
59
+ This method intercepts tool results, extracts any UI resources,
60
+ and adds them to the message channels for later display.
61
+ """
62
+ # If UI is disabled, just pass through to parent
63
+ if self._ui_mode == "disabled":
64
+ return await super().run_tools(request) # type: ignore
65
+
66
+ # Run the tools normally via parent implementation
67
+ result = await super().run_tools(request) # type: ignore
68
+
69
+ # Extract UI resources from tool results
70
+ if result and result.tool_results:
71
+ processed_results, ui_blocks = self._extract_ui_from_tool_results(result.tool_results)
72
+
73
+ # For mode 'auto', only act when we actually extracted something
74
+ if self._ui_mode == "enabled" or (self._ui_mode == "auto" and ui_blocks):
75
+ # Update tool_results with UI resources removed
76
+ result.tool_results = processed_results
77
+
78
+ # Add UI resources to channels
79
+ channels = result.channels or {}
80
+ current = channels.get(MCP_UI, [])
81
+ channels[MCP_UI] = current + ui_blocks
82
+ result.channels = channels
83
+
84
+ # Store for display after assistant message
85
+ self._pending_ui_resources = ui_blocks
86
+
87
+ return result
88
+
89
+ async def show_assistant_message(
90
+ self,
91
+ message: "PromptMessageExtended",
92
+ bottom_items: list[str] | None = None,
93
+ highlight_items: str | list[str] | None = None,
94
+ max_item_length: int | None = None,
95
+ name: str | None = None,
96
+ model: str | None = None,
97
+ additional_message: "Text" | None = None,
98
+ ) -> None:
99
+ """Override to display UI resources after showing assistant message."""
100
+ # Show the assistant message normally via parent
101
+ await super().show_assistant_message( # type: ignore
102
+ message,
103
+ bottom_items,
104
+ highlight_items,
105
+ max_item_length,
106
+ name=name,
107
+ model=model,
108
+ additional_message=additional_message,
109
+ )
110
+
111
+ # Handle any pending UI resources from the previous user message
112
+ if self._ui_mode != "disabled":
113
+ await self._display_ui_resources_from_history()
114
+
115
+ async def _display_ui_resources_from_history(self) -> None:
116
+ """
117
+ Check message history for UI resources and display them.
118
+
119
+ This looks at the previous user message for any UI resources
120
+ that should be displayed after the assistant's response.
121
+ """
122
+ try:
123
+ history = self.message_history # type: ignore
124
+ if history and len(history) >= 2:
125
+ prev = history[-2]
126
+ if prev and prev.role == "user":
127
+ channels = prev.channels or {}
128
+ ui_resources = channels.get(MCP_UI, []) if isinstance(channels, dict) else []
129
+ if ui_resources:
130
+ await self._display_ui_resources(ui_resources)
131
+ except Exception:
132
+ # Silently handle any errors in UI display
133
+ pass
134
+
135
+ async def _display_ui_resources(self, resources: Sequence[ContentBlock]) -> None:
136
+ """
137
+ Display UI resources by creating links and optionally opening in browser.
138
+
139
+ Args:
140
+ resources: List of UI resource content blocks
141
+ """
142
+ links = ui_links_from_channel(resources)
143
+ if links:
144
+ # Display links in console
145
+ await self.display.show_mcp_ui_links(links) # type: ignore
146
+
147
+ # Auto-open in browser if in auto mode
148
+ if self._ui_mode == "auto":
149
+ open_links_in_browser(links, mcp_ui_mode=self._ui_mode)
150
+
151
+ def _extract_ui_from_tool_results(
152
+ self,
153
+ tool_results: dict[str, CallToolResult],
154
+ ) -> tuple[dict[str, CallToolResult], list[ContentBlock]]:
155
+ """
156
+ Extract UI resources from tool results.
157
+
158
+ Returns a tuple of (cleaned_tool_results, extracted_ui_blocks).
159
+ """
160
+ if not tool_results:
161
+ return tool_results, []
162
+
163
+ extracted_ui: list[ContentBlock] = []
164
+ new_results: dict[str, CallToolResult] = {}
165
+
166
+ for key, result in tool_results.items():
167
+ try:
168
+ ui_blocks, other_blocks = self._split_ui_blocks(list(result.content or []))
169
+ if ui_blocks:
170
+ extracted_ui.extend(ui_blocks)
171
+
172
+ # Recreate CallToolResult without UI blocks
173
+ new_results[key] = CallToolResult(content=other_blocks, isError=result.isError)
174
+ except Exception:
175
+ # Pass through untouched on any error
176
+ new_results[key] = result
177
+
178
+ return new_results, extracted_ui
179
+
180
+ def _split_ui_blocks(
181
+ self, blocks: list[ContentBlock]
182
+ ) -> tuple[list[ContentBlock], list[ContentBlock]]:
183
+ """
184
+ Split content blocks into UI and non-UI blocks.
185
+
186
+ Returns tuple of (ui_blocks, other_blocks).
187
+ """
188
+ ui_blocks: list[ContentBlock] = []
189
+ other_blocks: list[ContentBlock] = []
190
+
191
+ for block in blocks or []:
192
+ if self._is_ui_embedded_resource(block):
193
+ ui_blocks.append(block)
194
+ else:
195
+ other_blocks.append(block)
196
+
197
+ return ui_blocks, other_blocks
198
+
199
+ def _is_ui_embedded_resource(self, block: ContentBlock) -> bool:
200
+ """Check if a content block is a UI embedded resource."""
201
+ try:
202
+ if isinstance(block, EmbeddedResource):
203
+ res = block.resource
204
+ uri = res.uri if res else None
205
+ if uri is not None:
206
+ return str(uri).startswith("ui://")
207
+ except Exception:
208
+ pass
209
+ return False
@@ -0,0 +1,89 @@
1
+ """
2
+ This module defines a `ServerRegistry` class for managing MCP server configurations
3
+ and initialization logic.
4
+
5
+ The class loads server configurations from a YAML file,
6
+ supports dynamic registration of initialization hooks, and provides methods for
7
+ server initialization.
8
+ """
9
+
10
+
11
+ from fast_agent.config import (
12
+ MCPServerSettings,
13
+ Settings,
14
+ get_settings,
15
+ )
16
+ from fast_agent.core.logging.logger import get_logger
17
+
18
+ logger = get_logger(__name__)
19
+
20
+
21
+ class ServerRegistry:
22
+ """
23
+ Maps MCP Server configurations to names; can be populated from a YAML file (other formats soon)
24
+
25
+ Attributes:
26
+ config_path (str): Path to the YAML configuration file.
27
+ registry (dict[str, MCPServerSettings]): Loaded server configurations.
28
+ """
29
+
30
+ registry: dict[str, MCPServerSettings] = {}
31
+
32
+ def __init__(
33
+ self,
34
+ config: Settings | None = None,
35
+ ) -> None:
36
+ """
37
+ Initialize the ServerRegistry with a configuration file.
38
+
39
+ Args:
40
+ config (Settings): The Settings object containing the server configurations.
41
+ config_path (str): Path to the YAML configuration file.
42
+ """
43
+ if config is not None and config.mcp is not None:
44
+ self.registry = config.mcp.servers or {}
45
+
46
+ ## TODO-- leaving this here to support more file formats to add servers
47
+ def load_registry_from_file(
48
+ self, config_path: str | None = None
49
+ ) -> dict[str, MCPServerSettings]:
50
+ """
51
+ Load the YAML configuration file and validate it.
52
+
53
+ Returns:
54
+ dict[str, MCPServerSettings]: A dictionary of server configurations.
55
+
56
+ Raises:
57
+ ValueError: If the configuration is invalid.
58
+ """
59
+ servers = {}
60
+
61
+ settings = get_settings(config_path)
62
+
63
+ if (
64
+ settings.mcp is not None
65
+ and hasattr(settings.mcp, "servers")
66
+ and settings.mcp.servers is not None
67
+ ):
68
+ return settings.mcp.servers
69
+
70
+ return servers
71
+
72
+ def get_server_config(self, server_name: str) -> MCPServerSettings | None:
73
+ """
74
+ Get the configuration for a specific server.
75
+
76
+ Args:
77
+ server_name (str): The name of the server.
78
+
79
+ Returns:
80
+ MCPServerSettings: The server configuration.
81
+ """
82
+
83
+ server_config = self.registry.get(server_name)
84
+ if server_config is None:
85
+ logger.warning(f"Server '{server_name}' not found in registry.")
86
+ return None
87
+ elif server_config.name is None:
88
+ server_config.name = server_name
89
+ return server_config
fast_agent/py.typed ADDED
File without changes
@@ -0,0 +1,189 @@
1
+ import asyncio
2
+
3
+ from fast_agent import FastAgent
4
+ from fast_agent.llm.fastagent_llm import RequestParams
5
+
6
+ # Create the application
7
+ fast = FastAgent("Data Analysis & Campaign Generator")
8
+
9
+
10
+ # Original data analysis components
11
+ @fast.agent(
12
+ name="data_analysis",
13
+ instruction="""
14
+ You have access to a Python 3.12 interpreter and you can use this to analyse and process data.
15
+ Common analysis packages such as Pandas, Seaborn and Matplotlib are already installed.
16
+ You can add further packages if needed.
17
+ Data files are accessible from the /mnt/data/ directory (this is the current working directory).
18
+ Visualisations should be saved as .png files in the current working directory.
19
+ Extract key insights that would be compelling for a social media campaign.
20
+ """,
21
+ servers=["interpreter"],
22
+ request_params=RequestParams(maxTokens=8192),
23
+ model="sonnet",
24
+ )
25
+ @fast.agent(
26
+ "evaluator",
27
+ """You are collaborating with a Data Analysis tool that has the capability to analyse data and produce visualisations.
28
+ You must make sure that the tool has:
29
+ - Considered the best way for a Human to interpret the data
30
+ - Produced insightful visualisations.
31
+ - Provided a high level summary report for the Human.
32
+ - Has had its findings challenged, and justified
33
+ - Extracted compelling insights suitable for social media promotion
34
+ """,
35
+ request_params=RequestParams(maxTokens=8192),
36
+ model="gpt-4.1",
37
+ )
38
+ @fast.evaluator_optimizer(
39
+ "analysis_tool",
40
+ generator="data_analysis",
41
+ evaluator="evaluator",
42
+ max_refinements=3,
43
+ min_rating="EXCELLENT",
44
+ )
45
+ # Research component using Brave search
46
+ @fast.agent(
47
+ "context_researcher",
48
+ """You are a research specialist who provides cultural context for different regions.
49
+ For any given data insight and target language/region, research:
50
+ 1. Cultural sensitivities related to presenting this type of data
51
+ 2. Local social media trends and preferences
52
+ 3. Region-specific considerations for marketing campaigns
53
+
54
+ Always provide actionable recommendations for adapting content to each culture.
55
+ """,
56
+ servers=["fetch", "brave"], # Using the fetch MCP server for Brave search
57
+ request_params=RequestParams(temperature=0.3),
58
+ model="gpt-4.1",
59
+ )
60
+ # Social media content generator
61
+ @fast.agent(
62
+ "campaign_generator",
63
+ """Generate engaging social media content based on data insights.
64
+ Create compelling, shareable content that:
65
+ - Highlights key research findings in an accessible way
66
+ - Uses appropriate tone for the platform (Twitter/X, LinkedIn, Instagram, etc.)
67
+ - Is concise and impactful
68
+ - Includes suggested hashtags and posting schedule
69
+
70
+ Format your response with clear sections for each platform.
71
+ Save different campaign elements as separate files in the current directory.
72
+ """,
73
+ servers=["filesystem"], # Using filesystem MCP server to save files
74
+ request_params=RequestParams(temperature=0.7),
75
+ model="sonnet",
76
+ use_history=False,
77
+ )
78
+ # Translation agents with cultural adaptation
79
+ @fast.agent(
80
+ "translate_fr",
81
+ """Translate social media content to French with cultural adaptation.
82
+ Consider French cultural norms, expressions, and social media preferences.
83
+ Ensure the translation maintains the impact of the original while being culturally appropriate.
84
+ Save the translated content to a file with appropriate naming.
85
+ """,
86
+ model="haiku",
87
+ use_history=False,
88
+ servers=["filesystem"],
89
+ )
90
+ @fast.agent(
91
+ "translate_es",
92
+ """Translate social media content to Spanish with cultural adaptation.
93
+ Consider Spanish-speaking cultural contexts, expressions, and social media preferences.
94
+ Ensure the translation maintains the impact of the original while being culturally appropriate.
95
+ Save the translated content to a file with appropriate naming.
96
+ """,
97
+ model="haiku",
98
+ use_history=False,
99
+ servers=["filesystem"],
100
+ )
101
+ @fast.agent(
102
+ "translate_de",
103
+ """Translate social media content to German with cultural adaptation.
104
+ Consider German cultural norms, expressions, and social media preferences.
105
+ Ensure the translation maintains the impact of the original while being culturally appropriate.
106
+ Save the translated content to a file with appropriate naming.
107
+ """,
108
+ model="haiku",
109
+ use_history=False,
110
+ servers=["filesystem"],
111
+ )
112
+ @fast.agent(
113
+ "translate_ja",
114
+ """Translate social media content to Japanese with cultural adaptation.
115
+ Consider Japanese cultural norms, expressions, and social media preferences.
116
+ Ensure the translation maintains the impact of the original while being culturally appropriate.
117
+ Save the translated content to a file with appropriate naming.
118
+ """,
119
+ model="haiku",
120
+ use_history=False,
121
+ servers=["filesystem"],
122
+ )
123
+ # Parallel workflow for translations
124
+ @fast.parallel(
125
+ "translate_campaign",
126
+ instruction="Translates content to French, Spanish, German and Japanese. Supply the content to translate, translations will be saved to the filesystem.",
127
+ fan_out=["translate_fr", "translate_es", "translate_de", "translate_ja"],
128
+ include_request=True,
129
+ )
130
+ # Cultural sensitivity review agent
131
+ @fast.agent(
132
+ "cultural_reviewer",
133
+ """Review all translated content for cultural sensitivity and appropriateness.
134
+ For each language version, evaluate:
135
+ - Cultural appropriateness
136
+ - Potential misunderstandings or sensitivities
137
+ - Effectiveness for the target culture
138
+
139
+ Provide specific recommendations for any needed adjustments and save a review report.
140
+ """,
141
+ servers=["filesystem"],
142
+ request_params=RequestParams(temperature=0.2),
143
+ )
144
+ # Campaign optimization workflow
145
+ @fast.evaluator_optimizer(
146
+ "campaign_optimizer",
147
+ generator="campaign_generator",
148
+ evaluator="cultural_reviewer",
149
+ max_refinements=2,
150
+ min_rating="EXCELLENT",
151
+ )
152
+ # Main workflow orchestration
153
+ @fast.orchestrator(
154
+ "research_campaign_creator",
155
+ instruction="""
156
+ Create a complete multi-lingual social media campaign based on data analysis results.
157
+ The workflow will:
158
+ 1. Analyze the provided data and extract key insights
159
+ 2. Research cultural contexts for target languages
160
+ 3. Generate appropriate social media content
161
+ 4. Translate and culturally adapt the content
162
+ 5. Review and optimize all materials
163
+ 6. Save all campaign elements to files
164
+ """,
165
+ agents=[
166
+ "analysis_tool",
167
+ "context_researcher",
168
+ "campaign_optimizer",
169
+ "translate_campaign",
170
+ ],
171
+ model="sonnet", # Using a more capable model for orchestration
172
+ request_params=RequestParams(maxTokens=8192),
173
+ plan_type="full",
174
+ )
175
+ async def main() -> None:
176
+ # Use the app's context manager
177
+ print(
178
+ "WARNING: This workflow will likely run for >10 minutes and consume a lot of tokens. Press Enter to accept the default prompt and proceed"
179
+ )
180
+
181
+ async with fast.run() as agent:
182
+ await agent.interactive(
183
+ "research_campaign_creator",
184
+ default_prompt="Analyze the CSV file in the current directory and create a comprehensive multi-lingual social media campaign based on the findings. Save all campaign elements as separate files.",
185
+ )
186
+
187
+
188
+ if __name__ == "__main__":
189
+ asyncio.run(main())
@@ -0,0 +1,68 @@
1
+ import asyncio
2
+
3
+ from fast_agent import FastAgent
4
+
5
+ # Create the application
6
+ fast = FastAgent("Data Analysis (Roots)")
7
+
8
+
9
+ # The sample data is under Database Contents License (DbCL) v1.0.
10
+ # Available here : https://www.kaggle.com/datasets/pavansubhasht/ibm-hr-analytics-attrition-dataset
11
+
12
+
13
+ @fast.agent(
14
+ name="data_analysis",
15
+ instruction="""
16
+ You have access to a Python 3.12 interpreter and you can use this to analyse and process data.
17
+ Common analysis packages such as Pandas, Seaborn and Matplotlib are already installed.
18
+ You can add further packages if needed.
19
+ Data files are accessible from the /mnt/data/ directory (this is the current working directory).
20
+ Visualisations should be saved as .png files in the current working directory.
21
+
22
+ {{serverInstructions}}
23
+
24
+ """,
25
+ servers=["interpreter"],
26
+ )
27
+ # @fast.agent(name="another_test", instruction="", servers=["filesystem"])
28
+ async def main() -> None:
29
+ # Use the app's context manager
30
+ async with fast.run() as agent:
31
+ await agent.interactive()
32
+ await agent.data_analysis(
33
+ "There is a csv file in the current directory. "
34
+ "Analyse the file, produce a detailed description of the data, and any patterns it contains.",
35
+ )
36
+ await agent.data_analysis(
37
+ "Consider the data, and how to usefully group it for presentation to a Human. Find insights, using the Python Interpreter as needed.\n"
38
+ "Use MatPlotLib to produce insightful visualisations. Save them as '.png' files in the current directory. Be sure to run the code and save the files.\n"
39
+ "Produce a summary with major insights to the data",
40
+ )
41
+ await agent()
42
+
43
+
44
+ if __name__ == "__main__":
45
+ asyncio.run(main())
46
+
47
+
48
+ ############################################################################################################
49
+ # Example of evaluator/optimizer flow
50
+ ############################################################################################################
51
+ # @fast.agent(
52
+ # "evaluator",
53
+ # """You are collaborating with a Data Analysis tool that has the capability to analyse data and produce visualisations.
54
+ # You must make sure that the tool has:
55
+ # - Considered the best way for a Human to interpret the data
56
+ # - Produced insightful visualasions.
57
+ # - Provided a high level summary report for the Human.
58
+ # - Has had its findings challenged, and justified
59
+ # """,
60
+ # request_params=RequestParams(maxTokens=8192),
61
+ # )
62
+ # @fast.evaluator_optimizer(
63
+ # "analysis_tool",
64
+ # generator="data_analysis",
65
+ # evaluator="evaluator",
66
+ # max_refinements=3,
67
+ # min_rating="EXCELLENT",
68
+ # )
@@ -0,0 +1,41 @@
1
+ default_model: sonnet
2
+
3
+ # on windows, adjust the mount point to be the full path e.g. x:/temp/data-analysis/mount-point:/mnt/data/
4
+
5
+ mcp:
6
+ servers:
7
+ interpreter:
8
+ command: "docker"
9
+ args:
10
+ [
11
+ "run",
12
+ "-i",
13
+ "--rm",
14
+ "--pull=always",
15
+ "-v",
16
+ "./mount-point:/mnt/data/",
17
+ "ghcr.io/evalstate/mcp-py-repl:latest",
18
+ ]
19
+ roots:
20
+ - uri: "file://./mount-point/"
21
+ name: "test_data"
22
+ server_uri_alias: "file:///mnt/data/"
23
+ filesystem:
24
+ # On windows update the command and arguments to use `node` and the absolute path to the server.
25
+ # Use `npm i -g @modelcontextprotocol/server-filesystem` to install the server globally.
26
+ # Use `npm -g root` to find the global node_modules path.`
27
+ # command: "node"
28
+ # args: ["c:/Program Files/nodejs/node_modules/@modelcontextprotocol/server-filesystem/dist/index.js","."]
29
+ command: "npx"
30
+ args: ["-y", "@modelcontextprotocol/server-filesystem", "./mount-point/"]
31
+ fetch:
32
+ command: "uvx"
33
+ args: ["mcp-server-fetch"]
34
+ brave:
35
+ # On windows replace the command and args line to use `node` and the absolute path to the server.
36
+ # Use `npm i -g @modelcontextprotocol/server-brave-search` to install the server globally.
37
+ # Use `npm -g root` to find the global node_modules path.`
38
+ # command: "node"
39
+ # args: ["c:/Program Files/nodejs/node_modules/@modelcontextprotocol/server-brave-search/dist/index.js"]
40
+ command: "npx"
41
+ args: ["-y", "@modelcontextprotocol/server-brave-search"]