datarobot-genai 0.2.27__tar.gz → 0.2.28__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.
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/PKG-INFO +1 -1
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/pyproject.toml +1 -1
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/config.py +121 -83
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/tool_config.py +17 -9
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/test_utils/tool_base_ete.py +68 -1
- datarobot_genai-0.2.28/src/datarobot_genai/drmcp/tools/clients/microsoft_graph.py +479 -0
- datarobot_genai-0.2.28/src/datarobot_genai/drmcp/tools/microsoft_graph/__init__.py +13 -0
- datarobot_genai-0.2.28/src/datarobot_genai/drmcp/tools/microsoft_graph/tools.py +198 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/tools/predictive/data.py +11 -3
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/tools/predictive/training.py +1 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/.gitignore +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/AUTHORS +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/LICENSE +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/README.md +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/__init__.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/core/__init__.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/core/agents/__init__.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/core/agents/base.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/core/chat/__init__.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/core/chat/auth.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/core/chat/client.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/core/chat/responses.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/core/cli/__init__.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/core/cli/agent_environment.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/core/cli/agent_kernel.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/core/custom_model.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/core/mcp/__init__.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/core/mcp/common.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/core/telemetry_agent.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/core/utils/__init__.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/core/utils/auth.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/core/utils/urls.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/crewai/__init__.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/crewai/agent.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/crewai/base.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/crewai/events.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/crewai/mcp.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/__init__.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/__init__.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/auth.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/clients.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/config_utils.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/constants.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/credentials.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/dr_mcp_server.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/dr_mcp_server_logo.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/dynamic_prompts/__init__.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/dynamic_prompts/controllers.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/dynamic_prompts/dr_lib.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/dynamic_prompts/register.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/dynamic_prompts/utils.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/dynamic_tools/__init__.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/__init__.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/adapters/__init__.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/adapters/base.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/adapters/default.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/adapters/drum.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/config.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/controllers.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/metadata.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/register.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/schemas/drum_agentic_fallback_schema.json +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/dynamic_tools/deployment/schemas/drum_prediction_fallback_schema.json +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/dynamic_tools/register.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/dynamic_tools/schema.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/exceptions.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/logging.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/mcp_instance.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/memory_management/__init__.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/memory_management/manager.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/memory_management/memory_tools.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/routes.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/routes_utils.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/server_life_cycle.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/telemetry.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/tool_filter.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/utils.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/server.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/test_utils/__init__.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/test_utils/elicitation_test_tool.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/test_utils/integration_mcp_server.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/test_utils/mcp_utils_ete.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/test_utils/mcp_utils_integration.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/test_utils/openai_llm_mcp_client.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/test_utils/test_interactive.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/test_utils/utils.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/tools/__init__.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/tools/clients/__init__.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/tools/clients/atlassian.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/tools/clients/confluence.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/tools/clients/gdrive.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/tools/clients/jira.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/tools/clients/s3.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/tools/confluence/__init__.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/tools/confluence/tools.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/tools/gdrive/__init__.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/tools/gdrive/tools.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/tools/jira/__init__.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/tools/jira/tools.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/tools/predictive/__init__.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/tools/predictive/deployment.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/tools/predictive/deployment_info.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/tools/predictive/model.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/tools/predictive/predict.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/tools/predictive/predict_realtime.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/tools/predictive/project.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/langgraph/__init__.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/langgraph/agent.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/langgraph/mcp.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/llama_index/__init__.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/llama_index/agent.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/llama_index/base.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/llama_index/mcp.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/nat/__init__.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/nat/agent.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/nat/datarobot_auth_provider.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/nat/datarobot_llm_clients.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/nat/datarobot_llm_providers.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/nat/datarobot_mcp_client.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/nat/helpers.py +0 -0
- {datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/py.typed +0 -0
|
@@ -31,6 +31,124 @@ from .constants import DEFAULT_DATAROBOT_ENDPOINT
|
|
|
31
31
|
from .constants import RUNTIME_PARAM_ENV_VAR_NAME_PREFIX
|
|
32
32
|
|
|
33
33
|
|
|
34
|
+
class MCPToolConfig(BaseSettings):
|
|
35
|
+
"""Tool configuration for MCP server."""
|
|
36
|
+
|
|
37
|
+
enable_predictive_tools: bool = Field(
|
|
38
|
+
default=True,
|
|
39
|
+
validation_alias=AliasChoices(
|
|
40
|
+
RUNTIME_PARAM_ENV_VAR_NAME_PREFIX + "ENABLE_PREDICTIVE_TOOLS",
|
|
41
|
+
"ENABLE_PREDICTIVE_TOOLS",
|
|
42
|
+
),
|
|
43
|
+
description="Enable/disable predictive tools",
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
enable_jira_tools: bool = Field(
|
|
47
|
+
default=False,
|
|
48
|
+
validation_alias=AliasChoices(
|
|
49
|
+
RUNTIME_PARAM_ENV_VAR_NAME_PREFIX + "ENABLE_JIRA_TOOLS",
|
|
50
|
+
"ENABLE_JIRA_TOOLS",
|
|
51
|
+
),
|
|
52
|
+
description="Enable/disable Jira tools",
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
enable_confluence_tools: bool = Field(
|
|
56
|
+
default=False,
|
|
57
|
+
validation_alias=AliasChoices(
|
|
58
|
+
RUNTIME_PARAM_ENV_VAR_NAME_PREFIX + "ENABLE_CONFLUENCE_TOOLS",
|
|
59
|
+
"ENABLE_CONFLUENCE_TOOLS",
|
|
60
|
+
),
|
|
61
|
+
description="Enable/disable Confluence tools",
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
enable_gdrive_tools: bool = Field(
|
|
65
|
+
default=False,
|
|
66
|
+
validation_alias=AliasChoices(
|
|
67
|
+
RUNTIME_PARAM_ENV_VAR_NAME_PREFIX + "ENABLE_GDRIVE_TOOLS",
|
|
68
|
+
"ENABLE_GDRIVE_TOOLS",
|
|
69
|
+
),
|
|
70
|
+
description="Enable/disable GDrive tools",
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
enable_microsoft_graph_tools: bool = Field(
|
|
74
|
+
default=False,
|
|
75
|
+
validation_alias=AliasChoices(
|
|
76
|
+
RUNTIME_PARAM_ENV_VAR_NAME_PREFIX + "ENABLE_MICROSOFT_GRAPH_TOOLS",
|
|
77
|
+
"ENABLE_MICROSOFT_GRAPH_TOOLS",
|
|
78
|
+
),
|
|
79
|
+
description="Enable/disable Sharepoint tools",
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
is_atlassian_oauth_provider_configured: bool = Field(
|
|
83
|
+
default=False,
|
|
84
|
+
validation_alias=AliasChoices(
|
|
85
|
+
RUNTIME_PARAM_ENV_VAR_NAME_PREFIX + "IS_ATLASSIAN_OAUTH_PROVIDER_CONFIGURED",
|
|
86
|
+
"IS_ATLASSIAN_OAUTH_PROVIDER_CONFIGURED",
|
|
87
|
+
),
|
|
88
|
+
description="Whether Atlassian OAuth provider is configured for Atlassian integration",
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
@property
|
|
92
|
+
def is_atlassian_oauth_configured(self) -> bool:
|
|
93
|
+
"""Check if Atlassian OAuth is configured via provider flag or environment variables."""
|
|
94
|
+
return self.is_atlassian_oauth_provider_configured or bool(
|
|
95
|
+
os.getenv("ATLASSIAN_CLIENT_ID") and os.getenv("ATLASSIAN_CLIENT_SECRET")
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
is_google_oauth_provider_configured: bool = Field(
|
|
99
|
+
default=False,
|
|
100
|
+
validation_alias=AliasChoices(
|
|
101
|
+
RUNTIME_PARAM_ENV_VAR_NAME_PREFIX + "IS_GOOGLE_OAUTH_PROVIDER_CONFIGURED",
|
|
102
|
+
"IS_GOOGLE_OAUTH_PROVIDER_CONFIGURED",
|
|
103
|
+
),
|
|
104
|
+
description="Whether Google OAuth provider is configured for Google integration",
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def is_google_oauth_configured(self) -> bool:
|
|
109
|
+
return self.is_google_oauth_provider_configured or bool(
|
|
110
|
+
os.getenv("GOOGLE_CLIENT_ID") and os.getenv("GOOGLE_CLIENT_SECRET")
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
is_microsoft_oauth_provider_configured: bool = Field(
|
|
114
|
+
default=False,
|
|
115
|
+
validation_alias=AliasChoices(
|
|
116
|
+
RUNTIME_PARAM_ENV_VAR_NAME_PREFIX + "IS_MICROSOFT_OAUTH_PROVIDER_CONFIGURED",
|
|
117
|
+
"IS_MICROSOFT_OAUTH_PROVIDER_CONFIGURED",
|
|
118
|
+
),
|
|
119
|
+
description="Whether Microsoft OAuth provider is configured for Microsoft integration",
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
@property
|
|
123
|
+
def is_microsoft_oauth_configured(self) -> bool:
|
|
124
|
+
return self.is_microsoft_oauth_provider_configured or bool(
|
|
125
|
+
os.getenv("MICROSOFT_CLIENT_ID") and os.getenv("MICROSOFT_CLIENT_SECRET")
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
@field_validator(
|
|
129
|
+
"enable_predictive_tools",
|
|
130
|
+
"enable_jira_tools",
|
|
131
|
+
"enable_confluence_tools",
|
|
132
|
+
"enable_gdrive_tools",
|
|
133
|
+
"enable_microsoft_graph_tools",
|
|
134
|
+
"is_atlassian_oauth_provider_configured",
|
|
135
|
+
"is_google_oauth_provider_configured",
|
|
136
|
+
"is_microsoft_oauth_provider_configured",
|
|
137
|
+
mode="before",
|
|
138
|
+
)
|
|
139
|
+
@classmethod
|
|
140
|
+
def validate_runtime_params(cls, v: Any) -> Any:
|
|
141
|
+
"""Validate runtime parameters."""
|
|
142
|
+
return extract_datarobot_runtime_param_payload(v)
|
|
143
|
+
|
|
144
|
+
model_config = SettingsConfigDict(
|
|
145
|
+
env_file=".env",
|
|
146
|
+
case_sensitive=False,
|
|
147
|
+
env_file_encoding="utf-8",
|
|
148
|
+
extra="ignore",
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
|
|
34
152
|
class MCPServerConfig(BaseSettings):
|
|
35
153
|
"""MCP Server configuration using pydantic settings."""
|
|
36
154
|
|
|
@@ -188,86 +306,11 @@ class MCPServerConfig(BaseSettings):
|
|
|
188
306
|
),
|
|
189
307
|
description="Enable/disable memory management",
|
|
190
308
|
)
|
|
191
|
-
enable_predictive_tools: bool = Field(
|
|
192
|
-
default=True,
|
|
193
|
-
validation_alias=AliasChoices(
|
|
194
|
-
RUNTIME_PARAM_ENV_VAR_NAME_PREFIX + "ENABLE_PREDICTIVE_TOOLS",
|
|
195
|
-
"ENABLE_PREDICTIVE_TOOLS",
|
|
196
|
-
),
|
|
197
|
-
description="Enable/disable predictive tools",
|
|
198
|
-
)
|
|
199
309
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
validation_alias=AliasChoices(
|
|
204
|
-
RUNTIME_PARAM_ENV_VAR_NAME_PREFIX + "ENABLE_JIRA_TOOLS",
|
|
205
|
-
"ENABLE_JIRA_TOOLS",
|
|
206
|
-
),
|
|
207
|
-
description="Enable/disable Jira tools",
|
|
310
|
+
tool_config: MCPToolConfig = Field(
|
|
311
|
+
default_factory=MCPToolConfig,
|
|
312
|
+
description="Tool configuration",
|
|
208
313
|
)
|
|
209
|
-
is_jira_oauth_provider_configured: bool = Field(
|
|
210
|
-
default=False,
|
|
211
|
-
validation_alias=AliasChoices(
|
|
212
|
-
RUNTIME_PARAM_ENV_VAR_NAME_PREFIX + "IS_JIRA_OAUTH_PROVIDER_CONFIGURED",
|
|
213
|
-
"IS_JIRA_OAUTH_PROVIDER_CONFIGURED",
|
|
214
|
-
),
|
|
215
|
-
description="Whether Jira OAuth provider is configured for Jira integration",
|
|
216
|
-
)
|
|
217
|
-
|
|
218
|
-
@property
|
|
219
|
-
def is_jira_oauth_configured(self) -> bool:
|
|
220
|
-
return self.is_jira_oauth_provider_configured or bool(
|
|
221
|
-
os.getenv("JIRA_CLIENT_ID") and os.getenv("JIRA_CLIENT_SECRET")
|
|
222
|
-
)
|
|
223
|
-
|
|
224
|
-
# Confluence tools
|
|
225
|
-
enable_confluence_tools: bool = Field(
|
|
226
|
-
default=False,
|
|
227
|
-
validation_alias=AliasChoices(
|
|
228
|
-
RUNTIME_PARAM_ENV_VAR_NAME_PREFIX + "ENABLE_CONFLUENCE_TOOLS",
|
|
229
|
-
"ENABLE_CONFLUENCE_TOOLS",
|
|
230
|
-
),
|
|
231
|
-
description="Enable/disable Confluence tools",
|
|
232
|
-
)
|
|
233
|
-
is_confluence_oauth_provider_configured: bool = Field(
|
|
234
|
-
default=False,
|
|
235
|
-
validation_alias=AliasChoices(
|
|
236
|
-
RUNTIME_PARAM_ENV_VAR_NAME_PREFIX + "IS_CONFLUENCE_OAUTH_PROVIDER_CONFIGURED",
|
|
237
|
-
"IS_CONFLUENCE_OAUTH_PROVIDER_CONFIGURED",
|
|
238
|
-
),
|
|
239
|
-
description="Whether Confluence OAuth provider is configured for Confluence integration",
|
|
240
|
-
)
|
|
241
|
-
|
|
242
|
-
@property
|
|
243
|
-
def is_confluence_oauth_configured(self) -> bool:
|
|
244
|
-
return self.is_confluence_oauth_provider_configured or bool(
|
|
245
|
-
os.getenv("CONFLUENCE_CLIENT_ID") and os.getenv("CONFLUENCE_CLIENT_SECRET")
|
|
246
|
-
)
|
|
247
|
-
|
|
248
|
-
# Gdrive tools
|
|
249
|
-
enable_gdrive_tools: bool = Field(
|
|
250
|
-
default=False,
|
|
251
|
-
validation_alias=AliasChoices(
|
|
252
|
-
RUNTIME_PARAM_ENV_VAR_NAME_PREFIX + "ENABLE_GDRIVE_TOOLS",
|
|
253
|
-
"ENABLE_GDRIVE_TOOLS",
|
|
254
|
-
),
|
|
255
|
-
description="Enable/disable GDrive tools",
|
|
256
|
-
)
|
|
257
|
-
is_gdrive_oauth_provider_configured: bool = Field(
|
|
258
|
-
default=False,
|
|
259
|
-
validation_alias=AliasChoices(
|
|
260
|
-
RUNTIME_PARAM_ENV_VAR_NAME_PREFIX + "IS_GDRIVE_OAUTH_PROVIDER_CONFIGURED",
|
|
261
|
-
"IS_GDRIVE_OAUTH_PROVIDER_CONFIGURED",
|
|
262
|
-
),
|
|
263
|
-
description="Whether GDrive OAuth provider is configured for GDrive integration",
|
|
264
|
-
)
|
|
265
|
-
|
|
266
|
-
@property
|
|
267
|
-
def is_gdrive_oauth_configured(self) -> bool:
|
|
268
|
-
return self.is_gdrive_oauth_provider_configured or bool(
|
|
269
|
-
os.getenv("GDRIVE_CLIENT_ID") and os.getenv("GDRIVE_CLIENT_SECRET")
|
|
270
|
-
)
|
|
271
314
|
|
|
272
315
|
@field_validator(
|
|
273
316
|
"otel_attributes",
|
|
@@ -291,11 +334,6 @@ class MCPServerConfig(BaseSettings):
|
|
|
291
334
|
"mcp_server_register_dynamic_tools_on_startup",
|
|
292
335
|
"tool_registration_duplicate_behavior",
|
|
293
336
|
"mcp_server_register_dynamic_prompts_on_startup",
|
|
294
|
-
"enable_predictive_tools",
|
|
295
|
-
"enable_jira_tools",
|
|
296
|
-
"is_jira_oauth_provider_configured",
|
|
297
|
-
"enable_confluence_tools",
|
|
298
|
-
"is_confluence_oauth_provider_configured",
|
|
299
337
|
mode="before",
|
|
300
338
|
)
|
|
301
339
|
@classmethod
|
{datarobot_genai-0.2.27 → datarobot_genai-0.2.28}/src/datarobot_genai/drmcp/core/tool_config.py
RENAMED
|
@@ -30,6 +30,7 @@ class ToolType(str, Enum):
|
|
|
30
30
|
JIRA = "jira"
|
|
31
31
|
CONFLUENCE = "confluence"
|
|
32
32
|
GDRIVE = "gdrive"
|
|
33
|
+
MICROSOFT_GRAPH = "microsoft_graph"
|
|
33
34
|
|
|
34
35
|
|
|
35
36
|
class ToolConfig(TypedDict):
|
|
@@ -39,7 +40,7 @@ class ToolConfig(TypedDict):
|
|
|
39
40
|
oauth_check: Callable[["MCPServerConfig"], bool] | None
|
|
40
41
|
directory: str
|
|
41
42
|
package_prefix: str
|
|
42
|
-
config_field_name: str
|
|
43
|
+
config_field_name: str
|
|
43
44
|
|
|
44
45
|
|
|
45
46
|
# Tool configuration registry
|
|
@@ -53,25 +54,32 @@ TOOL_CONFIGS: dict[ToolType, ToolConfig] = {
|
|
|
53
54
|
),
|
|
54
55
|
ToolType.JIRA: ToolConfig(
|
|
55
56
|
name="jira",
|
|
56
|
-
oauth_check=lambda config: config.
|
|
57
|
+
oauth_check=lambda config: config.tool_config.is_atlassian_oauth_configured,
|
|
57
58
|
directory="jira",
|
|
58
59
|
package_prefix="datarobot_genai.drmcp.tools.jira",
|
|
59
60
|
config_field_name="enable_jira_tools",
|
|
60
61
|
),
|
|
61
62
|
ToolType.CONFLUENCE: ToolConfig(
|
|
62
63
|
name="confluence",
|
|
63
|
-
oauth_check=lambda config: config.
|
|
64
|
+
oauth_check=lambda config: config.tool_config.is_atlassian_oauth_configured,
|
|
64
65
|
directory="confluence",
|
|
65
66
|
package_prefix="datarobot_genai.drmcp.tools.confluence",
|
|
66
67
|
config_field_name="enable_confluence_tools",
|
|
67
68
|
),
|
|
68
69
|
ToolType.GDRIVE: ToolConfig(
|
|
69
70
|
name="gdrive",
|
|
70
|
-
oauth_check=lambda config: config.
|
|
71
|
+
oauth_check=lambda config: config.tool_config.is_google_oauth_configured,
|
|
71
72
|
directory="gdrive",
|
|
72
73
|
package_prefix="datarobot_genai.drmcp.tools.gdrive",
|
|
73
74
|
config_field_name="enable_gdrive_tools",
|
|
74
75
|
),
|
|
76
|
+
ToolType.MICROSOFT_GRAPH: ToolConfig(
|
|
77
|
+
name="microsoft_graph",
|
|
78
|
+
oauth_check=lambda config: config.tool_config.is_microsoft_oauth_configured,
|
|
79
|
+
directory="microsoft_graph",
|
|
80
|
+
package_prefix="datarobot_genai.drmcp.tools.microsoft_graph",
|
|
81
|
+
config_field_name="enable_microsoft_graph_tools",
|
|
82
|
+
),
|
|
75
83
|
}
|
|
76
84
|
|
|
77
85
|
|
|
@@ -92,12 +100,12 @@ def is_tool_enabled(tool_type: ToolType, config: "MCPServerConfig") -> bool:
|
|
|
92
100
|
-------
|
|
93
101
|
True if the tool is enabled, False otherwise
|
|
94
102
|
"""
|
|
95
|
-
|
|
96
|
-
enable_config_name =
|
|
97
|
-
is_enabled = getattr(config, enable_config_name)
|
|
103
|
+
tool_config_registry = TOOL_CONFIGS[tool_type]
|
|
104
|
+
enable_config_name = tool_config_registry["config_field_name"]
|
|
105
|
+
is_enabled = getattr(config.tool_config, enable_config_name)
|
|
98
106
|
|
|
99
107
|
# If tool is enabled, check OAuth requirements if needed
|
|
100
|
-
if is_enabled and
|
|
101
|
-
return
|
|
108
|
+
if is_enabled and tool_config_registry["oauth_check"] is not None:
|
|
109
|
+
return tool_config_registry["oauth_check"](config)
|
|
102
110
|
|
|
103
111
|
return is_enabled
|
|
@@ -39,6 +39,54 @@ class ETETestExpectations(BaseModel):
|
|
|
39
39
|
SHOULD_NOT_BE_EMPTY = "SHOULD_NOT_BE_EMPTY"
|
|
40
40
|
|
|
41
41
|
|
|
42
|
+
def _extract_structured_content(tool_result: str) -> Any:
|
|
43
|
+
r"""
|
|
44
|
+
Extract and parse structured content from tool result string.
|
|
45
|
+
|
|
46
|
+
Tool results are formatted as:
|
|
47
|
+
"Content: {content}\nStructured content: {structured_content}"
|
|
48
|
+
|
|
49
|
+
Structured content can be:
|
|
50
|
+
1. A JSON object with a "result" key: {"result": "..."} or {"result": "{...}"}
|
|
51
|
+
2. A direct JSON object: {"key": "value", ...}
|
|
52
|
+
3. Empty or missing
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
tool_result: The tool result string
|
|
56
|
+
|
|
57
|
+
Returns
|
|
58
|
+
-------
|
|
59
|
+
Parsed structured content, or None if not available
|
|
60
|
+
"""
|
|
61
|
+
# Early returns for invalid inputs
|
|
62
|
+
if not tool_result or "Structured content: " not in tool_result:
|
|
63
|
+
return None
|
|
64
|
+
|
|
65
|
+
structured_part = tool_result.split("Structured content: ", 1)[1].strip()
|
|
66
|
+
# Parse JSON, return None on failure or empty structured_part
|
|
67
|
+
if not structured_part:
|
|
68
|
+
return None
|
|
69
|
+
try:
|
|
70
|
+
structured_data = json.loads(structured_part)
|
|
71
|
+
except json.JSONDecodeError:
|
|
72
|
+
return None
|
|
73
|
+
|
|
74
|
+
# If structured data has a "result" key, extract and parse that
|
|
75
|
+
if isinstance(structured_data, dict) and "result" in structured_data:
|
|
76
|
+
result_value = structured_data["result"]
|
|
77
|
+
# If result is a JSON string (starts with { or [), try to parse it
|
|
78
|
+
if isinstance(result_value, str) and result_value.strip().startswith(("{", "[")):
|
|
79
|
+
try:
|
|
80
|
+
parsed_result = json.loads(result_value)
|
|
81
|
+
except json.JSONDecodeError:
|
|
82
|
+
parsed_result = result_value # Return string as-is if parsing fails
|
|
83
|
+
return parsed_result
|
|
84
|
+
return result_value # Return result value directly
|
|
85
|
+
|
|
86
|
+
# If it's a direct JSON object (not wrapped in {"result": ...}), return it as-is
|
|
87
|
+
return structured_data
|
|
88
|
+
|
|
89
|
+
|
|
42
90
|
def _check_dict_has_keys(
|
|
43
91
|
expected: dict[str, Any],
|
|
44
92
|
actual: dict[str, Any] | list[dict[str, Any]],
|
|
@@ -130,7 +178,26 @@ class ToolBaseE2E:
|
|
|
130
178
|
f"result, but got: {response.tool_results[i]}"
|
|
131
179
|
)
|
|
132
180
|
else:
|
|
133
|
-
actual_result =
|
|
181
|
+
actual_result = _extract_structured_content(response.tool_results[i])
|
|
182
|
+
if actual_result is None:
|
|
183
|
+
# Fallback: try to parse the entire tool result as JSON
|
|
184
|
+
try:
|
|
185
|
+
actual_result = json.loads(response.tool_results[i])
|
|
186
|
+
except json.JSONDecodeError:
|
|
187
|
+
# If that fails, try to extract content part
|
|
188
|
+
if "Content: " in response.tool_results[i]:
|
|
189
|
+
content_part = response.tool_results[i].split("Content: ", 1)[1]
|
|
190
|
+
if "\nStructured content: " in content_part:
|
|
191
|
+
content_part = content_part.split(
|
|
192
|
+
"\nStructured content: ", 1
|
|
193
|
+
)[0]
|
|
194
|
+
try:
|
|
195
|
+
actual_result = json.loads(content_part.strip())
|
|
196
|
+
except json.JSONDecodeError:
|
|
197
|
+
raise AssertionError(
|
|
198
|
+
f"Could not parse tool result for "
|
|
199
|
+
f"{tool_call.tool_name}: {response.tool_results[i]}"
|
|
200
|
+
)
|
|
134
201
|
assert _check_dict_has_keys(expected_result, actual_result), (
|
|
135
202
|
f"Should have called {tool_call.tool_name} tool with the correct "
|
|
136
203
|
f"result structure, but got: {response.tool_results[i]}"
|