fast-agent-mcp 0.2.22__tar.gz → 0.2.24__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.24}/.gitignore +2 -3
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/PKG-INFO +3 -2
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/pyproject.toml +2 -2
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/agents/workflow/orchestrator_agent.py +2 -2
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/cli/commands/go.py +94 -29
- fast_agent_mcp-0.2.24/src/mcp_agent/cli/commands/url_parser.py +185 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/config.py +3 -1
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/context.py +2 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/core/fastagent.py +2 -2
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/core/request_params.py +5 -6
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/llm/providers/augmented_llm_openai.py +3 -1
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/mcp/mcp_agent_client_session.py +41 -11
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/mcp/mcp_aggregator.py +133 -2
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/mcp/mcp_connection_manager.py +33 -7
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/mcp/prompts/prompt_server.py +12 -4
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/mcp_server/agent_server.py +13 -10
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/mcp_server_registry.py +51 -9
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/mcp/state-transfer/fastagent.config.yaml +2 -2
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/ui/console_display.py +7 -6
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/LICENSE +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/README.md +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/data-analysis/analysis-campaign.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/data-analysis/analysis.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/data-analysis/fastagent.config.yaml +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/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.24}/examples/mcp/state-transfer/agent_one.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/mcp/state-transfer/agent_two.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/mcp/state-transfer/fastagent.config.yaml +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/mcp/vision-examples/example1.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/mcp/vision-examples/example2.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/mcp/vision-examples/example3.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/mcp/vision-examples/fastagent.config.yaml +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/otel/agent.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/otel/agent2.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/otel/docker-compose.yaml +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/otel/fastagent.config.yaml +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/researcher/fastagent.config.yaml +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/researcher/researcher-eval.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/researcher/researcher-imp.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/researcher/researcher.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/tensorzero/README.md +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/tensorzero/agent.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/tensorzero/docker-compose.yml +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/tensorzero/fastagent.config.yaml +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/tensorzero/image_demo.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/tensorzero/mcp_server/mcp_server.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/tensorzero/simple_agent.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/workflows/chaining.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/workflows/evaluator.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/workflows/fastagent.config.yaml +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/workflows/graded_report.md +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/workflows/human_input.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/workflows/orchestrator.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/workflows/parallel.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/workflows/router.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/workflows/short_story.md +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/examples/workflows/short_story.txt +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/__init__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/agents/__init__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/agents/agent.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/agents/base_agent.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/agents/workflow/__init__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/agents/workflow/chain_agent.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/agents/workflow/evaluator_optimizer.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/agents/workflow/orchestrator_models.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/agents/workflow/orchestrator_prompts.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/agents/workflow/parallel_agent.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/agents/workflow/router_agent.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/app.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/cli/__init__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/cli/__main__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/cli/commands/check_config.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/cli/commands/quickstart.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/cli/commands/setup.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/cli/main.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/cli/terminal.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/console.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/context_dependent.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/core/__init__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/core/agent_app.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/core/agent_types.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/core/direct_decorators.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/core/direct_factory.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/core/enhanced_prompt.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/core/error_handling.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/core/exceptions.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/core/interactive_prompt.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/core/mcp_content.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/core/prompt.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/core/validation.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/event_progress.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/executor/__init__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/executor/executor.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/executor/task_registry.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/executor/workflow_signal.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/human_input/__init__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/human_input/handler.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/human_input/types.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/llm/__init__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/llm/augmented_llm.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/llm/augmented_llm_passthrough.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/llm/augmented_llm_playback.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/llm/memory.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/llm/model_factory.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/llm/prompt_utils.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/llm/provider_key_manager.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/llm/provider_types.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/llm/providers/__init__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/llm/providers/anthropic_utils.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/llm/providers/augmented_llm_anthropic.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/llm/providers/augmented_llm_deepseek.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/llm/providers/augmented_llm_generic.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/llm/providers/augmented_llm_google.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/llm/providers/augmented_llm_openrouter.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/llm/providers/augmented_llm_tensorzero.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/llm/providers/multipart_converter_anthropic.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/llm/providers/multipart_converter_openai.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/llm/providers/multipart_converter_tensorzero.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/llm/providers/openai_multipart.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/llm/providers/openai_utils.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/llm/providers/sampling_converter_anthropic.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/llm/providers/sampling_converter_openai.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/llm/sampling_converter.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/llm/sampling_format_converter.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/logging/__init__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/logging/events.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/logging/json_serializer.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/logging/listeners.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/logging/logger.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/logging/rich_progress.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/logging/transport.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/mcp/__init__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/mcp/gen_client.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/mcp/helpers/__init__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/mcp/helpers/content_helpers.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/mcp/interfaces.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/mcp/logger_textio.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/mcp/mime_utils.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/mcp/prompt_message_multipart.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/mcp/prompt_render.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/mcp/prompt_serialization.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/mcp/prompts/__init__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/mcp/prompts/__main__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/mcp/prompts/prompt_constants.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/mcp/prompts/prompt_helpers.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/mcp/prompts/prompt_load.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/mcp/prompts/prompt_template.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/mcp/resource_utils.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/mcp/sampling.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/mcp_server/__init__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/progress_display.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/data-analysis/analysis-campaign.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/data-analysis/analysis.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/data-analysis/fastagent.config.yaml +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/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.24}/src/mcp_agent/resources/examples/in_dev/agent_build.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/in_dev/css-LICENSE.txt +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/in_dev/slides.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/internal/agent.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/internal/fastagent.config.yaml +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/internal/history_transfer.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/internal/job.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/internal/prompt_category.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/internal/prompt_sizing.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/internal/simple.txt +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/internal/sizer.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/internal/social.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/mcp/state-transfer/agent_one.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/mcp/state-transfer/agent_two.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/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.24}/src/mcp_agent/resources/examples/prompting/__init__.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/prompting/agent.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/prompting/delimited_prompt.txt +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/prompting/fastagent.config.yaml +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/prompting/image_server.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/prompting/prompt1.txt +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/prompting/work_with_image.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/researcher/fastagent.config.yaml +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/researcher/researcher-eval.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/researcher/researcher-imp.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/researcher/researcher.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/workflows/chaining.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/workflows/evaluator.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/workflows/fastagent.config.yaml +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/workflows/human_input.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/workflows/orchestrator.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/workflows/parallel.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/resources/examples/workflows/router.py +0 -0
- {fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/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
|
@@ -197,6 +197,5 @@ tests/integration/prompt-state/history.json
|
|
197
197
|
!tests/integration/api/fastagent.secrets.yaml
|
198
198
|
fastagent.jsonl
|
199
199
|
|
200
|
-
# JetBrains IDEs
|
201
|
-
.idea/
|
202
200
|
tests/e2e/smoke/base/weather_location.txt
|
201
|
+
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.24
|
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/
|
@@ -218,6 +218,7 @@ Requires-Dist: openai>=1.63.2
|
|
218
218
|
Requires-Dist: opentelemetry-distro>=0.50b0
|
219
219
|
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.29.0
|
220
220
|
Requires-Dist: opentelemetry-instrumentation-anthropic>=0.39.3
|
221
|
+
Requires-Dist: opentelemetry-instrumentation-mcp>=0.40.3
|
221
222
|
Requires-Dist: opentelemetry-instrumentation-openai>=0.39.3
|
222
223
|
Requires-Dist: prompt-toolkit>=3.0.50
|
223
224
|
Requires-Dist: pydantic-settings>=2.7.0
|
@@ -1,12 +1,11 @@
|
|
1
1
|
[project]
|
2
2
|
name = "fast-agent-mcp"
|
3
|
-
version = "0.2.
|
3
|
+
version = "0.2.24"
|
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",
|
@@ -32,6 +31,7 @@ dependencies = [
|
|
32
31
|
"opentelemetry-instrumentation-openai>=0.39.3",
|
33
32
|
"opentelemetry-instrumentation-anthropic>=0.39.3",
|
34
33
|
"tensorzero>=2025.4.7",
|
34
|
+
"opentelemetry-instrumentation-mcp>=0.40.3",
|
35
35
|
]
|
36
36
|
|
37
37
|
[project.optional-dependencies]
|
{fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/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):
|
@@ -11,6 +11,7 @@ from mcp import ServerSession
|
|
11
11
|
from opentelemetry import trace
|
12
12
|
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
|
13
13
|
from opentelemetry.instrumentation.anthropic import AnthropicInstrumentor
|
14
|
+
from opentelemetry.instrumentation.mcp import McpInstrumentor
|
14
15
|
from opentelemetry.instrumentation.openai import OpenAIInstrumentor
|
15
16
|
from opentelemetry.propagate import set_global_textmap
|
16
17
|
from opentelemetry.sdk.resources import Resource
|
@@ -111,6 +112,7 @@ async def configure_otel(config: "Settings") -> None:
|
|
111
112
|
trace.set_tracer_provider(tracer_provider)
|
112
113
|
AnthropicInstrumentor().instrument()
|
113
114
|
OpenAIInstrumentor().instrument()
|
115
|
+
McpInstrumentor().instrument()
|
114
116
|
|
115
117
|
|
116
118
|
async def configure_logger(config: "Settings") -> None:
|
@@ -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
|
"""
|
{fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/llm/providers/augmented_llm_openai.py
RENAMED
@@ -274,7 +274,9 @@ class OpenAIAugmentedLLM(AugmentedLLM[ChatCompletionMessageParam, ChatCompletion
|
|
274
274
|
# Calculate new conversation messages (excluding prompts)
|
275
275
|
new_messages = messages[len(prompt_messages) :]
|
276
276
|
|
277
|
-
|
277
|
+
if system_prompt:
|
278
|
+
new_messages = new_messages[1:]
|
279
|
+
|
278
280
|
self.history.set(new_messages)
|
279
281
|
|
280
282
|
self._log_chat_finished(model=self.default_request_params.model)
|
{fast_agent_mcp-0.2.22 → fast_agent_mcp-0.2.24}/src/mcp_agent/mcp/mcp_agent_client_session.py
RENAMED
@@ -6,21 +6,16 @@ It adds logging and supports sampling requests.
|
|
6
6
|
from datetime import timedelta
|
7
7
|
from typing import TYPE_CHECKING, Optional
|
8
8
|
|
9
|
-
from mcp import ClientSession
|
9
|
+
from mcp import ClientSession, ServerNotification
|
10
10
|
from mcp.shared.session import (
|
11
|
-
ReceiveNotificationT,
|
12
11
|
ReceiveResultT,
|
13
12
|
RequestId,
|
14
13
|
SendNotificationT,
|
15
14
|
SendRequestT,
|
16
15
|
SendResultT,
|
17
16
|
)
|
18
|
-
from mcp.types import
|
19
|
-
|
20
|
-
ListRootsResult,
|
21
|
-
Root,
|
22
|
-
)
|
23
|
-
from pydantic import AnyUrl
|
17
|
+
from mcp.types import ErrorData, ListRootsResult, Root, ToolListChangedNotification
|
18
|
+
from pydantic import FileUrl
|
24
19
|
|
25
20
|
from mcp_agent.context_dependent import ContextDependent
|
26
21
|
from mcp_agent.logging.logger import get_logger
|
@@ -45,7 +40,7 @@ async def list_roots(ctx: ClientSession) -> ListRootsResult:
|
|
45
40
|
):
|
46
41
|
roots = [
|
47
42
|
Root(
|
48
|
-
uri=
|
43
|
+
uri=FileUrl(
|
49
44
|
root.server_uri_alias or root.uri,
|
50
45
|
),
|
51
46
|
name=root.name,
|
@@ -67,6 +62,11 @@ class MCPAgentClientSession(ClientSession, ContextDependent):
|
|
67
62
|
"""
|
68
63
|
|
69
64
|
def __init__(self, *args, **kwargs) -> None:
|
65
|
+
# Extract server_name if provided in kwargs
|
66
|
+
self.session_server_name = kwargs.pop("server_name", None)
|
67
|
+
# Extract the notification callbacks if provided
|
68
|
+
self._tool_list_changed_callback = kwargs.pop("tool_list_changed_callback", None)
|
69
|
+
|
70
70
|
super().__init__(*args, **kwargs, list_roots_callback=list_roots, sampling_callback=sample)
|
71
71
|
self.server_config: Optional[MCPServerSettings] = None
|
72
72
|
|
@@ -104,7 +104,7 @@ class MCPAgentClientSession(ClientSession, ContextDependent):
|
|
104
104
|
)
|
105
105
|
return await super()._send_response(request_id, response)
|
106
106
|
|
107
|
-
async def _received_notification(self, notification:
|
107
|
+
async def _received_notification(self, notification: ServerNotification) -> None:
|
108
108
|
"""
|
109
109
|
Can be overridden by subclasses to handle a notification without needing
|
110
110
|
to listen on the message stream.
|
@@ -113,7 +113,37 @@ class MCPAgentClientSession(ClientSession, ContextDependent):
|
|
113
113
|
"_received_notification: notification=",
|
114
114
|
data=notification.model_dump(),
|
115
115
|
)
|
116
|
-
|
116
|
+
|
117
|
+
# Call parent notification handler first
|
118
|
+
await super()._received_notification(notification)
|
119
|
+
|
120
|
+
# Then process our specific notification types
|
121
|
+
match notification.root:
|
122
|
+
case ToolListChangedNotification():
|
123
|
+
# Simple notification handling - just call the callback if it exists
|
124
|
+
if self._tool_list_changed_callback and self.session_server_name:
|
125
|
+
logger.info(
|
126
|
+
f"Tool list changed for server '{self.session_server_name}', triggering callback"
|
127
|
+
)
|
128
|
+
# Use asyncio.create_task to prevent blocking the notification handler
|
129
|
+
import asyncio
|
130
|
+
asyncio.create_task(self._handle_tool_list_change_callback(self.session_server_name))
|
131
|
+
else:
|
132
|
+
logger.debug(
|
133
|
+
f"Tool list changed for server '{self.session_server_name}' but no callback registered"
|
134
|
+
)
|
135
|
+
|
136
|
+
return None
|
137
|
+
|
138
|
+
async def _handle_tool_list_change_callback(self, server_name: str) -> None:
|
139
|
+
"""
|
140
|
+
Helper method to handle tool list change callback in a separate task
|
141
|
+
to prevent blocking the notification handler
|
142
|
+
"""
|
143
|
+
try:
|
144
|
+
await self._tool_list_changed_callback(server_name)
|
145
|
+
except Exception as e:
|
146
|
+
logger.error(f"Error in tool list changed callback: {e}")
|
117
147
|
|
118
148
|
async def send_progress_notification(
|
119
149
|
self, progress_token: str | int, progress: float, total: float | None = None
|