Skip to main content
Glama
MCP Dota 2 Match Analysis Server

MCP Dota 2 Match Analysis Server

MCP Dota 2 Match Analysis Server

Build Status Documentation Python 3.12

FastMCP server for Dota 2 match analysis using replay files and OpenDota API.

Built-in coaching instructions guide LLMs to provide meaningful analysis - pattern recognition, objective rotations, networth swings linked to teamfights, and actionable coaching advice.

Quick Start

Local

git clone https://github.com/DeepBlueCoding/mcp-replay-dota2.git
cd mcp-replay-dota2
uv sync
uv run python dota_match_mcp_server.py

Docker

docker build -t dota2-mcp-server .
docker run -p 8081:8081 dota2-mcp-server --transport sse
# Connect to http://localhost:8081/sse

Related MCP server: Scalene-MCP

What It Does

  • Resources: Static reference data (heroes, map, pro players/teams)

  • Tools: Match analysis (deaths, combat log, objectives, timelines, drafts)

  • Instructions: Built-in coaching guidance for meaningful LLM responses

See full documentation for API reference and integration guides.

Development

uv run pytest                       # Run tests
uv run pytest -m "not integration"  # Skip slow tests

License

MIT

Available Tools

41 tools
delete_replayA

Delete cached replay file and parsed data for a match.

Use this tool when:

  • A replay appears to be corrupted and needs to be re-downloaded

  • You want to force a fresh download of a replay

  • Cached parsed data seems incorrect or outdated

After deletion, the next analysis request for this match will trigger a fresh download and parse.

Args: match_id: The Dota 2 match ID to delete cached data for

Returns: DeleteReplayResponse with deletion status

Inputs: match_id (required). Returns: Response for delete_replay tool.

download_replayA

Download and cache the replay file for a Dota 2 match.

Use this tool FIRST before asking analysis questions about a match. Replay files are large (50-400MB) and can take 1-5 minutes to download.

Once downloaded, the replay is cached locally and subsequent queries for the same match will be instant.

Progress is reported during download:

  • 0-10%: Checking cache and getting replay URL

  • 10-40%: Downloading compressed file

  • 40-50%: Extracting replay

  • 50-95%: Parsing replay

  • 95-100%: Caching results

Args: match_id: The Dota 2 match ID (from OpenDota, Dotabuff, or in-game)

Returns: DownloadReplayResponse with success status and file info

Inputs: match_id (required). Returns: Response for download_replay tool.

get_camp_stacksC

Get all neutral camp stacks in a Dota 2 match.

Inputs: match_id (required), hero_filter. Returns: Response for get_camp_stacks tool.

get_client_capabilitiesA

Diagnostic tool to check what MCP capabilities the connected client supports.

Returns information about sampling, roots, and other client capabilities.

Inputs: no named parameters. Returns: object

get_courier_killsA

Get all courier kills in a Dota 2 match.

Returns a list of courier kill events with:

  • game_time: Seconds since game start

  • game_time_str: Formatted as M:SS

  • killer: Hero that killed the courier

  • killer_is_hero: Whether the killer was a hero

  • team: Team whose courier was killed (radiant/dire)

Args: match_id: The Dota 2 match ID

Returns: CourierKillsResponse with list of courier kill events

Inputs: match_id (required). Returns: Response for get_courier_kills tool.

get_cs_at_minuteB

Get last hits, denies, gold, and level for all heroes at a specific minute.

Inputs: minute (required), match_id (required). Returns: Response for get_cs_at_minute tool.

get_farming_patternC

Analyze a hero's farming pattern with camp sequences, power spikes, and routes.

Inputs: hero (required), match_id (required), end_minute, start_minute. Returns: Response for get_farming_pattern tool.

get_fightC

Get detailed information about a specific fight.

Inputs: fight_id (required), match_id (required). Returns: Response for get_fight tool.

get_fight_combat_logA

Get detailed event-by-event combat log for a specific fight.

Automatically detects the fight around reference_time and returns the sequence of deaths, abilities, and key moments.

Args: match_id: The Dota 2 match ID reference_time: Game time in seconds (e.g., 1530 for 25:30) hero: Optional hero to anchor fight detection detail_level: "narrative" (default), "tactical", or "full" max_events: Maximum events to return

Inputs: match_id (required), reference_time (required), hero, max_events, +1 more. Returns: Response for get_fight_combat_log tool.

get_fight_replayC

Get high-resolution replay data for a fight.

Inputs: end_time (required), match_id (required), start_time (required), interval_seconds. Returns: Response for get_fight_replay tool.

get_hero_deathsA

Get chronological list of ALL hero deaths in a match.

Returns all deaths with killer, victim, time, location, and ability used. Use for global death timeline, first blood, or death pattern analysis.

Args: match_id: The Dota 2 match ID killer: Filter by killer hero (partial match, e.g. 'jugg') victim: Filter by victim hero (partial match) location: Filter by map location (partial match, e.g. 't1', 'roshan') ability: Filter by killing ability (partial match) start_time: Filter deaths after this game time (seconds) end_time: Filter deaths before this game time (seconds)

Inputs: match_id (required), killer, victim, ability, +3 more. Returns: Response for get_hero_deaths tool.

get_hero_performanceA

Get comprehensive performance data for a hero.

Returns kills, deaths, assists, ability stats (casts, hit rate), and per-fight breakdowns. Use ability_filter for specific ability analysis.

Time filtering: Use start_time/end_time to analyze specific game phases. Common time ranges:

  • Early game: start_time=0, end_time=900 (0-15 min)

  • Mid game: start_time=900, end_time=1800 (15-30 min)

  • Late game: start_time=1800 (30+ min)

Args: match_id: The Dota 2 match ID hero: Hero name (e.g., "jakiro", "mars", "batrider") ability_filter: Filter to specific ability (e.g., "ice_path", "flaming_lasso") start_time: Filter fights starting after this game time (seconds) end_time: Filter fights starting before this game time (seconds)

Inputs: hero (required), match_id (required), end_time, start_time, +1 more. Returns: Response for get_hero_combat_analysis tool.

get_hero_positionsB

Get hero positions at a specific minute in a Dota 2 match.

Inputs: minute (required), match_id (required). Returns: Response for get_hero_positions tool.

get_item_purchasesA

Get item purchase timings for heroes in a Dota 2 match.

Returns a chronological list of item purchases with:

  • game_time: Seconds since game start (can be negative for pre-horn purchases)

  • game_time_str: Formatted as M:SS

  • hero: Hero that purchased the item

  • item: Item name (e.g., "item_bfury", "item_power_treads")

Use this to answer questions like:

  • "When did Juggernaut finish Battlefury?"

  • "What was Anti-Mage's item progression?"

  • "Who bought the first BKB?"

Args: match_id: The Dota 2 match ID hero_filter: Only include purchases by this hero, e.g. "juggernaut" (optional)

Returns: ItemPurchasesResponse with list of item purchase events

Inputs: match_id (required), hero_filter. Returns: Response for get_item_purchases tool.

get_jungle_summaryB

Get jungle activity summary for a Dota 2 match.

Inputs: match_id (required). Returns: Response for get_jungle_summary tool.

get_lane_summaryC

Get laning phase summary for a Dota 2 match.

Inputs: match_id (required). Returns: Response for get_lane_summary tool.

get_league_matchesB

Get matches from a specific league/tournament with series grouping.

Inputs: league_id (required), limit. Returns: Response for get_league_matches tool.

get_leaguesC

Get all Dota 2 leagues/tournaments.

Inputs: tier. Returns: Response for get_leagues tool.

get_match_draftB

Get the complete draft (picks and bans) for a Dota 2 match with drafting context.

Inputs: match_id (required). Returns: Response for get_match_draft tool.

get_match_heroesC

Get the 10 heroes in a Dota 2 match with detailed stats.

Inputs: match_id (required). Returns: Response for get_match_heroes tool.

get_match_infoC

Get match metadata and player information for a Dota 2 match.

Inputs: match_id (required). Returns: Response for get_match_info tool.

get_match_playersB

Get the 10 players in a Dota 2 match with their hero assignments.

Inputs: match_id (required). Returns: Response for get_match_players tool.

get_match_timelineC

Get time-series data for a Dota 2 match.

Inputs: match_id (required). Returns: Response for get_match_timeline tool.

get_objective_killsA

Get all major objective kills in a Dota 2 match.

Returns kills of:

  • Roshan: game_time, killer, team, kill_number (1st, 2nd, 3rd Roshan)

  • Tormentor: game_time, killer, team, side (which Tormentor was killed)

  • Towers: game_time, tower name, team, tier, lane, killer

  • Barracks: game_time, barracks name, team, lane, type (melee/ranged), killer

Use this to analyze:

  • When did each team take Roshan?

  • Tower trade patterns and timing

  • High ground pushes and barracks destruction

  • Tormentor control

Args: match_id: The Dota 2 match ID

Returns: ObjectiveKillsResponse with all objective kill events

Inputs: match_id (required). Returns: Response for get_objective_kills tool.

get_position_timelineA

Get hero positions over a time range at regular intervals.

Inputs: end_time (required), match_id (required), start_time (required), hero_filter, +1 more. Returns: Response for get_position_timeline tool.

get_pro_matchesA

Get recent professional Dota 2 matches as a flat list.

Returns individual matches without series grouping. Use get_tournament_series for bracket/series analysis.

Args: limit: Maximum matches to return (default 50) tier: Filter by league tier (premium, professional, amateur) team1_name: Filter by first team (fuzzy match). Alone: all matches for team. team2_name: Filter by second team (fuzzy match). With team1: head-to-head matches. league_name: Filter by league/tournament name (contains, case-insensitive) days_back: Only return matches from last N days

Inputs: tier, limit, days_back, team1_name, +2 more. Returns: Response for get_pro_matches tool - flat list of matches.

get_pro_playerC

Get detailed information about a professional player by account ID.

Inputs: account_id (required). Returns: Response for get_pro_player tool.

get_pro_player_by_nameC

Get detailed information about a professional player by name.

Inputs: name (required). Returns: Response for get_pro_player tool.

get_raw_combat_eventsA

Get raw combat events for a specific time window.

Use for analyzing non-fight moments (e.g., Roshan attempts, specific plays). detail_level: "narrative" (deaths/abilities), "tactical" (+damage), "full" (all).

Args: match_id: The Dota 2 match ID start_time: Start of time window in seconds end_time: End of time window in seconds hero_filter: Filter to specific hero ability_filter: Filter to specific ability detail_level: "narrative", "tactical", or "full" max_events: Maximum events to return

Inputs: match_id (required), end_time, max_events, start_time, +3 more. Returns: Response for get_combat_log tool.

get_rotation_analysisB

Analyze hero rotations - movement patterns between lanes and outcomes.

Returns rotation events, gank attempts, and their success rates.

Inputs: match_id (required), end_minute, start_minute. Returns: Response for get_rotation_analysis tool.

get_rune_pickupsA

Get power rune pickups in a Dota 2 match.

Returns a list of power rune pickup events with:

  • game_time: Seconds since game start

  • game_time_str: Formatted as M:SS

  • hero: Hero that picked up the rune

  • rune_type: Type of rune (haste, double_damage, arcane, invisibility, regeneration, shield)

Note: Only power runes are trackable. Bounty, wisdom, and water runes don't leave detectable events in the replay data.

Use this to answer questions like:

  • "Who got the most power runes?"

  • "What runes did the mid player secure?"

  • "When did they get a DD rune before fighting?"

Args: match_id: The Dota 2 match ID

Returns: RunePickupsResponse with list of power rune pickup events

Inputs: match_id (required). Returns: Response for get_rune_pickups tool.

get_snapshot_at_timeC

Get game state snapshot at a specific game time.

Inputs: match_id (required), game_time (required). Returns: Response for get_snapshot_at_time tool.

get_stats_at_minuteB

Get player stats at a specific minute in a Dota 2 match.

Inputs: minute (required), match_id (required). Returns: Response for get_stats_at_minute tool.

get_teamA

Get detailed information about a team by ID.

Inputs: team_id (required). Returns: Response for get_team tool.

get_team_by_nameC

Get detailed information about a team by name.

Inputs: name (required). Returns: Response for get_team tool.

get_teamfightsA

Get major teamfights (3+ deaths) with coaching analysis.

Returns teamfight timing, participants, death sequences, and analysis.

Args: match_id: The Dota 2 match ID min_deaths: Minimum deaths to classify as teamfight (default 3) location: Filter by map location (partial match, e.g. 't1', 'roshan_pit') start_time: Filter teamfights starting after this game time (seconds) end_time: Filter teamfights starting before this game time (seconds)

Inputs: match_id (required), end_time, location, min_deaths, +1 more. Returns: Response for get_teamfights tool.

get_team_matchesC

Get recent matches for a team.

Inputs: team_id (required), limit. Returns: Response for get_team_matches tool.

get_tournament_seriesA

Get tournament series with bracket/game details.

Use this for tournament progression analysis: series results, Bo3/Bo5 outcomes, team advancement through brackets.

Args: league_name: Filter by league/tournament name (fuzzy match) league_id: Filter by specific league ID team_name: Filter series involving this team limit: Maximum series to return (default 20) days_back: Only series from last N days

Inputs: limit, days_back, league_id, team_name, +1 more. Returns: Response for get_tournament_series tool - series with nested games.

list_fightsA

List all fights/skirmishes in a match with death summaries.

Returns fight count, timing, participants, and deaths for each fight.

Args: match_id: The Dota 2 match ID location: Filter by map location (partial match, e.g. 't1', 'roshan_pit') min_deaths: Filter to fights with at least this many deaths is_teamfight: Filter to teamfights only (True) or skirmishes only (False) start_time: Filter fights starting after this game time (seconds) end_time: Filter fights starting before this game time (seconds)

Inputs: match_id (required), end_time, location, min_deaths, +2 more. Returns: Response for list_fights tool.

search_pro_playerB

Search for professional Dota 2 players by name or alias.

Inputs: query (required), max_results. Returns: Response for player search tool.

search_teamA

Search for professional Dota 2 teams by name, tag, or alias.

Inputs: query (required), max_results. Returns: Response for team search tool.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3/5.0

    Scored across 41 tools

    Disambiguation2/5

    Several tools have overlapping boundaries: get_fight, get_fight_combat_log, get_fight_replay, list_fights, and get_teamfights all cover fight analysis, and get_fight/get_fight_replay lack clear arguments to distinguish them. Similarly, search_pro_player vs get_pro_player_by_name and search_team vs get_team_by_name create predictable confusion.

    Naming Consistency4/5

    The majority of tools follow a clear snake_case verb_noun pattern (get_*, list_*, search_*, delete_*, download_*), making the set generally predictable. Minor inconsistencies like get_teamfights vs get_team_fights, search_pro_player vs get_team_by_name, and get_pro_matches vs get_league_matches keep it from a perfect score.

    Tool Count2/5

    41 tools is a heavy surface for an agent to reason over, especially since the server bundles replay-level match analysis with professional scene lookup. While each tool targets real Dota functionality, the count creates significant selection overhead and would benefit from being split into separate server concerns.

    Completeness4/5

    The server covers the major match-analysis workflows: replay download, fights, deaths, item/runes, objectives, farming, lane summaries, timelines, drafts, and professional scene data. Minor gaps exist (e.g., no ward/vision analysis, no player match-history lookup, no team roster tool), but agents can generally work around them.

    Maintenance

    ActivityInactive
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers

    • F
      license
      A
      quality
      D
      maintenance
      A FastMCP server that provides LLMs with structured access to Scalene's CPU, GPU, and memory profiling for Python applications. It enables automated performance analysis, bottleneck identification, and optimization suggestions through natural language interactions in supported IDEs.
      7
      1
      -
    • A
      license
      A
      quality
      D
      maintenance
      MCP server for log file analysis. Gives LLMs the ability to efficiently analyze large log files without loading them into context.
      7
      101
      MIT