Six tools registered with consistent naming (verb_noun pattern: get_*), but quality is uneven. Tool descriptions are present but generic and lack actionable detail for LLM selection. Input schemas are properly typed JSON Schema with descriptions, but parameters lack validation guidance (min/max, enum constraints, format details). No output schemas documented. Error handling is minimal, failures return generic text without recovery guidance. Tools are READ_ONLY and simple, reducing composition risk, but descriptions fail to explain WHEN to use each tool vs. similar alternatives (e.g., get_standings vs get_current_standings). No tool annotations (readonly hints) despite all being read-only. Average tool score: 52/100.
Ambiguous tool naming: get-standings and get-current-standings overlap in purpose. LLMs cannot distinguish when to use each. Descriptions do not explain the difference (current = live data vs. historical? filtered vs. unfiltered?).
Descriptions are generic and lack actionable guidance. 'Get current NHL standings' tells the LLM WHAT but not WHEN or WHY. Missing: prerequisites, output structure, when to call this vs. alternatives, pagination info.
Output schemas not documented. Callers cannot plan downstream operations without knowing field names, types, and structure. get-team returns a 'TeamResponse' but LLMs do not see the interface definition in the tool registration.
Clarify the distinction between get-current-standings (live standings now) and get-standings (filtered by division). Consider renaming get-current-standings to list-all-standings or get-standings-by-date, and updating descriptions to explain the difference. Alternatively, merge them into a single get-standings tool with an optional 'division' filter and a 'date' parameter defaulting to 'now'.
Expand tool descriptions to 100 - 200 characters following the LLM-optimized pattern: 'Retrieve current NHL standings grouped by division, sorted by points. Use this to see team records, rankings, and head-to-head stats. Returns structure: division → teams with wins/losses/points. See get-standings for historical data.' Include hints: 'Call this first to see available divisions before calling get-standings.'
Add output schema documentation to each tool. Example for get-team: 'Returns: { teamId: number, name: string, abbrev: string, division: string, wins: number, losses: number, otLosses: number, points: number, goalsFor: number, goalsAgainst: number, roster: [{playerId, firstName, lastName, position, sweaterNumber}] }'. This lets LLMs plan downstream calls (e.g., iterate roster to call get-player).
Add enum constraints to parameters: teamAbbrev should accept an enum of all 32 NHL team abbreviations (TOR, NYR, BOS, etc.). division should enumerate 'Atlantic', 'Metropolitan', 'Central', 'Pacific'. category for get-skater-leaders should enumerate 'goals', 'assists', 'points', 'plusMinus', 'powerPlayGoals', etc.
Parameter constraints missing: teamAbbrev accepts free-form strings with no enum or pattern. Should declare valid abbreviations (TOR, NYR, BOS, etc.). division accepts free-form strings; should enumerate 'Atlantic', 'Metropolitan', etc. category for skater-leaders has no enum; should list 'goals', 'assists', 'points', etc.
Error handling returns generic text ('Failed to retrieve NHL standings. The NHL API might be unavailable.') without recovery guidance. Does not tell LLM: is this retryable? Should user wait? Are there alternatives?
No tool annotations (readOnlyHint). All tools are READ_ONLY and stateless, but this is not declared. Agents should know these are safe to call repeatedly without side effects.
Parameter descriptions lack format/range guidance. 'Date in YYYY-MM-DD format' is good, but limit and playerId parameters have no min/max. What is a valid playerId range? Is limit 1 - 100, 1 - 1000?
get-scheduleget-playerget-skater-leaders
Add numeric bounds: limit parameter should specify '1 - 100' with a default of '20'. playerId has no documented range, add 'Valid player IDs: 1 - 10000' or document the lookup table. teamAbbrev should note 'Three-letter abbreviation, case-insensitive (e.g., TOR, tOr).'
Enhance error messages with recovery guidance. Example: 'Player ID 999999 not found. Try search-players(name: "Connor McDavid") to find the correct ID.' or 'Team abbreviation "XYZ" is invalid. Valid abbreviations: TOR, NYR, BOS, ... See get-teams() for a complete list.'
Add tool annotations to each tool registration. Since all are read-only: readOnlyHint: true. This informs agents that these calls are safe to retry and have no side effects.
Document pagination. Does get-schedule return all games? If not, add offset and limit parameters with guidance: 'limit: 1 - 100, default 20. Use offset to page through results.' Current code sorts by division but does not document whether it caps results.
Clarify relationships between tools. Add to get-current-standings description: 'For a specific division, use get-standings(division: "Atlantic"). For a specific team, use get-team(teamAbbrev: "TOR").' This prevents LLM confusion about when to call each.
Add 'See also' hints to each tool description. Example: 'get-current-standings, See also: get-team (team-specific stats), get-schedule (upcoming games), get-skater-leaders (individual player leaders).' This helps LLMs compose multi-tool queries efficiently.