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

1"""ESPN-backed MCP tools — teams, scoreboard, roster, news, standings, etc.""" 

2 

3import logging 

4 

5from mcp.server.fastmcp import FastMCP 

6 

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 

20 

21logger = logging.getLogger(__name__) 

22 

23 

24def register_espn_tools(mcp: FastMCP, service: USLSService, authorizer: Authorizer) -> None: 

25 """Register the eight ESPN-backed read-only tools on `mcp`.""" 

26 

27 @mcp.tool(annotations=_READ_ANNOTATIONS) 

28 async def get_teams() -> str: 

29 """Get all active USL Super League teams. 

30 

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) 

37 

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. 

41 

42 Returns full team information including display name, abbreviation, and 

43 location. Use the numeric ID returned by get_teams. 

44 

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) 

50 

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. 

54 

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. 

58 

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 ) 

67 

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. 

71 

72 Returns each player's jersey number, name, position, citizenship, 

73 and age. Use the team ID returned by get_teams. 

74 

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) 

80 

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. 

84 

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. 

88 

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 ) 

96 

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. 

100 

101 Returns scheduled, in-progress, and completed matches for the team — 

102 with opponent, date, score (if played), and status. 

103 

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 ) 

111 

112 @mcp.tool(annotations=_READ_ANNOTATIONS) 

113 async def get_news(limit: int = 10) -> str: 

114 """Get recent USL Super League news articles. 

115 

116 Returns each article's headline, publication date, summary, and link 

117 to the full ESPN story. 

118 

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) 

124 

125 @mcp.tool(annotations=_READ_ANNOTATIONS) 

126 async def get_standings() -> str: 

127 """Get the current USL Super League standings. 

128 

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)