Skip to main content
Glama
rishijatia

Fantasy Premier League MCP Server

get_league_standings

Retrieve current standings and team details for any Fantasy Premier League competition by entering the league 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

  • The main handler function for the 'get_league_standings' tool, decorated with @mcp.tool() and delegating to the core _get_league_standings logic.
    @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)
  • The register_tools function where the get_league_standings tool is registered with the MCP server using @mcp.tool() decorator.
    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)
  • Core helper function implementing the main logic: fetches raw data, parses it, applies limits.
    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
  • Helper function to fetch raw league standings data from the FPL API endpoint with caching (1 hour TTL).
    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)}"
            }
  • Helper function to parse raw API response into structured league info and formatted standings list.
    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
Behavior2/5

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

With no annotations provided, the description carries the full burden of behavioral disclosure. It mentions that the tool 'fetches' data, implying a read-only operation, but doesn't specify details like authentication requirements, rate limits, error handling, or whether it's a safe, non-destructive query. This leaves significant gaps in understanding the tool's behavior beyond basic functionality.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is appropriately concise and front-loaded, with the main purpose stated clearly in the first sentence. The Args and Returns sections are structured but slightly verbose for a single parameter; however, every sentence adds value without unnecessary fluff, making it efficient overall.

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

Completeness3/5

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

Given the tool's low complexity (one parameter, no nested objects) and lack of annotations or output schema, the description is minimally adequate. It covers the basic purpose and parameter semantics but lacks details on behavioral traits, usage context, and return format specifics, leaving room for improvement in completeness.

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 description adds meaningful context for the single parameter 'league_id' by explaining it's the 'ID of the league to fetch', which clarifies its purpose beyond the schema's basic type (integer). Since schema description coverage is 0% and there's only one parameter, this compensates well, though it could benefit from examples or format details.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose with a specific verb ('Get') and resource ('standings for a specified FPL league'), making it immediately understandable. However, it doesn't explicitly differentiate from sibling tools like 'get_league_analytics', which might also provide league-related data, leaving some ambiguity about when to choose one over the other.

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

Usage Guidelines2/5

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

The description provides no guidance on when to use this tool versus alternatives, such as 'get_league_analytics' or other league-related siblings. It simply states what the tool does without context about prerequisites, timing, or comparisons, leaving the agent to infer usage based on the name alone.

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