Skip to content

Conversation

strawgate
Copy link
Collaborator

@strawgate strawgate commented Sep 17, 2025

Description

Add a response caching middleware + in memory cache implementation + on disk cache implementation

  • cache list calls
  • cache call/read tool/prompt/resource
  • custom ttl by method
  • cache bust lists on update notifications

Todo:

  • Add ES implementation
  • Add redis implementation
  • Support max item size
  • support resource templates

Contributors Checklist

  • My change closes Response Caching Middleware #1844
  • I have followed the repository's development workflow
  • I have tested my changes manually and by adding relevant tests
  • I have performed all required documentation updates

Review Checklist

  • I have self-reviewed my changes
  • My Pull Request is ready for review

@marvin-context-protocol marvin-context-protocol bot added enhancement Improvement to existing functionality. For issues and smaller PR improvements. server Related to FastMCP server implementation or server-side functionality. labels Sep 17, 2025
@strawgate strawgate force-pushed the responsecachingmiddleware branch from 6850047 to 09369b5 Compare September 17, 2025 03:47
@strawgate strawgate changed the title Add Response Caching Middleware [Draft] Add Response Caching Middleware Sep 17, 2025
@strawgate strawgate changed the title [Draft] Add Response Caching Middleware Add Response Caching Middleware Sep 18, 2025
@strawgate strawgate changed the title Add Response Caching Middleware [Draft] Add Response Caching Middleware Sep 18, 2025
@strawgate strawgate requested a review from Copilot September 18, 2025 00:45
@strawgate strawgate force-pushed the responsecachingmiddleware branch from 03da107 to d5f01da Compare September 18, 2025 00:46
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR implements a comprehensive response caching middleware system for FastMCP. It adds caching capabilities for various MCP operations including tool calls, resource reads, and prompt requests to improve performance and reduce server load.

  • Implements both in-memory and disk-based caching backends
  • Adds configurable TTL settings and filtering options for different operation types
  • Includes cache invalidation through MCP notifications and comprehensive test coverage

Reviewed Changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/server/middleware/test_caching.py Comprehensive test suite covering cache implementations, middleware functionality, and integration tests
src/fastmcp/server/middleware/middleware.py Updated middleware base class to use proper return type for resource reading operations
src/fastmcp/server/middleware/caching.py Core caching middleware implementation with cache protocols, backends, and operation handlers
pyproject.toml Added caching dependencies and test dependencies
docs/servers/middleware.mdx Documentation for the new caching middleware functionality

@strawgate
Copy link
Collaborator Author

strawgate commented Sep 18, 2025

TypedDicts are a lot less fun than I was expecting and I'm not sure the cache entry model is going to stick around

The implementation for the cache entries is mostly for the benefit of distributed cache implementations that can't just pickle

@strawgate strawgate self-assigned this Sep 18, 2025
@strawgate strawgate requested a review from Copilot September 18, 2025 18:48
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Copilot reviewed 8 out of 11 changed files in this pull request and generated 3 comments.

class TestResponseCachingMiddlewareIntegration:
"""Integration tests with real FastMCP server."""

@pytest.fixture(params=["memory", "disk", "elasticsearch"])
Copy link
Preview

Copilot AI Sep 18, 2025

Choose a reason for hiding this comment

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

The test fixture includes 'elasticsearch' as a parameter but the actual implementation in the fixture method only handles 'memory' and 'disk' cases, which will cause the tests to fail when 'elasticsearch' is selected.

Copilot uses AI. Check for mistakes.


def get_size_of_value(value: CachableValueTypes) -> int:
"""Get the size of a cache entry."""
if isinstance(value, BaseModel | ToolResult | ReadResourceContents):
Copy link
Preview

Copilot AI Sep 18, 2025

Choose a reason for hiding this comment

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

The isinstance check uses union syntax with | but this will not work correctly. The condition should use a tuple: isinstance(value, (BaseModel, ToolResult, ReadResourceContents))

Suggested change
if isinstance(value, BaseModel | ToolResult | ReadResourceContents):
if isinstance(value, (BaseModel, ToolResult, ReadResourceContents)):

Copilot uses AI. Check for mistakes.

body={
"query": {
"range": {
"expires_at": {"lt": datetime.now(tz=timezone.utc).timestamp()},
Copy link
Preview

Copilot AI Sep 18, 2025

Choose a reason for hiding this comment

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

The comparison uses timestamp() but the mapping defines expires_at as a date type, not a numeric timestamp. This should use an ISO format string instead: datetime.now(tz=timezone.utc).isoformat()

Suggested change
"expires_at": {"lt": datetime.now(tz=timezone.utc).timestamp()},
"expires_at": {"lt": datetime.now(tz=timezone.utc).isoformat()},

Copilot uses AI. Check for mistakes.

@jlowin
Copy link
Owner

jlowin commented Sep 19, 2025

Love this idea! The CachedPrompt (and similar) classes feel a little overwrought -- I'm not totally clear on what makes the call_next results inherently uncacheable already? Or perhaps I'm missing something you're designing around

@strawgate
Copy link
Collaborator Author

strawgate commented Sep 19, 2025

Love this idea! The CachedPrompt (and similar) classes feel a little overwrought -- I'm not totally clear on what makes the call_next results inherently uncacheable already? Or perhaps I'm missing something you're designing around

Prompt cannot be instantiated directly as its an ABC and so what comes through the middleware is a FunctionPrompt which can't be serialized/deserialized due to the function reference -- so the CachedPrompt offers a serializable/deserializable model

Would love other ideas if you have them

@jlowin
Copy link
Owner

jlowin commented Sep 21, 2025

Oh! what do you think about removing the ABC from all components and just raising NotImplementedError() instead? Less self-documenting, more compatible?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Improvement to existing functionality. For issues and smaller PR improvements. server Related to FastMCP server implementation or server-side functionality.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants