Skip to content

Commit c5cba4b

Browse files
Merge remote-tracking branch 'upstream/release/1.3' into optimizer-doc-fix
# Conflicts: # docs/source/reference/cli.md
2 parents 9698a00 + cb31e79 commit c5cba4b

File tree

58 files changed

+1993
-340
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+1993
-340
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,13 @@ pip install nvidia-nat
8181
NeMo Agent Toolkit has many optional dependencies which can be installed with the core package. Optional dependencies are grouped by framework and can be installed with the core package. For example, to install the LangChain/LangGraph plugin, run the following:
8282

8383
```bash
84-
pip install nvidia-nat[langchain]
84+
pip install "nvidia-nat[langchain]"
8585
```
8686

8787
Or for all optional dependencies:
8888

8989
```bash
90-
pip install nvidia-nat[all]
90+
pip install "nvidia-nat[all]"
9191
```
9292

9393
The full list of optional dependencies can be found [here](./docs/source/quick-start/installing.md#framework-integrations).

docs/source/extend/telemetry-exporters.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -266,14 +266,14 @@ Before creating a custom exporter, check if your observability service is alread
266266
| Service | Type | Installation | Configuration |
267267
|---------|------|-------------|---------------|
268268
| **File** | `file` | `pip install nvidia-nat` | local file or directory |
269-
| **Langfuse** | `langfuse` | `pip install nvidia-nat[opentelemetry]` | endpoint + API keys |
270-
| **LangSmith** | `langsmith` | `pip install nvidia-nat[opentelemetry]` | endpoint + API key |
271-
| **OpenTelemetry Collector** | `otelcollector` | `pip install nvidia-nat[opentelemetry]` | endpoint + headers |
272-
| **Patronus** | `patronus` | `pip install nvidia-nat[opentelemetry]` | endpoint + API key |
273-
| **Galileo** | `galileo` | `pip install nvidia-nat[opentelemetry]` | endpoint + API key |
274-
| **Phoenix** | `phoenix` | `pip install nvidia-nat[phoenix]` | endpoint |
275-
| **RagaAI/Catalyst** | `catalyst` | `pip install nvidia-nat[ragaai]` | API key + project |
276-
| **Weave** | `weave` | `pip install nvidia-nat[weave]` | project name |
269+
| **Langfuse** | `langfuse` | `pip install "nvidia-nat[opentelemetry]"` | endpoint + API keys |
270+
| **LangSmith** | `langsmith` | `pip install "nvidia-nat[opentelemetry]"` | endpoint + API key |
271+
| **OpenTelemetry Collector** | `otelcollector` | `pip install "nvidia-nat[opentelemetry]"` | endpoint + headers |
272+
| **Patronus** | `patronus` | `pip install "nvidia-nat[opentelemetry]"` | endpoint + API key |
273+
| **Galileo** | `galileo` | `pip install "nvidia-nat[opentelemetry]"` | endpoint + API key |
274+
| **Phoenix** | `phoenix` | `pip install "nvidia-nat[phoenix]"` | endpoint |
275+
| **RagaAI/Catalyst** | `catalyst` | `pip install "nvidia-nat[ragaai]"` | API key + project |
276+
| **Weave** | `weave` | `pip install "nvidia-nat[weave]"` | project name |
277277

278278
### Simple Configuration Example
279279

@@ -412,7 +412,7 @@ class CustomSpanExporter(SpanExporter[Span, dict]):
412412
> **Note**: OpenTelemetry exporters require the `nvidia-nat-opentelemetry` subpackage. Install it with:
413413

414414
> ```bash
415-
> pip install nvidia-nat[opentelemetry]
415+
> pip install "nvidia-nat[opentelemetry]"
416416
> ```
417417

418418
For most OTLP-compatible services, use the pre-built `OTLPSpanAdapterExporter`:

docs/source/quick-start/installing.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,13 @@ pip install nvidia-nat
9292
NeMo Agent toolkit has many optional dependencies which can be installed with the core package. Optional dependencies are grouped by framework and can be installed with the core package. For example, to install the LangChain/LangGraph plugin, run the following:
9393

9494
```bash
95-
pip install nvidia-nat[langchain]
95+
pip install "nvidia-nat[langchain]"
9696
```
9797

9898
Or for all optional dependencies:
9999

100100
```bash
101-
pip install nvidia-nat[all]
101+
pip install "nvidia-nat[all]"
102102
```
103103

104104
The full list of optional dependencies can be found [here](../quick-start/installing.md#framework-integrations).

docs/source/reference/api-server-endpoints.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ result back to the client. The transaction schema is defined by the workflow.
6161
## Asynchronous Generate
6262
The asynchronous generate endpoint allows clients to submit a workflow to run in the background and return a response immediately with a unique identifier for the workflow. This can be used to query the status and results of the workflow at a later time. This is useful for long-running workflows, which would otherwise cause the client to time out.
6363

64-
This endpoint is only available when the `async_endpoints` optional dependency extra is installed. For users installing from source, this can be done by running `uv pip install -e '.[async_endpoints]'` from the root directory of the NeMo Agent toolkit library. Similarly, for users installing from PyPI, this can be done by running `pip install 'nvidia-nat[async_endpoints]'`.
64+
This endpoint is only available when the `async_endpoints` optional dependency extra is installed. For users installing from source, this can be done by running `uv pip install -e '.[async_endpoints]'` from the root directory of the NeMo Agent toolkit library. Similarly, for users installing from PyPI, this can be done by running `pip install "nvidia-nat[async_endpoints]"`.
6565

6666
Asynchronous jobs are managed using [Dask](https://docs.dask.org/en/stable/). By default, a local Dask cluster is created at start time, however you can also configure the server to connect to an existing Dask scheduler by setting the `scheduler_address` configuration parameter. The Dask scheduler is used to manage the execution of asynchronous jobs, and can be configured to run on a single machine or across a cluster of machines. Job history and metadata is stored in a SQL database using [SQLAlchemy](https://www.sqlalchemy.org/). By default, a temporary SQLite database is created at start time, however you can also configure the server to use a persistent database by setting the `db_url` configuration parameter. Refer to the [SQLAlchemy documentation](https://docs.sqlalchemy.org/en/20/core/engines.html#database-urls) for the format of the `db_url` parameter. Any database supported by [SQLAlchemy's Asynchronous I/O extension](https://docs.sqlalchemy.org/en/20/orm/extensions/asyncio.html) can be used. Refer to [SQLAlchemy's Dialects](https://docs.sqlalchemy.org/en/20/dialects/index.html) for a complete list (many but not all of these support Asynchronous I/O).
6767

docs/source/reference/cli.md

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,32 +36,43 @@ nat
3636
├── info
3737
│ ├── channels
3838
│ └── components
39-
40-
├── optimize
41-
39+
├── mcp
40+
│ ├── client
41+
│ │ ├── ping
42+
│ │ └── tool
43+
│ │ ├── call
44+
│ │ └── list
45+
│ └── serve
46+
├── object-store
47+
│ ├── mysql
48+
│ │ ├── delete
49+
│ │ └── upload
50+
│ ├── redis
51+
│ │ ├── delete
52+
│ │ └── upload
53+
│ └── s3
54+
│ ├── delete
55+
│ └── upload
56+
├── optimize
4257
├── registry
4358
│ ├── publish
4459
│ ├── pull
4560
│ ├── remove
4661
│ └── search
4762
├── run
4863
├── serve
64+
├── sizing
65+
│ └── calc
4966
├── start
5067
│ ├── console
5168
│ ├── fastapi
5269
│ └── mcp
53-
│ ├── serve
54-
│ └── client
55-
│ ├── ping
56-
│ └── tool
57-
│ ├── list
58-
│ └── call
5970
├── uninstall
6071
├── validate
6172
└── workflow
6273
├── create
63-
├── reinstall
64-
└── delete
74+
├── delete
75+
└── reinstall
6576
```
6677

6778
## Start

docs/source/reference/evaluate-api.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ limitations under the License.
2020
It is recommended that the [Evaluating NeMo Agent toolkit Workflows](./evaluate.md) guide be read before proceeding with this detailed documentation.
2121
:::
2222

23-
The evaluation endpoint can be used to start evaluation jobs on a remote NeMo Agent toolkit server. This endpoint is only available when the `async_endpoints` optional dependency extra is installed. For users installing from source, this can be done by running `uv pip install -e '.[async_endpoints]'` from the root directory of the NeMo Agent toolkit library. Similarly, for users installing from PyPI, this can be done by running `pip install 'nvidia-nat[async_endpoints]'`.
23+
The evaluation endpoint can be used to start evaluation jobs on a remote NeMo Agent toolkit server. This endpoint is only available when the `async_endpoints` optional dependency extra is installed. For users installing from source, this can be done by running `uv pip install -e '.[async_endpoints]'` from the root directory of the NeMo Agent toolkit library. Similarly, for users installing from PyPI, this can be done by running `pip install "nvidia-nat[async_endpoints]"`.
2424

2525
## Evaluation Endpoint Overview
2626
```{mermaid}

docs/source/workflows/evaluate.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ uv pip install -e '.[profiling]'
3434

3535
If you are installing from a package, you can install the sub-package by running the following command:
3636
```bash
37-
uv pip install nvidia-nat[profiling]
37+
uv pip install "nvidia-nat[profiling]"
3838
```
3939

4040
## Evaluating a Workflow

docs/source/workflows/mcp/index.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ NeMo Agent toolkit [Model Context Protocol (MCP)](https://modelcontextprotocol.i
2121
* An [MCP client](./mcp-client.md) to connect to and use tools served by remote MCP servers.
2222
* An [MCP server](./mcp-server.md) to publish tools using MCP to be used by any MCP client.
2323

24-
**Note:** MCP client functionality requires the `nvidia-nat-mcp` package. Install it with `uv pip install nvidia-nat[mcp]`.
24+
**Note:** MCP client functionality requires the `nvidia-nat-mcp` package. Install it with `uv pip install "nvidia-nat[mcp]"`.
2525

2626

2727
```{toctree}
@@ -30,4 +30,5 @@ NeMo Agent toolkit [Model Context Protocol (MCP)](https://modelcontextprotocol.i
3030
Connecting to Remote Tools <./mcp-client.md>
3131
Serving NeMo Agent toolkit Functions <./mcp-server.md>
3232
MCP Authentication <./mcp-auth.md>
33+
Secure Token Storage <./mcp-auth-token-storage.md>
3334
```
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
<!--
2+
SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3+
SPDX-License-Identifier: Apache-2.0
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
-->
17+
18+
# Secure Token Storage for MCP Authentication
19+
20+
The NeMo Agent toolkit provides a configurable, secure token storage mechanism for Model Context Protocol (MCP) OAuth2 authentication. You can store tokens securely using the object store infrastructure, which provides encryption at rest, access controls, and persistence across service restarts.
21+
22+
## Overview
23+
24+
When using MCP with OAuth2 authentication, the toolkit needs to store authentication tokens for each user. The secure token storage feature provides:
25+
26+
- **Encryption at rest**: Tokens are stored in object stores that support encryption
27+
- **Flexible backends**: Choose from in-memory (default), S3, MySQL, Redis, or custom object stores
28+
- **Persistence**: Tokens persist across restarts when using external storage backends
29+
- **Multi-user support**: Tokens are isolated per user with proper access controls
30+
- **Automatic refresh**: Supports OAuth2 token refresh flows
31+
32+
### Components
33+
34+
The token storage system includes three main components:
35+
36+
1. **TokenStorageBase**: Abstract interface defining `store()`, `retrieve()`, `delete()`, and `clear_all()` operations.
37+
2. **InMemoryTokenStorage**: Default implementation using the in-memory object store.
38+
3. **ObjectStoreTokenStorage**: Implementation backed by configurable object stores such as S3, MySQL, and Redis.
39+
40+
## Configuration
41+
42+
### Default Configuration (In-Memory Storage)
43+
44+
By default, MCP OAuth2 authentication uses in-memory storage. No additional configuration is required:
45+
46+
```yaml
47+
authentication:
48+
mcp_oauth2_jira:
49+
_type: mcp_oauth2
50+
server_url: ${CORPORATE_MCP_JIRA_URL}
51+
redirect_uri: http://localhost:8000/auth/redirect
52+
default_user_id: ${CORPORATE_MCP_JIRA_URL}
53+
allow_default_user_id_for_tool_calls: ${ALLOW_DEFAULT_USER_ID_FOR_TOOL_CALLS:-true}
54+
```
55+
56+
This setup is **ONLY suitable for development and testing environments** since it uses in-memory storage that is not
57+
persistent and also unsafe.
58+
59+
### External Object Store Configuration
60+
61+
For production environments, configure an external object store to persist tokens across restarts. The NeMo Agent toolkit supports S3-compatible storage (MinIO, AWS S3), MySQL, and Redis backends.
62+
63+
:::{note}
64+
For detailed object store setup instructions including MinIO, MySQL, and Redis installation and configuration examples, see the `examples/object_store/user_report/README.md` guide (under the "Choose an Object Store" section).
65+
:::
66+
67+
The following example shows token storage configuration using S3-compatible storage (MinIO):
68+
69+
```yaml
70+
object_stores:
71+
token_store:
72+
_type: s3
73+
endpoint_url: http://localhost:9000
74+
access_key: minioadmin
75+
secret_key: minioadmin
76+
bucket_name: my-bucket
77+
78+
function_groups:
79+
mcp_jira:
80+
_type: mcp_client
81+
server:
82+
transport: streamable-http
83+
url: ${CORPORATE_MCP_JIRA_URL}
84+
auth_provider: mcp_oauth2_jira
85+
86+
authentication:
87+
mcp_oauth2_jira:
88+
_type: mcp_oauth2
89+
server_url: ${CORPORATE_MCP_JIRA_URL}
90+
redirect_uri: http://localhost:8000/auth/redirect
91+
default_user_id: ${CORPORATE_MCP_JIRA_URL}
92+
allow_default_user_id_for_tool_calls: ${ALLOW_DEFAULT_USER_ID_FOR_TOOL_CALLS:-true}
93+
token_storage_object_store: token_store
94+
95+
llms:
96+
nim_llm:
97+
_type: nim
98+
model_name: meta/llama-3.1-70b-instruct
99+
temperature: 0.0
100+
max_tokens: 1024
101+
102+
workflow:
103+
_type: react_agent
104+
tool_names:
105+
- mcp_jira
106+
llm_name: nim_llm
107+
verbose: true
108+
retry_parsing_errors: true
109+
max_retries: 3
110+
```
111+
112+
For MySQL or Redis configurations, replace the `object_stores` section with the appropriate object store type. Refer to the [Object Store Documentation](../../store-and-retrieve/object-store.md) for configuration options for each backend.
113+
114+
## Token Storage Format
115+
116+
The system stores tokens as JSON-serialized `AuthResult` objects in the object store with the following structure:
117+
118+
- **Key format**: `tokens/{sha256_hash}` where the hash is computed from the `user_id` to ensure S3 compatibility
119+
- **Content type**: `application/json`
120+
- **Metadata**: Includes token expiration timestamp when available
121+
122+
Example stored token:
123+
```json
124+
{
125+
"credentials": [
126+
{
127+
"kind": "bearer",
128+
"token": "encrypted_token_value",
129+
"scheme": "Bearer",
130+
"header_name": "Authorization"
131+
}
132+
],
133+
"token_expires_at": "2025-10-02T12:00:00Z",
134+
"raw": {
135+
"access_token": "...",
136+
"refresh_token": "...",
137+
"expires_at": 1727870400
138+
}
139+
}
140+
```
141+
142+
## Token Lifecycle
143+
144+
### 1. Initial Authentication
145+
146+
When a user first authenticates, the system completes the following steps:
147+
1. The OAuth2 flow completes and returns an access token.
148+
2. The token is serialized and stored using the configured storage backend.
149+
3. The token is associated with the user's session ID.
150+
151+
### 2. Token Retrieval
152+
153+
On subsequent requests, the system completes the following steps:
154+
1. The user's session ID is extracted from cookies.
155+
2. The stored token is retrieved from the storage backend.
156+
3. The token expiration is checked.
157+
4. If expired, a token refresh is attempted.
158+
159+
### 3. Token Refresh
160+
161+
When a token expires, the system completes the following steps:
162+
1. The refresh token is extracted from the stored token.
163+
2. A new access token is requested from the OAuth2 provider.
164+
3. The new token is stored, replacing the old one.
165+
4. The refreshed token is returned for use.
166+
167+
168+
## Custom Token Storage
169+
170+
You can implement custom token storage by extending the `TokenStorageBase` abstract class:
171+
172+
```python
173+
from nat.plugins.mcp.auth.token_storage import TokenStorageBase
174+
from nat.data_models.authentication import AuthResult
175+
176+
class CustomTokenStorage(TokenStorageBase):
177+
async def store(self, user_id: str, auth_result: AuthResult) -> None:
178+
# Custom storage logic
179+
pass
180+
181+
async def retrieve(self, user_id: str) -> AuthResult | None:
182+
# Custom retrieval logic
183+
pass
184+
185+
async def delete(self, user_id: str) -> None:
186+
# Custom deletion logic
187+
pass
188+
189+
async def clear_all(self) -> None:
190+
# Custom clear logic
191+
pass
192+
```
193+
194+
Then configure your custom storage in the MCP provider initialization.
195+
196+
197+
## Related Documentation
198+
199+
- [MCP Client Configuration](mcp-client.md)
200+
- [Object Store Documentation](../../store-and-retrieve/object-store.md)
201+
- [Authentication API Reference](../../reference/api-authentication.md)
202+
- [Extending Object Stores](../../extend/object-store.md)

docs/source/workflows/mcp/mcp-auth.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ This will use the `mcp_oauth2` authentication provider to authenticate the user.
168168
- The `default_user_id` is used to cache the authenticating user during setup and optionally for tool calls. It is recommended to set `allow_default_user_id_for_tool_calls` to `false` in the authentication configuration for multi-user workflows to avoid accidental tool calls by unauthorized users.
169169
- Use HTTPS redirect URIs in production environments.
170170
- Scope OAuth2 tokens to the minimum required permissions.
171+
- For production deployments, configure [secure token storage](./mcp-auth-token-storage.md) using an external object store (S3, MySQL, or Redis) with encryption enabled.
171172

172173
## Troubleshooting
173174
1. **Setup fails** - This can happen if:
@@ -178,3 +179,8 @@ This will use the `mcp_oauth2` authentication provider to authenticate the user.
178179
- The workflow was not accessed in `WebSocket` mode, or
179180
- The user did not complete the authentication flow through the `WebSocket` UI, or
180181
- The user is not authorized to call the tool
182+
183+
## Related Documentation
184+
- [Secure Token Storage](./mcp-auth-token-storage.md) - Learn about configuring secure token storage for MCP authentication
185+
- [MCP Client](./mcp-client.md) - Connect to and use tools from remote MCP servers
186+
- [Object Store Documentation](../../store-and-retrieve/object-store.md) - Configure object stores for persistent token storage

0 commit comments

Comments
 (0)