nvidia-nat 1.4.0a20251028__py3-none-any.whl → 1.4.0a20251029__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.
- nat/data_models/common.py +25 -0
- nat/front_ends/mcp/mcp_front_end_config.py +16 -0
- nat/front_ends/mcp/mcp_front_end_plugin.py +76 -41
- nat/front_ends/mcp/mcp_front_end_plugin_worker.py +128 -38
- {nvidia_nat-1.4.0a20251028.dist-info → nvidia_nat-1.4.0a20251029.dist-info}/METADATA +2 -2
- {nvidia_nat-1.4.0a20251028.dist-info → nvidia_nat-1.4.0a20251029.dist-info}/RECORD +11 -11
- {nvidia_nat-1.4.0a20251028.dist-info → nvidia_nat-1.4.0a20251029.dist-info}/WHEEL +0 -0
- {nvidia_nat-1.4.0a20251028.dist-info → nvidia_nat-1.4.0a20251029.dist-info}/entry_points.txt +0 -0
- {nvidia_nat-1.4.0a20251028.dist-info → nvidia_nat-1.4.0a20251029.dist-info}/licenses/LICENSE-3rd-party.txt +0 -0
- {nvidia_nat-1.4.0a20251028.dist-info → nvidia_nat-1.4.0a20251029.dist-info}/licenses/LICENSE.md +0 -0
- {nvidia_nat-1.4.0a20251028.dist-info → nvidia_nat-1.4.0a20251029.dist-info}/top_level.txt +0 -0
nat/data_models/common.py
CHANGED
|
@@ -21,6 +21,8 @@ from hashlib import sha512
|
|
|
21
21
|
from pydantic import AliasChoices
|
|
22
22
|
from pydantic import BaseModel
|
|
23
23
|
from pydantic import Field
|
|
24
|
+
from pydantic import PlainSerializer
|
|
25
|
+
from pydantic import SecretStr
|
|
24
26
|
from pydantic.json_schema import GenerateJsonSchema
|
|
25
27
|
from pydantic.json_schema import JsonSchemaMode
|
|
26
28
|
|
|
@@ -169,3 +171,26 @@ class TypedBaseModel(BaseModel):
|
|
|
169
171
|
|
|
170
172
|
|
|
171
173
|
TypedBaseModelT = typing.TypeVar("TypedBaseModelT", bound=TypedBaseModel)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def get_secret_value(v: SecretStr | None) -> str | None:
|
|
177
|
+
"""
|
|
178
|
+
Extract the secret value from a SecretStr or return None.
|
|
179
|
+
|
|
180
|
+
Parameters
|
|
181
|
+
----------
|
|
182
|
+
v: SecretStr or None.
|
|
183
|
+
A field defined as OptionalSecretStr, which is either a SecretStr or None.
|
|
184
|
+
|
|
185
|
+
Returns
|
|
186
|
+
-------
|
|
187
|
+
str | None
|
|
188
|
+
The secret value as a plain string, or None if v is None.
|
|
189
|
+
"""
|
|
190
|
+
if v is None:
|
|
191
|
+
return None
|
|
192
|
+
return v.get_secret_value()
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
# A SecretStr or None that serializes to plain string
|
|
196
|
+
OptionalSecretStr = typing.Annotated[SecretStr | None, PlainSerializer(get_secret_value)]
|
|
@@ -17,6 +17,7 @@ import logging
|
|
|
17
17
|
from typing import Literal
|
|
18
18
|
|
|
19
19
|
from pydantic import Field
|
|
20
|
+
from pydantic import field_validator
|
|
20
21
|
from pydantic import model_validator
|
|
21
22
|
|
|
22
23
|
from nat.authentication.oauth2.oauth2_resource_server_config import OAuth2ResourceServerConfig
|
|
@@ -47,10 +48,25 @@ class MCPFrontEndConfig(FrontEndBaseConfig, name="mcp"):
|
|
|
47
48
|
description="Transport type for the MCP server (default: streamable-http, backwards compatible with sse)")
|
|
48
49
|
runner_class: str | None = Field(
|
|
49
50
|
default=None, description="Custom worker class for handling MCP routes (default: built-in worker)")
|
|
51
|
+
base_path: str | None = Field(default=None,
|
|
52
|
+
description="Base path to mount the MCP server at (e.g., '/api/v1'). "
|
|
53
|
+
"If specified, the server will be accessible at http://host:port{base_path}/mcp. "
|
|
54
|
+
"If None, server runs at root path /mcp.")
|
|
50
55
|
|
|
51
56
|
server_auth: OAuth2ResourceServerConfig | None = Field(
|
|
52
57
|
default=None, description=("OAuth 2.0 Resource Server configuration for token verification."))
|
|
53
58
|
|
|
59
|
+
@field_validator('base_path')
|
|
60
|
+
@classmethod
|
|
61
|
+
def validate_base_path(cls, v: str | None) -> str | None:
|
|
62
|
+
"""Validate that base_path starts with '/' and doesn't end with '/'."""
|
|
63
|
+
if v is not None:
|
|
64
|
+
if not v.startswith('/'):
|
|
65
|
+
raise ValueError("base_path must start with '/'")
|
|
66
|
+
if v.endswith('/'):
|
|
67
|
+
raise ValueError("base_path must not end with '/'")
|
|
68
|
+
return v
|
|
69
|
+
|
|
54
70
|
# Memory profiling configuration
|
|
55
71
|
enable_memory_profiling: bool = Field(default=False,
|
|
56
72
|
description="Enable memory profiling and diagnostics (default: False)")
|
|
@@ -16,12 +16,14 @@
|
|
|
16
16
|
import logging
|
|
17
17
|
import typing
|
|
18
18
|
|
|
19
|
-
from nat.authentication.oauth2.oauth2_resource_server_config import OAuth2ResourceServerConfig
|
|
20
19
|
from nat.builder.front_end import FrontEndBase
|
|
21
20
|
from nat.builder.workflow_builder import WorkflowBuilder
|
|
22
21
|
from nat.front_ends.mcp.mcp_front_end_config import MCPFrontEndConfig
|
|
23
22
|
from nat.front_ends.mcp.mcp_front_end_plugin_worker import MCPFrontEndPluginWorkerBase
|
|
24
23
|
|
|
24
|
+
if typing.TYPE_CHECKING:
|
|
25
|
+
from mcp.server.fastmcp import FastMCP
|
|
26
|
+
|
|
25
27
|
logger = logging.getLogger(__name__)
|
|
26
28
|
|
|
27
29
|
|
|
@@ -43,7 +45,7 @@ class MCPFrontEndPlugin(FrontEndBase[MCPFrontEndConfig]):
|
|
|
43
45
|
worker_class = self.get_worker_class()
|
|
44
46
|
return f"{worker_class.__module__}.{worker_class.__qualname__}"
|
|
45
47
|
|
|
46
|
-
def _get_worker_instance(self)
|
|
48
|
+
def _get_worker_instance(self):
|
|
47
49
|
"""Get an instance of the worker class."""
|
|
48
50
|
# Import the worker class dynamically if specified in config
|
|
49
51
|
if self.front_end_config.runner_class:
|
|
@@ -56,61 +58,94 @@ class MCPFrontEndPlugin(FrontEndBase[MCPFrontEndConfig]):
|
|
|
56
58
|
|
|
57
59
|
return worker_class(self.full_config)
|
|
58
60
|
|
|
59
|
-
async def _create_token_verifier(self, token_verifier_config: OAuth2ResourceServerConfig):
|
|
60
|
-
"""Create a token verifier based on configuration."""
|
|
61
|
-
from nat.front_ends.mcp.introspection_token_verifier import IntrospectionTokenVerifier
|
|
62
|
-
|
|
63
|
-
if not self.front_end_config.server_auth:
|
|
64
|
-
return None
|
|
65
|
-
|
|
66
|
-
return IntrospectionTokenVerifier(token_verifier_config)
|
|
67
|
-
|
|
68
61
|
async def run(self) -> None:
|
|
69
62
|
"""Run the MCP server."""
|
|
70
|
-
# Import FastMCP
|
|
71
|
-
from mcp.server.fastmcp import FastMCP
|
|
72
|
-
|
|
73
|
-
# Create auth settings and token verifier if auth is required
|
|
74
|
-
auth_settings = None
|
|
75
|
-
token_verifier = None
|
|
76
|
-
|
|
77
63
|
# Build the workflow and add routes using the worker
|
|
78
64
|
async with WorkflowBuilder.from_config(config=self.full_config) as builder:
|
|
79
65
|
|
|
80
|
-
|
|
81
|
-
from mcp.server.auth.settings import AuthSettings
|
|
82
|
-
from pydantic import AnyHttpUrl
|
|
83
|
-
|
|
84
|
-
server_url = f"http://{self.front_end_config.host}:{self.front_end_config.port}"
|
|
85
|
-
|
|
86
|
-
auth_settings = AuthSettings(issuer_url=AnyHttpUrl(self.front_end_config.server_auth.issuer_url),
|
|
87
|
-
required_scopes=self.front_end_config.server_auth.scopes,
|
|
88
|
-
resource_server_url=AnyHttpUrl(server_url))
|
|
89
|
-
|
|
90
|
-
token_verifier = await self._create_token_verifier(self.front_end_config.server_auth)
|
|
91
|
-
|
|
92
|
-
# Create an MCP server with the configured parameters
|
|
93
|
-
mcp = FastMCP(name=self.front_end_config.name,
|
|
94
|
-
host=self.front_end_config.host,
|
|
95
|
-
port=self.front_end_config.port,
|
|
96
|
-
debug=self.front_end_config.debug,
|
|
97
|
-
auth=auth_settings,
|
|
98
|
-
token_verifier=token_verifier)
|
|
99
|
-
|
|
100
|
-
# Get the worker instance and set up routes
|
|
66
|
+
# Get the worker instance
|
|
101
67
|
worker = self._get_worker_instance()
|
|
102
68
|
|
|
69
|
+
# Let the worker create the MCP server (allows plugins to customize)
|
|
70
|
+
mcp = await worker.create_mcp_server()
|
|
71
|
+
|
|
103
72
|
# Add routes through the worker (includes health endpoint and function registration)
|
|
104
73
|
await worker.add_routes(mcp, builder)
|
|
105
74
|
|
|
106
75
|
# Start the MCP server with configurable transport
|
|
107
76
|
# streamable-http is the default, but users can choose sse if preferred
|
|
108
77
|
try:
|
|
109
|
-
|
|
78
|
+
# If base_path is configured, mount server at sub-path using FastAPI wrapper
|
|
79
|
+
if self.front_end_config.base_path:
|
|
80
|
+
if self.front_end_config.transport == "sse":
|
|
81
|
+
logger.warning(
|
|
82
|
+
"base_path is configured but SSE transport does not support mounting at sub-paths. "
|
|
83
|
+
"Use streamable-http transport for base_path support.")
|
|
84
|
+
logger.info("Starting MCP server with SSE endpoint at /sse")
|
|
85
|
+
await mcp.run_sse_async()
|
|
86
|
+
else:
|
|
87
|
+
full_url = f"http://{self.front_end_config.host}:{self.front_end_config.port}{self.front_end_config.base_path}/mcp"
|
|
88
|
+
logger.info(
|
|
89
|
+
"Mounting MCP server at %s/mcp on %s:%s",
|
|
90
|
+
self.front_end_config.base_path,
|
|
91
|
+
self.front_end_config.host,
|
|
92
|
+
self.front_end_config.port,
|
|
93
|
+
)
|
|
94
|
+
logger.info("MCP server URL: %s", full_url)
|
|
95
|
+
await self._run_with_mount(mcp)
|
|
96
|
+
# Standard behavior - run at root path
|
|
97
|
+
elif self.front_end_config.transport == "sse":
|
|
110
98
|
logger.info("Starting MCP server with SSE endpoint at /sse")
|
|
111
99
|
await mcp.run_sse_async()
|
|
112
100
|
else: # streamable-http
|
|
113
|
-
|
|
101
|
+
full_url = f"http://{self.front_end_config.host}:{self.front_end_config.port}/mcp"
|
|
102
|
+
logger.info("MCP server URL: %s", full_url)
|
|
114
103
|
await mcp.run_streamable_http_async()
|
|
115
104
|
except KeyboardInterrupt:
|
|
116
105
|
logger.info("MCP server shutdown requested (Ctrl+C). Shutting down gracefully.")
|
|
106
|
+
|
|
107
|
+
async def _run_with_mount(self, mcp: "FastMCP") -> None:
|
|
108
|
+
"""Run MCP server mounted at configured base_path using FastAPI wrapper.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
mcp: The FastMCP server instance to mount
|
|
112
|
+
"""
|
|
113
|
+
import contextlib
|
|
114
|
+
|
|
115
|
+
import uvicorn
|
|
116
|
+
from fastapi import FastAPI
|
|
117
|
+
|
|
118
|
+
@contextlib.asynccontextmanager
|
|
119
|
+
async def lifespan(_app: FastAPI):
|
|
120
|
+
"""Manage MCP server session lifecycle."""
|
|
121
|
+
logger.info("Starting MCP server session manager...")
|
|
122
|
+
async with contextlib.AsyncExitStack() as stack:
|
|
123
|
+
try:
|
|
124
|
+
# Initialize the MCP server's session manager
|
|
125
|
+
await stack.enter_async_context(mcp.session_manager.run())
|
|
126
|
+
logger.info("MCP server session manager started successfully")
|
|
127
|
+
yield
|
|
128
|
+
except Exception as e:
|
|
129
|
+
logger.error("Failed to start MCP server session manager: %s", e)
|
|
130
|
+
raise
|
|
131
|
+
logger.info("MCP server session manager stopped")
|
|
132
|
+
|
|
133
|
+
# Create a FastAPI wrapper app with lifespan management
|
|
134
|
+
app = FastAPI(
|
|
135
|
+
title=self.front_end_config.name,
|
|
136
|
+
description="MCP server mounted at custom base path",
|
|
137
|
+
lifespan=lifespan,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
# Mount the MCP server's ASGI app at the configured base_path
|
|
141
|
+
app.mount(self.front_end_config.base_path, mcp.streamable_http_app())
|
|
142
|
+
|
|
143
|
+
# Configure and start uvicorn server
|
|
144
|
+
config = uvicorn.Config(
|
|
145
|
+
app,
|
|
146
|
+
host=self.front_end_config.host,
|
|
147
|
+
port=self.front_end_config.port,
|
|
148
|
+
log_level=self.front_end_config.log_level.lower(),
|
|
149
|
+
)
|
|
150
|
+
server = uvicorn.Server(config)
|
|
151
|
+
await server.serve()
|
|
@@ -35,7 +35,12 @@ logger = logging.getLogger(__name__)
|
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
class MCPFrontEndPluginWorkerBase(ABC):
|
|
38
|
-
"""Base class for MCP front end plugin workers.
|
|
38
|
+
"""Base class for MCP front end plugin workers.
|
|
39
|
+
|
|
40
|
+
This abstract base class provides shared utilities and defines the contract
|
|
41
|
+
for MCP worker implementations. Most users should inherit from
|
|
42
|
+
MCPFrontEndPluginWorker instead of this class directly.
|
|
43
|
+
"""
|
|
39
44
|
|
|
40
45
|
def __init__(self, config: Config):
|
|
41
46
|
"""Initialize the MCP worker with configuration.
|
|
@@ -83,15 +88,86 @@ class MCPFrontEndPluginWorkerBase(ABC):
|
|
|
83
88
|
},
|
|
84
89
|
status_code=503)
|
|
85
90
|
|
|
91
|
+
@abstractmethod
|
|
92
|
+
async def create_mcp_server(self) -> FastMCP:
|
|
93
|
+
"""Create and configure the MCP server instance.
|
|
94
|
+
|
|
95
|
+
This is the main extension point. Plugins can return FastMCP or any subclass
|
|
96
|
+
to customize server behavior (for example, add authentication, custom transports).
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
FastMCP instance or a subclass with custom behavior
|
|
100
|
+
"""
|
|
101
|
+
...
|
|
102
|
+
|
|
86
103
|
@abstractmethod
|
|
87
104
|
async def add_routes(self, mcp: FastMCP, builder: WorkflowBuilder):
|
|
88
105
|
"""Add routes to the MCP server.
|
|
89
106
|
|
|
107
|
+
Plugins must implement this method. Most plugins can call
|
|
108
|
+
_default_add_routes() for standard behavior and then add
|
|
109
|
+
custom enhancements.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
mcp: The FastMCP server instance
|
|
113
|
+
builder: The workflow builder instance
|
|
114
|
+
"""
|
|
115
|
+
...
|
|
116
|
+
|
|
117
|
+
async def _default_add_routes(self, mcp: FastMCP, builder: WorkflowBuilder):
|
|
118
|
+
"""Default route registration logic - reusable by subclasses.
|
|
119
|
+
|
|
120
|
+
This is a protected helper method that plugins can call to get
|
|
121
|
+
standard route registration behavior. Plugins typically call this
|
|
122
|
+
from their add_routes() implementation and then add custom features.
|
|
123
|
+
|
|
124
|
+
This method:
|
|
125
|
+
- Sets up the health endpoint
|
|
126
|
+
- Builds the workflow and extracts all functions
|
|
127
|
+
- Filters functions based on tool_names config
|
|
128
|
+
- Registers each function as an MCP tool
|
|
129
|
+
- Sets up debug endpoints for tool introspection
|
|
130
|
+
|
|
90
131
|
Args:
|
|
91
132
|
mcp: The FastMCP server instance
|
|
92
|
-
builder
|
|
133
|
+
builder: The workflow builder instance
|
|
93
134
|
"""
|
|
94
|
-
|
|
135
|
+
from nat.front_ends.mcp.tool_converter import register_function_with_mcp
|
|
136
|
+
|
|
137
|
+
# Set up the health endpoint
|
|
138
|
+
self._setup_health_endpoint(mcp)
|
|
139
|
+
|
|
140
|
+
# Build the workflow and register all functions with MCP
|
|
141
|
+
workflow = await builder.build()
|
|
142
|
+
|
|
143
|
+
# Get all functions from the workflow
|
|
144
|
+
functions = await self._get_all_functions(workflow)
|
|
145
|
+
|
|
146
|
+
# Filter functions based on tool_names if provided
|
|
147
|
+
if self.front_end_config.tool_names:
|
|
148
|
+
logger.info("Filtering functions based on tool_names: %s", self.front_end_config.tool_names)
|
|
149
|
+
filtered_functions: dict[str, Function] = {}
|
|
150
|
+
for function_name, function in functions.items():
|
|
151
|
+
if function_name in self.front_end_config.tool_names:
|
|
152
|
+
# Treat current tool_names as function names, so check if the function name is in the list
|
|
153
|
+
filtered_functions[function_name] = function
|
|
154
|
+
elif any(function_name.startswith(f"{group_name}.") for group_name in self.front_end_config.tool_names):
|
|
155
|
+
# Treat tool_names as function group names, so check if the function name starts with the group name
|
|
156
|
+
filtered_functions[function_name] = function
|
|
157
|
+
else:
|
|
158
|
+
logger.debug("Skipping function %s as it's not in tool_names", function_name)
|
|
159
|
+
functions = filtered_functions
|
|
160
|
+
|
|
161
|
+
# Register each function with MCP, passing workflow context for observability
|
|
162
|
+
for function_name, function in functions.items():
|
|
163
|
+
register_function_with_mcp(mcp, function_name, function, workflow, self.memory_profiler)
|
|
164
|
+
|
|
165
|
+
# Add a simple fallback function if no functions were found
|
|
166
|
+
if not functions:
|
|
167
|
+
raise RuntimeError("No functions found in workflow. Please check your configuration.")
|
|
168
|
+
|
|
169
|
+
# After registration, expose debug endpoints for tool/schema inspection
|
|
170
|
+
self._setup_debug_endpoints(mcp, functions)
|
|
95
171
|
|
|
96
172
|
async def _get_all_functions(self, workflow: Workflow) -> dict[str, Function]:
|
|
97
173
|
"""Get all functions from the workflow.
|
|
@@ -225,48 +301,62 @@ class MCPFrontEndPluginWorkerBase(ABC):
|
|
|
225
301
|
|
|
226
302
|
|
|
227
303
|
class MCPFrontEndPluginWorker(MCPFrontEndPluginWorkerBase):
|
|
228
|
-
"""Default MCP
|
|
304
|
+
"""Default MCP server worker implementation.
|
|
229
305
|
|
|
230
|
-
|
|
231
|
-
|
|
306
|
+
Inherit from this class to create custom MCP workers that extend or modify
|
|
307
|
+
server behavior. Override create_mcp_server() to use a different server type,
|
|
308
|
+
and override add_routes() to add custom functionality.
|
|
232
309
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
310
|
+
Example:
|
|
311
|
+
class CustomWorker(MCPFrontEndPluginWorker):
|
|
312
|
+
async def create_mcp_server(self):
|
|
313
|
+
# Return custom MCP server instance
|
|
314
|
+
return MyCustomFastMCP(...)
|
|
315
|
+
|
|
316
|
+
async def add_routes(self, mcp, builder):
|
|
317
|
+
# Get default routes
|
|
318
|
+
await super().add_routes(mcp, builder)
|
|
319
|
+
# Add custom features
|
|
320
|
+
self._add_my_custom_features(mcp)
|
|
321
|
+
"""
|
|
322
|
+
|
|
323
|
+
async def create_mcp_server(self) -> FastMCP:
|
|
324
|
+
"""Create default MCP server with optional authentication.
|
|
325
|
+
|
|
326
|
+
Returns:
|
|
327
|
+
FastMCP instance configured with settings from NAT config
|
|
236
328
|
"""
|
|
237
|
-
|
|
329
|
+
# Handle auth if configured
|
|
330
|
+
auth_settings = None
|
|
331
|
+
token_verifier = None
|
|
238
332
|
|
|
239
|
-
|
|
240
|
-
|
|
333
|
+
if self.front_end_config.server_auth:
|
|
334
|
+
from mcp.server.auth.settings import AuthSettings
|
|
335
|
+
from pydantic import AnyHttpUrl
|
|
241
336
|
|
|
242
|
-
|
|
243
|
-
|
|
337
|
+
server_url = f"http://{self.front_end_config.host}:{self.front_end_config.port}"
|
|
338
|
+
auth_settings = AuthSettings(issuer_url=AnyHttpUrl(self.front_end_config.server_auth.issuer_url),
|
|
339
|
+
required_scopes=self.front_end_config.server_auth.scopes,
|
|
340
|
+
resource_server_url=AnyHttpUrl(server_url))
|
|
244
341
|
|
|
245
|
-
|
|
246
|
-
|
|
342
|
+
# Create token verifier
|
|
343
|
+
from nat.front_ends.mcp.introspection_token_verifier import IntrospectionTokenVerifier
|
|
247
344
|
|
|
248
|
-
|
|
249
|
-
if self.front_end_config.tool_names:
|
|
250
|
-
logger.info("Filtering functions based on tool_names: %s", self.front_end_config.tool_names)
|
|
251
|
-
filtered_functions: dict[str, Function] = {}
|
|
252
|
-
for function_name, function in functions.items():
|
|
253
|
-
if function_name in self.front_end_config.tool_names:
|
|
254
|
-
# Treat current tool_names as function names, so check if the function name is in the list
|
|
255
|
-
filtered_functions[function_name] = function
|
|
256
|
-
elif any(function_name.startswith(f"{group_name}.") for group_name in self.front_end_config.tool_names):
|
|
257
|
-
# Treat tool_names as function group names, so check if the function name starts with the group name
|
|
258
|
-
filtered_functions[function_name] = function
|
|
259
|
-
else:
|
|
260
|
-
logger.debug("Skipping function %s as it's not in tool_names", function_name)
|
|
261
|
-
functions = filtered_functions
|
|
345
|
+
token_verifier = IntrospectionTokenVerifier(self.front_end_config.server_auth)
|
|
262
346
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
347
|
+
return FastMCP(name=self.front_end_config.name,
|
|
348
|
+
host=self.front_end_config.host,
|
|
349
|
+
port=self.front_end_config.port,
|
|
350
|
+
debug=self.front_end_config.debug,
|
|
351
|
+
auth=auth_settings,
|
|
352
|
+
token_verifier=token_verifier)
|
|
266
353
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
raise RuntimeError("No functions found in workflow. Please check your configuration.")
|
|
354
|
+
async def add_routes(self, mcp: FastMCP, builder: WorkflowBuilder):
|
|
355
|
+
"""Add default routes to the MCP server.
|
|
270
356
|
|
|
271
|
-
|
|
272
|
-
|
|
357
|
+
Args:
|
|
358
|
+
mcp: The FastMCP server instance
|
|
359
|
+
builder: The workflow builder instance
|
|
360
|
+
"""
|
|
361
|
+
# Use the default implementation from base class to add the tools to the MCP server
|
|
362
|
+
await self._default_add_routes(mcp, builder)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nvidia-nat
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.0a20251029
|
|
4
4
|
Summary: NVIDIA NeMo Agent toolkit
|
|
5
5
|
Author: NVIDIA Corporation
|
|
6
6
|
Maintainer: NVIDIA Corporation
|
|
@@ -22,7 +22,7 @@ Requires-Dist: click~=8.1
|
|
|
22
22
|
Requires-Dist: colorama~=0.4.6
|
|
23
23
|
Requires-Dist: datasets~=4.0
|
|
24
24
|
Requires-Dist: expandvars~=1.0
|
|
25
|
-
Requires-Dist: fastapi~=0.
|
|
25
|
+
Requires-Dist: fastapi~=0.120.1
|
|
26
26
|
Requires-Dist: httpx~=0.27
|
|
27
27
|
Requires-Dist: jinja2~=3.1
|
|
28
28
|
Requires-Dist: jsonpath-ng~=1.7
|
|
@@ -116,7 +116,7 @@ nat/data_models/__init__.py,sha256=Xs1JQ16L9btwreh4pdGKwskffAw1YFO48jKrU4ib_7c,6
|
|
|
116
116
|
nat/data_models/agent.py,sha256=IwDyb9Zc3R4Zd5rFeqt7q0EQswczAl5focxV9KozIzs,1625
|
|
117
117
|
nat/data_models/api_server.py,sha256=oQtSiP7jpkHIZ75g21A_lTiidNsQo54pq3qy2StIJcs,30652
|
|
118
118
|
nat/data_models/authentication.py,sha256=XPu9W8nh4XRSuxPv3HxO-FMQ_JtTEoK6Y02JwnzDwTg,8457
|
|
119
|
-
nat/data_models/common.py,sha256=
|
|
119
|
+
nat/data_models/common.py,sha256=0SL3qcQpY1SUJvFsup9HJW62n5ltgXgKMlKdvL6n5Zg,6542
|
|
120
120
|
nat/data_models/component.py,sha256=b_hXOA8Gm5UNvlFkAhsR6kEvf33ST50MKtr5kWf75Ao,1894
|
|
121
121
|
nat/data_models/component_ref.py,sha256=KFDWFVCcvJCfBBcXTh9f3R802EVHBtHXh9OdbRqFmdM,4747
|
|
122
122
|
nat/data_models/config.py,sha256=P0JJmjqvUHUkpZ3Yc0IrMPoA2qP8HkmOjl7CwNq-nQQ,18833
|
|
@@ -262,9 +262,9 @@ nat/front_ends/fastapi/html_snippets/__init__.py,sha256=GUJrgGtpvyMUCjUBvR3faAdv
|
|
|
262
262
|
nat/front_ends/fastapi/html_snippets/auth_code_grant_success.py,sha256=BNpWwzmA58UM0GK4kZXG4PHJy_5K9ihaVHu8SgCs5JA,1131
|
|
263
263
|
nat/front_ends/mcp/__init__.py,sha256=Xs1JQ16L9btwreh4pdGKwskffAw1YFO48jKrU4ib_7c,685
|
|
264
264
|
nat/front_ends/mcp/introspection_token_verifier.py,sha256=s7Q4Q6rWZJ0ZVujSxxpvVI6Bnhkg1LJQ3RLkvhzFIGE,2836
|
|
265
|
-
nat/front_ends/mcp/mcp_front_end_config.py,sha256=
|
|
266
|
-
nat/front_ends/mcp/mcp_front_end_plugin.py,sha256=
|
|
267
|
-
nat/front_ends/mcp/mcp_front_end_plugin_worker.py,sha256=
|
|
265
|
+
nat/front_ends/mcp/mcp_front_end_config.py,sha256=QHmz0OdB6pdUU9TH65NjLk7JsAnR-F6xisel5Bv2Po4,5744
|
|
266
|
+
nat/front_ends/mcp/mcp_front_end_plugin.py,sha256=MVYJBCOhZAzUPlnXest6CYP3Gf0Ef1lbURaezgHpoyg,6701
|
|
267
|
+
nat/front_ends/mcp/mcp_front_end_plugin_worker.py,sha256=qoRbYLC_HWqSH_jSNb-w7R_qwOmLyXaUA5JK0SX33GA,15362
|
|
268
268
|
nat/front_ends/mcp/memory_profiler.py,sha256=OpcpLBAGCdQwYSFZbtAqdfncrnGYVjDcMpWydB71hjY,12811
|
|
269
269
|
nat/front_ends/mcp/register.py,sha256=3aJtgG5VaiqujoeU1-Eq7Hl5pWslIlIwGFU2ASLTXgM,1173
|
|
270
270
|
nat/front_ends/mcp/tool_converter.py,sha256=14NweQN3cPFBw7ZNiGyUHO4VhMGHrtfLGgvu4_H38oU,12426
|
|
@@ -475,10 +475,10 @@ nat/utils/reactive/base/observer_base.py,sha256=6BiQfx26EMumotJ3KoVcdmFBYR_fnAss
|
|
|
475
475
|
nat/utils/reactive/base/subject_base.py,sha256=UQOxlkZTIeeyYmG5qLtDpNf_63Y7p-doEeUA08_R8ME,2521
|
|
476
476
|
nat/utils/settings/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
477
477
|
nat/utils/settings/global_settings.py,sha256=9JaO6pxKT_Pjw6rxJRsRlFCXdVKCl_xUKU2QHZQWWNM,7294
|
|
478
|
-
nvidia_nat-1.4.
|
|
479
|
-
nvidia_nat-1.4.
|
|
480
|
-
nvidia_nat-1.4.
|
|
481
|
-
nvidia_nat-1.4.
|
|
482
|
-
nvidia_nat-1.4.
|
|
483
|
-
nvidia_nat-1.4.
|
|
484
|
-
nvidia_nat-1.4.
|
|
478
|
+
nvidia_nat-1.4.0a20251029.dist-info/licenses/LICENSE-3rd-party.txt,sha256=fOk5jMmCX9YoKWyYzTtfgl-SUy477audFC5hNY4oP7Q,284609
|
|
479
|
+
nvidia_nat-1.4.0a20251029.dist-info/licenses/LICENSE.md,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
|
|
480
|
+
nvidia_nat-1.4.0a20251029.dist-info/METADATA,sha256=tiz911ksuk9pmFsLqH1gUexiw_Y6H5fqLvquikF0_Lo,10248
|
|
481
|
+
nvidia_nat-1.4.0a20251029.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
482
|
+
nvidia_nat-1.4.0a20251029.dist-info/entry_points.txt,sha256=4jCqjyETMpyoWbCBf4GalZU8I_wbstpzwQNezdAVbbo,698
|
|
483
|
+
nvidia_nat-1.4.0a20251029.dist-info/top_level.txt,sha256=lgJWLkigiVZuZ_O1nxVnD_ziYBwgpE2OStdaCduMEGc,8
|
|
484
|
+
nvidia_nat-1.4.0a20251029.dist-info/RECORD,,
|
|
File without changes
|
{nvidia_nat-1.4.0a20251028.dist-info → nvidia_nat-1.4.0a20251029.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
{nvidia_nat-1.4.0a20251028.dist-info → nvidia_nat-1.4.0a20251029.dist-info}/licenses/LICENSE.md
RENAMED
|
File without changes
|
|
File without changes
|