Skip to content

Add mount_path support for proper SSE endpoint routing with multiple FastMCP servers #540

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

tim-watcha
Copy link

Add mount_path capability to FastMCP for proper SSE endpoint handling when mounted under sub-paths

Motivation and Context

When multiple FastMCP servers are mounted under different sub-paths in a single Starlette application, the session URIs were being generated incorrectly. FastMCP would create session URIs that didn't include the mount path, causing clients to send messages to the wrong endpoint. This change fixes the issue by
adding a mount_path setting that properly normalizes URIs.

How Has This Been Tested?

  • Added unit tests for the path normalization function
  • Added unit tests for SSE app creation with different mount paths
  • Tested with a real application mounting multiple FastMCP servers under different paths
  • Manually verified session URI generation and message routing

Breaking Changes

None. This is backwards compatible with existing code. The new mount_path setting defaults to "/".

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

The issue occurs because the SseServerTransport class creates a session URI without considering that the server might be mounted under a sub-path. The fix adds a mount_path setting to FastMCP and implements a path normalization helper method that combines the mount path with the message path to ensure correct
URI generation.

This solution maintains clean separation between FastMCP and SseServerTransport without requiring changes to the SseServerTransport class itself.

This commit adds a mount_path attribute to FastMCP settings to support
properly constructing SSE endpoints when servers are mounted under
sub-paths. The _normalize_path helper method combines mount paths with
endpoints to ensure correct session_uri generation.

This fixes issues when running multiple FastMCP servers under different
path prefixes in a single Starlette application.
Tests to verify proper handling of mount paths when creating SSE applications.
Ensures path normalization works correctly for different path combinations.
This commit adds documentation for mounting multiple FastMCP servers
under different paths, showing how to configure mount_path for each
server instance.
tim-watcha and others added 2 commits April 19, 2025 13:01
Format code to comply with line length limit (88 characters).
@richardhundt
Copy link

I wish Starlette allowed some reflection on where a route was mounted. This kind of handshake could benefit from that, and I'm guessing the Starlette folks never thought it would be needed. That mount point duplication in settings just seems superfluous, but looking at the Starlette internals, I couldn't see a way of getting at those values either. Perhaps asking them nicely to add this capability would work.

@tim-watcha
Copy link
Author

tim-watcha commented Apr 20, 2025

I wish Starlette allowed some reflection on where a route was mounted. This kind of handshake could benefit from that, and I'm guessing the Starlette folks never thought it would be needed. That mount point duplication in settings just seems superfluous, but looking at the Starlette internals, I couldn't see a way of getting at those values either. Perhaps asking them nicely to add this capability would work.
Here's the comment content in English:

@richardhundt I agree that Starlette's lack of reflection on mount points is a bit unfortunate. While we wait for that capability, I was thinking of adding a syntactic sugar method that could help avoid the duplication:

def get_mount(self, mount_path: Optional[str] = None) -> Mount:
    """
    Configure mount_path and return a Mount object for Starlette routing.
    
    Args:
        mount_path: Optional override for the mount_path setting
    
    Returns:
        Starlette Mount object configured for this FastMCP server
    """
    # Set mount_path setting
    if mount_path:
        self.settings.mount_path = mount_path
    
    # Return configured Mount object
    return Mount(self.settings.mount_path, app=self.sse_app())

This would allow for more concise code:

# Current approach
github_mcp.settings.mount_path = "/github"
routes = [Mount("/github", app=github_mcp.sse_app())]

# Proposed approach
routes = [github_mcp.get_mount("/github")]

What do you think? This could help prevent mount path mismatches and simplify the API.

@richardhundt
Copy link

richardhundt commented Apr 20, 2025

Looks like this will all be moot soon. The updated specification reduces all communication to just a single endpoint supporting both SSE and transactional (request/response) style HTTP interactions (controlled by the Accept header). It complicates the clients a bit because they need to distinguish SSE streaming from transactional responses, but that's manageable and solves all of these routing issues.

https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http

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