Skip to content

MGMT-21086: support different protocols#38

Merged
openshift-merge-bot[bot] merged 1 commit intoopenshift-assisted:masterfrom
rccrdpccl:MGMT-21086-support-streamable-http
Jul 24, 2025
Merged

MGMT-21086: support different protocols#38
openshift-merge-bot[bot] merged 1 commit intoopenshift-assisted:masterfrom
rccrdpccl:MGMT-21086-support-streamable-http

Conversation

@rccrdpccl
Copy link
Copy Markdown
Contributor

@rccrdpccl rccrdpccl commented Jul 22, 2025

Add the possibility to support different protocols.
We can set the env var TRANSPORT to "sse", "http" or "streamable-http".
The default path for sse is /sse and for streamable-http is /mcp

We kept the default to SSE to maintain the current behaviour.

Summary by CodeRabbit

  • Chores
    • Updated the minimum required version of the fastmcp dependency.
    • Improved internal naming consistency and updated import paths.
    • Enhanced app initialization to support configurable transport protocol via environment variable.
    • Refined token retrieval to improve header access.
    • Updated tests to use client-based tool invocation and unified header mocking.
    • Added a new deployment parameter to configure the transport protocol with default and allowed values.

@openshift-ci-robot
Copy link
Copy Markdown

openshift-ci-robot commented Jul 22, 2025

@rccrdpccl: This pull request references MGMT-21086 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the task to target the "4.20.0" version, but no target version was set.

Details

In response to this:

Add the possibility to support different protocols.
We can set the env var TRANSPORT to "sse", "http" or "streamable-http".
The default path for sse is /sse and for streamable-http is /mcp

We kept the default to SSE to maintain the current behaviour.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jul 22, 2025
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jul 22, 2025

Walkthrough

The changes update the fastmcp dependency version requirement in pyproject.toml and rename the MCP server instance variable in server.py from mcp to mcp_server. The import path for FastMCP is updated, header retrieval is refactored to use get_http_headers(), and app initialization now supports a configurable transport protocol via an environment variable. The test suite is refactored to mock headers directly and invoke tool functions through the fastmcp.Client interface.

Changes

File(s) Change Summary
pyproject.toml Updated fastmcp dependency requirement from >=2.8.0 to >=2.10.6.
server.py Renamed MCP instance variable to mcp_server, updated import paths, replaced header access with get_http_headers(), updated decorators, simplified list_tools(), added get_transport() function, and enabled transport configuration via environment variable.
tests/test_server.py Refactored tests to mock get_http_headers() instead of MCP context/request headers and changed tool function calls to use fastmcp.Client.call_tool() within async context instead of direct calls.
template.yaml Added TRANSPORT parameter with default "sse" and description; added TRANSPORT environment variable to container spec in the deployment.

Estimated code review effort

3 (~40 minutes)

Suggested labels

size/L

Poem

In the code garden where rabbits hop,
The MCP server got a name swap!
FastMCP’s path is shiny and new,
With transport options in the queue.
Tests now mock headers with care,
And call tools through clients fair.
🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@openshift-ci openshift-ci Bot added the size/M Denotes a PR that changes 30-99 lines, ignoring generated files. label Jul 22, 2025
@openshift-ci-robot
Copy link
Copy Markdown

openshift-ci-robot commented Jul 22, 2025

@rccrdpccl: This pull request references MGMT-21086 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the task to target the "4.20.0" version, but no target version was set.

Details

In response to this:

Add the possibility to support different protocols.
We can set the env var TRANSPORT to "sse", "http" or "streamable-http".
The default path for sse is /sse and for streamable-http is /mcp

We kept the default to SSE to maintain the current behaviour.

Summary by CodeRabbit

  • Chores
  • Updated the minimum required version of the fastmcp dependency.
  • Improved internal naming consistency and updated import paths.
  • Enhanced app initialization to support configurable transport protocol via environment variable.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

Copy link
Copy Markdown

@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: 4

🧹 Nitpick comments (1)
server.py (1)

546-549: Fix docstring formatting issue.

Remove the blank line after the docstring to satisfy pydocstyle requirements.

 def list_tools() -> list[str]:
     """List all MCP tools."""
-
     tools = asyncio.run(mcp_server.get_tools())
     return list(tools.keys())
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d7fb34d and 101abcb.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (2)
  • pyproject.toml (1 hunks)
  • server.py (17 hunks)
🪛 GitHub Actions: Black
server.py

