mirror of
https://github.com/basicmachines-co/basic-memory
synced 2026-06-21 13:47:35 +00:00
35884ef3a7
FastMCP library changes now require calling decorated functions via the .fn attribute: - Tools: @mcp.tool() functions return FunctionTool, call with tool.fn() - Prompts: @mcp.prompt() functions return FunctionPrompt, call with prompt.fn() - Resources: @mcp.resource() functions return FunctionResource, call with resource.fn() Updated core files: - view_note.py: read_note() → read_note.fn() - read_note.py: search_notes() → search_notes.fn() (2 locations) - tool.py: 6 MCP tool calls updated to use .fn - recent_activity.py: recent_activity() → recent_activity.fn() - project.py: project_info() → project_info.fn() with type ignore Updated 100+ test files systematically to use .fn attribute and fixed mock targets. All 869 tests now pass. Fixes view_note tool error in Claude Desktop. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
119 lines
3.9 KiB
Python
119 lines
3.9 KiB
Python
"""Tests for discussion context MCP tool."""
|
|
|
|
import pytest
|
|
|
|
from mcp.server.fastmcp.exceptions import ToolError
|
|
|
|
from basic_memory.mcp.tools import recent_activity
|
|
from basic_memory.schemas.memory import (
|
|
EntitySummary,
|
|
ObservationSummary,
|
|
RelationSummary,
|
|
)
|
|
from basic_memory.schemas.search import SearchItemType
|
|
|
|
# Test data for different timeframe formats
|
|
valid_timeframes = [
|
|
"7d", # Standard format
|
|
"yesterday", # Natural language
|
|
"0d", # Zero duration
|
|
]
|
|
|
|
invalid_timeframes = [
|
|
"invalid", # Nonsense string
|
|
"tomorrow", # Future date
|
|
]
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_recent_activity_timeframe_formats(client, test_graph):
|
|
"""Test that recent_activity accepts various timeframe formats."""
|
|
# Test each valid timeframe
|
|
for timeframe in valid_timeframes:
|
|
try:
|
|
result = await recent_activity.fn(
|
|
type=["entity"], timeframe=timeframe, page=1, page_size=10, max_related=10
|
|
)
|
|
assert result is not None
|
|
except Exception as e:
|
|
pytest.fail(f"Failed with valid timeframe '{timeframe}': {str(e)}")
|
|
|
|
# Test invalid timeframes should raise ValidationError
|
|
for timeframe in invalid_timeframes:
|
|
with pytest.raises(ToolError):
|
|
await recent_activity.fn(timeframe=timeframe)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_recent_activity_type_filters(client, test_graph):
|
|
"""Test that recent_activity correctly filters by types."""
|
|
|
|
# Test single string type
|
|
result = await recent_activity.fn(type=SearchItemType.ENTITY)
|
|
assert result is not None
|
|
assert len(result.results) > 0
|
|
assert all(isinstance(item.primary_result, EntitySummary) for item in result.results)
|
|
|
|
# Test single string type
|
|
result = await recent_activity.fn(type="entity")
|
|
assert result is not None
|
|
assert len(result.results) > 0
|
|
assert all(isinstance(item.primary_result, EntitySummary) for item in result.results)
|
|
|
|
# Test single type
|
|
result = await recent_activity.fn(type=["entity"])
|
|
assert result is not None
|
|
assert len(result.results) > 0
|
|
assert all(isinstance(item.primary_result, EntitySummary) for item in result.results)
|
|
|
|
# Test multiple types
|
|
result = await recent_activity.fn(type=["entity", "observation"])
|
|
assert result is not None
|
|
assert len(result.results) > 0
|
|
assert all(
|
|
isinstance(item.primary_result, EntitySummary)
|
|
or isinstance(item.primary_result, ObservationSummary)
|
|
for item in result.results
|
|
)
|
|
|
|
# Test multiple types
|
|
result = await recent_activity.fn(type=[SearchItemType.ENTITY, SearchItemType.OBSERVATION])
|
|
assert result is not None
|
|
assert len(result.results) > 0
|
|
assert all(
|
|
isinstance(item.primary_result, EntitySummary)
|
|
or isinstance(item.primary_result, ObservationSummary)
|
|
for item in result.results
|
|
)
|
|
|
|
# Test all types
|
|
result = await recent_activity.fn(type=["entity", "observation", "relation"])
|
|
assert result is not None
|
|
assert len(result.results) > 0
|
|
# Results can be any type
|
|
assert all(
|
|
isinstance(item.primary_result, EntitySummary)
|
|
or isinstance(item.primary_result, ObservationSummary)
|
|
or isinstance(item.primary_result, RelationSummary)
|
|
for item in result.results
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_recent_activity_type_invalid(client, test_graph):
|
|
"""Test that recent_activity correctly filters by types."""
|
|
|
|
# Test single invalid string type
|
|
with pytest.raises(ValueError) as e:
|
|
await recent_activity.fn(type="note")
|
|
assert (
|
|
str(e.value) == "Invalid type: note. Valid types are: ['entity', 'observation', 'relation']"
|
|
)
|
|
|
|
# Test invalid string array type
|
|
with pytest.raises(ValueError) as e:
|
|
await recent_activity.fn(type=["note"])
|
|
assert (
|
|
str(e.value) == "Invalid type: note. Valid types are: ['entity', 'observation', 'relation']"
|
|
)
|