Skip to content

Conversation

@peaaceChoi
Copy link

@peaaceChoi peaaceChoi commented Dec 5, 2025

Link to Issue or Description of Change

1. Link to an existing issue (if applicable):

Testing Plan

Unit Tests:
I have added test cases related to caching to /tests/unittests/tools/test_mcp_toolset.py.

  • test_mcp_toolset_cache_disabled

  • test_mcp_toolset_cache_enabled

  • test_mcp_toolset_cache_with_ttl_not_expired

  • test_mcp_toolset_cache_with_ttl_expired

  • test_mcp_toolset_cache_concurrency

  • I have added or updated unit tests for my change.

  • All unit tests pass locally.

Please include a summary of passed pytest results.

.venv/bin/pytest tests/unittests/tools/test_mcp_toolset.py
========================================================================================================================= test session starts ==========================================================================================================================
platform darwin -- Python 3.11.0, pytest-9.0.1, pluggy-1.6.0
rootdir: /Users/ceres/dev/adk-python
configfile: pyproject.toml           
plugins: mock-3.15.1, anyio-4.12.0, langsmith-0.4.54, xdist-3.8.0, asyncio-1.3.0
asyncio: mode=Mode.AUTO, debug=False, asyncio_default_fixture_loop_scope=function, asyncio_default_test_loop_scope=function
collected 6 items                                                                                                                                                                                                                                                      
                                                                  
tests/unittests/tools/test_mcp_toolset.py ......                                                                                                                                                                                                                 [100%]
                                                                  
=========================================================================================================================== warnings summary ===========================================================================================================================
.venv/lib/python3.11/site-packages/litellm/types/llms/anthropic.py:465                        
  /Users/ceres/dev/adk-python/.venv/lib/python3.11/site-packages/litellm/types/llms/anthropic.py:465: PydanticDeprecatedSince20: Support for class-based `config` is deprecated, use ConfigDict instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic
 V2 Migration Guide at https://errors.pydantic.dev/2.12/migration/ 
    class AnthropicResponseContentBlockToolUse(BaseModel):

