aip-agents-binary 0.5.25b1__py3-none-macosx_13_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aip_agents/__init__.py +65 -0
- aip_agents/__init__.pyi +19 -0
- aip_agents/a2a/__init__.py +19 -0
- aip_agents/a2a/__init__.pyi +3 -0
- aip_agents/a2a/server/__init__.py +10 -0
- aip_agents/a2a/server/__init__.pyi +4 -0
- aip_agents/a2a/server/base_executor.py +1086 -0
- aip_agents/a2a/server/base_executor.pyi +73 -0
- aip_agents/a2a/server/google_adk_executor.py +198 -0
- aip_agents/a2a/server/google_adk_executor.pyi +51 -0
- aip_agents/a2a/server/langflow_executor.py +180 -0
- aip_agents/a2a/server/langflow_executor.pyi +43 -0
- aip_agents/a2a/server/langgraph_executor.py +270 -0
- aip_agents/a2a/server/langgraph_executor.pyi +47 -0
- aip_agents/a2a/types.py +232 -0
- aip_agents/a2a/types.pyi +132 -0
- aip_agents/agent/__init__.py +27 -0
- aip_agents/agent/__init__.pyi +9 -0
- aip_agents/agent/base_agent.py +970 -0
- aip_agents/agent/base_agent.pyi +221 -0
- aip_agents/agent/base_langgraph_agent.py +2948 -0
- aip_agents/agent/base_langgraph_agent.pyi +232 -0
- aip_agents/agent/google_adk_agent.py +926 -0
- aip_agents/agent/google_adk_agent.pyi +141 -0
- aip_agents/agent/google_adk_constants.py +6 -0
- aip_agents/agent/google_adk_constants.pyi +3 -0
- aip_agents/agent/hitl/__init__.py +24 -0
- aip_agents/agent/hitl/__init__.pyi +6 -0
- aip_agents/agent/hitl/config.py +28 -0
- aip_agents/agent/hitl/config.pyi +15 -0
- aip_agents/agent/hitl/langgraph_hitl_mixin.py +515 -0
- aip_agents/agent/hitl/langgraph_hitl_mixin.pyi +42 -0
- aip_agents/agent/hitl/manager.py +532 -0
- aip_agents/agent/hitl/manager.pyi +200 -0
- aip_agents/agent/hitl/models.py +18 -0
- aip_agents/agent/hitl/models.pyi +3 -0
- aip_agents/agent/hitl/prompt/__init__.py +9 -0
- aip_agents/agent/hitl/prompt/__init__.pyi +4 -0
- aip_agents/agent/hitl/prompt/base.py +42 -0
- aip_agents/agent/hitl/prompt/base.pyi +24 -0
- aip_agents/agent/hitl/prompt/deferred.py +73 -0
- aip_agents/agent/hitl/prompt/deferred.pyi +30 -0
- aip_agents/agent/hitl/registry.py +149 -0
- aip_agents/agent/hitl/registry.pyi +101 -0
- aip_agents/agent/interface.py +138 -0
- aip_agents/agent/interface.pyi +81 -0
- aip_agents/agent/interfaces.py +65 -0
- aip_agents/agent/interfaces.pyi +44 -0
- aip_agents/agent/langflow_agent.py +464 -0
- aip_agents/agent/langflow_agent.pyi +133 -0
- aip_agents/agent/langgraph_memory_enhancer_agent.py +433 -0
- aip_agents/agent/langgraph_memory_enhancer_agent.pyi +49 -0
- aip_agents/agent/langgraph_react_agent.py +2596 -0
- aip_agents/agent/langgraph_react_agent.pyi +131 -0
- aip_agents/agent/system_instruction_context.py +34 -0
- aip_agents/agent/system_instruction_context.pyi +13 -0
- aip_agents/clients/__init__.py +10 -0
- aip_agents/clients/__init__.pyi +4 -0
- aip_agents/clients/langflow/__init__.py +10 -0
- aip_agents/clients/langflow/__init__.pyi +4 -0
- aip_agents/clients/langflow/client.py +477 -0
- aip_agents/clients/langflow/client.pyi +140 -0
- aip_agents/clients/langflow/types.py +18 -0
- aip_agents/clients/langflow/types.pyi +7 -0
- aip_agents/constants.py +23 -0
- aip_agents/constants.pyi +7 -0
- aip_agents/credentials/manager.py +132 -0
- aip_agents/examples/__init__.py +5 -0
- aip_agents/examples/__init__.pyi +0 -0
- aip_agents/examples/compare_streaming_client.py +783 -0
- aip_agents/examples/compare_streaming_client.pyi +48 -0
- aip_agents/examples/compare_streaming_server.py +142 -0
- aip_agents/examples/compare_streaming_server.pyi +18 -0
- aip_agents/examples/demo_memory_recall.py +401 -0
- aip_agents/examples/demo_memory_recall.pyi +58 -0
- aip_agents/examples/hello_world_a2a_google_adk_client.py +49 -0
- aip_agents/examples/hello_world_a2a_google_adk_client.pyi +9 -0
- aip_agents/examples/hello_world_a2a_google_adk_client_agent.py +48 -0
- aip_agents/examples/hello_world_a2a_google_adk_client_agent.pyi +9 -0
- aip_agents/examples/hello_world_a2a_google_adk_client_streaming.py +60 -0
- aip_agents/examples/hello_world_a2a_google_adk_client_streaming.pyi +9 -0
- aip_agents/examples/hello_world_a2a_google_adk_server.py +79 -0
- aip_agents/examples/hello_world_a2a_google_adk_server.pyi +15 -0
- aip_agents/examples/hello_world_a2a_langchain_client.py +39 -0
- aip_agents/examples/hello_world_a2a_langchain_client.pyi +5 -0
- aip_agents/examples/hello_world_a2a_langchain_client_agent.py +39 -0
- aip_agents/examples/hello_world_a2a_langchain_client_agent.pyi +5 -0
- aip_agents/examples/hello_world_a2a_langchain_client_lm_invoker.py +37 -0
- aip_agents/examples/hello_world_a2a_langchain_client_lm_invoker.pyi +5 -0
- aip_agents/examples/hello_world_a2a_langchain_client_streaming.py +41 -0
- aip_agents/examples/hello_world_a2a_langchain_client_streaming.pyi +5 -0
- aip_agents/examples/hello_world_a2a_langchain_reference_client_streaming.py +60 -0
- aip_agents/examples/hello_world_a2a_langchain_reference_client_streaming.pyi +5 -0
- aip_agents/examples/hello_world_a2a_langchain_reference_server.py +105 -0
- aip_agents/examples/hello_world_a2a_langchain_reference_server.pyi +15 -0
- aip_agents/examples/hello_world_a2a_langchain_server.py +79 -0
- aip_agents/examples/hello_world_a2a_langchain_server.pyi +15 -0
- aip_agents/examples/hello_world_a2a_langchain_server_lm_invoker.py +78 -0
- aip_agents/examples/hello_world_a2a_langchain_server_lm_invoker.pyi +15 -0
- aip_agents/examples/hello_world_a2a_langflow_client.py +83 -0
- aip_agents/examples/hello_world_a2a_langflow_client.pyi +9 -0
- aip_agents/examples/hello_world_a2a_langflow_server.py +82 -0
- aip_agents/examples/hello_world_a2a_langflow_server.pyi +14 -0
- aip_agents/examples/hello_world_a2a_langgraph_artifact_client.py +73 -0
- aip_agents/examples/hello_world_a2a_langgraph_artifact_client.pyi +5 -0
- aip_agents/examples/hello_world_a2a_langgraph_artifact_client_streaming.py +76 -0
- aip_agents/examples/hello_world_a2a_langgraph_artifact_client_streaming.pyi +5 -0
- aip_agents/examples/hello_world_a2a_langgraph_artifact_server.py +92 -0
- aip_agents/examples/hello_world_a2a_langgraph_artifact_server.pyi +16 -0
- aip_agents/examples/hello_world_a2a_langgraph_client.py +54 -0
- aip_agents/examples/hello_world_a2a_langgraph_client.pyi +9 -0
- aip_agents/examples/hello_world_a2a_langgraph_client_agent.py +54 -0
- aip_agents/examples/hello_world_a2a_langgraph_client_agent.pyi +9 -0
- aip_agents/examples/hello_world_a2a_langgraph_client_agent_lm_invoker.py +32 -0
- aip_agents/examples/hello_world_a2a_langgraph_client_agent_lm_invoker.pyi +2 -0
- aip_agents/examples/hello_world_a2a_langgraph_client_streaming.py +50 -0
- aip_agents/examples/hello_world_a2a_langgraph_client_streaming.pyi +9 -0
- aip_agents/examples/hello_world_a2a_langgraph_client_streaming_lm_invoker.py +44 -0
- aip_agents/examples/hello_world_a2a_langgraph_client_streaming_lm_invoker.pyi +5 -0
- aip_agents/examples/hello_world_a2a_langgraph_client_streaming_tool_streaming.py +92 -0
- aip_agents/examples/hello_world_a2a_langgraph_client_streaming_tool_streaming.pyi +5 -0
- aip_agents/examples/hello_world_a2a_langgraph_server.py +84 -0
- aip_agents/examples/hello_world_a2a_langgraph_server.pyi +14 -0
- aip_agents/examples/hello_world_a2a_langgraph_server_lm_invoker.py +79 -0
- aip_agents/examples/hello_world_a2a_langgraph_server_lm_invoker.pyi +15 -0
- aip_agents/examples/hello_world_a2a_langgraph_server_tool_streaming.py +132 -0
- aip_agents/examples/hello_world_a2a_langgraph_server_tool_streaming.pyi +15 -0
- aip_agents/examples/hello_world_a2a_mcp_langgraph.py +196 -0
- aip_agents/examples/hello_world_a2a_mcp_langgraph.pyi +48 -0
- aip_agents/examples/hello_world_a2a_three_level_agent_hierarchy_client.py +244 -0
- aip_agents/examples/hello_world_a2a_three_level_agent_hierarchy_client.pyi +48 -0
- aip_agents/examples/hello_world_a2a_three_level_agent_hierarchy_server.py +251 -0
- aip_agents/examples/hello_world_a2a_three_level_agent_hierarchy_server.pyi +45 -0
- aip_agents/examples/hello_world_a2a_with_metadata_langchain_client.py +57 -0
- aip_agents/examples/hello_world_a2a_with_metadata_langchain_client.pyi +5 -0
- aip_agents/examples/hello_world_a2a_with_metadata_langchain_server_lm_invoker.py +80 -0
- aip_agents/examples/hello_world_a2a_with_metadata_langchain_server_lm_invoker.pyi +15 -0
- aip_agents/examples/hello_world_google_adk.py +41 -0
- aip_agents/examples/hello_world_google_adk.pyi +5 -0
- aip_agents/examples/hello_world_google_adk_mcp_http.py +34 -0
- aip_agents/examples/hello_world_google_adk_mcp_http.pyi +5 -0
- aip_agents/examples/hello_world_google_adk_mcp_http_stream.py +40 -0
- aip_agents/examples/hello_world_google_adk_mcp_http_stream.pyi +5 -0
- aip_agents/examples/hello_world_google_adk_mcp_sse.py +44 -0
- aip_agents/examples/hello_world_google_adk_mcp_sse.pyi +5 -0
- aip_agents/examples/hello_world_google_adk_mcp_sse_stream.py +48 -0
- aip_agents/examples/hello_world_google_adk_mcp_sse_stream.pyi +5 -0
- aip_agents/examples/hello_world_google_adk_mcp_stdio.py +44 -0
- aip_agents/examples/hello_world_google_adk_mcp_stdio.pyi +5 -0
- aip_agents/examples/hello_world_google_adk_mcp_stdio_stream.py +48 -0
- aip_agents/examples/hello_world_google_adk_mcp_stdio_stream.pyi +5 -0
- aip_agents/examples/hello_world_google_adk_stream.py +44 -0
- aip_agents/examples/hello_world_google_adk_stream.pyi +5 -0
- aip_agents/examples/hello_world_langchain.py +28 -0
- aip_agents/examples/hello_world_langchain.pyi +5 -0
- aip_agents/examples/hello_world_langchain_lm_invoker.py +15 -0
- aip_agents/examples/hello_world_langchain_lm_invoker.pyi +2 -0
- aip_agents/examples/hello_world_langchain_mcp_http.py +34 -0
- aip_agents/examples/hello_world_langchain_mcp_http.pyi +5 -0
- aip_agents/examples/hello_world_langchain_mcp_http_interactive.py +130 -0
- aip_agents/examples/hello_world_langchain_mcp_http_interactive.pyi +16 -0
- aip_agents/examples/hello_world_langchain_mcp_http_stream.py +42 -0
- aip_agents/examples/hello_world_langchain_mcp_http_stream.pyi +5 -0
- aip_agents/examples/hello_world_langchain_mcp_multi_server.py +155 -0
- aip_agents/examples/hello_world_langchain_mcp_multi_server.pyi +18 -0
- aip_agents/examples/hello_world_langchain_mcp_sse.py +34 -0
- aip_agents/examples/hello_world_langchain_mcp_sse.pyi +5 -0
- aip_agents/examples/hello_world_langchain_mcp_sse_stream.py +40 -0
- aip_agents/examples/hello_world_langchain_mcp_sse_stream.pyi +5 -0
- aip_agents/examples/hello_world_langchain_mcp_stdio.py +30 -0
- aip_agents/examples/hello_world_langchain_mcp_stdio.pyi +5 -0
- aip_agents/examples/hello_world_langchain_mcp_stdio_stream.py +41 -0
- aip_agents/examples/hello_world_langchain_mcp_stdio_stream.pyi +5 -0
- aip_agents/examples/hello_world_langchain_stream.py +36 -0
- aip_agents/examples/hello_world_langchain_stream.pyi +5 -0
- aip_agents/examples/hello_world_langchain_stream_lm_invoker.py +39 -0
- aip_agents/examples/hello_world_langchain_stream_lm_invoker.pyi +5 -0
- aip_agents/examples/hello_world_langflow_agent.py +163 -0
- aip_agents/examples/hello_world_langflow_agent.pyi +35 -0
- aip_agents/examples/hello_world_langgraph.py +39 -0
- aip_agents/examples/hello_world_langgraph.pyi +5 -0
- aip_agents/examples/hello_world_langgraph_gl_connector_twitter.py +44 -0
- aip_agents/examples/hello_world_langgraph_gl_connector_twitter.pyi +5 -0
- aip_agents/examples/hello_world_langgraph_mcp_http.py +31 -0
- aip_agents/examples/hello_world_langgraph_mcp_http.pyi +5 -0
- aip_agents/examples/hello_world_langgraph_mcp_http_stream.py +34 -0
- aip_agents/examples/hello_world_langgraph_mcp_http_stream.pyi +5 -0
- aip_agents/examples/hello_world_langgraph_mcp_sse.py +35 -0
- aip_agents/examples/hello_world_langgraph_mcp_sse.pyi +5 -0
- aip_agents/examples/hello_world_langgraph_mcp_sse_stream.py +50 -0
- aip_agents/examples/hello_world_langgraph_mcp_sse_stream.pyi +5 -0
- aip_agents/examples/hello_world_langgraph_mcp_stdio.py +35 -0
- aip_agents/examples/hello_world_langgraph_mcp_stdio.pyi +5 -0
- aip_agents/examples/hello_world_langgraph_mcp_stdio_stream.py +50 -0
- aip_agents/examples/hello_world_langgraph_mcp_stdio_stream.pyi +5 -0
- aip_agents/examples/hello_world_langgraph_stream.py +43 -0
- aip_agents/examples/hello_world_langgraph_stream.pyi +5 -0
- aip_agents/examples/hello_world_langgraph_stream_lm_invoker.py +37 -0
- aip_agents/examples/hello_world_langgraph_stream_lm_invoker.pyi +5 -0
- aip_agents/examples/hello_world_model_switch_cli.py +210 -0
- aip_agents/examples/hello_world_model_switch_cli.pyi +30 -0
- aip_agents/examples/hello_world_multi_agent_adk.py +75 -0
- aip_agents/examples/hello_world_multi_agent_adk.pyi +6 -0
- aip_agents/examples/hello_world_multi_agent_langchain.py +54 -0
- aip_agents/examples/hello_world_multi_agent_langchain.pyi +5 -0
- aip_agents/examples/hello_world_multi_agent_langgraph.py +66 -0
- aip_agents/examples/hello_world_multi_agent_langgraph.pyi +5 -0
- aip_agents/examples/hello_world_multi_agent_langgraph_lm_invoker.py +69 -0
- aip_agents/examples/hello_world_multi_agent_langgraph_lm_invoker.pyi +5 -0
- aip_agents/examples/hello_world_pii_logger.py +21 -0
- aip_agents/examples/hello_world_pii_logger.pyi +5 -0
- aip_agents/examples/hello_world_sentry.py +133 -0
- aip_agents/examples/hello_world_sentry.pyi +21 -0
- aip_agents/examples/hello_world_step_limits.py +273 -0
- aip_agents/examples/hello_world_step_limits.pyi +17 -0
- aip_agents/examples/hello_world_stock_a2a_server.py +103 -0
- aip_agents/examples/hello_world_stock_a2a_server.pyi +17 -0
- aip_agents/examples/hello_world_tool_output_client.py +46 -0
- aip_agents/examples/hello_world_tool_output_client.pyi +5 -0
- aip_agents/examples/hello_world_tool_output_server.py +114 -0
- aip_agents/examples/hello_world_tool_output_server.pyi +19 -0
- aip_agents/examples/hitl_demo.py +724 -0
- aip_agents/examples/hitl_demo.pyi +67 -0
- aip_agents/examples/mcp_configs/configs.py +63 -0
- aip_agents/examples/mcp_servers/common.py +76 -0
- aip_agents/examples/mcp_servers/mcp_name.py +29 -0
- aip_agents/examples/mcp_servers/mcp_server_http.py +19 -0
- aip_agents/examples/mcp_servers/mcp_server_sse.py +19 -0
- aip_agents/examples/mcp_servers/mcp_server_stdio.py +19 -0
- aip_agents/examples/mcp_servers/mcp_time.py +10 -0
- aip_agents/examples/pii_demo_langgraph_client.py +69 -0
- aip_agents/examples/pii_demo_langgraph_client.pyi +5 -0
- aip_agents/examples/pii_demo_langgraph_server.py +126 -0
- aip_agents/examples/pii_demo_langgraph_server.pyi +20 -0
- aip_agents/examples/pii_demo_multi_agent_client.py +80 -0
- aip_agents/examples/pii_demo_multi_agent_client.pyi +5 -0
- aip_agents/examples/pii_demo_multi_agent_server.py +247 -0
- aip_agents/examples/pii_demo_multi_agent_server.pyi +40 -0
- aip_agents/examples/todolist_planning_a2a_langchain_client.py +70 -0
- aip_agents/examples/todolist_planning_a2a_langchain_client.pyi +5 -0
- aip_agents/examples/todolist_planning_a2a_langgraph_server.py +88 -0
- aip_agents/examples/todolist_planning_a2a_langgraph_server.pyi +19 -0
- aip_agents/examples/tools/__init__.py +27 -0
- aip_agents/examples/tools/__init__.pyi +9 -0
- aip_agents/examples/tools/adk_arithmetic_tools.py +36 -0
- aip_agents/examples/tools/adk_arithmetic_tools.pyi +24 -0
- aip_agents/examples/tools/adk_weather_tool.py +60 -0
- aip_agents/examples/tools/adk_weather_tool.pyi +18 -0
- aip_agents/examples/tools/data_generator_tool.py +103 -0
- aip_agents/examples/tools/data_generator_tool.pyi +15 -0
- aip_agents/examples/tools/data_visualization_tool.py +312 -0
- aip_agents/examples/tools/data_visualization_tool.pyi +19 -0
- aip_agents/examples/tools/image_artifact_tool.py +136 -0
- aip_agents/examples/tools/image_artifact_tool.pyi +26 -0
- aip_agents/examples/tools/langchain_arithmetic_tools.py +26 -0
- aip_agents/examples/tools/langchain_arithmetic_tools.pyi +17 -0
- aip_agents/examples/tools/langchain_currency_exchange_tool.py +88 -0
- aip_agents/examples/tools/langchain_currency_exchange_tool.pyi +20 -0
- aip_agents/examples/tools/langchain_graph_artifact_tool.py +172 -0
- aip_agents/examples/tools/langchain_graph_artifact_tool.pyi +25 -0
- aip_agents/examples/tools/langchain_weather_tool.py +48 -0
- aip_agents/examples/tools/langchain_weather_tool.pyi +19 -0
- aip_agents/examples/tools/langgraph_streaming_tool.py +130 -0
- aip_agents/examples/tools/langgraph_streaming_tool.pyi +43 -0
- aip_agents/examples/tools/mock_retrieval_tool.py +56 -0
- aip_agents/examples/tools/mock_retrieval_tool.pyi +13 -0
- aip_agents/examples/tools/pii_demo_tools.py +189 -0
- aip_agents/examples/tools/pii_demo_tools.pyi +54 -0
- aip_agents/examples/tools/random_chart_tool.py +142 -0
- aip_agents/examples/tools/random_chart_tool.pyi +20 -0
- aip_agents/examples/tools/serper_tool.py +202 -0
- aip_agents/examples/tools/serper_tool.pyi +16 -0
- aip_agents/examples/tools/stock_tools.py +82 -0
- aip_agents/examples/tools/stock_tools.pyi +36 -0
- aip_agents/examples/tools/table_generator_tool.py +167 -0
- aip_agents/examples/tools/table_generator_tool.pyi +22 -0
- aip_agents/examples/tools/time_tool.py +82 -0
- aip_agents/examples/tools/time_tool.pyi +15 -0
- aip_agents/examples/tools/weather_forecast_tool.py +38 -0
- aip_agents/examples/tools/weather_forecast_tool.pyi +14 -0
- aip_agents/executor/agent_executor.py +473 -0
- aip_agents/executor/base.py +48 -0
- aip_agents/guardrails/__init__.py +83 -0
- aip_agents/guardrails/__init__.pyi +6 -0
- aip_agents/guardrails/engines/__init__.py +69 -0
- aip_agents/guardrails/engines/__init__.pyi +4 -0
- aip_agents/guardrails/engines/base.py +90 -0
- aip_agents/guardrails/engines/base.pyi +61 -0
- aip_agents/guardrails/engines/nemo.py +101 -0
- aip_agents/guardrails/engines/nemo.pyi +46 -0
- aip_agents/guardrails/engines/phrase_matcher.py +113 -0
- aip_agents/guardrails/engines/phrase_matcher.pyi +48 -0
- aip_agents/guardrails/exceptions.py +39 -0
- aip_agents/guardrails/exceptions.pyi +23 -0
- aip_agents/guardrails/manager.py +163 -0
- aip_agents/guardrails/manager.pyi +42 -0
- aip_agents/guardrails/middleware.py +199 -0
- aip_agents/guardrails/middleware.pyi +87 -0
- aip_agents/guardrails/schemas.py +63 -0
- aip_agents/guardrails/schemas.pyi +43 -0
- aip_agents/guardrails/utils.py +45 -0
- aip_agents/guardrails/utils.pyi +19 -0
- aip_agents/mcp/__init__.py +1 -0
- aip_agents/mcp/__init__.pyi +0 -0
- aip_agents/mcp/client/__init__.py +14 -0
- aip_agents/mcp/client/__init__.pyi +5 -0
- aip_agents/mcp/client/base_mcp_client.py +369 -0
- aip_agents/mcp/client/base_mcp_client.pyi +148 -0
- aip_agents/mcp/client/connection_manager.py +193 -0
- aip_agents/mcp/client/connection_manager.pyi +48 -0
- aip_agents/mcp/client/google_adk/__init__.py +11 -0
- aip_agents/mcp/client/google_adk/__init__.pyi +3 -0
- aip_agents/mcp/client/google_adk/client.py +381 -0
- aip_agents/mcp/client/google_adk/client.pyi +75 -0
- aip_agents/mcp/client/langchain/__init__.py +11 -0
- aip_agents/mcp/client/langchain/__init__.pyi +3 -0
- aip_agents/mcp/client/langchain/client.py +265 -0
- aip_agents/mcp/client/langchain/client.pyi +48 -0
- aip_agents/mcp/client/persistent_session.py +362 -0
- aip_agents/mcp/client/persistent_session.pyi +113 -0
- aip_agents/mcp/client/session_pool.py +351 -0
- aip_agents/mcp/client/session_pool.pyi +101 -0
- aip_agents/mcp/client/transports.py +228 -0
- aip_agents/mcp/client/transports.pyi +123 -0
- aip_agents/mcp/utils/__init__.py +7 -0
- aip_agents/mcp/utils/__init__.pyi +0 -0
- aip_agents/mcp/utils/config_validator.py +139 -0
- aip_agents/mcp/utils/config_validator.pyi +82 -0
- aip_agents/memory/__init__.py +14 -0
- aip_agents/memory/__init__.pyi +5 -0
- aip_agents/memory/adapters/__init__.py +10 -0
- aip_agents/memory/adapters/__init__.pyi +4 -0
- aip_agents/memory/adapters/base_adapter.py +717 -0
- aip_agents/memory/adapters/base_adapter.pyi +150 -0
- aip_agents/memory/adapters/mem0.py +84 -0
- aip_agents/memory/adapters/mem0.pyi +22 -0
- aip_agents/memory/base.py +84 -0
- aip_agents/memory/base.pyi +60 -0
- aip_agents/memory/constants.py +49 -0
- aip_agents/memory/constants.pyi +25 -0
- aip_agents/memory/factory.py +86 -0
- aip_agents/memory/factory.pyi +24 -0
- aip_agents/memory/guidance.py +20 -0
- aip_agents/memory/guidance.pyi +3 -0
- aip_agents/memory/simple_memory.py +47 -0
- aip_agents/memory/simple_memory.pyi +23 -0
- aip_agents/middleware/__init__.py +17 -0
- aip_agents/middleware/__init__.pyi +5 -0
- aip_agents/middleware/base.py +96 -0
- aip_agents/middleware/base.pyi +75 -0
- aip_agents/middleware/manager.py +150 -0
- aip_agents/middleware/manager.pyi +84 -0
- aip_agents/middleware/todolist.py +274 -0
- aip_agents/middleware/todolist.pyi +125 -0
- aip_agents/schema/__init__.py +69 -0
- aip_agents/schema/__init__.pyi +9 -0
- aip_agents/schema/a2a.py +56 -0
- aip_agents/schema/a2a.pyi +40 -0
- aip_agents/schema/agent.py +111 -0
- aip_agents/schema/agent.pyi +65 -0
- aip_agents/schema/hitl.py +157 -0
- aip_agents/schema/hitl.pyi +89 -0
- aip_agents/schema/langgraph.py +37 -0
- aip_agents/schema/langgraph.pyi +28 -0
- aip_agents/schema/model_id.py +97 -0
- aip_agents/schema/model_id.pyi +54 -0
- aip_agents/schema/step_limit.py +108 -0
- aip_agents/schema/step_limit.pyi +63 -0
- aip_agents/schema/storage.py +40 -0
- aip_agents/schema/storage.pyi +21 -0
- aip_agents/sentry/__init__.py +11 -0
- aip_agents/sentry/__init__.pyi +3 -0
- aip_agents/sentry/sentry.py +151 -0
- aip_agents/sentry/sentry.pyi +48 -0
- aip_agents/storage/__init__.py +41 -0
- aip_agents/storage/__init__.pyi +8 -0
- aip_agents/storage/base.py +85 -0
- aip_agents/storage/base.pyi +58 -0
- aip_agents/storage/clients/__init__.py +12 -0
- aip_agents/storage/clients/__init__.pyi +3 -0
- aip_agents/storage/clients/minio_client.py +318 -0
- aip_agents/storage/clients/minio_client.pyi +137 -0
- aip_agents/storage/config.py +62 -0
- aip_agents/storage/config.pyi +29 -0
- aip_agents/storage/providers/__init__.py +15 -0
- aip_agents/storage/providers/__init__.pyi +5 -0
- aip_agents/storage/providers/base.py +106 -0
- aip_agents/storage/providers/base.pyi +88 -0
- aip_agents/storage/providers/memory.py +114 -0
- aip_agents/storage/providers/memory.pyi +79 -0
- aip_agents/storage/providers/object_storage.py +214 -0
- aip_agents/storage/providers/object_storage.pyi +98 -0
- aip_agents/tools/__init__.py +53 -0
- aip_agents/tools/__init__.pyi +9 -0
- aip_agents/tools/browser_use/__init__.py +82 -0
- aip_agents/tools/browser_use/__init__.pyi +14 -0
- aip_agents/tools/browser_use/action_parser.py +103 -0
- aip_agents/tools/browser_use/action_parser.pyi +18 -0
- aip_agents/tools/browser_use/browser_use_tool.py +1112 -0
- aip_agents/tools/browser_use/browser_use_tool.pyi +50 -0
- aip_agents/tools/browser_use/llm_config.py +120 -0
- aip_agents/tools/browser_use/llm_config.pyi +52 -0
- aip_agents/tools/browser_use/minio_storage.py +198 -0
- aip_agents/tools/browser_use/minio_storage.pyi +109 -0
- aip_agents/tools/browser_use/schemas.py +119 -0
- aip_agents/tools/browser_use/schemas.pyi +32 -0
- aip_agents/tools/browser_use/session.py +76 -0
- aip_agents/tools/browser_use/session.pyi +4 -0
- aip_agents/tools/browser_use/session_errors.py +132 -0
- aip_agents/tools/browser_use/session_errors.pyi +53 -0
- aip_agents/tools/browser_use/steel_session_recording.py +317 -0
- aip_agents/tools/browser_use/steel_session_recording.pyi +63 -0
- aip_agents/tools/browser_use/streaming.py +813 -0
- aip_agents/tools/browser_use/streaming.pyi +81 -0
- aip_agents/tools/browser_use/structured_data_parser.py +257 -0
- aip_agents/tools/browser_use/structured_data_parser.pyi +86 -0
- aip_agents/tools/browser_use/structured_data_recovery.py +204 -0
- aip_agents/tools/browser_use/structured_data_recovery.pyi +43 -0
- aip_agents/tools/browser_use/types.py +78 -0
- aip_agents/tools/browser_use/types.pyi +45 -0
- aip_agents/tools/code_sandbox/__init__.py +26 -0
- aip_agents/tools/code_sandbox/__init__.pyi +3 -0
- aip_agents/tools/code_sandbox/constant.py +13 -0
- aip_agents/tools/code_sandbox/constant.pyi +4 -0
- aip_agents/tools/code_sandbox/e2b_cloud_sandbox_extended.py +306 -0
- aip_agents/tools/code_sandbox/e2b_cloud_sandbox_extended.pyi +102 -0
- aip_agents/tools/code_sandbox/e2b_sandbox_tool.py +411 -0
- aip_agents/tools/code_sandbox/e2b_sandbox_tool.pyi +29 -0
- aip_agents/tools/constants.py +177 -0
- aip_agents/tools/constants.pyi +138 -0
- aip_agents/tools/document_loader/__init__.py +44 -0
- aip_agents/tools/document_loader/__init__.pyi +7 -0
- aip_agents/tools/document_loader/base_reader.py +302 -0
- aip_agents/tools/document_loader/base_reader.pyi +75 -0
- aip_agents/tools/document_loader/docx_reader_tool.py +68 -0
- aip_agents/tools/document_loader/docx_reader_tool.pyi +10 -0
- aip_agents/tools/document_loader/excel_reader_tool.py +171 -0
- aip_agents/tools/document_loader/excel_reader_tool.pyi +26 -0
- aip_agents/tools/document_loader/pdf_reader_tool.py +79 -0
- aip_agents/tools/document_loader/pdf_reader_tool.pyi +11 -0
- aip_agents/tools/document_loader/pdf_splitter.py +169 -0
- aip_agents/tools/document_loader/pdf_splitter.pyi +18 -0
- aip_agents/tools/gl_connector/__init__.py +5 -0
- aip_agents/tools/gl_connector/__init__.pyi +3 -0
- aip_agents/tools/gl_connector/tool.py +383 -0
- aip_agents/tools/gl_connector/tool.pyi +74 -0
- aip_agents/tools/gl_connector_tools.py +119 -0
- aip_agents/tools/gl_connector_tools.pyi +39 -0
- aip_agents/tools/memory_search/__init__.py +22 -0
- aip_agents/tools/memory_search/__init__.pyi +5 -0
- aip_agents/tools/memory_search/base.py +200 -0
- aip_agents/tools/memory_search/base.pyi +69 -0
- aip_agents/tools/memory_search/mem0.py +258 -0
- aip_agents/tools/memory_search/mem0.pyi +19 -0
- aip_agents/tools/memory_search/schema.py +48 -0
- aip_agents/tools/memory_search/schema.pyi +15 -0
- aip_agents/tools/memory_search_tool.py +26 -0
- aip_agents/tools/memory_search_tool.pyi +3 -0
- aip_agents/tools/time_tool.py +117 -0
- aip_agents/tools/time_tool.pyi +16 -0
- aip_agents/tools/tool_config_injector.py +300 -0
- aip_agents/tools/tool_config_injector.pyi +26 -0
- aip_agents/tools/web_search/__init__.py +15 -0
- aip_agents/tools/web_search/__init__.pyi +3 -0
- aip_agents/tools/web_search/serper_tool.py +187 -0
- aip_agents/tools/web_search/serper_tool.pyi +19 -0
- aip_agents/types/__init__.py +70 -0
- aip_agents/types/__init__.pyi +36 -0
- aip_agents/types/a2a_events.py +13 -0
- aip_agents/types/a2a_events.pyi +3 -0
- aip_agents/utils/__init__.py +79 -0
- aip_agents/utils/__init__.pyi +11 -0
- aip_agents/utils/a2a_connector.py +1757 -0
- aip_agents/utils/a2a_connector.pyi +146 -0
- aip_agents/utils/artifact_helpers.py +502 -0
- aip_agents/utils/artifact_helpers.pyi +203 -0
- aip_agents/utils/constants.py +22 -0
- aip_agents/utils/constants.pyi +10 -0
- aip_agents/utils/datetime/__init__.py +34 -0
- aip_agents/utils/datetime/__init__.pyi +4 -0
- aip_agents/utils/datetime/normalization.py +231 -0
- aip_agents/utils/datetime/normalization.pyi +95 -0
- aip_agents/utils/datetime/timezone.py +206 -0
- aip_agents/utils/datetime/timezone.pyi +48 -0
- aip_agents/utils/env_loader.py +27 -0
- aip_agents/utils/env_loader.pyi +10 -0
- aip_agents/utils/event_handler_registry.py +58 -0
- aip_agents/utils/event_handler_registry.pyi +23 -0
- aip_agents/utils/file_prompt_utils.py +176 -0
- aip_agents/utils/file_prompt_utils.pyi +21 -0
- aip_agents/utils/final_response_builder.py +211 -0
- aip_agents/utils/final_response_builder.pyi +34 -0
- aip_agents/utils/formatter_llm_client.py +231 -0
- aip_agents/utils/formatter_llm_client.pyi +71 -0
- aip_agents/utils/langgraph/__init__.py +19 -0
- aip_agents/utils/langgraph/__init__.pyi +3 -0
- aip_agents/utils/langgraph/converter.py +128 -0
- aip_agents/utils/langgraph/converter.pyi +49 -0
- aip_agents/utils/langgraph/tool_managers/__init__.py +15 -0
- aip_agents/utils/langgraph/tool_managers/__init__.pyi +5 -0
- aip_agents/utils/langgraph/tool_managers/a2a_tool_manager.py +99 -0
- aip_agents/utils/langgraph/tool_managers/a2a_tool_manager.pyi +35 -0
- aip_agents/utils/langgraph/tool_managers/base_tool_manager.py +66 -0
- aip_agents/utils/langgraph/tool_managers/base_tool_manager.pyi +48 -0
- aip_agents/utils/langgraph/tool_managers/delegation_tool_manager.py +1071 -0
- aip_agents/utils/langgraph/tool_managers/delegation_tool_manager.pyi +56 -0
- aip_agents/utils/langgraph/tool_output_management.py +967 -0
- aip_agents/utils/langgraph/tool_output_management.pyi +292 -0
- aip_agents/utils/logger.py +195 -0
- aip_agents/utils/logger.pyi +60 -0
- aip_agents/utils/metadata/__init__.py +27 -0
- aip_agents/utils/metadata/__init__.pyi +5 -0
- aip_agents/utils/metadata/activity_metadata_helper.py +407 -0
- aip_agents/utils/metadata/activity_metadata_helper.pyi +25 -0
- aip_agents/utils/metadata/activity_narrative/__init__.py +35 -0
- aip_agents/utils/metadata/activity_narrative/__init__.pyi +7 -0
- aip_agents/utils/metadata/activity_narrative/builder.py +817 -0
- aip_agents/utils/metadata/activity_narrative/builder.pyi +35 -0
- aip_agents/utils/metadata/activity_narrative/constants.py +51 -0
- aip_agents/utils/metadata/activity_narrative/constants.pyi +10 -0
- aip_agents/utils/metadata/activity_narrative/context.py +49 -0
- aip_agents/utils/metadata/activity_narrative/context.pyi +32 -0
- aip_agents/utils/metadata/activity_narrative/formatters.py +230 -0
- aip_agents/utils/metadata/activity_narrative/formatters.pyi +48 -0
- aip_agents/utils/metadata/activity_narrative/utils.py +35 -0
- aip_agents/utils/metadata/activity_narrative/utils.pyi +12 -0
- aip_agents/utils/metadata/schemas/__init__.py +16 -0
- aip_agents/utils/metadata/schemas/__init__.pyi +4 -0
- aip_agents/utils/metadata/schemas/activity_schema.py +29 -0
- aip_agents/utils/metadata/schemas/activity_schema.pyi +18 -0
- aip_agents/utils/metadata/schemas/thinking_schema.py +31 -0
- aip_agents/utils/metadata/schemas/thinking_schema.pyi +20 -0
- aip_agents/utils/metadata/thinking_metadata_helper.py +38 -0
- aip_agents/utils/metadata/thinking_metadata_helper.pyi +4 -0
- aip_agents/utils/metadata_helper.py +358 -0
- aip_agents/utils/metadata_helper.pyi +117 -0
- aip_agents/utils/name_preprocessor/__init__.py +17 -0
- aip_agents/utils/name_preprocessor/__init__.pyi +6 -0
- aip_agents/utils/name_preprocessor/base_name_preprocessor.py +73 -0
- aip_agents/utils/name_preprocessor/base_name_preprocessor.pyi +52 -0
- aip_agents/utils/name_preprocessor/google_name_preprocessor.py +100 -0
- aip_agents/utils/name_preprocessor/google_name_preprocessor.pyi +38 -0
- aip_agents/utils/name_preprocessor/name_preprocessor.py +87 -0
- aip_agents/utils/name_preprocessor/name_preprocessor.pyi +41 -0
- aip_agents/utils/name_preprocessor/openai_name_preprocessor.py +48 -0
- aip_agents/utils/name_preprocessor/openai_name_preprocessor.pyi +34 -0
- aip_agents/utils/pii/__init__.py +25 -0
- aip_agents/utils/pii/__init__.pyi +5 -0
- aip_agents/utils/pii/pii_handler.py +397 -0
- aip_agents/utils/pii/pii_handler.pyi +96 -0
- aip_agents/utils/pii/pii_helper.py +207 -0
- aip_agents/utils/pii/pii_helper.pyi +78 -0
- aip_agents/utils/pii/uuid_deanonymizer_mapping.py +195 -0
- aip_agents/utils/pii/uuid_deanonymizer_mapping.pyi +73 -0
- aip_agents/utils/reference_helper.py +273 -0
- aip_agents/utils/reference_helper.pyi +81 -0
- aip_agents/utils/sse_chunk_transformer.py +831 -0
- aip_agents/utils/sse_chunk_transformer.pyi +166 -0
- aip_agents/utils/step_limit_manager.py +265 -0
- aip_agents/utils/step_limit_manager.pyi +112 -0
- aip_agents/utils/token_usage_helper.py +156 -0
- aip_agents/utils/token_usage_helper.pyi +60 -0
- aip_agents_binary-0.5.25b1.dist-info/METADATA +681 -0
- aip_agents_binary-0.5.25b1.dist-info/RECORD +566 -0
- aip_agents_binary-0.5.25b1.dist-info/WHEEL +5 -0
- aip_agents_binary-0.5.25b1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
"""MCP Session Pool for centralized session management.
|
|
2
|
+
|
|
3
|
+
This module manages a pool of persistent MCP sessions, providing centralized
|
|
4
|
+
initialization, tool collection, and cleanup.
|
|
5
|
+
|
|
6
|
+
Authors:
|
|
7
|
+
Putu Ravindra Wiguna (putu.r.wiguna@gdplabs.id)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import asyncio
|
|
11
|
+
|
|
12
|
+
from gllm_tools.mcp.client.config import MCPConfiguration
|
|
13
|
+
from mcp.types import Tool
|
|
14
|
+
|
|
15
|
+
from aip_agents.mcp.client.persistent_session import PersistentMCPSession
|
|
16
|
+
from aip_agents.mcp.utils.config_validator import validate_allowed_tools_config, validate_allowed_tools_list
|
|
17
|
+
from aip_agents.utils.logger import get_logger
|
|
18
|
+
|
|
19
|
+
logger = get_logger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class MCPSessionPool:
|
|
23
|
+
"""Manages pool of persistent MCP sessions.
|
|
24
|
+
|
|
25
|
+
This pool provides centralized management of MCP sessions, including
|
|
26
|
+
initialization, tool collection, and resource cleanup. Sessions are
|
|
27
|
+
reused across the agent lifecycle.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def __init__(self):
|
|
31
|
+
"""Initialize empty session pool."""
|
|
32
|
+
self.sessions: dict[str, PersistentMCPSession] = {}
|
|
33
|
+
self._lock = asyncio.Lock()
|
|
34
|
+
self._initialized = False
|
|
35
|
+
|
|
36
|
+
async def get_or_create_session(
|
|
37
|
+
self,
|
|
38
|
+
server_name: str,
|
|
39
|
+
config: MCPConfiguration,
|
|
40
|
+
allowed_tools: list[str] | None = None,
|
|
41
|
+
) -> PersistentMCPSession:
|
|
42
|
+
"""Get existing session or create new one.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
server_name (str): Name of the MCP server
|
|
46
|
+
config (MCPConfiguration): MCP server configuration
|
|
47
|
+
allowed_tools (list[str] | None): Optional list of tool names to allow. None means all tools allowed.
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
PersistentMCPSession: Persistent MCP session
|
|
51
|
+
|
|
52
|
+
Raises:
|
|
53
|
+
Exception: If session creation fails
|
|
54
|
+
"""
|
|
55
|
+
async with self._lock:
|
|
56
|
+
if server_name in self.sessions:
|
|
57
|
+
return self._update_existing_session(server_name, allowed_tools)
|
|
58
|
+
|
|
59
|
+
return await self._create_and_initialize_session(server_name, config, allowed_tools)
|
|
60
|
+
|
|
61
|
+
def _update_existing_session(
|
|
62
|
+
self,
|
|
63
|
+
server_name: str,
|
|
64
|
+
allowed_tools: list[str] | None,
|
|
65
|
+
) -> PersistentMCPSession:
|
|
66
|
+
"""Update existing session's allowed_tools if changed.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
server_name (str): Name of the MCP server
|
|
70
|
+
allowed_tools (list[str] | None): Optional list of tool names to allow
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
PersistentMCPSession: Updated existing session
|
|
74
|
+
"""
|
|
75
|
+
existing_session = self.sessions[server_name]
|
|
76
|
+
if existing_session.update_allowed_tools(allowed_tools):
|
|
77
|
+
logger.debug(f"Reconfigured allowed_tools for {server_name}")
|
|
78
|
+
else:
|
|
79
|
+
logger.debug(f"Reusing existing session for {server_name} (allowed_tools unchanged)")
|
|
80
|
+
return existing_session
|
|
81
|
+
|
|
82
|
+
async def _create_and_initialize_session(
|
|
83
|
+
self,
|
|
84
|
+
server_name: str,
|
|
85
|
+
config: MCPConfiguration,
|
|
86
|
+
allowed_tools: list[str] | None,
|
|
87
|
+
) -> PersistentMCPSession:
|
|
88
|
+
"""Create and initialize a new session.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
server_name (str): Name of the MCP server
|
|
92
|
+
config (MCPConfiguration): MCP server configuration
|
|
93
|
+
allowed_tools (list[str] | None): Optional list of tool names to allow
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
PersistentMCPSession: Newly created and initialized session
|
|
97
|
+
|
|
98
|
+
Raises:
|
|
99
|
+
Exception: If session creation or initialization fails
|
|
100
|
+
"""
|
|
101
|
+
logger.info(f"Creating new session for {server_name}")
|
|
102
|
+
session = PersistentMCPSession(
|
|
103
|
+
server_name,
|
|
104
|
+
config,
|
|
105
|
+
allowed_tools=allowed_tools,
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
# Initialize session first, only store if successful
|
|
109
|
+
try:
|
|
110
|
+
await session.initialize()
|
|
111
|
+
# Only store session after successful initialization
|
|
112
|
+
self.sessions[server_name] = session
|
|
113
|
+
logger.info(f"Session created and cached for {server_name}")
|
|
114
|
+
return session
|
|
115
|
+
except Exception:
|
|
116
|
+
# Clean up session on failure
|
|
117
|
+
await session.disconnect()
|
|
118
|
+
raise
|
|
119
|
+
|
|
120
|
+
async def initialize_all_sessions(self, server_configs: dict[str, MCPConfiguration]) -> None:
|
|
121
|
+
"""Initialize all sessions and cache tools.
|
|
122
|
+
|
|
123
|
+
This method initializes all configured MCP servers concurrently
|
|
124
|
+
for better performance.
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
server_configs (dict[str, MCPConfiguration]): Dictionary of server configurations
|
|
128
|
+
|
|
129
|
+
Raises:
|
|
130
|
+
Exception: If any session initialization fails
|
|
131
|
+
"""
|
|
132
|
+
if self._initialized:
|
|
133
|
+
logger.debug("Session pool already initialized")
|
|
134
|
+
return
|
|
135
|
+
|
|
136
|
+
logger.info(f"Initializing session pool with {len(server_configs)} servers")
|
|
137
|
+
|
|
138
|
+
# Initialize all sessions concurrently
|
|
139
|
+
initialization_tasks = []
|
|
140
|
+
for server_name, config in server_configs.items():
|
|
141
|
+
allowed_tools = self._extract_allowed_tools(server_name, config)
|
|
142
|
+
task = self._initialize_single_session(server_name, config, allowed_tools)
|
|
143
|
+
initialization_tasks.append(task)
|
|
144
|
+
|
|
145
|
+
if initialization_tasks:
|
|
146
|
+
try:
|
|
147
|
+
await asyncio.gather(*initialization_tasks)
|
|
148
|
+
self._initialized = True
|
|
149
|
+
logger.info(f"Session pool initialized with {len(self.sessions)} active sessions")
|
|
150
|
+
except Exception as e:
|
|
151
|
+
logger.error(f"Failed to initialize session pool: {e}")
|
|
152
|
+
# Cleanup any partially initialized sessions
|
|
153
|
+
await self.close_all_sessions()
|
|
154
|
+
# Ensure _initialized remains False to allow retrying
|
|
155
|
+
self._initialized = False
|
|
156
|
+
raise
|
|
157
|
+
else:
|
|
158
|
+
self._initialized = True
|
|
159
|
+
logger.info("Session pool initialized (no servers configured)")
|
|
160
|
+
|
|
161
|
+
def _extract_allowed_tools(
|
|
162
|
+
self,
|
|
163
|
+
server_name: str,
|
|
164
|
+
config: MCPConfiguration,
|
|
165
|
+
) -> list[str] | None:
|
|
166
|
+
"""Extract allowed_tools from config.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
server_name (str): Name of the MCP server
|
|
170
|
+
config (MCPConfiguration): MCP server configuration
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
list[str] | None: List of allowed tool names, or None if no restriction
|
|
174
|
+
|
|
175
|
+
Raises:
|
|
176
|
+
ValueError: If allowed_tools is not a list of strings
|
|
177
|
+
"""
|
|
178
|
+
allowed_tools: list[str] | None = None
|
|
179
|
+
|
|
180
|
+
# Try object attribute first (avoids double property call from hasattr+getattr)
|
|
181
|
+
try:
|
|
182
|
+
raw_allowed = config.allowed_tools
|
|
183
|
+
# Use unified validation logic
|
|
184
|
+
allowed_tools = validate_allowed_tools_list(raw_allowed, f"Server '{server_name}'")
|
|
185
|
+
except AttributeError:
|
|
186
|
+
# Check if config is dict-like
|
|
187
|
+
if isinstance(config, dict):
|
|
188
|
+
allowed_tools = validate_allowed_tools_config(config, server_name)
|
|
189
|
+
|
|
190
|
+
if allowed_tools:
|
|
191
|
+
logger.debug(f"Server '{server_name}' has {len(allowed_tools)} allowed tools")
|
|
192
|
+
else:
|
|
193
|
+
logger.debug(f"Server '{server_name}' allows all tools (no restriction)")
|
|
194
|
+
|
|
195
|
+
return allowed_tools
|
|
196
|
+
|
|
197
|
+
async def _initialize_single_session(
|
|
198
|
+
self,
|
|
199
|
+
server_name: str,
|
|
200
|
+
config: MCPConfiguration,
|
|
201
|
+
allowed_tools: list[str] | None = None,
|
|
202
|
+
) -> None:
|
|
203
|
+
"""Initialize a single session (internal method).
|
|
204
|
+
|
|
205
|
+
Args:
|
|
206
|
+
server_name (str): Name of the MCP server
|
|
207
|
+
config (MCPConfiguration): MCP server configuration
|
|
208
|
+
allowed_tools (list[str] | None): Optional list of tool names to allow
|
|
209
|
+
"""
|
|
210
|
+
try:
|
|
211
|
+
await self.get_or_create_session(server_name, config, allowed_tools)
|
|
212
|
+
logger.debug(f"Session initialized for {server_name}")
|
|
213
|
+
except Exception as e:
|
|
214
|
+
logger.debug(f"Failed to initialize session for {server_name}: {e}")
|
|
215
|
+
raise
|
|
216
|
+
|
|
217
|
+
def get_all_active_sessions(self) -> dict[str, PersistentMCPSession]:
|
|
218
|
+
"""Get all active sessions.
|
|
219
|
+
|
|
220
|
+
Returns:
|
|
221
|
+
dict[str, PersistentMCPSession]: Dictionary of active sessions by server name
|
|
222
|
+
"""
|
|
223
|
+
return {name: session for name, session in self.sessions.items() if session.is_initialized}
|
|
224
|
+
|
|
225
|
+
@property
|
|
226
|
+
def active_sessions(self) -> list[str]:
|
|
227
|
+
"""Get list of active session names.
|
|
228
|
+
|
|
229
|
+
Returns:
|
|
230
|
+
list[str]: List of active session names
|
|
231
|
+
"""
|
|
232
|
+
return [name for name, session in self.sessions.items() if session.is_initialized]
|
|
233
|
+
|
|
234
|
+
async def get_all_tools(self) -> list[Tool]:
|
|
235
|
+
"""Get all cached tools from all active sessions.
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
list[Tool]: List of all available tools across all sessions
|
|
239
|
+
"""
|
|
240
|
+
# Create snapshot of sessions under lock to prevent race conditions
|
|
241
|
+
async with self._lock:
|
|
242
|
+
session_snapshot = dict(self.sessions.items())
|
|
243
|
+
|
|
244
|
+
# Prepare tasks for active sessions
|
|
245
|
+
server_names = list(session_snapshot.keys())
|
|
246
|
+
tasks = [session_snapshot[name].list_tools() for name in server_names]
|
|
247
|
+
|
|
248
|
+
results = []
|
|
249
|
+
if tasks:
|
|
250
|
+
results = await asyncio.gather(*tasks, return_exceptions=True)
|
|
251
|
+
|
|
252
|
+
all_tools: list[Tool] = []
|
|
253
|
+
for server_name, result in zip(server_names, results, strict=False):
|
|
254
|
+
if isinstance(result, Exception):
|
|
255
|
+
logger.warning(f"Failed to get tools from {server_name}: {result}")
|
|
256
|
+
else:
|
|
257
|
+
all_tools.extend(result)
|
|
258
|
+
logger.debug(f"Added {len(result)} tools from {server_name}")
|
|
259
|
+
|
|
260
|
+
logger.debug(f"Total tools available: {len(all_tools)}")
|
|
261
|
+
return all_tools
|
|
262
|
+
|
|
263
|
+
async def close_session(self, server_name: str) -> None:
|
|
264
|
+
"""Close specific session.
|
|
265
|
+
|
|
266
|
+
Args:
|
|
267
|
+
server_name (str): Name of the server session to close
|
|
268
|
+
"""
|
|
269
|
+
async with self._lock:
|
|
270
|
+
if server_name in self.sessions:
|
|
271
|
+
try:
|
|
272
|
+
logger.info(f"Closing session for {server_name}")
|
|
273
|
+
await self.sessions[server_name].disconnect()
|
|
274
|
+
except Exception as e:
|
|
275
|
+
logger.warning(f"Error closing session {server_name}: {e}")
|
|
276
|
+
finally:
|
|
277
|
+
del self.sessions[server_name]
|
|
278
|
+
logger.info(f"Session {server_name} removed from pool")
|
|
279
|
+
|
|
280
|
+
async def close_all_sessions(self) -> None:
|
|
281
|
+
"""Close all sessions gracefully.
|
|
282
|
+
|
|
283
|
+
This method ensures all resources are cleaned up properly.
|
|
284
|
+
"""
|
|
285
|
+
async with self._lock:
|
|
286
|
+
logger.info("Closing all sessions in pool")
|
|
287
|
+
|
|
288
|
+
# Create list of sessions to close (to avoid modification during iteration)
|
|
289
|
+
sessions_to_close = list(self.sessions.keys())
|
|
290
|
+
|
|
291
|
+
# Close sessions concurrently for faster shutdown
|
|
292
|
+
close_tasks = []
|
|
293
|
+
for server_name in sessions_to_close:
|
|
294
|
+
task = self._close_single_session(server_name)
|
|
295
|
+
close_tasks.append(task)
|
|
296
|
+
|
|
297
|
+
if close_tasks:
|
|
298
|
+
await asyncio.gather(*close_tasks, return_exceptions=True)
|
|
299
|
+
|
|
300
|
+
# Clear all session data
|
|
301
|
+
self.sessions.clear()
|
|
302
|
+
self._initialized = False
|
|
303
|
+
|
|
304
|
+
logger.info("All sessions closed and pool cleared")
|
|
305
|
+
|
|
306
|
+
async def _close_single_session(self, server_name: str) -> None:
|
|
307
|
+
"""Close a single session (internal method).
|
|
308
|
+
|
|
309
|
+
Args:
|
|
310
|
+
server_name (str): Name of the server session to close
|
|
311
|
+
"""
|
|
312
|
+
try:
|
|
313
|
+
if server_name in self.sessions:
|
|
314
|
+
await self.sessions[server_name].disconnect()
|
|
315
|
+
logger.debug(f"Session {server_name} closed successfully")
|
|
316
|
+
except Exception as e:
|
|
317
|
+
logger.warning(f"Error closing session {server_name}: {e}")
|
|
318
|
+
|
|
319
|
+
@property
|
|
320
|
+
def is_initialized(self) -> bool:
|
|
321
|
+
"""Check if session pool is initialized.
|
|
322
|
+
|
|
323
|
+
Returns:
|
|
324
|
+
bool: True if initialized, False otherwise
|
|
325
|
+
"""
|
|
326
|
+
return self._initialized
|
|
327
|
+
|
|
328
|
+
@property
|
|
329
|
+
def session_count(self) -> int:
|
|
330
|
+
"""Get number of active sessions.
|
|
331
|
+
|
|
332
|
+
Returns:
|
|
333
|
+
int: Number of active sessions
|
|
334
|
+
"""
|
|
335
|
+
return len(self.sessions)
|
|
336
|
+
|
|
337
|
+
def get_session(self, server_name: str) -> PersistentMCPSession:
|
|
338
|
+
"""Get specific session by name.
|
|
339
|
+
|
|
340
|
+
Args:
|
|
341
|
+
server_name (str): Name of the server
|
|
342
|
+
|
|
343
|
+
Returns:
|
|
344
|
+
PersistentMCPSession: The requested session
|
|
345
|
+
|
|
346
|
+
Raises:
|
|
347
|
+
KeyError: If session doesn't exist
|
|
348
|
+
"""
|
|
349
|
+
if server_name not in self.sessions:
|
|
350
|
+
raise KeyError(f"Session '{server_name}' not found")
|
|
351
|
+
return self.sessions[server_name]
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
from _typeshed import Incomplete
|
|
2
|
+
from aip_agents.mcp.client.persistent_session import PersistentMCPSession as PersistentMCPSession
|
|
3
|
+
from aip_agents.mcp.utils.config_validator import validate_allowed_tools_config as validate_allowed_tools_config, validate_allowed_tools_list as validate_allowed_tools_list
|
|
4
|
+
from aip_agents.utils.logger import get_logger as get_logger
|
|
5
|
+
from gllm_tools.mcp.client.config import MCPConfiguration
|
|
6
|
+
from mcp.types import Tool as Tool
|
|
7
|
+
|
|
8
|
+
logger: Incomplete
|
|
9
|
+
|
|
10
|
+
class MCPSessionPool:
|
|
11
|
+
"""Manages pool of persistent MCP sessions.
|
|
12
|
+
|
|
13
|
+
This pool provides centralized management of MCP sessions, including
|
|
14
|
+
initialization, tool collection, and resource cleanup. Sessions are
|
|
15
|
+
reused across the agent lifecycle.
|
|
16
|
+
"""
|
|
17
|
+
sessions: dict[str, PersistentMCPSession]
|
|
18
|
+
def __init__(self) -> None:
|
|
19
|
+
"""Initialize empty session pool."""
|
|
20
|
+
async def get_or_create_session(self, server_name: str, config: MCPConfiguration, allowed_tools: list[str] | None = None) -> PersistentMCPSession:
|
|
21
|
+
"""Get existing session or create new one.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
server_name (str): Name of the MCP server
|
|
25
|
+
config (MCPConfiguration): MCP server configuration
|
|
26
|
+
allowed_tools (list[str] | None): Optional list of tool names to allow. None means all tools allowed.
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
PersistentMCPSession: Persistent MCP session
|
|
30
|
+
|
|
31
|
+
Raises:
|
|
32
|
+
Exception: If session creation fails
|
|
33
|
+
"""
|
|
34
|
+
async def initialize_all_sessions(self, server_configs: dict[str, MCPConfiguration]) -> None:
|
|
35
|
+
"""Initialize all sessions and cache tools.
|
|
36
|
+
|
|
37
|
+
This method initializes all configured MCP servers concurrently
|
|
38
|
+
for better performance.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
server_configs (dict[str, MCPConfiguration]): Dictionary of server configurations
|
|
42
|
+
|
|
43
|
+
Raises:
|
|
44
|
+
Exception: If any session initialization fails
|
|
45
|
+
"""
|
|
46
|
+
def get_all_active_sessions(self) -> dict[str, PersistentMCPSession]:
|
|
47
|
+
"""Get all active sessions.
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
dict[str, PersistentMCPSession]: Dictionary of active sessions by server name
|
|
51
|
+
"""
|
|
52
|
+
@property
|
|
53
|
+
def active_sessions(self) -> list[str]:
|
|
54
|
+
"""Get list of active session names.
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
list[str]: List of active session names
|
|
58
|
+
"""
|
|
59
|
+
async def get_all_tools(self) -> list[Tool]:
|
|
60
|
+
"""Get all cached tools from all active sessions.
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
list[Tool]: List of all available tools across all sessions
|
|
64
|
+
"""
|
|
65
|
+
async def close_session(self, server_name: str) -> None:
|
|
66
|
+
"""Close specific session.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
server_name (str): Name of the server session to close
|
|
70
|
+
"""
|
|
71
|
+
async def close_all_sessions(self) -> None:
|
|
72
|
+
"""Close all sessions gracefully.
|
|
73
|
+
|
|
74
|
+
This method ensures all resources are cleaned up properly.
|
|
75
|
+
"""
|
|
76
|
+
@property
|
|
77
|
+
def is_initialized(self) -> bool:
|
|
78
|
+
"""Check if session pool is initialized.
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
bool: True if initialized, False otherwise
|
|
82
|
+
"""
|
|
83
|
+
@property
|
|
84
|
+
def session_count(self) -> int:
|
|
85
|
+
"""Get number of active sessions.
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
int: Number of active sessions
|
|
89
|
+
"""
|
|
90
|
+
def get_session(self, server_name: str) -> PersistentMCPSession:
|
|
91
|
+
"""Get specific session by name.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
server_name (str): Name of the server
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
PersistentMCPSession: The requested session
|
|
98
|
+
|
|
99
|
+
Raises:
|
|
100
|
+
KeyError: If session doesn't exist
|
|
101
|
+
"""
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
"""MCP Transport Handlers.
|
|
2
|
+
|
|
3
|
+
This module provides abstract and concrete transport classes for STDIO, SSE, and streamable HTTP.
|
|
4
|
+
Each transport handles connection establishment specific to its protocol.
|
|
5
|
+
|
|
6
|
+
Authors:
|
|
7
|
+
Putu Ravindra Wiguna (putu.r.wiguna@gdplabs.id)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from abc import ABC, abstractmethod
|
|
11
|
+
from collections.abc import AsyncIterator
|
|
12
|
+
from enum import StrEnum
|
|
13
|
+
from typing import Any, Protocol
|
|
14
|
+
|
|
15
|
+
from gllm_tools.mcp.client.config import MCPConfiguration
|
|
16
|
+
from mcp.client.sse import sse_client
|
|
17
|
+
from mcp.client.stdio import StdioServerParameters, stdio_client
|
|
18
|
+
from mcp.client.streamable_http import streamablehttp_client
|
|
19
|
+
|
|
20
|
+
from aip_agents.utils.logger import get_logger
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class TransportContext(Protocol):
|
|
24
|
+
"""Protocol defining the interface for async context managers used in MCP transport connections."""
|
|
25
|
+
|
|
26
|
+
async def __aenter__(self):
|
|
27
|
+
"""Enter the async context, establishing the connection and returning read/write streams."""
|
|
28
|
+
...
|
|
29
|
+
|
|
30
|
+
async def __aexit__(self, _exc_type, _exc_val, _exc_tb):
|
|
31
|
+
"""Exit the async context, performing cleanup and closing the connection.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
_exc_type: Exception type if an exception occurred.
|
|
35
|
+
_exc_val: Exception value if an exception occurred.
|
|
36
|
+
_exc_tb: Exception traceback if an exception occurred.
|
|
37
|
+
"""
|
|
38
|
+
...
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
logger = get_logger(__name__)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
DEFAULT_TIMEOUT: float = 30.0
|
|
45
|
+
"""Default connection timeout in seconds."""
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _sanitize_headers(config: MCPConfiguration) -> dict[str, str]:
|
|
49
|
+
"""Remove headers with None values to avoid invalid HTTP headers.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
config (MCPConfiguration): Transport configuration containing optional headers.
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
dict[str, str]: Filtered headers with None values removed.
|
|
56
|
+
"""
|
|
57
|
+
headers = config.get("headers", {}) or {}
|
|
58
|
+
return {key: value for key, value in headers.items() if value is not None}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class TransportType(StrEnum):
|
|
62
|
+
"""Enum for supported MCP transport types."""
|
|
63
|
+
|
|
64
|
+
HTTP = "http"
|
|
65
|
+
SSE = "sse"
|
|
66
|
+
STDIO = "stdio"
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class Transport(ABC):
|
|
70
|
+
"""Abstract base class for MCP transports."""
|
|
71
|
+
|
|
72
|
+
def __init__(self, server_name: str, config: MCPConfiguration) -> None:
|
|
73
|
+
"""Initialize the transport.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
server_name (str): Name of the MCP server.
|
|
77
|
+
config (MCPConfiguration): Configuration for the transport.
|
|
78
|
+
"""
|
|
79
|
+
self.server_name = server_name
|
|
80
|
+
self.config = config
|
|
81
|
+
self.ctx: Any = None
|
|
82
|
+
|
|
83
|
+
@abstractmethod
|
|
84
|
+
async def connect(self) -> tuple[AsyncIterator[bytes], AsyncIterator[bytes], TransportContext]:
|
|
85
|
+
"""Establish connection and return read/write streams and context manager.
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
tuple[AsyncIterator[bytes], AsyncIterator[bytes], Any]:
|
|
89
|
+
(read_stream, write_stream, ctx)
|
|
90
|
+
Where:
|
|
91
|
+
- read_stream: AsyncIterator[bytes] for reading from the server.
|
|
92
|
+
- write_stream: AsyncIterator[bytes] for writing to the server.
|
|
93
|
+
- ctx: The async context manager instance for cleanup via __aexit__.
|
|
94
|
+
|
|
95
|
+
Raises:
|
|
96
|
+
ValueError: If required config (e.g., URL or command) is missing.
|
|
97
|
+
ConnectionError: If connection establishment fails.
|
|
98
|
+
"""
|
|
99
|
+
pass
|
|
100
|
+
|
|
101
|
+
async def close(self) -> None:
|
|
102
|
+
"""Clean up the transport connection."""
|
|
103
|
+
if self.ctx:
|
|
104
|
+
try:
|
|
105
|
+
await self.ctx.__aexit__(None, None, None)
|
|
106
|
+
except Exception as e:
|
|
107
|
+
logger.warning(f"Error during transport cleanup for {self.server_name}: {e}")
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class SSETransport(Transport):
|
|
111
|
+
"""SSE transport handler."""
|
|
112
|
+
|
|
113
|
+
async def connect(self) -> tuple[AsyncIterator[bytes], AsyncIterator[bytes], TransportContext]:
|
|
114
|
+
"""Connect using SSE transport.
|
|
115
|
+
|
|
116
|
+
Builds SSE URL from config, initializes client with timeout, and enters context.
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
tuple[AsyncIterator[bytes], AsyncIterator[bytes], Any]: (read_stream, write_stream, ctx)
|
|
120
|
+
|
|
121
|
+
Raises:
|
|
122
|
+
ValueError: If URL is missing.
|
|
123
|
+
ConnectionError: If SSE connection fails.
|
|
124
|
+
"""
|
|
125
|
+
base_url = self.config.get("url", "").rstrip("/")
|
|
126
|
+
if not base_url:
|
|
127
|
+
raise ValueError("URL is required for SSE transport")
|
|
128
|
+
|
|
129
|
+
url = f"{base_url}/sse" if not base_url.endswith("/sse") else base_url
|
|
130
|
+
timeout = self.config.get("timeout", DEFAULT_TIMEOUT)
|
|
131
|
+
headers = _sanitize_headers(self.config)
|
|
132
|
+
logger.debug(f"Attempting SSE connection to {url} with headers: {list(headers.keys())}")
|
|
133
|
+
try:
|
|
134
|
+
self.ctx = sse_client(url=url, timeout=timeout, sse_read_timeout=300.0, headers=headers)
|
|
135
|
+
read_stream, write_stream = await self.ctx.__aenter__()
|
|
136
|
+
logger.info(f"Connected to {self.server_name} via SSE")
|
|
137
|
+
return read_stream, write_stream, self.ctx
|
|
138
|
+
except Exception as e:
|
|
139
|
+
raise ConnectionError(f"SSE connection failed for {self.server_name}: {str(e)}") from e
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class HTTPTransport(Transport):
|
|
143
|
+
"""Streamable HTTP transport handler."""
|
|
144
|
+
|
|
145
|
+
async def connect(self) -> tuple[AsyncIterator[bytes], AsyncIterator[bytes], TransportContext]:
|
|
146
|
+
"""Connect using streamable HTTP transport.
|
|
147
|
+
|
|
148
|
+
Builds MCP URL from config, initializes client with timeout, and enters context.
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
tuple[AsyncIterator[bytes], AsyncIterator[bytes], Any]: (read_stream, write_stream, ctx)
|
|
152
|
+
|
|
153
|
+
Raises:
|
|
154
|
+
ValueError: If URL is missing.
|
|
155
|
+
ConnectionError: If HTTP connection fails.
|
|
156
|
+
"""
|
|
157
|
+
base_url = self.config.get("url", "").rstrip("/")
|
|
158
|
+
if not base_url:
|
|
159
|
+
raise ValueError("URL is required for HTTP transport")
|
|
160
|
+
|
|
161
|
+
url = f"{base_url}/mcp" if not base_url.endswith("/mcp") else base_url
|
|
162
|
+
timeout = self.config.get("timeout", DEFAULT_TIMEOUT)
|
|
163
|
+
headers = _sanitize_headers(self.config)
|
|
164
|
+
logger.debug(f"Attempting streamable HTTP connection to {url} with headers: {list(headers.keys())}")
|
|
165
|
+
try:
|
|
166
|
+
self.ctx = streamablehttp_client(url=url, timeout=timeout, headers=headers)
|
|
167
|
+
read_stream, write_stream, _ = await self.ctx.__aenter__()
|
|
168
|
+
logger.info(f"Connected to {self.server_name} via HTTP")
|
|
169
|
+
return read_stream, write_stream, self.ctx
|
|
170
|
+
except Exception as e:
|
|
171
|
+
raise ConnectionError(f"HTTP connection failed for {self.server_name}: {str(e)}") from e
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
class StdioTransport(Transport):
|
|
175
|
+
"""STDIO transport handler."""
|
|
176
|
+
|
|
177
|
+
async def connect(self) -> tuple[AsyncIterator[bytes], AsyncIterator[bytes], TransportContext]:
|
|
178
|
+
"""Connect using STDIO transport.
|
|
179
|
+
|
|
180
|
+
Initializes stdio client from command/args/env in config and enters context.
|
|
181
|
+
|
|
182
|
+
Returns:
|
|
183
|
+
tuple[AsyncIterator[bytes], AsyncIterator[bytes], Any]: (read_stream, write_stream, ctx)
|
|
184
|
+
|
|
185
|
+
Raises:
|
|
186
|
+
ValueError: If command is missing.
|
|
187
|
+
ConnectionError: If STDIO connection fails.
|
|
188
|
+
"""
|
|
189
|
+
command = self.config.get("command")
|
|
190
|
+
args = self.config.get("args", [])
|
|
191
|
+
env = self.config.get("env")
|
|
192
|
+
|
|
193
|
+
if not command:
|
|
194
|
+
raise ValueError("Command is required for stdio transport")
|
|
195
|
+
|
|
196
|
+
logger.debug(f"Attempting stdio connection with command: {command}, args: {args}")
|
|
197
|
+
try:
|
|
198
|
+
stdio_params = StdioServerParameters(command=command, args=args, env=env)
|
|
199
|
+
self.ctx = stdio_client(stdio_params)
|
|
200
|
+
read_stream, write_stream = await self.ctx.__aenter__()
|
|
201
|
+
logger.info(f"Connected to {self.server_name} via STDIO")
|
|
202
|
+
return read_stream, write_stream, self.ctx
|
|
203
|
+
except Exception as e:
|
|
204
|
+
raise ConnectionError(f"STDIO connection failed for {self.server_name}: {str(e)}") from e
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def create_transport(server_name: str, config: MCPConfiguration, transport_type: TransportType | str) -> Transport:
|
|
208
|
+
"""Factory to create the appropriate transport instance.
|
|
209
|
+
|
|
210
|
+
Args:
|
|
211
|
+
server_name (str): Server name
|
|
212
|
+
config (MCPConfiguration): Config
|
|
213
|
+
transport_type (str): Transport type ('http', 'sse', 'stdio')
|
|
214
|
+
|
|
215
|
+
Returns:
|
|
216
|
+
Transport: Concrete transport instance
|
|
217
|
+
|
|
218
|
+
Raises:
|
|
219
|
+
ValueError: If transport_type is unsupported.
|
|
220
|
+
"""
|
|
221
|
+
if transport_type == TransportType.HTTP:
|
|
222
|
+
return HTTPTransport(server_name, config)
|
|
223
|
+
elif transport_type == TransportType.SSE:
|
|
224
|
+
return SSETransport(server_name, config)
|
|
225
|
+
elif transport_type == TransportType.STDIO:
|
|
226
|
+
return StdioTransport(server_name, config)
|
|
227
|
+
else:
|
|
228
|
+
raise ValueError(f"Unsupported transport type: {transport_type}")
|