Coverage for src/usls/adapters/inbound/tools/espn.py: 75%
40 statements
« prev ^ index » next coverage.py v7.15.3, created at 2026-08-05 10:11 +0000
« prev ^ index » next coverage.py v7.15.3, created at 2026-08-05 10:11 +0000
1"""ESPN-backed MCP tools — teams, scoreboard, roster, news, standings, etc."""
3import logging
5from mcp.server.fastmcp import FastMCP
7from ....application.service import USLSService
8from ....ports.inbound import Authorizer
9from ..formatters import (
10 _fmt_match_details,
11 _fmt_news,
12 _fmt_roster,
13 _fmt_scoreboard,
14 _fmt_standings,
15 _fmt_team,
16 _fmt_team_schedule,
17 _fmt_teams,
18)
19from ._base import _READ_ANNOTATIONS, _safe_call_authorized
21logger = logging.getLogger(__name__)
24def register_espn_tools(mcp: FastMCP, service: USLSService, authorizer: Authorizer) -> None:
25 """Register the eight ESPN-backed read-only tools on `mcp`."""
27 @mcp.tool(annotations=_READ_ANNOTATIONS)
28 async def get_teams() -> str:
29 """Get all active USL Super League teams.
31 Returns a numbered list of teams with their ID, full name, abbreviation,
32 and home city. Use the ID or abbreviation with get_team to retrieve
33 detailed information about a specific team.
34 """
35 logger.info("tool=get_teams")
36 return await _safe_call_authorized(authorizer, "get_teams", service.get_teams(), _fmt_teams)
38 @mcp.tool(annotations=_READ_ANNOTATIONS)
39 async def get_team(team_id: str) -> str:
40 """Get details for a specific USL Super League team.
42 Returns full team information including display name, abbreviation, and
43 location. Use the numeric ID returned by get_teams.
45 Args:
46 team_id: ESPN numeric team ID (e.g. "18418" for Atlanta United FC).
47 """
48 logger.info("tool=get_team team_id=%r", team_id)
49 return await _safe_call_authorized(authorizer, "get_team", service.get_team(team_id), _fmt_team)
51 @mcp.tool(annotations=_READ_ANNOTATIONS)
52 async def get_scoreboard(date: str | None = None, end_date: str | None = None) -> str:
53 """Get USL Super League match scores and status for a date or date range.
55 With no arguments, returns matches for the current matchweek. With
56 `date` only, returns matches for that single day. With both `date`
57 and `end_date`, returns every match in the inclusive range.
59 Args:
60 date: Optional start date in YYYYMMDD format (e.g. "20260418").
61 end_date: Optional end date in YYYYMMDD format. Requires `date`.
62 """
63 logger.info("tool=get_scoreboard date=%r end_date=%r", date, end_date)
64 return await _safe_call_authorized(
65 authorizer, "get_scoreboard", service.get_scoreboard(date, end_date), _fmt_scoreboard
66 )
68 @mcp.tool(annotations=_READ_ANNOTATIONS)
69 async def get_roster(team_id: str) -> str:
70 """Get the active roster for an USL Super League team.
72 Returns each player's jersey number, name, position, citizenship,
73 and age. Use the team ID returned by get_teams.
75 Args:
76 team_id: ESPN numeric team ID (e.g. "18418" for Atlanta United FC).
77 """
78 logger.info("tool=get_roster team_id=%r", team_id)
79 return await _safe_call_authorized(authorizer, "get_roster", service.get_roster(team_id), _fmt_roster)
81 @mcp.tool(annotations=_READ_ANNOTATIONS)
82 async def get_match_details(match_id: str) -> str:
83 """Get detailed information for a single USL Super League match.
85 Returns the score, venue, attendance, and a chronological list of key
86 events (goals, substitutions, cards). Use the match ID returned by
87 get_scoreboard or get_team_schedule.
89 Args:
90 match_id: ESPN numeric event ID (e.g. "401853883").
91 """
92 logger.info("tool=get_match_details match_id=%r", match_id)
93 return await _safe_call_authorized(
94 authorizer, "get_match_details", service.get_match_details(match_id), _fmt_match_details
95 )
97 @mcp.tool(annotations=_READ_ANNOTATIONS)
98 async def get_team_schedule(team_id: str) -> str:
99 """Get all matches for a single USL Super League team in the current season.
101 Returns scheduled, in-progress, and completed matches for the team —
102 with opponent, date, score (if played), and status.
104 Args:
105 team_id: ESPN numeric team ID (e.g. "18418" for Atlanta United FC).
106 """
107 logger.info("tool=get_team_schedule team_id=%r", team_id)
108 return await _safe_call_authorized(
109 authorizer, "get_team_schedule", service.get_team_schedule(team_id), _fmt_team_schedule
110 )
112 @mcp.tool(annotations=_READ_ANNOTATIONS)
113 async def get_news(limit: int = 10) -> str:
114 """Get recent USL Super League news articles.
116 Returns each article's headline, publication date, summary, and link
117 to the full ESPN story.
119 Args:
120 limit: Maximum number of articles to return (default 10).
121 """
122 logger.info("tool=get_news limit=%r", limit)
123 return await _safe_call_authorized(authorizer, "get_news", service.get_news(limit), _fmt_news)
125 @mcp.tool(annotations=_READ_ANNOTATIONS)
126 async def get_standings() -> str:
127 """Get the current USL Super League standings.
129 Returns the eight-team table ordered by points descending, with
130 win/loss/tie record, goals for, goals against, and goal differential.
131 """
132 logger.info("tool=get_standings")
133 return await _safe_call_authorized(authorizer, "get_standings", service.get_standings(), _fmt_standings)