Skip to main content
Glama
pickleton89

cBioPortal MCP Server

by pickleton89

search_studies

Search cancer studies by keyword in names or descriptions with pagination to explore genomic data and clinical information.

Instructions

Search for cancer studies by keyword in their name or description with pagination support.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
keywordYes
page_numberNo
page_sizeNo
sort_byNo
directionNoASC
limitNo

Implementation Reference

  • Core handler implementation for search_studies tool: validates inputs, fetches all studies from API, filters by keyword in name/description, applies sorting and pagination, returns structured response.
    @handle_api_errors("search studies")
    async def search_studies(
        self,
        keyword: str,
        page_number: int = 0,
        page_size: int = 50,
        sort_by: Optional[str] = None,
        direction: str = "ASC",
        limit: Optional[int] = None,
    ) -> Dict[str, Any]:
        """
        Search for cancer studies by keyword in their name or description with pagination support.
    
        Args:
            keyword: Keyword to search for
            page_number: Page number to retrieve (0-based)
            page_size: Number of items per page
            sort_by: Field to sort by
            direction: Sort direction (ASC or DESC)
            limit: Maximum number of items to return across all pages (None for no limit)
    
        Returns:
            Dictionary containing list of studies and metadata
        """
        # Input Validation
        validate_keyword(keyword)
        validate_page_params(page_number, page_size, limit)
        validate_sort_params(sort_by, direction)
    
        try:
            # Await the asynchronous API call
            all_studies = await self.api_client.make_api_request("studies")
    
            if not isinstance(all_studies, list):
                # Handle cases where API request might not return a list (e.g., error response)
                error_message = (
                    "Unexpected response from API when fetching all studies."
                )
                if isinstance(all_studies, dict) and "error" in all_studies:
                    error_message = all_studies["error"]
                return {
                    "error": f"Failed to search studies for '{keyword}': {error_message}"
                }
    
            keyword_lower = keyword.lower()
            matching_studies = [
                study
                for study in all_studies
                if keyword_lower in study.get("name", "").lower()
                or keyword_lower in study.get("description", "").lower()
            ]
    
            if sort_by:
                reverse = direction.upper() == "DESC"
                matching_studies.sort(
                    key=lambda s: str(s.get(sort_by, "")), reverse=reverse
                )
    
            total_count = len(matching_studies)
            start_idx = page_number * page_size
            end_idx = start_idx + page_size
            paginated_studies = matching_studies[start_idx:end_idx]
    
            if limit and limit > 0 and len(paginated_studies) > limit:
                paginated_studies = paginated_studies[:limit]
    
            has_more = end_idx < total_count
    
            return {
                "studies": paginated_studies,
                "pagination": {
                    "page": page_number,
                    "page_size": page_size
                    if limit != 0
                    else total_count,  # Adjust page_size if all were requested
                    "total_found": total_count,
                    "has_more": has_more
                    if limit != 0
                    else False,  # No more if all were requested
                },
            }
        except httpx.HTTPStatusError as exc:
            return {
                "error": f"Failed to search studies for '{keyword}': API request failed with status {exc.response.status_code}"
            }
        except httpx.RequestError as exc:
            return {
                "error": f"Failed to search studies for '{keyword}': Network error - {str(exc)}"
            }
        except Exception as e:
            return {
                "error": f"Failed to search studies for '{keyword}': An unexpected error occurred - {str(e)}"
            }
  • Top-level MCP tool handler for search_studies that delegates to the StudiesEndpoints instance.
    async def search_studies(
        self,
        keyword: str,
        page_number: int = 0,
        page_size: int = 50,
        sort_by: Optional[str] = None,
        direction: str = "ASC",
        limit: Optional[int] = None,
    ) -> Dict[str, Any]:
        """Search for cancer studies by keyword in their name or description with pagination support."""
        return await self.studies.search_studies(
            keyword, page_number, page_size, sort_by, direction, limit
        )
  • Registration of all MCP tools including 'search_studies' by dynamically adding server methods to the FastMCP instance.
    tool_methods = [
        # Pagination utilities
        "paginate_results",
        "collect_all_results",
        # Studies endpoints
        "get_cancer_studies",
        "get_cancer_types",
        "search_studies",
        "get_study_details",
        "get_multiple_studies",
        # Genes endpoints
        "search_genes",
        "get_genes",
        "get_multiple_genes",
        "get_mutations_in_gene",
        # Samples endpoints
        "get_samples_in_study",
        "get_sample_list_id",
        # Molecular profiles endpoints
        "get_molecular_profiles",
        "get_clinical_data",
        "get_gene_panels_for_study",
        "get_gene_panel_details",
    ]
    
    for method_name in tool_methods:
        if hasattr(self, method_name):
            method = getattr(self, method_name)
            self.mcp.add_tool(method)
            logger.debug(f"Registered tool: {method_name}")
        else:
            logger.warning(f"Method {method_name} not found for tool registration")
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full burden for behavioral disclosure. It mentions 'pagination support' which is useful context, but doesn't describe what the tool returns (study objects, IDs, summaries?), error conditions, rate limits, authentication requirements, or whether it's a read-only operation. For a search tool with 6 parameters, this leaves significant behavioral gaps.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, efficient sentence that front-loads the core purpose. Every word earns its place - 'search for cancer studies' establishes the action, 'by keyword in their name or description' specifies the search scope, and 'with pagination support' adds important behavioral context without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a search tool with 6 parameters, 0% schema description coverage, no annotations, and no output schema, the description is insufficient. It doesn't explain return values, error handling, or fully document parameters. While concise, it doesn't provide enough context for an agent to use the tool effectively without additional documentation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate for all 6 parameters. It only mentions 'keyword' and implies pagination (covering 'page_number', 'page_size'), but doesn't explain 'sort_by', 'direction', or 'limit' parameters. The description adds some meaning for 2-3 parameters but leaves others completely undocumented.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool searches for cancer studies by keyword in name or description with pagination support, providing a specific verb ('search') and resource ('cancer studies'). It distinguishes from siblings like 'get_cancer_studies' by specifying keyword-based search, though it doesn't explicitly contrast with 'search_genes' or 'paginate_results'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description mentions 'pagination support' which implies usage for large result sets, but provides no explicit guidance on when to use this tool versus alternatives like 'get_cancer_studies' (which might retrieve specific studies) or 'paginate_results' (which might handle pagination differently). No when-not-to-use or prerequisite information is included.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/pickleton89/cbioportal-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server