testmo_get_cases_recursive
Recursively retrieve all test cases from a folder and its subfolders, returning a flat list with folder path and per-folder counts.
Instructions
Get all test cases from a folder and all subfolders in a single call.
Returns a flat list of cases annotated with folder name/path, plus per-folder counts.
Args: project_id: The project ID. folder_id: The root folder ID to collect cases from recursively. include_folder_path: Include folder path on each case (default: true).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| project_id | Yes | ||
| folder_id | Yes | ||
| include_folder_path | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- testmo/tools/composite.py:177-240 (handler)The main handler function for the 'testmo_get_cases_recursive' tool. Decorated with @mcp.tool(), it fetches all folders, collects the subtree of folders under the given folder_id, then paginates through each folder's test cases. Returns a flat list of cases annotated with folder name/path, plus per-folder summary counts.
@mcp.tool() async def testmo_get_cases_recursive( project_id: int, folder_id: int, include_folder_path: bool = True, ) -> dict[str, Any]: """Get all test cases from a folder and all subfolders in a single call. Returns a flat list of cases annotated with folder name/path, plus per-folder counts. Args: project_id: The project ID. folder_id: The root folder ID to collect cases from recursively. include_folder_path: Include folder path on each case (default: true). """ all_folders = await _get_all_folders(project_id) folder_map = _build_folder_map(all_folders) if folder_id not in folder_map: return {"error": f"Folder {folder_id} not found in project {project_id}"} subtree_ids = _collect_subtree(all_folders, folder_id) all_cases: list[dict[str, Any]] = [] folder_summary: list[dict[str, Any]] = [] for fid in sorted(subtree_ids): cases_page: list[dict[str, Any]] = [] page = 1 while True: params: dict[str, Any] = {"page": page, "per_page": 100, "folder_id": fid} result = await _request( "GET", f"/projects/{project_id}/cases", params=params ) cases_page.extend(result.get("result", [])) if result.get("next_page") is None: break page += 1 await asyncio.sleep(RATE_LIMIT_DELAY) folder_name = folder_map[fid]["name"] if fid in folder_map else str(fid) folder_path = _get_folder_path(fid, folder_map) if include_folder_path else None if cases_page: folder_summary.append({ "folder_id": fid, "folder_name": folder_name, "folder_path": folder_path, "case_count": len(cases_page), }) for case in cases_page: case["_folder_name"] = folder_name if include_folder_path: case["_folder_path"] = folder_path all_cases.append(case) if len(subtree_ids) > 1: await asyncio.sleep(RATE_LIMIT_DELAY) return { "total_cases": len(all_cases), "total_folders_searched": len(subtree_ids), "folder_summary": folder_summary, "cases": all_cases, } - testmo/tools/composite.py:177-177 (registration)Tool registration via the @mcp.tool() decorator on the testmo_get_cases_recursive function.
@mcp.tool() - testmo/tools/composite.py:11-23 (helper)Helper function '_collect_subtree' that returns a set of folder IDs in the subtree rooted at root_id (inclusive), used to find all folders to recurse into.
def _collect_subtree(all_folders: list[dict[str, Any]], root_id: int) -> set[int]: """Return set of folder IDs in the subtree rooted at root_id (inclusive).""" children_map: dict[int, list[int]] = defaultdict(list) for f in all_folders: children_map[f.get("parent_id") or 0].append(f["id"]) result = {root_id} stack = [root_id] while stack: current = stack.pop() for child_id in children_map.get(current, []): result.add(child_id) stack.append(child_id) return result - testmo/tools/composite.py:26-27 (helper)Helper function '_build_folder_map' that builds a folder_id-to-folder mapping dictionary.
def _build_folder_map(all_folders: list[dict[str, Any]]) -> dict[int, dict[str, Any]]: return {f["id"]: f for f in all_folders} - testmo/tools/composite.py:30-40 (helper)Helper function '_get_folder_path' that constructs the full folder path string (e.g. 'Parent / Child') used to annotate cases.
def _get_folder_path(folder_id: int, folder_map: dict[int, dict[str, Any]]) -> str: if folder_id not in folder_map: return "" folder = folder_map[folder_id] path_parts = [folder["name"]] parent_id = folder.get("parent_id") while parent_id and parent_id in folder_map: parent = folder_map[parent_id] path_parts.insert(0, parent["name"]) parent_id = parent.get("parent_id") return " / ".join(path_parts)