"""End-to-end tests for the /mcp HTTP endpoint mounted on the Quart app. These exercise the ASGI dispatch + auth middleware. The api_keys lookup is mocked so the tests don't require a database, matching the pattern in test_api_keys.py. """ from unittest.mock import AsyncMock, MagicMock, patch import pytest from fabledassistant.app import create_app @pytest.mark.asyncio async def test_mcp_endpoint_unauthenticated_returns_401(): app = create_app() async with app.test_client() as client: resp = await client.post( "/mcp", json={"jsonrpc": "2.0", "id": 1, "method": "ping"}, ) assert resp.status_code == 401 @pytest.mark.asyncio async def test_mcp_endpoint_invalid_token_returns_401(): app = create_app() with patch( "fabledassistant.mcp.auth.lookup_key", AsyncMock(return_value=None), ): async with app.test_client() as client: resp = await client.post( "/mcp", json={"jsonrpc": "2.0", "id": 1, "method": "ping"}, headers={"Authorization": "Bearer fmcp_invalid"}, ) assert resp.status_code == 401 @pytest.mark.asyncio async def test_mcp_endpoint_valid_token_passes_auth(): """With a valid Bearer, the request reaches FastMCP. FastMCP may return 200 (initialize handshake), 400, or a streaming response — anything other than 401 confirms auth passed and the request was handed off. """ fake_key = MagicMock() fake_key.user_id = 7 fake_key.scope = "write" app = create_app() with patch( "fabledassistant.mcp.auth.lookup_key", AsyncMock(return_value=fake_key), ): async with app.test_client() as client: resp = await client.post( "/mcp", json={ "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": {"name": "test", "version": "0"}, }, }, headers={ "Authorization": "Bearer fmcp_valid", "Accept": "application/json, text/event-stream", }, ) assert resp.status_code != 401 @pytest.mark.asyncio async def test_non_mcp_paths_bypass_mcp_dispatch(): """A non-/mcp path must not be routed to the FastMCP sub-app. Hitting an unknown /api/* route should return 404 from Quart, not 401 from the MCP middleware.""" app = create_app() async with app.test_client() as client: resp = await client.get("/api/this-route-does-not-exist") assert resp.status_code != 401