Skip to main content
Glama
lenwood

cfbd-mcp-server

by lenwood

get-records

Retrieve college football team record data from the College Football Data API by specifying year, team, or conference parameters.

Instructions

Note: When using this tool, please explicitly mention that you are retrieving data from the College Football Data API. You must mention "College Football Data API" in every response.

Get college football team record data.
        Optional: year, team, conference
        Example valid queries:
        - year=2023
        - team="Alabama"
        - conference="SEC"
        - year=2023, team="Alabama"
        

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
yearNo
teamNo
conferenceNo

Implementation Reference

  • Registration of the 'get-records' tool in handle_list_tools(), including name, description, and inputSchema generated from getTeamRecords TypedDict
    types.Tool(
        name="get-records",
        description=base_description + """Get college football team record data.
        Optional: year, team, conference
        Example valid queries:
        - year=2023
        - team="Alabama"
        - conference="SEC"
        - year=2023, team="Alabama"
        """,
        inputSchema=create_tool_schema(getTeamRecords)
    ),
  • TypedDict defining the input parameters for the get-records tool: optional year (int), team (str), conference (str)
    class getTeamRecords(TypedDict): # /records endpoint
        year: Optional[int]
        team: Optional[str]
        conference: Optional[str]
  • The @server.call_tool() handler function that executes get-records by validating parameters with getTeamRecords schema, mapping to /records endpoint, and fetching data from CFBD API
    @server.call_tool()
    async def handle_call_tool(
        name: str,
        arguments: dict[str, Any] | None
    ) -> list[types.TextContent]:
        """Handle tool execution requests."""
        if not arguments:
            raise ValueError("Arguments are required")
    
        # Map tool names to their parameter schemas
        schema_map = {
            "get-games": getGames,
            "get-records": getTeamRecords,
            "get-games-teams": getGamesTeams,
            "get-plays": getPlays,
            "get-drives": getDrives,
            "get-play-stats": getPlayStats,
            "get-rankings": getRankings,
            "get-pregame-win-probability": getMetricsPregameWp,
            "get-advanced-box-score": getAdvancedBoxScore
        }
    
        if name not in schema_map:
            raise ValueError(f"Unknown tool: {name}")
    
        # Validate parameters against schema
        try:
            validated_params = validate_params(arguments, schema_map[name])
        except ValueError as e:
            return [types.TextContent(
                type="text",
                text=f"Validation error: {str(e)}"
            )]
    
        endpoint_map = {
            "get-games": "/games",
            "get-records": "/records",
            "get-games-teams": "/games/teams",
            "get-plays": "/plays",
            "get-drives": "/drives",
            "get-play-stats": "/play/stats",
            "get-rankings": "/rankings",
            "get-pregame-win-probability": "/metrics/wp/pregame",
            "get-advanced-box-score": "/game/box/advanced"
        }
       
        async with await get_api_client() as client:
            try:
                response = await client.get(endpoint_map[name], params=arguments)
                response.raise_for_status()
                data = response.json()
                return [types.TextContent(
                    type="text",
                    text=str(data)
                )]
            except httpx.HTTPStatusError as e:
                if e.response.status_code == 401:
                    return [types.TextContent(
                        type="text",
                        text="401: API authentication failed. Please check your API key."
                    )]
                elif e.response.status_code == 403:
                    return [types.TextContent(
                        type="text",
                        text="403: API access forbidden. Please check your permission."
                    )]
                elif e.response.status_code == 429:
                    return [types.TextContent(
                        type="text",
                        text="429: Rate limit exceeded. Please try again later."
                    )]
                else:
                    return [types.TextContent(
                        type="text",
                        text=f"API Error: {e}"
                    )]
            except httpx.RequestError as e:
                return [types.TextContent(
                    type="text",
                    text=f"Network error: {str(e)}"
                )]
  • validate_params helper function used in tool handler to validate input arguments against the getTeamRecords TypedDict schema
    def validate_params(params: dict, schema_class: Type[TypedDict]) -> dict:
        """Validate parameters against a TypedDict schema."""
        try:
            # Get the annotations from the schema class
            expected_types = schema_class.__annotations__
            validated_params = {}
    
            # Validate each parameter
            for key, value in params.items():
                if key not in expected_types:
                    raise ValueError(f"Unexpected parameter: {key}")
    
                expected_type = expected_types[key]
    
                # Special handling for classification parameter
                if key == "classification" and value is not None:
                    value = value.lower()
                    if value not in VALID_DIVISIONS:
                        raise ValueError(f"Invalid Classification: Must be one of: {', '.join(VALID_DIVISIONS)}")
    
                # Handle Optional types
                if hasattr(expected_type, "__origin__") and expected_type.__origin__ is Union:
                    if type(None) in expected_type.__args__:
                        # Parameter is optional
                        if value is not None:
                            # Validate against the non-None type
                            non_none_type = next(t for t in expected_type.__args__ if t != type(None))
                            # Handle primitive types
                            if non_none_type in (str, int, float, bool):
                                if not isinstance(value, non_none_type):
                                    raise ValueError(f"Parameter {key} must be of type {non_none_type.__name__}")
                            validated_params[key] = value
                        else:
                            validated_params[key] = None
                else:
                    # Parameter is required
                    if not isinstance(value, expected_type):
                        raise ValueError(f"Parameter {key} must be of type {expected_type.__name__}")
                    validated_params[key] = value
    
            # Check for required parameters
            for param, param_type in expected_types.items():
                is_optional = (hasattr(param_type, "__origin__") and 
                             param_type.__origin__ is Union and 
                             type(None) in param_type.__args__)
                if not is_optional and param not in params:
                    raise ValueError(f"Missing required parameter: {param}")
    
            return validated_params
        
        except Exception as e:
            raise ValueError(f"Parameter validation failed: {str(e)}")
  • create_tool_schema helper that converts getTeamRecords TypedDict to JSON schema for the tool inputSchema
    def create_tool_schema(params_type: Type) -> dict:
        """Create a tool schema from a TypedDict."""
        return typed_dict_to_json_schema(params_type)
