diff --git a/src/cordra_mcp/server.py b/src/cordra_mcp/server.py index 54a9d9c..efbbc20 100644 --- a/src/cordra_mcp/server.py +++ b/src/cordra_mcp/server.py @@ -37,15 +37,21 @@ Examples: Pagination: - Results are paginated with 0-based page numbering -- Use 'limit' to control page size (default: 1) +- Use 'limit' to control page size (default: 25) - Use 'page_num' to specify which page to retrieve (default: 0) -Returns a JSON list of matching objects with their full metadata.""" +Returns a JSON object containing: +- object_ids: List of object IDs that match the search +- total_count: Total number of objects matching the query +- page_num: Current page number +- page_size: Number of results per page + +Use the cordra://objects/{prefix}/{suffix} resources to retrieve full object details.""", ) async def search_objects( query: str, type: str | None = None, - limit: int = 1, + limit: int = 25, page_num: int = 0, ) -> str: """Search for digital objects in the Cordra repository with pagination support. @@ -56,16 +62,22 @@ async def search_objects( - "/author:smith" - Find objects by author Smith - "/name:John AND type:Person" - Complex queries type: Optional filter by object type (e.g., "Person", "Document", "Project") - limit: Page size - number of results per page (default: 1) + limit: Page size - number of results per page (default: 25) page_num: Page number to retrieve, 0-based (default: 0 for first page) Returns: - JSON string containing list of matching objects with their full metadata + JSON string containing object IDs and pagination info """ try: - search_result = await cordra_client.find(query, object_type=type, page_size=limit, page_num=page_num) - results = search_result["results"] - return json.dumps(results, indent=2) + search_result = await cordra_client.find( + query, object_type=type, page_size=limit, page_num=page_num + ) + + # Extract only the IDs from the results + search_result["results"] = [obj["id"] for obj in search_result["results"]] + # Rename for consistency with documentation + search_result["total_count"] = search_result.pop("total_size") + return json.dumps(search_result, indent=2) except ValueError as e: raise RuntimeError(f"Invalid search parameters: {e}") from e @@ -168,7 +180,9 @@ async def register_schema_resources() -> None: page_size = 20 while True: - search_result = await cordra_client.find("type:Schema", page_size=page_size, page_num=page_num) + search_result = await cordra_client.find( + "type:Schema", page_size=page_size, page_num=page_num + ) schemas = search_result["results"] all_schemas.extend(schemas) diff --git a/tests/test_server.py b/tests/test_server.py index 4a9f171..1603dd0 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -306,12 +306,15 @@ class TestSearchObjects: # Verify the result is valid JSON parsed_result = json.loads(result) - assert len(parsed_result) == 2 - assert parsed_result[0]["id"] == "people/john-doe" - assert parsed_result[1]["id"] == "people/jane-smith" + assert parsed_result["results"] == ["people/john-doe", "people/jane-smith"] + assert parsed_result["total_count"] == 2 + assert parsed_result["page_num"] == 0 + assert parsed_result["page_size"] == 1000 # Verify the client was called with correct parameters - mock_client.find.assert_called_once_with("name:John", object_type=None, page_size=1, page_num=0) + mock_client.find.assert_called_once_with( + "name:John", object_type=None, page_size=25, page_num=0 + ) @patch('cordra_mcp.server.cordra_client') async def test_search_objects_with_type_filter(self, mock_client): @@ -330,11 +333,13 @@ class TestSearchObjects: # Verify the result is valid JSON parsed_result = json.loads(result) - assert len(parsed_result) == 1 - assert parsed_result[0]["type"] == "Person" + assert parsed_result["results"] == ["people/john-doe"] + assert parsed_result["total_count"] == 1 # Verify the client was called with type filter - mock_client.find.assert_called_once_with("name:John", object_type="Person", page_size=1, page_num=0) + mock_client.find.assert_called_once_with( + "name:John", object_type="Person", page_size=25, page_num=0 + ) @patch('cordra_mcp.server.cordra_client') async def test_search_objects_with_limit(self, mock_client): @@ -353,7 +358,8 @@ class TestSearchObjects: # Verify the result is valid JSON parsed_result = json.loads(result) - assert len(parsed_result) == 1 + assert parsed_result["results"] == ["people/john-doe"] + assert parsed_result["page_size"] == 50 # Verify the client was called with custom limit mock_client.find.assert_called_once_with("name:John", object_type=None, page_size=50, page_num=0) @@ -375,11 +381,13 @@ class TestSearchObjects: # Verify the result is valid JSON parsed_result = json.loads(result) - assert len(parsed_result) == 1 - assert parsed_result[0]["type"] == "Document" + assert parsed_result["results"] == ["documents/report-123"] + assert parsed_result["total_count"] == 1 # Verify the client was called with all parameters - mock_client.find.assert_called_once_with("title:Report", object_type="Document", page_size=25, page_num=0) + mock_client.find.assert_called_once_with( + "title:Report", object_type="Document", page_size=25, page_num=0 + ) @patch('cordra_mcp.server.cordra_client') async def test_search_objects_empty_results(self, mock_client): @@ -396,9 +404,12 @@ class TestSearchObjects: # Verify the result is valid JSON with empty array parsed_result = json.loads(result) - assert parsed_result == [] + assert parsed_result["results"] == [] + assert parsed_result["total_count"] == 0 - mock_client.find.assert_called_once_with("nonexistent:data", object_type=None, page_size=1, page_num=0) + mock_client.find.assert_called_once_with( + "nonexistent:data", object_type=None, page_size=25, page_num=0 + ) @patch('cordra_mcp.server.cordra_client') async def test_search_objects_client_error(self, mock_client): @@ -409,7 +420,9 @@ class TestSearchObjects: await search_objects("test:query") assert "Search failed:" in str(exc_info.value) - mock_client.find.assert_called_once_with("test:query", object_type=None, page_size=1, page_num=0) + mock_client.find.assert_called_once_with( + "test:query", object_type=None, page_size=25, page_num=0 + ) @patch('cordra_mcp.server.cordra_client') async def test_search_objects_value_error(self, mock_client): @@ -420,7 +433,9 @@ class TestSearchObjects: await search_objects("invalid:query") assert "Invalid search parameters:" in str(exc_info.value) - mock_client.find.assert_called_once_with("invalid:query", object_type=None, page_size=1, page_num=0) + mock_client.find.assert_called_once_with( + "invalid:query", object_type=None, page_size=25, page_num=0 + ) @patch('cordra_mcp.server.cordra_client') async def test_search_objects_json_formatting(self, mock_client): @@ -445,9 +460,8 @@ class TestSearchObjects: assert " " in result # Should have 2-space indentation # Verify the content is correctly formatted - assert parsed_result[0]["id"] == "test/object" - assert parsed_result[0]["type"] == "Test" - assert parsed_result[0]["content"]["data"] == "value" + assert parsed_result["results"] == ["test/object"] + assert parsed_result["total_count"] == 1 @patch('cordra_mcp.server.cordra_client') async def test_search_objects_with_page_num(self, mock_client): @@ -465,14 +479,20 @@ class TestSearchObjects: await search_objects("type:Document", page_num=1) # Verify the client was called with correct page number - mock_client.find.assert_called_once_with("type:Document", object_type=None, page_size=1, page_num=1) + mock_client.find.assert_called_once_with( + "type:Document", object_type=None, page_size=25, page_num=1 + ) @patch('cordra_mcp.server.cordra_client') async def test_search_objects_with_all_pagination_params(self, mock_client): """Test object search with all pagination parameters.""" mock_search_result = { "results": [ - {"id": "reports/report-51", "type": "Report", "content": {"title": "Report 51"}}, + { + "id": "reports/report-51", + "type": "Report", + "content": {"title": "Report 51"}, + }, ], "total_size": 100, "page_num": 5, @@ -483,7 +503,9 @@ class TestSearchObjects: await search_objects("type:Report", type="Report", limit=10, page_num=5) # Verify the client was called with all parameters - mock_client.find.assert_called_once_with("type:Report", object_type="Report", page_size=10, page_num=5) + mock_client.find.assert_called_once_with( + "type:Report", object_type="Report", page_size=10, page_num=5 + ) class TestGetCordraDesign: