Skip to content

Conversation

@vsraccubits
Copy link
Contributor

Summary

  • Fix RenamedToolset error in response formatters when MCP tools have gateway_slugs configured
  • Make get_tool_list() self-contained to avoid calling non-existent list_tools() method on RenamedToolset
  • Fix server_label validation error by providing default value

Problem

After the MCP tool name shortening feature was added, both non-streaming and streaming formatters started failing with:

"error": "Failed to list tools from MCP server '...': 'RenamedToolset' object has no attribute 'list_tools'"

Root cause: When gateway_slugs are present, load_tools() returns a RenamedToolset (via mcp_server.renamed(name_map)). The formatters then called get_tool_list(RenamedToolset) which tried to invoke list_tools() - a method that doesn't
exist on RenamedToolset.

Solution

Made get_tool_list() self-contained:

  • Takes tool_config: MCPToolConfig instead of mcp_server instance
  • Creates its own MCP connection internally
  • Strips gateway slugs from tool names before returning
  • Returns list[Tool] with short names for the response

This ensures formatters get the correct tool list without depending on load_tools() output.

Make get_tool_list() self-contained so it creates its own MCP connection
and strips gateway slugs from tool names. This fixes the error where
formatters called load_tools() (returns RenamedToolset) then tried to
call list_tools() on it, which doesn't exist on RenamedToolset.

Changes:
- get_tool_list() now takes tool_config and creates own MCP connection
- load_tools() calls mcp_server.list_tools() directly for original names
- Formatters call get_tool_list(tool_config) directly
- Fixed server_label validation error by defaulting to "unknown"

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @vsraccubits, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request resolves a critical issue affecting tool listing for MCP tools, particularly when gateway slugs are in use. The core problem stemmed from an incompatibility with RenamedToolset objects, which lacked a necessary method for tool enumeration. The changes refactor the tool loading and listing mechanism to be more robust and independent, ensuring that response formatters can correctly retrieve and process tool information, thereby enhancing the stability and reliability of the system's interaction with external tools.

Highlights

  • RenamedToolset Error Resolution: Fixed an error where response formatters failed with 'RenamedToolset' object having no attribute 'list_tools' when MCP tools had gateway_slugs configured, by making get_tool_list() self-contained.
  • Self-Contained Tool List Fetching: The get_tool_list() method in tool_loaders.py was refactored to be self-contained. It now takes MCPToolConfig directly, establishes its own MCP connection, and handles stripping gateway slugs from tool names, ensuring formatters receive the correct tool list without relying on load_tools() output.
  • Server Label Validation Fix: Addressed a server_label validation error by providing a default value of 'unknown' when creating an Mcp object, ensuring robustness even if tool_config.server_label is not explicitly set.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • services/budprompt/budprompt/executors/v4/openai_response_formatter.py
    • Added a default value 'unknown' for server_label in the Mcp object creation to prevent validation errors.
    • Modified _fetch_mcp_tool_lists to directly call the refactored loader.get_tool_list with tool_config, removing the previous dependency on an intermediate mcp_server instance.
  • services/budprompt/budprompt/executors/v4/openai_streaming_formatter.py
    • Updated emit_mcp_tool_list_events to directly invoke the refactored loader.get_tool_list with tool_config, streamlining the process of fetching tool lists for streaming responses.
  • services/budprompt/budprompt/executors/v4/tool_loaders.py
    • In load_tools, adjusted the logic for retrieving original tool names when gateway_slugs are present, now directly calling mcp_server.list_tools() to ensure accurate name mapping before any renaming occurs.
    • Changed a logging level from info to debug for messages related to stripping gateway prefixes.
    • Significantly refactored get_tool_list to accept tool_config directly, create its own MCPServerStreamableHTTP connection, and implement logic for stripping gateway slugs from tool names, returning Tool objects with their short names. This makes the method self-contained and independent.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@vsraccubits vsraccubits requested a review from dittops February 5, 2026 17:20
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request effectively resolves the RenamedToolset error by refactoring get_tool_list and correctly addresses a validation error by providing a default value for server_label. However, it introduces a potential Server-Side Request Forgery (SSRF) and credential leakage vulnerability in the MCPToolLoader.get_tool_list method due to unvalidated input in URL construction and the inclusion of a sensitive API key. Additionally, there are opportunities to improve maintainability by addressing code duplication in services/budprompt/budprompt/executors/v4/tool_loaders.py through helper methods.

Comment on lines +169 to +174
mcp_url = f"{self.base_url}servers/{tool_config.server_url}/mcp"
headers = {}
if self.api_key:
headers["Authorization"] = f"Bearer {self.api_key}"

mcp_server = MCPServerStreamableHTTP(url=mcp_url, headers=headers if headers else None)
Copy link
Contributor

Choose a reason for hiding this comment

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

security-high high

This block constructs an MCP server URL using tool_config.server_url without validation, leading to a potential Server-Side Request Forgery (SSRF) and credential leakage vulnerability. An attacker could manipulate server_url for path traversal, redirecting requests with the sensitive Authorization header to arbitrary endpoints. Strict validation for tool_config.server_url is crucial to prevent this. Additionally, this code block is duplicated; consider extracting it into a private helper method to improve maintainability and adhere to the DRY principle.

Suggested change
mcp_url = f"{self.base_url}servers/{tool_config.server_url}/mcp"
headers = {}
if self.api_key:
headers["Authorization"] = f"Bearer {self.api_key}"
mcp_server = MCPServerStreamableHTTP(url=mcp_url, headers=headers if headers else None)
if not all(c.isalnum() or c in "-_" for c in tool_config.server_url):
logger.error(f"Invalid server_url: {tool_config.server_url}")
return {"server_label": server_label, "tools": [], "error": "invalid server_url"}
mcp_url = f"{self.base_url}servers/{tool_config.server_url}/mcp"
headers = {"Authorization": f"Bearer {self.api_key}"} if self.api_key else None
mcp_server = MCPServerStreamableHTTP(url=mcp_url, headers=headers)

Comment on lines +188 to +194
for tool in tools_list:
short_name = tool.name
for slug in gateway_slugs:
prefix = f"{slug}-"
if tool.name.startswith(prefix):
short_name = tool.name[len(prefix) :]
break
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The logic inside this for loop to find a tool's short name by stripping a gateway slug prefix is very similar to the logic within the loop in load_tools (lines 101-107). To avoid this code duplication and make the logic reusable, you could extract it into a helper method.

For example:

def _get_short_name(self, original_name: str, gateway_slugs: list[str]) -> str:
    """Strips the first matching gateway slug prefix from a tool name."""
    for slug in gateway_slugs:
        prefix = f"{slug}-"
        if original_name.startswith(prefix):
            return original_name[len(prefix):]
    return original_name

This helper could then be used here as short_name = self._get_short_name(tool.name, gateway_slugs) and would also simplify the implementation in load_tools.

@vsraccubits vsraccubits merged commit a838885 into master Feb 5, 2026
14 checks passed
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.

2 participants