fast-agent-mcp 0.1.12__py3-none-any.whl → 0.1.13__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 (126) hide show
  1. {fast_agent_mcp-0.1.12.dist-info → fast_agent_mcp-0.1.13.dist-info}/METADATA +1 -1
  2. fast_agent_mcp-0.1.13.dist-info/RECORD +164 -0
  3. mcp_agent/agents/agent.py +37 -79
  4. mcp_agent/app.py +16 -22
  5. mcp_agent/cli/commands/bootstrap.py +22 -52
  6. mcp_agent/cli/commands/config.py +4 -4
  7. mcp_agent/cli/commands/setup.py +11 -26
  8. mcp_agent/cli/main.py +6 -9
  9. mcp_agent/cli/terminal.py +2 -2
  10. mcp_agent/config.py +1 -5
  11. mcp_agent/context.py +13 -24
  12. mcp_agent/context_dependent.py +3 -7
  13. mcp_agent/core/agent_app.py +45 -121
  14. mcp_agent/core/agent_utils.py +3 -5
  15. mcp_agent/core/decorators.py +5 -12
  16. mcp_agent/core/enhanced_prompt.py +25 -52
  17. mcp_agent/core/exceptions.py +8 -8
  18. mcp_agent/core/factory.py +29 -70
  19. mcp_agent/core/fastagent.py +48 -88
  20. mcp_agent/core/mcp_content.py +8 -16
  21. mcp_agent/core/prompt.py +8 -15
  22. mcp_agent/core/proxies.py +34 -25
  23. mcp_agent/core/request_params.py +6 -3
  24. mcp_agent/core/types.py +4 -6
  25. mcp_agent/core/validation.py +4 -3
  26. mcp_agent/executor/decorator_registry.py +11 -23
  27. mcp_agent/executor/executor.py +8 -17
  28. mcp_agent/executor/task_registry.py +2 -4
  29. mcp_agent/executor/temporal.py +28 -74
  30. mcp_agent/executor/workflow.py +3 -5
  31. mcp_agent/executor/workflow_signal.py +17 -29
  32. mcp_agent/human_input/handler.py +4 -9
  33. mcp_agent/human_input/types.py +2 -3
  34. mcp_agent/logging/events.py +1 -5
  35. mcp_agent/logging/json_serializer.py +7 -6
  36. mcp_agent/logging/listeners.py +20 -23
  37. mcp_agent/logging/logger.py +15 -17
  38. mcp_agent/logging/rich_progress.py +10 -8
  39. mcp_agent/logging/tracing.py +4 -6
  40. mcp_agent/logging/transport.py +22 -22
  41. mcp_agent/mcp/gen_client.py +4 -12
  42. mcp_agent/mcp/interfaces.py +71 -86
  43. mcp_agent/mcp/mcp_agent_client_session.py +11 -19
  44. mcp_agent/mcp/mcp_agent_server.py +8 -10
  45. mcp_agent/mcp/mcp_aggregator.py +45 -117
  46. mcp_agent/mcp/mcp_connection_manager.py +16 -37
  47. mcp_agent/mcp/prompt_message_multipart.py +12 -18
  48. mcp_agent/mcp/prompt_serialization.py +13 -38
  49. mcp_agent/mcp/prompts/prompt_load.py +99 -0
  50. mcp_agent/mcp/prompts/prompt_server.py +21 -128
  51. mcp_agent/mcp/prompts/prompt_template.py +20 -42
  52. mcp_agent/mcp/resource_utils.py +8 -17
  53. mcp_agent/mcp/sampling.py +5 -14
  54. mcp_agent/mcp/stdio.py +11 -8
  55. mcp_agent/mcp_server/agent_server.py +10 -17
  56. mcp_agent/mcp_server_registry.py +13 -35
  57. mcp_agent/resources/examples/data-analysis/analysis-campaign.py +1 -1
  58. mcp_agent/resources/examples/data-analysis/analysis.py +1 -1
  59. mcp_agent/resources/examples/data-analysis/slides.py +110 -0
  60. mcp_agent/resources/examples/internal/agent.py +2 -1
  61. mcp_agent/resources/examples/internal/job.py +2 -1
  62. mcp_agent/resources/examples/internal/prompt_category.py +1 -1
  63. mcp_agent/resources/examples/internal/prompt_sizing.py +3 -5
  64. mcp_agent/resources/examples/internal/sizer.py +2 -1
  65. mcp_agent/resources/examples/internal/social.py +2 -1
  66. mcp_agent/resources/examples/mcp_researcher/researcher-eval.py +1 -1
  67. mcp_agent/resources/examples/prompting/agent.py +2 -1
  68. mcp_agent/resources/examples/prompting/image_server.py +5 -11
  69. mcp_agent/resources/examples/researcher/researcher-eval.py +1 -1
  70. mcp_agent/resources/examples/researcher/researcher-imp.py +3 -4
  71. mcp_agent/resources/examples/researcher/researcher.py +2 -1
  72. mcp_agent/resources/examples/workflows/agent_build.py +2 -1
  73. mcp_agent/resources/examples/workflows/chaining.py +2 -1
  74. mcp_agent/resources/examples/workflows/evaluator.py +2 -1
  75. mcp_agent/resources/examples/workflows/human_input.py +2 -1
  76. mcp_agent/resources/examples/workflows/orchestrator.py +2 -1
  77. mcp_agent/resources/examples/workflows/parallel.py +2 -1
  78. mcp_agent/resources/examples/workflows/router.py +2 -1
  79. mcp_agent/resources/examples/workflows/sse.py +1 -1
  80. mcp_agent/telemetry/usage_tracking.py +2 -1
  81. mcp_agent/ui/console_display.py +15 -39
  82. mcp_agent/workflows/embedding/embedding_base.py +1 -4
  83. mcp_agent/workflows/embedding/embedding_cohere.py +2 -2
  84. mcp_agent/workflows/embedding/embedding_openai.py +4 -13
  85. mcp_agent/workflows/evaluator_optimizer/evaluator_optimizer.py +23 -57
  86. mcp_agent/workflows/intent_classifier/intent_classifier_base.py +5 -8
  87. mcp_agent/workflows/intent_classifier/intent_classifier_embedding.py +7 -11
  88. mcp_agent/workflows/intent_classifier/intent_classifier_embedding_cohere.py +4 -8
  89. mcp_agent/workflows/intent_classifier/intent_classifier_embedding_openai.py +4 -8
  90. mcp_agent/workflows/intent_classifier/intent_classifier_llm.py +11 -22
  91. mcp_agent/workflows/intent_classifier/intent_classifier_llm_anthropic.py +3 -3
  92. mcp_agent/workflows/intent_classifier/intent_classifier_llm_openai.py +4 -6
  93. mcp_agent/workflows/llm/anthropic_utils.py +8 -29
  94. mcp_agent/workflows/llm/augmented_llm.py +69 -247
  95. mcp_agent/workflows/llm/augmented_llm_anthropic.py +39 -73
  96. mcp_agent/workflows/llm/augmented_llm_openai.py +42 -97
  97. mcp_agent/workflows/llm/augmented_llm_passthrough.py +13 -20
  98. mcp_agent/workflows/llm/augmented_llm_playback.py +8 -6
  99. mcp_agent/workflows/llm/memory.py +103 -0
  100. mcp_agent/workflows/llm/model_factory.py +8 -20
  101. mcp_agent/workflows/llm/openai_utils.py +1 -1
  102. mcp_agent/workflows/llm/prompt_utils.py +1 -3
  103. mcp_agent/workflows/llm/providers/multipart_converter_anthropic.py +47 -89
  104. mcp_agent/workflows/llm/providers/multipart_converter_openai.py +20 -55
  105. mcp_agent/workflows/llm/providers/openai_multipart.py +19 -61
  106. mcp_agent/workflows/llm/providers/sampling_converter_anthropic.py +10 -12
  107. mcp_agent/workflows/llm/providers/sampling_converter_openai.py +7 -11
  108. mcp_agent/workflows/llm/sampling_converter.py +4 -11
  109. mcp_agent/workflows/llm/sampling_format_converter.py +12 -12
  110. mcp_agent/workflows/orchestrator/orchestrator.py +24 -67
  111. mcp_agent/workflows/orchestrator/orchestrator_models.py +14 -40
  112. mcp_agent/workflows/parallel/fan_in.py +17 -47
  113. mcp_agent/workflows/parallel/fan_out.py +6 -12
  114. mcp_agent/workflows/parallel/parallel_llm.py +9 -26
  115. mcp_agent/workflows/router/router_base.py +19 -49
  116. mcp_agent/workflows/router/router_embedding.py +11 -25
  117. mcp_agent/workflows/router/router_embedding_cohere.py +2 -2
  118. mcp_agent/workflows/router/router_embedding_openai.py +2 -2
  119. mcp_agent/workflows/router/router_llm.py +12 -28
  120. mcp_agent/workflows/swarm/swarm.py +20 -48
  121. mcp_agent/workflows/swarm/swarm_anthropic.py +2 -2
  122. mcp_agent/workflows/swarm/swarm_openai.py +2 -2
  123. fast_agent_mcp-0.1.12.dist-info/RECORD +0 -161
  124. {fast_agent_mcp-0.1.12.dist-info → fast_agent_mcp-0.1.13.dist-info}/WHEEL +0 -0
  125. {fast_agent_mcp-0.1.12.dist-info → fast_agent_mcp-0.1.13.dist-info}/entry_points.txt +0 -0
  126. {fast_agent_mcp-0.1.12.dist-info → fast_agent_mcp-0.1.13.dist-info}/licenses/LICENSE +0 -0
