aip-agents-binary 0.5.25__py3-none-macosx_13_0_arm64.whl → 0.6.8__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/agent/__init__.py +44 -4
- aip_agents/agent/base_langgraph_agent.py +163 -74
- aip_agents/agent/base_langgraph_agent.pyi +3 -2
- aip_agents/agent/langgraph_memory_enhancer_agent.py +368 -34
- aip_agents/agent/langgraph_memory_enhancer_agent.pyi +3 -2
- aip_agents/agent/langgraph_react_agent.py +329 -22
- aip_agents/agent/langgraph_react_agent.pyi +41 -2
- aip_agents/examples/hello_world_ptc.py +49 -0
- aip_agents/examples/hello_world_ptc.pyi +5 -0
- aip_agents/examples/hello_world_ptc_custom_tools.py +83 -0
- aip_agents/examples/hello_world_ptc_custom_tools.pyi +7 -0
- aip_agents/examples/hello_world_tool_output_client.py +9 -0
- aip_agents/examples/tools/multiply_tool.py +43 -0
- aip_agents/examples/tools/multiply_tool.pyi +18 -0
- aip_agents/guardrails/engines/base.py +6 -6
- aip_agents/mcp/client/__init__.py +38 -2
- aip_agents/mcp/client/connection_manager.py +36 -1
- aip_agents/mcp/client/connection_manager.pyi +3 -0
- aip_agents/mcp/client/persistent_session.py +318 -68
- aip_agents/mcp/client/persistent_session.pyi +9 -0
- aip_agents/mcp/client/transports.py +37 -2
- aip_agents/mcp/client/transports.pyi +9 -0
- aip_agents/memory/adapters/base_adapter.py +98 -0
- aip_agents/memory/adapters/base_adapter.pyi +25 -0
- aip_agents/ptc/__init__.py +87 -0
- aip_agents/ptc/__init__.pyi +14 -0
- aip_agents/ptc/custom_tools.py +473 -0
- aip_agents/ptc/custom_tools.pyi +184 -0
- aip_agents/ptc/custom_tools_payload.py +400 -0
- aip_agents/ptc/custom_tools_payload.pyi +31 -0
- aip_agents/ptc/custom_tools_templates/__init__.py +1 -0
- aip_agents/ptc/custom_tools_templates/__init__.pyi +0 -0
- aip_agents/ptc/custom_tools_templates/custom_build_function.py.template +23 -0
- aip_agents/ptc/custom_tools_templates/custom_init.py.template +15 -0
- aip_agents/ptc/custom_tools_templates/custom_invoke.py.template +60 -0
- aip_agents/ptc/custom_tools_templates/custom_registry.py.template +87 -0
- aip_agents/ptc/custom_tools_templates/custom_sources_init.py.template +7 -0
- aip_agents/ptc/custom_tools_templates/custom_wrapper.py.template +19 -0
- aip_agents/ptc/doc_gen.py +122 -0
- aip_agents/ptc/doc_gen.pyi +40 -0
- aip_agents/ptc/exceptions.py +57 -0
- aip_agents/ptc/exceptions.pyi +37 -0
- aip_agents/ptc/executor.py +261 -0
- aip_agents/ptc/executor.pyi +99 -0
- aip_agents/ptc/mcp/__init__.py +45 -0
- aip_agents/ptc/mcp/__init__.pyi +7 -0
- aip_agents/ptc/mcp/sandbox_bridge.py +668 -0
- aip_agents/ptc/mcp/sandbox_bridge.pyi +47 -0
- aip_agents/ptc/mcp/templates/__init__.py +1 -0
- aip_agents/ptc/mcp/templates/__init__.pyi +0 -0
- aip_agents/ptc/mcp/templates/mcp_client.py.template +239 -0
- aip_agents/ptc/naming.py +196 -0
- aip_agents/ptc/naming.pyi +85 -0
- aip_agents/ptc/payload.py +26 -0
- aip_agents/ptc/payload.pyi +15 -0
- aip_agents/ptc/prompt_builder.py +673 -0
- aip_agents/ptc/prompt_builder.pyi +59 -0
- aip_agents/ptc/ptc_helper.py +16 -0
- aip_agents/ptc/ptc_helper.pyi +1 -0
- aip_agents/ptc/sandbox_bridge.py +256 -0
- aip_agents/ptc/sandbox_bridge.pyi +38 -0
- aip_agents/ptc/template_utils.py +33 -0
- aip_agents/ptc/template_utils.pyi +13 -0
- aip_agents/ptc/templates/__init__.py +1 -0
- aip_agents/ptc/templates/__init__.pyi +0 -0
- aip_agents/ptc/templates/ptc_helper.py.template +134 -0
- aip_agents/ptc/tool_def_helpers.py +101 -0
- aip_agents/ptc/tool_def_helpers.pyi +38 -0
- aip_agents/ptc/tool_enrichment.py +163 -0
- aip_agents/ptc/tool_enrichment.pyi +60 -0
- aip_agents/sandbox/__init__.py +43 -0
- aip_agents/sandbox/__init__.pyi +5 -0
- aip_agents/sandbox/defaults.py +205 -0
- aip_agents/sandbox/defaults.pyi +30 -0
- aip_agents/sandbox/e2b_runtime.py +295 -0
- aip_agents/sandbox/e2b_runtime.pyi +57 -0
- aip_agents/sandbox/template_builder.py +131 -0
- aip_agents/sandbox/template_builder.pyi +36 -0
- aip_agents/sandbox/types.py +24 -0
- aip_agents/sandbox/types.pyi +14 -0
- aip_agents/sandbox/validation.py +50 -0
- aip_agents/sandbox/validation.pyi +20 -0
- aip_agents/sentry/sentry.py +29 -8
- aip_agents/sentry/sentry.pyi +3 -2
- aip_agents/tools/__init__.py +13 -2
- aip_agents/tools/__init__.pyi +3 -1
- aip_agents/tools/browser_use/browser_use_tool.py +8 -0
- aip_agents/tools/browser_use/streaming.py +2 -0
- aip_agents/tools/date_range_tool.py +554 -0
- aip_agents/tools/date_range_tool.pyi +21 -0
- aip_agents/tools/execute_ptc_code.py +357 -0
- aip_agents/tools/execute_ptc_code.pyi +90 -0
- aip_agents/tools/memory_search/__init__.py +8 -1
- aip_agents/tools/memory_search/__init__.pyi +3 -3
- aip_agents/tools/memory_search/mem0.py +114 -1
- aip_agents/tools/memory_search/mem0.pyi +11 -1
- aip_agents/tools/memory_search/schema.py +33 -0
- aip_agents/tools/memory_search/schema.pyi +10 -0
- aip_agents/tools/memory_search_tool.py +8 -0
- aip_agents/tools/memory_search_tool.pyi +2 -2
- aip_agents/utils/langgraph/tool_managers/delegation_tool_manager.py +26 -1
- aip_agents/utils/langgraph/tool_output_management.py +80 -0
- aip_agents/utils/langgraph/tool_output_management.pyi +37 -0
- {aip_agents_binary-0.5.25.dist-info → aip_agents_binary-0.6.8.dist-info}/METADATA +9 -19
- {aip_agents_binary-0.5.25.dist-info → aip_agents_binary-0.6.8.dist-info}/RECORD +107 -41
- {aip_agents_binary-0.5.25.dist-info → aip_agents_binary-0.6.8.dist-info}/WHEEL +1 -1
- aip_agents/examples/demo_memory_recall.py +0 -401
- aip_agents/examples/demo_memory_recall.pyi +0 -58
- {aip_agents_binary-0.5.25.dist-info → aip_agents_binary-0.6.8.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""Minimal PTC hello world example with custom tools.
|
|
2
|
+
|
|
3
|
+
Author: Putu Ravindra Wiguna (putu.r.wiguna@gdplabs.id)
|
|
4
|
+
|
|
5
|
+
Required environment variables:
|
|
6
|
+
- OPENAI_API_KEY
|
|
7
|
+
- E2B_API_KEY
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import asyncio
|
|
11
|
+
import json
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
from langchain_openai import ChatOpenAI
|
|
15
|
+
|
|
16
|
+
from aip_agents.agent import LangGraphReactAgent
|
|
17
|
+
from aip_agents.examples.tools.multiply_tool import MultiplyTool
|
|
18
|
+
from aip_agents.ptc import PromptConfig, PTCCustomToolConfig, PTCSandboxConfig, file_tool, package_tool
|
|
19
|
+
from aip_agents.tools.time_tool import TimeTool
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
async def main() -> None:
|
|
23
|
+
"""Run a hello-world PTC flow with custom tools."""
|
|
24
|
+
repo_root = Path.cwd()
|
|
25
|
+
multiply_tool_path = repo_root / "aip_agents/examples/tools/multiply_tool.py"
|
|
26
|
+
|
|
27
|
+
instruction = (
|
|
28
|
+
"You are a helpful assistant with access to execute_ptc_code. "
|
|
29
|
+
"Use execute_ptc_code to run Python and print output. "
|
|
30
|
+
"Custom tools are available under tools.custom (import with "
|
|
31
|
+
"'from tools.custom import <tool_name>')."
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
agent = LangGraphReactAgent(
|
|
35
|
+
name="ptc_custom_tools_hello_world",
|
|
36
|
+
instruction=instruction,
|
|
37
|
+
model=ChatOpenAI(model="gpt-5.2"),
|
|
38
|
+
tools=[TimeTool(), MultiplyTool()],
|
|
39
|
+
tool_configs={"multiply": {"offset": 20}},
|
|
40
|
+
ptc_config=PTCSandboxConfig(
|
|
41
|
+
enabled=True,
|
|
42
|
+
sandbox_timeout=180.0,
|
|
43
|
+
prompt=PromptConfig(mode="auto"),
|
|
44
|
+
custom_tools=PTCCustomToolConfig(
|
|
45
|
+
enabled=True,
|
|
46
|
+
bundle_roots=[str(repo_root)],
|
|
47
|
+
requirements=[],
|
|
48
|
+
tools=[
|
|
49
|
+
package_tool(
|
|
50
|
+
"time_tool",
|
|
51
|
+
import_path="aip_agents.tools.time_tool",
|
|
52
|
+
class_name="TimeTool",
|
|
53
|
+
),
|
|
54
|
+
file_tool(
|
|
55
|
+
"multiply",
|
|
56
|
+
file_path=str(multiply_tool_path),
|
|
57
|
+
class_name="MultiplyTool",
|
|
58
|
+
),
|
|
59
|
+
],
|
|
60
|
+
),
|
|
61
|
+
),
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
try:
|
|
65
|
+
# Pass tool config at runtime via metadata
|
|
66
|
+
# The multiply tool will use offset=10, so multiply(a=6, b=7) returns 6*7+10=52
|
|
67
|
+
print("execute_ptc_code output: ", end="")
|
|
68
|
+
last_chunk = None
|
|
69
|
+
async for chunk in agent.arun_sse_stream(
|
|
70
|
+
query=("Use execute_ptc_code to import from tools.custom. Print time_tool() and multiply(a=6, b=7)."),
|
|
71
|
+
metadata={"tool_configs": {"multiply": {"offset": 10}}},
|
|
72
|
+
):
|
|
73
|
+
last_chunk = chunk
|
|
74
|
+
print(json.dumps(chunk))
|
|
75
|
+
print("-" * 20)
|
|
76
|
+
finally:
|
|
77
|
+
await agent.cleanup()
|
|
78
|
+
|
|
79
|
+
print("execute_ptc_code output: ", last_chunk["content"])
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
if __name__ == "__main__":
|
|
83
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
from aip_agents.agent import LangGraphReactAgent as LangGraphReactAgent
|
|
2
|
+
from aip_agents.examples.tools.multiply_tool import MultiplyTool as MultiplyTool
|
|
3
|
+
from aip_agents.ptc import PTCCustomToolConfig as PTCCustomToolConfig, PTCSandboxConfig as PTCSandboxConfig, PromptConfig as PromptConfig, file_tool as file_tool, package_tool as package_tool
|
|
4
|
+
from aip_agents.tools.time_tool import TimeTool as TimeTool
|
|
5
|
+
|
|
6
|
+
async def main() -> None:
|
|
7
|
+
"""Run a hello-world PTC flow with custom tools."""
|
|
@@ -39,6 +39,15 @@ async def main():
|
|
|
39
39
|
print(chunk["content"], end="", flush=True)
|
|
40
40
|
if chunk.get("metadata"):
|
|
41
41
|
print(f"\nMetadata: {chunk['metadata']}", end="\n\n", flush=True)
|
|
42
|
+
tool_info = chunk.get("metadata", {}).get("tool_info") if isinstance(chunk.get("metadata"), dict) else None
|
|
43
|
+
if isinstance(tool_info, dict):
|
|
44
|
+
for tool_call in tool_info.get("tool_calls", []):
|
|
45
|
+
if tool_call.get("name") == "data_visualizer":
|
|
46
|
+
data_source = tool_call.get("args", {}).get("data_source")
|
|
47
|
+
if not (isinstance(data_source, str) and data_source.startswith("$tool_output.")):
|
|
48
|
+
raise RuntimeError(
|
|
49
|
+
"Tool output sharing failed: expected data_source to reference $tool_output.<call_id>."
|
|
50
|
+
)
|
|
42
51
|
print("\n")
|
|
43
52
|
|
|
44
53
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""Tool to multiply two integers.
|
|
2
|
+
|
|
3
|
+
Author: Putu Ravindra Wiguna (putu.r.wiguna@gdplabs.id)
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from langchain_core.tools import BaseTool
|
|
7
|
+
from pydantic import BaseModel, Field
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class MultiplyToolInput(BaseModel):
|
|
11
|
+
"""Input schema for the MultiplyTool."""
|
|
12
|
+
|
|
13
|
+
a: int = Field(..., description="First factor.")
|
|
14
|
+
b: int = Field(..., description="Second factor.")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class MultiplyToolConfig(BaseModel):
|
|
18
|
+
"""Configuration for MultiplyTool."""
|
|
19
|
+
|
|
20
|
+
offset: int = Field(default=0, description="Offset to add to the result.")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class MultiplyTool(BaseTool):
|
|
24
|
+
"""Tool to multiply two integers."""
|
|
25
|
+
|
|
26
|
+
name: str = "multiply"
|
|
27
|
+
description: str = "Multiply two integers."
|
|
28
|
+
args_schema: type[BaseModel] = MultiplyToolInput
|
|
29
|
+
tool_config_schema: type[BaseModel] = MultiplyToolConfig
|
|
30
|
+
|
|
31
|
+
def _run(self, a: int, b: int) -> int:
|
|
32
|
+
"""Return the product of two integers."""
|
|
33
|
+
offset = 0
|
|
34
|
+
if hasattr(self, "get_tool_config"):
|
|
35
|
+
config = self.get_tool_config()
|
|
36
|
+
if config:
|
|
37
|
+
offset = getattr(config, "offset", 0)
|
|
38
|
+
|
|
39
|
+
return a * b + offset
|
|
40
|
+
|
|
41
|
+
async def _arun(self, a: int, b: int) -> int:
|
|
42
|
+
"""Return the product of two integers asynchronously."""
|
|
43
|
+
return self._run(a=a, b=b)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from langchain_core.tools import BaseTool
|
|
2
|
+
from pydantic import BaseModel
|
|
3
|
+
|
|
4
|
+
class MultiplyToolInput(BaseModel):
|
|
5
|
+
"""Input schema for the MultiplyTool."""
|
|
6
|
+
a: int
|
|
7
|
+
b: int
|
|
8
|
+
|
|
9
|
+
class MultiplyToolConfig(BaseModel):
|
|
10
|
+
"""Configuration for MultiplyTool."""
|
|
11
|
+
offset: int
|
|
12
|
+
|
|
13
|
+
class MultiplyTool(BaseTool):
|
|
14
|
+
"""Tool to multiply two integers."""
|
|
15
|
+
name: str
|
|
16
|
+
description: str
|
|
17
|
+
args_schema: type[BaseModel]
|
|
18
|
+
tool_config_schema: type[BaseModel]
|
|
@@ -39,7 +39,7 @@ class GuardrailEngine(Protocol):
|
|
|
39
39
|
Returns:
|
|
40
40
|
GuardrailResult indicating if content is safe
|
|
41
41
|
"""
|
|
42
|
-
...
|
|
42
|
+
... # pragma: no cover
|
|
43
43
|
|
|
44
44
|
@abstractmethod
|
|
45
45
|
async def check_output(self, content: str) -> GuardrailResult:
|
|
@@ -51,12 +51,12 @@ class GuardrailEngine(Protocol):
|
|
|
51
51
|
Returns:
|
|
52
52
|
GuardrailResult indicating if content is safe
|
|
53
53
|
"""
|
|
54
|
-
...
|
|
54
|
+
... # pragma: no cover
|
|
55
55
|
|
|
56
56
|
@abstractmethod
|
|
57
57
|
def model_dump(self) -> dict:
|
|
58
58
|
"""Serialize engine configuration into a JSON-compatible dictionary."""
|
|
59
|
-
...
|
|
59
|
+
... # pragma: no cover
|
|
60
60
|
|
|
61
61
|
|
|
62
62
|
class BaseGuardrailEngine(ABC):
|
|
@@ -77,14 +77,14 @@ class BaseGuardrailEngine(ABC):
|
|
|
77
77
|
@abstractmethod
|
|
78
78
|
async def check_input(self, content: str) -> GuardrailResult:
|
|
79
79
|
"""Check user input content for safety violations."""
|
|
80
|
-
...
|
|
80
|
+
... # pragma: no cover
|
|
81
81
|
|
|
82
82
|
@abstractmethod
|
|
83
83
|
async def check_output(self, content: str) -> GuardrailResult:
|
|
84
84
|
"""Check AI output content for safety violations."""
|
|
85
|
-
...
|
|
85
|
+
... # pragma: no cover
|
|
86
86
|
|
|
87
87
|
@abstractmethod
|
|
88
88
|
def model_dump(self) -> dict:
|
|
89
89
|
"""Serialize engine configuration into a JSON-compatible dictionary."""
|
|
90
|
-
...
|
|
90
|
+
... # pragma: no cover
|
|
@@ -7,8 +7,44 @@ Authors:
|
|
|
7
7
|
Putu Ravindra Wiguna (putu.r.wiguna@gdplabs.id)
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from typing import TYPE_CHECKING, Any
|
|
13
|
+
|
|
10
14
|
from aip_agents.mcp.client.base_mcp_client import BaseMCPClient
|
|
11
|
-
|
|
12
|
-
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from aip_agents.mcp.client.google_adk.client import GoogleADKMCPClient
|
|
18
|
+
from aip_agents.mcp.client.langchain.client import LangchainMCPClient
|
|
13
19
|
|
|
14
20
|
__all__ = ["GoogleADKMCPClient", "LangchainMCPClient", "BaseMCPClient"]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def __getattr__(name: str) -> Any:
|
|
24
|
+
"""Lazy import of MCP client implementations.
|
|
25
|
+
|
|
26
|
+
This avoids importing heavy dependencies (Google ADK, Vertex AI, etc.)
|
|
27
|
+
when they are not needed.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
name: Attribute name to import.
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
The requested class.
|
|
34
|
+
|
|
35
|
+
Raises:
|
|
36
|
+
AttributeError: If attribute is not found.
|
|
37
|
+
"""
|
|
38
|
+
if name == "GoogleADKMCPClient":
|
|
39
|
+
from aip_agents.mcp.client.google_adk.client import (
|
|
40
|
+
GoogleADKMCPClient as _GoogleADKMCPClient,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
return _GoogleADKMCPClient
|
|
44
|
+
elif name == "LangchainMCPClient":
|
|
45
|
+
from aip_agents.mcp.client.langchain.client import (
|
|
46
|
+
LangchainMCPClient as _LangchainMCPClient,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
return _LangchainMCPClient
|
|
50
|
+
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
|
|
@@ -60,6 +60,9 @@ class MCPConnectionManager:
|
|
|
60
60
|
async def start(self) -> tuple[Any, Any]:
|
|
61
61
|
"""Start connection in background task.
|
|
62
62
|
|
|
63
|
+
For HTTP/SSE transports, establishes connection directly to avoid anyio context issues.
|
|
64
|
+
For stdio transport, uses background task to manage subprocess lifecycle.
|
|
65
|
+
|
|
63
66
|
Returns:
|
|
64
67
|
tuple[Any, Any]: Tuple of (read_stream, write_stream) for ClientSession
|
|
65
68
|
|
|
@@ -67,6 +70,17 @@ class MCPConnectionManager:
|
|
|
67
70
|
Exception: If connection establishment fails
|
|
68
71
|
"""
|
|
69
72
|
logger.debug(f"Starting connection manager for {self.server_name}")
|
|
73
|
+
|
|
74
|
+
# Determine transport type first
|
|
75
|
+
self.transport_type = self._get_transport_type()
|
|
76
|
+
|
|
77
|
+
# For HTTP/SSE: connect directly (no background task needed)
|
|
78
|
+
# This avoids anyio.BrokenResourceError when streams cross task boundaries
|
|
79
|
+
if self.transport_type in (TransportType.HTTP, TransportType.SSE):
|
|
80
|
+
await self._establish_connection()
|
|
81
|
+
return self._connection
|
|
82
|
+
|
|
83
|
+
# For stdio: use background task to manage subprocess
|
|
70
84
|
self._task = asyncio.create_task(self._connection_task())
|
|
71
85
|
await self._ready_event.wait()
|
|
72
86
|
|
|
@@ -78,6 +92,20 @@ class MCPConnectionManager:
|
|
|
78
92
|
async def stop(self) -> None:
|
|
79
93
|
"""Stop connection gracefully."""
|
|
80
94
|
logger.debug(f"Stopping connection manager for {self.server_name}")
|
|
95
|
+
|
|
96
|
+
# For HTTP/SSE (no background task), just close transport
|
|
97
|
+
if self.transport_type in (TransportType.HTTP, TransportType.SSE):
|
|
98
|
+
if self._transport:
|
|
99
|
+
try:
|
|
100
|
+
close_result = self._transport.close()
|
|
101
|
+
if inspect.isawaitable(close_result):
|
|
102
|
+
await close_result
|
|
103
|
+
except Exception as exc:
|
|
104
|
+
logger.warning(f"Failed to close transport cleanly for {self.server_name}: {exc}")
|
|
105
|
+
self._connection = None
|
|
106
|
+
return
|
|
107
|
+
|
|
108
|
+
# For stdio (with background task), wait for task to finish
|
|
81
109
|
if self._task and not self._task.done():
|
|
82
110
|
self._stop_event.set()
|
|
83
111
|
try:
|
|
@@ -94,6 +122,11 @@ class MCPConnectionManager:
|
|
|
94
122
|
Returns:
|
|
95
123
|
bool: True if connected, False otherwise
|
|
96
124
|
"""
|
|
125
|
+
# For HTTP/SSE (no background task), just check if connection exists
|
|
126
|
+
if self.transport_type in (TransportType.HTTP, TransportType.SSE):
|
|
127
|
+
return self._connection is not None
|
|
128
|
+
|
|
129
|
+
# For stdio (with background task), check task status too
|
|
97
130
|
return (
|
|
98
131
|
self._connection is not None
|
|
99
132
|
and self._task is not None
|
|
@@ -144,7 +177,9 @@ class MCPConnectionManager:
|
|
|
144
177
|
Raises:
|
|
145
178
|
ConnectionError: If all connection attempts fail
|
|
146
179
|
"""
|
|
147
|
-
|
|
180
|
+
# transport_type may already be set by start() for HTTP/SSE
|
|
181
|
+
if not self.transport_type:
|
|
182
|
+
self.transport_type = self._get_transport_type()
|
|
148
183
|
details = f"URL: {self.config.get('url', 'N/A')}, Command: {self.config.get('command', 'N/A')}"
|
|
149
184
|
logger.info(f"Establishing connection to {self.server_name} via {self.transport_type} ({details})")
|
|
150
185
|
|
|
@@ -31,6 +31,9 @@ class MCPConnectionManager:
|
|
|
31
31
|
async def start(self) -> tuple[Any, Any]:
|
|
32
32
|
"""Start connection in background task.
|
|
33
33
|
|
|
34
|
+
For HTTP/SSE transports, establishes connection directly to avoid anyio context issues.
|
|
35
|
+
For stdio transport, uses background task to manage subprocess lifecycle.
|
|
36
|
+
|
|
34
37
|
Returns:
|
|
35
38
|
tuple[Any, Any]: Tuple of (read_stream, write_stream) for ClientSession
|
|
36
39
|
|