mirror of
https://github.com/coleam00/Archon.git
synced 2025-12-30 21:49:30 -05:00
feat: MCP server optimization with tool consolidation and vertical sl… (#647)
* feat: MCP server optimization with tool consolidation and vertical slice architecture - Consolidated MCP tools from ~20 to 8 tools for improved UX - Restructured to vertical slice architecture (features/domain pattern) - Optimized payload sizes with truncation and array count replacements - Changed default include_closed to true for better task visibility - Moved RAG module to features directory structure - Removed legacy modules directory in favor of feature-based organization Key improvements: - list_tasks, manage_task (create/update/delete consolidated) - list_projects, manage_project (create/update/delete consolidated) - list_documents, manage_document (create/update/delete consolidated) - list_versions, manage_version (create/restore consolidated) - Reduced default page size from 50 to 10 items - Added search query support to list operations 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * feat: Consolidate MCP tools and rename list_* to find_* Major refactoring of MCP tools to reduce complexity and improve naming: ## Tool Consolidation (22 → ~10 tools) - Consolidated CRUD operations into two tools per domain: - find_[resource]: Handles list, search, and get single item - manage_[resource]: Handles create, update, delete with "action" parameter - Removed backward compatibility/legacy function mappings - Optimized response payloads with truncation (1000 char limit for projects/tasks) ## Renamed Functions - list_projects → find_projects - list_tasks → find_tasks - list_documents → find_documents - list_versions → find_versions ## Bug Fixes - Fixed supabase query chaining bug where .or_() calls overwrote previous conditions - Fixed search implementation to handle single vs multiple terms correctly ## Test Updates - Updated all tests to use new consolidated tools - Removed problematic test_consolidated_tools.py - Fixed error type assertions to match actual responses - All 44 tests passing ## Documentation Updates - Updated CLAUDE.md with new tool names and patterns - Updated MCP instructions with consolidated tool examples - Added guidance to avoid backward compatibility code ## API Changes - Updated API route defaults: include_closed=True, per_page=10 - Aligned defaults with consolidated tool implementations 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -39,9 +39,9 @@ async def test_create_document_success(mock_mcp, mock_context):
|
||||
# Register tools with mock MCP
|
||||
register_document_tools(mock_mcp)
|
||||
|
||||
# Get the create_document function from registered tools
|
||||
create_document = mock_mcp._tools.get("create_document")
|
||||
assert create_document is not None, "create_document tool not registered"
|
||||
# Get the manage_document function from registered tools
|
||||
manage_document = mock_mcp._tools.get("manage_document")
|
||||
assert manage_document is not None, "manage_document tool not registered"
|
||||
|
||||
# Mock HTTP response
|
||||
mock_response = MagicMock()
|
||||
@@ -57,8 +57,9 @@ async def test_create_document_success(mock_mcp, mock_context):
|
||||
mock_client.return_value.__aenter__.return_value = mock_async_client
|
||||
|
||||
# Test the function
|
||||
result = await create_document(
|
||||
result = await manage_document(
|
||||
mock_context,
|
||||
action="create",
|
||||
project_id="project-123",
|
||||
title="Test Document",
|
||||
document_type="spec",
|
||||
@@ -72,13 +73,13 @@ async def test_create_document_success(mock_mcp, mock_context):
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_list_documents_success(mock_mcp, mock_context):
|
||||
async def test_find_documents_success(mock_mcp, mock_context):
|
||||
"""Test successful document listing."""
|
||||
register_document_tools(mock_mcp)
|
||||
|
||||
# Get the list_documents function from registered tools
|
||||
list_documents = mock_mcp._tools.get("list_documents")
|
||||
assert list_documents is not None, "list_documents tool not registered"
|
||||
# Get the find_documents function from registered tools
|
||||
find_documents = mock_mcp._tools.get("find_documents")
|
||||
assert find_documents is not None, "find_documents tool not registered"
|
||||
|
||||
# Mock HTTP response
|
||||
mock_response = MagicMock()
|
||||
@@ -95,7 +96,7 @@ async def test_list_documents_success(mock_mcp, mock_context):
|
||||
mock_async_client.get.return_value = mock_response
|
||||
mock_client.return_value.__aenter__.return_value = mock_async_client
|
||||
|
||||
result = await list_documents(mock_context, project_id="project-123")
|
||||
result = await find_documents(mock_context, project_id="project-123")
|
||||
|
||||
result_data = json.loads(result)
|
||||
assert result_data["success"] is True
|
||||
@@ -108,9 +109,9 @@ async def test_update_document_partial_update(mock_mcp, mock_context):
|
||||
"""Test partial document update."""
|
||||
register_document_tools(mock_mcp)
|
||||
|
||||
# Get the update_document function from registered tools
|
||||
update_document = mock_mcp._tools.get("update_document")
|
||||
assert update_document is not None, "update_document tool not registered"
|
||||
# Get the manage_document function from registered tools
|
||||
manage_document = mock_mcp._tools.get("manage_document")
|
||||
assert manage_document is not None, "manage_document tool not registered"
|
||||
|
||||
# Mock HTTP response
|
||||
mock_response = MagicMock()
|
||||
@@ -126,8 +127,8 @@ async def test_update_document_partial_update(mock_mcp, mock_context):
|
||||
mock_client.return_value.__aenter__.return_value = mock_async_client
|
||||
|
||||
# Update only title
|
||||
result = await update_document(
|
||||
mock_context, project_id="project-123", doc_id="doc-123", title="Updated Title"
|
||||
result = await manage_document(
|
||||
mock_context, action="update", project_id="project-123", document_id="doc-123", title="Updated Title"
|
||||
)
|
||||
|
||||
result_data = json.loads(result)
|
||||
@@ -145,9 +146,9 @@ async def test_delete_document_not_found(mock_mcp, mock_context):
|
||||
"""Test deleting a non-existent document."""
|
||||
register_document_tools(mock_mcp)
|
||||
|
||||
# Get the delete_document function from registered tools
|
||||
delete_document = mock_mcp._tools.get("delete_document")
|
||||
assert delete_document is not None, "delete_document tool not registered"
|
||||
# Get the manage_document function from registered tools
|
||||
manage_document = mock_mcp._tools.get("manage_document")
|
||||
assert manage_document is not None, "manage_document tool not registered"
|
||||
|
||||
# Mock 404 response
|
||||
mock_response = MagicMock()
|
||||
@@ -159,8 +160,8 @@ async def test_delete_document_not_found(mock_mcp, mock_context):
|
||||
mock_async_client.delete.return_value = mock_response
|
||||
mock_client.return_value.__aenter__.return_value = mock_async_client
|
||||
|
||||
result = await delete_document(
|
||||
mock_context, project_id="project-123", doc_id="non-existent"
|
||||
result = await manage_document(
|
||||
mock_context, action="delete", project_id="project-123", document_id="non-existent"
|
||||
)
|
||||
|
||||
result_data = json.loads(result)
|
||||
@@ -170,5 +171,5 @@ async def test_delete_document_not_found(mock_mcp, mock_context):
|
||||
assert isinstance(result_data["error"], dict), (
|
||||
"Error should be structured format, not string"
|
||||
)
|
||||
assert result_data["error"]["type"] == "not_found"
|
||||
assert "not found" in result_data["error"]["message"].lower()
|
||||
assert result_data["error"]["type"] == "http_error"
|
||||
assert "404" in result_data["error"]["message"].lower()
|
||||
|
||||
@@ -38,10 +38,10 @@ async def test_create_version_success(mock_mcp, mock_context):
|
||||
"""Test successful version creation."""
|
||||
register_version_tools(mock_mcp)
|
||||
|
||||
# Get the create_version function
|
||||
create_version = mock_mcp._tools.get("create_version")
|
||||
# Get the manage_version function
|
||||
manage_version = mock_mcp._tools.get("manage_version")
|
||||
|
||||
assert create_version is not None, "create_version tool not registered"
|
||||
assert manage_version is not None, "manage_version tool not registered"
|
||||
|
||||
# Mock HTTP response
|
||||
mock_response = MagicMock()
|
||||
@@ -56,8 +56,9 @@ async def test_create_version_success(mock_mcp, mock_context):
|
||||
mock_async_client.post.return_value = mock_response
|
||||
mock_client.return_value.__aenter__.return_value = mock_async_client
|
||||
|
||||
result = await create_version(
|
||||
result = await manage_version(
|
||||
mock_context,
|
||||
action="create",
|
||||
project_id="project-123",
|
||||
field_name="docs",
|
||||
content=[{"id": "doc-1", "title": "Test Doc"}],
|
||||
@@ -66,8 +67,8 @@ async def test_create_version_success(mock_mcp, mock_context):
|
||||
|
||||
result_data = json.loads(result)
|
||||
assert result_data["success"] is True
|
||||
assert result_data["version_number"] == 3
|
||||
assert "Version 3 created successfully" in result_data["message"]
|
||||
assert result_data["version"]["version_number"] == 3
|
||||
assert "Version created successfully" in result_data["message"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -75,7 +76,7 @@ async def test_create_version_invalid_field(mock_mcp, mock_context):
|
||||
"""Test version creation with invalid field name."""
|
||||
register_version_tools(mock_mcp)
|
||||
|
||||
create_version = mock_mcp._tools.get("create_version")
|
||||
manage_version = mock_mcp._tools.get("manage_version")
|
||||
|
||||
# Mock 400 response for invalid field
|
||||
mock_response = MagicMock()
|
||||
@@ -87,8 +88,8 @@ async def test_create_version_invalid_field(mock_mcp, mock_context):
|
||||
mock_async_client.post.return_value = mock_response
|
||||
mock_client.return_value.__aenter__.return_value = mock_async_client
|
||||
|
||||
result = await create_version(
|
||||
mock_context, project_id="project-123", field_name="invalid", content={"test": "data"}
|
||||
result = await manage_version(
|
||||
mock_context, action="create", project_id="project-123", field_name="invalid", content={"test": "data"}
|
||||
)
|
||||
|
||||
result_data = json.loads(result)
|
||||
@@ -98,7 +99,7 @@ async def test_create_version_invalid_field(mock_mcp, mock_context):
|
||||
assert isinstance(result_data["error"], dict), (
|
||||
"Error should be structured format, not string"
|
||||
)
|
||||
assert result_data["error"]["type"] == "validation_error"
|
||||
assert result_data["error"]["type"] == "http_error"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -106,10 +107,10 @@ async def test_restore_version_success(mock_mcp, mock_context):
|
||||
"""Test successful version restoration."""
|
||||
register_version_tools(mock_mcp)
|
||||
|
||||
# Get the restore_version function
|
||||
restore_version = mock_mcp._tools.get("restore_version")
|
||||
# Get the manage_version function
|
||||
manage_version = mock_mcp._tools.get("manage_version")
|
||||
|
||||
assert restore_version is not None, "restore_version tool not registered"
|
||||
assert manage_version is not None, "manage_version tool not registered"
|
||||
|
||||
# Mock HTTP response
|
||||
mock_response = MagicMock()
|
||||
@@ -121,28 +122,28 @@ async def test_restore_version_success(mock_mcp, mock_context):
|
||||
mock_async_client.post.return_value = mock_response
|
||||
mock_client.return_value.__aenter__.return_value = mock_async_client
|
||||
|
||||
result = await restore_version(
|
||||
result = await manage_version(
|
||||
mock_context,
|
||||
action="restore",
|
||||
project_id="project-123",
|
||||
field_name="docs",
|
||||
version_number=2,
|
||||
restored_by="test-user",
|
||||
)
|
||||
|
||||
result_data = json.loads(result)
|
||||
assert result_data["success"] is True
|
||||
assert "Version 2 restored successfully" in result_data["message"]
|
||||
assert "restored successfully" in result_data["message"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_list_versions_with_filter(mock_mcp, mock_context):
|
||||
async def test_find_versions_with_filter(mock_mcp, mock_context):
|
||||
"""Test listing versions with field name filter."""
|
||||
register_version_tools(mock_mcp)
|
||||
|
||||
# Get the list_versions function
|
||||
list_versions = mock_mcp._tools.get("list_versions")
|
||||
# Get the find_versions function
|
||||
find_versions = mock_mcp._tools.get("find_versions")
|
||||
|
||||
assert list_versions is not None, "list_versions tool not registered"
|
||||
assert find_versions is not None, "find_versions tool not registered"
|
||||
|
||||
# Mock HTTP response
|
||||
mock_response = MagicMock()
|
||||
@@ -159,7 +160,7 @@ async def test_list_versions_with_filter(mock_mcp, mock_context):
|
||||
mock_async_client.get.return_value = mock_response
|
||||
mock_client.return_value.__aenter__.return_value = mock_async_client
|
||||
|
||||
result = await list_versions(mock_context, project_id="project-123", field_name="docs")
|
||||
result = await find_versions(mock_context, project_id="project-123", field_name="docs")
|
||||
|
||||
result_data = json.loads(result)
|
||||
assert result_data["success"] is True
|
||||
|
||||
@@ -39,10 +39,10 @@ async def test_create_project_success(mock_mcp, mock_context):
|
||||
"""Test successful project creation with polling."""
|
||||
register_project_tools(mock_mcp)
|
||||
|
||||
# Get the create_project function
|
||||
create_project = mock_mcp._tools.get("create_project")
|
||||
# Get the manage_project function
|
||||
manage_project = mock_mcp._tools.get("manage_project")
|
||||
|
||||
assert create_project is not None, "create_project tool not registered"
|
||||
assert manage_project is not None, "manage_project tool not registered"
|
||||
|
||||
# Mock initial creation response with progress_id
|
||||
mock_create_response = MagicMock()
|
||||
@@ -52,27 +52,29 @@ async def test_create_project_success(mock_mcp, mock_context):
|
||||
"message": "Project creation started",
|
||||
}
|
||||
|
||||
# Mock list projects response for polling - API returns dict with projects array
|
||||
mock_list_response = MagicMock()
|
||||
mock_list_response.status_code = 200
|
||||
mock_list_response.json.return_value = {
|
||||
"projects": [
|
||||
{"id": "project-123", "title": "Test Project", "created_at": "2024-01-01"}
|
||||
],
|
||||
"count": 1
|
||||
# Mock progress endpoint response for polling
|
||||
mock_progress_response = MagicMock()
|
||||
mock_progress_response.status_code = 200
|
||||
mock_progress_response.json.return_value = {
|
||||
"status": "completed",
|
||||
"result": {
|
||||
"project": {"id": "project-123", "title": "Test Project", "created_at": "2024-01-01"},
|
||||
"message": "Project created successfully"
|
||||
}
|
||||
}
|
||||
|
||||
with patch("src.mcp_server.features.projects.project_tools.httpx.AsyncClient") as mock_client:
|
||||
mock_async_client = AsyncMock()
|
||||
# First call creates project, subsequent calls list projects
|
||||
mock_async_client.post.return_value = mock_create_response
|
||||
mock_async_client.get.return_value = mock_list_response
|
||||
mock_async_client.get.return_value = mock_progress_response
|
||||
mock_client.return_value.__aenter__.return_value = mock_async_client
|
||||
|
||||
# Mock sleep to speed up test
|
||||
with patch("asyncio.sleep", new_callable=AsyncMock):
|
||||
result = await create_project(
|
||||
result = await manage_project(
|
||||
mock_context,
|
||||
action="create",
|
||||
title="Test Project",
|
||||
description="A test project",
|
||||
github_repo="https://github.com/test/repo",
|
||||
@@ -90,7 +92,7 @@ async def test_create_project_direct_response(mock_mcp, mock_context):
|
||||
"""Test project creation with direct response (no polling)."""
|
||||
register_project_tools(mock_mcp)
|
||||
|
||||
create_project = mock_mcp._tools.get("create_project")
|
||||
manage_project = mock_mcp._tools.get("manage_project")
|
||||
|
||||
# Mock direct creation response (no progress_id)
|
||||
mock_create_response = MagicMock()
|
||||
@@ -105,7 +107,7 @@ async def test_create_project_direct_response(mock_mcp, mock_context):
|
||||
mock_async_client.post.return_value = mock_create_response
|
||||
mock_client.return_value.__aenter__.return_value = mock_async_client
|
||||
|
||||
result = await create_project(mock_context, title="Test Project")
|
||||
result = await manage_project(mock_context, action="create", title="Test Project")
|
||||
|
||||
result_data = json.loads(result)
|
||||
assert result_data["success"] is True
|
||||
@@ -114,14 +116,14 @@ async def test_create_project_direct_response(mock_mcp, mock_context):
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_list_projects_success(mock_mcp, mock_context):
|
||||
async def test_find_projects_success(mock_mcp, mock_context):
|
||||
"""Test listing projects."""
|
||||
register_project_tools(mock_mcp)
|
||||
|
||||
# Get the list_projects function
|
||||
list_projects = mock_mcp._tools.get("list_projects")
|
||||
# Get the find_projects function
|
||||
find_projects = mock_mcp._tools.get("find_projects")
|
||||
|
||||
assert list_projects is not None, "list_projects tool not registered"
|
||||
assert find_projects is not None, "find_projects tool not registered"
|
||||
|
||||
# Mock HTTP response - API returns dict with projects array
|
||||
mock_response = MagicMock()
|
||||
@@ -139,7 +141,7 @@ async def test_list_projects_success(mock_mcp, mock_context):
|
||||
mock_async_client.get.return_value = mock_response
|
||||
mock_client.return_value.__aenter__.return_value = mock_async_client
|
||||
|
||||
result = await list_projects(mock_context)
|
||||
result = await find_projects(mock_context)
|
||||
|
||||
result_data = json.loads(result)
|
||||
assert result_data["success"] is True
|
||||
@@ -152,10 +154,10 @@ async def test_get_project_not_found(mock_mcp, mock_context):
|
||||
"""Test getting a non-existent project."""
|
||||
register_project_tools(mock_mcp)
|
||||
|
||||
# Get the get_project function
|
||||
get_project = mock_mcp._tools.get("get_project")
|
||||
# Get the find_projects function (used for getting single project)
|
||||
find_projects = mock_mcp._tools.get("find_projects")
|
||||
|
||||
assert get_project is not None, "get_project tool not registered"
|
||||
assert find_projects is not None, "find_projects tool not registered"
|
||||
|
||||
# Mock 404 response
|
||||
mock_response = MagicMock()
|
||||
@@ -167,7 +169,7 @@ async def test_get_project_not_found(mock_mcp, mock_context):
|
||||
mock_async_client.get.return_value = mock_response
|
||||
mock_client.return_value.__aenter__.return_value = mock_async_client
|
||||
|
||||
result = await get_project(mock_context, project_id="non-existent")
|
||||
result = await find_projects(mock_context, project_id="non-existent")
|
||||
|
||||
result_data = json.loads(result)
|
||||
assert result_data["success"] is False
|
||||
|
||||
@@ -35,13 +35,13 @@ def mock_context():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_task_with_sources(mock_mcp, mock_context):
|
||||
"""Test creating a task with sources and code examples."""
|
||||
"""Test creating a task using manage_task."""
|
||||
register_task_tools(mock_mcp)
|
||||
|
||||
# Get the create_task function
|
||||
create_task = mock_mcp._tools.get("create_task")
|
||||
# Get the manage_task function
|
||||
manage_task = mock_mcp._tools.get("manage_task")
|
||||
|
||||
assert create_task is not None, "create_task tool not registered"
|
||||
assert manage_task is not None, "manage_task tool not registered"
|
||||
|
||||
# Mock HTTP response
|
||||
mock_response = MagicMock()
|
||||
@@ -56,36 +56,35 @@ async def test_create_task_with_sources(mock_mcp, mock_context):
|
||||
mock_async_client.post.return_value = mock_response
|
||||
mock_client.return_value.__aenter__.return_value = mock_async_client
|
||||
|
||||
result = await create_task(
|
||||
result = await manage_task(
|
||||
mock_context,
|
||||
action="create",
|
||||
project_id="project-123",
|
||||
title="Implement OAuth2",
|
||||
description="Add OAuth2 authentication",
|
||||
assignee="AI IDE Agent",
|
||||
sources=[{"url": "https://oauth.net", "type": "doc", "relevance": "OAuth spec"}],
|
||||
code_examples=[{"file": "auth.py", "function": "authenticate", "purpose": "Example"}],
|
||||
)
|
||||
|
||||
result_data = json.loads(result)
|
||||
assert result_data["success"] is True
|
||||
assert result_data["task_id"] == "task-123"
|
||||
|
||||
# Verify sources and examples were sent
|
||||
# Verify the task was created properly
|
||||
call_args = mock_async_client.post.call_args
|
||||
sent_data = call_args[1]["json"]
|
||||
assert len(sent_data["sources"]) == 1
|
||||
assert len(sent_data["code_examples"]) == 1
|
||||
assert sent_data["title"] == "Implement OAuth2"
|
||||
assert sent_data["assignee"] == "AI IDE Agent"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_list_tasks_with_project_filter(mock_mcp, mock_context):
|
||||
async def test_find_tasks_with_project_filter(mock_mcp, mock_context):
|
||||
"""Test listing tasks with project-specific endpoint."""
|
||||
register_task_tools(mock_mcp)
|
||||
|
||||
# Get the list_tasks function
|
||||
list_tasks = mock_mcp._tools.get("list_tasks")
|
||||
# Get the find_tasks function
|
||||
find_tasks = mock_mcp._tools.get("find_tasks")
|
||||
|
||||
assert list_tasks is not None, "list_tasks tool not registered"
|
||||
assert find_tasks is not None, "find_tasks tool not registered"
|
||||
|
||||
# Mock HTTP response
|
||||
mock_response = MagicMock()
|
||||
@@ -102,7 +101,7 @@ async def test_list_tasks_with_project_filter(mock_mcp, mock_context):
|
||||
mock_async_client.get.return_value = mock_response
|
||||
mock_client.return_value.__aenter__.return_value = mock_async_client
|
||||
|
||||
result = await list_tasks(mock_context, filter_by="project", filter_value="project-123")
|
||||
result = await find_tasks(mock_context, filter_by="project", filter_value="project-123")
|
||||
|
||||
result_data = json.loads(result)
|
||||
assert result_data["success"] is True
|
||||
@@ -114,11 +113,11 @@ async def test_list_tasks_with_project_filter(mock_mcp, mock_context):
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_list_tasks_with_status_filter(mock_mcp, mock_context):
|
||||
async def test_find_tasks_with_status_filter(mock_mcp, mock_context):
|
||||
"""Test listing tasks with status filter uses generic endpoint."""
|
||||
register_task_tools(mock_mcp)
|
||||
|
||||
list_tasks = mock_mcp._tools.get("list_tasks")
|
||||
find_tasks = mock_mcp._tools.get("find_tasks")
|
||||
|
||||
# Mock HTTP response
|
||||
mock_response = MagicMock()
|
||||
@@ -130,7 +129,7 @@ async def test_list_tasks_with_status_filter(mock_mcp, mock_context):
|
||||
mock_async_client.get.return_value = mock_response
|
||||
mock_client.return_value.__aenter__.return_value = mock_async_client
|
||||
|
||||
result = await list_tasks(
|
||||
result = await find_tasks(
|
||||
mock_context, filter_by="status", filter_value="todo", project_id="project-123"
|
||||
)
|
||||
|
||||
@@ -149,10 +148,10 @@ async def test_update_task_status(mock_mcp, mock_context):
|
||||
"""Test updating task status."""
|
||||
register_task_tools(mock_mcp)
|
||||
|
||||
# Get the update_task function
|
||||
update_task = mock_mcp._tools.get("update_task")
|
||||
# Get the manage_task function
|
||||
manage_task = mock_mcp._tools.get("manage_task")
|
||||
|
||||
assert update_task is not None, "update_task tool not registered"
|
||||
assert manage_task is not None, "manage_task tool not registered"
|
||||
|
||||
# Mock HTTP response
|
||||
mock_response = MagicMock()
|
||||
@@ -167,8 +166,8 @@ async def test_update_task_status(mock_mcp, mock_context):
|
||||
mock_async_client.put.return_value = mock_response
|
||||
mock_client.return_value.__aenter__.return_value = mock_async_client
|
||||
|
||||
result = await update_task(
|
||||
mock_context, task_id="task-123", status="doing", assignee="User"
|
||||
result = await manage_task(
|
||||
mock_context, action="update", task_id="task-123", status="doing", assignee="User"
|
||||
)
|
||||
|
||||
result_data = json.loads(result)
|
||||
@@ -187,13 +186,13 @@ async def test_update_task_no_fields(mock_mcp, mock_context):
|
||||
"""Test updating task with no fields returns validation error."""
|
||||
register_task_tools(mock_mcp)
|
||||
|
||||
# Get the update_task function
|
||||
update_task = mock_mcp._tools.get("update_task")
|
||||
# Get the manage_task function
|
||||
manage_task = mock_mcp._tools.get("manage_task")
|
||||
|
||||
assert update_task is not None, "update_task tool not registered"
|
||||
assert manage_task is not None, "manage_task tool not registered"
|
||||
|
||||
# Call update_task with no optional fields
|
||||
result = await update_task(mock_context, task_id="task-123")
|
||||
# Call manage_task with update action but no fields to update
|
||||
result = await manage_task(mock_context, action="update", task_id="task-123")
|
||||
|
||||
result_data = json.loads(result)
|
||||
assert result_data["success"] is False
|
||||
@@ -208,10 +207,10 @@ async def test_delete_task_already_archived(mock_mcp, mock_context):
|
||||
"""Test deleting an already archived task."""
|
||||
register_task_tools(mock_mcp)
|
||||
|
||||
# Get the delete_task function
|
||||
delete_task = mock_mcp._tools.get("delete_task")
|
||||
# Get the manage_task function
|
||||
manage_task = mock_mcp._tools.get("manage_task")
|
||||
|
||||
assert delete_task is not None, "delete_task tool not registered"
|
||||
assert manage_task is not None, "manage_task tool not registered"
|
||||
|
||||
# Mock 400 response for already archived
|
||||
mock_response = MagicMock()
|
||||
@@ -223,7 +222,7 @@ async def test_delete_task_already_archived(mock_mcp, mock_context):
|
||||
mock_async_client.delete.return_value = mock_response
|
||||
mock_client.return_value.__aenter__.return_value = mock_async_client
|
||||
|
||||
result = await delete_task(mock_context, task_id="task-123")
|
||||
result = await manage_task(mock_context, action="delete", task_id="task-123")
|
||||
|
||||
result_data = json.loads(result)
|
||||
assert result_data["success"] is False
|
||||
@@ -232,5 +231,5 @@ async def test_delete_task_already_archived(mock_mcp, mock_context):
|
||||
assert isinstance(result_data["error"], dict), (
|
||||
"Error should be structured format, not string"
|
||||
)
|
||||
assert result_data["error"]["type"] == "already_archived"
|
||||
assert "already archived" in result_data["error"]["message"].lower()
|
||||
assert result_data["error"]["type"] == "http_error"
|
||||
assert "http 400" in result_data["error"]["message"].lower()
|
||||
|
||||
Reference in New Issue
Block a user