test_mcp_sdk.py•7.74 kB
"""
SDK Exploration Tests
Verify basic MCP SDK usage patterns before full migration.
Tests verify:
- SDK installation and import
- Basic server creation
- Tool definition and registration
- Request/response handling patterns
"""
import pytest
import asyncio
from typing import Any
class TestMCPSDKBasics:
"""Test basic MCP SDK functionality"""
def test_mcp_import(self):
"""Verify MCP SDK can be imported"""
try:
import mcp
assert mcp is not None
except ImportError as e:
pytest.skip(f"MCP SDK not installed: {e}")
def test_server_creation(self):
"""Verify Server instance can be created"""
try:
from mcp.server import Server
server = Server("test-server")
assert server is not None
assert server.name == "test-server"
except ImportError as e:
pytest.skip(f"MCP SDK not installed: {e}")
@pytest.mark.asyncio
async def test_list_tools_decorator(self):
"""Verify @server.list_tools() decorator works"""
try:
from mcp.server import Server
from mcp.types import Tool, TextContent
server = Server("test-server")
@server.list_tools()
async def list_tools():
return [
Tool(
name="test_tool",
description="A test tool",
inputSchema={"type": "object", "properties": {}},
)
]
assert server is not None
except ImportError as e:
pytest.skip(f"MCP SDK not installed: {e}")
@pytest.mark.asyncio
async def test_call_tool_decorator(self):
"""Verify @server.call_tool() decorator works"""
try:
from mcp.server import Server
from mcp.types import TextContent
server = Server("test-server")
@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[Any]:
if name == "test_tool":
return [TextContent(type="text", text="test result")]
return []
assert server is not None
except ImportError as e:
pytest.skip(f"MCP SDK not installed: {e}")
def test_stdlib_bdb_still_works(self):
"""Verify Python stdlib debugger (bdb) is not affected by SDK"""
import bdb
import sys
debugger = bdb.Bdb()
assert debugger is not None
# Verify basic functionality
assert hasattr(debugger, "set_trace")
assert hasattr(debugger, "set_break")
class TestSDKMessageTypes:
"""Test MCP SDK message type definitions"""
def test_import_types(self):
"""Verify MCP types can be imported"""
try:
from mcp.types import Tool, TextContent, ToolResult
assert Tool is not None
assert TextContent is not None
assert ToolResult is not None
except ImportError as e:
pytest.skip(f"MCP SDK not installed: {e}")
def test_tool_schema_validation(self):
"""Verify Tool object validates schema"""
try:
from mcp.types import Tool
tool = Tool(
name="example_tool",
description="Example tool for testing",
inputSchema={
"type": "object",
"properties": {
"param1": {"type": "string"},
"param2": {"type": "number"},
},
"required": ["param1"],
},
)
assert tool.name == "example_tool"
assert tool.inputSchema["properties"]["param1"]["type"] == "string"
except ImportError as e:
pytest.skip(f"MCP SDK not installed: {e}")
def test_text_content_response(self):
"""Verify TextContent response object"""
try:
from mcp.types import TextContent
content = TextContent(type="text", text="test response")
assert content.type == "text"
assert content.text == "test response"
except ImportError as e:
pytest.skip(f"MCP SDK not installed: {e}")
class TestAsyncPatterns:
"""Test async patterns for SDK migration"""
@pytest.mark.asyncio
async def test_async_function_execution(self):
"""Verify async functions work correctly"""
async def sample_async_func(value: str) -> str:
await asyncio.sleep(0.01)
return f"processed: {value}"
result = await sample_async_func("test")
assert result == "processed: test"
@pytest.mark.asyncio
async def test_asyncio_to_thread_wrapper(self):
"""Verify asyncio.to_thread() for wrapping sync code"""
def sync_function(x: int) -> int:
return x * 2
result = await asyncio.to_thread(sync_function, 5)
assert result == 10
@pytest.mark.asyncio
async def test_error_handling_in_async(self):
"""Verify error handling in async context"""
async def failing_async():
raise ValueError("test error")
with pytest.raises(ValueError, match="test error"):
await failing_async()
class TestSDKPatternComparison:
"""Compare old vs new implementation patterns"""
def test_old_pattern_compatibility(self):
"""Verify old JSON-RPC pattern still valid for reference"""
import json
# Simulate old request/response cycle
request = {
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {},
}
response = {
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "test",
"description": "test tool",
"inputSchema": {},
}
]
},
}
# Verify serialization still works
json_str = json.dumps(request)
parsed = json.loads(json_str)
assert parsed["method"] == "tools/list"
json_str = json.dumps(response)
parsed = json.loads(json_str)
assert len(parsed["result"]["tools"]) == 1
@pytest.mark.asyncio
async def test_new_pattern_example(self):
"""Verify new SDK pattern structure"""
try:
from mcp.server import Server
from mcp.types import Tool, TextContent
server = Server("migration-test")
tools_registered = []
@server.list_tools()
async def list_tools():
return [
Tool(
name="example",
description="Example tool",
inputSchema={"type": "object", "properties": {}},
)
]
@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list:
tools_registered.append(name)
return [TextContent(type="text", text="success")]
# Both handlers registered
assert server is not None
except ImportError as e:
pytest.skip(f"MCP SDK not installed: {e}")
if __name__ == "__main__":
pytest.main([__file__, "-v"])