aip-agents-binary 0.5.24__py3-none-any.whl → 0.5.25b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aip_agents/__init__.pyi +19 -0
- aip_agents/a2a/__init__.pyi +3 -0
- aip_agents/a2a/server/__init__.pyi +4 -0
- aip_agents/a2a/server/base_executor.pyi +73 -0
- aip_agents/a2a/server/google_adk_executor.pyi +51 -0
- aip_agents/a2a/server/langflow_executor.pyi +43 -0
- aip_agents/a2a/server/langgraph_executor.pyi +47 -0
- aip_agents/a2a/types.pyi +132 -0
- aip_agents/agent/__init__.pyi +9 -0
- aip_agents/agent/base_agent.pyi +221 -0
- aip_agents/agent/base_langgraph_agent.py +6 -0
- aip_agents/agent/base_langgraph_agent.pyi +232 -0
- aip_agents/agent/google_adk_agent.pyi +141 -0
- aip_agents/agent/google_adk_constants.pyi +3 -0
- aip_agents/agent/hitl/__init__.pyi +6 -0
- aip_agents/agent/hitl/config.pyi +15 -0
- aip_agents/agent/hitl/langgraph_hitl_mixin.pyi +42 -0
- aip_agents/agent/hitl/manager.pyi +200 -0
- aip_agents/agent/hitl/models.pyi +3 -0
- aip_agents/agent/hitl/prompt/__init__.pyi +4 -0
- aip_agents/agent/hitl/prompt/base.pyi +24 -0
- aip_agents/agent/hitl/prompt/deferred.pyi +30 -0
- aip_agents/agent/hitl/registry.pyi +101 -0
- aip_agents/agent/interface.pyi +81 -0
- aip_agents/agent/interfaces.pyi +44 -0
- aip_agents/agent/langflow_agent.pyi +133 -0
- aip_agents/agent/langgraph_memory_enhancer_agent.pyi +49 -0
- aip_agents/agent/langgraph_react_agent.py +96 -14
- aip_agents/agent/langgraph_react_agent.pyi +131 -0
- aip_agents/agent/system_instruction_context.pyi +13 -0
- aip_agents/clients/__init__.pyi +4 -0
- aip_agents/clients/langflow/__init__.pyi +4 -0
- aip_agents/clients/langflow/client.pyi +140 -0
- aip_agents/clients/langflow/types.pyi +7 -0
- aip_agents/constants.pyi +7 -0
- aip_agents/examples/__init__.pyi +0 -0
- aip_agents/examples/compare_streaming_client.py +2 -2
- aip_agents/examples/compare_streaming_client.pyi +48 -0
- aip_agents/examples/compare_streaming_server.py +1 -1
- aip_agents/examples/compare_streaming_server.pyi +18 -0
- aip_agents/examples/demo_memory_recall.pyi +58 -0
- aip_agents/examples/hello_world_a2a_google_adk_client.pyi +9 -0
- aip_agents/examples/hello_world_a2a_google_adk_client_agent.pyi +9 -0
- aip_agents/examples/hello_world_a2a_google_adk_client_streaming.pyi +9 -0
- aip_agents/examples/hello_world_a2a_google_adk_server.pyi +15 -0
- aip_agents/examples/hello_world_a2a_langchain_client.pyi +5 -0
- aip_agents/examples/hello_world_a2a_langchain_client_agent.pyi +5 -0
- aip_agents/examples/hello_world_a2a_langchain_client_lm_invoker.pyi +5 -0
- aip_agents/examples/hello_world_a2a_langchain_client_streaming.pyi +5 -0
- aip_agents/examples/hello_world_a2a_langchain_reference_client_streaming.pyi +5 -0
- aip_agents/examples/hello_world_a2a_langchain_reference_server.pyi +15 -0
- aip_agents/examples/hello_world_a2a_langchain_server.pyi +15 -0
- aip_agents/examples/hello_world_a2a_langchain_server_lm_invoker.pyi +15 -0
- aip_agents/examples/hello_world_a2a_langflow_client.pyi +9 -0
- aip_agents/examples/hello_world_a2a_langflow_server.pyi +14 -0
- aip_agents/examples/hello_world_a2a_langgraph_artifact_client.pyi +5 -0
- aip_agents/examples/hello_world_a2a_langgraph_artifact_client_streaming.pyi +5 -0
- aip_agents/examples/hello_world_a2a_langgraph_artifact_server.pyi +16 -0
- aip_agents/examples/hello_world_a2a_langgraph_client.pyi +9 -0
- aip_agents/examples/hello_world_a2a_langgraph_client_agent.pyi +9 -0
- aip_agents/examples/hello_world_a2a_langgraph_client_agent_lm_invoker.pyi +2 -0
- aip_agents/examples/hello_world_a2a_langgraph_client_streaming.pyi +9 -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.pyi +5 -0
- aip_agents/examples/hello_world_a2a_langgraph_server.pyi +14 -0
- aip_agents/examples/hello_world_a2a_langgraph_server_lm_invoker.pyi +15 -0
- aip_agents/examples/hello_world_a2a_langgraph_server_tool_streaming.pyi +15 -0
- aip_agents/examples/hello_world_a2a_mcp_langgraph.pyi +48 -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.pyi +45 -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.pyi +15 -0
- aip_agents/examples/hello_world_google_adk.pyi +5 -0
- aip_agents/examples/hello_world_google_adk_mcp_http.pyi +5 -0
- aip_agents/examples/hello_world_google_adk_mcp_http_stream.pyi +5 -0
- aip_agents/examples/hello_world_google_adk_mcp_sse.pyi +5 -0
- aip_agents/examples/hello_world_google_adk_mcp_sse_stream.pyi +5 -0
- aip_agents/examples/hello_world_google_adk_mcp_stdio.pyi +5 -0
- aip_agents/examples/hello_world_google_adk_mcp_stdio_stream.pyi +5 -0
- aip_agents/examples/hello_world_google_adk_stream.pyi +5 -0
- aip_agents/examples/hello_world_langchain.pyi +5 -0
- aip_agents/examples/hello_world_langchain_lm_invoker.pyi +2 -0
- aip_agents/examples/hello_world_langchain_mcp_http.pyi +5 -0
- aip_agents/examples/hello_world_langchain_mcp_http_interactive.pyi +16 -0
- aip_agents/examples/hello_world_langchain_mcp_http_stream.pyi +5 -0
- aip_agents/examples/hello_world_langchain_mcp_multi_server.pyi +18 -0
- aip_agents/examples/hello_world_langchain_mcp_sse.pyi +5 -0
- aip_agents/examples/hello_world_langchain_mcp_sse_stream.pyi +5 -0
- aip_agents/examples/hello_world_langchain_mcp_stdio.pyi +5 -0
- aip_agents/examples/hello_world_langchain_mcp_stdio_stream.pyi +5 -0
- aip_agents/examples/hello_world_langchain_stream.pyi +5 -0
- aip_agents/examples/hello_world_langchain_stream_lm_invoker.pyi +5 -0
- aip_agents/examples/hello_world_langflow_agent.pyi +35 -0
- aip_agents/examples/hello_world_langgraph.pyi +5 -0
- aip_agents/examples/hello_world_langgraph_gl_connector_twitter.pyi +5 -0
- aip_agents/examples/hello_world_langgraph_mcp_http.pyi +5 -0
- aip_agents/examples/hello_world_langgraph_mcp_http_stream.pyi +5 -0
- aip_agents/examples/hello_world_langgraph_mcp_sse.pyi +5 -0
- aip_agents/examples/hello_world_langgraph_mcp_sse_stream.pyi +5 -0
- aip_agents/examples/hello_world_langgraph_mcp_stdio.pyi +5 -0
- aip_agents/examples/hello_world_langgraph_mcp_stdio_stream.pyi +5 -0
- aip_agents/examples/hello_world_langgraph_stream.pyi +5 -0
- aip_agents/examples/hello_world_langgraph_stream_lm_invoker.pyi +5 -0
- aip_agents/examples/hello_world_model_switch_cli.pyi +30 -0
- aip_agents/examples/hello_world_multi_agent_adk.pyi +6 -0
- aip_agents/examples/hello_world_multi_agent_langchain.pyi +5 -0
- aip_agents/examples/hello_world_multi_agent_langgraph.pyi +5 -0
- aip_agents/examples/hello_world_multi_agent_langgraph_lm_invoker.pyi +5 -0
- aip_agents/examples/hello_world_pii_logger.pyi +5 -0
- aip_agents/examples/hello_world_sentry.pyi +21 -0
- aip_agents/examples/hello_world_step_limits.pyi +17 -0
- aip_agents/examples/hello_world_stock_a2a_server.pyi +17 -0
- aip_agents/examples/hello_world_tool_output_client.pyi +5 -0
- aip_agents/examples/hello_world_tool_output_server.pyi +19 -0
- aip_agents/examples/hitl_demo.pyi +67 -0
- aip_agents/examples/pii_demo_langgraph_client.pyi +5 -0
- aip_agents/examples/pii_demo_langgraph_server.pyi +20 -0
- aip_agents/examples/pii_demo_multi_agent_client.pyi +5 -0
- aip_agents/examples/pii_demo_multi_agent_server.pyi +40 -0
- aip_agents/examples/todolist_planning_a2a_langchain_client.py +2 -2
- aip_agents/examples/todolist_planning_a2a_langchain_client.pyi +5 -0
- aip_agents/examples/todolist_planning_a2a_langgraph_server.py +1 -1
- aip_agents/examples/todolist_planning_a2a_langgraph_server.pyi +19 -0
- aip_agents/examples/tools/__init__.pyi +9 -0
- aip_agents/examples/tools/adk_arithmetic_tools.pyi +24 -0
- aip_agents/examples/tools/adk_weather_tool.pyi +18 -0
- aip_agents/examples/tools/data_generator_tool.pyi +15 -0
- aip_agents/examples/tools/data_visualization_tool.pyi +19 -0
- aip_agents/examples/tools/image_artifact_tool.pyi +26 -0
- aip_agents/examples/tools/langchain_arithmetic_tools.pyi +17 -0
- aip_agents/examples/tools/langchain_currency_exchange_tool.pyi +20 -0
- aip_agents/examples/tools/langchain_graph_artifact_tool.pyi +25 -0
- aip_agents/examples/tools/langchain_weather_tool.pyi +19 -0
- aip_agents/examples/tools/langgraph_streaming_tool.pyi +43 -0
- aip_agents/examples/tools/mock_retrieval_tool.pyi +13 -0
- aip_agents/examples/tools/pii_demo_tools.pyi +54 -0
- aip_agents/examples/tools/random_chart_tool.pyi +20 -0
- aip_agents/examples/tools/serper_tool.pyi +16 -0
- aip_agents/examples/tools/stock_tools.pyi +36 -0
- aip_agents/examples/tools/table_generator_tool.pyi +22 -0
- aip_agents/examples/tools/time_tool.pyi +15 -0
- aip_agents/examples/tools/weather_forecast_tool.pyi +14 -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__.pyi +0 -0
- aip_agents/mcp/client/__init__.pyi +5 -0
- aip_agents/mcp/client/base_mcp_client.pyi +148 -0
- aip_agents/mcp/client/connection_manager.pyi +48 -0
- aip_agents/mcp/client/google_adk/__init__.pyi +3 -0
- aip_agents/mcp/client/google_adk/client.pyi +75 -0
- aip_agents/mcp/client/langchain/__init__.pyi +3 -0
- aip_agents/mcp/client/langchain/client.pyi +48 -0
- aip_agents/mcp/client/persistent_session.pyi +113 -0
- aip_agents/mcp/client/session_pool.pyi +101 -0
- aip_agents/mcp/client/transports.pyi +123 -0
- aip_agents/mcp/utils/__init__.pyi +0 -0
- aip_agents/mcp/utils/config_validator.pyi +82 -0
- aip_agents/memory/__init__.pyi +5 -0
- aip_agents/memory/adapters/__init__.pyi +4 -0
- aip_agents/memory/adapters/base_adapter.pyi +150 -0
- aip_agents/memory/adapters/mem0.pyi +22 -0
- aip_agents/memory/base.pyi +60 -0
- aip_agents/memory/constants.pyi +25 -0
- aip_agents/memory/factory.pyi +24 -0
- aip_agents/memory/guidance.pyi +3 -0
- aip_agents/memory/simple_memory.pyi +23 -0
- aip_agents/middleware/__init__.pyi +5 -0
- aip_agents/middleware/base.py +8 -0
- aip_agents/middleware/base.pyi +75 -0
- aip_agents/middleware/manager.py +22 -0
- aip_agents/middleware/manager.pyi +84 -0
- aip_agents/middleware/todolist.pyi +125 -0
- aip_agents/schema/__init__.pyi +9 -0
- aip_agents/schema/a2a.pyi +40 -0
- aip_agents/schema/agent.pyi +65 -0
- aip_agents/schema/hitl.pyi +89 -0
- aip_agents/schema/langgraph.pyi +28 -0
- aip_agents/schema/model_id.pyi +54 -0
- aip_agents/schema/step_limit.pyi +63 -0
- aip_agents/schema/storage.pyi +21 -0
- aip_agents/sentry/__init__.pyi +3 -0
- aip_agents/sentry/sentry.pyi +48 -0
- aip_agents/storage/__init__.pyi +8 -0
- aip_agents/storage/base.pyi +58 -0
- aip_agents/storage/clients/__init__.pyi +3 -0
- aip_agents/storage/clients/minio_client.pyi +137 -0
- aip_agents/storage/config.pyi +29 -0
- aip_agents/storage/providers/__init__.pyi +5 -0
- aip_agents/storage/providers/base.pyi +88 -0
- aip_agents/storage/providers/memory.pyi +79 -0
- aip_agents/storage/providers/object_storage.pyi +98 -0
- aip_agents/tools/__init__.pyi +9 -0
- aip_agents/tools/browser_use/__init__.pyi +14 -0
- aip_agents/tools/browser_use/action_parser.pyi +18 -0
- aip_agents/tools/browser_use/browser_use_tool.pyi +50 -0
- aip_agents/tools/browser_use/llm_config.pyi +52 -0
- aip_agents/tools/browser_use/minio_storage.pyi +109 -0
- aip_agents/tools/browser_use/schemas.pyi +32 -0
- aip_agents/tools/browser_use/session.pyi +4 -0
- aip_agents/tools/browser_use/session_errors.pyi +53 -0
- aip_agents/tools/browser_use/steel_session_recording.pyi +63 -0
- aip_agents/tools/browser_use/streaming.pyi +81 -0
- aip_agents/tools/browser_use/structured_data_parser.pyi +86 -0
- aip_agents/tools/browser_use/structured_data_recovery.pyi +43 -0
- aip_agents/tools/browser_use/types.pyi +45 -0
- aip_agents/tools/code_sandbox/__init__.pyi +3 -0
- aip_agents/tools/code_sandbox/constant.pyi +4 -0
- aip_agents/tools/code_sandbox/e2b_cloud_sandbox_extended.pyi +102 -0
- aip_agents/tools/code_sandbox/e2b_sandbox_tool.pyi +29 -0
- aip_agents/tools/constants.pyi +138 -0
- aip_agents/tools/document_loader/__init__.pyi +7 -0
- aip_agents/tools/document_loader/base_reader.pyi +75 -0
- aip_agents/tools/document_loader/docx_reader_tool.pyi +10 -0
- aip_agents/tools/document_loader/excel_reader_tool.pyi +26 -0
- aip_agents/tools/document_loader/pdf_reader_tool.pyi +11 -0
- aip_agents/tools/document_loader/pdf_splitter.pyi +18 -0
- aip_agents/tools/gl_connector/__init__.pyi +3 -0
- aip_agents/tools/gl_connector/tool.pyi +74 -0
- aip_agents/tools/gl_connector_tools.pyi +39 -0
- aip_agents/tools/memory_search/__init__.pyi +5 -0
- aip_agents/tools/memory_search/base.pyi +69 -0
- aip_agents/tools/memory_search/mem0.pyi +19 -0
- aip_agents/tools/memory_search/schema.pyi +15 -0
- aip_agents/tools/memory_search_tool.pyi +3 -0
- aip_agents/tools/time_tool.pyi +16 -0
- aip_agents/tools/tool_config_injector.pyi +26 -0
- aip_agents/tools/web_search/__init__.pyi +3 -0
- aip_agents/tools/web_search/serper_tool.pyi +19 -0
- aip_agents/types/__init__.pyi +36 -0
- aip_agents/types/a2a_events.pyi +3 -0
- aip_agents/utils/__init__.pyi +11 -0
- aip_agents/utils/a2a_connector.pyi +146 -0
- aip_agents/utils/artifact_helpers.pyi +203 -0
- aip_agents/utils/constants.pyi +10 -0
- aip_agents/utils/datetime/__init__.pyi +4 -0
- aip_agents/utils/datetime/normalization.pyi +95 -0
- aip_agents/utils/datetime/timezone.pyi +48 -0
- aip_agents/utils/env_loader.pyi +10 -0
- aip_agents/utils/event_handler_registry.pyi +23 -0
- aip_agents/utils/file_prompt_utils.pyi +21 -0
- aip_agents/utils/final_response_builder.pyi +34 -0
- aip_agents/utils/formatter_llm_client.pyi +71 -0
- aip_agents/utils/langgraph/__init__.pyi +3 -0
- aip_agents/utils/langgraph/converter.pyi +49 -0
- aip_agents/utils/langgraph/tool_managers/__init__.pyi +5 -0
- aip_agents/utils/langgraph/tool_managers/a2a_tool_manager.pyi +35 -0
- aip_agents/utils/langgraph/tool_managers/base_tool_manager.pyi +48 -0
- aip_agents/utils/langgraph/tool_managers/delegation_tool_manager.pyi +56 -0
- aip_agents/utils/langgraph/tool_output_management.pyi +292 -0
- aip_agents/utils/logger.pyi +60 -0
- aip_agents/utils/metadata/__init__.pyi +5 -0
- aip_agents/utils/metadata/activity_metadata_helper.pyi +25 -0
- aip_agents/utils/metadata/activity_narrative/__init__.pyi +7 -0
- aip_agents/utils/metadata/activity_narrative/builder.pyi +35 -0
- aip_agents/utils/metadata/activity_narrative/constants.pyi +10 -0
- aip_agents/utils/metadata/activity_narrative/context.pyi +32 -0
- aip_agents/utils/metadata/activity_narrative/formatters.pyi +48 -0
- aip_agents/utils/metadata/activity_narrative/utils.pyi +12 -0
- aip_agents/utils/metadata/schemas/__init__.pyi +4 -0
- aip_agents/utils/metadata/schemas/activity_schema.pyi +18 -0
- aip_agents/utils/metadata/schemas/thinking_schema.pyi +20 -0
- aip_agents/utils/metadata/thinking_metadata_helper.pyi +4 -0
- aip_agents/utils/metadata_helper.pyi +117 -0
- aip_agents/utils/name_preprocessor/__init__.pyi +6 -0
- aip_agents/utils/name_preprocessor/base_name_preprocessor.pyi +52 -0
- aip_agents/utils/name_preprocessor/google_name_preprocessor.pyi +38 -0
- aip_agents/utils/name_preprocessor/name_preprocessor.pyi +41 -0
- aip_agents/utils/name_preprocessor/openai_name_preprocessor.pyi +34 -0
- aip_agents/utils/pii/__init__.pyi +5 -0
- aip_agents/utils/pii/pii_handler.pyi +96 -0
- aip_agents/utils/pii/pii_helper.pyi +78 -0
- aip_agents/utils/pii/uuid_deanonymizer_mapping.pyi +73 -0
- aip_agents/utils/reference_helper.pyi +81 -0
- aip_agents/utils/sse_chunk_transformer.pyi +166 -0
- aip_agents/utils/step_limit_manager.pyi +112 -0
- aip_agents/utils/token_usage_helper.pyi +60 -0
- {aip_agents_binary-0.5.24.dist-info → aip_agents_binary-0.5.25b1.dist-info}/METADATA +49 -49
- aip_agents_binary-0.5.25b1.dist-info/RECORD +566 -0
- {aip_agents_binary-0.5.24.dist-info → aip_agents_binary-0.5.25b1.dist-info}/WHEEL +1 -1
- aip_agents_binary-0.5.24.dist-info/RECORD +0 -280
- {aip_agents_binary-0.5.24.dist-info → aip_agents_binary-0.5.25b1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
from _typeshed import Incomplete
|
|
2
|
+
from aip_agents.mcp.client.base_mcp_client import BaseMCPClient as BaseMCPClient
|
|
3
|
+
from aip_agents.utils.logger import get_logger as get_logger
|
|
4
|
+
from gllm_tools.mcp.client.config import MCPConfiguration as MCPConfiguration
|
|
5
|
+
from google.adk.tools import FunctionTool
|
|
6
|
+
from mcp.types import EmbeddedResource, ImageContent
|
|
7
|
+
|
|
8
|
+
NonTextContent = ImageContent | EmbeddedResource
|
|
9
|
+
logger: Incomplete
|
|
10
|
+
|
|
11
|
+
class GoogleADKMCPClient(BaseMCPClient):
|
|
12
|
+
'''Google ADK MCP Client with Persistent Sessions.
|
|
13
|
+
|
|
14
|
+
This client extends BaseMCPClient to provide Google ADK-specific tool conversion
|
|
15
|
+
while maintaining persistent MCP sessions and connection reuse across tool calls.
|
|
16
|
+
It converts MCP tools into ADK FunctionTool instances for seamless integration.
|
|
17
|
+
|
|
18
|
+
The client handles:
|
|
19
|
+
- Converting MCP tools to ADK FunctionTool instances using persistent sessions
|
|
20
|
+
- Managing MCP server connections with automatic reconnection
|
|
21
|
+
- Converting MCP resources to ADK-compatible formats
|
|
22
|
+
- Handling tool execution with proper error formatting for ADK agents
|
|
23
|
+
|
|
24
|
+
Example:
|
|
25
|
+
```python
|
|
26
|
+
from aip_agents.mcp.client.google_adk.client import GoogleADKMCPClient
|
|
27
|
+
from gllm_tools.mcp.client.config import MCPConfiguration
|
|
28
|
+
|
|
29
|
+
servers = {
|
|
30
|
+
"filesystem": MCPConfiguration(
|
|
31
|
+
command="npx",
|
|
32
|
+
args=["-y", "@modelcontextprotocol/server-filesystem", "/path/to/folder"]
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
client = GoogleADKMCPClient(servers)
|
|
37
|
+
await client.initialize() # Initialize persistent sessions
|
|
38
|
+
tools = await client.get_tools() # Returns list of ADK FunctionTool instances
|
|
39
|
+
```
|
|
40
|
+
'''
|
|
41
|
+
RESOURCE_FETCH_TIMEOUT: int
|
|
42
|
+
def __init__(self, servers: dict[str, MCPConfiguration]) -> None:
|
|
43
|
+
"""Initialize Google ADK MCP client.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
servers (dict[str, MCPConfiguration]): Dictionary of MCP server configurations
|
|
47
|
+
"""
|
|
48
|
+
async def initialize(self) -> None:
|
|
49
|
+
"""Initialize persistent MCP sessions for Google ADK integration.
|
|
50
|
+
|
|
51
|
+
This method ensures all MCP servers are connected with persistent sessions
|
|
52
|
+
and prepares the client for ADK tool conversion.
|
|
53
|
+
|
|
54
|
+
Raises:
|
|
55
|
+
Exception: If session initialization fails
|
|
56
|
+
"""
|
|
57
|
+
async def get_tools(self, server: str | None = None) -> list[FunctionTool]:
|
|
58
|
+
"""Get ADK-compatible FunctionTool instances with smart caching.
|
|
59
|
+
|
|
60
|
+
Converts MCP tools to ADK format and caches them for better performance
|
|
61
|
+
on repeated access. Cache is keyed by server parameter.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
server (str | None): Optional server name to filter tools from a specific server.
|
|
65
|
+
If None, returns tools from all configured servers.
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
list[FunctionTool]: List of cached ADK FunctionTool instances.
|
|
69
|
+
"""
|
|
70
|
+
async def cleanup(self) -> None:
|
|
71
|
+
"""Clean up Google ADK MCP client resources.
|
|
72
|
+
|
|
73
|
+
This method ensures all persistent sessions are properly closed and
|
|
74
|
+
ADK-specific resources are cleaned up.
|
|
75
|
+
"""
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from _typeshed import Incomplete
|
|
2
|
+
from aip_agents.mcp.client.base_mcp_client import BaseMCPClient as BaseMCPClient
|
|
3
|
+
from aip_agents.utils.logger import get_logger as get_logger
|
|
4
|
+
from gllm_tools.mcp.client.config import MCPConfiguration as MCPConfiguration
|
|
5
|
+
from langchain_core.tools import StructuredTool
|
|
6
|
+
from mcp.types import EmbeddedResource, ImageContent
|
|
7
|
+
|
|
8
|
+
NonTextContent = ImageContent | EmbeddedResource
|
|
9
|
+
logger: Incomplete
|
|
10
|
+
|
|
11
|
+
class LangchainMCPClient(BaseMCPClient):
|
|
12
|
+
"""Langchain MCP Client with Session Persistence.
|
|
13
|
+
|
|
14
|
+
This client extends BaseMCPClient to provide LangChain-specific tool conversion
|
|
15
|
+
while maintaining persistent MCP sessions and connection reuse across tool calls.
|
|
16
|
+
"""
|
|
17
|
+
RESOURCE_FETCH_TIMEOUT: int
|
|
18
|
+
def __init__(self, servers: dict[str, MCPConfiguration]) -> None:
|
|
19
|
+
"""Initialize LangChain MCP client.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
servers (dict[str, MCPConfiguration]): Dictionary of MCP server configurations
|
|
23
|
+
"""
|
|
24
|
+
async def initialize(self) -> None:
|
|
25
|
+
"""Initialize all sessions for LangChain client.
|
|
26
|
+
|
|
27
|
+
This method initializes the base MCP sessions and prepares for tool caching.
|
|
28
|
+
|
|
29
|
+
Raises:
|
|
30
|
+
Exception: If base initialization fails
|
|
31
|
+
"""
|
|
32
|
+
async def get_tools(self, server: str | None = None) -> list[StructuredTool]:
|
|
33
|
+
"""Get LangChain StructuredTools with smart caching.
|
|
34
|
+
|
|
35
|
+
Converts MCP tools to LangChain format and caches them for better performance
|
|
36
|
+
on repeated access. Cache is keyed by server parameter.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
server (str | None): Optional server name to filter tools. If None, returns all tools.
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
list[StructuredTool]: List of cached LangChain StructuredTool instances
|
|
43
|
+
"""
|
|
44
|
+
async def cleanup(self) -> None:
|
|
45
|
+
"""Cleanup LangChain MCP resources.
|
|
46
|
+
|
|
47
|
+
This method extends base class cleanup and clears the LangChain tool cache.
|
|
48
|
+
"""
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
from _typeshed import Incomplete
|
|
2
|
+
from aip_agents.mcp.client.connection_manager import MCPConnectionManager as MCPConnectionManager
|
|
3
|
+
from aip_agents.mcp.utils.config_validator import 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 import ClientSession
|
|
7
|
+
from mcp.types import CallToolResult, Tool as Tool
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
logger: Incomplete
|
|
11
|
+
|
|
12
|
+
class PersistentMCPSession:
|
|
13
|
+
"""Persistent MCP session that reuses connections.
|
|
14
|
+
|
|
15
|
+
This session wrapper manages the connection lifecycle and caches tools
|
|
16
|
+
to avoid repeated initialization overhead. It provides automatic reconnection
|
|
17
|
+
and thread-safe operations.
|
|
18
|
+
|
|
19
|
+
Tool Filtering:
|
|
20
|
+
When allowed_tools is configured, tools are filtered inline during list_tools()
|
|
21
|
+
and permission checked in call_tool() using set lookup.
|
|
22
|
+
"""
|
|
23
|
+
server_name: Incomplete
|
|
24
|
+
config: Incomplete
|
|
25
|
+
connection_manager: Incomplete
|
|
26
|
+
client_session: ClientSession | None
|
|
27
|
+
tools: list[Tool]
|
|
28
|
+
def __init__(self, server_name: str, config: MCPConfiguration, allowed_tools: list[str] | None = None) -> None:
|
|
29
|
+
"""Initialize persistent session.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
server_name: Name of the MCP server
|
|
33
|
+
config: MCP server configuration
|
|
34
|
+
allowed_tools: Optional list of tool names to allow. None or empty means all tools allowed.
|
|
35
|
+
"""
|
|
36
|
+
async def initialize(self) -> None:
|
|
37
|
+
"""Initialize session once and cache tools.
|
|
38
|
+
|
|
39
|
+
This method is idempotent and can be called multiple times safely.
|
|
40
|
+
|
|
41
|
+
Raises:
|
|
42
|
+
Exception: If session initialization fails
|
|
43
|
+
"""
|
|
44
|
+
async def call_tool(self, name: str, arguments: dict[str, Any]) -> CallToolResult:
|
|
45
|
+
"""Call MCP tool using persistent session.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
name (str): Tool name
|
|
49
|
+
arguments (dict[str, Any]): Tool arguments
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
CallToolResult: Tool call result
|
|
53
|
+
|
|
54
|
+
Raises:
|
|
55
|
+
Exception: If tool call fails
|
|
56
|
+
"""
|
|
57
|
+
async def read_resource(self, uri: str) -> Any:
|
|
58
|
+
"""Read an MCP resource using persistent session.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
uri (str): The URI of the resource to read
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
Any: The resource content
|
|
65
|
+
|
|
66
|
+
Raises:
|
|
67
|
+
Exception: If resource reading fails
|
|
68
|
+
"""
|
|
69
|
+
async def list_tools(self) -> list[Tool]:
|
|
70
|
+
"""Get cached tools list with allowed tools filtering applied.
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
list[Tool]: a copy of list of available tools, filtered to only allowed tools if configured
|
|
74
|
+
"""
|
|
75
|
+
def get_tools_count(self) -> int:
|
|
76
|
+
"""Get count of allowed tools.
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
Count of allowed tools
|
|
80
|
+
"""
|
|
81
|
+
async def ensure_connected(self) -> None:
|
|
82
|
+
"""Ensure connection is healthy, reconnect if needed.
|
|
83
|
+
|
|
84
|
+
This method provides automatic reconnection capability.
|
|
85
|
+
|
|
86
|
+
Raises:
|
|
87
|
+
Exception: If reconnection fails
|
|
88
|
+
"""
|
|
89
|
+
async def disconnect(self) -> None:
|
|
90
|
+
"""Disconnect session gracefully.
|
|
91
|
+
|
|
92
|
+
This method cleans up all resources and connections.
|
|
93
|
+
"""
|
|
94
|
+
@property
|
|
95
|
+
def is_initialized(self) -> bool:
|
|
96
|
+
"""Check if session is initialized.
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
bool: True if initialized and connected, False otherwise
|
|
100
|
+
"""
|
|
101
|
+
def update_allowed_tools(self, allowed_tools: list[str] | None) -> bool:
|
|
102
|
+
"""Update the list of allowed tools for this session.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
allowed_tools: New list of allowed tool names or None for no restriction.
|
|
106
|
+
None and empty list both mean 'no restrictions, allow all tools'.
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
bool: True if the configuration changed, False otherwise.
|
|
110
|
+
|
|
111
|
+
Raises:
|
|
112
|
+
ValueError: If allowed_tools contains invalid entries.
|
|
113
|
+
"""
|
|
@@ -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,123 @@
|
|
|
1
|
+
from _typeshed import Incomplete
|
|
2
|
+
from abc import ABC, abstractmethod
|
|
3
|
+
from aip_agents.utils.logger import get_logger as get_logger
|
|
4
|
+
from collections.abc import AsyncIterator as AsyncIterator
|
|
5
|
+
from enum import StrEnum
|
|
6
|
+
from gllm_tools.mcp.client.config import MCPConfiguration
|
|
7
|
+
from typing import Any, Protocol
|
|
8
|
+
|
|
9
|
+
class TransportContext(Protocol):
|
|
10
|
+
"""Protocol defining the interface for async context managers used in MCP transport connections."""
|
|
11
|
+
async def __aenter__(self) -> None:
|
|
12
|
+
"""Enter the async context, establishing the connection and returning read/write streams."""
|
|
13
|
+
async def __aexit__(self, _exc_type, _exc_val, _exc_tb) -> None:
|
|
14
|
+
"""Exit the async context, performing cleanup and closing the connection.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
_exc_type: Exception type if an exception occurred.
|
|
18
|
+
_exc_val: Exception value if an exception occurred.
|
|
19
|
+
_exc_tb: Exception traceback if an exception occurred.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
logger: Incomplete
|
|
23
|
+
DEFAULT_TIMEOUT: float
|
|
24
|
+
|
|
25
|
+
class TransportType(StrEnum):
|
|
26
|
+
"""Enum for supported MCP transport types."""
|
|
27
|
+
HTTP: str
|
|
28
|
+
SSE: str
|
|
29
|
+
STDIO: str
|
|
30
|
+
|
|
31
|
+
class Transport(ABC):
|
|
32
|
+
"""Abstract base class for MCP transports."""
|
|
33
|
+
server_name: Incomplete
|
|
34
|
+
config: Incomplete
|
|
35
|
+
ctx: Any
|
|
36
|
+
def __init__(self, server_name: str, config: MCPConfiguration) -> None:
|
|
37
|
+
"""Initialize the transport.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
server_name (str): Name of the MCP server.
|
|
41
|
+
config (MCPConfiguration): Configuration for the transport.
|
|
42
|
+
"""
|
|
43
|
+
@abstractmethod
|
|
44
|
+
async def connect(self) -> tuple[AsyncIterator[bytes], AsyncIterator[bytes], TransportContext]:
|
|
45
|
+
"""Establish connection and return read/write streams and context manager.
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
tuple[AsyncIterator[bytes], AsyncIterator[bytes], Any]:
|
|
49
|
+
(read_stream, write_stream, ctx)
|
|
50
|
+
Where:
|
|
51
|
+
- read_stream: AsyncIterator[bytes] for reading from the server.
|
|
52
|
+
- write_stream: AsyncIterator[bytes] for writing to the server.
|
|
53
|
+
- ctx: The async context manager instance for cleanup via __aexit__.
|
|
54
|
+
|
|
55
|
+
Raises:
|
|
56
|
+
ValueError: If required config (e.g., URL or command) is missing.
|
|
57
|
+
ConnectionError: If connection establishment fails.
|
|
58
|
+
"""
|
|
59
|
+
async def close(self) -> None:
|
|
60
|
+
"""Clean up the transport connection."""
|
|
61
|
+
|
|
62
|
+
class SSETransport(Transport):
|
|
63
|
+
"""SSE transport handler."""
|
|
64
|
+
ctx: Incomplete
|
|
65
|
+
async def connect(self) -> tuple[AsyncIterator[bytes], AsyncIterator[bytes], TransportContext]:
|
|
66
|
+
"""Connect using SSE transport.
|
|
67
|
+
|
|
68
|
+
Builds SSE URL from config, initializes client with timeout, and enters context.
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
tuple[AsyncIterator[bytes], AsyncIterator[bytes], Any]: (read_stream, write_stream, ctx)
|
|
72
|
+
|
|
73
|
+
Raises:
|
|
74
|
+
ValueError: If URL is missing.
|
|
75
|
+
ConnectionError: If SSE connection fails.
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
class HTTPTransport(Transport):
|
|
79
|
+
"""Streamable HTTP transport handler."""
|
|
80
|
+
ctx: Incomplete
|
|
81
|
+
async def connect(self) -> tuple[AsyncIterator[bytes], AsyncIterator[bytes], TransportContext]:
|
|
82
|
+
"""Connect using streamable HTTP transport.
|
|
83
|
+
|
|
84
|
+
Builds MCP URL from config, initializes client with timeout, and enters context.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
tuple[AsyncIterator[bytes], AsyncIterator[bytes], Any]: (read_stream, write_stream, ctx)
|
|
88
|
+
|
|
89
|
+
Raises:
|
|
90
|
+
ValueError: If URL is missing.
|
|
91
|
+
ConnectionError: If HTTP connection fails.
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
class StdioTransport(Transport):
|
|
95
|
+
"""STDIO transport handler."""
|
|
96
|
+
ctx: Incomplete
|
|
97
|
+
async def connect(self) -> tuple[AsyncIterator[bytes], AsyncIterator[bytes], TransportContext]:
|
|
98
|
+
"""Connect using STDIO transport.
|
|
99
|
+
|
|
100
|
+
Initializes stdio client from command/args/env in config and enters context.
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
tuple[AsyncIterator[bytes], AsyncIterator[bytes], Any]: (read_stream, write_stream, ctx)
|
|
104
|
+
|
|
105
|
+
Raises:
|
|
106
|
+
ValueError: If command is missing.
|
|
107
|
+
ConnectionError: If STDIO connection fails.
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
def create_transport(server_name: str, config: MCPConfiguration, transport_type: TransportType | str) -> Transport:
|
|
111
|
+
"""Factory to create the appropriate transport instance.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
server_name (str): Server name
|
|
115
|
+
config (MCPConfiguration): Config
|
|
116
|
+
transport_type (str): Transport type ('http', 'sse', 'stdio')
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
Transport: Concrete transport instance
|
|
120
|
+
|
|
121
|
+
Raises:
|
|
122
|
+
ValueError: If transport_type is unsupported.
|
|
123
|
+
"""
|
|
File without changes
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
from _typeshed import Incomplete
|
|
2
|
+
from aip_agents.utils.logger import get_logger as get_logger
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
logger: Incomplete
|
|
6
|
+
|
|
7
|
+
def validate_allowed_tools_list(allowed_tools: list[str] | None, context: str) -> list[str] | None:
|
|
8
|
+
'''Validate that allowed_tools is a list of strings or None.
|
|
9
|
+
|
|
10
|
+
This function validates the type and contents of allowed_tools parameter.
|
|
11
|
+
It can be used to validate allowed_tools from any source (config dict, function parameter, etc).
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
allowed_tools: The allowed_tools value to validate (can be any type)
|
|
15
|
+
context: Context string for error messages (e.g., "Server \'my_server\'", "\'allowed_tools\' parameter")
|
|
16
|
+
|
|
17
|
+
Returns:
|
|
18
|
+
Validated list of allowed tool names, or None if allowed_tools is None or empty.
|
|
19
|
+
None/empty means no restriction (all tools allowed).
|
|
20
|
+
|
|
21
|
+
Raises:
|
|
22
|
+
ValueError: If allowed_tools is not None/list or contains non-string elements
|
|
23
|
+
|
|
24
|
+
Examples:
|
|
25
|
+
>>> validate_allowed_tools_list(None, "test")
|
|
26
|
+
None
|
|
27
|
+
>>> validate_allowed_tools_list([], "test")
|
|
28
|
+
None
|
|
29
|
+
>>> validate_allowed_tools_list(["tool1", "tool2"], "test")
|
|
30
|
+
[\'tool1\', \'tool2\']
|
|
31
|
+
>>> validate_allowed_tools_list("invalid", "test") # doctest: +SKIP
|
|
32
|
+
ValueError: test: \'allowed_tools\' must be a list of strings, got str
|
|
33
|
+
'''
|
|
34
|
+
def validate_allowed_tools_config(config: dict[str, Any], server_name: str) -> list[str] | None:
|
|
35
|
+
'''Validate and extract allowed_tools configuration from server config.
|
|
36
|
+
|
|
37
|
+
This function validates that the allowed_tools field, if present, is a list of strings.
|
|
38
|
+
It returns a normalized list of allowed tool names, or None if not specified/empty.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
config: Server configuration dictionary that may contain \'allowed_tools\' field
|
|
42
|
+
server_name: Name of the server (for error messages)
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
List of allowed tool names, or None if allowed_tools is not specified or is empty.
|
|
46
|
+
None means no restriction (all tools allowed).
|
|
47
|
+
|
|
48
|
+
Raises:
|
|
49
|
+
ValueError: If allowed_tools is present but not a list
|
|
50
|
+
ValueError: If allowed_tools contains non-string elements
|
|
51
|
+
|
|
52
|
+
Examples:
|
|
53
|
+
>>> validate_allowed_tools_config({"url": "..."}, "my_server")
|
|
54
|
+
None
|
|
55
|
+
>>> validate_allowed_tools_config({"url": "...", "allowed_tools": []}, "my_server")
|
|
56
|
+
None
|
|
57
|
+
>>> validate_allowed_tools_config({"url": "...", "allowed_tools": ["tool1", "tool2"]}, "my_server")
|
|
58
|
+
[\'tool1\', \'tool2\']
|
|
59
|
+
'''
|
|
60
|
+
def validate_mcp_server_config(config: dict[str, Any], server_name: str) -> dict[str, Any]:
|
|
61
|
+
'''Validate complete MCP server configuration including allowed_tools.
|
|
62
|
+
|
|
63
|
+
This function performs comprehensive validation on an MCP server configuration,
|
|
64
|
+
ensuring all required fields are present and allowed_tools (if present) is valid.
|
|
65
|
+
Unknown configuration fields (such as any leftover disabled_tools) are silently ignored.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
config: Server configuration dictionary
|
|
69
|
+
server_name: Name of the server (for error messages)
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
Validated configuration dictionary (same as input, after validation)
|
|
73
|
+
|
|
74
|
+
Raises:
|
|
75
|
+
ValueError: If configuration is invalid
|
|
76
|
+
|
|
77
|
+
Examples:
|
|
78
|
+
>>> validate_mcp_server_config({"url": "http://localhost:8080"}, "my_server")
|
|
79
|
+
{\'url\': \'http://localhost:8080\'}
|
|
80
|
+
>>> validate_mcp_server_config({"command": "python", "args": ["server.py"]}, "my_server")
|
|
81
|
+
{\'command\': \'python\', \'args\': [\'server.py\']}
|
|
82
|
+
'''
|