datarobot-genai 0.1.68__py3-none-any.whl → 0.1.69__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.
- datarobot_genai/core/mcp/common.py +82 -48
- {datarobot_genai-0.1.68.dist-info → datarobot_genai-0.1.69.dist-info}/METADATA +1 -1
- {datarobot_genai-0.1.68.dist-info → datarobot_genai-0.1.69.dist-info}/RECORD +7 -7
- {datarobot_genai-0.1.68.dist-info → datarobot_genai-0.1.69.dist-info}/WHEEL +0 -0
- {datarobot_genai-0.1.68.dist-info → datarobot_genai-0.1.69.dist-info}/entry_points.txt +0 -0
- {datarobot_genai-0.1.68.dist-info → datarobot_genai-0.1.69.dist-info}/licenses/AUTHORS +0 -0
- {datarobot_genai-0.1.68.dist-info → datarobot_genai-0.1.69.dist-info}/licenses/LICENSE +0 -0
|
@@ -13,16 +13,20 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
import json
|
|
16
|
+
import logging
|
|
16
17
|
import re
|
|
18
|
+
from http import HTTPStatus
|
|
17
19
|
from typing import Any
|
|
18
20
|
from typing import Literal
|
|
19
|
-
from urllib.parse import urlparse
|
|
20
21
|
|
|
22
|
+
import requests
|
|
21
23
|
from datarobot.core.config import DataRobotAppFrameworkBaseSettings
|
|
22
24
|
from pydantic import field_validator
|
|
23
25
|
|
|
24
26
|
from datarobot_genai.core.utils.auth import AuthContextHeaderHandler
|
|
25
27
|
|
|
28
|
+
logger = logging.getLogger(__name__)
|
|
29
|
+
|
|
26
30
|
|
|
27
31
|
class MCPConfig(DataRobotAppFrameworkBaseSettings):
|
|
28
32
|
"""Configuration for MCP server connection.
|
|
@@ -39,6 +43,7 @@ class MCPConfig(DataRobotAppFrameworkBaseSettings):
|
|
|
39
43
|
datarobot_api_token: str | None = None
|
|
40
44
|
authorization_context: dict[str, Any] | None = None
|
|
41
45
|
forwarded_headers: dict[str, str] | None = None
|
|
46
|
+
mcp_server_port: int | None = None
|
|
42
47
|
|
|
43
48
|
_auth_context_handler: AuthContextHeaderHandler | None = None
|
|
44
49
|
_server_config: dict[str, Any] | None = None
|
|
@@ -49,17 +54,14 @@ class MCPConfig(DataRobotAppFrameworkBaseSettings):
|
|
|
49
54
|
if value is None:
|
|
50
55
|
return None
|
|
51
56
|
|
|
52
|
-
if not isinstance(value, str):
|
|
53
|
-
msg = "external_mcp_headers must be a JSON string"
|
|
54
|
-
raise TypeError(msg)
|
|
55
|
-
|
|
56
57
|
candidate = value.strip()
|
|
57
58
|
|
|
58
59
|
try:
|
|
59
60
|
json.loads(candidate)
|
|
60
|
-
except json.JSONDecodeError
|
|
61
|
+
except json.JSONDecodeError:
|
|
61
62
|
msg = "external_mcp_headers must be valid JSON"
|
|
62
|
-
|
|
63
|
+
logger.warning(msg)
|
|
64
|
+
return None
|
|
63
65
|
|
|
64
66
|
return candidate
|
|
65
67
|
|
|
@@ -69,15 +71,12 @@ class MCPConfig(DataRobotAppFrameworkBaseSettings):
|
|
|
69
71
|
if value is None:
|
|
70
72
|
return None
|
|
71
73
|
|
|
72
|
-
if not isinstance(value, str):
|
|
73
|
-
msg = "mcp_deployment_id must be a string"
|
|
74
|
-
raise TypeError(msg)
|
|
75
|
-
|
|
76
74
|
candidate = value.strip()
|
|
77
75
|
|
|
78
76
|
if not re.fullmatch(r"[0-9a-fA-F]{24}", candidate):
|
|
79
77
|
msg = "mcp_deployment_id must be a valid 24-character hex ID"
|
|
80
|
-
|
|
78
|
+
logger.warning(msg)
|
|
79
|
+
return None
|
|
81
80
|
|
|
82
81
|
return candidate
|
|
83
82
|
|
|
@@ -112,6 +111,45 @@ class MCPConfig(DataRobotAppFrameworkBaseSettings):
|
|
|
112
111
|
# Authorization context not available (e.g., in tests)
|
|
113
112
|
return {}
|
|
114
113
|
|
|
114
|
+
def _build_authenticated_headers(self) -> dict[str, str]:
|
|
115
|
+
"""Build headers for authenticated requests.
|
|
116
|
+
|
|
117
|
+
Returns
|
|
118
|
+
-------
|
|
119
|
+
Dictionary containing forwarded headers (if available) and authentication headers.
|
|
120
|
+
"""
|
|
121
|
+
headers: dict[str, str] = {}
|
|
122
|
+
if self.forwarded_headers:
|
|
123
|
+
headers.update(self.forwarded_headers)
|
|
124
|
+
headers.update(self._authorization_bearer_header())
|
|
125
|
+
headers.update(self._authorization_context_header())
|
|
126
|
+
return headers
|
|
127
|
+
|
|
128
|
+
def _check_localhost_server(self, url: str, timeout: float = 2.0) -> bool:
|
|
129
|
+
"""Check if MCP server is running on localhost.
|
|
130
|
+
|
|
131
|
+
Parameters
|
|
132
|
+
----------
|
|
133
|
+
url : str
|
|
134
|
+
The URL to check.
|
|
135
|
+
timeout : float, optional
|
|
136
|
+
Request timeout in seconds (default: 2.0).
|
|
137
|
+
|
|
138
|
+
Returns
|
|
139
|
+
-------
|
|
140
|
+
bool
|
|
141
|
+
True if server is running and responding with OK status, False otherwise.
|
|
142
|
+
"""
|
|
143
|
+
try:
|
|
144
|
+
response = requests.get(url, timeout=timeout)
|
|
145
|
+
return (
|
|
146
|
+
response.status_code == HTTPStatus.OK
|
|
147
|
+
and response.json().get("message") == "DataRobot MCP Server is running"
|
|
148
|
+
)
|
|
149
|
+
except requests.RequestException as e:
|
|
150
|
+
logger.debug(f"Failed to connect to MCP server at {url}: {e}")
|
|
151
|
+
return False
|
|
152
|
+
|
|
115
153
|
def _build_server_config(self) -> dict[str, Any] | None:
|
|
116
154
|
"""
|
|
117
155
|
Get MCP server configuration.
|
|
@@ -121,34 +159,6 @@ class MCPConfig(DataRobotAppFrameworkBaseSettings):
|
|
|
121
159
|
Server configuration dict with url, transport, and optional headers,
|
|
122
160
|
or None if not configured.
|
|
123
161
|
"""
|
|
124
|
-
if self.external_mcp_url:
|
|
125
|
-
# External MCP URL - no authentication needed
|
|
126
|
-
headers: dict[str, str] = {}
|
|
127
|
-
|
|
128
|
-
# Forward headers for localhost connections
|
|
129
|
-
if self.forwarded_headers:
|
|
130
|
-
try:
|
|
131
|
-
parsed_url = urlparse(self.external_mcp_url)
|
|
132
|
-
hostname = parsed_url.hostname or ""
|
|
133
|
-
# Check if hostname is localhost or 127.0.0.1
|
|
134
|
-
if hostname in ("localhost", "127.0.0.1", "::1"):
|
|
135
|
-
headers.update(self.forwarded_headers)
|
|
136
|
-
except Exception:
|
|
137
|
-
# If URL parsing fails, fall back to simple string check
|
|
138
|
-
if "localhost" in self.external_mcp_url or "127.0.0.1" in self.external_mcp_url:
|
|
139
|
-
headers.update(self.forwarded_headers)
|
|
140
|
-
|
|
141
|
-
# Merge external headers if provided
|
|
142
|
-
if self.external_mcp_headers:
|
|
143
|
-
external_headers = json.loads(self.external_mcp_headers)
|
|
144
|
-
headers.update(external_headers)
|
|
145
|
-
|
|
146
|
-
return {
|
|
147
|
-
"url": self.external_mcp_url.rstrip("/"),
|
|
148
|
-
"transport": self.external_mcp_transport,
|
|
149
|
-
"headers": headers,
|
|
150
|
-
}
|
|
151
|
-
|
|
152
162
|
if self.mcp_deployment_id:
|
|
153
163
|
# DataRobot deployment ID - requires authentication
|
|
154
164
|
if self.datarobot_endpoint is None:
|
|
@@ -165,15 +175,9 @@ class MCPConfig(DataRobotAppFrameworkBaseSettings):
|
|
|
165
175
|
base_url = f"{base_url}/api/v2"
|
|
166
176
|
|
|
167
177
|
url = f"{base_url}/deployments/{self.mcp_deployment_id}/directAccess/mcp"
|
|
178
|
+
headers = self._build_authenticated_headers()
|
|
168
179
|
|
|
169
|
-
|
|
170
|
-
headers = {}
|
|
171
|
-
if self.forwarded_headers:
|
|
172
|
-
headers.update(self.forwarded_headers)
|
|
173
|
-
|
|
174
|
-
# Add authentication headers
|
|
175
|
-
headers.update(self._authorization_bearer_header())
|
|
176
|
-
headers.update(self._authorization_context_header())
|
|
180
|
+
logger.info(f"Using DataRobot hosted MCP deployment: {url}")
|
|
177
181
|
|
|
178
182
|
return {
|
|
179
183
|
"url": url,
|
|
@@ -181,4 +185,34 @@ class MCPConfig(DataRobotAppFrameworkBaseSettings):
|
|
|
181
185
|
"headers": headers,
|
|
182
186
|
}
|
|
183
187
|
|
|
188
|
+
if self.external_mcp_url:
|
|
189
|
+
# External MCP URL - no authentication needed
|
|
190
|
+
headers = {}
|
|
191
|
+
|
|
192
|
+
# Merge external headers if provided
|
|
193
|
+
if self.external_mcp_headers:
|
|
194
|
+
external_headers = json.loads(self.external_mcp_headers)
|
|
195
|
+
headers.update(external_headers)
|
|
196
|
+
|
|
197
|
+
logger.info(f"Using external MCP URL: {self.external_mcp_url}")
|
|
198
|
+
|
|
199
|
+
return {
|
|
200
|
+
"url": self.external_mcp_url.rstrip("/"),
|
|
201
|
+
"transport": self.external_mcp_transport,
|
|
202
|
+
"headers": headers,
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
# No MCP configuration found, setup localhost if running locally
|
|
206
|
+
if self.mcp_server_port:
|
|
207
|
+
url = f"http://localhost:{self.mcp_server_port}"
|
|
208
|
+
if self._check_localhost_server(url):
|
|
209
|
+
headers = self._build_authenticated_headers()
|
|
210
|
+
logger.info(f"Using localhost MCP server: {url}")
|
|
211
|
+
return {
|
|
212
|
+
"url": f"{url}/mcp",
|
|
213
|
+
"transport": "streamable-http",
|
|
214
|
+
"headers": headers,
|
|
215
|
+
}
|
|
216
|
+
logger.warning(f"MCP server is not running or not responding at {url}")
|
|
217
|
+
|
|
184
218
|
return None
|
|
@@ -13,7 +13,7 @@ datarobot_genai/core/cli/__init__.py,sha256=B93Yb6VavoZpatrh8ltCL6YglIfR5FHgytXb
|
|
|
13
13
|
datarobot_genai/core/cli/agent_environment.py,sha256=BJzQoiDvZF5gW4mFE71U0yeg-l72C--kxiE-fv6W194,1662
|
|
14
14
|
datarobot_genai/core/cli/agent_kernel.py,sha256=3XX58DQ6XPpWB_tn5m3iGb3XTfhZf5X3W9tc6ADieU4,7790
|
|
15
15
|
datarobot_genai/core/mcp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
-
datarobot_genai/core/mcp/common.py,sha256=
|
|
16
|
+
datarobot_genai/core/mcp/common.py,sha256=Y8SjuquUODKEfI7T9X-QuTMKdIlpCWFI1b3xs6tmHFA,7812
|
|
17
17
|
datarobot_genai/core/utils/__init__.py,sha256=VxtRUz6iwb04eFQQy0zqTNXLAkYpPXcJxVoKV0nOdXk,59
|
|
18
18
|
datarobot_genai/core/utils/auth.py,sha256=Xo1PxVr6oMgtMHkmHdS02klDKK1cyDpjGvIMF4Tx0Lo,7874
|
|
19
19
|
datarobot_genai/core/utils/urls.py,sha256=tk0t13duDEPcmwz2OnS4vwEdatruiuX8lnxMMhSaJik,2289
|
|
@@ -93,9 +93,9 @@ datarobot_genai/nat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSu
|
|
|
93
93
|
datarobot_genai/nat/agent.py,sha256=siBLDWAff2-JwZ8Q3iNpM_e4_IoSwG9IvY0hyEjNenw,10292
|
|
94
94
|
datarobot_genai/nat/datarobot_llm_clients.py,sha256=IZq_kooUL8QyDTkpEreszLQk9vCzg6-FbTjIkXR9wc0,7203
|
|
95
95
|
datarobot_genai/nat/datarobot_llm_providers.py,sha256=lOVaL_0Fl6-7GFYl3HmfqttqKpKt-2w8o92P3T7B6cU,3683
|
|
96
|
-
datarobot_genai-0.1.
|
|
97
|
-
datarobot_genai-0.1.
|
|
98
|
-
datarobot_genai-0.1.
|
|
99
|
-
datarobot_genai-0.1.
|
|
100
|
-
datarobot_genai-0.1.
|
|
101
|
-
datarobot_genai-0.1.
|
|
96
|
+
datarobot_genai-0.1.69.dist-info/METADATA,sha256=ANM5ghmbD_jGo8UHS87Y63jcMZlZY4Pnm7suIWRdtsg,5918
|
|
97
|
+
datarobot_genai-0.1.69.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
98
|
+
datarobot_genai-0.1.69.dist-info/entry_points.txt,sha256=CZhmZcSyt_RBltgLN_b9xasJD6J5SaDc_z7K0wuOY9Y,150
|
|
99
|
+
datarobot_genai-0.1.69.dist-info/licenses/AUTHORS,sha256=isJGUXdjq1U7XZ_B_9AH8Qf0u4eX0XyQifJZ_Sxm4sA,80
|
|
100
|
+
datarobot_genai-0.1.69.dist-info/licenses/LICENSE,sha256=U2_VkLIktQoa60Nf6Tbt7E4RMlfhFSjWjcJJfVC-YCE,11341
|
|
101
|
+
datarobot_genai-0.1.69.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|