MCP Chat Analysis Server
- tests
import pytest
import json
from unittest.mock import Mock, AsyncMock
from pathlib import Path
from modelcontextprotocol.types import CallToolRequest, CallToolParams
from mcp_chat_analysis.server import ChatAnalysisServer
from mcp_chat_analysis.models import (
ConversationFormat,
ConversationData,
SearchQuery,
MetricsRequest,
ConceptRequest,
MetricType
)
@pytest.fixture
def mock_qdrant():
return Mock()
@pytest.fixture
def mock_neo4j():
return Mock()
@pytest.fixture
def mock_embedding_generator():
generator = Mock()
generator.generate_single = AsyncMock()
generator.generate = AsyncMock()
return generator
@pytest.fixture
async def server(mock_qdrant, mock_neo4j, mock_embedding_generator):
server = ChatAnalysisServer()
server.qdrant = mock_qdrant
server.neo4j = mock_neo4j
server.embedding_generator = mock_embedding_generator
return server
@pytest.mark.asyncio
async def test_list_tools(server):
"""Test that the server correctly lists available tools"""
result = await server._handle_list_tools(None)
assert "tools" in result
tools = result["tools"]
assert len(tools) == 4
tool_names = {tool["name"] for tool in tools}
expected_names = {
"import_conversations",
"semantic_search",
"analyze_metrics",
"extract_concepts"
}
assert tool_names == expected_names
@pytest.mark.asyncio
async def test_import_conversations(server):
"""Test conversation import tool"""
request = CallToolRequest(
params=CallToolParams(
name="import_conversations",
arguments={
"source_path": "/path/to/export.zip",
"format": "openai_native"
}
)
)
# Mock processor response
server.processor.process_conversations = AsyncMock(return_value={
"conversations_processed": 1,
"messages_processed": 10,
"vectors_created": 10,
"concepts_extracted": 5
})
result = await server._handle_call_tool(request)
assert result["content"][0]["type"] == "text"
assert "Imported conversations" in result["content"][0]["text"]
assert server.processor.process_conversations.called
@pytest.mark.asyncio
async def test_semantic_search(server):
"""Test semantic search tool"""
request = CallToolRequest(
params=CallToolParams(
name="semantic_search",
arguments={
"query": "test query",
"limit": 5
}
)
)
# Mock search results
server.processor.search = AsyncMock(return_value=[
{
"text": "Result 1",
"score": 0.9
}
])
result = await server._handle_call_tool(request)
assert result["content"][0]["type"] == "text"
assert "Search results" in result["content"][0]["text"]
assert server.processor.search.called
@pytest.mark.asyncio
async def test_analyze_metrics(server):
"""Test metrics analysis tool"""
request = CallToolRequest(
params=CallToolParams(
name="analyze_metrics",
arguments={
"conversation_id": "test-id",
"metrics": ["message_frequency", "response_times"]
}
)
)
# Mock metrics results
server.processor.analyze_metrics = AsyncMock(return_value={
"message_frequency": {"avg": 5},
"response_times": {"avg": 60}
})
result = await server._handle_call_tool(request)
assert result["content"][0]["type"] == "text"
assert "Metrics analysis" in result["content"][0]["text"]
assert server.processor.analyze_metrics.called
@pytest.mark.asyncio
async def test_extract_concepts(server):
"""Test concept extraction tool"""
request = CallToolRequest(
params=CallToolParams(
name="extract_concepts",
arguments={
"conversation_id": "test-id",
"min_relevance": 0.5
}
)
)
# Mock concept extraction results
server.processor.extract_concepts = AsyncMock(return_value=[
{
"name": "AI",
"relevance": 0.9,
"frequency": 5
}
])
result = await server._handle_call_tool(request)
assert result["content"][0]["type"] == "text"
assert "Extracted concepts" in result["content"][0]["text"]
assert server.processor.extract_concepts.called
@pytest.mark.asyncio
async def test_invalid_tool(server):
"""Test handling of invalid tool requests"""
request = CallToolRequest(
params=CallToolParams(
name="invalid_tool",
arguments={}
)
)
with pytest.raises(Exception) as exc:
await server._handle_call_tool(request)
assert "Unknown tool" in str(exc.value)
@pytest.mark.asyncio
async def test_invalid_arguments(server):
"""Test handling of invalid tool arguments"""
request = CallToolRequest(
params=CallToolParams(
name="semantic_search",
arguments={
"invalid": "argument"
}
)
)
with pytest.raises(Exception):
await server._handle_call_tool(request)