fast-agent-mcp 0.2.24__tar.gz → 0.2.26__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/PKG-INFO +8 -5
  2. fast_agent_mcp-0.2.26/examples/azure-openai/fastagent.config.yaml +54 -0
  3. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/pyproject.toml +14 -5
  4. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/cli/commands/check_config.py +61 -28
  5. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/config.py +17 -0
  6. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/event_progress.py +1 -0
  7. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/llm/model_factory.py +2 -0
  8. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/llm/provider_types.py +1 -0
  9. fast_agent_mcp-0.2.26/src/mcp_agent/llm/providers/augmented_llm_azure.py +137 -0
  10. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/llm/providers/augmented_llm_openai.py +5 -6
  11. fast_agent_mcp-0.2.26/src/mcp_agent/mcp/common.py +16 -0
  12. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/mcp/mcp_aggregator.py +16 -22
  13. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/ui/console_display.py +28 -1
  14. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/.gitignore +0 -0
  15. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/LICENSE +0 -0
  16. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/README.md +0 -0
  17. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/data-analysis/analysis-campaign.py +0 -0
  18. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/data-analysis/analysis.py +0 -0
  19. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/data-analysis/fastagent.config.yaml +0 -0
  20. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/data-analysis/mount-point/WA_Fn-UseC_-HR-Employee-Attrition.csv +0 -0
  21. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/mcp/state-transfer/agent_one.py +0 -0
  22. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/mcp/state-transfer/agent_two.py +0 -0
  23. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/mcp/state-transfer/fastagent.config.yaml +0 -0
  24. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/mcp/vision-examples/example1.py +0 -0
  25. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/mcp/vision-examples/example2.py +0 -0
  26. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/mcp/vision-examples/example3.py +0 -0
  27. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/mcp/vision-examples/fastagent.config.yaml +0 -0
  28. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/otel/agent.py +0 -0
  29. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/otel/agent2.py +0 -0
  30. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/otel/docker-compose.yaml +0 -0
  31. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/otel/fastagent.config.yaml +0 -0
  32. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/researcher/fastagent.config.yaml +0 -0
  33. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/researcher/researcher-eval.py +0 -0
  34. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/researcher/researcher-imp.py +0 -0
  35. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/researcher/researcher.py +0 -0
  36. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/tensorzero/README.md +0 -0
  37. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/tensorzero/agent.py +0 -0
  38. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/tensorzero/docker-compose.yml +0 -0
  39. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/tensorzero/fastagent.config.yaml +0 -0
  40. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/tensorzero/image_demo.py +0 -0
  41. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/tensorzero/mcp_server/mcp_server.py +0 -0
  42. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/tensorzero/simple_agent.py +0 -0
  43. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/workflows/chaining.py +0 -0
  44. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/workflows/evaluator.py +0 -0
  45. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/workflows/fastagent.config.yaml +0 -0
  46. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/workflows/graded_report.md +0 -0
  47. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/workflows/human_input.py +0 -0
  48. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/workflows/orchestrator.py +0 -0
  49. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/workflows/parallel.py +0 -0
  50. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/workflows/router.py +0 -0
  51. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/workflows/short_story.md +0 -0
  52. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/examples/workflows/short_story.txt +0 -0
  53. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/__init__.py +0 -0
  54. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/agents/__init__.py +0 -0
  55. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/agents/agent.py +0 -0
  56. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/agents/base_agent.py +0 -0
  57. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/agents/workflow/__init__.py +0 -0
  58. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/agents/workflow/chain_agent.py +0 -0
  59. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/agents/workflow/evaluator_optimizer.py +0 -0
  60. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/agents/workflow/orchestrator_agent.py +0 -0
  61. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/agents/workflow/orchestrator_models.py +0 -0
  62. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/agents/workflow/orchestrator_prompts.py +0 -0
  63. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/agents/workflow/parallel_agent.py +0 -0
  64. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/agents/workflow/router_agent.py +0 -0
  65. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/app.py +0 -0
  66. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/cli/__init__.py +0 -0
  67. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/cli/__main__.py +0 -0
  68. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/cli/commands/go.py +0 -0
  69. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/cli/commands/quickstart.py +0 -0
  70. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/cli/commands/setup.py +0 -0
  71. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/cli/commands/url_parser.py +0 -0
  72. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/cli/main.py +0 -0
  73. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/cli/terminal.py +0 -0
  74. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/console.py +0 -0
  75. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/context.py +0 -0
  76. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/context_dependent.py +0 -0
  77. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/core/__init__.py +0 -0
  78. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/core/agent_app.py +0 -0
  79. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/core/agent_types.py +0 -0
  80. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/core/direct_decorators.py +0 -0
  81. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/core/direct_factory.py +0 -0
  82. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/core/enhanced_prompt.py +0 -0
  83. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/core/error_handling.py +0 -0
  84. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/core/exceptions.py +0 -0
  85. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/core/fastagent.py +0 -0
  86. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/core/interactive_prompt.py +0 -0
  87. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/core/mcp_content.py +0 -0
  88. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/core/prompt.py +0 -0
  89. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/core/request_params.py +0 -0
  90. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/core/validation.py +0 -0
  91. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/executor/__init__.py +0 -0
  92. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/executor/executor.py +0 -0
  93. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/executor/task_registry.py +0 -0
  94. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/executor/workflow_signal.py +0 -0
  95. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/human_input/__init__.py +0 -0
  96. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/human_input/handler.py +0 -0
  97. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/human_input/types.py +0 -0
  98. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/llm/__init__.py +0 -0
  99. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/llm/augmented_llm.py +0 -0
  100. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/llm/augmented_llm_passthrough.py +0 -0
  101. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/llm/augmented_llm_playback.py +0 -0
  102. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/llm/memory.py +0 -0
  103. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/llm/prompt_utils.py +0 -0
  104. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/llm/provider_key_manager.py +0 -0
  105. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/llm/providers/__init__.py +0 -0
  106. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/llm/providers/anthropic_utils.py +0 -0
  107. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/llm/providers/augmented_llm_anthropic.py +0 -0
  108. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/llm/providers/augmented_llm_deepseek.py +0 -0
  109. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/llm/providers/augmented_llm_generic.py +0 -0
  110. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/llm/providers/augmented_llm_google.py +0 -0
  111. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/llm/providers/augmented_llm_openrouter.py +0 -0
  112. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/llm/providers/augmented_llm_tensorzero.py +0 -0
  113. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/llm/providers/multipart_converter_anthropic.py +0 -0
  114. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/llm/providers/multipart_converter_openai.py +0 -0
  115. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/llm/providers/multipart_converter_tensorzero.py +0 -0
  116. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/llm/providers/openai_multipart.py +0 -0
  117. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/llm/providers/openai_utils.py +0 -0
  118. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/llm/providers/sampling_converter_anthropic.py +0 -0
  119. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/llm/providers/sampling_converter_openai.py +0 -0
  120. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/llm/sampling_converter.py +0 -0
  121. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/llm/sampling_format_converter.py +0 -0
  122. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/logging/__init__.py +0 -0
  123. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/logging/events.py +0 -0
  124. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/logging/json_serializer.py +0 -0
  125. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/logging/listeners.py +0 -0
  126. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/logging/logger.py +0 -0
  127. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/logging/rich_progress.py +0 -0
  128. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/logging/transport.py +0 -0
  129. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/mcp/__init__.py +0 -0
  130. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/mcp/gen_client.py +0 -0
  131. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/mcp/helpers/__init__.py +0 -0
  132. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/mcp/helpers/content_helpers.py +0 -0
  133. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/mcp/interfaces.py +0 -0
  134. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/mcp/logger_textio.py +0 -0
  135. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/mcp/mcp_agent_client_session.py +0 -0
  136. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/mcp/mcp_connection_manager.py +0 -0
  137. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/mcp/mime_utils.py +0 -0
  138. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/mcp/prompt_message_multipart.py +0 -0
  139. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/mcp/prompt_render.py +0 -0
  140. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/mcp/prompt_serialization.py +0 -0
  141. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/mcp/prompts/__init__.py +0 -0
  142. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/mcp/prompts/__main__.py +0 -0
  143. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/mcp/prompts/prompt_constants.py +0 -0
  144. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/mcp/prompts/prompt_helpers.py +0 -0
  145. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/mcp/prompts/prompt_load.py +0 -0
  146. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/mcp/prompts/prompt_server.py +0 -0
  147. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/mcp/prompts/prompt_template.py +0 -0
  148. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/mcp/resource_utils.py +0 -0
  149. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/mcp/sampling.py +0 -0
  150. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/mcp_server/__init__.py +0 -0
  151. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/mcp_server/agent_server.py +0 -0
  152. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/mcp_server_registry.py +0 -0
  153. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/progress_display.py +0 -0
  154. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/data-analysis/analysis-campaign.py +0 -0
  155. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/data-analysis/analysis.py +0 -0
  156. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/data-analysis/fastagent.config.yaml +0 -0
  157. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/data-analysis/mount-point/WA_Fn-UseC_-HR-Employee-Attrition.csv +0 -0
  158. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/in_dev/agent_build.py +0 -0
  159. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/in_dev/css-LICENSE.txt +0 -0
  160. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/in_dev/slides.py +0 -0
  161. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/internal/agent.py +0 -0
  162. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/internal/fastagent.config.yaml +0 -0
  163. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/internal/history_transfer.py +0 -0
  164. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/internal/job.py +0 -0
  165. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/internal/prompt_category.py +0 -0
  166. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/internal/prompt_sizing.py +0 -0
  167. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/internal/simple.txt +0 -0
  168. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/internal/sizer.py +0 -0
  169. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/internal/social.py +0 -0
  170. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/mcp/state-transfer/agent_one.py +0 -0
  171. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/mcp/state-transfer/agent_two.py +0 -0
  172. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/mcp/state-transfer/fastagent.config.yaml +0 -0
  173. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/mcp/state-transfer/fastagent.secrets.yaml.example +0 -0
  174. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/prompting/__init__.py +0 -0
  175. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/prompting/agent.py +0 -0
  176. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/prompting/delimited_prompt.txt +0 -0
  177. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/prompting/fastagent.config.yaml +0 -0
  178. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/prompting/image_server.py +0 -0
  179. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/prompting/prompt1.txt +0 -0
  180. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/prompting/work_with_image.py +0 -0
  181. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/researcher/fastagent.config.yaml +0 -0
  182. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/researcher/researcher-eval.py +0 -0
  183. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/researcher/researcher-imp.py +0 -0
  184. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/researcher/researcher.py +0 -0
  185. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/workflows/chaining.py +0 -0
  186. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/workflows/evaluator.py +0 -0
  187. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/workflows/fastagent.config.yaml +0 -0
  188. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/workflows/human_input.py +0 -0
  189. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/workflows/orchestrator.py +0 -0
  190. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/workflows/parallel.py +0 -0
  191. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/workflows/router.py +0 -0
  192. {fast_agent_mcp-0.2.24 → fast_agent_mcp-0.2.26}/src/mcp_agent/resources/examples/workflows/short_story.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fast-agent-mcp
3
- Version: 0.2.24
3
+ Version: 0.2.26
4
4
  Summary: Define, Prompt and Test MCP enabled Agents and Workflows
5
5
  Author-email: Shaun Smith <fastagent@llmindset.co.uk>
6
6
  License: Apache License
@@ -212,14 +212,15 @@ Requires-Python: >=3.10
212
212
  Requires-Dist: a2a-types>=0.1.0
213
213
  Requires-Dist: aiohttp>=3.11.13
214
214
  Requires-Dist: anthropic>=0.49.0
215
+ Requires-Dist: azure-identity>=1.14.0
215
216
  Requires-Dist: fastapi>=0.115.6
216
- Requires-Dist: mcp>=1.8.0
217
+ Requires-Dist: mcp==1.8.0
217
218
  Requires-Dist: openai>=1.63.2
218
219
  Requires-Dist: opentelemetry-distro>=0.50b0
219
220
  Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.29.0
220
- Requires-Dist: opentelemetry-instrumentation-anthropic>=0.39.3
221
- Requires-Dist: opentelemetry-instrumentation-mcp>=0.40.3
222
- Requires-Dist: opentelemetry-instrumentation-openai>=0.39.3
221
+ Requires-Dist: opentelemetry-instrumentation-anthropic>=0.39.3; python_version >= '3.10' and python_version < '4.0'
222
+ Requires-Dist: opentelemetry-instrumentation-mcp>=0.40.3; python_version >= '3.10' and python_version < '4.0'
223
+ Requires-Dist: opentelemetry-instrumentation-openai>=0.39.3; python_version >= '3.10' and python_version < '4.0'
223
224
  Requires-Dist: prompt-toolkit>=3.0.50
