datarobot-genai 0.2.23__tar.gz → 0.2.25__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/PKG-INFO +1 -1
  2. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/pyproject.toml +1 -1
  3. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/dr_mcp_server.py +0 -3
  4. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/mcp_instance.py +3 -88
  5. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/tool_filter.py +10 -1
  6. datarobot_genai-0.2.25/src/datarobot_genai/drmcp/tools/predictive/project.py +90 -0
  7. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/tools/predictive/training.py +160 -151
  8. datarobot_genai-0.2.23/src/datarobot_genai/drmcp/core/mcp_server_tools.py +0 -129
  9. datarobot_genai-0.2.23/src/datarobot_genai/drmcp/tools/predictive/project.py +0 -72
  10. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/.gitignore +0 -0
  11. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/AUTHORS +0 -0
  12. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/LICENSE +0 -0
  13. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/README.md +0 -0
  14. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/__init__.py +0 -0
  15. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/core/__init__.py +0 -0
  16. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/core/agents/__init__.py +0 -0
  17. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/core/agents/base.py +0 -0
  18. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/core/chat/__init__.py +0 -0
  19. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/core/chat/auth.py +0 -0
  20. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/core/chat/client.py +0 -0
  21. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/core/chat/responses.py +0 -0
  22. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/core/cli/__init__.py +0 -0
  23. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/core/cli/agent_environment.py +0 -0
  24. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/core/cli/agent_kernel.py +0 -0
  25. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/core/custom_model.py +0 -0
  26. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/core/mcp/__init__.py +0 -0
  27. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/core/mcp/common.py +0 -0
  28. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/core/telemetry_agent.py +0 -0
  29. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/core/utils/__init__.py +0 -0
  30. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/core/utils/auth.py +0 -0
  31. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/core/utils/urls.py +0 -0
  32. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/crewai/__init__.py +0 -0
  33. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/crewai/agent.py +0 -0
  34. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/crewai/base.py +0 -0
  35. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/crewai/events.py +0 -0
  36. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/crewai/mcp.py +0 -0
  37. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/__init__.py +0 -0
  38. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/__init__.py +0 -0
  39. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/auth.py +0 -0
  40. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/clients.py +0 -0
  41. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/config.py +0 -0
  42. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/config_utils.py +0 -0
  43. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/constants.py +0 -0
  44. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/credentials.py +0 -0
  45. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/dr_mcp_server_logo.py +0 -0
  46. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/dynamic_prompts/__init__.py +0 -0
  47. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/dynamic_prompts/controllers.py +0 -0
  48. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/dynamic_prompts/dr_lib.py +0 -0
  49. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/dynamic_prompts/register.py +0 -0
  50. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/dynamic_prompts/utils.py +0 -0
  51. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/dynamic_tools/__init__.py +0 -0
  52. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/__init__.py +0 -0
  53. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/adapters/__init__.py +0 -0
  54. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/adapters/base.py +0 -0
  55. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/adapters/default.py +0 -0
  56. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/adapters/drum.py +0 -0
  57. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/config.py +0 -0
  58. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/controllers.py +0 -0
  59. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/metadata.py +0 -0
  60. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/register.py +0 -0
  61. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/schemas/drum_agentic_fallback_schema.json +0 -0
  62. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/schemas/drum_prediction_fallback_schema.json +0 -0
  63. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/dynamic_tools/register.py +0 -0
  64. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/dynamic_tools/schema.py +0 -0
  65. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/exceptions.py +0 -0
  66. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/logging.py +0 -0
  67. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/memory_management/__init__.py +0 -0
  68. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/memory_management/manager.py +0 -0
  69. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/memory_management/memory_tools.py +0 -0
  70. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/routes.py +0 -0
  71. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/routes_utils.py +0 -0
  72. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/server_life_cycle.py +0 -0
  73. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/telemetry.py +0 -0
  74. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/tool_config.py +0 -0
  75. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/core/utils.py +0 -0
  76. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/server.py +0 -0
  77. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/test_utils/__init__.py +0 -0
  78. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/test_utils/elicitation_test_tool.py +0 -0
  79. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/test_utils/integration_mcp_server.py +0 -0
  80. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/test_utils/mcp_utils_ete.py +0 -0
  81. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/test_utils/mcp_utils_integration.py +0 -0
  82. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/test_utils/openai_llm_mcp_client.py +0 -0
  83. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/test_utils/test_interactive.py +0 -0
  84. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/test_utils/tool_base_ete.py +0 -0
  85. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/test_utils/utils.py +0 -0
  86. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/tools/__init__.py +0 -0
  87. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/tools/clients/__init__.py +0 -0
  88. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/tools/clients/atlassian.py +0 -0
  89. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/tools/clients/confluence.py +0 -0
  90. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/tools/clients/gdrive.py +0 -0
  91. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/tools/clients/jira.py +0 -0
  92. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/tools/clients/s3.py +0 -0
  93. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/tools/confluence/__init__.py +0 -0
  94. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/tools/confluence/tools.py +0 -0
  95. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/tools/gdrive/__init__.py +0 -0
  96. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/tools/gdrive/tools.py +0 -0
  97. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/tools/jira/__init__.py +0 -0
  98. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/tools/jira/tools.py +0 -0
  99. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/tools/predictive/__init__.py +0 -0
  100. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/tools/predictive/data.py +0 -0
  101. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/tools/predictive/deployment.py +0 -0
  102. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/tools/predictive/deployment_info.py +0 -0
  103. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/tools/predictive/model.py +0 -0
  104. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/tools/predictive/predict.py +0 -0
  105. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/drmcp/tools/predictive/predict_realtime.py +0 -0
  106. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/langgraph/__init__.py +0 -0
  107. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/langgraph/agent.py +0 -0
  108. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/langgraph/mcp.py +0 -0
  109. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/llama_index/__init__.py +0 -0
  110. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/llama_index/agent.py +0 -0
  111. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/llama_index/base.py +0 -0
  112. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/llama_index/mcp.py +0 -0
  113. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/nat/__init__.py +0 -0
  114. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/nat/agent.py +0 -0
  115. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/nat/datarobot_auth_provider.py +0 -0
  116. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/nat/datarobot_llm_clients.py +0 -0
  117. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/nat/datarobot_llm_providers.py +0 -0
  118. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/nat/datarobot_mcp_client.py +0 -0
  119. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/nat/helpers.py +0 -0
  120. {datarobot_genai-0.2.23 → datarobot_genai-0.2.25}/src/datarobot_genai/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: datarobot-genai