[error] 1-1: Black formatting check failed. The file would be reformatted. Run 'black server.py' to fix code style issues.

🪛 GitHub Actions: Pydocstyle
server.py

[error] 547-547: pydocstyle D202: No blank lines allowed after function docstring (found 1) in public function list_tools.

🪛 GitHub Actions: Python linter
server.py

[error] 67-67: pylint E1101: Instance of 'FastMCP' has no 'get_context' member (no-member)


[error] 94-94: pylint E1101: Instance of 'FastMCP' has no 'get_context' member (no-member)


[error] 34-34: pylint E1101: Module 'server' has no 'mcp' member (no-member)


[error] 95-95: pylint E1101: Module 'server' has no 'mcp' member (no-member)


[error] 224-224: pylint E1101: Module 'server' has no 'mcp' member (no-member)

🪛 GitHub Actions: Unit Tests
server.py

[error] 34-34: AttributeError: module 'server' has no attribute 'mcp' at setup of multiple TestTokenFunctions tests.


[error] 95-95: AttributeError: module 'server' has no attribute 'mcp' in test_get_offline_token_no_request.


[error] 224-224: AttributeError: module 'server' has no attribute 'mcp' in test_get_access_token_no_request_context.


[error] 265-265: TypeError: 'FunctionTool' object is not callable in test_cluster_info_success.


[error] 298-298: TypeError: 'FunctionTool' object is not callable in test_list_clusters_success.


[error] 318-318: TypeError: 'FunctionTool' object is not callable in test_cluster_events_success.


[error] 340-340: TypeError: 'FunctionTool' object is not callable in test_host_events_success.


[error] 370-370: TypeError: 'FunctionTool' object is not callable in test_cluster_iso_download_url_success.


[error] 424-424: TypeError: 'FunctionTool' object is not callable in test_cluster_iso_download_url_multiple_infraenvs.


[error] 464-464: TypeError: 'FunctionTool' object is not callable in test_cluster_iso_download_url_no_expiration.


[error] 496-496: TypeError: 'FunctionTool' object is not callable in test_cluster_iso_download_url_zero_expiration.


[error] 519-519: TypeError: 'FunctionTool' object is not callable in test_cluster_iso_download_url_no_infraenvs.


[error] 552-552: TypeError: 'FunctionTool' object is not callable in test_create_cluster_success.


[error] 581-581: TypeError: 'FunctionTool' object is not callable in test_set_cluster_vips_success.


[error] 602-602: TypeError: 'FunctionTool' object is not callable in test_install_cluster_success.


[error] 620-620: TypeError: 'FunctionTool' object is not callable in test_list_versions_success.


[error] 642-642: TypeError: 'FunctionTool' object is not callable in test_list_operator_bundles_success.


[error] 664-664: TypeError: 'FunctionTool' object is not callable in test_add_operator_bundle_to_cluster_success.


[error] 690-690: TypeError: 'FunctionTool' object is not callable in test_set_host_role_success.


[error] 715-715: TypeError: 'FunctionTool' object is not callable in test_cluster_credentials_download_url_success.


[error] 743-743: TypeError: 'FunctionTool' object is not callable in test_cluster_credentials_download_url_no_expiration.


[error] 773-773: TypeError: 'FunctionTool' object is not callable in test_cluster_credentials_download_url_zero_expiration.

🪛 GitHub Actions: Type checks
server.py

[error] 21-21: mypy: Need type annotation for "mcp_server" [var-annotated]


[error] 549-549: mypy: Argument 1 to "run" has incompatible type "Coroutine[Any, Any, dict[str, Tool]]"; expected "Coroutine[Any, Any, list[str]]" [arg-type]


[error] 554-554: mypy: Argument "transport" to "http_app" of "FastMCP" has incompatible type "str"; expected "Literal['http', 'streamable-http', 'sse']" [arg-type]


[error] 265-265: mypy: "FunctionTool" not callable [operator]


[error] 298-298: mypy: "FunctionTool" not callable [operator]


[error] 318-318: mypy: "FunctionTool" not callable [operator]


[error] 340-340: mypy: "FunctionTool" not callable [operator]


[error] 370-370: mypy: "FunctionTool" not callable [operator]


[error] 424-424: mypy: "FunctionTool" not callable [operator]


[error] 464-464: mypy: "FunctionTool" not callable [operator]


[error] 496-496: mypy: "FunctionTool" not callable [operator]