tests/unittests/tools/test_mcp_toolset.py: 25 warnings
  /Users/ceres/dev/adk-python/src/google/adk/tools/mcp_tool/mcp_toolset.py:226: DeprecationWarning: MCPTool class is deprecated, use `McpTool` instead.
    mcp_tool = MCPTool(

tests/unittests/tools/test_mcp_toolset.py::test_mcp_toolset_with_prefix
tests/unittests/tools/test_mcp_toolset.py::test_mcp_toolset_cache_disabled
tests/unittests/tools/test_mcp_toolset.py::test_mcp_toolset_cache_enabled
tests/unittests/tools/test_mcp_toolset.py::test_mcp_toolset_cache_with_ttl_not_expired
tests/unittests/tools/test_mcp_toolset.py::test_mcp_toolset_cache_with_ttl_expired
tests/unittests/tools/test_mcp_toolset.py::test_mcp_toolset_cache_concurrency
  /Users/ceres/dev/adk-python/src/google/adk/tools/mcp_tool/mcp_tool.py:88: UserWarning: [EXPERIMENTAL] BaseAuthenticatedTool: This feature is experimental and may change or be removed in future versions without notice. It may introduce breaking changes at any tim
e.
    super().__init__(

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
==================================================================================================================== 6 passed, 32 warnings in 7.49s ====================================================================================================================

Checklist

  • I have read the CONTRIBUTING.md document.
  • I have performed a self-review of my own code.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have added tests that prove my fix is effective or that my feature works.
  • New and existing unit tests pass locally with my changes.
  • I have manually tested my changes end-to-end.
  • Any dependent changes have been merged and published in downstream modules.

@google-cla
Copy link

google-cla bot commented Dec 5, 2025

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @peaaceChoi, 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 introduces an in-memory caching mechanism with Time-To-Live (TTL) support to the McpToolset. This enhancement aims to significantly improve performance by reducing redundant calls to the MCP server for tool listings. Consumers of the McpToolset can now opt-in to caching and configure an expiration time for cached data, ensuring that frequently accessed tool information is retrieved more efficiently while remaining up-to-date.

Highlights

  • In-Memory Caching: Implemented in-memory caching for the McpToolset to store responses from list_tools calls, reducing redundant network requests.
  • Configurable Caching: Added cache (boolean) and cache_ttl_seconds (optional integer) parameters to the McpToolset constructor, allowing users to enable caching and define a Time-To-Live (TTL) for cached data.
  • TTL-Based Cache Invalidation: Introduced a mechanism to automatically invalidate cached data when its specified TTL expires, ensuring data freshness.
  • Comprehensive Unit Tests: Added new unit tests to thoroughly validate the caching functionality, covering scenarios where caching is disabled, enabled, and when the TTL has or has not expired.
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.

@adk-bot adk-bot added the mcp [Component] Issues about MCP support label Dec 5, 2025
@adk-bot
Copy link
Collaborator

adk-bot commented Dec 5, 2025

Response from ADK Triaging Agent

Hello @peaaceChoi, thank you for creating this PR!

It looks like you have not yet signed the Contributor License Agreement (CLA). Please visit https://cla.developers.google.com/ to sign the agreement. Once the CLA is signed, the cla/google check will pass and we can proceed with the review of your PR.

Thanks!

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 introduces an in-memory cache with TTL support for McpToolset, which is a great feature for improving performance and reducing server load. The implementation is mostly correct, and the accompanying tests cover the new functionality well.

My review includes a few suggestions:

  • A fix for a race condition in the cache implementation to prevent cache stampedes under concurrent access.
  • A suggestion to improve the structure of the cache validation logic for better readability and maintainability.
  • An improvement for the new tests to make them more robust and faster by mocking time instead of using asyncio.sleep().

Overall, this is a good addition. Addressing these points will make the caching mechanism more robust and the tests more reliable.

Comment on lines 171 to 182
def _is_cache_valid():
if not self._cache or not self._cached_tool_response:
return False

if self._cache_ttl_seconds is None:
return True # No TTL set, consider cache always valid

if self._cache_creation_time is None:
return False # This should not happen in a well-initialized system

elapsed = time.monotonic() - self._cache_creation_time
return elapsed <= self._cache_ttl_seconds
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 _is_cache_valid function is defined inside get_tools. While this works, moving it to a private method of the McpToolset class (e.g., _is_cache_valid(self)) would improve code organization and readability. It makes the get_tools method shorter and more focused on its main logic. It also makes the cache validation logic reusable and easier to test in isolation if needed in the future.

await toolset.get_tools()
mock_session.list_tools.assert_called_once()

await asyncio.sleep(1.1)
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

Using asyncio.sleep() to test time-dependent logic can make tests slow and potentially flaky. A more robust approach is to mock the time source, time.monotonic. This gives you precise control over time in your test, making it faster and more reliable.

You can use mocker.patch from pytest-mock to do this. Here's an example of how you could rewrite this test:

@pytest.mark.asyncio
async def test_mcp_toolset_cache_with_ttl_expired(mocker):
    """Test that list_tools is called again after TTL expires."""
    mock_connection_params = MagicMock()
    mock_connection_params.timeout = None
    mock_session_manager, mock_session = _create_mock_session_manager()

    toolset = McpToolset(
        connection_params=mock_connection_params, cache=True, cache_ttl_seconds=1
    )
    toolset._mcp_session_manager = mock_session_manager

    # Patch time.monotonic
    mock_time = mocker.patch('time.monotonic')

    # First call, populates cache
    mock_time.return_value = 1000.0
    await toolset.get_tools()
    mock_session.list_tools.assert_called_once()

    # Second call, after TTL expired
    mock_time.return_value = 1001.1  # More than 1 second later
    await toolset.get_tools()
    assert mock_session.list_tools.call_count == 2

@ryanaiagent ryanaiagent self-assigned this Dec 5, 2025
@ryanaiagent ryanaiagent added the request clarification [Status] The maintainer need clarification or more information from the author label Dec 5, 2025
@ryanaiagent
Copy link
Collaborator

Hi @peaaceChoi , Thank you for your contribution! It appears you haven't yet signed the Contributor License Agreement (CLA). Please visit https://cla.developers.google.com/ to complete the signing process. Once the CLA is signed, we'll be able to proceed with the review of your PR. Thank you!

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

Labels

mcp [Component] Issues about MCP support request clarification [Status] The maintainer need clarification or more information from the author

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants