Skip to main content
Glama

get_match_data

Retrieve detailed Dota 2 match information including player stats, scores, and game metrics for analysis or reference.

Instructions

Get detailed data for a specific match.

Args: match_id: ID of the match to retrieve Returns: Detailed match information including players, scores, and stats

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
match_idYes

Implementation Reference

  • The core handler function for the 'get_match_data' tool. Decorated with @mcp.tool() for automatic registration in the FastMCP server. It fetches match data from the OpenDota API using make_opendota_request and formats it using format_match_data.
    @mcp.tool() async def get_match_data(match_id: int) -> str: """Get detailed data for a specific match. Args: match_id: ID of the match to retrieve Returns: Detailed match information including players, scores, and stats """ match_data = await make_opendota_request(f"matches/{match_id}") if "error" in match_data: return f"Error retrieving match data: {match_data['error']}" return format_match_data(match_data)
  • Helper function that formats the raw match dictionary from the API into a detailed, human-readable string including match details, scores, teams, and per-player stats.
    def format_match_data(match: Dict[str, Any]) -> str: """Format match data into a readable string.""" if not match or "match_id" not in match: return "Match data not found." # Basic match info match_id = match.get("match_id", "Unknown") duration = match.get("duration", 0) duration_formatted = format_duration(duration) start_time = format_timestamp(match.get("start_time", 0)) game_mode = match.get("game_mode", "Unknown") radiant_win = match.get("radiant_win", False) winner = "Radiant" if radiant_win else "Dire" # Scores radiant_score = match.get("radiant_score", 0) dire_score = match.get("dire_score", 0) # Teams radiant_team_data = match.get("radiant_team", {}) dire_team_data = match.get("dire_team", {}) # Handle the case where these might be strings instead of dicts if isinstance(radiant_team_data, dict): radiant_team = radiant_team_data.get("name", "Radiant") else: radiant_team = "Radiant" if isinstance(dire_team_data, dict): dire_team = dire_team_data.get("name", "Dire") else: dire_team = "Dire" # Format players data player_data = [] players = match.get("players", []) for player in players: account_id = player.get("account_id", "Anonymous") hero_id = player.get("hero_id", "Unknown") hero_name = player.get("hero_name", "Unknown Hero") kills = player.get("kills", 0) deaths = player.get("deaths", 0) assists = player.get("assists", 0) gpm = player.get("gold_per_min", 0) xpm = player.get("xp_per_min", 0) team = "Radiant" if player.get("player_slot", 0) < 128 else "Dire" player_data.append( f"Player ID: {account_id}\n" f"- Team: {team}\n" f"- Hero: {hero_name} (ID: {hero_id})\n" f"- K/D/A: {kills}/{deaths}/{assists}\n" f"- GPM/XPM: {gpm}/{xpm}" ) joined_player_data = "\n\n".join(player_data) formatted_output = ( f"Match ID: {match_id}\n" f"Date: {start_time}\n" f"Duration: {duration_formatted}\n" f"Game Mode: {game_mode}\n" f"Teams: {radiant_team} vs {dire_team}\n" f"Score: {radiant_score} - {dire_score}\n" f"Winner: {winner}\n\n" f"Player Details:\n" f"{'-' * 40}\n" f"{joined_player_data}" ) return formatted_output
  • Core utility function used by get_match_data to perform API requests to OpenDota. Includes rate limiting, caching (5min TTL), retries, and comprehensive error handling.
    async def make_opendota_request( endpoint: str, params: Optional[Dict[str, Any]] = None ) -> Dict[str, Any]: """Make a request to the OpenDota API with proper error handling and caching.""" # Apply rate limiting await apply_rate_limit() url = f"{OPENDOTA_API_BASE}/{endpoint}" request_params = API_PARAMS.copy() if params: request_params.update(params) # Create a cache key manually cache_key = endpoint if request_params: param_str = "&".join(f"{k}={v}" for k, v in sorted(request_params.items())) cache_key = f"{endpoint}?{param_str}" # Check cache cache_entry = api_cache.get(cache_key) if cache_entry: timestamp, data = cache_entry if time.time() - timestamp < CACHE_TTL: logger.debug(f"Cache hit for {cache_key}") return data logger.info(f"Making request to {endpoint} with params {request_params}") async with httpx.AsyncClient() as client: try: response = await client.get( url, params=request_params, headers={"User-Agent": USER_AGENT}, timeout=10.0, ) response.raise_for_status() data = response.json() # Cache the response api_cache[cache_key] = (time.time(), data) return data except httpx.HTTPStatusError as e: if e.response.status_code == 429: logger.error(f"Rate limit exceeded for {endpoint}") return { "error": "Rate limit exceeded. Consider using an API key for more requests." } if e.response.status_code == 404: logger.error(f"Resource not found: {endpoint}") return {"error": "Not found. The requested resource doesn't exist."} if e.response.status_code >= 500: logger.error(f"OpenDota API server error: {e.response.status_code}") return {"error": "OpenDota API server error. Please try again later."} logger.error( f"HTTP error {e.response.status_code} for {endpoint}: {e.response.text}" ) return {"error": f"HTTP error {e.response.status_code}: {e.response.text}"} except Exception as e: logger.error(f"Unexpected error for {endpoint}: {str(e)}") return {"error": f"Unexpected error: {str(e)}"}
  • The @mcp.tool() decorator registers the get_match_data function as an MCP tool in the FastMCP server.
    @mcp.tool()

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/asusevski/opendota-mcp-server'

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