Skip to main content
Glama
tarun7r

cricket-mcp-server

get_live_commentary

Fetch recent live cricket commentary events for any Cricbuzz match by providing the match URL and specifying the number of items to retrieve.

Instructions

Get recent live commentary events for a Cricbuzz match.

Args: match_url (str): Cricbuzz match URL. Can be a general match page; the commentary tab will be resolved automatically. limit (int): Maximum number of recent commentary items to return.

Returns: dict: {"title": str, "commentary_url": str, "events": [{"text": str}]}

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
limitNo
match_urlYes

Implementation Reference

  • The main handler function for the get_live_commentary tool. It is decorated with @mcp.tool() for automatic registration in FastMCP. The function fetches live commentary primarily from the Cricbuzz JSON API, falling back to HTML scraping if needed. It extracts match title, commentary events, and handles errors gracefully.
    def get_live_commentary(match_url: str, limit: int = 20) -> dict:
        """
        Get recent live commentary events for a Cricbuzz match.
    
        Args:
            match_url (str): Cricbuzz match URL. Can be a general match page; the commentary tab will be resolved automatically.
            limit (int): Maximum number of recent commentary items to return.
    
        Returns:
            dict: {"title": str, "commentary_url": str, "events": [{"text": str}]}
        """
        if not match_url or "cricbuzz.com" not in match_url:
            return {"error": "A valid Cricbuzz match URL is required."}
    
        # Try official JSON commentary API first (more reliable than HTML scraping)
        match_id_match = re.search(r"/(\d{5,7})/", match_url)
        if not match_id_match:
            return {"error": "Could not extract match id from URL."}
        match_id = match_id_match.group(1)
    
        api_url = f"https://www.cricbuzz.com/api/cricket-match/commentary/{match_id}"
        try:
            resp = requests.get(api_url, headers=HEADERS, timeout=15)
            resp.raise_for_status()
            data = resp.json()
        except Exception as e:
            data = None
    
        def _clean_comm_text(text: str) -> str:
            # Remove formatting markers like "B0$", "I0$" etc.
            t = re.sub(r"[A-Z]\d\$", "", text)
            # Normalize whitespace
            t = re.sub(r"\s+", " ", t).strip()
            return t
    
        if isinstance(data, dict) and data.get("commentaryList"):
            header = data.get("matchHeader", {})
            miniscore = data.get("miniscore", {})
            title_parts = []
            if header.get("matchDescription"):
                title_parts.append(header.get("matchDescription"))
            if header.get("status"):
                title_parts.append(header.get("status"))
            title = " - ".join(title_parts) if title_parts else None
    
            events = []
            for item in data.get("commentaryList", [])[: max(0, limit)]:
                text = _clean_comm_text(str(item.get("commText", "")).strip())
                if not text:
                    continue
                ev = {"text": text}
                if item.get("event"):
                    ev["event"] = item.get("event")
                if item.get("ballNbr") is not None:
                    ev["ball"] = item.get("ballNbr")
                events.append(ev)
    
            return {
                "title": title,
                "commentary_url": match_url,
                "events": events,
            }
    
        # If JSON API fails, fall back to HTML scraping heuristics
        def _fetch(url: str) -> BeautifulSoup | None:
            try:
                resp = requests.get(url, headers=HEADERS, timeout=15)
                resp.raise_for_status()
                return BeautifulSoup(resp.text, "lxml")
            except Exception:
                return None
    
        page = _fetch(match_url)
        if not page:
            return {"error": "Failed to load match page. The match might not be live or the URL may be incorrect."}
    
        commentary_url = None
        try:
            nav = page.find("div", class_=re.compile("cb-nav-pills"))
            if nav:
                for a in nav.find_all("a", href=True):
                    if "commentary" in a.get("href", "").lower() or (a.text and "commentary" in a.text.lower()):
                        commentary_url = ("https://www.cricbuzz.com" + a["href"]) if a["href"].startswith("/") else a["href"]
                        break
        except Exception:
            pass
    
        if not commentary_url:
            commentary_url = match_url.rstrip("/") + "/commentary"
    
        cpage = _fetch(commentary_url)
        if not cpage:
            return {"error": "Failed to load commentary page. This match may not have live commentary available."}
    
        result: dict = {"title": None, "commentary_url": commentary_url, "events": []}
        title_tag = cpage.find("h1", class_=re.compile("cb-nav-hdr"))
        if title_tag:
            result["title"] = title_tag.text.strip()
    
        candidates = []
        candidates.extend(cpage.find_all("div", class_=re.compile(r"cb-col\s+cb-col-90\s+cb-com-ln")))
        if not candidates:
            lst = cpage.find("div", class_=re.compile("cb-com-lst"))
            if lst:
                candidates.extend(lst.find_all("div", class_=re.compile(r"cb-col\s+cb-col-90")))
        if not candidates:
            candidates.extend(cpage.find_all("p", class_=re.compile("cb-com-ln")))
        if not candidates:
            candidates.extend(cpage.find_all("div", class_=re.compile("cb-com-ln")))
        if not candidates:
            for div in cpage.find_all("div"):
                text = div.get_text(" ", strip=True)
                if text and len(text) > 20 and ("ball" in text.lower() or "over" in text.lower() or "wicket" in text.lower()):
                    candidates.append(div)
    
        events = []
        for node in candidates:
            try:
                text = node.get_text(" ", strip=True)
                if not text:
                    continue
                if text.lower().startswith("commentary"):
                    continue
                if len(text) < 10:
                    continue
                events.append({"text": text})
                if len(events) >= limit:
                    break
            except Exception:
                continue
    
        result["events"] = events
        if not events:
            result["note"] = "No commentary items found. This match may not be live or commentary may not be available."
            try:
                match_info = get_match_details(match_url)
                if "error" not in match_info:
                    result["fallback"] = "Commentary not available, but here's the match details:"
                    result["match_details"] = match_info
            except Exception:
                pass
    
        return result
Behavior2/5

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

No annotations are provided, so the description carries the full burden of behavioral disclosure. It mentions that the tool returns recent commentary events and handles URL resolution automatically, but lacks details on permissions, rate limits, error handling, or whether it's read-only. For a tool with no annotations, 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 front-loaded with the core purpose, followed by structured Args and Returns sections. Every sentence earns its place by providing essential information without redundancy, making it highly efficient and well-organized.

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 no annotations, 0% schema coverage, and no output schema, the description does a decent job explaining parameters and return structure. However, it lacks details on behavioral aspects like error cases or operational constraints, which are important for a tool interacting with external data. It's adequate but has clear gaps in completeness.

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

Parameters4/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. It adds meaningful semantics: match_url is explained as a Cricbuzz URL where the commentary tab is resolved automatically, and limit specifies the maximum number of recent items. This clarifies beyond the schema's basic types, though it doesn't cover all potential nuances like URL format constraints.

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 specific action ('Get recent live commentary events') and resource ('for a Cricbuzz match'), distinguishing it from siblings like get_match_details or get_live_matches. It precisely identifies what the tool retrieves without being vague or tautological.

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

Usage Guidelines4/5

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

The description provides clear context for when to use this tool—for live commentary events on Cricbuzz matches. It implicitly distinguishes from siblings like get_cricket_news or get_player_stats by focusing on commentary. However, it does not explicitly state when not to use it or name alternatives like search_live_commentary for more specific queries.

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

Related 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/tarun7r/cricket-mcp-server'

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