224
225
  Requires-Dist: pydantic-settings>=2.7.0
225
226
  Requires-Dist: pydantic>=2.10.4
@@ -227,6 +228,8 @@ Requires-Dist: pyyaml>=6.0.2
227
228
  Requires-Dist: rich>=13.9.4
228
229
  Requires-Dist: tensorzero>=2025.4.7
229
230
  Requires-Dist: typer>=0.15.1
231
+ Provides-Extra: azure
232
+ Requires-Dist: azure-identity>=1.14.0; extra == 'azure'
230
233
  Provides-Extra: dev
231
234
  Requires-Dist: anthropic>=0.42.0; extra == 'dev'
232
235
  Requires-Dist: pre-commit>=4.0.1; extra == 'dev'
@@ -0,0 +1,54 @@
1
+ # NOTE: Since version X.X, the Azure OpenAI integration in FastAgent reuses the OpenAI logic.
2
+ # Authentication (API Key or DefaultAzureCredential) and connectivity are managed automatically.
3
+ # You only need to configure the 'azure' section as indicated below; the system will select the appropriate method.
4
+ #
5
+ # Example configuration for Azure OpenAI in fast-agent
6
+ #
7
+ # There are three supported authentication/configuration modes for Azure OpenAI:
8
+ #
9
+ # 1. Using 'resource_name' and 'api_key' (recommended for most users)
10
+ # 2. Using 'base_url' and 'api_key' (for custom endpoints or sovereign clouds)
11
+ # 3. Using 'base_url' and DefaultAzureCredential (for managed identity, Azure CLI, etc.)
12
+ #
13
+ # Use ONLY one of the parameters: 'resource_name' or 'base_url'.
14
+ # - If you define 'base_url', it will be used directly as the endpoint and 'resource_name' will be ignored.
15
+ # - If you define 'resource_name' (and not 'base_url'), the endpoint will be constructed automatically.
16
+ # - If both are missing, the configuration is invalid.
17
+ #
18
+ # Do not include both at the same time.
19
+
20
+ # --- OPTION 1: Using resource_name and api_key (recommended for standard Azure) ---
21
+ default_model: "azure.my-deployment"
22
+
23
+ azure:
24
+ api_key: "YOUR_AZURE_OPENAI_API_KEY"
25
+ resource_name: "your-resource-name"
26
+ azure_deployment: "my-deployment"
27
+ api_version: "2023-05-15"
28
+ # Do not include base_url if you use resource_name
29
+
30
+ # --- OPTION 2: Using base_url and api_key (for custom endpoints or sovereign clouds) ---
31
+ # default_model: "azure.my-deployment"
32
+ #
33
+ # azure:
34
+ # api_key: "YOUR_AZURE_OPENAI_API_KEY"
35
+ # base_url: "https://your-resource-name.openai.azure.com/"
36
+ # azure_deployment: "my-deployment"
37
+ # api_version: "2023-05-15"
38
+ # # Do not include resource_name if you use base_url
39
+
40
+ # --- OPTION 3: Using base_url and DefaultAzureCredential (for managed identity, Azure CLI, etc.) ---
41
+ # Requires the 'azure-identity' package to be installed.
42
+ # No api_key or resource_name should be present in this mode.
43
+ # base_url is required and must be the full endpoint URL.
44
+ #
45
+ # default_model: "azure.my-deployment"
46
+ #
47
+ # azure:
48
+ # use_default_azure_credential: true
49
+ # base_url: "https://your-resource-name.openai.azure.com/"
50
+ # azure_deployment: "my-deployment"
51
+ # api_version: "2023-05-15"
52
+ # # Do not include api_key or resource_name in this mode
53
+
54
+ # You can add other providers or settings as needed.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "fast-agent-mcp"
3
- version = "0.2.24"
3
+ version = "0.2.26"
4
4
  description = "Define, Prompt and Test MCP enabled Agents and Workflows"
