fix: use pure ASGI app for SSE transport compatibility
- Replace Starlette routing with direct ASGI dispatcher to avoid double-response issues with SSE transport - Simplify integration test fixtures by removing async client fixture - Consolidate integration tests into single test functions per file to prevent SSE connection cleanup issues between tests - Fix add_records assertion to expect 'inserted_ids' (actual API response)
This commit is contained in:
@@ -1,57 +1,61 @@
|
||||
"""Test MCP protocol compliance over SSE transport."""
|
||||
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
import pytest
|
||||
from mcp import ClientSession
|
||||
from mcp.client.sse import sse_client
|
||||
|
||||
|
||||
GRIST_MCP_URL = "http://localhost:3000"
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def create_mcp_session():
|
||||
"""Create and yield an MCP session."""
|
||||
async with sse_client(f"{GRIST_MCP_URL}/sse") as (read_stream, write_stream):
|
||||
async with ClientSession(read_stream, write_stream) as session:
|
||||
await session.initialize()
|
||||
yield session
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mcp_connection_initializes(mcp_client):
|
||||
"""Test that MCP client can connect and initialize."""
|
||||
# If we get here, connection and initialization succeeded
|
||||
assert mcp_client is not None
|
||||
async def test_mcp_protocol_compliance(services_ready):
|
||||
"""Test MCP protocol compliance - connection, tools, descriptions, schemas."""
|
||||
async with create_mcp_session() as client:
|
||||
# Test 1: Connection initializes
|
||||
assert client is not None
|
||||
|
||||
# Test 2: list_tools returns all expected tools
|
||||
result = await client.list_tools()
|
||||
tool_names = [tool.name for tool in result.tools]
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_list_tools_returns_all_tools(mcp_client):
|
||||
"""Test that list_tools returns all expected tools."""
|
||||
result = await mcp_client.list_tools()
|
||||
tool_names = [tool.name for tool in result.tools]
|
||||
expected_tools = [
|
||||
"list_documents",
|
||||
"list_tables",
|
||||
"describe_table",
|
||||
"get_records",
|
||||
"sql_query",
|
||||
"add_records",
|
||||
"update_records",
|
||||
"delete_records",
|
||||
"create_table",
|
||||
"add_column",
|
||||
"modify_column",
|
||||
"delete_column",
|
||||
]
|
||||
|
||||
expected_tools = [
|
||||
"list_documents",
|
||||
"list_tables",
|
||||
"describe_table",
|
||||
"get_records",
|
||||
"sql_query",
|
||||
"add_records",
|
||||
"update_records",
|
||||
"delete_records",
|
||||
"create_table",
|
||||
"add_column",
|
||||
"modify_column",
|
||||
"delete_column",
|
||||
]
|
||||
for expected in expected_tools:
|
||||
assert expected in tool_names, f"Missing tool: {expected}"
|
||||
|
||||
for expected in expected_tools:
|
||||
assert expected in tool_names, f"Missing tool: {expected}"
|
||||
assert len(result.tools) == 12, f"Expected 12 tools, got {len(result.tools)}"
|
||||
|
||||
assert len(result.tools) == 12
|
||||
# Test 3: All tools have descriptions
|
||||
for tool in result.tools:
|
||||
assert tool.description, f"Tool {tool.name} has no description"
|
||||
assert len(tool.description) > 10, f"Tool {tool.name} description too short"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_list_tools_has_descriptions(mcp_client):
|
||||
"""Test that all tools have descriptions."""
|
||||
result = await mcp_client.list_tools()
|
||||
|
||||
for tool in result.tools:
|
||||
assert tool.description, f"Tool {tool.name} has no description"
|
||||
assert len(tool.description) > 10, f"Tool {tool.name} description too short"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_list_tools_has_input_schemas(mcp_client):
|
||||
"""Test that all tools have input schemas."""
|
||||
result = await mcp_client.list_tools()
|
||||
|
||||
for tool in result.tools:
|
||||
assert tool.inputSchema is not None, f"Tool {tool.name} has no inputSchema"
|
||||
assert "type" in tool.inputSchema, f"Tool {tool.name} schema missing type"
|
||||
# Test 4: All tools have input schemas
|
||||
for tool in result.tools:
|
||||
assert tool.inputSchema is not None, f"Tool {tool.name} has no inputSchema"
|
||||
assert "type" in tool.inputSchema, f"Tool {tool.name} schema missing type"
|
||||
|
||||
Reference in New Issue
Block a user