From 00e72d24a620c3389c3a5aa21070a7e1d945ad44 Mon Sep 17 00:00:00 2001 From: Chris Coutinho Date: Fri, 14 Nov 2025 19:20:30 +0100 Subject: [PATCH] feat: Enable SSE transport for mcp service and update test fixtures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes: - Remove streamable-http transport override from mcp service in docker-compose.yml - Service now uses CLI default SSE transport on /sse endpoint - Add create_mcp_client_session_sse() helper for SSE connections - Update nc_mcp_client fixture to use SSE transport - Fix unpacking for SSE client (yields 2 values vs 3 for streamable-http) Testing: - All 4 smoke tests pass with SSE transport - 32/34 affected tests pass (2 skipped for vector sync) - OAuth services remain on streamable-http (unchanged) Note: SSE transport is being deprecated in favor of streamable-http. This enables minimal validation testing before deprecation. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- docker-compose.yml | 1 - tests/conftest.py | 54 +++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 38f72db..0bc1016 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -69,7 +69,6 @@ services: mcp: build: . - command: ["--transport", "streamable-http"] restart: always depends_on: app: diff --git a/tests/conftest.py b/tests/conftest.py index f7355be..98bb2e4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -9,6 +9,7 @@ import pytest from httpx import HTTPStatusError from mcp import ClientSession from mcp.client.session import RequestContext +from mcp.client.sse import sse_client from mcp.client.streamable_http import streamablehttp_client from mcp.types import ElicitRequestParams, ElicitResult, ErrorData @@ -165,6 +166,51 @@ async def create_mcp_client_session( logger.debug(f"{client_name} client session cleaned up successfully") +async def create_mcp_client_session_sse( + url: str, + token: str | None = None, + client_name: str = "MCP", + elicitation_callback: Any = None, +) -> AsyncGenerator[ClientSession, Any]: + """ + Factory function to create an MCP client session using SSE transport. + + Similar to create_mcp_client_session but uses SSE transport instead of streamable-http. + Uses native async context managers to ensure correct LIFO cleanup order. + + Args: + url: MCP server URL (e.g., "http://localhost:8000/sse") + token: Optional OAuth access token for Bearer authentication + client_name: Client name for logging (e.g., "Basic MCP (SSE)") + elicitation_callback: Optional callback for handling elicitation requests + + Yields: + Initialized MCP ClientSession + + Note: + SSE transport is being deprecated in favor of streamable-http. + This function exists for compatibility testing only. + """ + logger.info(f"Creating SSE client for {client_name}") + + # Prepare headers with OAuth token if provided + headers = {"Authorization": f"Bearer {token}"} if token else None + + # Use native async with - Python ensures LIFO cleanup + # Cleanup order will be: ClientSession.__aexit__ -> sse_client.__aexit__ + # Note: sse_client yields only (read_stream, write_stream), not 3 values like streamablehttp_client + async with sse_client(url, headers=headers) as (read_stream, write_stream): + async with ClientSession( + read_stream, write_stream, elicitation_callback=elicitation_callback + ) as session: + await session.initialize() + logger.info(f"{client_name} client session initialized successfully") + yield session + + # Cleanup happens automatically in LIFO order - no exception suppression needed + logger.debug(f"{client_name} client session cleaned up successfully") + + @pytest.fixture(scope="session") async def nc_client(anyio_backend) -> AsyncGenerator[NextcloudClient, Any]: """ @@ -203,12 +249,14 @@ async def nc_client(anyio_backend) -> AsyncGenerator[NextcloudClient, Any]: @pytest.fixture(scope="session") async def nc_mcp_client(anyio_backend) -> AsyncGenerator[ClientSession, Any]: """ - Fixture to create an MCP client session for integration tests using streamable-http. + Fixture to create an MCP client session for integration tests using SSE transport. Uses anyio pytest plugin for proper async fixture handling. + + Note: SSE transport is being deprecated. This fixture uses SSE for compatibility testing. """ - async for session in create_mcp_client_session( - url="http://localhost:8000/mcp", client_name="Basic MCP" + async for session in create_mcp_client_session_sse( + url="http://localhost:8000/sse", client_name="Basic MCP (SSE)" ): yield session