[error] 519-519: mypy: "FunctionTool" not callable [operator]


[error] 552-552: mypy: "FunctionTool" not callable [operator]


[error] 581-581: mypy: "FunctionTool" not callable [operator]


[error] 602-602: mypy: "FunctionTool" not callable [operator]


[error] 620-620: mypy: "FunctionTool" not callable [operator]


[error] 642-642: mypy: "FunctionTool" not callable [operator]


[error] 664-664: mypy: "FunctionTool" not callable [operator]


[error] 690-690: mypy: "FunctionTool" not callable [operator]


[error] 715-715: mypy: "FunctionTool" not callable [operator]


[error] 743-743: mypy: "FunctionTool" not callable [operator]


[error] 773-773: mypy: "FunctionTool" not callable [operator]

🪛 GitHub Actions: Pyright
server.py

[error] 67-67: Cannot access attribute "get_context" for class "FastMCP[Unknown]" (reportAttributeAccessIssue)


[error] 94-94: Cannot access attribute "get_context" for class "FastMCP[Unknown]" (reportAttributeAccessIssue)


[error] 549-549: Type "dict[str, Tool]" is not assignable to return type "list[str]" (reportReturnType)


[error] 554-554: Argument of type "str" cannot be assigned to parameter "transport" of type "Literal['http', 'streamable-http', 'sse']" in function "http_app" (reportArgumentType)


[error] 34-34: "mcp" is not a known attribute of module "server" (reportAttributeAccessIssue)


[error] 95-95: "mcp" is not a known attribute of module "server" (reportAttributeAccessIssue)


[error] 224-224: "mcp" is not a known attribute of module "server" (reportAttributeAccessIssue)


[error] 265-265: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 298-298: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 318-318: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 340-340: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 370-370: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 424-424: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 464-464: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 496-496: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 519-519: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 552-552: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 581-581: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 602-602: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 620-620: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 642-642: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 664-664: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 690-690: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 715-715: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 743-743: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 773-773: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)

🧰 Additional context used
🪛 GitHub Actions: Black
server.py

[error] 1-1: Black formatting check failed. The file would be reformatted. Run 'black server.py' to fix code style issues.

🪛 GitHub Actions: Pydocstyle
server.py

[error] 547-547: pydocstyle D202: No blank lines allowed after function docstring (found 1) in public function list_tools.

🪛 GitHub Actions: Python linter
server.py

[error] 67-67: pylint E1101: Instance of 'FastMCP' has no 'get_context' member (no-member)


[error] 94-94: pylint E1101: Instance of 'FastMCP' has no 'get_context' member (no-member)


[error] 34-34: pylint E1101: Module 'server' has no 'mcp' member (no-member)


[error] 95-95: pylint E1101: Module 'server' has no 'mcp' member (no-member)


[error] 224-224: pylint E1101: Module 'server' has no 'mcp' member (no-member)

🪛 GitHub Actions: Unit Tests
server.py

[error] 34-34: AttributeError: module 'server' has no attribute 'mcp' at setup of multiple TestTokenFunctions tests.


[error] 95-95: AttributeError: module 'server' has no attribute 'mcp' in test_get_offline_token_no_request.


[error] 224-224: AttributeError: module 'server' has no attribute 'mcp' in test_get_access_token_no_request_context.


[error] 265-265: TypeError: 'FunctionTool' object is not callable in test_cluster_info_success.


[error] 298-298: TypeError: 'FunctionTool' object is not callable in test_list_clusters_success.


[error] 318-318: TypeError: 'FunctionTool' object is not callable in test_cluster_events_success.


[error] 340-340: TypeError: 'FunctionTool' object is not callable in test_host_events_success.


[error] 370-370: TypeError: 'FunctionTool' object is not callable in test_cluster_iso_download_url_success.


[error] 424-424: TypeError: 'FunctionTool' object is not callable in test_cluster_iso_download_url_multiple_infraenvs.


[error] 464-464: TypeError: 'FunctionTool' object is not callable in test_cluster_iso_download_url_no_expiration.


[error] 496-496: TypeError: 'FunctionTool' object is not callable in test_cluster_iso_download_url_zero_expiration.


[error] 519-519: TypeError: 'FunctionTool' object is not callable in test_cluster_iso_download_url_no_infraenvs.


[error] 552-552: TypeError: 'FunctionTool' object is not callable in test_create_cluster_success.


[error] 581-581: TypeError: 'FunctionTool' object is not callable in test_set_cluster_vips_success.


