dtlpymcp 0.1.11__tar.gz → 0.1.13__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.
- {dtlpymcp-0.1.11 → dtlpymcp-0.1.13}/PKG-INFO +1 -1
- {dtlpymcp-0.1.11 → dtlpymcp-0.1.13}/dtlpymcp/__init__.py +1 -1
- {dtlpymcp-0.1.11 → dtlpymcp-0.1.13}/dtlpymcp/utils/dtlpy_context.py +34 -9
- {dtlpymcp-0.1.11 → dtlpymcp-0.1.13}/dtlpymcp.egg-info/PKG-INFO +1 -1
- {dtlpymcp-0.1.11 → dtlpymcp-0.1.13}/pyproject.toml +1 -1
- {dtlpymcp-0.1.11 → dtlpymcp-0.1.13}/tests/test_run.py +1 -1
- {dtlpymcp-0.1.11 → dtlpymcp-0.1.13}/MANIFEST.in +0 -0
- {dtlpymcp-0.1.11 → dtlpymcp-0.1.13}/README.md +0 -0
- {dtlpymcp-0.1.11 → dtlpymcp-0.1.13}/dtlpymcp/__main__.py +0 -0
- {dtlpymcp-0.1.11 → dtlpymcp-0.1.13}/dtlpymcp/min_proxy.py +0 -0
- {dtlpymcp-0.1.11 → dtlpymcp-0.1.13}/dtlpymcp/proxy.py +0 -0
- {dtlpymcp-0.1.11 → dtlpymcp-0.1.13}/dtlpymcp.egg-info/SOURCES.txt +0 -0
- {dtlpymcp-0.1.11 → dtlpymcp-0.1.13}/dtlpymcp.egg-info/dependency_links.txt +0 -0
- {dtlpymcp-0.1.11 → dtlpymcp-0.1.13}/dtlpymcp.egg-info/entry_points.txt +0 -0
- {dtlpymcp-0.1.11 → dtlpymcp-0.1.13}/dtlpymcp.egg-info/requires.txt +0 -0
- {dtlpymcp-0.1.11 → dtlpymcp-0.1.13}/dtlpymcp.egg-info/top_level.txt +0 -0
- {dtlpymcp-0.1.11 → dtlpymcp-0.1.13}/setup.cfg +0 -0
- {dtlpymcp-0.1.11 → dtlpymcp-0.1.13}/tests/test_context.py +0 -0
- {dtlpymcp-0.1.11 → dtlpymcp-0.1.13}/tests/test_custom_sources_file.py +0 -0
- {dtlpymcp-0.1.11 → dtlpymcp-0.1.13}/tests/test_list_platform_tools.py +0 -0
- {dtlpymcp-0.1.11 → dtlpymcp-0.1.13}/tests/test_proxy.py +0 -0
|
@@ -20,6 +20,8 @@ logger = logging.getLogger("dtlpymcp")
|
|
|
20
20
|
class MCPSource(BaseModel):
|
|
21
21
|
dpk_name: Optional[str] = None
|
|
22
22
|
app_url: Optional[str] = None
|
|
23
|
+
dpk_version: Optional[str] = None
|
|
24
|
+
app_trusted: Optional[bool] = None
|
|
23
25
|
server_url: Optional[str] = None
|
|
24
26
|
app_jwt: Optional[str] = None
|
|
25
27
|
tools: Optional[List[Tool]] = []
|
|
@@ -60,6 +62,7 @@ class DataloopContext:
|
|
|
60
62
|
sources.append(
|
|
61
63
|
{
|
|
62
64
|
"dpk_name": app.dpk_name,
|
|
65
|
+
"dpk_version": app.dpk_version,
|
|
63
66
|
"app_url": next(iter(app.routes.values())),
|
|
64
67
|
"server_url": None,
|
|
65
68
|
"app_jwt": None,
|
|
@@ -154,6 +157,8 @@ class DataloopContext:
|
|
|
154
157
|
app = apps[0]
|
|
155
158
|
logger.info(f"App: {app.name}")
|
|
156
159
|
source.app_url = next(iter(app.routes.values()))
|
|
160
|
+
dpk = dl.dpks.get(dpk_name=source.dpk_name, dpk_version=source.dpk_version).to_json()
|
|
161
|
+
source.app_trusted = dpk.get('trusted', False)
|
|
157
162
|
session = requests.Session()
|
|
158
163
|
response = session.get(source.app_url, headers=dl.client_api.auth)
|
|
159
164
|
logger.info(f"App route URL: {response.url}")
|
|
@@ -168,14 +173,21 @@ class DataloopContext:
|
|
|
168
173
|
def is_expired(app_jwt: str) -> bool:
|
|
169
174
|
"""
|
|
170
175
|
Check if the APP_JWT is expired.
|
|
176
|
+
|
|
177
|
+
Note: Verification is intentionally skipped - this is only used for
|
|
178
|
+
client-side expiration checking. The server validates the JWT.
|
|
171
179
|
"""
|
|
172
180
|
try:
|
|
173
|
-
decoded = jwt.decode(
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
181
|
+
decoded = jwt.decode(
|
|
182
|
+
app_jwt,
|
|
183
|
+
options={
|
|
184
|
+
"verify_signature": False,
|
|
185
|
+
"verify_exp": False,
|
|
186
|
+
"verify_aud": False,
|
|
187
|
+
"verify_iss": False,
|
|
188
|
+
},
|
|
189
|
+
)
|
|
190
|
+
return decoded.get("exp", 0) < time.time()
|
|
179
191
|
except Exception as e:
|
|
180
192
|
logger.error(f"Error decoding JWT: {e}")
|
|
181
193
|
return True
|
|
@@ -203,9 +215,19 @@ class DataloopContext:
|
|
|
203
215
|
def user_info(token: str) -> dict:
|
|
204
216
|
"""
|
|
205
217
|
Decode a JWT token and return user info.
|
|
218
|
+
|
|
219
|
+
Note: Verification is intentionally skipped - this is only used for
|
|
220
|
+
reading claims client-side. The server validates the JWT.
|
|
206
221
|
"""
|
|
207
|
-
|
|
208
|
-
|
|
222
|
+
return jwt.decode(
|
|
223
|
+
token,
|
|
224
|
+
options={
|
|
225
|
+
"verify_signature": False,
|
|
226
|
+
"verify_exp": False,
|
|
227
|
+
"verify_aud": False,
|
|
228
|
+
"verify_iss": False,
|
|
229
|
+
},
|
|
230
|
+
)
|
|
209
231
|
|
|
210
232
|
async def list_source_tools(self, source: MCPSource) -> Tuple[str, List[dict], Callable]:
|
|
211
233
|
"""
|
|
@@ -214,7 +236,10 @@ class DataloopContext:
|
|
|
214
236
|
if source.server_url is None:
|
|
215
237
|
logger.error("DataloopContext required for DPK servers")
|
|
216
238
|
raise ValueError("DataloopContext required for DPK servers")
|
|
217
|
-
|
|
239
|
+
if source.app_trusted:
|
|
240
|
+
headers = {"authorization": f"Bearer {self.token}", "x-dl-info": f"{self.token}"}
|
|
241
|
+
else:
|
|
242
|
+
headers = {"Cookie": f"JWT-APP={source.app_jwt}", "x-dl-info": f"{self.token}"}
|
|
218
243
|
async with streamablehttp_client(source.server_url, headers=headers) as (read, write, _):
|
|
219
244
|
async with ClientSession(read, write, read_timeout_seconds=timedelta(seconds=60)) as session:
|
|
220
245
|
await session.initialize()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|