5
5
  readme = "README.md"
6
6
  license = { file = "LICENSE" }
@@ -15,7 +15,7 @@ classifiers = [
15
15
  requires-python = ">=3.10"
16
16
  dependencies = [
17
17
  "fastapi>=0.115.6",
18
- "mcp>=1.8.0",
18
+ "mcp==1.8.0",
19
19
  "opentelemetry-distro>=0.50b0",
20
20
  "opentelemetry-exporter-otlp-proto-http>=1.29.0",
21
21
  "pydantic-settings>=2.7.0",
@@ -25,19 +25,24 @@ dependencies = [
25
25
  "typer>=0.15.1",
26
26
  "anthropic>=0.49.0",
27
27
  "openai>=1.63.2",
28
+ "azure-identity>=1.14.0",
28
29
  "prompt-toolkit>=3.0.50",
29
30
  "aiohttp>=3.11.13",
30
31
  "a2a-types>=0.1.0",
31
- "opentelemetry-instrumentation-openai>=0.39.3",
32
- "opentelemetry-instrumentation-anthropic>=0.39.3",
32
+ "opentelemetry-instrumentation-openai>=0.39.3; python_version >= '3.10' and python_version < '4.0'",
33
+ "opentelemetry-instrumentation-anthropic>=0.39.3; python_version >= '3.10' and python_version < '4.0'",
33
34
  "tensorzero>=2025.4.7",
34
- "opentelemetry-instrumentation-mcp>=0.40.3",
35
+ "opentelemetry-instrumentation-mcp>=0.40.3; python_version >= '3.10' and python_version < '4.0'",
35
36
  ]
36
37
 
37
38
  [project.optional-dependencies]
38
39
  openai = [
39
40
  "openai>=1.58.1",
40
41
  ]
42
+ # For Azure OpenAI with DefaultAzureCredential support, install with: pip install fast-agent-mcp[azure]
43
+ azure = [
44
+ "azure-identity>=1.14.0"
45
+ ]
41
46
  dev = [
42
47
  "anthropic>=0.42.0",
43
48
  "pre-commit>=4.0.1",
@@ -57,6 +62,10 @@ build-backend = "hatchling.build"
57
62
  [tool.hatch.build.targets.wheel]
58
63
  packages = ["src/mcp_agent"]
59
64
 
65
+ [[tool.poetry.packages]]
66
+ include = "mcp_agent"
67
+ from = "src"
68
+
60
69
  [tool.hatch.build]
61
70
  include = [
62
71
  "src/mcp_agent/**/*.py",
@@ -92,42 +92,73 @@ def get_secrets_summary(secrets_path: Optional[Path]) -> dict:
92
92
  return result
93
93
 
94
94
 
95
- def check_api_keys(secrets_summary: dict) -> dict:
96
- """Check if API keys are configured in secrets file or environment."""
95
+ def check_api_keys(secrets_summary: dict, config_summary: dict) -> dict:
96
+ """Check if API keys are configured in secrets file or environment, including Azure DefaultAzureCredential.
97
+ Now also checks Azure config in main config file for retrocompatibility.
98
+ """
97
99
  import os
98
100
 
99
- # Initialize results dict using Provider enum values
100
101
  results = {
101
- provider.value: {"env": None, "config": None}
102
+ provider.value: {"env": "", "config": ""}
102
103
  for provider in Provider
103
104
  if provider != Provider.FAST_AGENT
104
- } # Include GENERIC but exclude FAST_AGENT
105
+ }
105
106
 
106
107
  # Get secrets if available
107
108
  secrets = secrets_summary.get("secrets", {})
108
109
  secrets_status = secrets_summary.get("status", "not_found")
110
+ # Get config if available
111
+ config = config_summary if config_summary.get("status") == "parsed" else {}
112
+ config_azure = {}
113
+ if config and "azure" in config.get("config", {}):
114
+ config_azure = config["config"]["azure"]
109
115
 
110
- # Check both environment variables and config file for each provider
111
116
  for provider_value in results:
112
- # Check environment variables using ProviderKeyManager
113
- env_key_name = ProviderKeyManager.get_env_key_name(provider_value)
114
- env_key_value = os.environ.get(env_key_name)
115
- if env_key_value:
116
- # Store the last 5 characters if key is long enough
117
- if len(env_key_value) > 5:
118
- results[provider_value]["env"] = f"...{env_key_value[-5:]}"
119
- else:
120
- results[provider_value]["env"] = "...***"
121
-
122
- # Check secrets file if it was parsed successfully
123
- if secrets_status == "parsed":
124
- config_key = ProviderKeyManager.get_config_file_key(provider_value, secrets)
125
- if config_key and config_key != API_KEY_HINT_TEXT:
126
- # Store the last 5 characters if key is long enough
127
- if len(config_key) > 5:
128
- results[provider_value]["config"] = f"...{config_key[-5:]}"
117
+ # Special handling for Azure: support api_key and DefaultAzureCredential
118
+ if provider_value == "azure":
119
+ # Prefer secrets if present, else fallback to config
120
+ azure_cfg = {}
121
+ if secrets_status == "parsed" and "azure" in secrets:
122
+ azure_cfg = secrets.get("azure", {})
123
+ elif config_azure:
124
+ azure_cfg = config_azure
125
+
126
+ use_default_cred = azure_cfg.get("use_default_azure_credential", False)
127
+ base_url = azure_cfg.get("base_url")
128
+ api_key = azure_cfg.get("api_key")
129
+ # DefaultAzureCredential mode
130
+ if use_default_cred and base_url:
131
+ results[provider_value]["config"] = "DefaultAzureCredential"
132
+ # API key mode (retrocompatible)
133
+ if api_key and api_key != API_KEY_HINT_TEXT:
134
+ if len(api_key) > 5:
135
+ if results[provider_value]["config"]:
136
+ results[provider_value]["config"] += " + api_key"
137
+ else:
138
+ results[provider_value]["config"] = f"...{api_key[-5:]}"
129
139
  else:
130
- results[provider_value]["config"] = "...***"
140
+ if results[provider_value]["config"]:
141
+ results[provider_value]["config"] += " + api_key"
142
+ else:
143
+ results[provider_value]["config"] = "...***"
144
+ else:
145
+ # Check environment variables using ProviderKeyManager
146
+ env_key_name = ProviderKeyManager.get_env_key_name(provider_value)
147
+ env_key_value = os.environ.get(env_key_name)
148
+ if env_key_value:
149
+ if len(env_key_value) > 5:
150
+ results[provider_value]["env"] = f"...{env_key_value[-5:]}"
151
+ else:
152
+ results[provider_value]["env"] = "...***"
153
+
154
+ # Check secrets file if it was parsed successfully
155
+ if secrets_status == "parsed":
156
+ config_key = ProviderKeyManager.get_config_file_key(provider_value, secrets)
157
+ if config_key and config_key != API_KEY_HINT_TEXT:
158
+ if len(config_key) > 5:
159
+ results[provider_value]["config"] = f"...{config_key[-5:]}"
160
+ else:
161
+ results[provider_value]["config"] = "...***"
131
162
 
132
163
  return results
133
164
 
@@ -235,7 +266,7 @@ def show_check_summary() -> None:
235
266
  system_info = get_system_info()
236
267
  config_summary = get_config_summary(config_files["config"])
237
268
  secrets_summary = get_secrets_summary(config_files["secrets"])
238
- api_keys = check_api_keys(secrets_summary)
269
+ api_keys = check_api_keys(secrets_summary, config_summary)
239
270
  fastagent_version = get_fastagent_version()
240
271
 
241
272
  # System info panel
@@ -341,8 +372,10 @@ def show_check_summary() -> None:
341
372
 
342
373
  keys_table.add_row(provider.capitalize(), env_status, config_status, active)
343
374
 
344
- console.print(Panel(keys_table, title="API Keys", border_style="blue"))
345
-
375
+ # Print the API Keys panel (fix: this was missing)
376
+ keys_panel = Panel(keys_table, title="API Keys", border_style="blue", subtitle_align="left")
377
+ console.print(keys_panel)
378
+
346
379
  # MCP Servers panel (shown after API Keys)
347
380
  if config_summary.get("status") == "parsed":
348
381
  mcp_servers = config_summary.get("mcp_servers", [])
@@ -447,4 +480,4 @@ def show(
447
480
  def main(ctx: typer.Context) -> None:
448
481
  """Check and diagnose FastAgent configuration."""
449
482
  if ctx.invoked_subcommand is None:
450
- show_check_summary()
483
+ show_check_summary()
@@ -179,6 +179,20 @@ class OpenRouterSettings(BaseModel):
179
179
  model_config = ConfigDict(extra="allow", arbitrary_types_allowed=True)
180
180
 
181
181
 
182
+ class AzureSettings(BaseModel):
183
+ """
184
+ Settings for using Azure OpenAI Service in the fast-agent application.
185
+ """
186
+
187
+ api_key: str | None = None
188
+ resource_name: str | None = None
189
+ azure_deployment: str | None = None
190
+ api_version: str | None = None
191
+ base_url: str | None = None # Optional, can be constructed from resource_name
192
+
193
+ model_config = ConfigDict(extra="allow", arbitrary_types_allowed=True)
194
+
195
+
182
196
  class OpenTelemetrySettings(BaseModel):
183
197
  """
184
198
  OTEL settings for the fast-agent application.
@@ -302,6 +316,9 @@ class Settings(BaseSettings):
302
316
  tensorzero: Optional[TensorZeroSettings] = None
303
317
  """Settings for using TensorZero inference gateway"""
304
318
 
319
+ azure: AzureSettings | None = None
320
+ """Settings for using Azure OpenAI Service in the fast-agent application"""
321
+
305
322
  logger: LoggerSettings | None = LoggerSettings()
306
323
  """Logger settings for the fast-agent application"""
307
324
 
@@ -19,6 +19,7 @@ class ProgressAction(str, Enum):
19
19
  PLANNING = "Planning"
20
20
  READY = "Ready"
21
21
  CALLING_TOOL = "Calling Tool"
22
+ UPDATED = "Updated"
22
23
  FINISHED = "Finished"
23
24
  SHUTDOWN = "Shutdown"
24
25
  AGGREGATOR_INITIALIZED = "Running"
@@ -10,6 +10,7 @@ from mcp_agent.llm.augmented_llm_passthrough import PassthroughLLM
10
10
  from mcp_agent.llm.augmented_llm_playback import PlaybackLLM
11
11
  from mcp_agent.llm.provider_types import Provider
12
12
  from mcp_agent.llm.providers.augmented_llm_anthropic import AnthropicAugmentedLLM
13
+ from mcp_agent.llm.providers.augmented_llm_azure import AzureOpenAIAugmentedLLM
13
14
  from mcp_agent.llm.providers.augmented_llm_deepseek import DeepSeekAugmentedLLM
14
15
  from mcp_agent.llm.providers.augmented_llm_generic import GenericAugmentedLLM
15
16
  from mcp_agent.llm.providers.augmented_llm_google import GoogleAugmentedLLM
@@ -113,6 +114,7 @@ class ModelFactory:
113
114
  Provider.GOOGLE: GoogleAugmentedLLM, # type: ignore
114
115
  Provider.OPENROUTER: OpenRouterAugmentedLLM,
115
116
  Provider.TENSORZERO: TensorZeroAugmentedLLM,
117
+ Provider.AZURE: AzureOpenAIAugmentedLLM,
116
118
  }
117
119
 
118
120
  # Mapping of special model names to their specific LLM classes
@@ -16,3 +16,4 @@ class Provider(Enum):
16
16
  GENERIC = "generic"
17
17
  OPENROUTER = "openrouter"
18
18
  TENSORZERO = "tensorzero" # For TensorZero Gateway
19
+ AZURE = "azure" # Azure OpenAI Service
@@ -0,0 +1,137 @@
1
+ from openai import AuthenticationError, AzureOpenAI, OpenAI
2
+
3
+ from mcp_agent.core.exceptions import ProviderKeyError
4
+ from mcp_agent.llm.provider_types import Provider
5
+ from mcp_agent.llm.providers.augmented_llm_openai import OpenAIAugmentedLLM
6
+
7
+ try:
8
+ from azure.identity import DefaultAzureCredential
9
+ except ImportError:
10
+ DefaultAzureCredential = None
11
+
12
+
13
+ def _extract_resource_name(url: str) -> str | None:
14
+ from urllib.parse import urlparse
15
+
16
+ host = urlparse(url).hostname or ""
17
+ suffix = ".openai.azure.com"
18
+ return host.replace(suffix, "") if host.endswith(suffix) else None
19
+
20
+
21
+ DEFAULT_AZURE_API_VERSION = "2023-05-15"
22
+
23
+
24
+ class AzureOpenAIAugmentedLLM(OpenAIAugmentedLLM):
25
+ """
26
+ Azure OpenAI implementation extending OpenAIAugmentedLLM.
27
+ Handles both API Key and DefaultAzureCredential authentication.
28
+ """
29
+
30
+ def __init__(self, provider: Provider = Provider.AZURE, *args, **kwargs):
31
+ # Set provider to AZURE, pass through to base
32
+ super().__init__(provider=provider, *args, **kwargs)
33
+
34
+ # Context/config extraction
35
+ context = getattr(self, "context", None)
36
+ config = getattr(context, "config", None) if context else None
37
+ azure_cfg = getattr(config, "azure", None) if config else None
38
+
39
+ if azure_cfg is None:
40
+ raise ProviderKeyError(
41
+ "Missing Azure configuration",
42
+ "Azure provider requires configuration section 'azure' in your config file.",
43
+ )
44
+
45
+ self.use_default_cred = getattr(azure_cfg, "use_default_azure_credential", False)
46
+ default_request_params = getattr(self, "default_request_params", None)
47
+ self.deployment_name = getattr(default_request_params, "model", None) or getattr(
48
+ azure_cfg, "azure_deployment", None
49
+ )
50
+ self.api_version = getattr(azure_cfg, "api_version", None) or DEFAULT_AZURE_API_VERSION
51
+
52
+ if self.use_default_cred:
53
+ self.base_url = getattr(azure_cfg, "base_url", None)
54
+ if not self.base_url:
55
+ raise ProviderKeyError(
56
+ "Missing Azure endpoint",
57
+ "When using 'use_default_azure_credential', 'base_url' is required in azure config.",
58
+ )
59
+ if DefaultAzureCredential is None:
60
+ raise ProviderKeyError(
61
+ "azure-identity not installed",
62
+ "You must install 'azure-identity' to use DefaultAzureCredential authentication.",
63
+ )
64
+ self.credential = DefaultAzureCredential()
65
+
66
+ def get_azure_token():
67
+ token = self.credential.get_token("https://cognitiveservices.azure.com/.default")
68
+ return token.token
69
+
70
+ self.get_azure_token = get_azure_token
71
+ else:
72
+ self.api_key = getattr(azure_cfg, "api_key", None)
73
+ self.resource_name = getattr(azure_cfg, "resource_name", None)
74
+ self.base_url = getattr(azure_cfg, "base_url", None) or (
75
+ f"https://{self.resource_name}.openai.azure.com/" if self.resource_name else None
76
+ )
77
+ if not self.api_key:
78
+ raise ProviderKeyError(
79
+ "Missing Azure OpenAI credentials",
80
+ "Field 'api_key' is required in azure config.",
81
+ )
82
+ if not (self.resource_name or self.base_url):
83
+ raise ProviderKeyError(
84
+ "Missing Azure endpoint",
85
+ "Provide either 'resource_name' or 'base_url' under azure config.",
86
+ )
87
+ if not self.deployment_name:
88
+ raise ProviderKeyError(
89
+ "Missing deployment name",
90
+ "Set 'azure_deployment' in config or pass model=<deployment>.",
91
+ )
92
+ # If resource_name was missing, try to extract it from base_url
93
+ if not self.resource_name and self.base_url:
94
+ self.resource_name = _extract_resource_name(self.base_url)
95
+
96
+ def _openai_client(self) -> OpenAI:
97
+ """
98
+ Returns an AzureOpenAI client, handling both API Key and DefaultAzureCredential.
99
+ """
100
+ try:
101
+ if self.use_default_cred:
102
+ if self.base_url is None:
103
+ raise ProviderKeyError(
104
+ "Missing Azure endpoint",
105
+ "azure_endpoint (base_url) is None at client creation time.",
106
+ )
107
+ return AzureOpenAI(
108
+ azure_ad_token_provider=self.get_azure_token,
109
+ azure_endpoint=self.base_url,
110
+ api_version=self.api_version,
111
+ azure_deployment=self.deployment_name,
112
+ )
113
+ else:
114
+ if self.base_url is None:
115
+ raise ProviderKeyError(
116
+ "Missing Azure endpoint",
117
+ "azure_endpoint (base_url) is None at client creation time.",
118
+ )
119
+ return AzureOpenAI(
120
+ api_key=self.api_key,
121
+ azure_endpoint=self.base_url,
122
+ api_version=self.api_version,
123
+ azure_deployment=self.deployment_name,
124
+ )
125
+ except AuthenticationError as e:
126
+ if self.use_default_cred:
127
+ raise ProviderKeyError(
128
+ "Invalid Azure AD credentials",
129
+ "The configured Azure AD credentials were rejected.\n"
130
+ "Please check your Azure identity setup.",
131
+ ) from e
132
+ else:
133
+ raise ProviderKeyError(
134
+ "Invalid Azure OpenAI API key",
135
+ "The configured Azure OpenAI API key was rejected.\n"
136
+ "Please check that your API key is valid and not expired.",
137
+ ) from e
@@ -78,7 +78,7 @@ class OpenAIAugmentedLLM(AugmentedLLM[ChatCompletionMessageParam, ChatCompletion
78
78
  self._reasoning_effort = self.context.config.openai.reasoning_effort
79
79
 
80
80
  # Determine if we're using a reasoning model
81
- # TODO -- move this to model capabiltities, add o4.
81
+ # TODO -- move this to model capabilities, add o4.
82
82
  chosen_model = self.default_request_params.model if self.default_request_params else None
83
83
  self._reasoning = chosen_model and (
84
84
  chosen_model.startswith("o3") or chosen_model.startswith("o1")
@@ -325,7 +325,7 @@ class OpenAIAugmentedLLM(AugmentedLLM[ChatCompletionMessageParam, ChatCompletion
325
325
  return result
326
326
 
327
327
  def _prepare_api_request(
328
- self, messages, tools, request_params: RequestParams
328
+ self, messages, tools: List[ChatCompletionToolParam] | None, request_params: RequestParams
329
329
  ) -> dict[str, str]:
330
330
  # Create base arguments dictionary
331
331
 
@@ -345,9 +345,8 @@ class OpenAIAugmentedLLM(AugmentedLLM[ChatCompletionMessageParam, ChatCompletion
345
345
  )
346
346
  else:
347
347
  base_args["max_tokens"] = request_params.maxTokens
348
-
349
- if tools:
350
- base_args["parallel_tool_calls"] = request_params.parallel_tool_calls
348
+ if tools:
349
+ base_args["parallel_tool_calls"] = request_params.parallel_tool_calls
351
350
 
352
351
  arguments: Dict[str, str] = self.prepare_provider_arguments(
353
352
  base_args, request_params, self.OPENAI_EXCLUDE_FIELDS.union(self.BASE_EXCLUDE_FIELDS)
@@ -356,7 +355,7 @@ class OpenAIAugmentedLLM(AugmentedLLM[ChatCompletionMessageParam, ChatCompletion
356
355
 
357
356
  def adjust_schema(self, inputSchema: Dict) -> Dict:
358
357
  # return inputSchema
359
- if not Provider.OPENAI == self.provider:
358
+ if self.provider not in [Provider.OPENAI, Provider.AZURE]:
360
359
  return inputSchema
361
360
 
362
361
  if "properties" in inputSchema:
@@ -0,0 +1,16 @@
1
+ """
2
+ Common constants and utilities shared between modules to avoid circular imports.
3
+ """
4
+
5
+ # Constants
6
+ SEP = "-"
7
+
8
+
9
+ def create_namespaced_name(server_name: str, resource_name: str) -> str:
10
+ """Create a namespaced resource name from server and resource names"""
11
+ return f"{server_name}{SEP}{resource_name}"
12
+
13
+
14
+ def is_namespaced_name(name: str) -> bool:
15
+ """Check if a name is already namespaced"""
16
+ return SEP in name
@@ -25,6 +25,7 @@ from pydantic import AnyUrl, BaseModel, ConfigDict
25
25
  from mcp_agent.context_dependent import ContextDependent
26
26
  from mcp_agent.event_progress import ProgressAction
27
27
  from mcp_agent.logging.logger import get_logger
28
+ from mcp_agent.mcp.common import SEP, create_namespaced_name, is_namespaced_name
28
29
  from mcp_agent.mcp.gen_client import gen_client
29
30
  from mcp_agent.mcp.mcp_agent_client_session import MCPAgentClientSession
30
31
  from mcp_agent.mcp.mcp_connection_manager import MCPConnectionManager
@@ -35,23 +36,11 @@ if TYPE_CHECKING:
35
36
 
36
37
  logger = get_logger(__name__) # This will be replaced per-instance when agent_name is available
37
38
 
38
- SEP = "-"
39
-
40
39
  # Define type variables for the generalized method
41
40
  T = TypeVar("T")
42
41
  R = TypeVar("R")
43
42
 
44
43
 
45
- def create_namespaced_name(server_name: str, resource_name: str) -> str:
46
- """Create a namespaced resource name from server and resource names"""
47
- return f"{server_name}{SEP}{resource_name}"
48
-
49
-
50
- def is_namespaced_name(name: str) -> bool:
51
- """Check if a name is already namespaced"""
52
- return SEP in name
53
-
54
-
55
44
  class NamespacedTool(BaseModel):
56
45
  """
57
46
  A tool that is namespaced by server name.
@@ -94,6 +83,11 @@ class MCPAggregator(ContextDependent):
94
83
  self._persistent_connection_manager = self.context._connection_manager
95
84
 
96
85
  await self.load_servers()
86
+ # Import the display component here to avoid circular imports
87
+ from mcp_agent.ui.console_display import ConsoleDisplay
88
+
89
+ # Initialize the display component
90
+ self.display = ConsoleDisplay(config=self.context.config)
97
91
 
98
92
  return self
99
93
 
@@ -227,12 +221,11 @@ class MCPAggregator(ContextDependent):
227
221
  write_stream,
228
222
  read_timeout,
229
223
  server_name=server_name,
230
- tool_list_changed_callback=self._handle_tool_list_changed
224
+ tool_list_changed_callback=self._handle_tool_list_changed,
231
225
  )
232
226
 
233
227
  await self._persistent_connection_manager.get_server(
234
- server_name,
235
- client_session_factory=session_factory
228
+ server_name, client_session_factory=session_factory
236
229
  )
237
230
 
238
231
  logger.info(
@@ -282,13 +275,13 @@ class MCPAggregator(ContextDependent):
282
275
  write_stream,
283
276
  read_timeout,
284
277
  server_name=server_name,
285
- tool_list_changed_callback=self._handle_tool_list_changed
278
+ tool_list_changed_callback=self._handle_tool_list_changed,
286
279
  )
287
280
 
288
281
  async with gen_client(
289
282
  server_name,
290
283
  server_registry=self.context.server_registry,
291
- client_session_factory=create_session
284
+ client_session_factory=create_session,
292
285
  ) as client:
293
286
  tools = await fetch_tools(client)
294
287
  prompts = await fetch_prompts(client, server_name)
@@ -923,6 +916,8 @@ class MCPAggregator(ContextDependent):
923
916
  logger.error(f"Cannot refresh tools for unknown server '{server_name}'")
924
917
  return
925
918
 
919
+ await self.display.show_tool_update(aggregator=self, updated_server=server_name)
920
+
926
921
  async with self._refresh_lock:
927
922
  try:
928
923
  # Fetch new tools from the server
@@ -934,12 +929,11 @@ class MCPAggregator(ContextDependent):
934
929
  write_stream,
935
930
  read_timeout,
936
931
  server_name=server_name,
937
- tool_list_changed_callback=self._handle_tool_list_changed
932
+ tool_list_changed_callback=self._handle_tool_list_changed,
938
933
  )
939
934
 
940
935
  server_connection = await self._persistent_connection_manager.get_server(
941
- server_name,
942
- client_session_factory=create_session
936
+ server_name, client_session_factory=create_session
943
937
  )
944
938
  tools_result = await server_connection.session.list_tools()
945
939
  new_tools = tools_result.tools or []
@@ -951,13 +945,13 @@ class MCPAggregator(ContextDependent):
951
945
  write_stream,
952
946
  read_timeout,
953
947
  server_name=server_name,
954
- tool_list_changed_callback=self._handle_tool_list_changed
948
+ tool_list_changed_callback=self._handle_tool_list_changed,
955
949
  )
956
950
 
957
951
  async with gen_client(
958
952
  server_name,
959
953
  server_registry=self.context.server_registry,
960
- client_session_factory=create_session
954
+ client_session_factory=create_session,
961
955
  ) as client:
962
956
  tools_result = await client.list_tools()
963
957
  new_tools = tools_result.tools or []