@@ -7,7 +7,7 @@ Enables user-friendly error handling for common issues.
7
7
  class FastAgentError(Exception):
8
8
  """Base exception class for FastAgent errors"""
9
9
 
10
- def __init__(self, message: str, details: str = ""):
10
+ def __init__(self, message: str, details: str = "") -> None:
11
11
  self.message = message
12
12
  self.details = details
13
13
  super().__init__(f"{message}\n\n{details}" if details else message)
@@ -18,7 +18,7 @@ class ServerConfigError(FastAgentError):
18
18
  Example: Server name referenced in agent.servers[] but not defined in config
19
19
  """
20
20
 
21
- def __init__(self, message: str, details: str = ""):
21
+ def __init__(self, message: str, details: str = "") -> None:
22
22
  super().__init__(message, details)
23
23
 
24
24
 
@@ -27,7 +27,7 @@ class AgentConfigError(FastAgentError):
27
27
  Example: Parallel fan-in references unknown agent
28
28
  """
29
29
 
30
- def __init__(self, message: str, details: str = ""):
30
+ def __init__(self, message: str, details: str = "") -> None:
31
31
  super().__init__(message, details)
32
32
 
33
33
 
@@ -36,14 +36,14 @@ class ProviderKeyError(FastAgentError):
36
36
  Example: OpenAI/Anthropic key not configured but model requires it