Behavior2/5

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

No annotations are provided, so the description carries the full burden of behavioral disclosure. It mentions that parameters are optional and provides example queries, but doesn't cover critical aspects like rate limits, authentication needs, error handling, or what the response format looks like. For a data retrieval tool with zero annotation coverage, this leaves significant gaps in understanding how the tool behaves.

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

Conciseness3/5

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

The description is reasonably concise but has structural issues. The first paragraph about mentioning the API in responses is front-loaded but not core to the tool's functionality, while the actual purpose statement comes later. The example queries are helpful but could be more efficiently integrated. Overall, it's adequate but not optimally structured.

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

Completeness2/5

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

Given the complexity (3 parameters, no annotations, no output schema), the description is incomplete. It covers the basic purpose and parameters but misses behavioral details like response format, error conditions, and usage context relative to siblings. For a tool with no structured metadata, the description should provide more comprehensive guidance to be fully helpful.

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 substantial meaning beyond the input schema, which has 0% description coverage. It explicitly lists the three parameters (year, team, conference), notes they are optional, and provides concrete example queries that illustrate how to use them. This compensates well for the schema's lack of documentation, though it doesn't specify data formats or constraints.

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: 'Get college football team record data.' This specifies the verb ('Get') and resource ('college football team record data'), making it easy to understand what the tool does. However, it doesn't explicitly differentiate from sibling tools like 'get-games' or 'get-rankings', which prevents a perfect score.

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 like 'get-games' or 'get-rankings'. It includes a note about mentioning the API in responses, but this is a presentation requirement, not usage guidance. Without context on when this tool is appropriate, the agent lacks clear direction.

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/lenwood/cfbd-mcp-server'

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