nvidia-nat-mcp 1.4.0a20260107__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 (37) hide show
  1. nat/meta/pypi.md +32 -0
  2. nat/plugins/mcp/__init__.py +14 -0
  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 +86 -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 +1051 -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 +211 -0
  20. nat/plugins/mcp/exceptions.py +142 -0
  21. nat/plugins/mcp/register.py +23 -0
  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 +411 -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 +286 -0
  30. nat/plugins/mcp/utils.py +228 -0
  31. nvidia_nat_mcp-1.4.0a20260107.dist-info/METADATA +55 -0
  32. nvidia_nat_mcp-1.4.0a20260107.dist-info/RECORD +37 -0
  33. nvidia_nat_mcp-1.4.0a20260107.dist-info/WHEEL +5 -0
  34. nvidia_nat_mcp-1.4.0a20260107.dist-info/entry_points.txt +9 -0
  35. nvidia_nat_mcp-1.4.0a20260107.dist-info/licenses/LICENSE-3rd-party.txt +5478 -0
  36. nvidia_nat_mcp-1.4.0a20260107.dist-info/licenses/LICENSE.md +201 -0
  37. nvidia_nat_mcp-1.4.0a20260107.dist-info/top_level.txt +1 -0
@@ -0,0 +1,228 @@
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
+ from enum import Enum
17
+ from typing import Any
18
+
19
+ from pydantic import BaseModel
20
+ from pydantic import Field
21
+ from pydantic import create_model
22
+
23
+
24
+ def truncate_session_id(session_id: str, max_length: int = 10) -> str:
25
+ """
26
+ Truncate a session ID for logging purposes.
27
+
28
+ Args:
29
+ session_id: The session ID to truncate
30
+ max_length: Maximum length before truncation (default: 10)
31
+
32
+ Returns:
33
+ Truncated session ID with "..." if longer than max_length, otherwise full ID
34
+ """
35
+ if len(session_id) > max_length:
36
+ return session_id[:max_length] + "..."
37
+ return session_id
38
+
39
+
40
+ def model_from_mcp_schema(name: str, mcp_input_schema: dict) -> type[BaseModel]:
41
+ """
42
+ Create a pydantic model from the input schema of the MCP tool
43
+ """
44
+ _type_map = {
45
+ "string": str,
46
+ "number": float,
47
+ "integer": int,
48
+ "boolean": bool,
49
+ "array": list,
50
+ "null": type(None),
51
+ "object": dict,
52
+ }
53
+
54
+ properties = mcp_input_schema.get("properties", {})
55
+ required_fields = set(mcp_input_schema.get("required", []))
56
+ schema_dict = {}
57
+
58
+ def _generate_valid_classname(class_name: str):
59
+ return class_name.replace('_', ' ').replace('-', ' ').title().replace(' ', '')
60
+
61
+ def _resolve_schema_type(schema: dict[str, Any], name: str) -> Any:
62
+ """
63
+ Recursively resolve a JSON schema to a Python type.
64
+ Handles nested anyOf/oneOf, arrays, objects, enums, and primitive types.
65
+ """
66
+ # Check for anyOf/oneOf first
67
+ any_of = schema.get("anyOf")
68
+ one_of = schema.get("oneOf")
69
+
70
+ if any_of or one_of:
71
+ union_schemas = any_of if any_of else one_of
72
+ resolved_type: Any = None
73
+
74
+ if union_schemas:
75
+ for sub_schema in union_schemas:
76
+ mapped = _resolve_schema_type(sub_schema, name)
77
+ if resolved_type is None:
78
+ resolved_type = mapped
79
+ elif mapped is not type(None):
80
+ # Don't add None here, handle separately
81
+ resolved_type = resolved_type | mapped
82
+ else:
83
+ # If we encounter null, combine with None at the end
84
+ resolved_type = resolved_type | None if resolved_type else type(None)
85
+
86
+ return resolved_type if resolved_type is not None else Any
87
+
88
+ # Handle enum values
89
+ enum_vals = schema.get("enum")
90
+ if enum_vals:
91
+ # Check if enum contains null
92
+ has_null = any(val is None or val == "null" for val in enum_vals)
93
+ # Filter out None/null values from enum
94
+ non_null_vals = [v for v in enum_vals if v is not None and v != "null"]
95
+
96
+ if non_null_vals:
97
+ enum_name = f"{name.capitalize()}Enum"
98
+ enum_type: Any = Enum(enum_name, {item: item for item in non_null_vals})
99
+ # If enum had null, make it a union with None
100
+ return enum_type | None if has_null else enum_type
101
+ elif has_null:
102
+ # Enum only contains null
103
+ return type(None)
104
+ else:
105
+ # Empty enum (shouldn't happen but handle gracefully)
106
+ return Any
107
+
108
+ schema_type = schema.get("type")
109
+
110
+ # Handle type as list (e.g., ["string", "integer", "null"])
111
+ if isinstance(schema_type, list):
112
+ list_type: Any = None
113
+ for t in schema_type:
114
+ if t == "array":
115
+ # Incorporate the mapped type of items
116
+ item_schema = schema.get("items", {})
117
+ if item_schema:
118
+ item_type = _resolve_schema_type(item_schema, name)
119
+ mapped = list[item_type]
120
+ else:
121
+ mapped = _type_map.get(t, Any)
122
+ elif t == "object":
123
+ # Incorporate the mapped type from properties
124
+ if "properties" in schema:
125
+ mapped = model_from_mcp_schema(name=name, mcp_input_schema=schema)
126
+ else:
127
+ mapped = _type_map.get(t, Any)
128
+ else:
129
+ mapped = _type_map.get(t, Any)
130
+
131
+ list_type = mapped if list_type is None else list_type | mapped
132
+ return list_type if list_type is not None else Any
133
+
134
+ # Handle null type
135
+ if schema_type == "null":
136
+ return type(None)
137
+
138
+ # Handle object type
139
+ if schema_type == "object" and "properties" in schema:
140
+ return model_from_mcp_schema(name=name, mcp_input_schema=schema)
141
+
142
+ # Handle array type
143
+ if schema_type == "array" and "items" in schema:
144
+ item_schema = schema.get("items", {})
145
+ # Recursively resolve item type (handles nested anyOf/oneOf)
146
+ item_type = _resolve_schema_type(item_schema, name)
147
+ return list[item_type]
148
+
149
+ # Handle primitive types
150
+ if schema_type is not None:
151
+ return _type_map.get(schema_type, Any)
152
+
153
+ return Any
154
+
155
+ def _has_null_in_type(field_properties: dict[str, Any]) -> bool:
156
+ """Check if a schema contains null as a valid type."""
157
+ # Check anyOf/oneOf for null
158
+ any_of = field_properties.get("anyOf")
159
+ one_of = field_properties.get("oneOf")
160
+ if any_of or one_of:
161
+ union_schemas = any_of if any_of else one_of
162
+ if union_schemas:
163
+ for schema in union_schemas:
164
+ if schema.get("type") == "null":
165
+ return True
166
+
167
+ # Check type list for null
168
+ json_type = field_properties.get("type")
169
+ if isinstance(json_type, list) and "null" in json_type:
170
+ return True
171
+
172
+ # Check enum for null (Python None or string "null")
173
+ enum_vals = field_properties.get("enum")
174
+ if enum_vals:
175
+ for val in enum_vals:
176
+ if val is None or val == "null":
177
+ return True
178
+
179
+ # Check const for null (Python None or string "null")
180
+ if "const" in field_properties:
181
+ const_val = field_properties.get("const")
182
+ if const_val is None or const_val == "null":
183
+ return True
184
+
185
+ return False
186
+
187
+ def _generate_field(field_name: str, field_properties: dict[str, Any]) -> tuple:
188
+ """
189
+ Generate a Pydantic field from JSON schema properties.
190
+ Uses _resolve_schema_type for type resolution and handles field-specific logic.
191
+ """
192
+ # Resolve the field type using the unified resolver
193
+ field_type = _resolve_schema_type(field_properties, field_name)
194
+
195
+ # Check if the type includes null
196
+ has_null = _has_null_in_type(field_properties)
197
+
198
+ # Determine the default value based on whether the field is required
199
+ default_value = field_properties.get("default")
200
+
201
+ if field_name in required_fields:
202
+ # Field is required - use explicit default if provided, otherwise use ... to enforce presence
203
+ if default_value is None and "default" not in field_properties:
204
+ # Required field without explicit default: always use ... even if nullable
205
+ default_value = ...
206
+ # Make the field type nullable if it allows null
207
+ if has_null:
208
+ field_type = field_type | None
209
+ else:
210
+ # Field is optional - use explicit default if provided, otherwise None
211
+ if default_value is None:
212
+ default_value = None
213
+ # Make the type optional if no default was provided and not already nullable
214
+ if "default" not in field_properties and not has_null:
215
+ field_type = field_type | None
216
+
217
+ # Handle nullable property (less common, but still supported)
218
+ nullable = field_properties.get("nullable", False)
219
+ if nullable and not has_null:
220
+ field_type = field_type | None
221
+
222
+ description = field_properties.get("description", "")
223
+
224
+ return field_type, Field(default=default_value, description=description)
225
+
226
+ for field_name, field_props in properties.items():
227
+ schema_dict[field_name] = _generate_field(field_name=field_name, field_properties=field_props)
228
+ return create_model(f"{_generate_valid_classname(name)}InputSchema", **schema_dict)
@@ -0,0 +1,55 @@
1
+ Metadata-Version: 2.4
2
+ Name: nvidia-nat-mcp
3
+ Version: 1.4.0a20260107
4
+ Summary: Subpackage for MCP client integration in NeMo Agent toolkit
5
+ Author: NVIDIA Corporation
6
+ Maintainer: NVIDIA Corporation
7
+ License: Apache-2.0
8
+ Project-URL: documentation, https://docs.nvidia.com/nemo/agent-toolkit/latest/
9
+ Project-URL: source, https://github.com/NVIDIA/NeMo-Agent-Toolkit
10
+ Keywords: ai,rag,agents,mcp
11
+ Classifier: Programming Language :: Python
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Requires-Python: <3.14,>=3.11
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE-3rd-party.txt
18
+ License-File: LICENSE.md
19
+ Requires-Dist: nvidia-nat==v1.4.0a20260107
20
+ Requires-Dist: aiorwlock~=1.5.0
21
+ Requires-Dist: mcp~=1.25
22
+ Dynamic: license-file
23
+
24
+ <!--
25
+ SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
26
+ SPDX-License-Identifier: Apache-2.0
27
+
28
+ Licensed under the Apache License, Version 2.0 (the "License");
29
+ you may not use this file except in compliance with the License.
30
+ You may obtain a copy of the License at
31
+
32
+ http://www.apache.org/licenses/LICENSE-2.0
33
+
34
+ Unless required by applicable law or agreed to in writing, software
35
+ distributed under the License is distributed on an "AS IS" BASIS,
36
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
37
+ See the License for the specific language governing permissions and
38
+ limitations under the License.
39
+ -->
40
+
41
+ ![NVIDIA NeMo Agent Toolkit](https://media.githubusercontent.com/media/NVIDIA/NeMo-Agent-Toolkit/refs/heads/main/docs/source/_static/banner.png "NeMo Agent toolkit banner image")
42
+
43
+
44
+ # NVIDIA NeMo Agent Toolkit MCP Subpackage
45
+ Subpackage for MCP integration in NeMo Agent toolkit.
46
+
47
+ This package provides MCP (Model Context Protocol) functionality, allowing NeMo Agent toolkit workflows to connect to external MCP servers and use their tools as functions.
48
+
49
+ ## Features
50
+
51
+ - Connect to MCP servers via streamable-http, SSE, or stdio transports
52
+ - Wrap individual MCP tools as NeMo Agent toolkit functions
53
+ - Connect to MCP servers and dynamically discover available tools
54
+
55
+ For more information about the NVIDIA NeMo Agent toolkit, please visit the [NeMo Agent toolkit GitHub Repo](https://github.com/NVIDIA/NeMo-Agent-Toolkit).
@@ -0,0 +1,37 @@
1
+ nat/meta/pypi.md,sha256=-P0JFDuIEDuCRryhXejNke80c_b6AeAzMNKMGgS-NT4,1489
2
+ nat/plugins/mcp/__init__.py,sha256=hiEJ2ajB5zhZuZOUHAyHfTA9w9UNhygij7hp4yfA6QE,685
3
+ nat/plugins/mcp/exception_handler.py,sha256=iEVSZFgiKm6Mr2XB3NRYbYBgyK7GJ6LnnPYXs8MYwJI,7653
4
+ nat/plugins/mcp/exceptions.py,sha256=87fm20cBNijam8n0dYx7drwCZqH1zr9tKls2ayfkK0A,5985
5
+ nat/plugins/mcp/register.py,sha256=-_SHPsqmVuFNlo6fwnXpZA9whIlMKifk4vnBfNX33mA,858
6
+ nat/plugins/mcp/utils.py,sha256=5foCyTdCp0p72FvlP_VjkQe6wgWLc9__XCfGk_iAUbY,9116
7
+ nat/plugins/mcp/auth/__init__.py,sha256=hiEJ2ajB5zhZuZOUHAyHfTA9w9UNhygij7hp4yfA6QE,685
8
+ nat/plugins/mcp/auth/auth_flow_handler.py,sha256=BvrclzC1mmVBsUZ2lx6Cv5NNFtMmUDxsTwLAKRrjiWU,9130
9
+ nat/plugins/mcp/auth/auth_provider.py,sha256=c-Y_FIDVUjEUixvqzeh7Sl0r5aiCR9JDyfudnfC6um8,21326
10
+ nat/plugins/mcp/auth/auth_provider_config.py,sha256=qWyeDgieorQC4IziiOxMrITqpyvZGh7w11F7QTKwuCk,4148
11
+ nat/plugins/mcp/auth/register.py,sha256=FEp4L_ff4HQgFI4QDH04NIEIKRvh8bacns957dQlk9g,1759
12
+ nat/plugins/mcp/auth/token_storage.py,sha256=Zuj0tAWqkv8pPt4baeVEL2eEmnCE4AjU4h6eLhyKyKI,9263
13
+ nat/plugins/mcp/auth/service_account/__init__.py,sha256=hiEJ2ajB5zhZuZOUHAyHfTA9w9UNhygij7hp4yfA6QE,685
14
+ nat/plugins/mcp/auth/service_account/provider.py,sha256=Gsb44cy-5Ap_1BcG3Ny9fc94VtfPg4lVrwM3LKeTBA8,5920
15
+ nat/plugins/mcp/auth/service_account/provider_config.py,sha256=rrzHAo1qmK1yI5CNaadNTVsmh5qtYF1UrYz2Q1nLF2E,5332
16
+ nat/plugins/mcp/auth/service_account/token_client.py,sha256=bGAjq_vG8oo8ZoQfRJjEgigGmF0hgF0umaUOWv0_ZOY,5986
17
+ nat/plugins/mcp/cli/__init__.py,sha256=GLpBQw8r1Nj38vIOluSHsTlLINI24tZ_JJbcWWksBJE,709
18
+ nat/plugins/mcp/cli/commands.py,sha256=cBdNXslsihsHOXbS5MoDbabbEB4milfRHLGOTEodDDg,46602
19
+ nat/plugins/mcp/client/__init__.py,sha256=SFdgClH-7zCAAcujmdvtfiqSz3Xe1KVRX7fviW-45Zg,714
20
+ nat/plugins/mcp/client/client_base.py,sha256=jWNwb20qWIUuIJg7Ldp_WgiJlQmYin4YvVSJ9_ECP5c,26831
21
+ nat/plugins/mcp/client/client_config.py,sha256=qrBjXCKHpMoS2A5i9DoXkN7hdYnGy77FBcZDGZlyb4w,7179
22
+ nat/plugins/mcp/client/client_impl.py,sha256=dygcLnhnWnMh7u45aLvYbGEP1uv02uSb886YsOucxgs,36661
23
+ nat/plugins/mcp/server/__init__.py,sha256=Ioza5tZX7qlOicklSVbhcXO3r7EjRLENvV5AtBSusAQ,723
24
+ nat/plugins/mcp/server/front_end_config.py,sha256=yFmEMKcz_ANJnef4Zu4dwGtnfNZ0uzVdc_dYYCLmgCg,5749
25
+ nat/plugins/mcp/server/front_end_plugin.py,sha256=WAqgYFHAswUK1WKk_PIUo6Lyf0pvJLelT3esHhmIHFM,6896
26
+ nat/plugins/mcp/server/front_end_plugin_worker.py,sha256=OBk1sMjH_1coBXj3dYXNWyoK4wofVQERt3_0gLscP4I,17992
27
+ nat/plugins/mcp/server/introspection_token_verifier.py,sha256=oyhZkCTo6u3w7m469DicF57BNmhTPLcMYtWuHvcCsRg,2840
28
+ nat/plugins/mcp/server/memory_profiler.py,sha256=KjJw4ARSmEFult2MorFySiucog0bD8ClI9ZbkJhIwns,12816
29
+ nat/plugins/mcp/server/register_frontend.py,sha256=gfHfQaQ4NhkZkDSrFur1bxbG93kbAGBtumm4eKYOzKE,1178
30
+ nat/plugins/mcp/server/tool_converter.py,sha256=Y-3Cr8jNrRjQFFFmmILIeUI6kO3C_CUpCZ2k9NJnJdk,11339
31
+ nvidia_nat_mcp-1.4.0a20260107.dist-info/licenses/LICENSE-3rd-party.txt,sha256=fOk5jMmCX9YoKWyYzTtfgl-SUy477audFC5hNY4oP7Q,284609
32
+ nvidia_nat_mcp-1.4.0a20260107.dist-info/licenses/LICENSE.md,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
33
+ nvidia_nat_mcp-1.4.0a20260107.dist-info/METADATA,sha256=9otJsZHNUMeKwR5lTUW4cTfwSZ9VKrIcODC38JNm2Mc,2326
34
+ nvidia_nat_mcp-1.4.0a20260107.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
35
+ nvidia_nat_mcp-1.4.0a20260107.dist-info/entry_points.txt,sha256=t5HYRfXR-dyZf6BWRz1u1TqPprKpCWt-WLHKQXfiLLU,231
36
+ nvidia_nat_mcp-1.4.0a20260107.dist-info/top_level.txt,sha256=8-CJ2cP6-f0ZReXe5Hzqp-5pvzzHz-5Ds5H2bGqh1-U,4
37
+ nvidia_nat_mcp-1.4.0a20260107.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,9 @@
1
+ [nat.cli]
2
+ mcp = nat.plugins.mcp.cli.commands:mcp_command
3
+
4
+ [nat.components]
5
+ nat_mcp = nat.plugins.mcp.register
6
+ nat_mcp_auth = nat.plugins.mcp.auth.register
7
+
8
+ [nat.front_ends]
9
+ nat_mcp_server = nat.plugins.mcp.server.register_frontend