datarobot-genai 0.2.6__py3-none-any.whl → 0.2.7__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.
@@ -11,13 +11,22 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
+ from collections.abc import AsyncGenerator
15
+ from typing import Any
16
+
14
17
  from datarobot.core.config import DataRobotAppFrameworkBaseSettings
15
18
  from nat.authentication.api_key.api_key_auth_provider import APIKeyAuthProvider
16
19
  from nat.authentication.api_key.api_key_auth_provider_config import APIKeyAuthProviderConfig
20
+ from nat.authentication.interfaces import AuthProviderBase
17
21
  from nat.builder.builder import Builder
18
22
  from nat.cli.register_workflow import register_auth_provider
23
+ from nat.data_models.authentication import AuthProviderBaseConfig
24
+ from nat.data_models.authentication import AuthResult
25
+ from nat.data_models.authentication import HeaderCred
19
26
  from pydantic import Field
20
27
 
28
+ from datarobot_genai.core.mcp.common import MCPConfig
29
+
21
30
 
22
31
  class Config(DataRobotAppFrameworkBaseSettings):
23
32
  """
@@ -49,5 +58,53 @@ class DataRobotAPIKeyAuthProviderConfig(APIKeyAuthProviderConfig, name="datarobo
49
58
  @register_auth_provider(config_type=DataRobotAPIKeyAuthProviderConfig)
50
59
  async def datarobot_api_key_client(
51
60
  config: DataRobotAPIKeyAuthProviderConfig, builder: Builder
52
- ) -> APIKeyAuthProviderConfig:
61
+ ) -> AsyncGenerator[APIKeyAuthProvider]:
53
62
  yield APIKeyAuthProvider(config=config)
63
+
64
+
65
+ mcp_config = MCPConfig().server_config
66
+
67
+
68
+ class DataRobotMCPAuthProviderConfig(AuthProviderBaseConfig, name="datarobot_mcp_auth"): # type: ignore[call-arg]
69
+ headers: dict[str, str] | None = Field(
70
+ description=("Headers to be used for authentication. "),
71
+ default=mcp_config["headers"] if mcp_config else None,
72
+ )
73
+ default_user_id: str | None = Field(default="default-user", description="Default user ID")
74
+ allow_default_user_id_for_tool_calls: bool = Field(
75
+ default=True, description="Allow default user ID for tool calls"
76
+ )
77
+
78
+
79
+ class DataRobotMCPAuthProvider(AuthProviderBase[DataRobotMCPAuthProviderConfig]):
80
+ def __init__(
81
+ self, config: DataRobotMCPAuthProviderConfig, config_name: str | None = None
82
+ ) -> None:
83
+ assert isinstance(config, DataRobotMCPAuthProviderConfig), (
84
+ "Config is not DataRobotMCPAuthProviderConfig"
85
+ )
86
+ super().__init__(config)
87
+
88
+ async def authenticate(self, user_id: str | None = None, **kwargs: Any) -> AuthResult | None:
89
+ """
90
+ Authenticate the user using the API key credentials.
91
+
92
+ Args:
93
+ user_id (str): The user ID to authenticate.
94
+
95
+ Returns
96
+ -------
97
+ AuthenticatedContext: The authenticated context containing headers
98
+ """
99
+ return AuthResult(
100
+ credentials=[
101
+ HeaderCred(name=name, value=value) for name, value in self.config.headers.items()
102
+ ]
103
+ )
104
+
105
+
106
+ @register_auth_provider(config_type=DataRobotMCPAuthProviderConfig)
107
+ async def datarobot_mcp_auth_provider(
108
+ config: DataRobotMCPAuthProviderConfig, builder: Builder
109
+ ) -> AsyncGenerator[DataRobotMCPAuthProvider]:
110
+ yield DataRobotMCPAuthProvider(config=config)
@@ -13,11 +13,15 @@
13
13
  # limitations under the License.
14
14
 
15
15
  import logging
16
+ from datetime import timedelta
16
17
  from typing import Literal
17
18
 
19
+ import httpx
20
+ from nat.authentication.interfaces import AuthProviderBase
18
21
  from nat.builder.builder import Builder
19
22
  from nat.cli.register_workflow import register_function_group
20
23
  from nat.data_models.component_ref import AuthenticationRef
24
+ from nat.plugins.mcp.client_base import AuthAdapter
21
25
  from nat.plugins.mcp.client_base import MCPSSEClient
22
26
  from nat.plugins.mcp.client_base import MCPStdioClient
23
27
  from nat.plugins.mcp.client_base import MCPStreamableHTTPClient
@@ -47,7 +51,7 @@ class DataRobotMCPServerConfig(MCPServerConfig):
47
51
  )
48
52
  # Authentication configuration
49
53
  auth_provider: str | AuthenticationRef | None = Field(
50
- default="datarobot_api_key" if config else None,
54
+ default="datarobot_mcp_auth" if config else None,
51
55
  description="Reference to authentication provider",
52
56
  )
53
57
  command: str | None = Field(
@@ -62,6 +66,55 @@ class DataRobotMCPClientConfig(MCPClientConfig, name="datarobot_mcp_client"): #
62
66
  )
63
67
 
64
68
 
69
+ class DataRobotAuthAdapter(AuthAdapter):
70
+ async def _get_auth_headers(
71
+ self, request: httpx.Request | None = None, response: httpx.Response | None = None
72
+ ) -> dict[str, str]:
73
+ """Get authentication headers from the NAT auth provider."""
74
+ try:
75
+ # Use the user_id passed to this AuthAdapter instance
76
+ auth_result = await self.auth_provider.authenticate(
77
+ user_id=self.user_id, response=response
78
+ )
79
+ as_kwargs = auth_result.as_requests_kwargs()
80
+ return as_kwargs["headers"]
81
+ except Exception as e:
82
+ logger.warning("Failed to get auth token: %s", e)
83
+ return {}
84
+
85
+
86
+ class DataRobotMCPStreamableHTTPClient(MCPStreamableHTTPClient):
87
+ def __init__(
88
+ self,
89
+ url: str,
90
+ auth_provider: AuthProviderBase | None = None,
91
+ user_id: str | None = None,
92
+ tool_call_timeout: timedelta = timedelta(seconds=60),
93
+ auth_flow_timeout: timedelta = timedelta(seconds=300),
94
+ reconnect_enabled: bool = True,
95
+ reconnect_max_attempts: int = 2,
96
+ reconnect_initial_backoff: float = 0.5,
97
+ reconnect_max_backoff: float = 50.0,
98
+ ):
99
+ super().__init__(
100
+ url=url,
101
+ auth_provider=auth_provider,
102
+ user_id=user_id,
103
+ tool_call_timeout=tool_call_timeout,
104
+ auth_flow_timeout=auth_flow_timeout,
105
+ reconnect_enabled=reconnect_enabled,
106
+ reconnect_max_attempts=reconnect_max_attempts,
107
+ reconnect_initial_backoff=reconnect_initial_backoff,
108
+ reconnect_max_backoff=reconnect_max_backoff,
109
+ )
110
+ effective_user_id = user_id or (
111
+ auth_provider.config.default_user_id if auth_provider else None
112
+ )
113
+ self._httpx_auth = (
114
+ DataRobotAuthAdapter(auth_provider, effective_user_id) if auth_provider else None
115
+ )
116
+
117
+
65
118
  @register_function_group(config_type=DataRobotMCPClientConfig)
66
119
  async def datarobot_mcp_client_function_group(
67
120
  config: DataRobotMCPClientConfig, _builder: Builder
@@ -108,7 +161,7 @@ async def datarobot_mcp_client_function_group(
108
161
  elif config.server.transport == "streamable-http":
109
162
  # Use default_user_id for the base client
110
163
  base_user_id = auth_provider.config.default_user_id if auth_provider else None
111
- client = MCPStreamableHTTPClient(
164
+ client = DataRobotMCPStreamableHTTPClient(
112
165
  str(config.server.url),
113
166
  auth_provider=auth_provider,
114
167
  user_id=base_user_id,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: datarobot-genai
3
- Version: 0.2.6
3
+ Version: 0.2.7
4
4
  Summary: Generic helpers for GenAI
5
5
  Project-URL: Homepage, https://github.com/datarobot-oss/datarobot-genai
6
6
  Author: DataRobot, Inc.
@@ -101,13 +101,13 @@ datarobot_genai/llama_index/base.py,sha256=ovcQQtC-djD_hcLrWdn93jg23AmD6NBEj7xtw
101
101
  datarobot_genai/llama_index/mcp.py,sha256=leXqF1C4zhuYEKFwNEfZHY4dsUuGZk3W7KArY-zxVL8,2645
102
102
  datarobot_genai/nat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
103
103
  datarobot_genai/nat/agent.py,sha256=jDeIS9f-8vGbeLy5gQkSjeuHINx5Fh_4BvXYERsgIIk,10516
104
- datarobot_genai/nat/datarobot_auth_provider.py,sha256=5SBs0xBEZAlBvK-_zOR2cfE_rnn2CoEXeb-Du-rqotc,2117
104
+ datarobot_genai/nat/datarobot_auth_provider.py,sha256=Z4NSsrHxK8hUeiqtK_lryHsUuZC74ziNo_FHbsZgtiM,4230
105
105
  datarobot_genai/nat/datarobot_llm_clients.py,sha256=STzAZ4OF8U-Y_cUTywxmKBGVotwsnbGP6vTojnu6q0g,9921
106
106
  datarobot_genai/nat/datarobot_llm_providers.py,sha256=aDoQcTeGI-odqydPXEX9OGGNFbzAtpqzTvHHEkmJuEQ,4963
107
- datarobot_genai/nat/datarobot_mcp_client.py,sha256=XK3-Tp4hdQmTdI-Zwrl3Xd81qH5RhFTw_UaLTqwnYn4,7531
108
- datarobot_genai-0.2.6.dist-info/METADATA,sha256=2F0MD9IDjdYCmuhCO76dJHljxSk0cJP0rX17TJQoPaQ,6172
109
- datarobot_genai-0.2.6.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
110
- datarobot_genai-0.2.6.dist-info/entry_points.txt,sha256=jEW3WxDZ8XIK9-ISmTyt5DbmBb047rFlzQuhY09rGrM,284
111
- datarobot_genai-0.2.6.dist-info/licenses/AUTHORS,sha256=isJGUXdjq1U7XZ_B_9AH8Qf0u4eX0XyQifJZ_Sxm4sA,80
112
- datarobot_genai-0.2.6.dist-info/licenses/LICENSE,sha256=U2_VkLIktQoa60Nf6Tbt7E4RMlfhFSjWjcJJfVC-YCE,11341
113
- datarobot_genai-0.2.6.dist-info/RECORD,,
107
+ datarobot_genai/nat/datarobot_mcp_client.py,sha256=35FzilxNp4VqwBYI0NsOc91-xZm1C-AzWqrOdDy962A,9612
108
+ datarobot_genai-0.2.7.dist-info/METADATA,sha256=dWVPDIxuaXhv5tFM-_yhFvatzWmHzLvZtcC5pM_NsLw,6172
109
+ datarobot_genai-0.2.7.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
110
+ datarobot_genai-0.2.7.dist-info/entry_points.txt,sha256=jEW3WxDZ8XIK9-ISmTyt5DbmBb047rFlzQuhY09rGrM,284
111
+ datarobot_genai-0.2.7.dist-info/licenses/AUTHORS,sha256=isJGUXdjq1U7XZ_B_9AH8Qf0u4eX0XyQifJZ_Sxm4sA,80
112
+ datarobot_genai-0.2.7.dist-info/licenses/LICENSE,sha256=U2_VkLIktQoa60Nf6Tbt7E4RMlfhFSjWjcJJfVC-YCE,11341
113
+ datarobot_genai-0.2.7.dist-info/RECORD,,