3
- Version: 0.2.23
3
+ Version: 0.2.25
4
4
  Summary: Generic helpers for GenAI
5
5
  Project-URL: Homepage, https://github.com/datarobot-oss/datarobot-genai
6
6
  Author: DataRobot, Inc.
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "datarobot-genai"
7
- version = "0.2.23"
7
+ version = "0.2.25"
8
8
  description = "Generic helpers for GenAI"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10, <3.13"
@@ -31,9 +31,6 @@ from .dynamic_prompts.register import register_prompts_from_datarobot_prompt_man
31
31
  from .dynamic_tools.deployment.register import register_tools_of_datarobot_deployments
32
32
  from .logging import MCPLogging
33
33
  from .mcp_instance import mcp
34
- from .mcp_server_tools import get_all_available_tags # noqa # pylint: disable=unused-import
35
- from .mcp_server_tools import get_tool_info_by_name # noqa # pylint: disable=unused-import
36
- from .mcp_server_tools import list_tools_by_tags # noqa # pylint: disable=unused-import
37
34
  from .memory_management.manager import MemoryManager
38
35
  from .routes import register_routes
39
36
  from .routes_utils import prefix_mount_path
@@ -16,17 +16,13 @@ import logging
16
16
  from collections.abc import Callable
17
17
  from functools import wraps
18
18
  from typing import Any
19
- from typing import overload
20
19
 
21
20
  from fastmcp import Context
22
21
  from fastmcp import FastMCP
23
22
  from fastmcp.exceptions import NotFoundError
24
23
  from fastmcp.prompts.prompt import Prompt
25
24
  from fastmcp.server.dependencies import get_context
26
- from fastmcp.tools import FunctionTool
27
25
  from fastmcp.tools import Tool
28
- from fastmcp.utilities.types import NotSet
29
- from fastmcp.utilities.types import NotSetT
30
26
  from mcp.types import AnyFunction
31
27
  from mcp.types import Tool as MCPTool
32
28
  from mcp.types import ToolAnnotations
@@ -120,86 +116,6 @@ class TaggedFastMCP(FastMCP):
120
116
  "In stateless mode, clients will see changes on next request."
121
117
  )
122
118
 
123
- @overload
124
- def tool(
125
- self,
126
- name_or_fn: AnyFunction,
127
- *,
128
- name: str | None = None,
129
- title: str | None = None,
130
- description: str | None = None,
131
- tags: set[str] | None = None,
132
- output_schema: dict[str, Any] | None | NotSetT = NotSet,
133
- annotations: ToolAnnotations | dict[str, Any] | None = None,
134
- exclude_args: list[str] | None = None,
135
- meta: dict[str, Any] | None = None,
136
- enabled: bool | None = None,
137
- ) -> FunctionTool: ...
138
-
139
- @overload
140
- def tool(
141
- self,
142
- name_or_fn: str | None = None,
143
- *,
144
- name: str | None = None,
145
- title: str | None = None,
146
- description: str | None = None,
147
- tags: set[str] | None = None,
148
- output_schema: dict[str, Any] | None | NotSetT = NotSet,
149
- annotations: ToolAnnotations | dict[str, Any] | None = None,
150
- exclude_args: list[str] | None = None,
151
- meta: dict[str, Any] | None = None,
152
- enabled: bool | None = None,
153
- ) -> Callable[[AnyFunction], FunctionTool]: ...
154
-
155
- def tool(
156
- self,
157
- name_or_fn: str | Callable[..., Any] | None = None,
158
- *,
159
- name: str | None = None,
160
- title: str | None = None,
161
- description: str | None = None,
162
- tags: set[str] | None = None,
163
- output_schema: dict[str, Any] | None | NotSetT = NotSet,
164
- annotations: ToolAnnotations | dict[str, Any] | None = None,
165
- exclude_args: list[str] | None = None,
166
- meta: dict[str, Any] | None = None,
167
- enabled: bool | None = None,
168
- **kwargs: Any,
169
- ) -> Callable[[AnyFunction], FunctionTool] | FunctionTool:
170
- """
171
- Extend tool decorator that supports tags and other annotations, while remaining
172
- signature-compatible with FastMCP.tool to avoid recursion issues with partials.
173
- """
174
- if isinstance(annotations, dict):
175
- annotations = ToolAnnotations(**annotations)
176
-
177
- # Ensure tags are available both via native fastmcp `tags` and inside annotations
178
- if tags is not None:
179
- tags_ = sorted(tags)
180
- if annotations is None:
181
- annotations = ToolAnnotations() # type: ignore[call-arg]
182
- annotations.tags = tags_ # type: ignore[attr-defined, union-attr]
183
- else:
184
- # At this point, annotations is ToolAnnotations (not dict)
185
- assert isinstance(annotations, ToolAnnotations)
186
- annotations.tags = tags_ # type: ignore[attr-defined]
187
-
188
- return super().tool(
189
- name_or_fn,
190
- name=name,
191
- title=title,
192
- description=description,
193
- tags=tags,
194
- output_schema=output_schema
195
- if output_schema is not None
196
- else kwargs.get("output_schema"),
197
- annotations=annotations,
198
- exclude_args=exclude_args,
199
- meta=meta,
200
- enabled=enabled,
201
- )
202
-
203
119
  async def list_tools(
204
120
  self, tags: list[str] | None = None, match_all: bool = False
205
121
  ) -> list[MCPTool]:
