analyze_player_fixtures
Analyze upcoming fixtures for Fantasy Premier League players to assess difficulty ratings and optimize team selection decisions.
Instructions
Analyze upcoming fixtures for a player and provide a difficulty rating
Args:
player_name: Player name to search for
num_fixtures: Number of upcoming fixtures to analyze (default: 5)
Returns:
Analysis of player's upcoming fixtures with difficulty ratings
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| player_name | Yes | ||
| num_fixtures | No |
Implementation Reference
- src/fpl_mcp/__main__.py:242-282 (registration)Registration of the MCP tool 'analyze_player_fixtures'. This wrapper function handles player lookup by name and delegates to the core implementation.@mcp.tool() async def analyze_player_fixtures(player_name: str, num_fixtures: int = 5) -> Dict[str, Any]: """Analyze upcoming fixtures for a player and provide a difficulty rating Args: player_name: Player name to search for num_fixtures: Number of upcoming fixtures to analyze (default: 5) Returns: Analysis of player's upcoming fixtures with difficulty ratings """ logger.info(f"Tool called: analyze_player_fixtures({player_name}, {num_fixtures})") # Handle case when a dictionary is passed instead of string (error case) if isinstance(player_name, dict): if 'player_name' in player_name: player_name = player_name['player_name'] elif 'query' in player_name: player_name = player_name['query'] else: # If we can't find a usable key, convert the dict to a string player_name = str(player_name) # Handle case when num_fixtures is a dict if isinstance(num_fixtures, dict): if 'num_fixtures' in num_fixtures: num_fixtures = num_fixtures['num_fixtures'] else: # Default to 5 if we can't find a usable value num_fixtures = 5 # Find the player player_matches = await players.find_players_by_name(player_name) if not player_matches: return {"error": f"No player found matching '{player_name}'"} player = player_matches[0] analysis = await fixtures.analyze_player_fixtures(player["id"], num_fixtures) return analysis
- Core handler function that executes the tool logic: fetches player/team/position data, gets upcoming fixtures, calculates adjusted difficulty score (1-10, higher better), provides textual analysis.async def analyze_player_fixtures(player_id: int, num_fixtures: int = 5) -> Dict[str, Any]: """Analyze upcoming fixtures for a player and provide a difficulty rating Args: player_id: FPL ID of the player num_fixtures: Number of upcoming fixtures to analyze Returns: Analysis of player's upcoming fixtures with difficulty ratings """ logger.info(f"Analyzing player fixtures (player_id={player_id}, num_fixtures={num_fixtures})") # Get player data players_data = await api.get_players() player = None for p in players_data: if p.get("id") == player_id: player = p break if not player: logger.warning(f"Player with ID {player_id} not found") return {"error": f"Player with ID {player_id} not found"} # Get team and position data for the player teams_data = await api.get_teams() team_map = {t["id"]: t for t in teams_data} logger.info("Analyze Player Fixtures: Team data loaded: %s", team_map) position_data = await api.get_bootstrap_static() position_map = {p["id"]: p for p in position_data.get("element_types", [])} logger.info("Analyze Player Fixtures: Position data loaded: %s", position_map) # Map team name logger.info("Searching for team name %s and position %s", player.get("team"), player.get("element_type")) team_id = player.get("team") team_info = team_map.get(team_id, {}) team_name = team_info.get("name", "Unknown team") # Map position name position_id = player.get("element_type") position_info = position_map.get(position_id, {}) position_code = position_info.get("singular_name_short", "Unknown position") logger.info("Player %s plays as %s for %s", player.get("web_name"), position_code, team_name) # Make sure position is one of GK, DEF, MID, FWD position_mapping = { "GKP": "GK", "DEF": "DEF", "MID": "MID", "FWD": "FWD" } position = position_mapping.get(position_code, position_code) # Get player's fixtures fixtures = await get_player_fixtures(player_id, num_fixtures) if not fixtures: return { "player": { "id": player_id, "name": player.get("web_name", "Unknown player"), "team": team_name, "position": position, }, "fixture_analysis": { "fixtures_analyzed": [], "difficulty_score": 0, "analysis": "No upcoming fixtures found" } } # Calculate difficulty score (lower is better) total_difficulty = sum(f["difficulty"] for f in fixtures) avg_difficulty = total_difficulty / len(fixtures) # Adjust for home/away balance (home advantage) home_fixtures = [f for f in fixtures if f["location"] == "home"] home_percentage = len(home_fixtures) / len(fixtures) * 100 # Scale to 1-10 (invert so higher is better) # Difficulty is originally 1-5, where 5 is most difficult # We want 1-10 where 10 is best fixtures fixture_score = (6 - avg_difficulty) * 2 # Adjust for home advantage (up to +0.5 for all home, -0.5 for all away) home_adjustment = (home_percentage - 50) / 100 adjusted_score = fixture_score + home_adjustment # Cap between 1-10 final_score = max(1, min(10, adjusted_score)) # Generate text analysis if final_score >= 8.5: analysis = "Excellent fixtures - highly favorable schedule" elif final_score >= 7: analysis = "Good fixtures - favorable schedule" elif final_score >= 5.5: analysis = "Average fixtures - balanced schedule" elif final_score >= 4: analysis = "Difficult fixtures - challenging schedule" else: analysis = "Very difficult fixtures - extremely challenging schedule" # Return formatted analysis return { "player": { "id": player_id, "name": player.get("web_name", "Unknown player"), "team": team_name, "position": position_code, }, "fixture_analysis": { "fixtures_analyzed": fixtures, "difficulty_score": round(final_score, 1), "analysis": analysis, "home_fixtures_percentage": round(home_percentage, 1) } }
- Key helper function called by the handler to retrieve and format the player's upcoming fixtures.async def get_player_fixtures(player_id: int, num_fixtures: int = 5) -> List[Dict[str, Any]]: """Get upcoming fixtures for a specific player Args: player_id: FPL ID of the player num_fixtures: Number of upcoming fixtures to return Returns: List of upcoming fixtures for the player """ logger.info(f"Getting player fixtures (player_id={player_id}, num_fixtures={num_fixtures})") # Get player data to find their team players_data = await api.get_players() player = None for p in players_data: if p.get("id") == player_id: player = p break if not player: logger.warning(f"Player with ID {player_id} not found") return [] team_id = player.get("team") if not team_id: logger.warning(f"Team ID not found for player {player_id}") return [] # Get all fixtures all_fixtures = await api.get_fixtures() if not all_fixtures: logger.warning("No fixtures data found") return [] # Get gameweeks to determine current gameweek gameweeks = await api.get_gameweeks() current_gameweek = None for gw in gameweeks: if gw.get("is_current"): current_gameweek = gw.get("id") break if not current_gameweek: for gw in gameweeks: if gw.get("is_next"): current_gameweek = gw.get("id") - 1 break if not current_gameweek: logger.warning("Could not determine current gameweek") return [] # Filter upcoming fixtures for player's team upcoming_fixtures = [] for fixture in all_fixtures: # Only include fixtures from current gameweek onwards if fixture.get("event") and fixture.get("event") >= current_gameweek: # Check if player's team is involved if fixture.get("team_h") == team_id or fixture.get("team_a") == team_id: upcoming_fixtures.append(fixture) # Sort by gameweek upcoming_fixtures.sort(key=lambda x: x.get("event", 0)) # Limit to requested number of fixtures upcoming_fixtures = upcoming_fixtures[:num_fixtures] # Get teams data for mapping IDs to names teams_data = await api.get_teams() team_map = {t["id"]: t for t in teams_data} # Format fixtures formatted_fixtures = [] for fixture in upcoming_fixtures: home_id = fixture.get("team_h", 0) away_id = fixture.get("team_a", 0) # Determine if player's team is home or away is_home = home_id == team_id # Get opponent team data opponent_id = away_id if is_home else home_id opponent_team = team_map.get(opponent_id, {}) # Determine difficulty - higher is more difficult difficulty = fixture.get("team_h_difficulty" if is_home else "team_a_difficulty", 3) formatted_fixture = { "gameweek": fixture.get("event"), "kickoff_time": fixture.get("kickoff_time", ""), "location": "home" if is_home else "away", "opponent": opponent_team.get("name", f"Team {opponent_id}"), "opponent_short": opponent_team.get("short_name", ""), "difficulty": difficulty, } formatted_fixtures.append(formatted_fixture) return formatted_fixtures