agno 2.0.0rc2__py3-none-any.whl → 2.3.0__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.
- agno/agent/agent.py +6009 -2874
- agno/api/api.py +2 -0
- agno/api/os.py +1 -1
- agno/culture/__init__.py +3 -0
- agno/culture/manager.py +956 -0
- agno/db/async_postgres/__init__.py +3 -0
- agno/db/base.py +385 -6
- agno/db/dynamo/dynamo.py +388 -81
- agno/db/dynamo/schemas.py +47 -10
- agno/db/dynamo/utils.py +63 -4
- agno/db/firestore/firestore.py +435 -64
- agno/db/firestore/schemas.py +11 -0
- agno/db/firestore/utils.py +102 -4
- agno/db/gcs_json/gcs_json_db.py +384 -42
- agno/db/gcs_json/utils.py +60 -26
- agno/db/in_memory/in_memory_db.py +351 -66
- agno/db/in_memory/utils.py +60 -2
- agno/db/json/json_db.py +339 -48
- agno/db/json/utils.py +60 -26
- agno/db/migrations/manager.py +199 -0
- agno/db/migrations/v1_to_v2.py +510 -37
- agno/db/migrations/versions/__init__.py +0 -0
- agno/db/migrations/versions/v2_3_0.py +938 -0
- agno/db/mongo/__init__.py +15 -1
- agno/db/mongo/async_mongo.py +2036 -0
- agno/db/mongo/mongo.py +653 -76
- agno/db/mongo/schemas.py +13 -0
- agno/db/mongo/utils.py +80 -8
- agno/db/mysql/mysql.py +687 -25
- agno/db/mysql/schemas.py +61 -37
- agno/db/mysql/utils.py +60 -2
- agno/db/postgres/__init__.py +2 -1
- agno/db/postgres/async_postgres.py +2001 -0
- agno/db/postgres/postgres.py +676 -57
- agno/db/postgres/schemas.py +43 -18
- agno/db/postgres/utils.py +164 -2
- agno/db/redis/redis.py +344 -38
- agno/db/redis/schemas.py +18 -0
- agno/db/redis/utils.py +60 -2
- agno/db/schemas/__init__.py +2 -1
- agno/db/schemas/culture.py +120 -0
- agno/db/schemas/memory.py +13 -0
- agno/db/singlestore/schemas.py +26 -1
- agno/db/singlestore/singlestore.py +687 -53
- agno/db/singlestore/utils.py +60 -2
- agno/db/sqlite/__init__.py +2 -1
- agno/db/sqlite/async_sqlite.py +2371 -0
- agno/db/sqlite/schemas.py +24 -0
- agno/db/sqlite/sqlite.py +774 -85
- agno/db/sqlite/utils.py +168 -5
- agno/db/surrealdb/__init__.py +3 -0
- agno/db/surrealdb/metrics.py +292 -0
- agno/db/surrealdb/models.py +309 -0
- agno/db/surrealdb/queries.py +71 -0
- agno/db/surrealdb/surrealdb.py +1361 -0
- agno/db/surrealdb/utils.py +147 -0
- agno/db/utils.py +50 -22
- agno/eval/accuracy.py +50 -43
- agno/eval/performance.py +6 -3
- agno/eval/reliability.py +6 -3
- agno/eval/utils.py +33 -16
- agno/exceptions.py +68 -1
- agno/filters.py +354 -0
- agno/guardrails/__init__.py +6 -0
- agno/guardrails/base.py +19 -0
- agno/guardrails/openai.py +144 -0
- agno/guardrails/pii.py +94 -0
- agno/guardrails/prompt_injection.py +52 -0
- agno/integrations/discord/client.py +1 -0
- agno/knowledge/chunking/agentic.py +13 -10
- agno/knowledge/chunking/fixed.py +1 -1
- agno/knowledge/chunking/semantic.py +40 -8
- agno/knowledge/chunking/strategy.py +59 -15
- agno/knowledge/embedder/aws_bedrock.py +9 -4
- agno/knowledge/embedder/azure_openai.py +54 -0
- agno/knowledge/embedder/base.py +2 -0
- agno/knowledge/embedder/cohere.py +184 -5
- agno/knowledge/embedder/fastembed.py +1 -1
- agno/knowledge/embedder/google.py +79 -1
- agno/knowledge/embedder/huggingface.py +9 -4
- agno/knowledge/embedder/jina.py +63 -0
- agno/knowledge/embedder/mistral.py +78 -11
- agno/knowledge/embedder/nebius.py +1 -1
- agno/knowledge/embedder/ollama.py +13 -0
- agno/knowledge/embedder/openai.py +37 -65
- agno/knowledge/embedder/sentence_transformer.py +8 -4
- agno/knowledge/embedder/vllm.py +262 -0
- agno/knowledge/embedder/voyageai.py +69 -16
- agno/knowledge/knowledge.py +595 -187
- agno/knowledge/reader/base.py +9 -2
- agno/knowledge/reader/csv_reader.py +8 -10
- agno/knowledge/reader/docx_reader.py +5 -6
- agno/knowledge/reader/field_labeled_csv_reader.py +290 -0
- agno/knowledge/reader/json_reader.py +6 -5
- agno/knowledge/reader/markdown_reader.py +13 -13
- agno/knowledge/reader/pdf_reader.py +43 -68
- agno/knowledge/reader/pptx_reader.py +101 -0
- agno/knowledge/reader/reader_factory.py +51 -6
- agno/knowledge/reader/s3_reader.py +3 -15
- agno/knowledge/reader/tavily_reader.py +194 -0
- agno/knowledge/reader/text_reader.py +13 -13
- agno/knowledge/reader/web_search_reader.py +2 -43
- agno/knowledge/reader/website_reader.py +43 -25
- agno/knowledge/reranker/__init__.py +3 -0
- agno/knowledge/types.py +9 -0
- agno/knowledge/utils.py +20 -0
- agno/media.py +339 -266
- agno/memory/manager.py +336 -82
- agno/models/aimlapi/aimlapi.py +2 -2
- agno/models/anthropic/claude.py +183 -37
- agno/models/aws/bedrock.py +52 -112
- agno/models/aws/claude.py +33 -1
- agno/models/azure/ai_foundry.py +33 -15
- agno/models/azure/openai_chat.py +25 -8
- agno/models/base.py +1011 -566
- agno/models/cerebras/cerebras.py +19 -13
- agno/models/cerebras/cerebras_openai.py +8 -5
- agno/models/cohere/chat.py +27 -1
- agno/models/cometapi/__init__.py +5 -0
- agno/models/cometapi/cometapi.py +57 -0
- agno/models/dashscope/dashscope.py +1 -0
- agno/models/deepinfra/deepinfra.py +2 -2
- agno/models/deepseek/deepseek.py +2 -2
- agno/models/fireworks/fireworks.py +2 -2
- agno/models/google/gemini.py +110 -37
- agno/models/groq/groq.py +28 -11
- agno/models/huggingface/huggingface.py +2 -1
- agno/models/internlm/internlm.py +2 -2
- agno/models/langdb/langdb.py +4 -4
- agno/models/litellm/chat.py +18 -1
- agno/models/litellm/litellm_openai.py +2 -2
- agno/models/llama_cpp/__init__.py +5 -0
- agno/models/llama_cpp/llama_cpp.py +22 -0
- agno/models/message.py +143 -4
- agno/models/meta/llama.py +27 -10
- agno/models/meta/llama_openai.py +5 -17
- agno/models/nebius/nebius.py +6 -6
- agno/models/nexus/__init__.py +3 -0
- agno/models/nexus/nexus.py +22 -0
- agno/models/nvidia/nvidia.py +2 -2
- agno/models/ollama/chat.py +60 -6
- agno/models/openai/chat.py +102 -43
- agno/models/openai/responses.py +103 -106
- agno/models/openrouter/openrouter.py +41 -3
- agno/models/perplexity/perplexity.py +4 -5
- agno/models/portkey/portkey.py +3 -3
- agno/models/requesty/__init__.py +5 -0
- agno/models/requesty/requesty.py +52 -0
- agno/models/response.py +81 -5
- agno/models/sambanova/sambanova.py +2 -2
- agno/models/siliconflow/__init__.py +5 -0
- agno/models/siliconflow/siliconflow.py +25 -0
- agno/models/together/together.py +2 -2
- agno/models/utils.py +254 -8
- agno/models/vercel/v0.py +2 -2
- agno/models/vertexai/__init__.py +0 -0
- agno/models/vertexai/claude.py +96 -0
- agno/models/vllm/vllm.py +1 -0
- agno/models/xai/xai.py +3 -2
- agno/os/app.py +543 -175
- agno/os/auth.py +24 -14
- agno/os/config.py +1 -0
- agno/os/interfaces/__init__.py +1 -0
- agno/os/interfaces/a2a/__init__.py +3 -0
- agno/os/interfaces/a2a/a2a.py +42 -0
- agno/os/interfaces/a2a/router.py +250 -0
- agno/os/interfaces/a2a/utils.py +924 -0
- agno/os/interfaces/agui/agui.py +23 -7
- agno/os/interfaces/agui/router.py +27 -3
- agno/os/interfaces/agui/utils.py +242 -142
- agno/os/interfaces/base.py +6 -2
- agno/os/interfaces/slack/router.py +81 -23
- agno/os/interfaces/slack/slack.py +29 -14
- agno/os/interfaces/whatsapp/router.py +11 -4
- agno/os/interfaces/whatsapp/whatsapp.py +14 -7
- agno/os/mcp.py +111 -54
- agno/os/middleware/__init__.py +7 -0
- agno/os/middleware/jwt.py +233 -0
- agno/os/router.py +556 -139
- agno/os/routers/evals/evals.py +71 -34
- agno/os/routers/evals/schemas.py +31 -31
- agno/os/routers/evals/utils.py +6 -5
- agno/os/routers/health.py +31 -0
- agno/os/routers/home.py +52 -0
- agno/os/routers/knowledge/knowledge.py +185 -38
- agno/os/routers/knowledge/schemas.py +82 -22
- agno/os/routers/memory/memory.py +158 -53
- agno/os/routers/memory/schemas.py +20 -16
- agno/os/routers/metrics/metrics.py +20 -8
- agno/os/routers/metrics/schemas.py +16 -16
- agno/os/routers/session/session.py +499 -38
- agno/os/schema.py +308 -198
- agno/os/utils.py +401 -41
- agno/reasoning/anthropic.py +80 -0
- agno/reasoning/azure_ai_foundry.py +2 -2
- agno/reasoning/deepseek.py +2 -2
- agno/reasoning/default.py +3 -1
- agno/reasoning/gemini.py +73 -0
- agno/reasoning/groq.py +2 -2
- agno/reasoning/ollama.py +2 -2
- agno/reasoning/openai.py +7 -2
- agno/reasoning/vertexai.py +76 -0
- agno/run/__init__.py +6 -0
- agno/run/agent.py +266 -112
- agno/run/base.py +53 -24
- agno/run/team.py +252 -111
- agno/run/workflow.py +156 -45
- agno/session/agent.py +105 -89
- agno/session/summary.py +65 -25
- agno/session/team.py +176 -96
- agno/session/workflow.py +406 -40
- agno/team/team.py +3854 -1692
- agno/tools/brightdata.py +3 -3
- agno/tools/cartesia.py +3 -5
- agno/tools/dalle.py +9 -8
- agno/tools/decorator.py +4 -2
- agno/tools/desi_vocal.py +2 -2
- agno/tools/duckduckgo.py +15 -11
- agno/tools/e2b.py +20 -13
- agno/tools/eleven_labs.py +26 -28
- agno/tools/exa.py +21 -16
- agno/tools/fal.py +4 -4
- agno/tools/file.py +153 -23
- agno/tools/file_generation.py +350 -0
- agno/tools/firecrawl.py +4 -4
- agno/tools/function.py +257 -37
- agno/tools/giphy.py +2 -2
- agno/tools/gmail.py +238 -14
- agno/tools/google_drive.py +270 -0
- agno/tools/googlecalendar.py +36 -8
- agno/tools/googlesheets.py +20 -5
- agno/tools/jira.py +20 -0
- agno/tools/knowledge.py +3 -3
- agno/tools/lumalab.py +3 -3
- agno/tools/mcp/__init__.py +10 -0
- agno/tools/mcp/mcp.py +331 -0
- agno/tools/mcp/multi_mcp.py +347 -0
- agno/tools/mcp/params.py +24 -0
- agno/tools/mcp_toolbox.py +284 -0
- agno/tools/mem0.py +11 -17
- agno/tools/memori.py +1 -53
- agno/tools/memory.py +419 -0
- agno/tools/models/azure_openai.py +2 -2
- agno/tools/models/gemini.py +3 -3
- agno/tools/models/groq.py +3 -5
- agno/tools/models/nebius.py +7 -7
- agno/tools/models_labs.py +25 -15
- agno/tools/notion.py +204 -0
- agno/tools/openai.py +4 -9
- agno/tools/opencv.py +3 -3
- agno/tools/parallel.py +314 -0
- agno/tools/replicate.py +7 -7
- agno/tools/scrapegraph.py +58 -31
- agno/tools/searxng.py +2 -2
- agno/tools/serper.py +2 -2
- agno/tools/slack.py +18 -3
- agno/tools/spider.py +2 -2
- agno/tools/tavily.py +146 -0
- agno/tools/whatsapp.py +1 -1
- agno/tools/workflow.py +278 -0
- agno/tools/yfinance.py +12 -11
- agno/utils/agent.py +820 -0
- agno/utils/audio.py +27 -0
- agno/utils/common.py +90 -1
- agno/utils/events.py +222 -7
- agno/utils/gemini.py +181 -23
- agno/utils/hooks.py +57 -0
- agno/utils/http.py +111 -0
- agno/utils/knowledge.py +12 -5
- agno/utils/log.py +1 -0
- agno/utils/mcp.py +95 -5
- agno/utils/media.py +188 -10
- agno/utils/merge_dict.py +22 -1
- agno/utils/message.py +60 -0
- agno/utils/models/claude.py +40 -11
- agno/utils/models/cohere.py +1 -1
- agno/utils/models/watsonx.py +1 -1
- agno/utils/openai.py +1 -1
- agno/utils/print_response/agent.py +105 -21
- agno/utils/print_response/team.py +103 -38
- agno/utils/print_response/workflow.py +251 -34
- agno/utils/reasoning.py +22 -1
- agno/utils/serialize.py +32 -0
- agno/utils/streamlit.py +16 -10
- agno/utils/string.py +41 -0
- agno/utils/team.py +98 -9
- agno/utils/tools.py +1 -1
- agno/vectordb/base.py +23 -4
- agno/vectordb/cassandra/cassandra.py +65 -9
- agno/vectordb/chroma/chromadb.py +182 -38
- agno/vectordb/clickhouse/clickhousedb.py +64 -11
- agno/vectordb/couchbase/couchbase.py +105 -10
- agno/vectordb/lancedb/lance_db.py +183 -135
- agno/vectordb/langchaindb/langchaindb.py +25 -7
- agno/vectordb/lightrag/lightrag.py +17 -3
- agno/vectordb/llamaindex/__init__.py +3 -0
- agno/vectordb/llamaindex/llamaindexdb.py +46 -7
- agno/vectordb/milvus/milvus.py +126 -9
- agno/vectordb/mongodb/__init__.py +7 -1
- agno/vectordb/mongodb/mongodb.py +112 -7
- agno/vectordb/pgvector/pgvector.py +142 -21
- agno/vectordb/pineconedb/pineconedb.py +80 -8
- agno/vectordb/qdrant/qdrant.py +125 -39
- agno/vectordb/redis/__init__.py +9 -0
- agno/vectordb/redis/redisdb.py +694 -0
- agno/vectordb/singlestore/singlestore.py +111 -25
- agno/vectordb/surrealdb/surrealdb.py +31 -5
- agno/vectordb/upstashdb/upstashdb.py +76 -8
- agno/vectordb/weaviate/weaviate.py +86 -15
- agno/workflow/__init__.py +2 -0
- agno/workflow/agent.py +299 -0
- agno/workflow/condition.py +112 -18
- agno/workflow/loop.py +69 -10
- agno/workflow/parallel.py +266 -118
- agno/workflow/router.py +110 -17
- agno/workflow/step.py +645 -136
- agno/workflow/steps.py +65 -6
- agno/workflow/types.py +71 -33
- agno/workflow/workflow.py +2113 -300
- agno-2.3.0.dist-info/METADATA +618 -0
- agno-2.3.0.dist-info/RECORD +577 -0
- agno-2.3.0.dist-info/licenses/LICENSE +201 -0
- agno/knowledge/reader/url_reader.py +0 -128
- agno/tools/googlesearch.py +0 -98
- agno/tools/mcp.py +0 -610
- agno/utils/models/aws_claude.py +0 -170
- agno-2.0.0rc2.dist-info/METADATA +0 -355
- agno-2.0.0rc2.dist-info/RECORD +0 -515
- agno-2.0.0rc2.dist-info/licenses/LICENSE +0 -375
- {agno-2.0.0rc2.dist-info → agno-2.3.0.dist-info}/WHEEL +0 -0
- {agno-2.0.0rc2.dist-info → agno-2.3.0.dist-info}/top_level.txt +0 -0
agno/tools/mcp.py
DELETED
|
@@ -1,610 +0,0 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
import weakref
|
|
3
|
-
from contextlib import AsyncExitStack
|
|
4
|
-
from dataclasses import asdict, dataclass
|
|
5
|
-
from datetime import timedelta
|
|
6
|
-
from types import TracebackType
|
|
7
|
-
from typing import Any, Dict, List, Literal, Optional, Union
|
|
8
|
-
|
|
9
|
-
from agno.tools import Toolkit
|
|
10
|
-
from agno.tools.function import Function
|
|
11
|
-
from agno.utils.log import log_debug, log_info, log_warning, logger
|
|
12
|
-
from agno.utils.mcp import get_entrypoint_for_tool
|
|
13
|
-
|
|
14
|
-
try:
|
|
15
|
-
from mcp import ClientSession, StdioServerParameters
|
|
16
|
-
from mcp.client.sse import sse_client
|
|
17
|
-
from mcp.client.stdio import get_default_environment, stdio_client
|
|
18
|
-
from mcp.client.streamable_http import streamablehttp_client
|
|
19
|
-
except (ImportError, ModuleNotFoundError):
|
|
20
|
-
raise ImportError("`mcp` not installed. Please install using `pip install mcp`")
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def _prepare_command(command: str) -> list[str]:
|
|
24
|
-
"""Sanitize a command and split it into parts before using it to run a MCP server."""
|
|
25
|
-
from shlex import split
|
|
26
|
-
|
|
27
|
-
# Block dangerous characters
|
|
28
|
-
if any(char in command for char in ["&", "|", ";", "`", "$", "(", ")"]):
|
|
29
|
-
raise ValueError("MCP command can't contain shell metacharacters")
|
|
30
|
-
|
|
31
|
-
parts = split(command)
|
|
32
|
-
if not parts:
|
|
33
|
-
raise ValueError("MCP command can't be empty")
|
|
34
|
-
|
|
35
|
-
# Only allow specific executables
|
|
36
|
-
ALLOWED_COMMANDS = {
|
|
37
|
-
# Python
|
|
38
|
-
"python",
|
|
39
|
-
"python3",
|
|
40
|
-
"uv",
|
|
41
|
-
"uvx",
|
|
42
|
-
"pipx",
|
|
43
|
-
# Node
|
|
44
|
-
"node",
|
|
45
|
-
"npm",
|
|
46
|
-
"npx",
|
|
47
|
-
"yarn",
|
|
48
|
-
"pnpm",
|
|
49
|
-
"bun",
|
|
50
|
-
# Other runtimes
|
|
51
|
-
"deno",
|
|
52
|
-
"java",
|
|
53
|
-
"ruby",
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
executable = parts[0].split("/")[-1]
|
|
57
|
-
if executable not in ALLOWED_COMMANDS:
|
|
58
|
-
raise ValueError(f"MCP command needs to use one of the following executables: {ALLOWED_COMMANDS}")
|
|
59
|
-
|
|
60
|
-
return parts
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
@dataclass
|
|
64
|
-
class SSEClientParams:
|
|
65
|
-
"""Parameters for SSE client connection."""
|
|
66
|
-
|
|
67
|
-
url: str
|
|
68
|
-
headers: Optional[Dict[str, Any]] = None
|
|
69
|
-
timeout: Optional[float] = 5
|
|
70
|
-
sse_read_timeout: Optional[float] = 60 * 5
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
@dataclass
|
|
74
|
-
class StreamableHTTPClientParams:
|
|
75
|
-
"""Parameters for Streamable HTTP client connection."""
|
|
76
|
-
|
|
77
|
-
url: str
|
|
78
|
-
headers: Optional[Dict[str, Any]] = None
|
|
79
|
-
timeout: Optional[timedelta] = timedelta(seconds=30)
|
|
80
|
-
sse_read_timeout: Optional[timedelta] = timedelta(seconds=60 * 5)
|
|
81
|
-
terminate_on_close: Optional[bool] = None
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
class MCPTools(Toolkit):
|
|
85
|
-
"""
|
|
86
|
-
A toolkit for integrating Model Context Protocol (MCP) servers with Agno agents.
|
|
87
|
-
This allows agents to access tools, resources, and prompts exposed by MCP servers.
|
|
88
|
-
|
|
89
|
-
Can be used in three ways:
|
|
90
|
-
1. Direct initialization with a ClientSession
|
|
91
|
-
2. As an async context manager with StdioServerParameters
|
|
92
|
-
3. As an async context manager with SSE or Streamable HTTP client parameters
|
|
93
|
-
"""
|
|
94
|
-
|
|
95
|
-
def __init__(
|
|
96
|
-
self,
|
|
97
|
-
command: Optional[str] = None,
|
|
98
|
-
*,
|
|
99
|
-
url: Optional[str] = None,
|
|
100
|
-
env: Optional[dict[str, str]] = None,
|
|
101
|
-
transport: Literal["stdio", "sse", "streamable-http"] = "stdio",
|
|
102
|
-
server_params: Optional[Union[StdioServerParameters, SSEClientParams, StreamableHTTPClientParams]] = None,
|
|
103
|
-
session: Optional[ClientSession] = None,
|
|
104
|
-
timeout_seconds: int = 5,
|
|
105
|
-
client=None,
|
|
106
|
-
include_tools: Optional[list[str]] = None,
|
|
107
|
-
exclude_tools: Optional[list[str]] = None,
|
|
108
|
-
**kwargs,
|
|
109
|
-
):
|
|
110
|
-
"""
|
|
111
|
-
Initialize the MCP toolkit.
|
|
112
|
-
|
|
113
|
-
Args:
|
|
114
|
-
session: An initialized MCP ClientSession connected to an MCP server
|
|
115
|
-
server_params: Parameters for creating a new session
|
|
116
|
-
command: The command to run to start the server. Should be used in conjunction with env.
|
|
117
|
-
url: The URL endpoint for SSE or Streamable HTTP connection when transport is "sse" or "streamable-http".
|
|
118
|
-
env: The environment variables to pass to the server. Should be used in conjunction with command.
|
|
119
|
-
client: The underlying MCP client (optional, used to prevent garbage collection)
|
|
120
|
-
timeout_seconds: Read timeout in seconds for the MCP client
|
|
121
|
-
include_tools: Optional list of tool names to include (if None, includes all)
|
|
122
|
-
exclude_tools: Optional list of tool names to exclude (if None, excludes none)
|
|
123
|
-
transport: The transport protocol to use, either "stdio" or "sse" or "streamable-http"
|
|
124
|
-
"""
|
|
125
|
-
super().__init__(name="MCPTools", **kwargs)
|
|
126
|
-
|
|
127
|
-
if transport == "sse":
|
|
128
|
-
log_info("SSE as a standalone transport is deprecated. Please use Streamable HTTP instead.")
|
|
129
|
-
|
|
130
|
-
# Set these after `__init__` to bypass the `_check_tools_filters`
|
|
131
|
-
# because tools are not available until `initialize()` is called.
|
|
132
|
-
self.include_tools = include_tools
|
|
133
|
-
self.exclude_tools = exclude_tools
|
|
134
|
-
|
|
135
|
-
if session is None and server_params is None:
|
|
136
|
-
if transport == "sse" and url is None:
|
|
137
|
-
raise ValueError("One of 'url' or 'server_params' parameters must be provided when using SSE transport")
|
|
138
|
-
if transport == "stdio" and command is None:
|
|
139
|
-
raise ValueError(
|
|
140
|
-
"One of 'command' or 'server_params' parameters must be provided when using stdio transport"
|
|
141
|
-
)
|
|
142
|
-
if transport == "streamable-http" and url is None:
|
|
143
|
-
raise ValueError(
|
|
144
|
-
"One of 'url' or 'server_params' parameters must be provided when using Streamable HTTP transport"
|
|
145
|
-
)
|
|
146
|
-
|
|
147
|
-
# Ensure the received server_params are valid for the given transport
|
|
148
|
-
if server_params is not None:
|
|
149
|
-
if transport == "sse":
|
|
150
|
-
if not isinstance(server_params, SSEClientParams):
|
|
151
|
-
raise ValueError(
|
|
152
|
-
"If using the SSE transport, server_params must be an instance of SSEClientParams."
|
|
153
|
-
)
|
|
154
|
-
elif transport == "stdio":
|
|
155
|
-
if not isinstance(server_params, StdioServerParameters):
|
|
156
|
-
raise ValueError(
|
|
157
|
-
"If using the stdio transport, server_params must be an instance of StdioServerParameters."
|
|
158
|
-
)
|
|
159
|
-
elif transport == "streamable-http":
|
|
160
|
-
if not isinstance(server_params, StreamableHTTPClientParams):
|
|
161
|
-
raise ValueError(
|
|
162
|
-
"If using the streamable-http transport, server_params must be an instance of StreamableHTTPClientParams."
|
|
163
|
-
)
|
|
164
|
-
|
|
165
|
-
self.timeout_seconds = timeout_seconds
|
|
166
|
-
self.session: Optional[ClientSession] = session
|
|
167
|
-
self.server_params: Optional[Union[StdioServerParameters, SSEClientParams, StreamableHTTPClientParams]] = (
|
|
168
|
-
server_params
|
|
169
|
-
)
|
|
170
|
-
self.transport = transport
|
|
171
|
-
self.url = url
|
|
172
|
-
|
|
173
|
-
# Merge provided env with system env
|
|
174
|
-
if env is not None:
|
|
175
|
-
env = {
|
|
176
|
-
**get_default_environment(),
|
|
177
|
-
**env,
|
|
178
|
-
}
|
|
179
|
-
else:
|
|
180
|
-
env = get_default_environment()
|
|
181
|
-
|
|
182
|
-
if command is not None and transport not in ["sse", "streamable-http"]:
|
|
183
|
-
parts = _prepare_command(command)
|
|
184
|
-
cmd = parts[0]
|
|
185
|
-
arguments = parts[1:] if len(parts) > 1 else []
|
|
186
|
-
self.server_params = StdioServerParameters(command=cmd, args=arguments, env=env)
|
|
187
|
-
|
|
188
|
-
self._client = client
|
|
189
|
-
self._context = None
|
|
190
|
-
self._session_context = None
|
|
191
|
-
self._initialized = False
|
|
192
|
-
self._connection_task = None
|
|
193
|
-
|
|
194
|
-
def cleanup():
|
|
195
|
-
"""Cancel active connections"""
|
|
196
|
-
if self._connection_task and not self._connection_task.done():
|
|
197
|
-
self._connection_task.cancel()
|
|
198
|
-
|
|
199
|
-
# Setup cleanup logic before the instance is garbage collected
|
|
200
|
-
self._cleanup_finalizer = weakref.finalize(self, cleanup)
|
|
201
|
-
|
|
202
|
-
async def connect(self):
|
|
203
|
-
"""Initialize a MCPTools instance and connect to the contextual MCP server"""
|
|
204
|
-
if self._initialized:
|
|
205
|
-
return
|
|
206
|
-
|
|
207
|
-
await self._connect()
|
|
208
|
-
|
|
209
|
-
def _start_connection(self):
|
|
210
|
-
"""Ensure there are no active connections and setup a new one"""
|
|
211
|
-
if self._connection_task is None or self._connection_task.done():
|
|
212
|
-
self._connection_task = asyncio.create_task(self._connect()) # type: ignore
|
|
213
|
-
|
|
214
|
-
async def _connect(self) -> None:
|
|
215
|
-
"""Connects to the MCP server and initializes the tools"""
|
|
216
|
-
if self._initialized:
|
|
217
|
-
return
|
|
218
|
-
|
|
219
|
-
if self.session is not None:
|
|
220
|
-
await self.initialize()
|
|
221
|
-
return
|
|
222
|
-
|
|
223
|
-
if not hasattr(self, "_active_contexts"):
|
|
224
|
-
self._active_contexts: list[Any] = []
|
|
225
|
-
|
|
226
|
-
# Create a new studio session
|
|
227
|
-
if self.transport == "sse":
|
|
228
|
-
sse_params = asdict(self.server_params) if self.server_params is not None else {} # type: ignore
|
|
229
|
-
if "url" not in sse_params:
|
|
230
|
-
sse_params["url"] = self.url
|
|
231
|
-
self._context = sse_client(**sse_params) # type: ignore
|
|
232
|
-
client_timeout = min(self.timeout_seconds, sse_params.get("timeout", self.timeout_seconds))
|
|
233
|
-
|
|
234
|
-
# Create a new streamable HTTP session
|
|
235
|
-
elif self.transport == "streamable-http":
|
|
236
|
-
streamable_http_params = asdict(self.server_params) if self.server_params is not None else {} # type: ignore
|
|
237
|
-
if "url" not in streamable_http_params:
|
|
238
|
-
streamable_http_params["url"] = self.url
|
|
239
|
-
self._context = streamablehttp_client(**streamable_http_params) # type: ignore
|
|
240
|
-
params_timeout = streamable_http_params.get("timeout", self.timeout_seconds)
|
|
241
|
-
if isinstance(params_timeout, timedelta):
|
|
242
|
-
params_timeout = int(params_timeout.total_seconds())
|
|
243
|
-
client_timeout = min(self.timeout_seconds, params_timeout)
|
|
244
|
-
|
|
245
|
-
else:
|
|
246
|
-
if self.server_params is None:
|
|
247
|
-
raise ValueError("server_params must be provided when using stdio transport.")
|
|
248
|
-
self._context = stdio_client(self.server_params) # type: ignore
|
|
249
|
-
client_timeout = self.timeout_seconds
|
|
250
|
-
|
|
251
|
-
session_params = await self._context.__aenter__() # type: ignore
|
|
252
|
-
self._active_contexts.append(self._context)
|
|
253
|
-
read, write = session_params[0:2]
|
|
254
|
-
|
|
255
|
-
self._session_context = ClientSession(read, write, read_timeout_seconds=timedelta(seconds=client_timeout)) # type: ignore
|
|
256
|
-
self.session = await self._session_context.__aenter__() # type: ignore
|
|
257
|
-
self._active_contexts.append(self._session_context)
|
|
258
|
-
|
|
259
|
-
# Initialize with the new session
|
|
260
|
-
await self.initialize()
|
|
261
|
-
|
|
262
|
-
async def close(self) -> None:
|
|
263
|
-
"""Close the MCP connection and clean up resources"""
|
|
264
|
-
if self._session_context is not None:
|
|
265
|
-
await self._session_context.__aexit__(None, None, None)
|
|
266
|
-
self.session = None
|
|
267
|
-
self._session_context = None
|
|
268
|
-
|
|
269
|
-
if self._context is not None:
|
|
270
|
-
await self._context.__aexit__(None, None, None)
|
|
271
|
-
self._context = None
|
|
272
|
-
|
|
273
|
-
self._initialized = False
|
|
274
|
-
|
|
275
|
-
async def __aenter__(self) -> "MCPTools":
|
|
276
|
-
await self._connect()
|
|
277
|
-
return self
|
|
278
|
-
|
|
279
|
-
async def __aexit__(self, _exc_type, _exc_val, _exc_tb):
|
|
280
|
-
"""Exit the async context manager."""
|
|
281
|
-
if self._session_context is not None:
|
|
282
|
-
await self._session_context.__aexit__(_exc_type, _exc_val, _exc_tb)
|
|
283
|
-
self.session = None
|
|
284
|
-
self._session_context = None
|
|
285
|
-
|
|
286
|
-
if self._context is not None:
|
|
287
|
-
await self._context.__aexit__(_exc_type, _exc_val, _exc_tb)
|
|
288
|
-
self._context = None
|
|
289
|
-
|
|
290
|
-
self._initialized = False
|
|
291
|
-
|
|
292
|
-
async def initialize(self) -> None:
|
|
293
|
-
"""Initialize the MCP toolkit by getting available tools from the MCP server"""
|
|
294
|
-
if self._initialized:
|
|
295
|
-
return
|
|
296
|
-
|
|
297
|
-
try:
|
|
298
|
-
if self.session is None:
|
|
299
|
-
raise ValueError("Failed to establish session connection")
|
|
300
|
-
|
|
301
|
-
# Initialize the session if not already initialized
|
|
302
|
-
await self.session.initialize()
|
|
303
|
-
|
|
304
|
-
# Get the list of tools from the MCP server
|
|
305
|
-
available_tools = await self.session.list_tools()
|
|
306
|
-
|
|
307
|
-
self._check_tools_filters(
|
|
308
|
-
available_tools=[tool.name for tool in available_tools.tools],
|
|
309
|
-
include_tools=self.include_tools,
|
|
310
|
-
exclude_tools=self.exclude_tools,
|
|
311
|
-
)
|
|
312
|
-
|
|
313
|
-
# Filter tools based on include/exclude lists
|
|
314
|
-
filtered_tools = []
|
|
315
|
-
for tool in available_tools.tools:
|
|
316
|
-
if self.exclude_tools and tool.name in self.exclude_tools:
|
|
317
|
-
continue
|
|
318
|
-
if self.include_tools is None or tool.name in self.include_tools:
|
|
319
|
-
filtered_tools.append(tool)
|
|
320
|
-
|
|
321
|
-
# Register the tools with the toolkit
|
|
322
|
-
for tool in filtered_tools:
|
|
323
|
-
try:
|
|
324
|
-
# Get an entrypoint for the tool
|
|
325
|
-
entrypoint = get_entrypoint_for_tool(tool, self.session)
|
|
326
|
-
# Create a Function for the tool
|
|
327
|
-
f = Function(
|
|
328
|
-
name=tool.name,
|
|
329
|
-
description=tool.description,
|
|
330
|
-
parameters=tool.inputSchema,
|
|
331
|
-
entrypoint=entrypoint,
|
|
332
|
-
# Set skip_entrypoint_processing to True to avoid processing the entrypoint
|
|
333
|
-
skip_entrypoint_processing=True,
|
|
334
|
-
)
|
|
335
|
-
|
|
336
|
-
# Register the Function with the toolkit
|
|
337
|
-
self.functions[f.name] = f
|
|
338
|
-
log_debug(f"Function: {f.name} registered with {self.name}")
|
|
339
|
-
except Exception as e:
|
|
340
|
-
logger.error(f"Failed to register tool {tool.name}: {e}")
|
|
341
|
-
|
|
342
|
-
log_debug(f"{self.name} initialized with {len(filtered_tools)} tools")
|
|
343
|
-
self._initialized = True
|
|
344
|
-
except Exception as e:
|
|
345
|
-
logger.error(f"Failed to get MCP tools: {e}")
|
|
346
|
-
raise
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
class MultiMCPTools(Toolkit):
|
|
350
|
-
"""
|
|
351
|
-
A toolkit for integrating multiple Model Context Protocol (MCP) servers with Agno agents.
|
|
352
|
-
This allows agents to access tools, resources, and prompts exposed by MCP servers.
|
|
353
|
-
|
|
354
|
-
Can be used in three ways:
|
|
355
|
-
1. Direct initialization with a ClientSession
|
|
356
|
-
2. As an async context manager with StdioServerParameters
|
|
357
|
-
3. As an async context manager with SSE or Streamable HTTP endpoints
|
|
358
|
-
"""
|
|
359
|
-
|
|
360
|
-
def __init__(
|
|
361
|
-
self,
|
|
362
|
-
commands: Optional[List[str]] = None,
|
|
363
|
-
urls: Optional[List[str]] = None,
|
|
364
|
-
urls_transports: Optional[List[Literal["sse", "streamable-http"]]] = None,
|
|
365
|
-
*,
|
|
366
|
-
env: Optional[dict[str, str]] = None,
|
|
367
|
-
server_params_list: Optional[
|
|
368
|
-
list[Union[SSEClientParams, StdioServerParameters, StreamableHTTPClientParams]]
|
|
369
|
-
] = None,
|
|
370
|
-
timeout_seconds: int = 5,
|
|
371
|
-
client=None,
|
|
372
|
-
include_tools: Optional[list[str]] = None,
|
|
373
|
-
exclude_tools: Optional[list[str]] = None,
|
|
374
|
-
**kwargs,
|
|
375
|
-
):
|
|
376
|
-
"""
|
|
377
|
-
Initialize the MCP toolkit.
|
|
378
|
-
|
|
379
|
-
Args:
|
|
380
|
-
commands: List of commands to run to start the servers. Should be used in conjunction with env.
|
|
381
|
-
urls: List of URLs for SSE and/or Streamable HTTP endpoints.
|
|
382
|
-
urls_transports: List of transports to use for the given URLs.
|
|
383
|
-
server_params_list: List of StdioServerParameters or SSEClientParams or StreamableHTTPClientParams for creating new sessions.
|
|
384
|
-
env: The environment variables to pass to the servers. Should be used in conjunction with commands.
|
|
385
|
-
client: The underlying MCP client (optional, used to prevent garbage collection).
|
|
386
|
-
timeout_seconds: Timeout in seconds for managing timeouts for Client Session if Agent or Tool doesn't respond.
|
|
387
|
-
include_tools: Optional list of tool names to include (if None, includes all).
|
|
388
|
-
exclude_tools: Optional list of tool names to exclude (if None, excludes none).
|
|
389
|
-
"""
|
|
390
|
-
super().__init__(name="MultiMCPTools", **kwargs)
|
|
391
|
-
|
|
392
|
-
if urls_transports is not None:
|
|
393
|
-
if "sse" in urls_transports:
|
|
394
|
-
log_info("SSE as a standalone transport is deprecated. Please use Streamable HTTP instead.")
|
|
395
|
-
|
|
396
|
-
if urls is not None:
|
|
397
|
-
if urls_transports is None:
|
|
398
|
-
log_warning(
|
|
399
|
-
"The default transport 'streamable-http' will be used. You can explicitly set the transports by providing the urls_transports parameter."
|
|
400
|
-
)
|
|
401
|
-
else:
|
|
402
|
-
if len(urls) != len(urls_transports):
|
|
403
|
-
raise ValueError("urls and urls_transports must be of the same length")
|
|
404
|
-
|
|
405
|
-
# Set these after `__init__` to bypass the `_check_tools_filters`
|
|
406
|
-
# beacuse tools are not available until `initialize()` is called.
|
|
407
|
-
self.include_tools = include_tools
|
|
408
|
-
self.exclude_tools = exclude_tools
|
|
409
|
-
|
|
410
|
-
if server_params_list is None and commands is None and urls is None:
|
|
411
|
-
raise ValueError("Either server_params_list or commands or urls must be provided")
|
|
412
|
-
|
|
413
|
-
self.server_params_list: List[Union[SSEClientParams, StdioServerParameters, StreamableHTTPClientParams]] = (
|
|
414
|
-
server_params_list or []
|
|
415
|
-
)
|
|
416
|
-
self.timeout_seconds = timeout_seconds
|
|
417
|
-
self.commands: Optional[List[str]] = commands
|
|
418
|
-
self.urls: Optional[List[str]] = urls
|
|
419
|
-
# Merge provided env with system env
|
|
420
|
-
if env is not None:
|
|
421
|
-
env = {
|
|
422
|
-
**get_default_environment(),
|
|
423
|
-
**env,
|
|
424
|
-
}
|
|
425
|
-
else:
|
|
426
|
-
env = get_default_environment()
|
|
427
|
-
|
|
428
|
-
if commands is not None:
|
|
429
|
-
for command in commands:
|
|
430
|
-
parts = _prepare_command(command)
|
|
431
|
-
cmd = parts[0]
|
|
432
|
-
arguments = parts[1:] if len(parts) > 1 else []
|
|
433
|
-
self.server_params_list.append(StdioServerParameters(command=cmd, args=arguments, env=env))
|
|
434
|
-
|
|
435
|
-
if urls is not None:
|
|
436
|
-
if urls_transports is not None:
|
|
437
|
-
for url, transport in zip(urls, urls_transports):
|
|
438
|
-
if transport == "streamable-http":
|
|
439
|
-
self.server_params_list.append(StreamableHTTPClientParams(url=url))
|
|
440
|
-
else:
|
|
441
|
-
self.server_params_list.append(SSEClientParams(url=url))
|
|
442
|
-
else:
|
|
443
|
-
for url in urls:
|
|
444
|
-
self.server_params_list.append(StreamableHTTPClientParams(url=url))
|
|
445
|
-
|
|
446
|
-
self._async_exit_stack = AsyncExitStack()
|
|
447
|
-
self._initialized = False
|
|
448
|
-
self._connection_task = None
|
|
449
|
-
self._active_contexts: list[Any] = []
|
|
450
|
-
self._used_as_context_manager = False
|
|
451
|
-
|
|
452
|
-
self._client = client
|
|
453
|
-
|
|
454
|
-
def cleanup():
|
|
455
|
-
"""Cancel active connections"""
|
|
456
|
-
if self._connection_task and not self._connection_task.done():
|
|
457
|
-
self._connection_task.cancel()
|
|
458
|
-
|
|
459
|
-
# Setup cleanup logic before the instance is garbage collected
|
|
460
|
-
self._cleanup_finalizer = weakref.finalize(self, cleanup)
|
|
461
|
-
|
|
462
|
-
async def connect(self):
|
|
463
|
-
"""Initialize a MultiMCPTools instance and connect to the MCP servers"""
|
|
464
|
-
if self._initialized:
|
|
465
|
-
return
|
|
466
|
-
|
|
467
|
-
await self._connect()
|
|
468
|
-
|
|
469
|
-
@classmethod
|
|
470
|
-
async def create_and_connect(
|
|
471
|
-
cls,
|
|
472
|
-
commands: Optional[List[str]] = None,
|
|
473
|
-
urls: Optional[List[str]] = None,
|
|
474
|
-
urls_transports: Optional[List[Literal["sse", "streamable-http"]]] = None,
|
|
475
|
-
*,
|
|
476
|
-
env: Optional[dict[str, str]] = None,
|
|
477
|
-
server_params_list: Optional[
|
|
478
|
-
List[Union[SSEClientParams, StdioServerParameters, StreamableHTTPClientParams]]
|
|
479
|
-
] = None,
|
|
480
|
-
timeout_seconds: int = 5,
|
|
481
|
-
client=None,
|
|
482
|
-
include_tools: Optional[list[str]] = None,
|
|
483
|
-
exclude_tools: Optional[list[str]] = None,
|
|
484
|
-
**kwargs,
|
|
485
|
-
) -> "MultiMCPTools":
|
|
486
|
-
"""Initialize a MultiMCPTools instance and connect to the MCP servers"""
|
|
487
|
-
instance = cls(
|
|
488
|
-
commands=commands,
|
|
489
|
-
urls=urls,
|
|
490
|
-
urls_transports=urls_transports,
|
|
491
|
-
env=env,
|
|
492
|
-
server_params_list=server_params_list,
|
|
493
|
-
timeout_seconds=timeout_seconds,
|
|
494
|
-
client=client,
|
|
495
|
-
include_tools=include_tools,
|
|
496
|
-
exclude_tools=exclude_tools,
|
|
497
|
-
**kwargs,
|
|
498
|
-
)
|
|
499
|
-
|
|
500
|
-
await instance._connect()
|
|
501
|
-
return instance
|
|
502
|
-
|
|
503
|
-
def _start_connection(self):
|
|
504
|
-
"""Ensure there are no active connections and setup a new one"""
|
|
505
|
-
if self._connection_task is None or self._connection_task.done():
|
|
506
|
-
self._connection_task = asyncio.create_task(self._connect()) # type: ignore
|
|
507
|
-
|
|
508
|
-
async def _connect(self) -> None:
|
|
509
|
-
"""Connects to the MCP servers and initializes the tools"""
|
|
510
|
-
if self._initialized:
|
|
511
|
-
return
|
|
512
|
-
|
|
513
|
-
for server_params in self.server_params_list:
|
|
514
|
-
# Handle stdio connections
|
|
515
|
-
if isinstance(server_params, StdioServerParameters):
|
|
516
|
-
stdio_transport = await self._async_exit_stack.enter_async_context(stdio_client(server_params))
|
|
517
|
-
self._active_contexts.append(stdio_transport)
|
|
518
|
-
read, write = stdio_transport
|
|
519
|
-
session = await self._async_exit_stack.enter_async_context(
|
|
520
|
-
ClientSession(read, write, read_timeout_seconds=timedelta(seconds=self.timeout_seconds))
|
|
521
|
-
)
|
|
522
|
-
self._active_contexts.append(session)
|
|
523
|
-
await self.initialize(session)
|
|
524
|
-
# Handle SSE connections
|
|
525
|
-
elif isinstance(server_params, SSEClientParams):
|
|
526
|
-
client_connection = await self._async_exit_stack.enter_async_context(
|
|
527
|
-
sse_client(**asdict(server_params))
|
|
528
|
-
)
|
|
529
|
-
self._active_contexts.append(client_connection)
|
|
530
|
-
read, write = client_connection
|
|
531
|
-
session = await self._async_exit_stack.enter_async_context(ClientSession(read, write))
|
|
532
|
-
self._active_contexts.append(session)
|
|
533
|
-
await self.initialize(session)
|
|
534
|
-
# Handle Streamable HTTP connections
|
|
535
|
-
elif isinstance(server_params, StreamableHTTPClientParams):
|
|
536
|
-
client_connection = await self._async_exit_stack.enter_async_context(
|
|
537
|
-
streamablehttp_client(**asdict(server_params))
|
|
538
|
-
)
|
|
539
|
-
self._active_contexts.append(client_connection)
|
|
540
|
-
read, write = client_connection[0:2]
|
|
541
|
-
session = await self._async_exit_stack.enter_async_context(ClientSession(read, write))
|
|
542
|
-
self._active_contexts.append(session)
|
|
543
|
-
await self.initialize(session)
|
|
544
|
-
|
|
545
|
-
self._initialized = True
|
|
546
|
-
|
|
547
|
-
async def close(self) -> None:
|
|
548
|
-
"""Close the MCP connections and clean up resources"""
|
|
549
|
-
await self._async_exit_stack.aclose()
|
|
550
|
-
self._initialized = False
|
|
551
|
-
|
|
552
|
-
async def __aenter__(self) -> "MultiMCPTools":
|
|
553
|
-
"""Enter the async context manager."""
|
|
554
|
-
await self._connect()
|
|
555
|
-
return self
|
|
556
|
-
|
|
557
|
-
async def __aexit__(
|
|
558
|
-
self,
|
|
559
|
-
exc_type: Union[type[BaseException], None],
|
|
560
|
-
exc_val: Union[BaseException, None],
|
|
561
|
-
exc_tb: Union[TracebackType, None],
|
|
562
|
-
):
|
|
563
|
-
"""Exit the async context manager."""
|
|
564
|
-
await self._async_exit_stack.aclose()
|
|
565
|
-
|
|
566
|
-
async def initialize(self, session: ClientSession) -> None:
|
|
567
|
-
"""Initialize the MCP toolkit by getting available tools from the MCP server"""
|
|
568
|
-
|
|
569
|
-
try:
|
|
570
|
-
# Initialize the session if not already initialized
|
|
571
|
-
await session.initialize()
|
|
572
|
-
|
|
573
|
-
# Get the list of tools from the MCP server
|
|
574
|
-
available_tools = await session.list_tools()
|
|
575
|
-
|
|
576
|
-
# Filter tools based on include/exclude lists
|
|
577
|
-
filtered_tools = []
|
|
578
|
-
for tool in available_tools.tools:
|
|
579
|
-
if self.exclude_tools and tool.name in self.exclude_tools:
|
|
580
|
-
continue
|
|
581
|
-
if self.include_tools is None or tool.name in self.include_tools:
|
|
582
|
-
filtered_tools.append(tool)
|
|
583
|
-
|
|
584
|
-
# Register the tools with the toolkit
|
|
585
|
-
for tool in filtered_tools:
|
|
586
|
-
try:
|
|
587
|
-
# Get an entrypoint for the tool
|
|
588
|
-
entrypoint = get_entrypoint_for_tool(tool, session)
|
|
589
|
-
|
|
590
|
-
# Create a Function for the tool
|
|
591
|
-
f = Function(
|
|
592
|
-
name=tool.name,
|
|
593
|
-
description=tool.description,
|
|
594
|
-
parameters=tool.inputSchema,
|
|
595
|
-
entrypoint=entrypoint,
|
|
596
|
-
# Set skip_entrypoint_processing to True to avoid processing the entrypoint
|
|
597
|
-
skip_entrypoint_processing=True,
|
|
598
|
-
)
|
|
599
|
-
|
|
600
|
-
# Register the Function with the toolkit
|
|
601
|
-
self.functions[f.name] = f
|
|
602
|
-
log_debug(f"Function: {f.name} registered with {self.name}")
|
|
603
|
-
except Exception as e:
|
|
604
|
-
logger.error(f"Failed to register tool {tool.name}: {e}")
|
|
605
|
-
|
|
606
|
-
log_debug(f"{self.name} initialized with {len(filtered_tools)} tools")
|
|
607
|
-
self._initialized = True
|
|
608
|
-
except Exception as e:
|
|
609
|
-
logger.error(f"Failed to get MCP tools: {e}")
|
|
610
|
-
raise
|