Skip to main content
Glama
JLKmach

ServiceNow MCP Server

by JLKmach

list_categories

Retrieve knowledge base categories with filtering options for knowledge base ID, parent category, active status, and search queries to organize content.

Instructions

List categories in a knowledge base

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
knowledge_baseNoFilter by knowledge base ID
parent_categoryNoFilter by parent category ID
limitNoMaximum number of categories to return
offsetNoOffset for pagination
activeNoFilter by active status
queryNoSearch query for categories

Implementation Reference

  • The main execution function for the 'list_categories' tool. It queries the ServiceNow 'kb_category' table API with filters and returns a structured dictionary of categories.
    def list_categories(
        config: ServerConfig,
        auth_manager: AuthManager,
        params: ListCategoriesParams,
    ) -> Dict[str, Any]:
        """
        List categories in a knowledge base.
    
        Args:
            config: Server configuration.
            auth_manager: Authentication manager.
            params: Parameters for listing categories.
    
        Returns:
            Dictionary with list of categories and metadata.
        """
        api_url = f"{config.api_url}/table/kb_category"
    
        # Build query parameters
        query_params = {
            "sysparm_limit": params.limit,
            "sysparm_offset": params.offset,
            "sysparm_display_value": "all",
        }
    
        # Build query string
        query_parts = []
        if params.knowledge_base:
            # Try different query format to ensure we match by sys_id value
            query_parts.append(f"kb_knowledge_base.sys_id={params.knowledge_base}")
        if params.parent_category:
            query_parts.append(f"parent.sys_id={params.parent_category}")
        if params.active is not None:
            query_parts.append(f"active={str(params.active).lower()}")
        if params.query:
            query_parts.append(f"labelLIKE{params.query}^ORdescriptionLIKE{params.query}")
    
        if query_parts:
            query_string = "^".join(query_parts)
            logger.debug(f"Constructed query string: {query_string}")
            query_params["sysparm_query"] = query_string
        
        # Log the query parameters for debugging
        logger.debug(f"Listing categories with query params: {query_params}")
    
        # Make request
        try:
            response = requests.get(
                api_url,
                params=query_params,
                headers=auth_manager.get_headers(),
                timeout=config.timeout,
            )
            response.raise_for_status()
    
            # Get the JSON response
            json_response = response.json()
            
            # Safely extract the result
            if isinstance(json_response, dict) and "result" in json_response:
                result = json_response.get("result", [])
            else:
                logger.error("Unexpected response format: %s", json_response)
                return {
                    "success": False,
                    "message": "Unexpected response format",
                    "categories": [],
                    "count": 0,
                    "limit": params.limit,
                    "offset": params.offset,
                }
    
            # Transform the results
            categories = []
            
            # Handle either string or list
            if isinstance(result, list):
                for category_item in result:
                    if not isinstance(category_item, dict):
                        logger.warning("Skipping non-dictionary category item: %s", category_item)
                        continue
                        
                    # Safely extract values
                    category_id = category_item.get("sys_id", "")
                    title = category_item.get("label", "")
                    description = category_item.get("description", "")
                    
                    # Extract knowledge base - handle both dictionary and string cases
                    knowledge_base = ""
                    kb_field = category_item.get("kb_knowledge_base")
                    if isinstance(kb_field, dict):
                        knowledge_base = kb_field.get("display_value", "")
                    elif isinstance(kb_field, str):
                        knowledge_base = kb_field
                    # Also check if kb_knowledge_base is missing but there's a separate value field
                    elif "kb_knowledge_base_value" in category_item:
                        knowledge_base = category_item.get("kb_knowledge_base_value", "")
                    elif "kb_knowledge_base.display_value" in category_item:
                        knowledge_base = category_item.get("kb_knowledge_base.display_value", "")
                    
                    # Extract parent category - handle both dictionary and string cases
                    parent = ""
                    parent_field = category_item.get("parent")
                    if isinstance(parent_field, dict):
                        parent = parent_field.get("display_value", "")
                    elif isinstance(parent_field, str):
                        parent = parent_field
                    # Also check alternative field names
                    elif "parent_value" in category_item:
                        parent = category_item.get("parent_value", "")
                    elif "parent.display_value" in category_item:
                        parent = category_item.get("parent.display_value", "")
                    
                    # Convert active to boolean - handle string or boolean types
                    active_field = category_item.get("active")
                    if isinstance(active_field, str):
                        active = active_field.lower() == "true"
                    elif isinstance(active_field, bool):
                        active = active_field
                    else:
                        active = False
                    
                    created = category_item.get("sys_created_on", "")
                    updated = category_item.get("sys_updated_on", "")
                    
                    categories.append({
                        "id": category_id,
                        "title": title,
                        "description": description,
                        "knowledge_base": knowledge_base,
                        "parent_category": parent,
                        "active": active,
                        "created": created,
                        "updated": updated,
                    })
                    
                    # Log for debugging purposes
                    logger.debug(f"Processed category: {title}, KB: {knowledge_base}, Parent: {parent}")
            else:
                logger.warning("Result is not a list: %s", result)
    
            return {
                "success": True,
                "message": f"Found {len(categories)} categories",
                "categories": categories,
                "count": len(categories),
                "limit": params.limit,
                "offset": params.offset,
            }
    
        except requests.RequestException as e:
            logger.error(f"Failed to list categories: {e}")
            return {
                "success": False,
                "message": f"Failed to list categories: {str(e)}",
                "categories": [],
                "count": 0,
                "limit": params.limit,
                "offset": params.offset,
            } 
  • Pydantic BaseModel defining the input parameters and their validation for the list_categories tool.
    class ListCategoriesParams(BaseModel):
        """Parameters for listing categories in a knowledge base."""
        
        knowledge_base: Optional[str] = Field(None, description="Filter by knowledge base ID")
        parent_category: Optional[str] = Field(None, description="Filter by parent category ID")
        limit: int = Field(10, description="Maximum number of categories to return")
        offset: int = Field(0, description="Offset for pagination")
        active: Optional[bool] = Field(None, description="Filter by active status")
        query: Optional[str] = Field(None, description="Search query for categories")
  • Registration of the 'list_categories' tool in the central tool_definitions dictionary, specifying the aliased implementation function, input schema (aliased ListKBCategoriesParams), return type hint, description, and serialization method.
    "list_categories": (
        list_kb_categories_tool_impl,  # Use passed function
        ListKBCategoriesParams,
        Dict[str, Any],  # Expects dict
        "List categories in a knowledge base",
        "raw_dict",  # Tool returns raw dict
    ),
  • Import of the list_categories function aliased as list_kb_categories_tool, which is passed to get_tool_definitions for server registration.
    from servicenow_mcp.tools.knowledge_base import (
        list_categories as list_kb_categories_tool,
  • Re-export of the list_categories function from knowledge_base.py for convenient access in the tools package.
    list_categories,

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/JLKmach/servicenow-mcp'

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