37
37
  """
38
38
 
39
- def __init__(self, message: str, details: str = ""):
39
+ def __init__(self, message: str, details: str = "") -> None:
40
40
  super().__init__(message, details)
41
41
 
42
42
 
43
43
  class ServerInitializationError(FastAgentError):
44
44
  """Raised when a server fails to initialize properly."""
45
45
 
46
- def __init__(self, message: str, details: str = ""):
46
+ def __init__(self, message: str, details: str = "") -> None:
47
47
  super().__init__(message, details)
48
48
 
49
49
 
@@ -52,14 +52,14 @@ class ModelConfigError(FastAgentError):
52
52
  Example: Unknown model name in model specification string
53
53
  """
54
54
 
55
- def __init__(self, message: str, details: str = ""):
55
+ def __init__(self, message: str, details: str = "") -> None:
56
56
  super().__init__(message, details)
57
57
 
58
58
 
59
59
  class CircularDependencyError(FastAgentError):
60
60
  """Raised when we detect a Circular Dependency in the workflow"""
61
61
 
62
- def __init__(self, message: str, details: str = ""):
62
+ def __init__(self, message: str, details: str = "") -> None:
63
63
  super().__init__(message, details)
64
64
 
65
65
 
@@ -67,5 +67,5 @@ class PromptExitError(FastAgentError):
67
67
  """Raised from enhanced_prompt when the user requests hard exits"""
68
68
 
69
69
  # TODO an exception for flow control :(
70
- def __init__(self, message: str, details: str = ""):
70
+ def __init__(self, message: str, details: str = "") -> None:
71
71
  super().__init__(message, details)
mcp_agent/core/factory.py CHANGED
@@ -2,11 +2,22 @@
2
2
  Factory functions for creating agent and workflow instances.
3
3
  """
4
4
 
5
- from typing import Dict, Any, Optional, TypeVar, Callable
5
+ from typing import Any, Callable, Dict, Optional, TypeVar
6
6
 
7
- from mcp_agent.app import MCPApp
8
7
  from mcp_agent.agents.agent import Agent
8
+ from mcp_agent.app import MCPApp
9
9
  from mcp_agent.core.agent_types import AgentConfig, AgentType
10
+ from mcp_agent.core.agent_utils import get_agent_instances, log_agent_load, unwrap_proxy
11
+ from mcp_agent.core.exceptions import AgentConfigError
12
+ from mcp_agent.core.proxies import (
13
+ BaseAgentProxy,
14
+ ChainProxy,
15
+ LLMAgentProxy,
16
+ RouterProxy,
17
+ WorkflowProxy,
18
+ )
19
+ from mcp_agent.core.types import AgentOrWorkflow, ProxyDict
20
+ from mcp_agent.core.validation import get_dependencies
10
21
  from mcp_agent.event_progress import ProgressAction
11
22
  from mcp_agent.workflows.evaluator_optimizer.evaluator_optimizer import (
12
23
  EvaluatorOptimizerLLM,
@@ -17,24 +28,11 @@ from mcp_agent.workflows.llm.model_factory import ModelFactory
17
28
  from mcp_agent.workflows.orchestrator.orchestrator import Orchestrator
18
29
  from mcp_agent.workflows.parallel.parallel_llm import ParallelLLM
19
30
  from mcp_agent.workflows.router.router_llm import LLMRouter
20
- from mcp_agent.core.exceptions import AgentConfigError
21
- from mcp_agent.core.proxies import (
22
- BaseAgentProxy,
23
- LLMAgentProxy,
24
- WorkflowProxy,
25
- RouterProxy,
26
- ChainProxy,
27
- )
28
- from mcp_agent.core.types import AgentOrWorkflow, ProxyDict
29
- from mcp_agent.core.agent_utils import log_agent_load, unwrap_proxy, get_agent_instances
30
- from mcp_agent.core.validation import get_dependencies
31
31
 
32
32
  T = TypeVar("T") # For the wrapper classes
33
33
 
34
34
 
35
- def create_proxy(
36
- app: MCPApp, name: str, instance: AgentOrWorkflow, agent_type: str
37
- ) -> BaseAgentProxy:
35
+ def create_proxy(app: MCPApp, name: str, instance: AgentOrWorkflow, agent_type: str) -> BaseAgentProxy:
38
36
  """Create appropriate proxy type based on agent type and validate instance type