[error] 602-602: TypeError: 'FunctionTool' object is not callable in test_install_cluster_success.


[error] 620-620: TypeError: 'FunctionTool' object is not callable in test_list_versions_success.


[error] 642-642: TypeError: 'FunctionTool' object is not callable in test_list_operator_bundles_success.


[error] 664-664: TypeError: 'FunctionTool' object is not callable in test_add_operator_bundle_to_cluster_success.


[error] 690-690: TypeError: 'FunctionTool' object is not callable in test_set_host_role_success.


[error] 715-715: TypeError: 'FunctionTool' object is not callable in test_cluster_credentials_download_url_success.


[error] 743-743: TypeError: 'FunctionTool' object is not callable in test_cluster_credentials_download_url_no_expiration.


[error] 773-773: TypeError: 'FunctionTool' object is not callable in test_cluster_credentials_download_url_zero_expiration.

🪛 GitHub Actions: Type checks
server.py

[error] 21-21: mypy: Need type annotation for "mcp_server" [var-annotated]


[error] 549-549: mypy: Argument 1 to "run" has incompatible type "Coroutine[Any, Any, dict[str, Tool]]"; expected "Coroutine[Any, Any, list[str]]" [arg-type]


[error] 554-554: mypy: Argument "transport" to "http_app" of "FastMCP" has incompatible type "str"; expected "Literal['http', 'streamable-http', 'sse']" [arg-type]


[error] 265-265: mypy: "FunctionTool" not callable [operator]


[error] 298-298: mypy: "FunctionTool" not callable [operator]


[error] 318-318: mypy: "FunctionTool" not callable [operator]


[error] 340-340: mypy: "FunctionTool" not callable [operator]


[error] 370-370: mypy: "FunctionTool" not callable [operator]


[error] 424-424: mypy: "FunctionTool" not callable [operator]


[error] 464-464: mypy: "FunctionTool" not callable [operator]


[error] 496-496: mypy: "FunctionTool" not callable [operator]


[error] 519-519: mypy: "FunctionTool" not callable [operator]


[error] 552-552: mypy: "FunctionTool" not callable [operator]


[error] 581-581: mypy: "FunctionTool" not callable [operator]


[error] 602-602: mypy: "FunctionTool" not callable [operator]


[error] 620-620: mypy: "FunctionTool" not callable [operator]


[error] 642-642: mypy: "FunctionTool" not callable [operator]


[error] 664-664: mypy: "FunctionTool" not callable [operator]


[error] 690-690: mypy: "FunctionTool" not callable [operator]


[error] 715-715: mypy: "FunctionTool" not callable [operator]


[error] 743-743: mypy: "FunctionTool" not callable [operator]


[error] 773-773: mypy: "FunctionTool" not callable [operator]

🪛 GitHub Actions: Pyright
server.py

[error] 67-67: Cannot access attribute "get_context" for class "FastMCP[Unknown]" (reportAttributeAccessIssue)


[error] 94-94: Cannot access attribute "get_context" for class "FastMCP[Unknown]" (reportAttributeAccessIssue)


[error] 549-549: Type "dict[str, Tool]" is not assignable to return type "list[str]" (reportReturnType)


[error] 554-554: Argument of type "str" cannot be assigned to parameter "transport" of type "Literal['http', 'streamable-http', 'sse']" in function "http_app" (reportArgumentType)


[error] 34-34: "mcp" is not a known attribute of module "server" (reportAttributeAccessIssue)


[error] 95-95: "mcp" is not a known attribute of module "server" (reportAttributeAccessIssue)


[error] 224-224: "mcp" is not a known attribute of module "server" (reportAttributeAccessIssue)


[error] 265-265: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 298-298: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 318-318: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 340-340: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 370-370: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 424-424: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 464-464: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 496-496: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 519-519: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 552-552: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 581-581: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 602-602: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 620-620: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 642-642: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 664-664: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 690-690: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 715-715: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 743-743: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)


[error] 773-773: Object of type "FunctionTool" is not callable; Attribute "call" is unknown (reportCallIssue)

⏰ 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: Red Hat Konflux / assisted-service-mcp-saas-main-on-pull-request
🔇 Additional comments (3)
pyproject.toml (1)

9-9: LGTM! Dependency version update aligns with API changes.

The fastmcp version update to >=2.10.6 properly supports the new import path and API usage changes in server.py.

server.py (2)

15-15: LGTM! Import path updated correctly.

The import change from mcp.server.fastmcp to fastmcp aligns with the fastmcp >=2.10.6 API.


120-549: Update tests for FastMCP FunctionTool invocation

I didn’t find any test files calling the legacy decorated functions in this repo. To restore test compatibility with the new FastMCP API, update your tests to:

  • Retrieve tools via the MCP server:
    import asyncio
    tools = asyncio.run(mcp_server.get_tools())
  • Select the desired tool by name:
    cluster_info = next(t for t in tools if t.name == "cluster_info")
  • Invoke it asynchronously instead of calling the function directly:
    result = asyncio.run(cluster_info.invoke(cluster_id="…"))

If your tests live outside tests/ or under a different path, locate them and apply the same pattern.

Comment thread server.py Outdated
Comment thread server.py Outdated
Comment thread server.py Outdated
Comment thread server.py Outdated
@rccrdpccl
Copy link
Copy Markdown
Contributor Author

/hold

@openshift-ci openshift-ci Bot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Jul 22, 2025
@rccrdpccl rccrdpccl force-pushed the MGMT-21086-support-streamable-http branch from 101abcb to 02e691e Compare July 22, 2025 14:19
@openshift-ci openshift-ci Bot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. and removed size/M Denotes a PR that changes 30-99 lines, ignoring generated files. labels Jul 22, 2025
@rccrdpccl rccrdpccl force-pushed the MGMT-21086-support-streamable-http branch from 02e691e to 2fbe6e6 Compare July 22, 2025 14:20
@openshift-ci openshift-ci Bot added size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. and removed size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Jul 22, 2025
@openshift-ci-robot
Copy link
Copy Markdown

openshift-ci-robot commented Jul 22, 2025

@rccrdpccl: This pull request references MGMT-21086 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the task to target the "4.20.0" version, but no target version was set.

Details

In response to this:

Add the possibility to support different protocols.
We can set the env var TRANSPORT to "sse", "http" or "streamable-http".
The default path for sse is /sse and for streamable-http is /mcp

We kept the default to SSE to maintain the current behaviour.

Summary by CodeRabbit

  • Chores
  • Updated the minimum required version of the fastmcp dependency.
  • Improved internal naming consistency and updated import paths.
  • Enhanced app initialization to support configurable transport protocol via environment variable.
  • Refined token retrieval to improve header access.
  • Updated tests to use client-based tool invocation and unified header mocking.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

Copy link
Copy Markdown

@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: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 101abcb and 2fbe6e6.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • pyproject.toml (1 hunks)
  • server.py (17 hunks)
  • tests/test_server.py (29 hunks)
🧬 Code Graph Analysis (1)
tests/test_server.py (3)
server.py (6)
  • get_offline_token (46-75)
  • get_access_token (78-116)
  • list_clusters (148-177)
  • create_cluster (289-335)
  • install_cluster (375-400)
  • add_operator_bundle_to_cluster (447-470)
tests/test_assisted_service_api.py (1)
  • client (32-37)
service_client/assisted_service_api.py (14)
  • get_cluster (98-137)
  • list_clusters (139-161)
  • get_events (163-225)
  • list_infra_envs (263-298)
  • get_infra_env_download_url (682-723)
  • create_cluster (300-349)
  • create_infra_env (351-390)
  • update_cluster (392-441)
  • install_cluster (443-473)
  • get_openshift_versions (475-505)
  • get_operator_bundles (507-529)
  • add_operator_bundle_to_cluster (531-581)
  • update_host (583-630)
  • get_presigned_for_cluster_credentials (632-680)
🪛 GitHub Actions: Pydocstyle
tests/test_server.py

[error] 546-546: pydocstyle D202: No blank lines allowed after function docstring (found 1) in public function list_tools.

🪛 GitHub Actions: Type checks
tests/test_server.py

[error] 22-22: mypy: Need type annotation for "mcp_server" [var-annotated]


[error] 548-548: mypy: Argument 1 to "run" has incompatible type "Coroutine[Any, Any, dict[str, Tool]]"; expected "Coroutine[Any, Any, list[str]]" [arg-type]


[error] 553-553: mypy: Argument "transport" to "http_app" of "FastMCP" has incompatible type "str"; expected "Literal['http', 'streamable-http', 'sse']" [arg-type]

🪛 GitHub Actions: Pyright
tests/test_server.py

