Skip to content

Conversation

@AnuradhaKaruppiah
Copy link
Contributor

@AnuradhaKaruppiah AnuradhaKaruppiah commented Oct 22, 2025

Description

This PR updates and documents an extensibility feature in the NeMo Agent Toolkit that allows developers to create custom MCP server workers by subclassing MCPFrontEndPluginWorker.

Developers can now extend MCPFrontEndPluginWorker to implement custom authentication, middleware, telemetry, or transport logic.

Note:
The fast api change in #1117 will be merged before this PR

By Submitting this PR I confirm:

  • I am familiar with the Contributing Guidelines.
  • We require that all contributors "sign-off" on their commits. This certifies that the contribution is your original work, or you have rights to submit it under the same license, or a compatible license.
    • Any contribution which contains commits that are not Signed-Off will not be accepted.
  • When the PR is ready for review, new or existing tests cover these changes.
  • When the PR is ready for review, the documentation is up to date with these changes.

Summary by CodeRabbit

  • New Features

    • Mount MCP server at custom URL paths via new base_path config (validated); SSE is routed at /sse and streamable-http supports mounting at base_path/mcp with updated startup behavior and logs.
    • Pluggable MCP server workers: server creation and route registration are now extensible; optional authentication can be enabled for MCP servers.
  • Documentation

    • New guide for creating/registering custom MCP server workers and docs with mounting-at-path examples and transport compatibility notes.

Signed-off-by: Anuradha Karuppiah <[email protected]>
@AnuradhaKaruppiah AnuradhaKaruppiah self-assigned this Oct 22, 2025
@AnuradhaKaruppiah AnuradhaKaruppiah added improvement Improvement to existing functionality non-breaking Non-breaking change labels Oct 22, 2025
@coderabbitai
Copy link

coderabbitai bot commented Oct 22, 2025

Walkthrough

Delegates MCP server creation and route registration from the plugin to worker classes; adds configurable and validated base_path with mounting support; introduces new worker abstract methods and a default worker implementation (including optional auth wiring); and updates docs and vocabulary for custom MCP workers.

Changes

Cohort / File(s) Summary
Core MCP Plugin
src/nat/front_ends/mcp/mcp_front_end_plugin.py
Removed direct OAuth2/token verifier wiring; _get_worker_instance return annotation removed; run() now obtains worker, awaits create_mcp_server() and add_routes(); added _run_with_mount() to mount MCP under base_path via FastAPI/uvicorn; updated logging and SSE/base_path handling; added TYPE_CHECKING import for FastMCP.
Worker Base & Impl
src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py
Introduced abstract worker contract with async methods create_mcp_server, add_routes, _default_add_routes, _get_all_functions, and _setup_debug_endpoints; implemented default worker MCPFrontEndPluginWorker that creates/configures FastMCP (optional AuthSettings + IntrospectionTokenVerifier), and implements default route registration flow.
MCP Config
src/nat/front_ends/mcp/mcp_front_end_config.py
Added `base_path: str
Docs — Extend Guide
docs/source/extend/mcp-server.md
New guide describing how to implement/register custom MCP server workers, example CustomStatusWorker, usage of add_routes/create_mcp_server, and notes on auth, telemetry, and mounting.
Docs — Workflows
docs/source/workflows/mcp/mcp-server.md
Added "Mounting at Custom Paths" section with base_path YAML example, URL composition, and note that base_path requires streamable-http (SSE unsupported).
Docs — Index
docs/source/index.md
Added "Adding a Custom MCP Server Worker" entry to Extend toctrees.
Vale Vocabulary
ci/vale/styles/config/vocabularies/nat/accept.txt
Added accepted-regex [Mm]iddleware to the vocabulary list.

Sequence Diagram(s)

sequenceDiagram
    participant CLI as User/CLI
    participant Plugin as MCPFrontEndPlugin
    participant Worker as MCPFrontEndPluginWorker
    participant FastMCP as FastMCP
    participant UV as uvicorn

    CLI->>Plugin: run(...)
    Plugin->>Plugin: _get_worker_instance()
    Plugin->>Worker: await create_mcp_server()
    Worker->>Worker: configure auth (optional)
    Worker-->>Plugin: FastMCP instance
    Plugin->>Worker: await add_routes(mcp, builder)
    Worker->>Worker: _default_add_routes() (health, funcs, debug)
    alt base_path configured (streamable-http)
        Plugin->>Plugin: _run_with_mount(mcp) (FastAPI wrapper)
        Plugin->>UV: run uvicorn with mounted app
    else base_path absent or SSE
        Plugin->>FastMCP: start inline (SSE or streamable-http)
    end
    Plugin-->>CLI: server ready / URL logged
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Attention areas:
    • Async/await correctness across create_mcp_server() / add_routes() and callers
    • base_path validation, composition, SSE incompatibility, and mount path correctness
    • Auth wiring in worker (AuthSettings / IntrospectionTokenVerifier) and its optional usage
    • Lifespan/context management in _run_with_mount() and FastAPI/uvicorn integration
    • New/renamed worker base types and cross-module references (type hints / TYPE_CHECKING)

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "Support custom MCP server implementations" is fully related to the main changeset. The PR's core objective is to enable developers to create custom MCP server implementations by introducing an extensible architecture with abstract methods on MCPFrontEndPluginWorkerBase, providing concrete implementation examples, adding configuration options like base_path, and delivering comprehensive documentation. The title uses imperative mood ("Support"), is concise at 41 characters (well under the 72-character limit), and clearly summarizes the primary intent of the changes.
Docstring Coverage ✅ Passed Docstring coverage is 94.59% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@AnuradhaKaruppiah AnuradhaKaruppiah changed the title Changes to allow custom mcp servers Changes to allow custom MCP servers Oct 27, 2025
@AnuradhaKaruppiah AnuradhaKaruppiah force-pushed the ak-nat-mcp-custom-frontend branch from 8f15f7b to 2a5be28 Compare October 27, 2025 21:48
@AnuradhaKaruppiah
Copy link
Contributor Author

@CodeRabbit review full

@coderabbitai
Copy link

coderabbitai bot commented Oct 27, 2025

@AnuradhaKaruppiah: I'll perform a full review of all the changes in this PR.

✅ Actions performed

Full review triggered.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
pyproject.toml (1)

1-1: Missing SPDX header (compliance).

All files must start with the standard SPDX Apache-2.0 header. Add it at the top.

As per coding guidelines.

Apply this diff:

+## SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+## SPDX-License-Identifier: Apache-2.0
+
 [build-system]
 build-backend = "setuptools.build_meta"
 requires = ["setuptools >= 64", "setuptools-scm>=8"]
src/nat/front_ends/mcp/mcp_front_end_plugin.py (1)

45-57: Validate custom worker type.

Ensure the dynamically loaded class is a subclass of McpServerWorker to avoid runtime errors.

         if self.front_end_config.runner_class:
             module_name, class_name = self.front_end_config.runner_class.rsplit(".", 1)
             import importlib
             module = importlib.import_module(module_name)
             worker_class = getattr(module, class_name)
         else:
             worker_class = self.get_worker_class()
 
+        if not issubclass(worker_class, McpServerWorker):
+            raise TypeError(
+                f"Configured runner_class {worker_class!r} must subclass McpServerWorker."
+            )
+
         return worker_class(self.full_config)
🧹 Nitpick comments (12)
src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py (4)

16-21: Add a module-level docstring.

Public modules must include a concise Google‑style module docstring.

As per coding guidelines.

 import logging
 from abc import ABC
 from abc import abstractmethod
 from collections.abc import Mapping
 from typing import Any
 
+"""MCP server worker base classes and default implementation."""

239-246: Preserve order when parsing repeated/comma-separated name params.

Current set() drops order. Deduplicate while preserving client-specified order.

-            names_param_list = set(request.query_params.getlist("name"))
-            names: list[str] = []
-            for raw in names_param_list:
-                # if p.strip() is empty, it won't be included in the list!
-                parts = [p.strip() for p in raw.split(",") if p.strip()]
-                names.extend(parts)
+            raw_names = request.query_params.getlist("name")
+            parts: list[str] = []
+            for raw in raw_names:
+                parts.extend([p.strip() for p in raw.split(",") if p.strip()])
+            # Deduplicate while preserving order
+            names = list(dict.fromkeys(parts))

71-101: Health check relies on private MCP internals.

Using mcp._mcp_server.request_handlers[...] is fragile across MCP versions. Prefer a public API or add a safe fallback.

Consider:

  • If MCP exposes a ping method, call it.
  • Otherwise, catch KeyError/AttributeError explicitly and return healthy if app starts, logging at debug.

Would you like me to propose a compatibility shim that tries multiple strategies?


230-318: 404 detail echoes user input; constrain exposure.

Minor hardening: limit length and sanitize the tool name in error messages.

-            except KeyError as e:
-                    raise HTTPException(status_code=404, detail=f"Tool \"{e.args[0]}\" not found.") from e
+            except KeyError as e:
+                missing = str(e.args[0])[:100]
+                raise HTTPException(status_code=404, detail=f'Tool "{missing}" not found.') from e
tests/nat/front_ends/mcp/test_mcp_custom_server.py (4)

140-150: Align fixture naming with project conventions.

Use fixture_ prefix and set name= to keep the public fixture name.

As per coding guidelines.

-@pytest.fixture
-def base_config():
+@pytest.fixture(name="base_config")
+def fixture_base_config():
     """Create base config for testing."""
     echo_function_config = EchoFunctionConfig()
 
     mcp_front_end_config = MCPFrontEndConfig(name="Test Server", host="localhost", port=9999)
 
     return Config(general=GeneralConfig(front_end=mcp_front_end_config),
                   workflow=echo_function_config,
                   functions={"echo": echo_function_config})

327-332: Fix Ruff ARG001 by ignoring or prefixing unused arg.

Rename the unused parameter to _request.

-    async def mock_call_next(request):
+    async def mock_call_next(_request):
         return mock_response

292-297: Avoid asserting private attributes.

builder._workflow is private and may change. Prefer asserting via public behavior (e.g., call list-tools endpoint or check MCP registration if a public API exists).

If there's no public accessor, consider exposing a minimal getter in WorkflowBuilder for tests. Do you want me to draft that?


282-293: Middleware assertion: make it robust.

Instead of len(user_middleware) > 0, assert that our logging middleware is present.

assert any(getattr(m.cls, "__name__", "") == "log_requests" for m in mcp.app.user_middleware)
docs/source/extend/custom-mcp-worker.md (4)

156-163: Add language to fenced code block.

Label the “Expected output” block as text.

-```
+```text
 INFO:     Started server process [12345]
 INFO:     Waiting for application startup.
 INFO:     Application startup complete.
 INFO:     Uvicorn running on http://localhost:9000 (Press CTRL+C to quit)

---

`176-181`: **Add language to fenced code block.**

Label the “Observe the logs” block as text.


```diff
-```
+```text
 INFO:my_package.logging_worker:Request: POST /tools/call
 INFO:my_package.logging_worker:Response: 200 (0.45s)