39
37
 
40
38
  Args:
@@ -61,27 +59,19 @@ def create_proxy(
61
59
  return LLMAgentProxy(app, name, instance)
62
60
  elif agent_type == AgentType.ORCHESTRATOR.value:
63
61
  if not isinstance(instance, Orchestrator):
64
- raise TypeError(
65
- f"Expected Orchestrator instance for {name}, got {type(instance)}"
66
- )
62
+ raise TypeError(f"Expected Orchestrator instance for {name}, got {type(instance)}")
67
63
  return WorkflowProxy(app, name, instance)
68
64
  elif agent_type == AgentType.PARALLEL.value:
69
65
  if not isinstance(instance, ParallelLLM):
70
- raise TypeError(
71
- f"Expected ParallelLLM instance for {name}, got {type(instance)}"
72
- )
66
+ raise TypeError(f"Expected ParallelLLM instance for {name}, got {type(instance)}")
73
67
  return WorkflowProxy(app, name, instance)
74
68
  elif agent_type == AgentType.EVALUATOR_OPTIMIZER.value:
75
69
  if not isinstance(instance, EvaluatorOptimizerLLM):
76
- raise TypeError(
77
- f"Expected EvaluatorOptimizerLLM instance for {name}, got {type(instance)}"
78
- )
70
+ raise TypeError(f"Expected EvaluatorOptimizerLLM instance for {name}, got {type(instance)}")
79
71
  return WorkflowProxy(app, name, instance)
80
72
  elif agent_type == AgentType.ROUTER.value:
81
73
  if not isinstance(instance, LLMRouter):
82
- raise TypeError(
83
- f"Expected LLMRouter instance for {name}, got {type(instance)}"
84
- )
74
+ raise TypeError(f"Expected LLMRouter instance for {name}, got {type(instance)}")
85
75
  return RouterProxy(app, name, instance)
86
76
  elif agent_type == AgentType.CHAIN.value:
87
77
  # Chain proxy is directly returned from _create_agents_by_type
@@ -187,11 +177,7 @@ async def create_agents_by_type(
187
177
 
188
178
  elif agent_type == AgentType.ORCHESTRATOR:
189
179
  # Get base params configured with model settings
190
- base_params = (
191
- config.default_request_params.model_copy()
192
- if config.default_request_params
193
- else RequestParams()
194
- )
180
+ base_params = config.default_request_params.model_copy() if config.default_request_params else RequestParams()
195
181
  base_params.use_history = False # Force no history for orchestrator
196
182
 
197
183
  # Get the child agents - need to unwrap proxies and validate LLM config
@@ -231,7 +217,6 @@ async def create_agents_by_type(
231
217
  )
232
218
 
233
219
  planner = await planner_agent.attach_llm(planner_factory)
234
- await planner.initialize()
235
220
  # Create the orchestrator with pre-configured planner
236
221
  instance = Orchestrator(
237
222
  name=config.name,
@@ -239,9 +224,7 @@ async def create_agents_by_type(
239
224
  available_agents=child_agents,
240
225
  context=app_instance.context,
241
226
  request_params=planner.default_request_params, # Base params already include model settings
242
- plan_type=agent_data.get(
243
- "plan_type", "full"
244
- ), # Get plan_type from agent_data
227
+ plan_type=agent_data.get("plan_type", "full"), # Get plan_type from agent_data
245
228
  verb=ProgressAction.PLANNING,
246
229
  )
247
230
 
@@ -251,19 +234,13 @@ async def create_agents_by_type(
251
234
  evaluator = unwrap_proxy(active_agents[agent_data["evaluator"]])
252
235
 
253
236
  if not generator or not evaluator:
254
- raise ValueError(
255
- f"Missing agents for workflow {name}: "
256
- f"generator={agent_data['generator']}, "
257
- f"evaluator={agent_data['evaluator']}"
258
- )
237
+ raise ValueError(f"Missing agents for workflow {name}: generator={agent_data['generator']}, evaluator={agent_data['evaluator']}")
259
238
 
260
239
  # Get model from generator if it's an Agent, or from config otherwise
261
240
  optimizer_model = None
262
241
  if isinstance(generator, Agent):
263
242
  optimizer_model = generator.config.model
264
- elif hasattr(generator, "_sequence") and hasattr(
265
- generator, "_agent_proxies"
266
- ):
243
+ elif hasattr(generator, "_sequence") and hasattr(generator, "_agent_proxies"):
267
244
  # For ChainProxy, use the config model directly
268
245
  optimizer_model = config.model
269
246
 
@@ -328,27 +305,19 @@ async def create_agents_by_type(
328
305
 
329
306
  # Generate a better description
330
307
  if agent_names:
331
- server_part = (
332
- f" with access to servers: {', '.join(sorted(all_servers))}"
333
- if all_servers
334
- else ""
335
- )
308
+ server_part = f" with access to servers: {', '.join(sorted(all_servers))}" if all_servers else ""
336
309
  config.instruction = f"Sequence of agents: {', '.join(agent_names)}{server_part}."
337
310
 
338
311
  # Create a ChainProxy without needing a new instance
339
312
  # Just pass the agent proxies and sequence
340
313
  instance = ChainProxy(app_instance, name, sequence, active_agents)
341
314
  # Set continue_with_final behavior from configuration
342
- instance._continue_with_final = agent_data.get(
343
- "continue_with_final", True
344
- )
315
+ instance._continue_with_final = agent_data.get("continue_with_final", True)
345
316
  # Set cumulative behavior from configuration
346
317
  instance._cumulative = agent_data.get("cumulative", False)
347
318
 
348
319
  elif agent_type == AgentType.PARALLEL:
349
- fan_out_agents = get_agent_instances(
350
- agent_data["fan_out"], active_agents
351
- )
320
+ fan_out_agents = get_agent_instances(agent_data["fan_out"], active_agents)
352
321
 
353
322
  # Get fan-in agent - unwrap proxy
354
323
  fan_in_agent = unwrap_proxy(active_agents[agent_data["fan_in"]])
@@ -370,9 +339,7 @@ async def create_agents_by_type(
370
339
  raise ValueError(f"Unsupported agent type: {agent_type}")
371
340
 
372
341
  # Create the appropriate proxy and store in results
373
- result_agents[name] = create_proxy(
374
- app_instance, name, instance, agent_type.value
375
- )
342
+ result_agents[name] = create_proxy(app_instance, name, instance, agent_type.value)
376
343
 
377
344
  return result_agents
378
345
 
@@ -426,24 +393,16 @@ async def create_agents_in_dependency_order(
426
393
  visited = set()
427
394
 
428
395
  # Get all agents of the specified type
429
- agent_names = [
430
- name
431
- for name, agent_data in agents_dict.items()
432
- if agent_data["type"] == agent_type.value
433
- ]
396
+ agent_names = [name for name, agent_data in agents_dict.items() if agent_data["type"] == agent_type.value]
434
397
 
435
398
  # Create agents in dependency order
436
399
  for name in agent_names:
437
400
  # Get ordered dependencies if not already processed
438
401
  if name not in visited:
439
402
  try:
440
- ordered_agents = get_dependencies(
441
- name, agents_dict, visited, set(), agent_type
442
- )
403
+ ordered_agents = get_dependencies(name, agents_dict, visited, set(), agent_type)
443
404
  except ValueError as e:
444
- raise ValueError(
445
- f"Error creating {agent_type.name.lower()} agent {name}: {str(e)}"
446
- )
405
+ raise ValueError(f"Error creating {agent_type.name.lower()} agent {name}: {str(e)}")
447
406
 
448
407
  # Create each agent in order
449
408
  for agent_name in ordered_agents:
@@ -3,61 +3,59 @@ Decorator-based interface for MCP Agent applications.
3
3
  Provides a simplified way to create and manage agents using decorators.
4
4
  """
5
5
 
6
+ import argparse
6
7
  import asyncio
8
+ from contextlib import asynccontextmanager
9
+ from functools import partial
7
10
  from typing import (
8
- Optional,
11
+ Any,
9
12
  Dict,
13
+ Optional,
10
14
  TypeVar,
11
- Any,
12
15
  )
16
+
13
17
  import yaml
14
- import argparse
15
- from contextlib import asynccontextmanager
16
- from functools import partial
18
+
19
+ # TODO -- reinstate once Windows&Python 3.13 platform issues are fixed
20
+ # import readline # noqa: F401
21
+ from rich import print
17
22
 
18
23
  from mcp_agent.app import MCPApp
19
24
  from mcp_agent.config import Settings
20
-
21
25
  from mcp_agent.core.agent_app import AgentApp
22
26
  from mcp_agent.core.agent_types import AgentType
27
+ from mcp_agent.core.decorators import (
28
+ _create_decorator,
29
+ agent,
30
+ chain,
31
+ evaluator_optimizer,
32
+ orchestrator,
33
+ parallel,
34
+ passthrough,
35
+ router,
36
+ )
23
37
  from mcp_agent.core.error_handling import handle_error
24
- from mcp_agent.core.proxies import LLMAgentProxy
25
- from mcp_agent.core.types import ProxyDict
26
38
  from mcp_agent.core.exceptions import (
27
39
  AgentConfigError,
28
40
  CircularDependencyError,
29
41
  ModelConfigError,
30
42
  PromptExitError,
31
- ServerConfigError,
32
43
  ProviderKeyError,
44
+ ServerConfigError,
33
45
  ServerInitializationError,
34
46
  )
35
- from mcp_agent.core.decorators import (
36
- _create_decorator,
37
- agent,
38
- orchestrator,
39
- parallel,
40
- evaluator_optimizer,
41
- router,
42
- chain,
43
- passthrough,
47
+ from mcp_agent.core.factory import (
48
+ create_agents_by_type,
49
+ create_agents_in_dependency_order,
50
+ create_basic_agents,
51
+ get_model_factory,
44
52
  )
53
+ from mcp_agent.core.proxies import LLMAgentProxy
54
+ from mcp_agent.core.types import ProxyDict
45
55
  from mcp_agent.core.validation import (
46
56
  validate_server_references,
47
57
  validate_workflow_references,
48
58
  )
49
- from mcp_agent.core.factory import (
50
- get_model_factory,
51
- create_basic_agents,
52
- create_agents_in_dependency_order,
53
- create_agents_by_type,
54
- )
55
-
56
- # TODO -- reinstate once Windows&Python 3.13 platform issues are fixed
57
- # import readline # noqa: F401
58
-
59
- from rich import print
60
-
61
59
  from mcp_agent.mcp_server import AgentMCPServer
62
60
 
63
61
  T = TypeVar("T") # For the wrapper classes
@@ -74,7 +72,7 @@ class FastAgent:
74
72
  name: str,
75
73
  config_path: Optional[str] = None,
76
74
  ignore_unknown_args: bool = False,
77
- ):
75
+ ) -> None:
78
76
  """
79
77
  Initialize the decorator interface.
80
78
 
@@ -218,9 +216,7 @@ class FastAgent:
218
216
  model_factory_func = partial(self._get_model_factory)
219
217
  return await create_basic_agents(agent_app, self.agents, model_factory_func)
220
218
 
221
- async def _create_orchestrators(
222
- self, agent_app: MCPApp, active_agents: ProxyDict
223
- ) -> ProxyDict:
219
+ async def _create_orchestrators(self, agent_app: MCPApp, active_agents: ProxyDict) -> ProxyDict:
224
220
  """
225
221
  Create orchestrator agents.
226
222
 
@@ -231,13 +227,9 @@ class FastAgent:
231
227
  Returns:
232
228
  Dictionary of initialized orchestrator agents wrapped in appropriate proxies
233
229
  """
234
- return await self._create_agents_by_type(
235
- agent_app, AgentType.ORCHESTRATOR, active_agents
236
- )
230
+ return await self._create_agents_by_type(agent_app, AgentType.ORCHESTRATOR, active_agents)
237
231
 
238
- async def _create_evaluator_optimizers(
239
- self, agent_app: MCPApp, active_agents: ProxyDict
240
- ) -> ProxyDict:
232
+ async def _create_evaluator_optimizers(self, agent_app: MCPApp, active_agents: ProxyDict) -> ProxyDict:
241
233
  """
242
234
  Create evaluator-optimizer workflows.
243
235
 
@@ -248,13 +240,9 @@ class FastAgent:
248
240
  Returns:
249
241
  Dictionary of initialized evaluator-optimizer workflows
250
242
  """
251
- return await self._create_agents_by_type(
252
- agent_app, AgentType.EVALUATOR_OPTIMIZER, active_agents
253
- )
243
+ return await self._create_agents_by_type(agent_app, AgentType.EVALUATOR_OPTIMIZER, active_agents)
254
244
 
255
- async def _create_parallel_agents(
256
- self, agent_app: MCPApp, active_agents: ProxyDict
257
- ) -> ProxyDict:
245
+ async def _create_parallel_agents(self, agent_app: MCPApp, active_agents: ProxyDict) -> ProxyDict:
258
246
  """
259
247
  Create parallel execution agents in dependency order.
260
248
 
@@ -274,9 +262,7 @@ class FastAgent:
274
262
  model_factory_func,
275
263
  )
276
264
 
277
- async def _create_agents_in_dependency_order(
278
- self, agent_app: MCPApp, active_agents: ProxyDict, agent_type: AgentType
279
- ) -> ProxyDict:
265
+ async def _create_agents_in_dependency_order(self, agent_app: MCPApp, active_agents: ProxyDict, agent_type: AgentType) -> ProxyDict:
280
266
  """
281
267
  Create agents in dependency order to avoid circular references.
282
268
  Works for both Parallel and Chain workflows.
@@ -290,13 +276,9 @@ class FastAgent:
290
276
  Dictionary of initialized agents
291
277
  """
292
278
  model_factory_func = partial(self._get_model_factory)
293
- return await create_agents_in_dependency_order(
294
- agent_app, self.agents, active_agents, agent_type, model_factory_func
295
- )
279
+ return await create_agents_in_dependency_order(agent_app, self.agents, active_agents, agent_type, model_factory_func)
296
280
 
297
- async def _create_routers(
298
- self, agent_app: MCPApp, active_agents: ProxyDict
299
- ) -> ProxyDict:
281
+ async def _create_routers(self, agent_app: MCPApp, active_agents: ProxyDict) -> ProxyDict:
300
282
  """
301
283
  Create router agents.
302
284
 
@@ -307,9 +289,7 @@ class FastAgent:
307
289
  Returns:
308
290
  Dictionary of initialized router agents
309
291
  """
310
- return await self._create_agents_by_type(
311
- agent_app, AgentType.ROUTER, active_agents
312
- )
292
+ return await self._create_agents_by_type(agent_app, AgentType.ROUTER, active_agents)
313
293
 
314
294
  @asynccontextmanager
315
295
  async def run(self):
@@ -327,11 +307,7 @@ class FastAgent:
327
307
  try:
328
308
  async with self.app.run() as agent_app:
329
309
  # Apply quiet mode directly to the context's config if needed
330
- if (
331
- quiet_mode
332
- and hasattr(agent_app.context, "config")
333
- and hasattr(agent_app.context.config, "logger")
334
- ):
310
+ if quiet_mode and hasattr(agent_app.context, "config") and hasattr(agent_app.context.config, "logger"):
335
311
  # Apply after initialization but before agents are created
336
312
  agent_app.context.config.logger.progress_display = False
337
313
  agent_app.context.config.logger.show_chat = False
@@ -351,9 +327,7 @@ class FastAgent:
351
327
  active_agents = await self._create_basic_agents(agent_app)
352
328
 
353
329
  # Create parallel agents next as they might be dependencies
354
- parallel_agents = await self._create_parallel_agents(
355
- agent_app, active_agents
356
- )
330
+ parallel_agents = await self._create_parallel_agents(agent_app, active_agents)
357
331
  active_agents.update(parallel_agents)
358
332
 
359
333
  # Create routers next
@@ -361,21 +335,15 @@ class FastAgent:
361
335
  active_agents.update(routers)
362
336
 
363
337
  # Create chains next - MOVED UP because evaluator-optimizers might depend on chains
364
- chains = await self._create_agents_in_dependency_order(
365
- agent_app, active_agents, AgentType.CHAIN
366
- )
338
+ chains = await self._create_agents_in_dependency_order(agent_app, active_agents, AgentType.CHAIN)
367
339
  active_agents.update(chains)
368
340
 
369
341
  # Now create evaluator-optimizers AFTER chains are available
370
- evaluator_optimizers = await self._create_evaluator_optimizers(
371
- agent_app, active_agents
372
- )
342
+ evaluator_optimizers = await self._create_evaluator_optimizers(agent_app, active_agents)
373
343
  active_agents.update(evaluator_optimizers)
374
344
 
375
345
  # Create orchestrators last as they might depend on any other agent type
376
- orchestrators = await self._create_orchestrators(
377
- agent_app, active_agents
378
- )
346
+ orchestrators = await self._create_orchestrators(agent_app, active_agents)
379
347
 
380
348
  # Add orchestrators to active_agents (other types were already added)
381
349
  active_agents.update(orchestrators)
@@ -393,9 +361,7 @@ class FastAgent:
393
361
 
394
362
  if agent_name not in active_agents:
395
363
  available_agents = ", ".join(active_agents.keys())
396
- print(
397
- f"\n\nError: Agent '{agent_name}' not found. Available agents: {available_agents}"
398
- )
364
+ print(f"\n\nError: Agent '{agent_name}' not found. Available agents: {available_agents}")
399
365
  raise SystemExit(1)
400
366
 
401
367
  try:
@@ -408,9 +374,7 @@ class FastAgent:
408
374
 
409
375
  raise SystemExit(0)
410
376
  except Exception as e:
411
- print(
412
- f"\n\nError sending message to agent '{agent_name}': {str(e)}"
413
- )
377
+ print(f"\n\nError sending message to agent '{agent_name}': {str(e)}")
414
378
  raise SystemExit(1)
415
379
 
416
380
  yield wrapper
@@ -488,9 +452,7 @@ class FastAgent:
488
452
  print(f"DEBUG {e.message}")
489
453
  pass # Ignore cleanup errors
490
454
 
491
- def _handle_error(
492
- self, e: Exception, error_type: str, suggestion: str = None
493
- ) -> None:
455
+ def _handle_error(self, e: Exception, error_type: str, suggestion: str = None) -> None:
494
456
  """
495
457
  Handle errors with consistent formatting and messaging.
496
458
 
@@ -535,7 +497,7 @@ class FastAgent:
535
497
  port: int = 8000,
536
498
  server_name: str = None,
537
499
  server_description: str = None,
538
- ):
500
+ ) -> None:
539
501
  """
540
502
  Run the FastAgent application and expose agents through an MCP server.
541
503
 
@@ -555,9 +517,7 @@ class FastAgent:
555
517
  )
556
518
 
557
519
  # Run the MCP server in a separate task
558
- server_task = asyncio.create_task(
559
- mcp_server.run_async(transport=transport, host=host, port=port)
560
- )
520
+ server_task = asyncio.create_task(mcp_server.run_async(transport=transport, host=host, port=port))
561
521
 
562
522
  try:
563
523
  # Wait for the server task to complete (or be cancelled)
@@ -7,14 +7,14 @@ EmbeddedResource, and other MCP content types with minimal boilerplate.
7
7
 
8
8
  import base64
9
9
  from pathlib import Path
10
- from typing import Literal, Optional, Union, List, Any
10
+ from typing import Any, List, Literal, Optional, Union
11
11
 
12
12
  from mcp.types import (
13
- TextContent,
14
- ImageContent,
13
+ BlobResourceContents,
15
14
  EmbeddedResource,
15
+ ImageContent,
16
+ TextContent,
16
17
  TextResourceContents,
17
- BlobResourceContents,
18
18
  )
19
19
 
20
20
  from mcp_agent.mcp.mime_utils import (
@@ -86,9 +86,7 @@ def MCPImage(
86
86
 
87
87
  return {
88
88
  "role": role,
89
- "content": ImageContent(
90
- type="image", data=b64_data, mimeType=mime_type, annotations=annotations
91
- ),
89
+ "content": ImageContent(type="image", data=b64_data, mimeType=mime_type, annotations=annotations),
92
90
  }
93
91
 
94
92
 
@@ -134,21 +132,15 @@ def MCPFile(
134
132
  # Fallback to binary if text read fails
135
133
  binary_data = path.read_bytes()
136
134
  b64_data = base64.b64encode(binary_data).decode("ascii")
137
- resource = BlobResourceContents(
138
- uri=uri, blob=b64_data, mimeType=mime_type or "application/octet-stream"
139
- )
135
+ resource = BlobResourceContents(uri=uri, blob=b64_data, mimeType=mime_type or "application/octet-stream")
140
136
 
141
137
  return {
142
138
  "role": role,
143
- "content": EmbeddedResource(
144
- type="resource", resource=resource, annotations=annotations
145
- ),
139
+ "content": EmbeddedResource(type="resource", resource=resource, annotations=annotations),
146
140
  }
147
141
 
148
142
 
149
- def MCPPrompt(
150
- *content_items, role: Literal["user", "assistant"] = "user"
151
- ) -> List[dict]:
143
+ def MCPPrompt(*content_items, role: Literal["user", "assistant"] = "user") -> List[dict]:
152
144
  """
153
145
  Create one or more prompt messages with various content types.
154
146
 
mcp_agent/core/prompt.py CHANGED
@@ -5,10 +5,11 @@ Prompt class for easily creating and working with MCP prompt content.
5
5
  from typing import List, Literal
6
6
 
7
7
  from mcp.types import PromptMessage
8
+
8
9
  from mcp_agent.mcp.prompt_message_multipart import PromptMessageMultipart
9
10
 
10
11
  # Import our content helper functions
11
- from .mcp_content import User, Assistant, MCPPrompt
12
+ from .mcp_content import Assistant, MCPPrompt, User
12
13
 
13
14
 
14
15
  class Prompt:
@@ -39,9 +40,7 @@ class Prompt:
39
40
  A PromptMessageMultipart with user role and the specified content
40
41
  """
41
42
  messages = User(*content_items)
42
- return PromptMessageMultipart(
43
- role="user", content=[msg["content"] for msg in messages]
44
- )
43
+ return PromptMessageMultipart(role="user", content=[msg["content"] for msg in messages])
45
44
 
46
45
  @classmethod
47
46
  def assistant(cls, *content_items) -> PromptMessageMultipart:
@@ -55,14 +54,10 @@ class Prompt:
55
54
  A PromptMessageMultipart with assistant role and the specified content
56
55
  """
57
56
  messages = Assistant(*content_items)
58
- return PromptMessageMultipart(
59
- role="assistant", content=[msg["content"] for msg in messages]
60
- )
57
+ return PromptMessageMultipart(role="assistant", content=[msg["content"] for msg in messages])
61
58
 
62
59
  @classmethod
63
- def message(
64
- cls, *content_items, role: Literal["user", "assistant"] = "user"
65
- ) -> PromptMessageMultipart:
60
+ def message(cls, *content_items, role: Literal["user", "assistant"] = "user") -> PromptMessageMultipart:
66
61
  """
67
62
  Create a PromptMessageMultipart with the specified role and content items.
68
63
 
@@ -100,7 +95,7 @@ class Prompt:
100
95
  for item in messages:
101
96
  if isinstance(item, PromptMessageMultipart):
102
97
  # Convert PromptMessageMultipart to a list of PromptMessages
103
- result.extend(item.to_prompt_messages())
98
+ result.extend(item.from_multipart())
104
99
  elif isinstance(item, dict) and "role" in item and "content" in item:
105
100
  # Convert a single message dict to PromptMessage
106
101
  result.append(PromptMessage(**item))
@@ -114,9 +109,7 @@ class Prompt:
114
109
  return result
115
110
 
116
111
  @classmethod
117
- def from_multipart(
118
- cls, multipart: List[PromptMessageMultipart]
119
- ) -> List[PromptMessage]:
112
+ def from_multipart(cls, multipart: List[PromptMessageMultipart]) -> List[PromptMessage]:
120
113
  """
121
114
  Convert a list of PromptMessageMultipart objects to PromptMessages.
122
115
 
@@ -128,5 +121,5 @@ class Prompt:
128
121
  """
129
122
  result = []
130
123
  for mp in multipart:
131
- result.extend(mp.to_prompt_messages())
124
+ result.extend(mp.from_multipart())
132
125
  return result