[error] 548-548: Pyright error: Type "dict[str, Tool]" is not assignable to return type "list[str]" (reportReturnType).


[error] 553-553: Pyright error: Argument of type "str" cannot be assigned to parameter "transport" of type "Literal['http', 'streamable-http', 'sse']" in function "http_app" (reportArgumentType).


[error] 247-247: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 247-247: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 247-247: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 247-247: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 281-281: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 281-281: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 281-281: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 281-281: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 302-302: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 302-302: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 302-302: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 302-302: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 326-326: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 326-326: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 326-326: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 326-326: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 359-359: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 359-359: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 359-359: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 359-359: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 422-422: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 422-422: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 422-422: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 422-422: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 461-461: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 461-461: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 461-461: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 461-461: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 498-498: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 498-498: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 498-498: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 498-498: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 524-524: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 524-524: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 524-524: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 524-524: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 569-569: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 569-569: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 569-569: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 569-569: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 608-608: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 608-608: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 608-608: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 608-608: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 631-631: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 631-631: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 631-631: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 631-631: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 652-652: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 652-652: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 652-652: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 652-652: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 676-676: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 676-676: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 676-676: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 676-676: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 700-700: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 700-700: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 700-700: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 700-700: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 727-727: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 727-727: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 727-727: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 727-727: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 756-756: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 756-756: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 756-756: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 756-756: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 785-785: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 785-785: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 785-785: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 785-785: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 817-817: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 817-817: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 817-817: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 817-817: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).

✅ Files skipped from review due to trivial changes (1)
  • pyproject.toml
🚧 Files skipped from review as they are similar to previous changes (1)
  • server.py
🧰 Additional context used
🧬 Code Graph Analysis (1)
tests/test_server.py (3)
server.py (6)
  • get_offline_token (46-75)
  • get_access_token (78-116)
  • list_clusters (148-177)
  • create_cluster (289-335)
  • install_cluster (375-400)
  • add_operator_bundle_to_cluster (447-470)
tests/test_assisted_service_api.py (1)
  • client (32-37)
service_client/assisted_service_api.py (14)
  • get_cluster (98-137)
  • list_clusters (139-161)
  • get_events (163-225)
  • list_infra_envs (263-298)
  • get_infra_env_download_url (682-723)
  • create_cluster (300-349)
  • create_infra_env (351-390)
  • update_cluster (392-441)
  • install_cluster (443-473)
  • get_openshift_versions (475-505)
  • get_operator_bundles (507-529)
  • add_operator_bundle_to_cluster (531-581)
  • update_host (583-630)
  • get_presigned_for_cluster_credentials (632-680)
🪛 GitHub Actions: Pydocstyle
tests/test_server.py

[error] 546-546: pydocstyle D202: No blank lines allowed after function docstring (found 1) in public function list_tools.

🪛 GitHub Actions: Type checks
tests/test_server.py

[error] 22-22: mypy: Need type annotation for "mcp_server" [var-annotated]


[error] 548-548: mypy: Argument 1 to "run" has incompatible type "Coroutine[Any, Any, dict[str, Tool]]"; expected "Coroutine[Any, Any, list[str]]" [arg-type]


[error] 553-553: mypy: Argument "transport" to "http_app" of "FastMCP" has incompatible type "str"; expected "Literal['http', 'streamable-http', 'sse']" [arg-type]

🪛 GitHub Actions: Pyright
tests/test_server.py

[error] 548-548: Pyright error: Type "dict[str, Tool]" is not assignable to return type "list[str]" (reportReturnType).


[error] 553-553: Pyright error: Argument of type "str" cannot be assigned to parameter "transport" of type "Literal['http', 'streamable-http', 'sse']" in function "http_app" (reportArgumentType).


[error] 247-247: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 247-247: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 247-247: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 247-247: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 281-281: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 281-281: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 281-281: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 281-281: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 302-302: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 302-302: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 302-302: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 302-302: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 326-326: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 326-326: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 326-326: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 326-326: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 359-359: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 359-359: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 359-359: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 359-359: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 422-422: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 422-422: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 422-422: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 422-422: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 461-461: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 461-461: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 461-461: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 461-461: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 498-498: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 498-498: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 498-498: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 498-498: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 524-524: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 524-524: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 524-524: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 524-524: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 569-569: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 569-569: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 569-569: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 569-569: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 608-608: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 608-608: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 608-608: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 608-608: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 631-631: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 631-631: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 631-631: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 631-631: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 652-652: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 652-652: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 652-652: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 652-652: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 676-676: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 676-676: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 676-676: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 676-676: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 700-700: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 700-700: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 700-700: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 700-700: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 727-727: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 727-727: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 727-727: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 727-727: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 756-756: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 756-756: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 756-756: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 756-756: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 785-785: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 785-785: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 785-785: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 785-785: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).


