nvidia-nat-mcp 1.3.0a20250910__py3-none-any.whl → 1.5.0a20260117__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.
Files changed (42) hide show
  1. nat/meta/pypi.md +3 -3
  2. nat/plugins/mcp/__init__.py +1 -1
  3. nat/plugins/mcp/auth/__init__.py +14 -0
  4. nat/plugins/mcp/auth/auth_flow_handler.py +208 -0
  5. nat/plugins/mcp/auth/auth_provider.py +431 -0
  6. nat/plugins/mcp/auth/auth_provider_config.py +87 -0
  7. nat/plugins/mcp/auth/register.py +33 -0
  8. nat/plugins/mcp/auth/service_account/__init__.py +14 -0
  9. nat/plugins/mcp/auth/service_account/provider.py +136 -0
  10. nat/plugins/mcp/auth/service_account/provider_config.py +137 -0
  11. nat/plugins/mcp/auth/service_account/token_client.py +156 -0
  12. nat/plugins/mcp/auth/token_storage.py +265 -0
  13. nat/plugins/mcp/cli/__init__.py +15 -0
  14. nat/plugins/mcp/cli/commands.py +1094 -0
  15. nat/plugins/mcp/client/__init__.py +15 -0
  16. nat/plugins/mcp/client/client_base.py +665 -0
  17. nat/plugins/mcp/client/client_config.py +146 -0
  18. nat/plugins/mcp/client/client_impl.py +782 -0
  19. nat/plugins/mcp/exception_handler.py +2 -2
  20. nat/plugins/mcp/exceptions.py +1 -1
  21. nat/plugins/mcp/register.py +5 -4
  22. nat/plugins/mcp/server/__init__.py +15 -0
  23. nat/plugins/mcp/server/front_end_config.py +109 -0
  24. nat/plugins/mcp/server/front_end_plugin.py +155 -0
  25. nat/plugins/mcp/server/front_end_plugin_worker.py +415 -0
  26. nat/plugins/mcp/server/introspection_token_verifier.py +72 -0
  27. nat/plugins/mcp/server/memory_profiler.py +320 -0
  28. nat/plugins/mcp/server/register_frontend.py +27 -0
  29. nat/plugins/mcp/server/tool_converter.py +290 -0
  30. nat/plugins/mcp/utils.py +228 -0
  31. {nvidia_nat_mcp-1.3.0a20250910.dist-info → nvidia_nat_mcp-1.5.0a20260117.dist-info}/METADATA +15 -6
  32. nvidia_nat_mcp-1.5.0a20260117.dist-info/RECORD +37 -0
  33. nvidia_nat_mcp-1.5.0a20260117.dist-info/entry_points.txt +9 -0
  34. nvidia_nat_mcp-1.5.0a20260117.dist-info/licenses/LICENSE-3rd-party.txt +5478 -0
  35. nvidia_nat_mcp-1.5.0a20260117.dist-info/licenses/LICENSE.md +201 -0
  36. nat/plugins/mcp/client_base.py +0 -406
  37. nat/plugins/mcp/client_impl.py +0 -229
  38. nat/plugins/mcp/tool.py +0 -133
  39. nvidia_nat_mcp-1.3.0a20250910.dist-info/RECORD +0 -13
  40. nvidia_nat_mcp-1.3.0a20250910.dist-info/entry_points.txt +0 -2
  41. {nvidia_nat_mcp-1.3.0a20250910.dist-info → nvidia_nat_mcp-1.5.0a20260117.dist-info}/WHEEL +0 -0
  42. {nvidia_nat_mcp-1.3.0a20250910.dist-info → nvidia_nat_mcp-1.5.0a20260117.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,265 @@
1
+ # SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ import hashlib
17
+ import json
18
+ import logging
19
+ from abc import ABC
20
+ from abc import abstractmethod
21
+
22
+ from nat.data_models.authentication import AuthResult
23
+ from nat.data_models.authentication import BasicAuthCred
24
+ from nat.data_models.authentication import BearerTokenCred
25
+ from nat.data_models.authentication import CookieCred
26
+ from nat.data_models.authentication import HeaderCred
27
+ from nat.data_models.authentication import QueryCred
28
+ from nat.data_models.object_store import NoSuchKeyError
29
+ from nat.object_store.interfaces import ObjectStore
30
+ from nat.object_store.models import ObjectStoreItem
31
+
32
+ logger = logging.getLogger(__name__)
33
+
34
+
35
+ class TokenStorageBase(ABC):
36
+ """
37
+ Abstract base class for token storage implementations.
38
+
39
+ Token storage implementations handle the secure persistence of authentication
40
+ tokens for MCP OAuth2 flows. Implementations can use various backends such as
41
+ object stores, databases, or in-memory storage.
42
+ """
43
+
44
+ @abstractmethod
45
+ async def store(self, user_id: str, auth_result: AuthResult) -> None:
46
+ """
47
+ Store an authentication result for a user.
48
+
49
+ Args:
50
+ user_id: The unique identifier for the user
51
+ auth_result: The authentication result to store
52
+ """
53
+ pass
54
+
55
+ @abstractmethod
56
+ async def retrieve(self, user_id: str) -> AuthResult | None:
57
+ """
58
+ Retrieve an authentication result for a user.
59
+
60
+ Args:
61
+ user_id: The unique identifier for the user
62
+
63
+ Returns:
64
+ The authentication result if found, None otherwise
65
+ """
66
+ pass
67
+
68
+ @abstractmethod
69
+ async def delete(self, user_id: str) -> None:
70
+ """
71
+ Delete an authentication result for a user.
72
+
73
+ Args:
74
+ user_id: The unique identifier for the user
75
+ """
76
+ pass
77
+
78
+ @abstractmethod
79
+ async def clear_all(self) -> None:
80
+ """
81
+ Clear all stored authentication results.
82
+ """
83
+ pass
84
+
85
+
86
+ class ObjectStoreTokenStorage(TokenStorageBase):
87
+ """
88
+ Token storage implementation backed by a NeMo Agent toolkit object store.
89
+
90
+ This implementation uses the object store infrastructure to persist tokens,
91
+ which provides encryption at rest, access controls, and persistence across
92
+ restarts when using backends like S3, MySQL, or Redis.
93
+ """
94
+
95
+ def __init__(self, object_store: ObjectStore):
96
+ """
97
+ Initialize the object store token storage.
98
+
99
+ Args:
100
+ object_store: The object store instance to use for token persistence
101
+ """
102
+ self._object_store = object_store
103
+
104
+ def _get_key(self, user_id: str) -> str:
105
+ """
106
+ Generate the object store key for a user's token.
107
+
108
+ Uses SHA256 hash to ensure the key is S3-compatible and doesn't
109
+ contain special characters like "://" that are invalid in object keys.
110
+
111
+ Args:
112
+ user_id: The user identifier
113
+
114
+ Returns:
115
+ The object store key
116
+ """
117
+ # Hash the user_id to create an S3-safe key
118
+ user_hash = hashlib.sha256(user_id.encode('utf-8')).hexdigest()
119
+ return f"tokens/{user_hash}"
120
+
121
+ async def store(self, user_id: str, auth_result: AuthResult) -> None:
122
+ """
123
+ Store an authentication result in the object store.
124
+
125
+ Args:
126
+ user_id: The unique identifier for the user
127
+ auth_result: The authentication result to store
128
+ """
129
+ key = self._get_key(user_id)
130
+
131
+ # Serialize the AuthResult to JSON with secrets exposed
132
+ # SecretStr values are masked by default, so we need to expose them manually
133
+ # Create a serializable dict with exposed secrets
134
+ auth_dict = auth_result.model_dump(mode='json')
135
+ # Manually expose SecretStr values in credentials
136
+ for i, cred_obj in enumerate(auth_result.credentials):
137
+ if isinstance(cred_obj, BearerTokenCred):
138
+ auth_dict['credentials'][i]['token'] = cred_obj.token.get_secret_value()
139
+ elif isinstance(cred_obj, BasicAuthCred):
140
+ auth_dict['credentials'][i]['username'] = cred_obj.username.get_secret_value()
141
+ auth_dict['credentials'][i]['password'] = cred_obj.password.get_secret_value()
142
+ elif isinstance(cred_obj, HeaderCred | QueryCred | CookieCred):
143
+ auth_dict['credentials'][i]['value'] = cred_obj.value.get_secret_value()
144
+
145
+ data = json.dumps(auth_dict).encode('utf-8')
146
+
147
+ # Prepare metadata
148
+ metadata = {}
149
+ if auth_result.token_expires_at:
150
+ metadata["expires_at"] = auth_result.token_expires_at.isoformat()
151
+
152
+ # Create the object store item
153
+ item = ObjectStoreItem(data=data, content_type="application/json", metadata=metadata if metadata else None)
154
+
155
+ # Store using upsert to handle both new and existing tokens
156
+ await self._object_store.upsert_object(key, item)
157
+
158
+ async def retrieve(self, user_id: str) -> AuthResult | None:
159
+ """
160
+ Retrieve an authentication result from the object store.
161
+
162
+ Args:
163
+ user_id: The unique identifier for the user
164
+
165
+ Returns:
166
+ The authentication result if found, None otherwise
167
+ """
168
+ key = self._get_key(user_id)
169
+
170
+ try:
171
+ item = await self._object_store.get_object(key)
172
+ # Deserialize the AuthResult from JSON
173
+ auth_result = AuthResult.model_validate_json(item.data)
174
+ return auth_result
175
+ except NoSuchKeyError:
176
+ return None
177
+ except Exception as e:
178
+ logger.error(f"Error deserializing token for user {user_id}: {e}", exc_info=True)
179
+ return None
180
+
181
+ async def delete(self, user_id: str) -> None:
182
+ """
183
+ Delete an authentication result from the object store.
184
+
185
+ Args:
186
+ user_id: The unique identifier for the user
187
+ """
188
+ key = self._get_key(user_id)
189
+
190
+ try:
191
+ await self._object_store.delete_object(key)
192
+ except NoSuchKeyError:
193
+ # Token doesn't exist, which is fine for delete operations
194
+ pass
195
+
196
+ async def clear_all(self) -> None:
197
+ """
198
+ Clear all stored authentication results.
199
+
200
+ Note: This implementation does not support clearing all tokens as the
201
+ object store interface doesn't provide a list operation. Individual
202
+ tokens must be deleted explicitly.
203
+ """
204
+ logger.warning("clear_all() is not supported for ObjectStoreTokenStorage")
205
+
206
+
207
+ class InMemoryTokenStorage(TokenStorageBase):
208
+ """
209
+ In-memory token storage using the built-in object store provided by the NeMo Agent toolkit.
210
+
211
+ This implementation uses the in-memory object store for token persistence,
212
+ which provides a secure default option that doesn't require external storage
213
+ configuration. Tokens are stored in memory and cleared when the process exits.
214
+ """
215
+
216
+ def __init__(self):
217
+ """
218
+ Initialize the in-memory token storage.
219
+ """
220
+ from nat.object_store.in_memory_object_store import InMemoryObjectStore
221
+
222
+ # Create a dedicated in-memory object store for tokens
223
+ self._object_store = InMemoryObjectStore()
224
+
225
+ # Wrap with ObjectStoreTokenStorage for the actual implementation
226
+ self._storage = ObjectStoreTokenStorage(self._object_store)
227
+ logger.debug("Initialized in-memory token storage")
228
+
229
+ async def store(self, user_id: str, auth_result: AuthResult) -> None:
230
+ """
231
+ Store an authentication result in memory.
232
+
233
+ Args:
234
+ user_id: The unique identifier for the user
235
+ auth_result: The authentication result to store
236
+ """
237
+ await self._storage.store(user_id, auth_result)
238
+
239
+ async def retrieve(self, user_id: str) -> AuthResult | None:
240
+ """
241
+ Retrieve an authentication result from memory.
242
+
243
+ Args:
244
+ user_id: The unique identifier for the user
245
+
246
+ Returns:
247
+ The authentication result if found, None otherwise
248
+ """
249
+ return await self._storage.retrieve(user_id)
250
+
251
+ async def delete(self, user_id: str) -> None:
252
+ """
253
+ Delete an authentication result from memory.
254
+
255
+ Args:
256
+ user_id: The unique identifier for the user
257
+ """
258
+ await self._storage.delete(user_id)
259
+
260
+ async def clear_all(self) -> None:
261
+ """
262
+ Clear all stored authentication results from memory.
263
+ """
264
+ # For in-memory storage, we can access the internal storage
265
+ self._object_store._store.clear()
@@ -0,0 +1,15 @@
1
+ # SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ """MCP CLI commands."""