Skip to main content
Glama

ticket_search

Search project tickets by keywords in title or description, with filters for project, status, priority, and tags to find relevant issues.

Instructions

PROJECT MANAGEMENT (TPM): Search tickets by keyword.

USE THIS TOOL WHEN:

  • User asks "find tickets about X" or "search for Y"

  • Looking for tickets by keywords in title or description

  • Need to discover relevant tickets across projects

Searches title and description. Supports prefix matching (e.g., "org" matches "organization"). Case-insensitive. All filters are combinable.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryYesSearch query (keywords to search in title/description)
project_idNoFilter by project ID (optional, case-insensitive)
statusNoFilter by status (optional)
priorityNoFilter by priority (optional)
tagsNoFilter by tags - ticket must have all specified tags (optional)
limitNoMaximum results to return (default: 20, max: 100)

Implementation Reference

  • Registration of the 'ticket_search' tool in the list_tools() function, including name, description, and JSON inputSchema.
            Tool(
                name="ticket_search",
                description="""PROJECT MANAGEMENT (TPM): Search tickets by keyword.
    
    USE THIS TOOL WHEN:
    - User asks "find tickets about X" or "search for Y"
    - Looking for tickets by keywords in title or description
    - Need to discover relevant tickets across projects
    
    Searches title and description. Supports prefix matching (e.g., "org" matches "organization").
    Case-insensitive. All filters are combinable.""",
                inputSchema={
                    "type": "object",
                    "properties": {
                        "query": {
                            "type": "string",
                            "description": "Search query (keywords to search in title/description)",
                        },
                        "project_id": {
                            "type": "string",
                            "description": "Filter by project ID (optional, case-insensitive)",
                        },
                        "status": {
                            "type": "string",
                            "enum": ["backlog", "planned", "in-progress", "done", "blocked"],
                            "description": "Filter by status (optional)",
                        },
                        "priority": {
                            "type": "string",
                            "enum": ["critical", "high", "medium", "low"],
                            "description": "Filter by priority (optional)",
                        },
                        "tags": {
                            "type": "array",
                            "items": {"type": "string"},
                            "description": "Filter by tags - ticket must have all specified tags (optional)",
                        },
                        "limit": {
                            "type": "integer",
                            "description": "Maximum results to return (default: 20, max: 100)",
                            "default": 20,
                        },
                    },
                    "required": ["query"],
                },
            ),
  • Handler logic in _handle_tool() that processes arguments, normalizes them, calls db.search_tickets(), and formats the JSON response.
    if name == "ticket_search":
        limit = min(args.get("limit", 20), 100)
        status = TicketStatus(args["status"]) if args.get("status") else None
        priority = Priority(args["priority"]) if args.get("priority") else None
    
        results = db.search_tickets(
            query=args["query"],
            project_id=args.get("project_id"),
            status=status,
            priority=priority,
            tags=args.get("tags"),
            limit=limit,
        )
    
        return _json({
            "results": results,
            "total": len(results),
            "query": args["query"],
        })
  • Core implementation of ticket search using SQLite FTS5 full-text search on titles/descriptions, with dynamic filters for project, status, priority, tags, and limit. Returns highlighted snippets.
    def search_tickets(
        self,
        query: str,
        project_id: str | None = None,
        status: TicketStatus | None = None,
        priority: Priority | None = None,
        tags: list[str] | None = None,
        limit: int = 20,
    ) -> list[dict]:
        """Search tickets using full-text search with optional filters.
    
        Args:
            query: Search query (supports prefix matching)
            project_id: Filter by project ID (case-insensitive)
            status: Filter by ticket status
            priority: Filter by priority level
            tags: Filter by tags (ticket must have all specified tags)
            limit: Maximum results to return (default 20)
    
        Returns:
            List of dicts with: id, title, project_id, status, priority, tags, snippet
        """
        if not query or not query.strip():
            return []
    
        # Build FTS5 query with prefix matching for each term
        terms = query.strip().split()
        fts_query = " ".join(f"{term}*" for term in terms)
    
        # Build the SQL query with joins and filters
        sql = """
            SELECT
                t.id,
                t.title,
                t.project_id,
                t.status,
                t.priority,
                t.tags,
                snippet(tickets_fts, 1, '<b>', '</b>', '...', 32) as snippet
            FROM tickets_fts
            JOIN tickets t ON tickets_fts.ticket_id = t.id
            WHERE tickets_fts MATCH ?
        """
        params: list = [fts_query]
    
        # Add filters
        if project_id:
            project_id = self._normalize_id(project_id)
            sql += " AND LOWER(t.project_id) = ?"
            params.append(project_id)
    
        if status:
            sql += " AND t.status = ?"
            params.append(status.value)
    
        if priority:
            sql += " AND t.priority = ?"
            params.append(priority.value)
    
        if tags:
            # Check that ticket has all specified tags using json_each
            for tag in tags:
                sql += " AND EXISTS (SELECT 1 FROM json_each(t.tags) WHERE value = ?)"
                params.append(tag)
    
        # Order by relevance (FTS5 rank) and limit
        sql += " ORDER BY rank LIMIT ?"
        params.append(limit)
    
        try:
            rows = self.conn.execute(sql, params).fetchall()
            return [
                {
                    "id": r["id"],
                    "title": r["title"],
                    "project_id": r["project_id"],
                    "status": r["status"],
                    "priority": r["priority"],
                    "tags": _from_json(r["tags"]),
                    "snippet": r["snippet"],
                }
                for r in rows
            ]
        except Exception:
            # Handle FTS5 syntax errors gracefully
            return []
Behavior4/5

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

With no annotations provided, the description carries full burden and does well by disclosing key behavioral traits: it searches title and description, supports prefix matching, is case-insensitive, and all filters are combinable. It doesn't mention pagination behavior beyond the limit parameter, rate limits, or authentication requirements, but provides substantial operational context.

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 well-structured with clear sections, front-loading the core purpose, then providing usage guidelines, then behavioral details. Every sentence earns its place - no redundant information, no fluff. The bullet points make it scannable while remaining concise.

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

Completeness4/5

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

For a search tool with no annotations and no output schema, the description provides good context about what the tool does, when to use it, and key behavioral characteristics. It could be more complete by describing the return format (what fields are included in results) or pagination behavior beyond the limit parameter, but covers the essential operational aspects well.

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 6 parameters thoroughly. The description adds minimal parameter-specific information beyond what's in the schema - it mentions that searches are in title/description and filters are combinable, but doesn't provide additional semantic context about individual parameters. Baseline 3 is appropriate when 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 searches tickets by keyword, specifying it searches title and description fields. It distinguishes itself from sibling tools like ticket_list (which presumably lists without search) and ticket_get (which gets specific tickets). The phrase 'Search tickets by keyword' provides specific verb+resource combination.

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 includes an explicit 'USE THIS TOOL WHEN:' section with three bullet points providing clear guidance on when to use this tool. It gives specific examples of user queries ('find tickets about X') and use cases (searching by keywords, discovering across projects), which helps distinguish it from alternatives like ticket_list.

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/urjitbhatia/tpm-mcp'

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