fast-agent-mcp 0.2.22__tar.gz → 0.2.23__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.
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/.gitignore +2 -1
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/PKG-INFO +2 -2
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/pyproject.toml +1 -2
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/agents/workflow/orchestrator_agent.py +2 -2
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/cli/commands/go.py +94 -29
- fast_agent_mcp-0.2.23/src/mcp_agent/cli/commands/url_parser.py +185 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/config.py +3 -1
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/core/fastagent.py +2 -2
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/core/request_params.py +5 -6
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/mcp/mcp_connection_manager.py +33 -7
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/mcp/prompts/prompt_server.py +12 -4
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/mcp_server/agent_server.py +13 -10
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/mcp_server_registry.py +51 -9
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/mcp/state-transfer/fastagent.config.yaml +2 -2
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/ui/console_display.py +7 -6
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/LICENSE +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/README.md +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/data-analysis/analysis-campaign.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/data-analysis/analysis.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/data-analysis/fastagent.config.yaml +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/data-analysis/mount-point/WA_Fn-UseC_-HR-Employee-Attrition.csv +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/mcp/state-transfer/agent_one.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/mcp/state-transfer/agent_two.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/mcp/state-transfer/fastagent.config.yaml +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/mcp/vision-examples/example1.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/mcp/vision-examples/example2.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/mcp/vision-examples/example3.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/mcp/vision-examples/fastagent.config.yaml +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/otel/agent.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/otel/agent2.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/otel/docker-compose.yaml +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/otel/fastagent.config.yaml +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/researcher/fastagent.config.yaml +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/researcher/researcher-eval.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/researcher/researcher-imp.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/researcher/researcher.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/tensorzero/README.md +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/tensorzero/agent.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/tensorzero/docker-compose.yml +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/tensorzero/fastagent.config.yaml +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/tensorzero/image_demo.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/tensorzero/mcp_server/mcp_server.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/tensorzero/simple_agent.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/workflows/chaining.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/workflows/evaluator.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/workflows/fastagent.config.yaml +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/workflows/graded_report.md +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/workflows/human_input.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/workflows/orchestrator.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/workflows/parallel.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/workflows/router.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/workflows/short_story.md +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/examples/workflows/short_story.txt +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/__init__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/agents/__init__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/agents/agent.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/agents/base_agent.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/agents/workflow/__init__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/agents/workflow/chain_agent.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/agents/workflow/evaluator_optimizer.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/agents/workflow/orchestrator_models.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/agents/workflow/orchestrator_prompts.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/agents/workflow/parallel_agent.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/agents/workflow/router_agent.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/app.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/cli/__init__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/cli/__main__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/cli/commands/check_config.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/cli/commands/quickstart.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/cli/commands/setup.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/cli/main.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/cli/terminal.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/console.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/context.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/context_dependent.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/core/__init__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/core/agent_app.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/core/agent_types.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/core/direct_decorators.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/core/direct_factory.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/core/enhanced_prompt.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/core/error_handling.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/core/exceptions.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/core/interactive_prompt.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/core/mcp_content.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/core/prompt.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/core/validation.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/event_progress.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/executor/__init__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/executor/executor.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/executor/task_registry.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/executor/workflow_signal.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/human_input/__init__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/human_input/handler.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/human_input/types.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/llm/__init__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/llm/augmented_llm.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/llm/augmented_llm_passthrough.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/llm/augmented_llm_playback.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/llm/memory.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/llm/model_factory.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/llm/prompt_utils.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/llm/provider_key_manager.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/llm/provider_types.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/llm/providers/__init__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/llm/providers/anthropic_utils.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/llm/providers/augmented_llm_anthropic.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/llm/providers/augmented_llm_deepseek.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/llm/providers/augmented_llm_generic.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/llm/providers/augmented_llm_google.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/llm/providers/augmented_llm_openai.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/llm/providers/augmented_llm_openrouter.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/llm/providers/augmented_llm_tensorzero.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/llm/providers/multipart_converter_anthropic.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/llm/providers/multipart_converter_openai.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/llm/providers/multipart_converter_tensorzero.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/llm/providers/openai_multipart.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/llm/providers/openai_utils.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/llm/providers/sampling_converter_anthropic.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/llm/providers/sampling_converter_openai.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/llm/sampling_converter.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/llm/sampling_format_converter.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/logging/__init__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/logging/events.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/logging/json_serializer.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/logging/listeners.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/logging/logger.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/logging/rich_progress.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/logging/transport.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/mcp/__init__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/mcp/gen_client.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/mcp/helpers/__init__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/mcp/helpers/content_helpers.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/mcp/interfaces.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/mcp/logger_textio.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/mcp/mcp_agent_client_session.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/mcp/mcp_aggregator.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/mcp/mime_utils.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/mcp/prompt_message_multipart.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/mcp/prompt_render.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/mcp/prompt_serialization.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/mcp/prompts/__init__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/mcp/prompts/__main__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/mcp/prompts/prompt_constants.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/mcp/prompts/prompt_helpers.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/mcp/prompts/prompt_load.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/mcp/prompts/prompt_template.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/mcp/resource_utils.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/mcp/sampling.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/mcp_server/__init__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/progress_display.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/data-analysis/analysis-campaign.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/data-analysis/analysis.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/data-analysis/fastagent.config.yaml +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/data-analysis/mount-point/WA_Fn-UseC_-HR-Employee-Attrition.csv +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/in_dev/agent_build.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/in_dev/css-LICENSE.txt +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/in_dev/slides.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/internal/agent.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/internal/fastagent.config.yaml +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/internal/history_transfer.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/internal/job.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/internal/prompt_category.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/internal/prompt_sizing.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/internal/simple.txt +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/internal/sizer.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/internal/social.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/mcp/state-transfer/agent_one.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/mcp/state-transfer/agent_two.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/mcp/state-transfer/fastagent.secrets.yaml.example +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/prompting/__init__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/prompting/agent.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/prompting/delimited_prompt.txt +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/prompting/fastagent.config.yaml +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/prompting/image_server.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/prompting/prompt1.txt +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/prompting/work_with_image.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/researcher/fastagent.config.yaml +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/researcher/researcher-eval.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/researcher/researcher-imp.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/researcher/researcher.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/workflows/chaining.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/workflows/evaluator.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/workflows/fastagent.config.yaml +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/workflows/human_input.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/workflows/orchestrator.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/workflows/parallel.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/workflows/router.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/resources/examples/workflows/short_story.txt +0 -0
@@ -1,4 +1,4 @@
|
|
1
|
-
# Byte-compiled / optimized / DLL files
|
1
|
+
s# Byte-compiled / optimized / DLL files
|
2
2
|
__pycache__/
|
3
3
|
*.py[cod]
|
4
4
|
*$py.class
|
@@ -200,3 +200,4 @@ fastagent.jsonl
|
|
200
200
|
# JetBrains IDEs
|
201
201
|
.idea/
|
202
202
|
tests/e2e/smoke/base/weather_location.txt
|
203
|
+
tests/integration/roots/fastagent.jsonl
|
@@ -1,8 +1,8 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: fast-agent-mcp
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.23
|
4
4
|
Summary: Define, Prompt and Test MCP enabled Agents and Workflows
|
5
|
-
Author-email: Shaun Smith <fastagent@llmindset.co.uk
|
5
|
+
Author-email: Shaun Smith <fastagent@llmindset.co.uk>
|
6
6
|
License: Apache License
|
7
7
|
Version 2.0, January 2004
|
8
8
|
http://www.apache.org/licenses/
|
@@ -1,12 +1,11 @@
|
|
1
1
|
[project]
|
2
2
|
name = "fast-agent-mcp"
|
3
|
-
version = "0.2.
|
3
|
+
version = "0.2.23"
|
4
4
|
description = "Define, Prompt and Test MCP enabled Agents and Workflows"
|
5
5
|
readme = "README.md"
|
6
6
|
license = { file = "LICENSE" }
|
7
7
|
authors = [
|
8
8
|
{ name = "Shaun Smith", email = "fastagent@llmindset.co.uk"},
|
9
|
-
{ name = "Sarmad Qadri", email = "sarmad@lastmileai.dev" }
|
10
9
|
]
|
11
10
|
classifiers = [
|
12
11
|
"Programming Language :: Python :: 3",
|
{fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.23}/src/mcp_agent/agents/workflow/orchestrator_agent.py
RENAMED
@@ -229,7 +229,7 @@ class OrchestratorAgent(BaseAgent):
|
|
229
229
|
self.logger.warning(
|
230
230
|
f"Reached maximum step limit ({max_steps}) without completing objective"
|
231
231
|
)
|
232
|
-
plan_result.
|
232
|
+
plan_result.max_iterations_reached = True
|
233
233
|
break
|
234
234
|
|
235
235
|
# Execute the step and collect results
|
@@ -239,7 +239,7 @@ class OrchestratorAgent(BaseAgent):
|
|
239
239
|
total_steps_executed += 1
|
240
240
|
|
241
241
|
# Check if we need to break due to hitting max steps
|
242
|
-
if getattr(plan_result, "
|
242
|
+
if getattr(plan_result, "max_iterations_reached", False):
|
243
243
|
break
|
244
244
|
|
245
245
|
# If the plan is marked complete, finalize the result
|
@@ -2,16 +2,18 @@
|
|
2
2
|
|
3
3
|
import asyncio
|
4
4
|
import sys
|
5
|
-
from typing import List, Optional
|
5
|
+
from typing import Dict, List, Optional
|
6
6
|
|
7
7
|
import typer
|
8
8
|
|
9
|
+
from mcp_agent.cli.commands.url_parser import generate_server_configs, parse_server_urls
|
9
10
|
from mcp_agent.core.fastagent import FastAgent
|
10
11
|
|
11
12
|
app = typer.Typer(
|
12
13
|
help="Run an interactive agent directly from the command line without creating an agent.py file"
|
13
14
|
)
|
14
15
|
|
16
|
+
|
15
17
|
async def _run_agent(
|
16
18
|
name: str = "FastAgent CLI",
|
17
19
|
instruction: str = "You are a helpful AI Agent.",
|
@@ -19,33 +21,61 @@ async def _run_agent(
|
|
19
21
|
server_list: Optional[List[str]] = None,
|
20
22
|
model: Optional[str] = None,
|
21
23
|
message: Optional[str] = None,
|
22
|
-
prompt_file: Optional[str] = None
|
24
|
+
prompt_file: Optional[str] = None,
|
25
|
+
url_servers: Optional[Dict[str, Dict[str, str]]] = None,
|
23
26
|
) -> None:
|
24
27
|
"""Async implementation to run an interactive agent."""
|
25
28
|
from pathlib import Path
|
26
29
|
|
30
|
+
from mcp_agent.config import MCPServerSettings, MCPSettings
|
27
31
|
from mcp_agent.mcp.prompts.prompt_load import load_prompt_multipart
|
28
32
|
|
29
|
-
# Create the FastAgent instance
|
30
|
-
# It will automatically parse args like --model, --quiet, etc.
|
33
|
+
# Create the FastAgent instance
|
31
34
|
fast_kwargs = {
|
32
35
|
"name": name,
|
33
36
|
"config_path": config_path,
|
34
37
|
"ignore_unknown_args": True,
|
35
38
|
"parse_cli_args": False, # Don't parse CLI args, we're handling it ourselves
|
36
39
|
}
|
37
|
-
|
40
|
+
|
38
41
|
fast = FastAgent(**fast_kwargs)
|
39
42
|
|
43
|
+
# Add URL-based servers to the context configuration
|
44
|
+
if url_servers:
|
45
|
+
# Initialize the app to ensure context is ready
|
46
|
+
await fast.app.initialize()
|
47
|
+
|
48
|
+
# Initialize mcp settings if needed
|
49
|
+
if not hasattr(fast.app.context.config, "mcp"):
|
50
|
+
fast.app.context.config.mcp = MCPSettings()
|
51
|
+
|
52
|
+
# Initialize servers dictionary if needed
|
53
|
+
if (
|
54
|
+
not hasattr(fast.app.context.config.mcp, "servers")
|
55
|
+
or fast.app.context.config.mcp.servers is None
|
56
|
+
):
|
57
|
+
fast.app.context.config.mcp.servers = {}
|
58
|
+
|
59
|
+
# Add each URL server to the config
|
60
|
+
for server_name, server_config in url_servers.items():
|
61
|
+
server_settings = {"transport": server_config["transport"], "url": server_config["url"]}
|
62
|
+
|
63
|
+
# Add headers if present in the server config
|
64
|
+
if "headers" in server_config:
|
65
|
+
server_settings["headers"] = server_config["headers"]
|
66
|
+
|
67
|
+
fast.app.context.config.mcp.servers[server_name] = MCPServerSettings(**server_settings)
|
68
|
+
|
40
69
|
# Define the agent with specified parameters
|
41
70
|
agent_kwargs = {"instruction": instruction}
|
42
71
|
if server_list:
|
43
72
|
agent_kwargs["servers"] = server_list
|
44
73
|
if model:
|
45
74
|
agent_kwargs["model"] = model
|
46
|
-
|
75
|
+
|
47
76
|
# Handle prompt file and message options
|
48
77
|
if message or prompt_file:
|
78
|
+
|
49
79
|
@fast.agent(**agent_kwargs)
|
50
80
|
async def cli_agent():
|
51
81
|
async with fast.run() as agent:
|
@@ -55,7 +85,7 @@ async def _run_agent(
|
|
55
85
|
print(response)
|
56
86
|
elif prompt_file:
|
57
87
|
prompt = load_prompt_multipart(Path(prompt_file))
|
58
|
-
response = await agent.generate(prompt)
|
88
|
+
response = await agent.default.generate(prompt)
|
59
89
|
# Print the response text and exit
|
60
90
|
print(response.last_text())
|
61
91
|
else:
|
@@ -68,18 +98,37 @@ async def _run_agent(
|
|
68
98
|
# Run the agent
|
69
99
|
await cli_agent()
|
70
100
|
|
101
|
+
|
71
102
|
def run_async_agent(
|
72
|
-
name: str,
|
73
|
-
instruction: str,
|
74
|
-
config_path: Optional[str] = None,
|
103
|
+
name: str,
|
104
|
+
instruction: str,
|
105
|
+
config_path: Optional[str] = None,
|
75
106
|
servers: Optional[str] = None,
|
107
|
+
urls: Optional[str] = None,
|
108
|
+
auth: Optional[str] = None,
|
76
109
|
model: Optional[str] = None,
|
77
110
|
message: Optional[str] = None,
|
78
|
-
prompt_file: Optional[str] = None
|
111
|
+
prompt_file: Optional[str] = None,
|
79
112
|
):
|
80
113
|
"""Run the async agent function with proper loop handling."""
|
81
|
-
server_list = servers.split(
|
82
|
-
|
114
|
+
server_list = servers.split(",") if servers else None
|
115
|
+
|
116
|
+
# Parse URLs and generate server configurations if provided
|
117
|
+
url_servers = None
|
118
|
+
if urls:
|
119
|
+
try:
|
120
|
+
parsed_urls = parse_server_urls(urls, auth)
|
121
|
+
url_servers = generate_server_configs(parsed_urls)
|
122
|
+
# If we have servers from URLs, add their names to the server_list
|
123
|
+
if url_servers and not server_list:
|
124
|
+
server_list = list(url_servers.keys())
|
125
|
+
elif url_servers and server_list:
|
126
|
+
# Merge both lists
|
127
|
+
server_list.extend(list(url_servers.keys()))
|
128
|
+
except ValueError as e:
|
129
|
+
print(f"Error parsing URLs: {e}")
|
130
|
+
return
|
131
|
+
|
83
132
|
# Check if we're already in an event loop
|
84
133
|
try:
|
85
134
|
loop = asyncio.get_event_loop()
|
@@ -92,24 +141,27 @@ def run_async_agent(
|
|
92
141
|
# No event loop exists, so we'll create one
|
93
142
|
loop = asyncio.new_event_loop()
|
94
143
|
asyncio.set_event_loop(loop)
|
95
|
-
|
144
|
+
|
96
145
|
try:
|
97
|
-
loop.run_until_complete(
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
146
|
+
loop.run_until_complete(
|
147
|
+
_run_agent(
|
148
|
+
name=name,
|
149
|
+
instruction=instruction,
|
150
|
+
config_path=config_path,
|
151
|
+
server_list=server_list,
|
152
|
+
model=model,
|
153
|
+
message=message,
|
154
|
+
prompt_file=prompt_file,
|
155
|
+
url_servers=url_servers,
|
156
|
+
)
|
157
|
+
)
|
106
158
|
finally:
|
107
159
|
try:
|
108
160
|
# Clean up the loop
|
109
161
|
tasks = asyncio.all_tasks(loop)
|
110
162
|
for task in tasks:
|
111
163
|
task.cancel()
|
112
|
-
|
164
|
+
|
113
165
|
# Run the event loop until all tasks are done
|
114
166
|
if sys.version_info >= (3, 7):
|
115
167
|
loop.run_until_complete(asyncio.gather(*tasks, return_exceptions=True))
|
@@ -118,6 +170,7 @@ def run_async_agent(
|
|
118
170
|
except Exception:
|
119
171
|
pass
|
120
172
|
|
173
|
+
|
121
174
|
@app.callback(invoke_without_command=True)
|
122
175
|
def go(
|
123
176
|
ctx: typer.Context,
|
@@ -131,6 +184,12 @@ def go(
|
|
131
184
|
servers: Optional[str] = typer.Option(
|
132
185
|
None, "--servers", help="Comma-separated list of server names to enable from config"
|
133
186
|
),
|
187
|
+
urls: Optional[str] = typer.Option(
|
188
|
+
None, "--url", help="Comma-separated list of HTTP/SSE URLs to connect to"
|
189
|
+
),
|
190
|
+
auth: Optional[str] = typer.Option(
|
191
|
+
None, "--auth", help="Bearer token for authorization with URL-based servers"
|
192
|
+
),
|
134
193
|
model: Optional[str] = typer.Option(
|
135
194
|
None, "--model", help="Override the default model (e.g., haiku, sonnet, gpt-4)"
|
136
195
|
),
|
@@ -148,6 +207,8 @@ def go(
|
|
148
207
|
fast-agent go --model=haiku --instruction="You are a coding assistant" --servers=fetch,filesystem
|
149
208
|
fast-agent go --message="What is the weather today?" --model=haiku
|
150
209
|
fast-agent go --prompt-file=my-prompt.txt --model=haiku
|
210
|
+
fast-agent go --url=http://localhost:8001/mcp,http://api.example.com/sse
|
211
|
+
fast-agent go --url=https://api.example.com/mcp --auth=YOUR_API_TOKEN
|
151
212
|
|
152
213
|
This will start an interactive session with the agent, using the specified model
|
153
214
|
and instruction. It will use the default configuration from fastagent.config.yaml
|
@@ -157,15 +218,19 @@ def go(
|
|
157
218
|
--model Override the default model (e.g., --model=haiku)
|
158
219
|
--quiet Disable progress display and logging
|
159
220
|
--servers Comma-separated list of server names to enable from config
|
221
|
+
--url Comma-separated list of HTTP/SSE URLs to connect to
|
222
|
+
--auth Bearer token for authorization with URL-based servers
|
160
223
|
--message, -m Send a single message and exit
|
161
224
|
--prompt-file, -p Use a prompt file instead of interactive mode
|
162
225
|
"""
|
163
226
|
run_async_agent(
|
164
|
-
name=name,
|
165
|
-
instruction=instruction,
|
166
|
-
config_path=config_path,
|
227
|
+
name=name,
|
228
|
+
instruction=instruction,
|
229
|
+
config_path=config_path,
|
167
230
|
servers=servers,
|
231
|
+
urls=urls,
|
232
|
+
auth=auth,
|
168
233
|
model=model,
|
169
234
|
message=message,
|
170
|
-
prompt_file=prompt_file
|
171
|
-
)
|
235
|
+
prompt_file=prompt_file,
|
236
|
+
)
|
@@ -0,0 +1,185 @@
|
|
1
|
+
"""
|
2
|
+
URL parsing utility for the fast-agent CLI.
|
3
|
+
Provides functions to parse URLs and determine MCP server configurations.
|
4
|
+
"""
|
5
|
+
|
6
|
+
import hashlib
|
7
|
+
import re
|
8
|
+
from typing import Dict, List, Literal, Tuple
|
9
|
+
from urllib.parse import urlparse
|
10
|
+
|
11
|
+
|
12
|
+
def parse_server_url(
|
13
|
+
url: str,
|
14
|
+
) -> Tuple[str, Literal["http", "sse"], str]:
|
15
|
+
"""
|
16
|
+
Parse a server URL and determine the transport type and server name.
|
17
|
+
|
18
|
+
Args:
|
19
|
+
url: The URL to parse
|
20
|
+
|
21
|
+
Returns:
|
22
|
+
Tuple containing:
|
23
|
+
- server_name: A generated name for the server
|
24
|
+
- transport_type: Either "http" or "sse" based on URL
|
25
|
+
- url: The parsed and validated URL
|
26
|
+
|
27
|
+
Raises:
|
28
|
+
ValueError: If the URL is invalid or unsupported
|
29
|
+
"""
|
30
|
+
# Basic URL validation
|
31
|
+
if not url:
|
32
|
+
raise ValueError("URL cannot be empty")
|
33
|
+
|
34
|
+
# Parse the URL
|
35
|
+
parsed_url = urlparse(url)
|
36
|
+
|
37
|
+
# Ensure scheme is present and is either http or https
|
38
|
+
if not parsed_url.scheme or parsed_url.scheme not in ("http", "https"):
|
39
|
+
raise ValueError(f"URL must have http or https scheme: {url}")
|
40
|
+
|
41
|
+
# Ensure netloc (hostname) is present
|
42
|
+
if not parsed_url.netloc:
|
43
|
+
raise ValueError(f"URL must include a hostname: {url}")
|
44
|
+
|
45
|
+
# Determine transport type based on URL path
|
46
|
+
transport_type: Literal["http", "sse"] = "http"
|
47
|
+
if parsed_url.path.endswith("/sse"):
|
48
|
+
transport_type = "sse"
|
49
|
+
elif not parsed_url.path.endswith("/mcp"):
|
50
|
+
# If path doesn't end with /mcp or /sse, append /mcp
|
51
|
+
url = url if url.endswith("/") else f"{url}/"
|
52
|
+
url = f"{url}mcp"
|
53
|
+
|
54
|
+
# Generate a server name based on hostname and port
|
55
|
+
server_name = generate_server_name(url)
|
56
|
+
|
57
|
+
return server_name, transport_type, url
|
58
|
+
|
59
|
+
|
60
|
+
def generate_server_name(url: str) -> str:
|
61
|
+
"""
|
62
|
+
Generate a unique and readable server name from a URL.
|
63
|
+
|
64
|
+
Args:
|
65
|
+
url: The URL to generate a name for
|
66
|
+
|
67
|
+
Returns:
|
68
|
+
A server name string
|
69
|
+
"""
|
70
|
+
parsed_url = urlparse(url)
|
71
|
+
|
72
|
+
# Extract hostname and port
|
73
|
+
hostname = parsed_url.netloc.split(":")[0]
|
74
|
+
|
75
|
+
# Clean the hostname for use in a server name
|
76
|
+
# Replace non-alphanumeric characters with underscores
|
77
|
+
clean_hostname = re.sub(r"[^a-zA-Z0-9]", "_", hostname)
|
78
|
+
|
79
|
+
if len(clean_hostname) > 15:
|
80
|
+
clean_hostname = clean_hostname[:9] + clean_hostname[-5:]
|
81
|
+
|
82
|
+
# If it's localhost or an IP, add a more unique identifier
|
83
|
+
if clean_hostname in ("localhost", "127_0_0_1") or re.match(r"^(\d+_){3}\d+$", clean_hostname):
|
84
|
+
# Use the path as part of the name for uniqueness
|
85
|
+
path = parsed_url.path.strip("/")
|
86
|
+
path = re.sub(r"[^a-zA-Z0-9]", "_", path)
|
87
|
+
|
88
|
+
# Include port if specified
|
89
|
+
port = ""
|
90
|
+
if ":" in parsed_url.netloc:
|
91
|
+
port = f"_{parsed_url.netloc.split(':')[1]}"
|
92
|
+
|
93
|
+
if path:
|
94
|
+
return f"{clean_hostname}{port}_{path[:20]}" # Limit path length
|
95
|
+
else:
|
96
|
+
# Use a hash if no path for uniqueness
|
97
|
+
url_hash = hashlib.md5(url.encode()).hexdigest()[:8]
|
98
|
+
return f"{clean_hostname}{port}_{url_hash}"
|
99
|
+
|
100
|
+
return clean_hostname
|
101
|
+
|
102
|
+
|
103
|
+
def parse_server_urls(
|
104
|
+
urls_param: str, auth_token: str = None
|
105
|
+
) -> List[Tuple[str, Literal["http", "sse"], str, Dict[str, str] | None]]:
|
106
|
+
"""
|
107
|
+
Parse a comma-separated list of URLs into server configurations.
|
108
|
+
|
109
|
+
Args:
|
110
|
+
urls_param: Comma-separated list of URLs
|
111
|
+
auth_token: Optional bearer token for authorization
|
112
|
+
|
113
|
+
Returns:
|
114
|
+
List of tuples containing (server_name, transport_type, url, headers)
|
115
|
+
|
116
|
+
Raises:
|
117
|
+
ValueError: If any URL is invalid
|
118
|
+
"""
|
119
|
+
if not urls_param:
|
120
|
+
return []
|
121
|
+
|
122
|
+
# Split by comma and strip whitespace
|
123
|
+
url_list = [url.strip() for url in urls_param.split(",")]
|
124
|
+
|
125
|
+
# Prepare headers if auth token is provided
|
126
|
+
headers = None
|
127
|
+
if auth_token:
|
128
|
+
headers = {"Authorization": f"Bearer {auth_token}"}
|
129
|
+
|
130
|
+
# Parse each URL
|
131
|
+
result = []
|
132
|
+
for url in url_list:
|
133
|
+
server_name, transport_type, parsed_url = parse_server_url(url)
|
134
|
+
result.append((server_name, transport_type, parsed_url, headers))
|
135
|
+
|
136
|
+
return result
|
137
|
+
|
138
|
+
|
139
|
+
def generate_server_configs(
|
140
|
+
parsed_urls: List[Tuple[str, Literal["http", "sse"], str, Dict[str, str] | None]],
|
141
|
+
) -> Dict[str, Dict[str, str | Dict[str, str]]]:
|
142
|
+
"""
|
143
|
+
Generate server configurations from parsed URLs.
|
144
|
+
|
145
|
+
Args:
|
146
|
+
parsed_urls: List of tuples containing (server_name, transport_type, url, headers)
|
147
|
+
|
148
|
+
Returns:
|
149
|
+
Dictionary of server configurations
|
150
|
+
"""
|
151
|
+
server_configs = {}
|
152
|
+
# Keep track of server name occurrences to handle collisions
|
153
|
+
name_counts = {}
|
154
|
+
|
155
|
+
for server_name, transport_type, url, headers in parsed_urls:
|
156
|
+
# Handle name collisions by adding a suffix
|
157
|
+
final_name = server_name
|
158
|
+
if server_name in server_configs:
|
159
|
+
# Initialize counter if we haven't seen this name yet
|
160
|
+
if server_name not in name_counts:
|
161
|
+
name_counts[server_name] = 1
|
162
|
+
|
163
|
+
# Generate a new name with suffix
|
164
|
+
suffix = name_counts[server_name]
|
165
|
+
final_name = f"{server_name}_{suffix}"
|
166
|
+
name_counts[server_name] += 1
|
167
|
+
|
168
|
+
# Ensure the new name is also unique
|
169
|
+
while final_name in server_configs:
|
170
|
+
suffix = name_counts[server_name]
|
171
|
+
final_name = f"{server_name}_{suffix}"
|
172
|
+
name_counts[server_name] += 1
|
173
|
+
|
174
|
+
config = {
|
175
|
+
"transport": transport_type,
|
176
|
+
"url": url,
|
177
|
+
}
|
178
|
+
|
179
|
+
# Add headers if provided
|
180
|
+
if headers:
|
181
|
+
config["headers"] = headers
|
182
|
+
|
183
|
+
server_configs[final_name] = config
|
184
|
+
|
185
|
+
return server_configs
|
@@ -60,7 +60,7 @@ class MCPServerSettings(BaseModel):
|
|
60
60
|
description: str | None = None
|
61
61
|
"""The description of the server."""
|
62
62
|
|
63
|
-
transport: Literal["stdio", "sse"] = "stdio"
|
63
|
+
transport: Literal["stdio", "sse", "http"] = "stdio"
|
64
64
|
"""The transport mechanism."""
|
65
65
|
|
66
66
|
command: str | None = None
|
@@ -249,6 +249,8 @@ class LoggerSettings(BaseModel):
|
|
249
249
|
"""Show MCP Sever tool calls on the console"""
|
250
250
|
truncate_tools: bool = True
|
251
251
|
"""Truncate display of long tool calls"""
|
252
|
+
enable_markup: bool = True
|
253
|
+
"""Enable markup in console output. Disable for outputs that may conflict with rich console formatting"""
|
252
254
|
|
253
255
|
|
254
256
|
class Settings(BaseSettings):
|
@@ -131,8 +131,8 @@ class FastAgent:
|
|
131
131
|
)
|
132
132
|
parser.add_argument(
|
133
133
|
"--transport",
|
134
|
-
choices=["sse", "stdio"],
|
135
|
-
default="
|
134
|
+
choices=["sse", "http", "stdio"],
|
135
|
+
default="http",
|
136
136
|
help="Transport protocol to use when running as a server (sse or stdio)",
|
137
137
|
)
|
138
138
|
parser.add_argument(
|
@@ -25,24 +25,23 @@ class RequestParams(CreateMessageRequestParams):
|
|
25
25
|
|
26
26
|
model: str | None = None
|
27
27
|
"""
|
28
|
-
The model to use for the LLM generation.
|
28
|
+
The model to use for the LLM generation. This can only be set during Agent creation.
|
29
29
|
If specified, this overrides the 'modelPreferences' selection criteria.
|
30
30
|
"""
|
31
31
|
|
32
32
|
use_history: bool = True
|
33
33
|
"""
|
34
|
-
|
34
|
+
Agent/LLM maintains conversation history. Does not include applied Prompts
|
35
35
|
"""
|
36
36
|
|
37
|
-
max_iterations: int =
|
37
|
+
max_iterations: int = 20
|
38
38
|
"""
|
39
|
-
The maximum number of
|
39
|
+
The maximum number of tool calls allowed in a conversation turn
|
40
40
|
"""
|
41
41
|
|
42
42
|
parallel_tool_calls: bool = True
|
43
43
|
"""
|
44
|
-
Whether to allow
|
45
|
-
Also known as multi-step tool use.
|
44
|
+
Whether to allow simultaneous tool calls
|
46
45
|
"""
|
47
46
|
response_format: Any | None = None
|
48
47
|
"""
|
@@ -23,6 +23,7 @@ from mcp.client.stdio import (
|
|
23
23
|
get_default_environment,
|
24
24
|
stdio_client,
|
25
25
|
)
|
26
|
+
from mcp.client.streamable_http import GetSessionIdCallback, streamablehttp_client
|
26
27
|
from mcp.types import JSONRPCMessage, ServerCapabilities
|
27
28
|
|
28
29
|
from mcp_agent.config import MCPServerSettings
|
@@ -40,6 +41,27 @@ if TYPE_CHECKING:
|
|
40
41
|
logger = get_logger(__name__)
|
41
42
|
|
42
43
|
|
44
|
+
class StreamingContextAdapter:
|
45
|
+
"""Adapter to provide a 3-value context from a 2-value context manager"""
|
46
|
+
|
47
|
+
def __init__(self, context_manager):
|
48
|
+
self.context_manager = context_manager
|
49
|
+
self.cm_instance = None
|
50
|
+
|
51
|
+
async def __aenter__(self):
|
52
|
+
self.cm_instance = await self.context_manager.__aenter__()
|
53
|
+
read_stream, write_stream = self.cm_instance
|
54
|
+
return read_stream, write_stream, None
|
55
|
+
|
56
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
57
|
+
return await self.context_manager.__aexit__(exc_type, exc_val, exc_tb)
|
58
|
+
|
59
|
+
|
60
|
+
def _add_none_to_context(context_manager):
|
61
|
+
"""Helper to add a None value to context managers that return 2 values instead of 3"""
|
62
|
+
return StreamingContextAdapter(context_manager)
|
63
|
+
|
64
|
+
|
43
65
|
class ServerConnection:
|
44
66
|
"""
|
45
67
|
Represents a long-lived MCP server connection, including:
|
@@ -57,6 +79,7 @@ class ServerConnection:
|
|
57
79
|
tuple[
|
58
80
|
MemoryObjectReceiveStream[JSONRPCMessage | Exception],
|
59
81
|
MemoryObjectSendStream[JSONRPCMessage],
|
82
|
+
GetSessionIdCallback | None,
|
60
83
|
],
|
61
84
|
None,
|
62
85
|
],
|
@@ -162,7 +185,7 @@ async def _server_lifecycle_task(server_conn: ServerConnection) -> None:
|
|
162
185
|
try:
|
163
186
|
transport_context = server_conn._transport_context_factory()
|
164
187
|
|
165
|
-
async with transport_context as (read_stream, write_stream):
|
188
|
+
async with transport_context as (read_stream, write_stream, _):
|
166
189
|
server_conn.create_session(read_stream, write_stream)
|
167
190
|
|
168
191
|
async with server_conn.session:
|
@@ -303,14 +326,17 @@ class MCPConnectionManager(ContextDependent):
|
|
303
326
|
error_handler = get_stderr_handler(server_name)
|
304
327
|
# Explicitly ensure we're using our custom logger for stderr
|
305
328
|
logger.debug(f"{server_name}: Creating stdio client with custom error handler")
|
306
|
-
return stdio_client(server_params, errlog=error_handler)
|
329
|
+
return _add_none_to_context(stdio_client(server_params, errlog=error_handler))
|
307
330
|
elif config.transport == "sse":
|
308
|
-
return
|
309
|
-
|
310
|
-
|
311
|
-
|
331
|
+
return _add_none_to_context(
|
332
|
+
sse_client(
|
333
|
+
config.url,
|
334
|
+
config.headers,
|
335
|
+
sse_read_timeout=config.read_transport_sse_timeout_seconds,
|
336
|
+
)
|
312
337
|
)
|
313
|
-
|
338
|
+
elif config.transport == "http":
|
339
|
+
return streamablehttp_client(config.url, config.headers)
|
314
340
|
else:
|
315
341
|
raise ValueError(f"Unsupported transport: {config.transport}")
|
316
342
|
|
@@ -335,7 +335,7 @@ def parse_args():
|
|
335
335
|
parser.add_argument(
|
336
336
|
"--transport",
|
337
337
|
type=str,
|
338
|
-
choices=["stdio", "sse"],
|
338
|
+
choices=["stdio", "sse", "http"],
|
339
339
|
default="stdio",
|
340
340
|
help="Transport to use (default: stdio)",
|
341
341
|
)
|
@@ -502,14 +502,22 @@ async def async_main() -> int:
|
|
502
502
|
return await test_prompt(args.test, config)
|
503
503
|
|
504
504
|
# Start the server with the specified transport
|
505
|
-
if config.transport == "
|
506
|
-
await mcp.run_stdio_async()
|
507
|
-
else: # sse
|
505
|
+
if config.transport == "sse": # sse
|
508
506
|
# Set the host and port in settings before running the server
|
509
507
|
mcp.settings.host = config.host
|
510
508
|
mcp.settings.port = config.port
|
511
509
|
logger.info(f"Starting SSE server on {config.host}:{config.port}")
|
512
510
|
await mcp.run_sse_async()
|
511
|
+
elif config.transport == "http":
|
512
|
+
mcp.settings.host = config.host
|
513
|
+
mcp.settings.port = config.port
|
514
|
+
logger.info(f"Starting SSE server on {config.host}:{config.port}")
|
515
|
+
await mcp.run_streamable_http_async()
|
516
|
+
elif config.transport == "stdio":
|
517
|
+
await mcp.run_stdio_async()
|
518
|
+
else:
|
519
|
+
logger.error(f"Unknown transport: {config.transport}")
|
520
|
+
return 1
|
513
521
|
return 0
|
514
522
|
|
515
523
|
|