---

`205-216`: **Hyphenate “front-end” in prose.**

Minor style fix.


```diff
-- **`self.front_end_config`**: MCP server configuration
+- **`self.front_end_config`**: MCP server configuration
   - `name`: Server name
-  - `host`: Server host address
-  - `port`: Server port number
-  - `debug`: Debug mode flag
+  - `host`: Server host address
+  - `port`: Server port number
+  - `debug`: Debug-mode flag

20-22: Update cross-reference wording.

Avoid “NAT” and clarify the reference.

-We recommend reading the [MCP Server Guide](../workflows/mcp/mcp-server.md) before proceeding with this documentation, to understand how MCP servers work in NAT.
+We recommend reading the [MCP Server Guide](../workflows/mcp/mcp-server.md) before proceeding, to understand how MCP servers work in the NeMo Agent toolkit.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a9b81db and 2a5be28.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • docs/source/extend/custom-mcp-worker.md (1 hunks)
  • pyproject.toml (1 hunks)
  • src/nat/front_ends/mcp/mcp_front_end_plugin.py (3 hunks)
  • src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py (3 hunks)
  • tests/nat/front_ends/mcp/test_mcp_custom_server.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (12)
{**/*.py,**/*.sh,**/*.md,**/*.toml,**/*.y?(a)ml,**/*.json,**/*.txt,**/*.ini,**/*.cfg,**/*.ipynb}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

{**/*.py,**/*.sh,**/*.md,**/*.toml,**/*.y?(a)ml,**/*.json,**/*.txt,**/*.ini,**/*.cfg,**/*.ipynb}: Every file must start with the standard SPDX Apache-2.0 header
Confirm copyright years are up to date when a file is changed
All source files must include the SPDX Apache-2.0 header template (copy from an existing file)

Files:

  • pyproject.toml
  • src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py
  • docs/source/extend/custom-mcp-worker.md
  • tests/nat/front_ends/mcp/test_mcp_custom_server.py
  • src/nat/front_ends/mcp/mcp_front_end_plugin.py
{**/pyproject.toml,uv.lock}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

New dependencies must be added to both pyproject.toml (alphabetically) and uv.lock via ‘uv pip install --sync’

Files:

  • pyproject.toml
**/*

⚙️ CodeRabbit configuration file

**/*: # Code Review Instructions

  • Ensure the code follows best practices and coding standards. - For Python code, follow
    PEP 20 and
    PEP 8 for style guidelines.
  • Check for security vulnerabilities and potential issues. - Python methods should use type hints for all parameters and return values.
    Example:
    def my_function(param1: int, param2: str) -> bool:
        pass
  • For Python exception handling, ensure proper stack trace preservation:
    • When re-raising exceptions: use bare raise statements to maintain the original stack trace,
      and use logger.error() (not logger.exception()) to avoid duplicate stack trace output.
    • When catching and logging exceptions without re-raising: always use logger.exception()
      to capture the full stack trace information.

Documentation Review Instructions - Verify that documentation and comments are clear and comprehensive. - Verify that the documentation doesn't contain any TODOs, FIXMEs or placeholder text like "lorem ipsum". - Verify that the documentation doesn't contain any offensive or outdated terms. - Verify that documentation and comments are free of spelling mistakes, ensure the documentation doesn't contain any

words listed in the ci/vale/styles/config/vocabularies/nat/reject.txt file, words that might appear to be
spelling mistakes but are listed in the ci/vale/styles/config/vocabularies/nat/accept.txt file are OK.

Misc. - All code (except .mdc files that contain Cursor rules) should be licensed under the Apache License 2.0,

and should contain an Apache License 2.0 header comment at the top of each file.

  • Confirm that copyright years are up-to date whenever a file is changed.

Files:

  • pyproject.toml
  • src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py
  • docs/source/extend/custom-mcp-worker.md
  • tests/nat/front_ends/mcp/test_mcp_custom_server.py
  • src/nat/front_ends/mcp/mcp_front_end_plugin.py
**/*.py

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.py: In code comments use the abbreviations: nat (API namespace/CLI), nvidia-nat (package), NAT (env var prefixes); never use these abbreviations in documentation
Follow PEP 20 and PEP 8 for Python style
Run yapf with column_limit=120; yapf is used for formatting (run second)
Indent with 4 spaces (no tabs) and end each file with a single trailing newline
Use ruff (ruff check --fix) as a linter (not formatter) per pyproject.toml; fix warnings unless explicitly ignored
Respect Python naming schemes: snake_case for functions/variables, PascalCase for classes, UPPER_CASE for constants
When re-raising exceptions, use bare raise to preserve stack trace; log with logger.error(), not logger.exception()
When catching and logging without re-raising, use logger.exception() to capture full stack trace
Provide Google-style docstrings for every public module, class, function, and CLI command
Docstring first line must be a concise description ending with a period
Validate and sanitize all user input, especially in web or CLI interfaces
Prefer httpx with SSL verification enabled by default and follow OWASP Top-10 recommendations
Use async/await for I/O-bound work (HTTP, DB, file I/O)
Cache expensive computations with functools.lru_cache or an external cache when appropriate
Leverage NumPy vectorized operations when beneficial and feasible

Files:

  • src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py
  • tests/nat/front_ends/mcp/test_mcp_custom_server.py
  • src/nat/front_ends/mcp/mcp_front_end_plugin.py
{src/**/*.py,packages/*/src/**/*.py}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

{src/**/*.py,packages/*/src/**/*.py}: All importable Python code must live under src/ or packages//src/
All public APIs must have Python 3.11+ type hints on parameters and return values
Prefer typing/collections.abc abstractions (e.g., Sequence over list)
Use typing.Annotated for units or metadata when useful
Treat pyright warnings as errors during development

Files:

  • src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py
  • src/nat/front_ends/mcp/mcp_front_end_plugin.py
src/nat/**/*

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

src/nat/**/* contains core functionality; changes should prioritize backward compatibility

Files:

  • src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py
  • src/nat/front_ends/mcp/mcp_front_end_plugin.py

⚙️ CodeRabbit configuration file

This directory contains the core functionality of the toolkit. Changes should prioritize backward compatibility.

Files:

  • src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py
  • src/nat/front_ends/mcp/mcp_front_end_plugin.py
{docs/source/**/*.md,**/README.@(md|ipynb)}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

{docs/source/**/*.md,**/README.@(md|ipynb)}: Use the full name “NVIDIA NeMo Agent toolkit” on first use in documentation, then “NeMo Agent toolkit”; in headings use “NeMo Agent Toolkit” (capital T)
Do not use deprecated names (Agent Intelligence toolkit, aiqtoolkit, AgentIQ, AIQ/aiq) in documentation unless explicitly referring to deprecated names
Never use “NAT”/“nat” abbreviations in documentation
Documentation must be clear/comprehensive; avoid TODOs/FIXMEs/placeholders; avoid offensive/outdated terms; ensure spelling is correct

Files:

  • docs/source/extend/custom-mcp-worker.md
docs/source/**/*.md

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

docs/source/**/*.md: Documentation sources are Markdown files under docs/source
Surround code entities with backticks in docs to avoid Vale false positives
Do not use words listed in ci/vale/styles/config/vocabularies/nat/reject.txt; accepted words in accept.txt are allowed

Files:

  • docs/source/extend/custom-mcp-worker.md
docs/source/**/*

⚙️ CodeRabbit configuration file

This directory contains the source code for the documentation. All documentation should be written in Markdown format. Any image files should be placed in the docs/source/_static directory.

Files:

  • docs/source/extend/custom-mcp-worker.md
{tests/**/*.py,examples/*/tests/**/*.py}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

Unit tests live in tests/ or examples/*/tests and use markers defined in pyproject.toml (e.g., integration)

Files:

  • tests/nat/front_ends/mcp/test_mcp_custom_server.py
{tests/**/*.py,examples/*/tests/**/*.py,packages/*/tests/**/*.py}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

{tests/**/*.py,examples/*/tests/**/*.py,packages/*/tests/**/*.py}: Use pytest with pytest-asyncio for async code
Test functions should be named with test_ prefix using snake_case
Extract frequently repeated test code into pytest fixtures
Pytest fixtures should define the name argument in @pytest.fixture and the function should be prefixed fixture_ using snake_case
Mock external services with pytest_httpserver or unittest.mock; avoid live endpoints
Mark slow tests with @pytest.mark.slow to skip in default test suite
Mark integration tests requiring external services with @pytest.mark.integration and follow nat-tests guidelines

Files:

  • tests/nat/front_ends/mcp/test_mcp_custom_server.py
tests/**/*.py

⚙️ CodeRabbit configuration file

tests/**/*.py: - Ensure that tests are comprehensive, cover edge cases, and validate the functionality of the code. - Test functions should be named using the test_ prefix, using snake_case. - Any frequently repeated code should be extracted into pytest fixtures. - Pytest fixtures should define the name argument when applying the pytest.fixture decorator. The fixture
function being decorated should be named using the fixture_ prefix, using snake_case. Example:
@pytest.fixture(name="my_fixture")
def fixture_my_fixture():
pass

Files:

  • tests/nat/front_ends/mcp/test_mcp_custom_server.py
🪛 LanguageTool
docs/source/extend/custom-mcp-worker.md

[style] ~45-~45: Consider using “who” when you are referring to a person instead of an object.
Context: ...ollowing example shows a minimal worker that adds request logging middleware. Each ...

(THAT_WHO)


[grammar] ~216-~216: Use a hyphen to join words.
Context: ...neral: General settings including front end config - llms`: LLM configuration...

