Skip to main content
Glama

search_entries

Find videos and media content by searching across titles, descriptions, tags, and transcripts. Filter results by date, category, or custom metadata to discover relevant content in Kaltura's media library.

Instructions

SEARCH for videos or LIST all content. USE WHEN: Finding videos by keyword, listing newest content, discovering what's available, filtering by date/category. POWERFUL SEARCH across titles, descriptions, tags, captions. EXAMPLES: 'Find videos about python', 'Show newest 10 videos' (use query='*' sort_field='created_at'), 'Search in transcripts for keyword', 'List videos from last week'. This is your primary discovery tool!

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryYesSearch terms or '*' for all. EXAMPLES: '*' = list all videos, 'marketing' = find marketing content, '"exact phrase"' = exact match, 'python programming' = videos containing both words. ALWAYS use '*' when listing newest/all videos.
search_typeNoSearch scope: 'unified' (all fields), 'entry' (titles/descriptions), 'caption' (transcripts), 'metadata' (custom fields), 'cuepoint' (chapters). Default: 'unified'
match_typeNoMatch type: 'partial' (contains), 'exact_match' (exact phrase), 'starts_with' (prefix), 'exists' (has value), 'range' (numeric/date). Default: 'partial'
specific_fieldNoSpecific field to search within the selected scope. Common fields: 'name', 'description', 'tags', 'created_at'. Leave blank to search all fields.
boolean_operatorNoBoolean operator for multi-term queries: 'and' (all terms), 'or' (any term), 'not' (exclude). Default: 'and'
include_highlightsNoInclude highlighted matching text snippets in results. Default: true
custom_metadataNoCustom metadata search parameters. Requires both profile_id and xpath. Used for searching custom metadata fields.
date_rangeNoFilter entries by creation date range. Use YYYY-MM-DD format.
max_resultsNoMaximum number of results to return (default: 20, max: 100)
sort_fieldNoField to sort by. Options: 'created_at' (creation date), 'updated_at' (last modified), 'name' (alphabetical), 'views' (view count), 'plays' (play count), 'last_played_at' (recent activity), 'rank' (relevance), 'start_date' (schedule start), 'end_date' (schedule end). Default: 'created_at'
sort_orderNoSort direction. Use 'desc' for newest/highest first (default), 'asc' for oldest/lowest first. For finding latest content, use 'desc' with 'created_at'

Implementation Reference

  • Primary handler for 'search_entries' tool. Intelligently handles parameters, calls esearch_entries, adds rich search context, and formats results for MCP.
    async def search_entries_intelligent(
        manager: KalturaClientManager,
        query: str,
        search_type: str = "unified",
        match_type: str = "partial",
        specific_field: Optional[str] = None,
        boolean_operator: str = "and",
        include_highlights: bool = True,
        custom_metadata: Optional[Dict[str, Any]] = None,
        date_range: Optional[Dict[str, str]] = None,
        max_results: int = 20,
        sort_field: str = "created_at",
        sort_order: str = "desc",
    ) -> str:
        """
        Advanced search function that exposes the full power of Kaltura's eSearch API.
    
        This is the PRIMARY tool for finding and listing media entries. Use this for:
        - General searches with keywords
        - Listing all entries (query="*")
        - Filtering by date ranges, content types, fields
        - Searching in transcripts, metadata, or specific fields
        - Complex boolean queries with multiple criteria
    
        This function provides access to all eSearch capabilities while maintaining
        clear parameter naming and comprehensive documentation for LLM usage.
        """
    
        # Validate and cap max_results
        max_results = min(max_results, 100)
    
        # Handle special case for listing all entries
        if query == "*":
            # For wildcard searches, we need to avoid field-specific restrictions
            # Use unified search with a common term that should match most entries
            search_type = "unified"  # Force unified search to avoid field restrictions
            match_type = "partial"  # Use partial matching
            # Use common terms that are likely to appear in most entries (video, audio, or metadata)
            # "e" is the most common letter in English and should match most content
            query = "e"
            specific_field = None  # Clear any specific field to avoid API restrictions
    
        # Extract date range if provided
        date_after = None
        date_before = None
        if date_range:
            date_after = date_range.get("after")
            date_before = date_range.get("before")
    
        # Extract custom metadata parameters
        metadata_profile_id = None
        metadata_xpath = None
        if custom_metadata:
            metadata_profile_id = custom_metadata.get("profile_id")
            metadata_xpath = custom_metadata.get("xpath")
    
        # Call the underlying eSearch function with all parameters
        try:
            result = await esearch_entries(
                manager=manager,
                search_term=query,
                search_type=search_type,
                item_type=match_type,
                field_name=specific_field,
                add_highlight=include_highlights,
                operator_type=boolean_operator,
                metadata_profile_id=metadata_profile_id,
                metadata_xpath=metadata_xpath,
                date_range_start=date_after,
                date_range_end=date_before,
                limit=max_results,
                sort_field=sort_field,
                sort_order=sort_order,
            )
    
            # Parse the result to add comprehensive search context
            import json
    
            result_data = json.loads(result)
    
            # Add detailed search context information
            if "entries" in result_data:
                # Determine operation type
                original_query = query if query else "*"
                operation_type = "list_all" if original_query == "*" else "search"
    
                search_context = {
                    "searchQuery": original_query,
                    "operationType": operation_type,
                    "searchConfiguration": {
                        "scope": search_type,
                        "matchType": match_type,
                        "specificField": specific_field,
                        "booleanOperator": boolean_operator,
                        "highlightsEnabled": include_highlights,
                    },
                    "filters": {
                        "dateRange": date_range,
                        "customMetadata": custom_metadata if custom_metadata else None,
                    },
                    "results": {
                        "count": len(result_data["entries"]),
                        "totalMatches": result_data.get("totalCount", 0),
                        "maxRequested": max_results,
                    },
                    "searchCapabilities": {
                        "availableScopes": [
                            "unified (all content)",
                            "entry (metadata)",
                            "caption (transcripts)",
                            "metadata (custom fields)",
                            "cuepoint (temporal markers)",
                        ],
                        "availableMatchTypes": [
                            "partial (contains)",
                            "exact_match (exact phrase)",
                            "starts_with (prefix)",
                            "exists (field has value)",
                            "range (numeric/date)",
                        ],
                        "advancedFeatures": [
                            "highlighting",
                            "boolean operators",
                            "custom metadata search",
                            "date filtering",
                            "field-specific search",
                        ],
                    },
                }
                result_data["searchContext"] = search_context
    
            return json.dumps(result_data, indent=2)
    
        except Exception as e:
            # If eSearch fails, provide detailed error information
            logger.error(f"eSearch failed: {e}")
            return handle_kaltura_error(
                e,
                "search entries",
                {
                    "searchQuery": query,
                    "searchType": search_type,
                    "suggestion": "Try using simpler parameters or check your search syntax",
                },
            )
  • Input schema and description for the 'search_entries' tool, defining all parameters like query, search_type, sort_field, etc.
        name="search_entries",
        description="SEARCH for videos or LIST all content. USE WHEN: Finding videos by keyword, listing newest content, discovering what's available, filtering by date/category. POWERFUL SEARCH across titles, descriptions, tags, captions. EXAMPLES: 'Find videos about python', 'Show newest 10 videos' (use query='*' sort_field='created_at'), 'Search in transcripts for keyword', 'List videos from last week'. This is your primary discovery tool!",
        inputSchema={
            "type": "object",
            "properties": {
                "query": {
                    "type": "string",
                    "description": "Search terms or '*' for all. EXAMPLES: '*' = list all videos, 'marketing' = find marketing content, '\"exact phrase\"' = exact match, 'python programming' = videos containing both words. ALWAYS use '*' when listing newest/all videos.",
                },
                "search_type": {
                    "type": "string",
                    "enum": ["unified", "entry", "caption", "metadata", "cuepoint"],
                    "description": "Search scope: 'unified' (all fields), 'entry' (titles/descriptions), 'caption' (transcripts), 'metadata' (custom fields), 'cuepoint' (chapters). Default: 'unified'",
                },
                "match_type": {
                    "type": "string",
                    "enum": ["partial", "exact_match", "starts_with", "exists", "range"],
                    "description": "Match type: 'partial' (contains), 'exact_match' (exact phrase), 'starts_with' (prefix), 'exists' (has value), 'range' (numeric/date). Default: 'partial'",
                },
                "specific_field": {
                    "type": "string",
                    "description": "Specific field to search within the selected scope. Common fields: 'name', 'description', 'tags', 'created_at'. Leave blank to search all fields.",
                },
                "boolean_operator": {
                    "type": "string",
                    "enum": ["and", "or", "not"],
                    "description": "Boolean operator for multi-term queries: 'and' (all terms), 'or' (any term), 'not' (exclude). Default: 'and'",
                },
                "include_highlights": {
                    "type": "boolean",
                    "description": "Include highlighted matching text snippets in results. Default: true",
                },
                "custom_metadata": {
                    "type": "object",
                    "properties": {
                        "profile_id": {
                            "type": "integer",
                            "description": "Custom metadata profile ID",
                        },
                        "xpath": {
                            "type": "string",
                            "description": "XPath to specific metadata field",
                        },
                    },
                    "description": "Custom metadata search parameters. Requires both profile_id and xpath. Used for searching custom metadata fields.",
                },
                "date_range": {
                    "type": "object",
                    "properties": {
                        "after": {
                            "type": "string",
                            "description": "Created after this date (YYYY-MM-DD format)",
                        },
                        "before": {
                            "type": "string",
                            "description": "Created before this date (YYYY-MM-DD format)",
                        },
                    },
                    "description": "Filter entries by creation date range. Use YYYY-MM-DD format.",
                },
                "max_results": {
                    "type": "integer",
                    "description": "Maximum number of results to return (default: 20, max: 100)",
                },
                "sort_field": {
                    "type": "string",
                    "enum": [
                        "created_at",
                        "updated_at",
                        "name",
                        "views",
                        "plays",
                        "last_played_at",
                        "rank",
                        "start_date",
                        "end_date",
                    ],
                    "description": "Field to sort by. Options: 'created_at' (creation date), 'updated_at' (last modified), 'name' (alphabetical), 'views' (view count), 'plays' (play count), 'last_played_at' (recent activity), 'rank' (relevance), 'start_date' (schedule start), 'end_date' (schedule end). Default: 'created_at'",
                },
                "sort_order": {
                    "type": "string",
                    "enum": ["desc", "asc"],
                    "description": "Sort direction. Use 'desc' for newest/highest first (default), 'asc' for oldest/lowest first. For finding latest content, use 'desc' with 'created_at'",
                },
            },
            "required": ["query"],
        },
    ),
  • Dispatch/registration in call_tool handler mapping 'search_entries' to search_entries_intelligent function.
    elif name == "search_entries":
        result = await search_entries_intelligent(kaltura_manager, **arguments)
  • Core helper implementing Kaltura eSearch API calls, used by search_entries_intelligent.
    async def esearch_entries(
        manager: KalturaClientManager,
        search_term: str,
        search_type: str = "unified",
        item_type: str = "partial",
        field_name: Optional[str] = None,
        add_highlight: bool = True,
        operator_type: str = "and",
        metadata_profile_id: Optional[int] = None,
        metadata_xpath: Optional[str] = None,
        date_range_start: Optional[str] = None,
        date_range_end: Optional[str] = None,
        limit: int = 20,
        sort_field: str = "created_at",
        sort_order: str = "desc",
    ) -> str:
        """Enhanced search using Kaltura eSearch API with advanced capabilities."""
    
        client = manager.get_client()
    
        try:
            # Use the ElasticSearch service through the client
    
            # Create search items based on search type
            search_items = []
    
            if search_type == "unified":
                # Unified search across all entry data
                unified_item = KalturaESearchUnifiedItem()
                unified_item.searchTerm = search_term
                unified_item.itemType = _get_item_type(item_type)
                unified_item.addHighlight = add_highlight
                search_items.append(unified_item)
    
            elif search_type == "entry":
                # Search in specific entry fields
                entry_item = KalturaESearchEntryItem()
                entry_item.searchTerm = search_term
                entry_item.itemType = _get_item_type(item_type)
                entry_item.fieldName = _get_entry_field_name(field_name or "name")
                entry_item.addHighlight = add_highlight
                search_items.append(entry_item)
    
            elif search_type == "caption":
                # Search in captions
                caption_item = KalturaESearchCaptionItem()
                caption_item.searchTerm = search_term
                caption_item.itemType = _get_item_type(item_type)
                caption_item.fieldName = _get_caption_field_name(field_name or "content")
                caption_item.addHighlight = add_highlight
                search_items.append(caption_item)
    
            elif search_type == "metadata":
                # Search in custom metadata
                metadata_item = KalturaESearchEntryMetadataItem()
                metadata_item.searchTerm = search_term
                metadata_item.itemType = _get_item_type(item_type)
                metadata_item.addHighlight = add_highlight
    
                if metadata_profile_id:
                    metadata_item.metadataProfileId = metadata_profile_id
                if metadata_xpath:
                    metadata_item.xpath = metadata_xpath
    
                search_items.append(metadata_item)
    
            elif search_type == "cuepoint":
                # Search in cue points
                cuepoint_item = KalturaESearchCuePointItem()
                cuepoint_item.searchTerm = search_term
                cuepoint_item.itemType = _get_item_type(item_type)
                cuepoint_item.fieldName = _get_cuepoint_field_name(field_name or "text")
                cuepoint_item.addHighlight = add_highlight
                search_items.append(cuepoint_item)
    
            # Add date range filtering if specified
            if date_range_start and date_range_end:
                try:
                    start_timestamp = int(datetime.strptime(date_range_start, "%Y-%m-%d").timestamp())
                    end_timestamp = int(datetime.strptime(date_range_end, "%Y-%m-%d").timestamp())
    
                    range_item = KalturaESearchRange()
                    range_item.greaterThanOrEqual = start_timestamp
                    range_item.lessThanOrEqual = end_timestamp
    
                    date_item = KalturaESearchEntryItem()
                    date_item.itemType = KalturaESearchItemType.RANGE
                    date_item.fieldName = KalturaESearchEntryFieldName.CREATED_AT
                    date_item.range = range_item
    
                    search_items.append(date_item)
                except ValueError:
                    return json.dumps({"error": "Invalid date format. Use YYYY-MM-DD"})
    
            # Create search operator
            search_operator = KalturaESearchEntryOperator()
            search_operator.operator = _get_operator_type(operator_type)
            search_operator.searchItems = search_items
    
            # Create search parameters
            search_params = KalturaESearchEntryParams()
            search_params.searchOperator = search_operator
    
            # Add sorting
            order_by = KalturaESearchOrderBy()
            order_item = KalturaESearchEntryOrderByItem()
            order_item.sortField = _get_sort_field(sort_field)
            order_item.sortOrder = _get_sort_order(sort_order)
            order_by.orderItems = [order_item]
            search_params.orderBy = order_by
    
            # Add paging
            pager = KalturaFilterPager()
            pager.pageSize = limit
    
            # Execute search using the client's elasticsearch service
            search_results = client.elasticSearch.eSearch.searchEntry(search_params, pager)
    
            # Process results
            entries = []
            for result in search_results.objects:
                entry_data = {
                    "id": result.object.id,
                    "name": result.object.name,
                    "description": result.object.description,
                    "mediaType": result.object.mediaType.value
                    if hasattr(result.object.mediaType, "value")
                    else result.object.mediaType,
                    "createdAt": datetime.fromtimestamp(result.object.createdAt).isoformat()
                    if result.object.createdAt
                    else None,
                    "duration": result.object.duration,
                    "tags": result.object.tags,
                    "thumbnailUrl": result.object.thumbnailUrl,
                    "plays": result.object.plays,
                    "views": result.object.views,
                }
    
                # Add highlights if available
                if hasattr(result, "highlight") and result.highlight:
                    highlights = []
                    for highlight in result.highlight:
                        highlight_data = {
                            "fieldName": highlight.fieldName,
                            "hits": [hit.value for hit in highlight.hits] if highlight.hits else [],
                        }
                        highlights.append(highlight_data)
                    entry_data["highlights"] = highlights
    
                # Add items data (for captions, metadata, etc.)
                if hasattr(result, "itemsData") and result.itemsData:
                    items_data = []
                    for item_data in result.itemsData:
                        item_info = {"totalCount": item_data.totalCount, "items": []}
    
                        if hasattr(item_data, "items") and item_data.items:
                            for item in item_data.items:
                                item_detail = {}
    
                                # Handle different item types
                                if hasattr(item, "line"):  # Caption item
                                    item_detail.update(
                                        {
                                            "line": item.line,
                                            "startsAt": item.startsAt,
                                            "endsAt": item.endsAt,
                                            "language": item.language,
                                            "captionAssetId": item.captionAssetId,
                                        }
                                    )
                                elif hasattr(item, "valueText"):  # Metadata item
                                    item_detail.update(
                                        {
                                            "xpath": item.xpath,
                                            "metadataProfileId": item.metadataProfileId,
                                            "metadataFieldId": item.metadataFieldId,
                                            "valueText": item.valueText,
                                        }
                                    )
    
                                # Add highlights for this item
                                if hasattr(item, "highlight") and item.highlight:
                                    item_highlights = []
                                    for highlight in item.highlight:
                                        item_highlight = {
                                            "fieldName": highlight.fieldName,
                                            "hits": [hit.value for hit in highlight.hits]
                                            if highlight.hits
                                            else [],
                                        }
                                        item_highlights.append(item_highlight)
                                    item_detail["highlights"] = item_highlights
    
                                item_info["items"].append(item_detail)
    
                        items_data.append(item_info)
                    entry_data["itemsData"] = items_data
    
                entries.append(entry_data)
    
            return json.dumps(
                {
                    "searchTerm": search_term,
                    "searchType": search_type,
                    "totalCount": search_results.totalCount,
                    "entries": entries,
                },
                indent=2,
            )
    
        except Exception as e:
            return json.dumps(
                {
                    "error": f"eSearch failed: {str(e)}",
                    "searchTerm": search_term,
                    "searchType": search_type,
                },
                indent=2,
            )
  • Exports search_entries and search_entries_intelligent for import in server.py.
    from .search import (
        esearch_entries,
        list_categories,
        search_entries,
        search_entries_intelligent,
    )
    from .utils import (
        handle_kaltura_error,
        safe_serialize_kaltura_field,
        validate_entry_id,
    )
    
    # Export all tools
    __all__ = [
        # Utilities
        "handle_kaltura_error",
        "safe_serialize_kaltura_field",
        "validate_entry_id",
        # Media operations
        "get_download_url",
        "get_media_entry",
        "get_thumbnail_url",
        "list_media_entries",
        # Analytics operations
        "get_analytics",
        "get_analytics_timeseries",
        "get_video_retention",
        "get_realtime_metrics",
        "get_quality_metrics",
        "get_geographic_breakdown",
        "list_analytics_capabilities",
        # Search operations
        "esearch_entries",
        "list_categories",
        "search_entries",
        "search_entries_intelligent",
Behavior3/5

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

No annotations are provided, so the description carries full burden. It mentions 'POWERFUL SEARCH across titles, descriptions, tags, captions' and 'primary discovery tool,' which gives some behavioral context (e.g., broad search capabilities). However, it lacks details on permissions, rate limits, pagination, or error handling, leaving gaps for a tool with 11 parameters and no output schema.

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

Conciseness4/5

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

The description is front-loaded with key information (purpose and usage) and uses bullet-like examples efficiently. However, it includes some redundancy (e.g., repeating search capabilities) and could be slightly more streamlined, but overall it's well-structured and earns its place with helpful guidance.

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

Completeness3/5

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

Given the complexity (11 parameters, no output schema, no annotations), the description is adequate but incomplete. It covers purpose and usage well but lacks behavioral details (e.g., response format, error cases) and doesn't fully address the tool's richness. It's a minimum viable description that leaves the agent to rely heavily on the schema for execution.

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

Parameters3/5

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

Schema description coverage is 100%, so the schema already documents all parameters thoroughly. The description adds minimal parameter semantics beyond the schema, such as implying the tool handles 'videos' and 'content' and giving example queries, but it doesn't provide additional meaning or clarify complex interactions between parameters. Baseline 3 is appropriate as the schema does the heavy lifting.

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

Purpose5/5

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

The description clearly states the tool's purpose with specific verbs ('SEARCH for videos or LIST all content') and resource ('videos'/'content'). It distinguishes this as the 'primary discovery tool' from siblings that appear to be more specific retrieval tools (like get_media_entry, get_caption_content, etc.), making the scope and role explicit.

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

Usage Guidelines5/5

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

The description explicitly states 'USE WHEN:' with multiple scenarios (finding by keyword, listing newest content, discovering what's available, filtering by date/category). It provides concrete examples and distinguishes this as the go-to tool for discovery, implying alternatives are not needed for these tasks, though it doesn't name specific sibling tools to avoid.

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/zoharbabin/kaltura-mcp'

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