Skip to main content
Glama
rishijatia

Fantasy Premier League MCP Server

get_league_analytics

Analyze Fantasy Premier League mini-leagues to visualize performance trends, team compositions, and decision patterns for strategic insights.

Instructions

Get rich analytics for a Fantasy Premier League mini-league

Returns visualization-optimized data for various types of league analysis. Args: league_id: ID of the league to analyze analysis_type: Type of analysis to perform: - "overview": General league overview (default) - "historical": Historical performance analysis - "team_composition": Team composition analysis - "decisions": Captain and transfer decision analysis - "fixtures": Fixture difficulty comparison start_gw: Starting gameweek (defaults to 1 or use "current-N" format) end_gw: Ending gameweek (defaults to current) Returns: Rich analytics data structured for visualization

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
league_idYes
analysis_typeNooverview
start_gwNo
end_gwNo

Implementation Reference

  • Main tool handler function 'get_league_analytics' decorated with @mcp.tool(). Includes type annotations serving as input schema and comprehensive docstring describing parameters and analysis types. Delegates to core implementation.
    async def get_league_analytics( league_id: int, analysis_type: str = "overview", start_gw: Optional[int] = None, end_gw: Optional[int] = None ) -> Dict[str, Any]: """Get rich analytics for a Fantasy Premier League mini-league Returns visualization-optimized data for various types of league analysis. Args: league_id: ID of the league to analyze analysis_type: Type of analysis to perform: - "overview": General league overview (default) - "historical": Historical performance analysis - "team_composition": Team composition analysis - "decisions": Captain and transfer decision analysis - "fixtures": Fixture difficulty comparison start_gw: Starting gameweek (defaults to 1 or use "current-N" format) end_gw: Ending gameweek (defaults to current) Returns: Rich analytics data structured for visualization """ return await _get_league_analytics(league_id, analysis_type, start_gw, end_gw)
  • Core helper function '_get_league_analytics' containing the primary execution logic: input validation, gameweek processing, league data fetching, and routing to specialized analysis based on analysis_type.
    async def _get_league_analytics( league_id: int, analysis_type: str = "overview", start_gw: Optional[int] = None, end_gw: Optional[int] = None ) -> Dict[str, Any]: """ Get rich analytics for a Fantasy Premier League mini-league Returns visualization-optimized data for various types of league analysis. Args: league_id: ID of the league to analyze analysis_type: Type of analysis to perform: - "overview": General league overview (default) - "historical": Historical performance analysis - "team_composition": Team composition analysis - "decisions": Captain and transfer decision analysis - "fixtures": Fixture difficulty comparison start_gw: Starting gameweek (defaults to 1) end_gw: Ending gameweek (defaults to current) Returns: Rich analytics data structured for visualization """ # Add logging for debugging logger.info(f"Starting league analytics: {analysis_type} for league {league_id}") # Validate analysis type valid_types = ["overview", "historical", "team_composition", "decisions", "fixtures"] if analysis_type not in valid_types: return { "error": f"Invalid analysis type: {analysis_type}", "valid_types": valid_types } # Get current gameweek try: current_gw_data = await api.get_current_gameweek() current_gw = current_gw_data.get("id", 1) logger.info(f"Current gameweek: {current_gw}") except Exception as e: logger.error(f"Error getting current gameweek: {e}") current_gw = 1 # Use the configured limit for all analysis types logger.info(f"Using configured limit of {LEAGUE_RESULTS_LIMIT} teams for {analysis_type} analysis") # Process gameweek range to ensure it's not too large effective_start_gw = start_gw effective_end_gw = end_gw # Handle start gameweek - using a consistent default (last 5 gameweeks) for all analysis types DEFAULT_GW_LOOKBACK = 5 if effective_start_gw is None: effective_start_gw = max(1, current_gw - DEFAULT_GW_LOOKBACK + 1) logger.info(f"Using default start gameweek: {effective_start_gw}") elif isinstance(effective_start_gw, str) and effective_start_gw.startswith("current-"): try: offset = int(effective_start_gw.split("-")[1]) effective_start_gw = max(1, current_gw - offset) logger.info(f"Parsed relative start gameweek: {effective_start_gw}") except ValueError: effective_start_gw = max(1, current_gw - DEFAULT_GW_LOOKBACK + 1) logger.info(f"Invalid relative start gameweek, using default: {effective_start_gw}") # Handle end gameweek if effective_end_gw is None or effective_end_gw == "current": effective_end_gw = current_gw logger.info(f"Using current end gameweek: {effective_end_gw}") elif isinstance(effective_end_gw, str) and effective_end_gw.startswith("current-"): try: offset = int(effective_end_gw.split("-")[1]) effective_end_gw = max(1, current_gw - offset) logger.info(f"Parsed relative end gameweek: {effective_end_gw}") except ValueError: effective_end_gw = current_gw logger.info(f"Invalid relative end gameweek, using current: {effective_end_gw}") # Convert to integers if necessary try: effective_start_gw = int(effective_start_gw) effective_end_gw = int(effective_end_gw) except (ValueError, TypeError): logger.error(f"Invalid gameweek values: start={effective_start_gw}, end={effective_end_gw}") return {"error": "Invalid gameweek values"} # Ensure the range is valid and not too large if effective_start_gw < 1: effective_start_gw = 1 if effective_end_gw > current_gw: effective_end_gw = current_gw if effective_start_gw > effective_end_gw: effective_start_gw, effective_end_gw = effective_end_gw, effective_start_gw # Apply consistent gameweek range limit to prevent performance issues gw_range = effective_end_gw - effective_start_gw + 1 # MAX_GW_RANGE = 5 # Use a consistent max range for all analysis types # if gw_range > MAX_GW_RANGE: # logger.info(f"Reducing gameweek range from {gw_range} to {MAX_GW_RANGE}") # effective_start_gw = max(1, effective_end_gw - MAX_GW_RANGE + 1) # logger.info(f"Final gameweek range: {effective_start_gw} to {effective_end_gw}") # Get league standings first logger.info(f"Fetching league standings for league {league_id}") try: # Don't check size limit, just fetch all and filter league_data = await _get_league_standings(league_id) # Check for errors if "error" in league_data: logger.error(f"Error getting league standings: {league_data['error']}") return league_data logger.info(f"Successfully fetched standings for {len(league_data['standings'])} teams") except Exception as e: logger.error(f"Exception getting league standings: {e}") return {"error": f"Failed to get league standings: {str(e)}"} # Route to the appropriate analysis function (with timeout protection) try: if analysis_type == "overview" or analysis_type == "historical": # For overview analysis, use the regular function but with reduced range return await _get_league_historical_performance( league_id, effective_start_gw, effective_end_gw ) elif analysis_type == "team_composition": # For team composition, use specified gameweek # Previously this only used end_gw, but we'll now pass both for consistency return await _get_league_team_composition( league_id, effective_end_gw ) elif analysis_type == "decisions": # For decisions, use our new simplified analysis function return await get_simplified_league_decision_analysis( league_id, effective_start_gw, effective_end_gw, _get_league_standings, get_teams_historical_data, league_data=league_data # Pass league data to avoid fetching again ) elif analysis_type == "fixtures": # Call the league fixture analysis function return await _get_league_fixture_analysis( league_id, effective_start_gw, effective_end_gw ) except Exception as e: logger.error(f"Error in league analytics: {e}") return { "error": f"Analysis failed: {str(e)}", "league_info": league_data["league_info"], "standings": league_data["standings"], "status": "error" } # This shouldn't happen due to earlier validation return {"error": "Unknown analysis type"}
  • Module-level registration function 'register_tools(mcp)' that defines and registers the 'get_league_analytics' tool (and get_league_standings) using the @mcp.tool() decorator. This function is imported and called from tools/__init__.py.
    def register_tools(mcp): """Register league analytics tools with the MCP server""" @mcp.tool() async def get_league_standings(league_id: int) -> Dict[str, Any]: """Get standings for a specified FPL league Args: league_id: ID of the league to fetch Returns: League information with standings and team details """ # When directly using the tool, enforce size check return await _get_league_standings(league_id) @mcp.tool() async def get_league_analytics( league_id: int, analysis_type: str = "overview", start_gw: Optional[int] = None, end_gw: Optional[int] = None ) -> Dict[str, Any]: """Get rich analytics for a Fantasy Premier League mini-league Returns visualization-optimized data for various types of league analysis. Args: league_id: ID of the league to analyze analysis_type: Type of analysis to perform: - "overview": General league overview (default) - "historical": Historical performance analysis - "team_composition": Team composition analysis - "decisions": Captain and transfer decision analysis - "fixtures": Fixture difficulty comparison start_gw: Starting gameweek (defaults to 1 or use "current-N" format) end_gw: Ending gameweek (defaults to current) Returns: Rich analytics data structured for visualization """ return await _get_league_analytics(league_id, analysis_type, start_gw, end_gw)

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/rishijatia/fantasy-pl-mcp'

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