[error] 817-817: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 817-817: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 817-817: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 817-817: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).

🔇 Additional comments (5)
tests/test_server.py (5)

7-7: LGTM! Appropriate imports for the refactored test approach.

The addition of Generator type hint and Client import aligns with the new testing pattern.

Also applies to: 13-14


29-33: LGTM! Fixture correctly updated to match server implementation.

The fixture properly mocks get_http_headers which aligns with the refactored token retrieval logic in server.py.


42-59: LGTM! Test correctly validates environment variable precedence.

The test properly verifies that environment variables take precedence over HTTP headers for offline token retrieval.


367-431: Excellent test coverage for multiple infrastructure environments.

The test thoroughly validates the handling of multiple infraenvs, including proper formatting of multiple URLs and verification of all API calls.


571-577: Confirm intentional hardcoding of “chatbot” tag

Both server.py (in the call to client.create_cluster(..., tags="chatbot")) and tests/test_server.py (asserting tags="chatbot") use a literal "chatbot" tag. Please verify that this hardcoded tag is intentional rather than a value that should be configurable.
If it should be configurable, extract it into a constant or configuration parameter and update both the implementation and tests accordingly.

Comment thread tests/test_server.py
Comment thread tests/test_server.py
resp = await client.call_tool(
"cluster_info", {"cluster_id": cluster_id}
)
assert resp.content[0].text == cluster.to_str()
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

⚠️ Potential issue

Apply type-safe content access pattern across all tests.

All test methods accessing resp.content[0].text have the same type safety issue. Consider creating a helper function to safely extract text content:

def get_text_content(resp: CallToolResult) -> str:
    """Safely extract text content from response."""
    if not resp.content:
        raise AssertionError("No content in response")
    
    content = resp.content[0]
    if not hasattr(content, 'text'):
        raise AssertionError(f"Expected text content, got {type(content).__name__}")
    
    return content.text

Then use it consistently:

-                assert resp.content[0].text == expected_result
+                assert get_text_content(resp) == expected_result

Also applies to: 281-281, 302-302, 326-326, 359-359, 422-422, 461-461, 498-498, 524-524, 569-569, 608-608, 631-631, 652-652, 676-676, 700-700, 727-727, 756-756, 785-785, 817-817

🧰 Tools
🪛 GitHub Actions: Pyright

[error] 247-247: Pyright error: Cannot access attribute "text" for class "ImageContent" (reportAttributeAccessIssue).


[error] 247-247: Pyright error: Cannot access attribute "text" for class "AudioContent" (reportAttributeAccessIssue).


[error] 247-247: Pyright error: Cannot access attribute "text" for class "ResourceLink" (reportAttributeAccessIssue).


[error] 247-247: Pyright error: Cannot access attribute "text" for class "EmbeddedResource" (reportAttributeAccessIssue).

🤖 Prompt for AI Agents
In tests/test_server.py at lines 247, 281, 302, 326, 359, 422, 461, 498, 524,
569, 608, 631, 652, 676, 700, 727, 756, 785, and 817, the test code accesses
resp.content[0].text directly without type safety checks. To fix this, create a
helper function that safely extracts the text content from the response by
checking if resp.content is not empty and if the first content item has a 'text'
attribute, raising an AssertionError otherwise. Replace all direct accesses to
resp.content[0].text with calls to this helper function to ensure consistent and
safe content extraction across all tests.

@rccrdpccl rccrdpccl force-pushed the MGMT-21086-support-streamable-http branch 2 times, most recently from e93d03e to 831f4f0 Compare July 22, 2025 15:26
Signed-off-by: Riccardo Piccoli <rpiccoli@redhat.com>
@rccrdpccl rccrdpccl force-pushed the MGMT-21086-support-streamable-http branch from 831f4f0 to 341dc0e Compare July 22, 2025 16:37
@openshift-ci-robot
Copy link
Copy Markdown

openshift-ci-robot commented Jul 22, 2025

@rccrdpccl: This pull request references MGMT-21086 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the task to target the "4.20.0" version, but no target version was set.

Details

In response to this:

