Skip to content

CWFHEALTH-5046: Add retry logic to MCP server registration#2163

Open
willianrampazzo wants to merge 1 commit into
lightspeed-core:mainfrom
willianrampazzo:add_mcp_retry
Open

CWFHEALTH-5046: Add retry logic to MCP server registration#2163
willianrampazzo wants to merge 1 commit into
lightspeed-core:mainfrom
willianrampazzo:add_mcp_retry

Conversation

@willianrampazzo

@willianrampazzo willianrampazzo commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Add retry on APIConnectionError to _register_mcp_toolgroups_async(), preventing lightspeed-stack from crashing when Llama Stack is briefly unreachable during MCP server registration at startup. Reuses the existing max_retries and retry_delay config from llama_stack settings, following the same pattern as check_llama_stack_version().

CWFHEALTH-5046: Add retry logic to MCP server registration

Description

Type of change

  • Refactor
  • New feature
  • Bug fix
  • CVE fix
  • Optimization
  • Documentation Update
  • Configuration Update
  • Bump-up service version
  • Bump-up dependent library
  • Bump-up library or tool used for development (does not change the final image)
  • CI configuration change
  • Konflux configuration change
  • Unit tests improvement
  • Integration tests improvement
  • End to end tests improvement
  • Benchmarks improvement

Tools used to create PR

Identify any AI code assistants used in this PR (for transparency and review context)

  • Assisted-by: (e.g., Claude, CodeRabbit, Ollama, etc., N/A if not used)
  • Generated by: (e.g., tool name and version; N/A if not used)

Related Tickets & Documents

  • Related Issue # CWFHEALTH-5046

Checklist before requesting a review

  • I have performed a self-review of my code.
  • PR has passed all pre-merge test jobs.
  • If it is a core feature, I have added thorough tests.

Testing

  • Please provide detailed steps to perform tests related to this code change.
  • How were the fix/results from this change verified? Please provide relevant screenshots or results.

Summary by CodeRabbit

  • Reliability

    • MCP toolgroup registration now automatically retries temporary connection failures.
    • Retry attempts and delay are configurable.
    • Non-retryable errors continue to surface immediately, while exhausted retries report the failure clearly.
    • Invalid retry settings are rejected.
  • Tests

    • Added coverage for successful registration, retry behavior, exhausted retries, configuration validation, and error handling.

Add retry on APIConnectionError to _register_mcp_toolgroups_async(),
preventing lightspeed-stack from crashing when Llama Stack is briefly
unreachable during MCP server registration at startup. Reuses the
existing max_retries and retry_delay config from llama_stack settings,
following the same pattern as check_llama_stack_version().

CWFHEALTH-5046: Add retry logic to MCP server registration

Signed-off-by: Willian Rampazzo <willianr@redhat.com>
@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

MCP toolgroup registration now accepts configurable retry settings in both client modes. The registration helper retries APIConnectionError, validates max_retries, and has unit tests covering retry, failure, and exception behavior.

Changes

MCP registration retry flow

Layer / File(s) Summary
Retry configuration wiring
src/utils/common.py
Retry defaults and configuration.llama_stack values are passed to MCP registration for library-client and service-client modes.
Retry execution and validation
src/utils/common.py, tests/unit/utils/test_common.py
Toolgroup listing and registration retry on APIConnectionError; invalid retry counts and non-connection exceptions are handled and tested.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested reviewers: tisnik

Sequence Diagram(s)

sequenceDiagram
  participant Configuration
  participant register_mcp_servers_async
  participant _register_mcp_toolgroups_async
  participant MCPToolgroupsAPI
  Configuration->>register_mcp_servers_async: provide max_retries and retry_delay
  register_mcp_servers_async->>_register_mcp_toolgroups_async: invoke with retry configuration
  _register_mcp_toolgroups_async->>MCPToolgroupsAPI: list existing toolgroups
  MCPToolgroupsAPI-->>_register_mcp_toolgroups_async: toolgroups or APIConnectionError
  _register_mcp_toolgroups_async->>MCPToolgroupsAPI: register missing toolgroups
  MCPToolgroupsAPI-->>_register_mcp_toolgroups_async: success or APIConnectionError
  _register_mcp_toolgroups_async->>_register_mcp_toolgroups_async: sleep and retry after connection error
Loading
🚥 Pre-merge checks | ✅ 7
✅ Passed checks (7 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Performance And Algorithmic Complexity ✅ Passed Retries are bounded by max_retries; list() is once per attempt and per-server register loop is pre-existing, so no meaningful regression.
Security And Secret Handling ✅ Passed No new secret leakage, auth gaps, or injection paths were introduced; the change only adds APIConnectionError retries in src/utils/common.py.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding retry logic to MCP server registration.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
✨ Simplify code
  • Create PR with simplified code

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (1)
src/utils/common.py (1)

46-68: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consolidate the identical registration call to avoid duplication.

Since the registration step is identical for both the library and service clients, you can consolidate the _register_mcp_toolgroups_async call after the if/else block to DRY up the code.

♻️ Proposed refactor
     if configuration.llama_stack.use_as_library_client:
         # Library client - use async interface
         client = cast(
             AsyncLlamaStackAsLibraryClient, AsyncLlamaStackClientHolder().get_client()
         )
         await client.initialize()
-        await _register_mcp_toolgroups_async(
-            client,
-            configuration.mcp_servers,
-            logger,
-            max_retries=configuration.llama_stack.max_retries,
-            retry_delay=configuration.llama_stack.retry_delay,
-        )
     else:
         # Service client - also use async interface
         client = AsyncLlamaStackClientHolder().get_client()
-        await _register_mcp_toolgroups_async(
-            client,
-            configuration.mcp_servers,
-            logger,
-            max_retries=configuration.llama_stack.max_retries,
-            retry_delay=configuration.llama_stack.retry_delay,
-        )
+
+    await _register_mcp_toolgroups_async(
+        client,
+        configuration.mcp_servers,
+        logger,
+        max_retries=configuration.llama_stack.max_retries,
+        retry_delay=configuration.llama_stack.retry_delay,
+    )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/common.py` around lines 46 - 68, Consolidate the duplicated
_register_mcp_toolgroups_async invocation in the client setup flow: keep client
selection and library-only initialize() inside the if/else, then call
_register_mcp_toolgroups_async once afterward using the selected client and
existing configuration arguments.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/utils/common.py`:
- Around line 46-68: Consolidate the duplicated _register_mcp_toolgroups_async
invocation in the client setup flow: keep client selection and library-only
initialize() inside the if/else, then call _register_mcp_toolgroups_async once
afterward using the selected client and existing configuration arguments.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: ac427fe8-2424-4a9d-8ae3-ef40d1e3fada

📥 Commits

Reviewing files that changed from the base of the PR and between 938dcac and bd12ae1.

📒 Files selected for processing (2)
  • src/utils/common.py
  • tests/unit/utils/test_common.py
📜 Review details
⏰ Context from checks skipped due to timeout. (6)
  • GitHub Check: Pylinter
  • GitHub Check: integration_tests (3.13)
  • GitHub Check: E2E: library mode / ci / group 1
  • GitHub Check: radon
  • GitHub Check: Pyright
  • GitHub Check: spectral
🧰 Additional context used
📓 Path-based instructions (6)
**/*

📄 CodeRabbit inference engine (Custom checks)

**/*: Flag meaningful O(n^2)+ algorithms on non-trivial inputs, including handlers and Kubernetes list operations.
Flag N+1 patterns that list items and then query once per item, including Kubernetes API and database access.
Flag expensive work inside loops, including API calls, JSON parsing, and regex compilation.
Flag unbounded growth in caches, watchers, or buffers when eviction or limits are missing.
Flag missing pagination or limits on list operations and API endpoints.
Flag secrets or tokens logged in plaintext or hardcoded in source.
Flag API endpoints missing authentication or authorization.
Flag injection vulnerabilities, including SQL injection, command injection, and path traversal.
Flag sensitive data leaked in API responses, WebSocket messages, or logs.
Flag Kubernetes Secrets and Red Hat secrets missing OwnerReferences.

Files:

  • src/utils/common.py
  • tests/unit/utils/test_common.py
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Use absolute imports for internal Python modules.
Start every module with a descriptive docstring and use logger = get_logger(__name__) for module logging.
Define shared constants in the central constants.py module, use descriptive comments, and annotate constants with Final[type].
Use complete type annotations for function parameters and return values, modern union syntax, and typing_extensions.Self for model validators.
Document all modules, classes, and functions using Google-style Python docstrings, including applicable Parameters, Returns, Raises, and Attributes sections.
Use descriptive snake_case, action-oriented function names such as get_, validate_, and check_.
Avoid modifying input parameters in place; return a newly created data structure instead.
Use async def for I/O operations and external API calls.
Use standard logger levels appropriately: debug for diagnostics, info for normal execution, warning for unexpected conditions, and error for serious failures.
Name classes with PascalCase and use descriptive suffixes such as Configuration, Error/Exception, Resolver, and Interface where applicable.
Use ABC and @abstractmethod for abstract interfaces; provide complete, specific type annotations for class attributes and avoid Any.

Files:

  • src/utils/common.py
  • tests/unit/utils/test_common.py
src/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Configuration models must extend ConfigurationBase, whose extra="forbid" behavior rejects unknown fields; use types such as Optional[FilePath], PositiveInt, and SecretStr where appropriate.

Files:

  • src/utils/common.py
**/*.{py,yaml,yml,json,toml}

📄 CodeRabbit inference engine (AGENTS.md)

Never commit secrets or keys; use environment variables for sensitive data.

Files:

  • src/utils/common.py
  • tests/unit/utils/test_common.py
tests/unit/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Use pytest for unit tests, shared fixtures in conftest.py, pytest-mock for mocks, and pytest.mark.asyncio for asynchronous tests; do not use unittest.

Files:

  • tests/unit/utils/test_common.py
tests/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Maintain at least 60% unit-test coverage and 10% integration-test coverage.

Files:

  • tests/unit/utils/test_common.py
🧠 Learnings (2)
📚 Learning: 2026-06-24T13:45:37.249Z
Learnt from: Jdubrick
Repo: lightspeed-core/lightspeed-stack PR: 1971
File: src/utils/markdown_repair.py:31-36
Timestamp: 2026-06-24T13:45:37.249Z
Learning: In the lightspeed-stack repository, docstrings must use the section header name "Parameters:" (not "Args:") for function arguments, even if the project references Google Python docstring conventions. Ensure docstrings follow the project’s established "Parameters:" header format for any documented function parameters.

Applied to files:

  • src/utils/common.py
  • tests/unit/utils/test_common.py
📚 Learning: 2026-07-06T15:26:18.398Z
Learnt from: Jdubrick
Repo: lightspeed-core/lightspeed-stack PR: 2071
File: src/models/config.py:2416-2422
Timestamp: 2026-07-06T15:26:18.398Z
Learning: In this repo’s Python code under src/**, don’t treat differences in string concatenation style as a style inconsistency when Black has effectively forced (or made clearer) use of explicit `+` string concatenation in multi-line logger/string expressions. If adjacent-literal implicit concatenation is avoided/changed specifically to accommodate Black’s formatting in these call sites, accept the `+` usage and don’t recommend converting it solely for consistency with nearby blocks that use implicit concatenation.

Applied to files:

  • src/utils/common.py
🔇 Additional comments (2)
src/utils/common.py (1)

10-13: LGTM!

Also applies to: 87-89, 99-137

tests/unit/utils/test_common.py (1)

6-6: LGTM!

Also applies to: 18-18, 419-612

@willianrampazzo willianrampazzo changed the title Add retry logic to MCP server registration CWFHEALTH-5046: Add retry logic to MCP server registration Jul 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant