2929from mcp .server .sse import SseServerTransport
3030from mcp .types import TextContent , Tool
3131
32- try :
33- from fakeredis import aioredis as fake_redis # noqa: F401
34- except ImportError :
35- pytest .skip (
36- "fakeredis is required for testing Redis functionality" , allow_module_level = True
37- )
38-
3932SERVER_NAME = "test_server_for_redis_integration_v3"
4033
4134
@@ -117,7 +110,6 @@ async def lifespan(app: Starlette) -> AsyncGenerator[None, None]:
117110 lifespan = lifespan ,
118111 )
119112
120- # Return the app, message_dispatch, and mock_redis for testing
121113 return app , message_dispatch , message_dispatch ._redis
122114
123115
@@ -152,7 +144,6 @@ async def server_and_redis(redis_server_and_app, server_port: int):
152144 f"Server failed to start after { max_attempts } attempts"
153145 )
154146
155- # Yield Redis for tests
156147 try :
157148 yield mock_redis , message_dispatch
158149 finally :
@@ -170,7 +161,6 @@ async def client_session(server_and_redis, server_url: str):
170161 """Create a client session for testing."""
171162 async with sse_client (server_url + "/sse" ) as streams :
172163 async with ClientSession (* streams ) as session :
173- # Initialize the session
174164 result = await session .initialize ()
175165 assert result .serverInfo .name == SERVER_NAME
176166 yield session
@@ -181,17 +171,12 @@ async def test_redis_integration_key_verification(
181171 server_and_redis , client_session
182172) -> None :
183173 """Test that Redis keys are created correctly for sessions."""
184- mock_redis , message_dispatch = server_and_redis
185- # client_session argument is used by this test (fixture yields session)
174+ mock_redis , _ = server_and_redis
186175
187- # Check that session keys exist in Redis
188- # The keys should follow pattern: mcp:pubsub:session_active:<session_id>
189176 all_keys = await mock_redis .keys ("*" ) # type: ignore
190177
191- # Should have session active key and potentially channel subscription
192178 assert len (all_keys ) > 0
193179
194- # Find session active key
195180 session_key = None
196181 for key in all_keys :
197182 if key .startswith ("mcp:pubsub:session_active:" ):
@@ -200,80 +185,40 @@ async def test_redis_integration_key_verification(
200185
201186 assert session_key is not None , f"No session key found. Keys: { all_keys } "
202187
203- # Verify session key has a TTL
204188 ttl = await mock_redis .ttl (session_key ) # type: ignore
205189 assert ttl > 0 , f"Session key should have TTL, got: { ttl } "
206190
207191
208- # Note: This test doesn't check cleanup since the session is managed by fixture
209-
210-
211- @pytest .mark .anyio
212- async def test_redis_integration_pubsub_channels (
213- server_and_redis , client_session
214- ) -> None :
215- """Test that Redis pubsub channels are used correctly."""
216- mock_redis , message_dispatch = server_and_redis
217-
218- # Make a tool call to ensure the pubsub channel is active
219- tool_result = await client_session .call_tool ("test_tool" , {})
220- assert tool_result .content [0 ].text == "Called test_tool" # type: ignore
221-
222- # Check pubsub channels (fakeredis might not expose all pubsub info)
223- # But we can verify keys related to pubsub
224- all_keys = await mock_redis .keys ("*" ) # type: ignore
225-
226- # Should have session keys
227- assert any (key .startswith ("mcp:pubsub:session_active:" ) for key in all_keys )
228-
229-
230192@pytest .mark .anyio
231- async def test_redis_integration_message_publishing (
232- server_and_redis , client_session
233- ) -> None :
193+ async def test_tool_calls (server_and_redis , client_session ) -> None :
234194 """Test that messages are properly published through Redis."""
235- mock_redis , message_dispatch = server_and_redis
195+ mock_redis , _ = server_and_redis
236196
237- # Make multiple tool calls to test message publishing
238197 for i in range (3 ):
239198 tool_result = await client_session .call_tool (
240199 "echo_message" , {"message" : f"Test { i } " }
241200 )
242201 assert tool_result .content [0 ].text == f"Echo: Test { i } " # type: ignore
243202
244- # If we can successfully make these calls, it means the Redis
245- # pubsub message publishing is working correctly
246-
247203
248204@pytest .mark .anyio
249- async def test_redis_integration_session_cleanup_detailed (
250- server_and_redis , server_url : str
251- ) -> None :
205+ async def test_session_cleanup (server_and_redis , server_url : str ) -> None :
252206 """Test Redis key cleanup when sessions end."""
253- mock_redis , message_dispatch = server_and_redis
254-
255- # Create and terminate multiple sessions to verify cleanup
207+ mock_redis , _ = server_and_redis
256208 session_keys_seen = set ()
257209
258210 for i in range (3 ):
259211 async with sse_client (server_url + "/sse" ) as streams :
260212 async with ClientSession (* streams ) as session :
261- # Initialize session
262- result = await session .initialize ()
263- assert result .serverInfo .name == SERVER_NAME
213+ await session .initialize ()
264214
265- # Check Redis keys
266215 all_keys = await mock_redis .keys ("*" ) # type: ignore
267-
268- # Find session active key
269216 for key in all_keys :
270217 if key .startswith ("mcp:pubsub:session_active:" ):
271218 session_keys_seen .add (key )
272- # Verify session has value "1"
273219 value = await mock_redis .get (key ) # type: ignore
274220 assert value == "1"
275221
276- # After each session ends, verify cleanup
277222 await anyio .sleep (0.1 ) # Give time for cleanup
278223 all_keys = await mock_redis .keys ("*" ) # type: ignore
279224 assert (
@@ -284,43 +229,16 @@ async def test_redis_integration_session_cleanup_detailed(
284229 assert len (session_keys_seen ) == 3 , "Should have seen 3 unique session keys"
285230
286231
287- # Include the other tests from the previous version
288- @pytest .mark .anyio
289- async def test_redis_integration_basic_tool_call (
290- server_and_redis , client_session
291- ) -> None :
292- """Test that a basic tool call works with Redis message dispatch."""
293- mock_redis , message_dispatch = server_and_redis
294-
295- # Call a tool
296- result = await client_session .call_tool ("test_tool" , {})
297- assert result .content [0 ].text == "Called test_tool" # type: ignore
298-
299-
300232@pytest .mark .anyio
301- async def test_redis_integration_multiple_clients_with_keys (
302- server_and_redis , server_url : str
303- ) -> None :
233+ async def concurrent_tool_call (server_and_redis , server_url : str ) -> None :
304234 """Test multiple clients and verify Redis key management."""
305- mock_redis , message_dispatch = server_and_redis
306-
307- # Track session keys for multiple concurrent clients
308- session_keys = []
235+ mock_redis , _ = server_and_redis
309236
310237 async def client_task (client_id : int ) -> str :
311238 async with sse_client (server_url + "/sse" ) as streams :
312239 async with ClientSession (* streams ) as session :
313240 await session .initialize ()
314241
315- # Check session keys
316- all_keys = await mock_redis .keys ("*" ) # type: ignore
317- for key in all_keys :
318- if (
319- key .startswith ("mcp:pubsub:session_active:" )
320- and key not in session_keys
321- ):
322- session_keys .append (key )
323-
324242 result = await session .call_tool (
325243 "echo_message" ,
326244 {"message" : f"Message from client { client_id } " },
@@ -336,11 +254,6 @@ async def client_task(client_id: int) -> str:
336254 for i , result in enumerate (results ):
337255 assert result == f"Echo: Message from client { i } "
338256
339- # At peak we should have seen multiple session keys
340- assert (
341- len (session_keys ) >= 2
342- ), f"Should have seen multiple session keys, got: { session_keys } "
343-
344257 # After all clients disconnect, keys should be cleaned up
345258 await anyio .sleep (0.1 ) # Give time for cleanup
346259 all_keys = await mock_redis .keys ("*" ) # type: ignore
0 commit comments