Add the possibility to support different protocols.
We can set the env var TRANSPORT to "sse", "http" or "streamable-http".
The default path for sse is /sse and for streamable-http is /mcp

We kept the default to SSE to maintain the current behaviour.

Summary by CodeRabbit

  • Chores
  • Updated the minimum required version of the fastmcp dependency.
  • Improved internal naming consistency and updated import paths.
  • Enhanced app initialization to support configurable transport protocol via environment variable.
  • Refined token retrieval to improve header access.
  • Updated tests to use client-based tool invocation and unified header mocking.
  • Added a new deployment parameter to configure the transport protocol with default and allowed values.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

Copy link
Copy Markdown

@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)
template.yaml (1)

16-18: Consider explicitly setting required: true (or clarifying why it's optional).

Every deployment of assisted-service-mcp will now rely on a valid transport value at runtime.
Making the parameter required helps catch typos or empty overrides early during template processing rather than at application start-up.

- - name: TRANSPORT
-   value: "sse"
-   description: "MCP transport type. Valid values: 'http', 'streamable-http', 'sse'. Defaults to 'sse'."
+ - name: TRANSPORT
+   value: "sse"
+   required: true   # <-- add if the value must always be present
+   description: "MCP transport type. Valid values: 'http', 'streamable-http', 'sse'. Defaults to 'sse'."

If the default of "sse" is genuinely sufficient and the parameter should remain optional, feel free to ignore.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 831f4f0 and 341dc0e.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • pyproject.toml (1 hunks)
  • server.py (17 hunks)
  • template.yaml (2 hunks)
  • tests/test_server.py (29 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • pyproject.toml
  • tests/test_server.py
  • server.py
⏰ 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: Red Hat Konflux / assisted-service-mcp-saas-main-on-pull-request
🔇 Additional comments (1)
template.yaml (1)

87-88: Verify downstream consumers pick up the new TRANSPORT env-var.

The container now receives TRANSPORT=${TRANSPORT}. Double-check:

  1. server.py (or equivalent) reads os.getenv("TRANSPORT", "sse") to keep the default.
  2. CI / Helm charts / GitHub workflows that previously kubectl exec or parse logs don’t assume SSE-only behaviour.
  3. Docs / run-books mention the new knob so operators know how to switch protocols.

No code change needed if these items are already covered.

@rccrdpccl
Copy link
Copy Markdown
Contributor Author

/unhold

/cc @eranco74 @carbonin PTAL

@openshift-ci openshift-ci Bot removed the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Jul 23, 2025
@openshift-ci openshift-ci Bot requested review from carbonin and eranco74 July 23, 2025 08:13
@openshift-ci
Copy link
Copy Markdown

openshift-ci Bot commented Jul 23, 2025

@rccrdpccl: GitHub didn't allow me to request PR reviews from the following users: PTAL.

Note that only openshift-assisted members and repo collaborators can review this PR, and authors cannot review their own PRs.

Details

In response to this:

/unhold

/cc @eranco74 @carbonin PTAL

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@eranco74
Copy link
Copy Markdown
Collaborator

/lgtm

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label Jul 24, 2025
@eranco74
Copy link
Copy Markdown
Collaborator

/approve

@openshift-ci
Copy link
Copy Markdown

openshift-ci Bot commented Jul 24, 2025

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: eranco74, rccrdpccl

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jul 24, 2025
@zszabo-rh
Copy link
Copy Markdown
Contributor

/test ci/prow/images ci/prow/unit

@openshift-ci
Copy link
Copy Markdown

openshift-ci Bot commented Jul 24, 2025

@zszabo-rh: The specified target(s) for /test were not found.
The following commands are available to trigger required jobs:

/test images
/test unit

Use /test all to run all jobs.

Details

In response to this:

/test ci/prow/images ci/prow/unit

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@zszabo-rh
Copy link
Copy Markdown
Contributor

/test images unit

@openshift-merge-bot openshift-merge-bot Bot merged commit f3d540c into openshift-assisted:master Jul 24, 2025
15 checks passed
@carbonin
Copy link
Copy Markdown
Collaborator

Sorry, but this seems to be breaking chat.

I tested locally and in the integration environment and both are broken currently.
It must have something to do with the new mcp package we're importing because just bumping the version and using the same APIs seems to work.

We'll sort out adding this back when we have time, but for now I think getting things working again is the priority.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. lgtm Indicates that a PR is ready to be merged. size/XL Denotes a PR that changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants