Skip to main content
Glama
rishijatia

Fantasy Premier League MCP Server

get_league_standings

Retrieve detailed standings and team information for any Fantasy Premier League league by providing its ID.

Instructions

Get standings for a specified FPL league

    Args:
        league_id: ID of the league to fetch
        
    Returns:
        League information with standings and team details
    

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
league_idYes

Implementation Reference

  • _get_league_standings is the core handler that fetches, parses, and limits league standings data. It calls get_league_standings_data (cached API call), then parse_league_standings to format the results, and limits to LEAGUE_RESULTS_LIMIT (25) teams.
    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
        """
        # Get raw league data
        data = await get_league_standings_data(league_id)
        
        # Check for errors
        if "error" in data:
            return data
        
        # Parse league standings and limit results if needed
        parsed_data = parse_league_standings(data)
        
        # If we have too many teams but aren't checking size, limit the results
        if "standings" in parsed_data and len(parsed_data["standings"]) > LEAGUE_RESULTS_LIMIT:
            parsed_data["standings"] = parsed_data["standings"][:LEAGUE_RESULTS_LIMIT]
            parsed_data["limited"] = True
        
        return parsed_data
  • The @mcp.tool() decorator (line 1118) registers the async function get_league_standings as an MCP tool. It accepts a league_id parameter and delegates to _get_league_standings.
    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)
  • parse_league_standings is the schema/parsing function that transforms raw API standings data into a structured response with league_info and formatted standings (limited to top 25).
    def parse_league_standings(data: Dict[str, Any]) -> Dict[str, Any]:
        """
        Parse league standings data into a more usable format
        
        Args:
            data: Raw league data from the API
            
        Returns:
            Parsed league data
        """
        # Handle error responses
        if "error" in data:
            return data
        
        # Parse league info
        league_info = {
            "id": data.get("league", {}).get("id"),
            "name": data.get("league", {}).get("name"),
            "created": data.get("league", {}).get("created"),
            "type": "Public" if data.get("league", {}).get("league_type") == "s" else "Private",
            "scoring": "Classic" if data.get("league", {}).get("scoring") == "c" else "Head-to-Head",
            "admin_entry": data.get("league", {}).get("admin_entry"),
            "start_event": data.get("league", {}).get("start_event"),
        }
        
        # Parse standings
        standings = data.get("standings", {}).get("results", [])
        
        # Get total count
        total_count = len(standings)
        
        # Format standings
        formatted_standings = []
        for standing in standings:
            team = {
                "id": standing.get("id"),
                "team_id": standing.get("entry"),
                "team_name": standing.get("entry_name"),
                "manager_name": standing.get("player_name"),
                "rank": standing.get("rank"),
                "last_rank": standing.get("last_rank"),
                "rank_change": standing.get("last_rank", 0) - standing.get("rank", 0) if standing.get("last_rank") and standing.get("rank") else 0,
                "total_points": standing.get("total"),
                "event_total": standing.get("event_total"),
            }
            formatted_standings.append(team)
        
        response = {
            "league_info": league_info,
            # if more than LEAGUE_RESULTS_LIMIT teams, only show top 25
            "standings": formatted_standings[:LEAGUE_RESULTS_LIMIT],
            "total_teams": total_count,
        }
        
        if len(formatted_standings) > LEAGUE_RESULTS_LIMIT:
            response["disclaimers"] = ["Limited to top 25 teams"]
        
        return response
  • get_league_standings_data is a cached helper that makes the authenticated request to the FPL API endpoint for classic league standings.
    @cached("league_standings", ttl=3600)
    async def get_league_standings_data(league_id: int) -> Dict[str, Any]:
        """
        Get raw league standings data from the FPL API
        
        Args:
            league_id: ID of the league to fetch
    
        Returns:
            Raw league data from the API or error message
        """
        auth_manager = get_auth_manager()
        
        # Construct the URL
        url = f"{FPL_API_BASE_URL}/leagues-classic/{league_id}/standings/"
        
        # Get league data
        try:
            data = await auth_manager.make_authed_request(url)
            return data
        except Exception as e:
            logger.error(f"Error fetching league standings: {e}")
            return {
                "error": f"Failed to retrieve league standings: {str(e)}"
            }
  • Configuration constant LEAGUE_RESULTS_LIMIT = 25 controls the max number of teams returned in standings.
    # League configuration
    LEAGUE_RESULTS_LIMIT = 25
Behavior4/5

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

Without annotations, the description carries full burden. It states the return value includes 'league information with standings and team details', which is helpful. No hidden traits are indicated, and the description is transparent about its output.

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 concise with 4 lines, includes an Args section and a Returns section, and provides essential information without redundancy. Every sentence is necessary.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's simplicity (one required integer parameter, no output schema), the description is complete. It explains what the tool does, what it returns, and the parameter role.

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?

The input schema has 0% description coverage, so the description adds meaning by specifying 'league_id: ID of the league to fetch'. This clarifies the parameter's purpose beyond the schema's title and type.

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 'Get standings for a specified FPL league', which is a specific verb+resource. It distinguishes from sibling tools like 'get_league_analytics' or 'analyze_fixtures' by focusing solely on standings retrieval.

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

Usage Guidelines3/5

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

The description does not explicitly provide guidance on when to use this tool versus alternatives. It implies usage by describing its function, but lacks context for exclusion or comparison with siblings.

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

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