@@ -488,11 +404,10 @@ async def register_tools(
488
404
  # Apply dr_mcp_extras to the memory-aware function
489
405
  wrapped_fn = dr_mcp_extras()(memory_aware_fn)
490
406
 
491
- # Create annotations with tags, deployment_id if provided
492
- annotations = ToolAnnotations() # type: ignore[call-arg]
493
- if tags is not None:
494
- annotations.tags = tags # type: ignore[attr-defined]
407
+ # Create annotations only when additional metadata is required
408
+ annotations: ToolAnnotations | None = None # type: ignore[assignment]
495
409
  if deployment_id is not None:
410
+ annotations = ToolAnnotations() # type: ignore[call-arg]
496
411
  annotations.deployment_id = deployment_id # type: ignore[attr-defined]
497
412
 
498
413
  tool = Tool.from_function(
@@ -41,7 +41,7 @@ def filter_tools_by_tags(
41
41
  filtered_tools = []
42
42
 
43
43
  for tool in tools:
44
- tool_tags = getattr(tool.annotations, "tags", []) if tool.annotations else []
44
+ tool_tags = get_tool_tags(tool)
45
45
 
46
46
  if not tool_tags:
47
47
  continue
@@ -68,9 +68,18 @@ def get_tool_tags(tool: Tool | MCPTool) -> list[str]:
68
68
  -------
69
69
  List of tags for the tool
70
70
  """
71
+ # Primary: native FastMCP meta location
72
+ if hasattr(tool, "meta") and getattr(tool, "meta"):
73
+ fastmcp_meta = tool.meta.get("_fastmcp", {})
74
+ meta_tags = fastmcp_meta.get("tags", [])
75
+ if isinstance(meta_tags, list):
76
+ return meta_tags
77
+
78
+ # Fallback: annotations.tags (for compatibility during transition)
71
79
  if tool.annotations and hasattr(tool.annotations, "tags"):
72
80
  tags = getattr(tool.annotations, "tags", [])
73
81
  return tags if isinstance(tags, list) else []
82
+
74
83
  return []
75
84
 
76
85
 
@@ -0,0 +1,90 @@
1
+ # Copyright 2025 DataRobot, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import json
16
+ import logging
17
+ from typing import Annotated
18
+
19
+ from fastmcp.exceptions import ToolError
20
+ from fastmcp.tools.tool import ToolResult
21
+
22
+ from datarobot_genai.drmcp.core.clients import get_sdk_client
23
+ from datarobot_genai.drmcp.core.mcp_instance import dr_mcp_tool
24
+
25
+ logger = logging.getLogger(__name__)
26
+
27
+
28
+ @dr_mcp_tool(tags={"predictive", "project", "read", "management", "list"})
29
+ async def list_projects() -> ToolResult:
30
+ """List all DataRobot projects for the authenticated user."""
31
+ client = get_sdk_client()
32
+ projects = client.Project.list()
33
+ projects = {p.id: p.project_name for p in projects}
34
+
35
+ return ToolResult(
36
+ content=(
37
+ json.dumps(projects, indent=2)
38
+ if projects
39
+ else json.dumps({"message": "No projects found."}, indent=2)
40
+ ),
41
+ structured_content=projects,
42
+ )
43
+
44
+
45
+ @dr_mcp_tool(tags={"predictive", "project", "read", "data", "info"})
46
+ async def get_project_dataset_by_name(
47
+ *,
48
+ project_id: Annotated[str, "The ID of the DataRobot project."] | None = None,
49
+ dataset_name: Annotated[str, "The name of the dataset to find (e.g., 'training', 'holdout')."]
50
+ | None = None,
51
+ ) -> ToolError | ToolResult:
52
+ """Get a dataset ID by name for a given project.
53
+
54
+ The dataset ID and the dataset type (source or prediction) as a string, or an error message.
55
+ """
56
+ if not project_id:
57
+ return ToolError("Project ID is required.")
58
+ if not dataset_name:
59
+ return ToolError("Dataset name is required.")
60
+
61
+ client = get_sdk_client()
62
+ project = client.Project.get(project_id)
63
+ all_datasets = []
64
+ source_dataset = project.get_dataset()
65
+ if source_dataset:
66
+ all_datasets.append({"type": "source", "dataset": source_dataset})
67
+ prediction_datasets = project.get_datasets()
68
+ if prediction_datasets:
69
+ all_datasets.extend([{"type": "prediction", "dataset": ds} for ds in prediction_datasets])
70
+ for ds in all_datasets:
71
+ if dataset_name.lower() in ds["dataset"].name.lower():
72
+ return ToolResult(
73
+ content=(
74
+ json.dumps(
75
+ {
76
+ "dataset_id": ds["dataset"].id,
77
+ "dataset_type": ds["type"],
78
+ },
79
+ indent=2,
80
+ )
81
+ ),
82
+ structured_content={
83
+ "dataset_id": ds["dataset"].id,
84
+ "dataset_type": ds["type"],
85
+ },
86
+ )
87
+ return ToolResult(
88
+ content=f"Dataset with name containing '{dataset_name}' not found in project {project_id}.",
89
+ structured_content={},
90
+ )