Skip to content

Commit c4c05e1

Browse files
committed
Add tests for mount_path and path normalization in FastMCP
Tests to verify proper handling of mount paths when creating SSE applications. Ensures path normalization works correctly for different path combinations.
1 parent 9325779 commit c4c05e1

File tree

1 file changed

+65
-2
lines changed

1 file changed

+65
-2
lines changed

tests/server/fastmcp/test_server.py

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import base64
22
from pathlib import Path
33
from typing import TYPE_CHECKING
4+
from unittest.mock import patch
45

56
import pytest
67
from pydantic import AnyUrl
8+
from starlette.routing import Mount, Route
79

810
from mcp.server.fastmcp import Context, FastMCP
911
from mcp.server.fastmcp.prompts.base import EmbeddedResource, Message, UserMessage
@@ -31,6 +33,69 @@ async def test_create_server(self):
3133
assert mcp.name == "FastMCP"
3234
assert mcp.instructions == "Server instructions"
3335

36+
@pytest.mark.anyio
37+
async def test_normalize_path(self):
38+
"""Test path normalization for mount paths."""
39+
mcp = FastMCP()
40+
41+
# Test root path
42+
assert mcp._normalize_path("/", "/messages/") == "/messages/"
43+
44+
# Test path with trailing slash
45+
assert mcp._normalize_path("/github/", "/messages/") == "/github/messages/"
46+
47+
# Test path without trailing slash
48+
assert mcp._normalize_path("/github", "/messages/") == "/github/messages/"
49+
50+
# Test endpoint without leading slash
51+
assert mcp._normalize_path("/github", "messages/") == "/github/messages/"
52+
53+
# Test both with trailing/leading slashes
54+
assert mcp._normalize_path("/api/", "/v1/") == "/api/v1/"
55+
56+
@pytest.mark.anyio
57+
async def test_sse_app_with_mount_path(self):
58+
"""Test SSE app creation with different mount paths."""
59+
# Test with default mount path
60+
mcp = FastMCP()
61+
with patch.object(
62+
mcp, "_normalize_path", return_value="/messages/"
63+
) as mock_normalize:
64+
mcp.sse_app()
65+
# Verify _normalize_path was called with correct args
66+
mock_normalize.assert_called_once_with("/", "/messages/")
67+
68+
# Test with custom mount path
69+
mcp = FastMCP()
70+
mcp.settings.mount_path = "/custom"
71+
with patch.object(
72+
mcp, "_normalize_path", return_value="/custom/messages/"
73+
) as mock_normalize:
74+
mcp.sse_app()
75+
# Verify _normalize_path was called with correct args
76+
mock_normalize.assert_called_once_with("/custom", "/messages/")
77+
78+
@pytest.mark.anyio
79+
async def test_starlette_routes_with_mount_path(self):
80+
"""Test that Starlette routes are correctly configured with mount path."""
81+
mcp = FastMCP()
82+
mcp.settings.mount_path = "/api"
83+
app = mcp.sse_app()
84+
85+
# Find routes by type
86+
sse_routes = [r for r in app.routes if isinstance(r, Route)]
87+
mount_routes = [r for r in app.routes if isinstance(r, Mount)]
88+
89+
# Verify routes exist
90+
assert len(sse_routes) == 1, "Should have one SSE route"
91+
assert len(mount_routes) == 1, "Should have one mount route"
92+
93+
# Verify path values
94+
assert sse_routes[0].path == "/sse", "SSE route path should be /sse"
95+
assert (
96+
mount_routes[0].path == "/messages"
97+
), "Mount route path should be /messages"
98+
3499
@pytest.mark.anyio
35100
async def test_non_ascii_description(self):
36101
"""Test that FastMCP handles non-ASCII characters in descriptions correctly"""
@@ -518,8 +583,6 @@ async def async_tool(x: int, ctx: Context) -> str:
518583

519584
@pytest.mark.anyio
520585
async def test_context_logging(self):
521-
from unittest.mock import patch
522-
523586
import mcp.server.session
524587

525588
"""Test that context logging methods work."""

0 commit comments

Comments
 (0)