(QB_NEW_EN_HYPHEN)

🪛 markdownlint-cli2 (0.18.1)
docs/source/extend/custom-mcp-worker.md

157-157: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


177-177: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Ruff (0.14.1)
src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py

193-193: Avoid specifying long messages outside the exception class

(TRY003)

tests/nat/front_ends/mcp/test_mcp_custom_server.py

327-327: Unused function argument: request

(ARG001)

🔇 Additional comments (2)
docs/source/extend/custom-mcp-worker.md (1)

1-16: Header looks good.

SPDX block present and correct.

pyproject.toml (1)

27-27: Based on my verification of the lock file and web research, the FastAPI 0.120.0 update in the codebase is properly reflected:

  • FastAPI 0.120.0 contains a transition to the annotated_doc.Doc package, with no new dependency constraints introduced
  • Earlier versions bumped Starlette to allow up to 0.46.0 with constraint >=0.40.0,<0.47.0, which means Starlette 0.46.2 is compatible
  • The uv.lock file confirms FastAPI 0.120.0 is pinned, Uvicorn 0.35.0 satisfies the <0.36 constraint, and Starlette 0.46.2 falls within the expected version range

The lock file is consistent with pyproject.toml specifications and no compatibility conflicts are present.

Signed-off-by: Anuradha Karuppiah <[email protected]>
Signed-off-by: Anuradha Karuppiah <[email protected]>
Signed-off-by: Anuradha Karuppiah <[email protected]>
Signed-off-by: Anuradha Karuppiah <[email protected]>
Signed-off-by: Anuradha Karuppiah <[email protected]>
Signed-off-by: Anuradha Karuppiah <[email protected]>
Signed-off-by: Anuradha Karuppiah <[email protected]>
@AnuradhaKaruppiah AnuradhaKaruppiah marked this pull request as ready for review October 28, 2025 02:47
@AnuradhaKaruppiah AnuradhaKaruppiah requested review from a team as code owners October 28, 2025 02:47
@AnuradhaKaruppiah
Copy link
Contributor Author

@CodeRabbit review full

@coderabbitai
Copy link

coderabbitai bot commented Oct 28, 2025

@AnuradhaKaruppiah: I'll perform a full review of all the changes in this PR again.

✅ Actions performed

Full review triggered.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ci/vale/styles/config/vocabularies/nat/accept.txt (1)

1-4: Add SPDX header to comply with repo policy.

This .txt file lacks the required SPDX Apache-2.0 header. Please prepend it as comments.

As per coding guidelines.

+# SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+# SPDX-License-Identifier: Apache-2.0
+
 # List of case-sensitive regular expressions matching words that should be accepted by Vale. For product names like
 # "cuDF" or "cuML", we want to ensure that they are capitalized the same way they're written by the product owners.
 # Regular expressions are parsed according to the Go syntax: https://golang.org/pkg/regexp/syntax/
♻️ Duplicate comments (1)
src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py (1)

184-186: Gate debug endpoints behind a config flag.

Only register debug endpoints when debug is enabled to avoid exposing internal metadata.

-        # After registration, expose debug endpoints for tool/schema inspection
-        self._setup_debug_endpoints(mcp, functions)
+        # Expose debug endpoints only in debug mode
+        if self.front_end_config.debug:
+            self._setup_debug_endpoints(mcp, functions)

As per coding guidelines.

🧹 Nitpick comments (10)
docs/source/extend/mcp-server.md (1)

136-141: Specify a language for the fenced block.

markdownlint MD040: add a language (e.g., text) to the “Expected output” block.

-```
+```text
 INFO:     Started server process [12345]
 INFO:     Waiting for application startup.
 INFO:     Application startup complete.
 INFO:     Uvicorn running on http://localhost:9000 (Press CTRL+C to quit)
As per coding guidelines.

</blockquote></details>
<details>
<summary>src/nat/front_ends/mcp/mcp_front_end_plugin.py (1)</summary><blockquote>

`45-57`: **Add return type and validate configured worker class.**

Annotate return type and guard against misconfiguration with issubclass + clearer import errors.


```diff
-    def _get_worker_instance(self):
+    def _get_worker_instance(self) -> MCPFrontEndPluginWorkerBase:
         """Get an instance of the worker class."""
         # Import the worker class dynamically if specified in config
-        if self.front_end_config.runner_class:
-            module_name, class_name = self.front_end_config.runner_class.rsplit(".", 1)
-            import importlib
-            module = importlib.import_module(module_name)
-            worker_class = getattr(module, class_name)
+        if self.front_end_config.runner_class:
+            module_name, class_name = self.front_end_config.runner_class.rsplit(".", 1)
+            import importlib
+            try:
+                module = importlib.import_module(module_name)
+                worker_class = getattr(module, class_name)
+            except (ModuleNotFoundError, AttributeError) as e:
+                raise ImportError(f"Cannot import worker '{self.front_end_config.runner_class}': {e}") from e
         else:
             worker_class = self.get_worker_class()
 
+        if not issubclass(worker_class, MCPFrontEndPluginWorkerBase):
+            raise TypeError(f"Configured worker '{worker_class.__module__}.{worker_class.__qualname__}' "
+                            f"must subclass MCPFrontEndPluginWorkerBase")
         return worker_class(self.full_config)

As per coding guidelines.

src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py (8)

45-59: Annotate init return type.

Prefer explicit -> None on init for consistency with project typing rules.

-    def __init__(self, config: Config):
+    def __init__(self, config: Config) -> None:

As per coding guidelines.


60-66: Add explicit return type.

Annotate helper with -> None.

-    def _setup_health_endpoint(self, mcp: FastMCP):
+    def _setup_health_endpoint(self, mcp: FastMCP) -> None:

As per coding guidelines.


71-76: Avoid relying on private attributes in health check.

Accessing mcp._mcp_server.request_handlers is fragile. Guard with getattr and fall back to a public ping if available.

-            # Call the ping handler directly (same one that responds to MCP pings)
-            await mcp._mcp_server.request_handlers[PingRequest](ping_request)
+            # Prefer public API; fall back carefully if needed
+            handler = getattr(getattr(mcp, "_mcp_server", None), "request_handlers", {}).get(PingRequest)  # type: ignore[attr-defined]
+            if callable(handler):
+                await handler(ping_request)
+            elif hasattr(mcp, "ping"):
+                # type: ignore[attr-defined]
+                await mcp.ping()  # public ping if exposed by FastMCP
+            else:
+                raise RuntimeError("Ping handler not available via public or known internal API")

If FastMCP exposes a canonical ping API, consider switching to it directly.


110-129: Add return type annotation for add_routes.

The abstract and overrides should declare -> None.

-    async def add_routes(self, mcp: FastMCP, builder: WorkflowBuilder):
+    async def add_routes(self, mcp: FastMCP, builder: WorkflowBuilder) -> None:

Apply the same to concrete overrides below.
As per coding guidelines.


132-149: Add return type annotation.

mark helper as returning None for consistency.

-    async def _default_add_routes(self, mcp: FastMCP, builder: WorkflowBuilder):
+    async def _default_add_routes(self, mcp: FastMCP, builder: WorkflowBuilder) -> None:

As per coding guidelines.


180-183: Comment/code mismatch.

Comment says “Add a simple fallback function if no functions were found” but code raises RuntimeError. Align the comment or implement a real fallback.

-        # Add a simple fallback function if no functions were found
+        # If no functions were found, raise an error to surface misconfiguration

348-367: Pydantic URL construction: avoid calling AnyHttpUrl(...) directly.

Let Pydantic validate from strings (or use TypeAdapter) to reduce runtime coupling to pydantic internals.

-            from pydantic import AnyHttpUrl
-
             server_url = f"http://{self.front_end_config.host}:{self.front_end_config.port}"
-            auth_settings = AuthSettings(issuer_url=AnyHttpUrl(self.front_end_config.server_auth.issuer_url),
-                                         required_scopes=self.front_end_config.server_auth.scopes,
-                                         resource_server_url=AnyHttpUrl(server_url))
+            auth_settings = AuthSettings(
+                issuer_url=self.front_end_config.server_auth.issuer_url,
+                required_scopes=self.front_end_config.server_auth.scopes,
+                resource_server_url=server_url,
+            )

If AuthSettings requires AnyHttpUrl types, consider:

from pydantic import AnyHttpUrl, TypeAdapter
issuer = TypeAdapter(AnyHttpUrl).validate_python(self.front_end_config.server_auth.issuer_url)
resource = TypeAdapter(AnyHttpUrl).validate_python(server_url)

As per coding guidelines.


369-377: Return type annotation for override.

Add -> None to the concrete add_routes for consistency.

-    async def add_routes(self, mcp: FastMCP, builder: WorkflowBuilder):
+    async def add_routes(self, mcp: FastMCP, builder: WorkflowBuilder) -> None:

As per coding guidelines.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2a5be28 and 77579ac.

📒 Files selected for processing (6)
  • ci/vale/styles/config/vocabularies/nat/accept.txt (1 hunks)
  • docs/source/extend/mcp-server.md (1 hunks)
  • docs/source/index.md (1 hunks)
  • pyproject.toml (1 hunks)
  • src/nat/front_ends/mcp/mcp_front_end_plugin.py (2 hunks)
  • src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py (3 hunks)
✅ Files skipped from review due to trivial changes (1)
  • docs/source/index.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • pyproject.toml
🧰 Additional context used
📓 Path-based instructions (8)
{docs/source/**/*.md,**/README.@(md|ipynb)}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

{docs/source/**/*.md,**/README.@(md|ipynb)}: Use the full name “NVIDIA NeMo Agent toolkit” on first use in documentation, then “NeMo Agent toolkit”; in headings use “NeMo Agent Toolkit” (capital T)
Do not use deprecated names (Agent Intelligence toolkit, aiqtoolkit, AgentIQ, AIQ/aiq) in documentation unless explicitly referring to deprecated names
Never use “NAT”/“nat” abbreviations in documentation
Documentation must be clear/comprehensive; avoid TODOs/FIXMEs/placeholders; avoid offensive/outdated terms; ensure spelling is correct

Files:

  • docs/source/extend/mcp-server.md
docs/source/**/*.md

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

docs/source/**/*.md: Documentation sources are Markdown files under docs/source
Surround code entities with backticks in docs to avoid Vale false positives
Do not use words listed in ci/vale/styles/config/vocabularies/nat/reject.txt; accepted words in accept.txt are allowed

Files:

  • docs/source/extend/mcp-server.md
{**/*.py,**/*.sh,**/*.md,**/*.toml,**/*.y?(a)ml,**/*.json,**/*.txt,**/*.ini,**/*.cfg,**/*.ipynb}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

{**/*.py,**/*.sh,**/*.md,**/*.toml,**/*.y?(a)ml,**/*.json,**/*.txt,**/*.ini,**/*.cfg,**/*.ipynb}: Every file must start with the standard SPDX Apache-2.0 header
Confirm copyright years are up to date when a file is changed
All source files must include the SPDX Apache-2.0 header template (copy from an existing file)

Files:

  • docs/source/extend/mcp-server.md
  • src/nat/front_ends/mcp/mcp_front_end_plugin.py
  • ci/vale/styles/config/vocabularies/nat/accept.txt
  • src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py
**/*

⚙️ CodeRabbit configuration file

**/*: # Code Review Instructions

  • Ensure the code follows best practices and coding standards. - For Python code, follow
    PEP 20 and
    PEP 8 for style guidelines.
  • Check for security vulnerabilities and potential issues. - Python methods should use type hints for all parameters and return values.
    Example:
    def my_function(param1: int, param2: str) -> bool:
        pass
  • For Python exception handling, ensure proper stack trace preservation:
    • When re-raising exceptions: use bare raise statements to maintain the original stack trace,
      and use logger.error() (not logger.exception()) to avoid duplicate stack trace output.
    • When catching and logging exceptions without re-raising: always use logger.exception()
      to capture the full stack trace information.

Documentation Review Instructions - Verify that documentation and comments are clear and comprehensive. - Verify that the documentation doesn't contain any TODOs, FIXMEs or placeholder text like "lorem ipsum". - Verify that the documentation doesn't contain any offensive or outdated terms. - Verify that documentation and comments are free of spelling mistakes, ensure the documentation doesn't contain any

words listed in the ci/vale/styles/config/vocabularies/nat/reject.txt file, words that might appear to be
spelling mistakes but are listed in the ci/vale/styles/config/vocabularies/nat/accept.txt file are OK.

Misc. - All code (except .mdc files that contain Cursor rules) should be licensed under the Apache License 2.0,

and should contain an Apache License 2.0 header comment at the top of each file.

  • Confirm that copyright years are up-to date whenever a file is changed.

Files:

  • docs/source/extend/mcp-server.md
  • src/nat/front_ends/mcp/mcp_front_end_plugin.py
  • ci/vale/styles/config/vocabularies/nat/accept.txt
  • src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py
docs/source/**/*

⚙️ CodeRabbit configuration file

This directory contains the source code for the documentation. All documentation should be written in Markdown format. Any image files should be placed in the docs/source/_static directory.

Files:

  • docs/source/extend/mcp-server.md
**/*.py

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.py: In code comments use the abbreviations: nat (API namespace/CLI), nvidia-nat (package), NAT (env var prefixes); never use these abbreviations in documentation
Follow PEP 20 and PEP 8 for Python style
Run yapf with column_limit=120; yapf is used for formatting (run second)
Indent with 4 spaces (no tabs) and end each file with a single trailing newline
Use ruff (ruff check --fix) as a linter (not formatter) per pyproject.toml; fix warnings unless explicitly ignored
Respect Python naming schemes: snake_case for functions/variables, PascalCase for classes, UPPER_CASE for constants
When re-raising exceptions, use bare raise to preserve stack trace; log with logger.error(), not logger.exception()
When catching and logging without re-raising, use logger.exception() to capture full stack trace
Provide Google-style docstrings for every public module, class, function, and CLI command
Docstring first line must be a concise description ending with a period
Validate and sanitize all user input, especially in web or CLI interfaces
Prefer httpx with SSL verification enabled by default and follow OWASP Top-10 recommendations
Use async/await for I/O-bound work (HTTP, DB, file I/O)
Cache expensive computations with functools.lru_cache or an external cache when appropriate
Leverage NumPy vectorized operations when beneficial and feasible

Files:

  • src/nat/front_ends/mcp/mcp_front_end_plugin.py
  • src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py
{src/**/*.py,packages/*/src/**/*.py}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

{src/**/*.py,packages/*/src/**/*.py}: All importable Python code must live under src/ or packages//src/
All public APIs must have Python 3.11+ type hints on parameters and return values
Prefer typing/collections.abc abstractions (e.g., Sequence over list)
Use typing.Annotated for units or metadata when useful
Treat pyright warnings as errors during development

Files:

  • src/nat/front_ends/mcp/mcp_front_end_plugin.py
  • src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py
src/nat/**/*

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

src/nat/**/* contains core functionality; changes should prioritize backward compatibility

Files:

  • src/nat/front_ends/mcp/mcp_front_end_plugin.py
  • src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py

⚙️ CodeRabbit configuration file

This directory contains the core functionality of the toolkit. Changes should prioritize backward compatibility.

Files:

  • src/nat/front_ends/mcp/mcp_front_end_plugin.py
  • src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py
🧠 Learnings (4)
📚 Learning: 2025-10-22T22:02:12.903Z
Learnt from: CR
PR: NVIDIA/NeMo-Agent-Toolkit#0
File: .cursor/rules/general.mdc:0-0
Timestamp: 2025-10-22T22:02:12.903Z
Learning: Applies to {docs/source/**/*.md,**/README.@(md|ipynb)} : Use the full name “NVIDIA NeMo Agent toolkit” on first use in documentation, then “NeMo Agent toolkit”; in headings use “NeMo Agent Toolkit” (capital T)

Applied to files:

  • docs/source/extend/mcp-server.md
📚 Learning: 2025-10-22T22:02:12.903Z
Learnt from: CR
PR: NVIDIA/NeMo-Agent-Toolkit#0
File: .cursor/rules/general.mdc:0-0
Timestamp: 2025-10-22T22:02:12.903Z
Learning: Applies to {docs/source/**/*.md,**/README.@(md|ipynb)} : Never use “NAT”/“nat” abbreviations in documentation

Applied to files:

  • docs/source/extend/mcp-server.md
📚 Learning: 2025-08-22T20:18:28.041Z
Learnt from: CR
PR: NVIDIA/NeMo-Agent-Toolkit#0
File: .cursor/rules/cursor-rules.mdc:0-0
Timestamp: 2025-08-22T20:18:28.041Z
Learning: Applies to .cursor/rules/**/*.mdc : Use consistent project terminology in descriptions (e.g., NAT workflows, NAT CLI commands)

Applied to files:

  • docs/source/extend/mcp-server.md
📚 Learning: 2025-10-22T22:02:12.903Z
Learnt from: CR
PR: NVIDIA/NeMo-Agent-Toolkit#0
File: .cursor/rules/general.mdc:0-0
Timestamp: 2025-10-22T22:02:12.903Z
Learning: Applies to **/*.py : In code comments use the abbreviations: nat (API namespace/CLI), nvidia-nat (package), NAT (env var prefixes); never use these abbreviations in documentation

Applied to files:

  • docs/source/extend/mcp-server.md
🧬 Code graph analysis (2)
src/nat/front_ends/mcp/mcp_front_end_plugin.py (1)
src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py (2)
  • create_mcp_server (92-108)
  • create_mcp_server (338-367)
src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py (5)
src/nat/front_ends/fastapi/fastapi_front_end_plugin_worker.py (2)
  • add_routes (241-253)
  • front_end_config (126-127)
tests/nat/front_ends/mcp/test_mcp_custom_routes.py (1)
  • add_routes (35-51)
src/nat/builder/workflow_builder.py (2)
  • WorkflowBuilder (144-1157)
  • build (263-378)
src/nat/front_ends/mcp/tool_converter.py (1)
  • register_function_with_mcp (254-290)
src/nat/front_ends/mcp/introspection_token_verifier.py (1)
  • IntrospectionTokenVerifier (28-73)
🪛 LanguageTool
docs/source/extend/mcp-server.md

[style] ~43-~43: Consider using “who” when you are referring to a person instead of an object.
Context: ...ollowing example shows a minimal worker that adds a custom status endpoint to the MC...

(THAT_WHO)


[grammar] ~221-~221: Use a hyphen to join words.
Context: ...neral: General settings including front end config - llms`: LLM configuration...

(QB_NEW_EN_HYPHEN)

🪛 markdownlint-cli2 (0.18.1)
docs/source/extend/mcp-server.md

136-136: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Ruff (0.14.1)
src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py

182-182: Avoid specifying long messages outside the exception class

(TRY003)

🔇 Additional comments (4)
ci/vale/styles/config/vocabularies/nat/accept.txt (1)

88-88: LGTM: vocabulary addition.

Adding “[Mm]iddleware” is appropriate and alphabetically placed between Mem0 and Milvus.

docs/source/extend/mcp-server.md (2)

1-16: License header: good.

SPDX header present and correct.


20-25: Product naming is correct.

Uses “NVIDIA NeMo Agent toolkit” on first use and “NeMo Agent toolkit” thereafter; CLI shown in code blocks.

Based on learnings.

src/nat/front_ends/mcp/mcp_front_end_plugin.py (1)

63-71: Delegation to worker: good.

run() cleanly delegates server creation and route registration to the worker.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/nat/front_ends/mcp/mcp_front_end_plugin.py (1)

45-56: Add return type annotation.

The method _get_worker_instance is missing a return type annotation. Per coding guidelines, all Python methods should use type hints for parameters and return values.

Apply this diff:

-    def _get_worker_instance(self):
+    def _get_worker_instance(self) -> MCPFrontEndPluginWorkerBase:
         """Get an instance of the worker class."""
🧹 Nitpick comments (1)
docs/source/extend/mcp-server.md (1)

210-243: Add hyphen to compound adjective.

On line 221, "front end config" should be "front-end config" when used as a compound adjective before a noun.

Apply this diff:

-- **`self.front_end_config`**: MCP server configuration
+- **`self.front_end_config`**: MCP server configuration

Note: The actual field name front_end_config (with underscore) remains unchanged - this is only about the prose description.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2095ca0 and 77579ac.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (6)
  • ci/vale/styles/config/vocabularies/nat/accept.txt (1 hunks)
  • docs/source/extend/mcp-server.md (1 hunks)
  • docs/source/index.md (1 hunks)
  • pyproject.toml (1 hunks)
  • src/nat/front_ends/mcp/mcp_front_end_plugin.py (2 hunks)
  • src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py (3 hunks)
🧰 Additional context used
📓 Path-based instructions (9)
{**/*.py,**/*.sh,**/*.md,**/*.toml,**/*.y?(a)ml,**/*.json,**/*.txt,**/*.ini,**/*.cfg,**/*.ipynb}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

{**/*.py,**/*.sh,**/*.md,**/*.toml,**/*.y?(a)ml,**/*.json,**/*.txt,**/*.ini,**/*.cfg,**/*.ipynb}: Every file must start with the standard SPDX Apache-2.0 header
Confirm copyright years are up to date when a file is changed
All source files must include the SPDX Apache-2.0 header template (copy from an existing file)

Files:

  • ci/vale/styles/config/vocabularies/nat/accept.txt
  • docs/source/index.md
  • docs/source/extend/mcp-server.md
  • src/nat/front_ends/mcp/mcp_front_end_plugin.py
  • src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py
  • pyproject.toml
**/*

⚙️ CodeRabbit configuration file

**/*: # Code Review Instructions

  • Ensure the code follows best practices and coding standards. - For Python code, follow
    PEP 20 and
    PEP 8 for style guidelines.
  • Check for security vulnerabilities and potential issues. - Python methods should use type hints for all parameters and return values.
    Example:
    def my_function(param1: int, param2: str) -> bool:
        pass
  • For Python exception handling, ensure proper stack trace preservation:
    • When re-raising exceptions: use bare raise statements to maintain the original stack trace,
      and use logger.error() (not logger.exception()) to avoid duplicate stack trace output.
    • When catching and logging exceptions without re-raising: always use logger.exception()
      to capture the full stack trace information.

Documentation Review Instructions - Verify that documentation and comments are clear and comprehensive. - Verify that the documentation doesn't contain any TODOs, FIXMEs or placeholder text like "lorem ipsum". - Verify that the documentation doesn't contain any offensive or outdated terms. - Verify that documentation and comments are free of spelling mistakes, ensure the documentation doesn't contain any

words listed in the ci/vale/styles/config/vocabularies/nat/reject.txt file, words that might appear to be
spelling mistakes but are listed in the ci/vale/styles/config/vocabularies/nat/accept.txt file are OK.

Misc. - All code (except .mdc files that contain Cursor rules) should be licensed under the Apache License 2.0,

and should contain an Apache License 2.0 header comment at the top of each file.

  • Confirm that copyright years are up-to date whenever a file is changed.

Files:

  • ci/vale/styles/config/vocabularies/nat/accept.txt
  • docs/source/index.md
  • docs/source/extend/mcp-server.md
  • src/nat/front_ends/mcp/mcp_front_end_plugin.py
  • src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py
  • pyproject.toml
{docs/source/**/*.md,**/README.@(md|ipynb)}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

{docs/source/**/*.md,**/README.@(md|ipynb)}: Use the full name “NVIDIA NeMo Agent toolkit” on first use in documentation, then “NeMo Agent toolkit”; in headings use “NeMo Agent Toolkit” (capital T)
Do not use deprecated names (Agent Intelligence toolkit, aiqtoolkit, AgentIQ, AIQ/aiq) in documentation unless explicitly referring to deprecated names
Never use “NAT”/“nat” abbreviations in documentation
Documentation must be clear/comprehensive; avoid TODOs/FIXMEs/placeholders; avoid offensive/outdated terms; ensure spelling is correct

Files:

  • docs/source/index.md
  • docs/source/extend/mcp-server.md
docs/source/**/*.md

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

docs/source/**/*.md: Documentation sources are Markdown files under docs/source
Surround code entities with backticks in docs to avoid Vale false positives
Do not use words listed in ci/vale/styles/config/vocabularies/nat/reject.txt; accepted words in accept.txt are allowed

Files:

  • docs/source/index.md
  • docs/source/extend/mcp-server.md
docs/source/**/*

⚙️ CodeRabbit configuration file

This directory contains the source code for the documentation. All documentation should be written in Markdown format. Any image files should be placed in the docs/source/_static directory.

Files:

  • docs/source/index.md
  • docs/source/extend/mcp-server.md
**/*.py

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.py: In code comments use the abbreviations: nat (API namespace/CLI), nvidia-nat (package), NAT (env var prefixes); never use these abbreviations in documentation
Follow PEP 20 and PEP 8 for Python style
Run yapf with column_limit=120; yapf is used for formatting (run second)
Indent with 4 spaces (no tabs) and end each file with a single trailing newline
Use ruff (ruff check --fix) as a linter (not formatter) per pyproject.toml; fix warnings unless explicitly ignored
Respect Python naming schemes: snake_case for functions/variables, PascalCase for classes, UPPER_CASE for constants
When re-raising exceptions, use bare raise to preserve stack trace; log with logger.error(), not logger.exception()
When catching and logging without re-raising, use logger.exception() to capture full stack trace
Provide Google-style docstrings for every public module, class, function, and CLI command
Docstring first line must be a concise description ending with a period
Validate and sanitize all user input, especially in web or CLI interfaces
Prefer httpx with SSL verification enabled by default and follow OWASP Top-10 recommendations
Use async/await for I/O-bound work (HTTP, DB, file I/O)
Cache expensive computations with functools.lru_cache or an external cache when appropriate
Leverage NumPy vectorized operations when beneficial and feasible

Files:

  • src/nat/front_ends/mcp/mcp_front_end_plugin.py
  • src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py
{src/**/*.py,packages/*/src/**/*.py}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

{src/**/*.py,packages/*/src/**/*.py}: All importable Python code must live under src/ or packages//src/
All public APIs must have Python 3.11+ type hints on parameters and return values
Prefer typing/collections.abc abstractions (e.g., Sequence over list)
Use typing.Annotated for units or metadata when useful
Treat pyright warnings as errors during development

Files:

  • src/nat/front_ends/mcp/mcp_front_end_plugin.py
  • src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py
src/nat/**/*

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

src/nat/**/* contains core functionality; changes should prioritize backward compatibility

Files:

  • src/nat/front_ends/mcp/mcp_front_end_plugin.py
  • src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py

⚙️ CodeRabbit configuration file

This directory contains the core functionality of the toolkit. Changes should prioritize backward compatibility.

Files:

  • src/nat/front_ends/mcp/mcp_front_end_plugin.py
  • src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py
{**/pyproject.toml,uv.lock}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

New dependencies must be added to both pyproject.toml (alphabetically) and uv.lock via ‘uv pip install --sync’

Files:

  • pyproject.toml
🧠 Learnings (4)
📚 Learning: 2025-10-22T22:02:12.903Z
Learnt from: CR
PR: NVIDIA/NeMo-Agent-Toolkit#0
File: .cursor/rules/general.mdc:0-0
Timestamp: 2025-10-22T22:02:12.903Z
Learning: Applies to {docs/source/**/*.md,**/README.@(md|ipynb)} : Use the full name “NVIDIA NeMo Agent toolkit” on first use in documentation, then “NeMo Agent toolkit”; in headings use “NeMo Agent Toolkit” (capital T)

Applied to files:

  • docs/source/extend/mcp-server.md
📚 Learning: 2025-10-22T22:02:12.903Z
Learnt from: CR
PR: NVIDIA/NeMo-Agent-Toolkit#0
File: .cursor/rules/general.mdc:0-0
Timestamp: 2025-10-22T22:02:12.903Z
Learning: Applies to {docs/source/**/*.md,**/README.@(md|ipynb)} : Never use “NAT”/“nat” abbreviations in documentation

Applied to files:

  • docs/source/extend/mcp-server.md
📚 Learning: 2025-08-22T20:18:28.041Z
Learnt from: CR
PR: NVIDIA/NeMo-Agent-Toolkit#0
File: .cursor/rules/cursor-rules.mdc:0-0
Timestamp: 2025-08-22T20:18:28.041Z
Learning: Applies to .cursor/rules/**/*.mdc : Use consistent project terminology in descriptions (e.g., NAT workflows, NAT CLI commands)

Applied to files:

  • docs/source/extend/mcp-server.md
📚 Learning: 2025-10-22T22:02:12.903Z
Learnt from: CR
PR: NVIDIA/NeMo-Agent-Toolkit#0
File: .cursor/rules/general.mdc:0-0
Timestamp: 2025-10-22T22:02:12.903Z
Learning: Applies to **/*.py : In code comments use the abbreviations: nat (API namespace/CLI), nvidia-nat (package), NAT (env var prefixes); never use these abbreviations in documentation

Applied to files:

  • docs/source/extend/mcp-server.md
🪛 LanguageTool
docs/source/extend/mcp-server.md

[style] ~43-~43: Consider using “who” when you are referring to a person instead of an object.
Context: ...ollowing example shows a minimal worker that adds a custom status endpoint to the MC...

(THAT_WHO)


[grammar] ~221-~221: Use a hyphen to join words.
Context: ...neral: General settings including front end config - llms`: LLM configuration...

(QB_NEW_EN_HYPHEN)

🪛 Ruff (0.14.1)
src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py

182-182: Avoid specifying long messages outside the exception class

(TRY003)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: CI Pipeline / Check
🔇 Additional comments (24)
ci/vale/styles/config/vocabularies/nat/accept.txt (1)

88-88: LGTM!

The addition of [Mm]iddleware to the accepted vocabulary aligns with the new MCP server customization features documented in this PR.

docs/source/index.md (1)

124-124: LGTM!

The new documentation entry for custom MCP server workers is properly placed in the Extend section and follows the correct toctree format.

src/nat/front_ends/mcp/mcp_front_end_plugin.py (2)

36-43: LGTM!

The @typing.final decorator correctly indicates that get_worker_class_name should not be overridden by subclasses. The method implementation is clean and straightforward.


58-82: LGTM!

The refactored flow cleanly delegates MCP server creation and route registration to the worker, providing a clear extension point for custom implementations. The separation of concerns is well-designed.

docs/source/extend/mcp-server.md (10)

1-16: LGTM!

The Apache-2.0 SPDX header is correctly formatted and includes the proper copyright year 2025.


18-34: LGTM!

The introduction clearly explains when and why developers should create custom MCP server workers. The use cases are well-documented and relevant to enterprise requirements.


35-48: LGTM!

The section provides clear context and appropriate framing for the tutorial. The note to read the MCP Server Guide first is helpful for readers.


49-88: LGTM!

The code example is clear, well-commented, and demonstrates proper inheritance and method overriding patterns. The use of super().add_routes() to extend default behavior is the correct approach.


90-95: LGTM!

The key components breakdown clearly explains the important patterns used in the example.


96-125: LGTM!

The YAML configuration example is clear and correctly shows how to register a custom worker using the runner_class field.


127-165: LGTM!

The testing section provides clear commands and expected outputs, making it easy for developers to verify their custom worker implementation.


167-189: LGTM!

The explanation of super().add_routes() is clear and accurately describes what default functionality it provides.


191-209: LGTM!

The section clearly explains when and how to override create_mcp_server(), and importantly notes that custom workers take ownership of authentication configuration when overriding this method.


245-253: LGTM!

The summary effectively recaps the key points and emphasizes the benefits of custom workers for enterprise use cases.

src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py (9)

37-59: LGTM!

The base class docstring clearly explains the purpose and recommends using MCPFrontEndPluginWorker instead of direct inheritance. The constructor is well-documented and properly initializes the memory profiler.


60-90: LGTM!

The health endpoint implementation correctly uses the MCP server's internal ping handler to verify server health. The error handling is appropriate, returning a 503 status code for unhealthy states.


91-108: LGTM!

The abstract method create_mcp_server() provides a clear extension point for custom server implementations. The docstring includes a helpful example showing the expected return pattern.


110-130: LGTM!

The abstract method add_routes() is well-documented with clear guidance on calling _default_add_routes() for standard behavior before adding custom features. The example demonstrates the recommended pattern.


132-185: LGTM!

The _default_add_routes() method provides a comprehensive default implementation that handles health endpoints, workflow building, function registration, and debug endpoints. The filtering logic for tool_names is well-implemented, supporting both individual function names and function group prefixes.


187-208: LGTM!

The _get_all_functions() method correctly extracts functions from the workflow, function groups, and includes the workflow itself using the configured alias. The implementation is straightforward and comprehensive.


210-316: LGTM!

The debug endpoints provide valuable introspection capabilities:

  • /debug/tools/list supports filtering and detail control with sensible defaults
  • /debug/memory/stats exposes memory profiling statistics
  • The implementation handles query parameters flexibly (comma-separated and repeated)
  • Error handling for missing tools is appropriate

318-367: LGTM!

The concrete MCPFrontEndPluginWorker implementation provides excellent default behavior:

  • create_mcp_server() properly handles optional authentication configuration
  • Authentication settings are correctly constructed from front-end config
  • The IntrospectionTokenVerifier is instantiated when auth is enabled
  • All configuration parameters are passed through to FastMCP

369-377: LGTM!

The add_routes() implementation correctly delegates to the base class _default_add_routes() method, providing a clean extension pattern for subclasses.

pyproject.toml (1)

27-27: FastAPI 0.120.1 verified as available and secure.

The version exists on PyPI and is not affected by known security vulnerabilities (CSRF vulnerability fixed in 0.65.2 and ReDoS vulnerability fixed in 0.109.1). The semver constraint ~=0.120.1 appropriately allows patch-level updates.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 77579ac and 1ecf232.

📒 Files selected for processing (2)
  • src/nat/front_ends/mcp/mcp_front_end_config.py (1 hunks)
  • src/nat/front_ends/mcp/mcp_front_end_plugin.py (2 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.py

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.py: In code comments use the abbreviations: nat (API namespace/CLI), nvidia-nat (package), NAT (env var prefixes); never use these abbreviations in documentation
Follow PEP 20 and PEP 8 for Python style
Run yapf with column_limit=120; yapf is used for formatting (run second)
Indent with 4 spaces (no tabs) and end each file with a single trailing newline
Use ruff (ruff check --fix) as a linter (not formatter) per pyproject.toml; fix warnings unless explicitly ignored
Respect Python naming schemes: snake_case for functions/variables, PascalCase for classes, UPPER_CASE for constants
When re-raising exceptions, use bare raise to preserve stack trace; log with logger.error(), not logger.exception()
When catching and logging without re-raising, use logger.exception() to capture full stack trace
Provide Google-style docstrings for every public module, class, function, and CLI command
Docstring first line must be a concise description ending with a period
Validate and sanitize all user input, especially in web or CLI interfaces
Prefer httpx with SSL verification enabled by default and follow OWASP Top-10 recommendations
Use async/await for I/O-bound work (HTTP, DB, file I/O)
Cache expensive computations with functools.lru_cache or an external cache when appropriate
Leverage NumPy vectorized operations when beneficial and feasible

Files:

  • src/nat/front_ends/mcp/mcp_front_end_plugin.py
  • src/nat/front_ends/mcp/mcp_front_end_config.py
{src/**/*.py,packages/*/src/**/*.py}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

{src/**/*.py,packages/*/src/**/*.py}: All importable Python code must live under src/ or packages//src/
All public APIs must have Python 3.11+ type hints on parameters and return values
Prefer typing/collections.abc abstractions (e.g., Sequence over list)
Use typing.Annotated for units or metadata when useful
Treat pyright warnings as errors during development

Files:

  • src/nat/front_ends/mcp/mcp_front_end_plugin.py
  • src/nat/front_ends/mcp/mcp_front_end_config.py
src/nat/**/*

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

src/nat/**/* contains core functionality; changes should prioritize backward compatibility

Files:

  • src/nat/front_ends/mcp/mcp_front_end_plugin.py
  • src/nat/front_ends/mcp/mcp_front_end_config.py

⚙️ CodeRabbit configuration file

This directory contains the core functionality of the toolkit. Changes should prioritize backward compatibility.

Files:

  • src/nat/front_ends/mcp/mcp_front_end_plugin.py
  • src/nat/front_ends/mcp/mcp_front_end_config.py
{**/*.py,**/*.sh,**/*.md,**/*.toml,**/*.y?(a)ml,**/*.json,**/*.txt,**/*.ini,**/*.cfg,**/*.ipynb}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

{**/*.py,**/*.sh,**/*.md,**/*.toml,**/*.y?(a)ml,**/*.json,**/*.txt,**/*.ini,**/*.cfg,**/*.ipynb}: Every file must start with the standard SPDX Apache-2.0 header
Confirm copyright years are up to date when a file is changed
All source files must include the SPDX Apache-2.0 header template (copy from an existing file)

Files:

  • src/nat/front_ends/mcp/mcp_front_end_plugin.py
  • src/nat/front_ends/mcp/mcp_front_end_config.py
**/*

⚙️ CodeRabbit configuration file

**/*: # Code Review Instructions

  • Ensure the code follows best practices and coding standards. - For Python code, follow
    PEP 20 and
    PEP 8 for style guidelines.
  • Check for security vulnerabilities and potential issues. - Python methods should use type hints for all parameters and return values.
    Example:
    def my_function(param1: int, param2: str) -> bool:
        pass
  • For Python exception handling, ensure proper stack trace preservation:
    • When re-raising exceptions: use bare raise statements to maintain the original stack trace,
      and use logger.error() (not logger.exception()) to avoid duplicate stack trace output.
    • When catching and logging exceptions without re-raising: always use logger.exception()
      to capture the full stack trace information.

Documentation Review Instructions - Verify that documentation and comments are clear and comprehensive. - Verify that the documentation doesn't contain any TODOs, FIXMEs or placeholder text like "lorem ipsum". - Verify that the documentation doesn't contain any offensive or outdated terms. - Verify that documentation and comments are free of spelling mistakes, ensure the documentation doesn't contain any

words listed in the ci/vale/styles/config/vocabularies/nat/reject.txt file, words that might appear to be
spelling mistakes but are listed in the ci/vale/styles/config/vocabularies/nat/accept.txt file are OK.

Misc. - All code (except .mdc files that contain Cursor rules) should be licensed under the Apache License 2.0,

and should contain an Apache License 2.0 header comment at the top of each file.

  • Confirm that copyright years are up-to date whenever a file is changed.

Files:

  • src/nat/front_ends/mcp/mcp_front_end_plugin.py
  • src/nat/front_ends/mcp/mcp_front_end_config.py
🧬 Code graph analysis (1)
src/nat/front_ends/mcp/mcp_front_end_plugin.py (2)
tests/nat/front_ends/mcp/test_mcp_debug_routes.py (1)
  • worker (104-106)
src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py (4)
  • create_mcp_server (92-108)
  • create_mcp_server (338-367)
  • add_routes (111-130)
  • add_routes (369-377)
🪛 Ruff (0.14.2)
src/nat/front_ends/mcp/mcp_front_end_plugin.py

126-126: Use logging.exception instead of logging.error

Replace with exception

(TRY400)

🔇 Additional comments (4)
src/nat/front_ends/mcp/mcp_front_end_plugin.py (4)

45-56: LGTM: Clean worker instantiation pattern.

The dynamic import logic correctly handles both custom and default worker classes, with appropriate fallback behavior.


63-70: LGTM: Proper delegation to worker.

The worker-driven lifecycle correctly delegates MCP server creation and route registration to the worker instance, enabling the extensibility described in the PR objectives.


75-100: Good conditional logic with appropriate warnings.

The base_path mounting logic correctly handles transport compatibility and provides clear logging. The URL construction at line 84 depends on proper base_path validation (see comment on config file).


126-126: Static analysis false positive - current code is correct.

The static analysis tool suggests using logger.exception() instead of logger.error(), but this is incorrect. The coding guidelines explicitly state: "When re-raising exceptions, use bare raise to preserve stack trace; log with logger.error(), not logger.exception()." The current implementation correctly uses logger.error() before re-raising.

As per coding guidelines.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/source/workflows/mcp/mcp-server.md (1)

20-24: Use full product name on first mention.

Per doc style, first use should be “NVIDIA NeMo Agent toolkit”; subsequent uses can be “NeMo Agent toolkit”. Update the first textual mention accordingly.

-This guide will cover how to use NeMo Agent toolkit as an MCP Server to publish tools using MCP.
+This guide will cover how to use NVIDIA NeMo Agent toolkit as an MCP Server to publish tools using MCP.

As per coding guidelines.

🧹 Nitpick comments (2)
docs/source/workflows/mcp/mcp-server.md (2)

75-77: Specify base_path constraints (leading slash, trailing slash, normalization).

Document required/accepted formats to prevent misconfigurations (e.g., "/api/v1" vs "api/v1" vs "/api/v1/") and whether normalization strips trailing slashes.

Proposed note text:

 :::note
-The `base_path` feature requires the `streamable-http` transport. SSE transport does not support custom base paths.
+The `base_path` feature requires the `streamable-http` transport. SSE transport does not support custom base paths.
+
+Constraints:
+- Must start with `/` (e.g., `/api/v1`).
+- Trailing slash is [accepted|rejected]; if accepted it is normalized to `/api/v1`.
+- Empty string or `/` disables custom mounting (defaults to root).
+- Whitespace and URL-encoded characters are not allowed.
 :::

As per coding guidelines.


62-74: Clarify that base_path affects ALL routes (including /health and /debug/*) and update documentation examples.

After verifying the implementation, I confirmed that when base_path is configured, app.mount(base_path, mcp_server_app) mounts the entire MCP server application at that path. This means all routes get the prefix, not just /mcp:

  • With base_path: "/api/v1":
    • MCP endpoint: /api/v1/mcp
    • Health check: /api/v1/health
    • Debug routes: /api/v1/debug/tools/list, /api/v1/debug/memory/stats

The current documentation (lines 62-77) only mentions the MCP endpoint. However, later sections contain numerous examples that will break with base_path:

  • Lines 126-329: Multiple curl examples for /debug/tools/list use root paths
  • Lines 355-372: Health check examples use /health and nat mcp client ping --url http://localhost:9901/mcp

Recommended additions:

  1. After line 73, add explicit clarification:
When using `base_path`, all server routes are mounted under that path:
- MCP endpoint: `http://localhost:9901/api/v1/mcp`
- Health endpoint: `http://localhost:9901/api/v1/health`
- Debug endpoints: `http://localhost:9901/api/v1/debug/tools/list`
- CLI commands must include the base path: `nat mcp client ping --url http://localhost:9901/api/v1/mcp`
  1. Add notes to the /debug/tools/list section (around line 122) and health check section (around line 352) reminding users to prepend base_path if configured.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1ecf232 and 2e852ab.

📒 Files selected for processing (1)
  • docs/source/workflows/mcp/mcp-server.md (1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
{docs/source/**/*.md,**/README.@(md|ipynb)}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

{docs/source/**/*.md,**/README.@(md|ipynb)}: Use the full name “NVIDIA NeMo Agent toolkit” on first use in documentation, then “NeMo Agent toolkit”; in headings use “NeMo Agent Toolkit” (capital T)
Do not use deprecated names (Agent Intelligence toolkit, aiqtoolkit, AgentIQ, AIQ/aiq) in documentation unless explicitly referring to deprecated names
Never use “NAT”/“nat” abbreviations in documentation
Documentation must be clear/comprehensive; avoid TODOs/FIXMEs/placeholders; avoid offensive/outdated terms; ensure spelling is correct

Files:

  • docs/source/workflows/mcp/mcp-server.md
docs/source/**/*.md

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

docs/source/**/*.md: Documentation sources are Markdown files under docs/source
Surround code entities with backticks in docs to avoid Vale false positives
Do not use words listed in ci/vale/styles/config/vocabularies/nat/reject.txt; accepted words in accept.txt are allowed

Files:

  • docs/source/workflows/mcp/mcp-server.md
{**/*.py,**/*.sh,**/*.md,**/*.toml,**/*.y?(a)ml,**/*.json,**/*.txt,**/*.ini,**/*.cfg,**/*.ipynb}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

{**/*.py,**/*.sh,**/*.md,**/*.toml,**/*.y?(a)ml,**/*.json,**/*.txt,**/*.ini,**/*.cfg,**/*.ipynb}: Every file must start with the standard SPDX Apache-2.0 header
Confirm copyright years are up to date when a file is changed
All source files must include the SPDX Apache-2.0 header template (copy from an existing file)

Files:

  • docs/source/workflows/mcp/mcp-server.md
**/*

⚙️ CodeRabbit configuration file

**/*: # Code Review Instructions

  • Ensure the code follows best practices and coding standards. - For Python code, follow
    PEP 20 and
    PEP 8 for style guidelines.
  • Check for security vulnerabilities and potential issues. - Python methods should use type hints for all parameters and return values.
    Example:
    def my_function(param1: int, param2: str) -> bool:
        pass
  • For Python exception handling, ensure proper stack trace preservation:
    • When re-raising exceptions: use bare raise statements to maintain the original stack trace,
      and use logger.error() (not logger.exception()) to avoid duplicate stack trace output.
    • When catching and logging exceptions without re-raising: always use logger.exception()
      to capture the full stack trace information.

Documentation Review Instructions - Verify that documentation and comments are clear and comprehensive. - Verify that the documentation doesn't contain any TODOs, FIXMEs or placeholder text like "lorem ipsum". - Verify that the documentation doesn't contain any offensive or outdated terms. - Verify that documentation and comments are free of spelling mistakes, ensure the documentation doesn't contain any

words listed in the ci/vale/styles/config/vocabularies/nat/reject.txt file, words that might appear to be
spelling mistakes but are listed in the ci/vale/styles/config/vocabularies/nat/accept.txt file are OK.

Misc. - All code (except .mdc files that contain Cursor rules) should be licensed under the Apache License 2.0,

and should contain an Apache License 2.0 header comment at the top of each file.

  • Confirm that copyright years are up-to date whenever a file is changed.

Files:

  • docs/source/workflows/mcp/mcp-server.md
docs/source/**/*

⚙️ CodeRabbit configuration file

This directory contains the source code for the documentation. All documentation should be written in Markdown format. Any image files should be placed in the docs/source/_static directory.

Files:

  • docs/source/workflows/mcp/mcp-server.md

@AnuradhaKaruppiah AnuradhaKaruppiah removed the request for review from a team October 28, 2025 19:27
Signed-off-by: Anuradha Karuppiah <[email protected]>
@AnuradhaKaruppiah AnuradhaKaruppiah changed the title Changes to allow custom MCP servers Support custom MCP server implementations Oct 28, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/nat/front_ends/mcp/mcp_front_end_plugin.py (1)

48-48: Add return type hint for consistency.

The _get_worker_instance method is missing a return type hint. For consistency with the rest of the codebase and the fix applied to _run_with_mount (line 107), add the return type.

Apply this diff to add the return type hint:

-    def _get_worker_instance(self):
+    def _get_worker_instance(self) -> MCPFrontEndPluginWorkerBase:
         """Get an instance of the worker class."""
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 46f5af2 and 9ae0ab8.

📒 Files selected for processing (1)
  • src/nat/front_ends/mcp/mcp_front_end_plugin.py (3 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.py

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.py: In code comments use the abbreviations: nat (API namespace/CLI), nvidia-nat (package), NAT (env var prefixes); never use these abbreviations in documentation
Follow PEP 20 and PEP 8 for Python style
Run yapf with column_limit=120; yapf is used for formatting (run second)
Indent with 4 spaces (no tabs) and end each file with a single trailing newline
Use ruff (ruff check --fix) as a linter (not formatter) per pyproject.toml; fix warnings unless explicitly ignored
Respect Python naming schemes: snake_case for functions/variables, PascalCase for classes, UPPER_CASE for constants
When re-raising exceptions, use bare raise to preserve stack trace; log with logger.error(), not logger.exception()
When catching and logging without re-raising, use logger.exception() to capture full stack trace
Provide Google-style docstrings for every public module, class, function, and CLI command
Docstring first line must be a concise description ending with a period
Validate and sanitize all user input, especially in web or CLI interfaces
Prefer httpx with SSL verification enabled by default and follow OWASP Top-10 recommendations
Use async/await for I/O-bound work (HTTP, DB, file I/O)
Cache expensive computations with functools.lru_cache or an external cache when appropriate
Leverage NumPy vectorized operations when beneficial and feasible

Files:

  • src/nat/front_ends/mcp/mcp_front_end_plugin.py
{src/**/*.py,packages/*/src/**/*.py}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

{src/**/*.py,packages/*/src/**/*.py}: All importable Python code must live under src/ or packages//src/
All public APIs must have Python 3.11+ type hints on parameters and return values
Prefer typing/collections.abc abstractions (e.g., Sequence over list)
Use typing.Annotated for units or metadata when useful
Treat pyright warnings as errors during development

Files:

  • src/nat/front_ends/mcp/mcp_front_end_plugin.py
src/nat/**/*

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

src/nat/**/* contains core functionality; changes should prioritize backward compatibility

Files:

  • src/nat/front_ends/mcp/mcp_front_end_plugin.py

⚙️ CodeRabbit configuration file

This directory contains the core functionality of the toolkit. Changes should prioritize backward compatibility.

Files:

  • src/nat/front_ends/mcp/mcp_front_end_plugin.py
{**/*.py,**/*.sh,**/*.md,**/*.toml,**/*.y?(a)ml,**/*.json,**/*.txt,**/*.ini,**/*.cfg,**/*.ipynb}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

{**/*.py,**/*.sh,**/*.md,**/*.toml,**/*.y?(a)ml,**/*.json,**/*.txt,**/*.ini,**/*.cfg,**/*.ipynb}: Every file must start with the standard SPDX Apache-2.0 header
Confirm copyright years are up to date when a file is changed
All source files must include the SPDX Apache-2.0 header template (copy from an existing file)

Files:

  • src/nat/front_ends/mcp/mcp_front_end_plugin.py
**/*

⚙️ CodeRabbit configuration file

**/*: # Code Review Instructions

  • Ensure the code follows best practices and coding standards. - For Python code, follow
    PEP 20 and
    PEP 8 for style guidelines.
  • Check for security vulnerabilities and potential issues. - Python methods should use type hints for all parameters and return values.
    Example:
    def my_function(param1: int, param2: str) -> bool:
        pass
  • For Python exception handling, ensure proper stack trace preservation:
    • When re-raising exceptions: use bare raise statements to maintain the original stack trace,
      and use logger.error() (not logger.exception()) to avoid duplicate stack trace output.
    • When catching and logging exceptions without re-raising: always use logger.exception()
      to capture the full stack trace information.

Documentation Review Instructions - Verify that documentation and comments are clear and comprehensive. - Verify that the documentation doesn't contain any TODOs, FIXMEs or placeholder text like "lorem ipsum". - Verify that the documentation doesn't contain any offensive or outdated terms. - Verify that documentation and comments are free of spelling mistakes, ensure the documentation doesn't contain any

words listed in the ci/vale/styles/config/vocabularies/nat/reject.txt file, words that might appear to be
spelling mistakes but are listed in the ci/vale/styles/config/vocabularies/nat/accept.txt file are OK.

Misc. - All code (except .mdc files that contain Cursor rules) should be licensed under the Apache License 2.0,

and should contain an Apache License 2.0 header comment at the top of each file.

  • Confirm that copyright years are up-to date whenever a file is changed.

Files:

  • src/nat/front_ends/mcp/mcp_front_end_plugin.py
🧬 Code graph analysis (1)
src/nat/front_ends/mcp/mcp_front_end_plugin.py (1)
src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py (4)
  • create_mcp_server (92-108)
  • create_mcp_server (338-367)
  • add_routes (111-130)
  • add_routes (369-377)
🪛 Ruff (0.14.2)
src/nat/front_ends/mcp/mcp_front_end_plugin.py

129-129: Use logging.exception instead of logging.error

Replace with exception

(TRY400)

🔇 Additional comments (5)
src/nat/front_ends/mcp/mcp_front_end_plugin.py (5)

24-25: LGTM! Good use of TYPE_CHECKING for forward references.

The TYPE_CHECKING import enables the FastMCP type hint on line 107 without incurring runtime import overhead, which is best practice for type hints.


66-73: LGTM! Clean delegation to worker abstraction.

The refactored flow properly delegates MCP server creation and route registration to the worker, enabling the extensibility feature described in the PR objectives.


78-95: LGTM! Proper handling of base_path mounting with transport-specific logic.

The implementation correctly handles the SSE transport limitation and provides clear user feedback via logging. The mounting logic for other transports is well-structured.


107-151: LGTM! Well-structured mounting implementation with proper lifecycle management.

The _run_with_mount method correctly implements mounting at a custom base_path using a FastAPI wrapper. The type hint for the mcp parameter (noted in the past review) has been properly addressed with the forward reference.

The lifespan context manager properly handles the MCP server session lifecycle, and the FastAPI mounting logic is clean and correct.


129-130: Static analysis false positive: logger.error() is correct here.

The Ruff hint suggesting logger.exception() is incorrect in this context. The coding guidelines explicitly state: "When re-raising exceptions, use bare raise to preserve stack trace; log with logger.error(), not logger.exception()." Since line 130 re-raises the exception with bare raise, using logger.error() on line 129 is the correct approach to avoid duplicate stack traces.

Based on coding guidelines.

Copy link
Contributor

@yczhang-nv yczhang-nv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Just a nit on the documentation

@AnuradhaKaruppiah
Copy link
Contributor Author

Thanks for the review @yczhang-nv!

Signed-off-by: Anuradha Karuppiah <[email protected]>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py (1)

167-167: Consider extracting the exception message to a constant.

The error message could be defined as a module-level constant to follow PEP 8 style guidelines.

+# Error message constants
+_NO_FUNCTIONS_ERROR = "No functions found in workflow. Please check your configuration."
+
 # ... (in _default_add_routes)
-            raise RuntimeError("No functions found in workflow. Please check your configuration.")
+            raise RuntimeError(_NO_FUNCTIONS_ERROR)
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between de4f1ac and 2a0a4c5.

📒 Files selected for processing (1)
  • src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py (3 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.py

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.py: In code comments use the abbreviations: nat (API namespace/CLI), nvidia-nat (package), NAT (env var prefixes); never use these abbreviations in documentation
Follow PEP 20 and PEP 8 for Python style
Run yapf with column_limit=120; yapf is used for formatting (run second)
Indent with 4 spaces (no tabs) and end each file with a single trailing newline
Use ruff (ruff check --fix) as a linter (not formatter) per pyproject.toml; fix warnings unless explicitly ignored
Respect Python naming schemes: snake_case for functions/variables, PascalCase for classes, UPPER_CASE for constants
When re-raising exceptions, use bare raise to preserve stack trace; log with logger.error(), not logger.exception()
When catching and logging without re-raising, use logger.exception() to capture full stack trace
Provide Google-style docstrings for every public module, class, function, and CLI command
Docstring first line must be a concise description ending with a period
Validate and sanitize all user input, especially in web or CLI interfaces
Prefer httpx with SSL verification enabled by default and follow OWASP Top-10 recommendations
Use async/await for I/O-bound work (HTTP, DB, file I/O)
Cache expensive computations with functools.lru_cache or an external cache when appropriate
Leverage NumPy vectorized operations when beneficial and feasible

Files:

  • src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py
{src/**/*.py,packages/*/src/**/*.py}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

{src/**/*.py,packages/*/src/**/*.py}: All importable Python code must live under src/ or packages//src/
All public APIs must have Python 3.11+ type hints on parameters and return values
Prefer typing/collections.abc abstractions (e.g., Sequence over list)
Use typing.Annotated for units or metadata when useful
Treat pyright warnings as errors during development

Files:

  • src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py
src/nat/**/*

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

src/nat/**/* contains core functionality; changes should prioritize backward compatibility

Files:

  • src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py

⚙️ CodeRabbit configuration file

This directory contains the core functionality of the toolkit. Changes should prioritize backward compatibility.

Files:

  • src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py
{**/*.py,**/*.sh,**/*.md,**/*.toml,**/*.y?(a)ml,**/*.json,**/*.txt,**/*.ini,**/*.cfg,**/*.ipynb}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

{**/*.py,**/*.sh,**/*.md,**/*.toml,**/*.y?(a)ml,**/*.json,**/*.txt,**/*.ini,**/*.cfg,**/*.ipynb}: Every file must start with the standard SPDX Apache-2.0 header
Confirm copyright years are up to date when a file is changed
All source files must include the SPDX Apache-2.0 header template (copy from an existing file)

Files:

  • src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py
**/*

⚙️ CodeRabbit configuration file

**/*: # Code Review Instructions

  • Ensure the code follows best practices and coding standards. - For Python code, follow
    PEP 20 and
    PEP 8 for style guidelines.
  • Check for security vulnerabilities and potential issues. - Python methods should use type hints for all parameters and return values.
    Example:
    def my_function(param1: int, param2: str) -> bool:
        pass
  • For Python exception handling, ensure proper stack trace preservation:
    • When re-raising exceptions: use bare raise statements to maintain the original stack trace,
      and use logger.error() (not logger.exception()) to avoid duplicate stack trace output.
    • When catching and logging exceptions without re-raising: always use logger.exception()
      to capture the full stack trace information.

Documentation Review Instructions - Verify that documentation and comments are clear and comprehensive. - Verify that the documentation doesn't contain any TODOs, FIXMEs or placeholder text like "lorem ipsum". - Verify that the documentation doesn't contain any offensive or outdated terms. - Verify that documentation and comments are free of spelling mistakes, ensure the documentation doesn't contain any

words listed in the ci/vale/styles/config/vocabularies/nat/reject.txt file, words that might appear to be
spelling mistakes but are listed in the ci/vale/styles/config/vocabularies/nat/accept.txt file are OK.

Misc. - All code (except .mdc files that contain Cursor rules) should be licensed under the Apache License 2.0,

and should contain an Apache License 2.0 header comment at the top of each file.

  • Confirm that copyright years are up-to date whenever a file is changed.

Files:

  • src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py
🧬 Code graph analysis (1)
src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py (5)
src/nat/front_ends/fastapi/fastapi_front_end_plugin_worker.py (2)
  • add_routes (241-253)
  • front_end_config (126-127)
tests/nat/front_ends/mcp/test_mcp_custom_routes.py (1)
  • add_routes (35-51)
src/nat/builder/workflow_builder.py (2)
  • WorkflowBuilder (144-1157)
  • build (263-378)
src/nat/front_ends/mcp/tool_converter.py (1)
  • register_function_with_mcp (254-290)
src/nat/front_ends/mcp/introspection_token_verifier.py (1)
  • IntrospectionTokenVerifier (28-73)
🪛 Ruff (0.14.2)
src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py

167-167: Avoid specifying long messages outside the exception class

(TRY003)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: CI Pipeline / Check
🔇 Additional comments (7)
src/nat/front_ends/mcp/mcp_front_end_plugin_worker.py (7)

37-43: LGTM!

The class documentation clearly explains the purpose of the base class and provides appropriate guidance on which class to inherit from.


91-101: LGTM!

The abstract method provides a clear extensibility point for customizing MCP server creation. The docstring appropriately documents that subclasses of FastMCP can be returned.


103-116: LGTM!

The updated documentation clearly explains how plugins should implement this method and how they can leverage the _default_add_routes() helper.


117-170: Well-structured default implementation.

The method provides a comprehensive default route registration flow that subclasses can leverage. The logic for filtering functions by tool_names correctly handles both exact function names and group-name prefixes.


303-321: LGTM!

The class documentation provides an excellent example demonstrating how to extend the worker class and customize server behavior while still leveraging the default route registration.


323-352: Authentication setup looks correct, but verify protocol usage.

The authentication wiring correctly creates AuthSettings and IntrospectionTokenVerifier when server_auth is configured. However, please verify the protocol used in the server_url.


354-362: LGTM!

The implementation correctly delegates to the base class _default_add_routes() method, providing the standard route registration behavior while allowing subclasses to override and customize as needed.

@AnuradhaKaruppiah
Copy link
Contributor Author

/merge

@rapids-bot rapids-bot bot merged commit 1fc7768 into NVIDIA:develop Oct 29, 2025
17 checks passed
@AnuradhaKaruppiah AnuradhaKaruppiah deleted the ak-nat-mcp-custom-frontend branch October 29, 2025 22:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

improvement Improvement to existing functionality non-breaking Non-breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants