fpl-mcp-server 0.1.5__py3-none-any.whl → 0.1.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fpl-mcp-server
3
- Version: 0.1.5
3
+ Version: 0.1.7
4
4
  Summary: Fantasy Premier League MCP Server
5
5
  Project-URL: Homepage, https://github.com/nguyenanhducs/fpl-mcp
6
6
  Project-URL: Repository, https://github.com/nguyenanhducs/fpl-mcp
@@ -29,81 +29,100 @@ Requires-Dist: pytest>=7.0.0; extra == 'dev'
29
29
  Requires-Dist: ruff>=0.14.0; extra == 'dev'
30
30
  Description-Content-Type: text/markdown
31
31
 
32
- # FPL MCP Server 🏆⚽
32
+ # Fantasy Premier League MCP Server
33
33
 
34
34
  A comprehensive **Model Context Protocol (MCP)** server for Fantasy Premier League analysis and strategy. This server provides AI assistants with powerful tools, resources, and prompts to help you dominate your FPL mini-leagues with data-driven insights.
35
35
 
36
36
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
37
- [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
37
+ [![Python 3.13+](https://img.shields.io/badge/python-3.13+-blue.svg)](https://www.python.org/downloads/)
38
38
  [![MCP](https://img.shields.io/badge/MCP-compatible-green.svg)](https://modelcontextprotocol.io)
39
39
 
40
- ## 🌟 Features
40
+ ## Features
41
41
 
42
42
  This MCP server provides comprehensive FPL analysis capabilities through:
43
43
 
44
- - **26 Interactive Tools** - Search players, analyze fixtures, compare managers, track transfers, and more
45
- - **16 Data Resources** - Efficient URI-based access to players, teams, gameweeks, and manager data
46
- - **7 Strategy Prompts** - Structured templates for squad analysis, transfer planning, and chip strategy
44
+ - **17 Interactive Tools** - Search players, analyze fixtures, compare managers, track transfers, and more
45
+ - **4 Data Resources** - access to players, teams, and gameweeks bootstrap data
46
+ - **8 Strategy Prompts** - Structured templates for squad analysis, transfer planning, chip strategy, and captain selection
47
47
  - **Smart Caching** - 4-hour cache for bootstrap data to minimize API calls while keeping data fresh
48
48
  - **Fuzzy Matching** - Find players even with spelling variations or nicknames
49
49
  - **Live Transfer Trends** - Track the most transferred in/out players for current gameweek
50
50
  - **Manager Insights** - Analyze squads, transfers, and chip usage (supports 2025/26 half-season system)
51
51
  - **Fixture Analysis** - Assess team fixtures and plan transfers around favorable runs
52
52
 
53
- ## 🚀 Quick Start
53
+ ## Quick Start
54
54
 
55
- You have **two options** to run the FPL MCP server:
55
+ ### Option 1: uvx (Recommended)
56
56
 
57
- ### Option 1: Run with Docker (Recommended)
57
+ The fastest way to get started - no installation required:
58
58
 
59
59
  ```json
60
60
  {
61
61
  "mcpServers": {
62
62
  "fpl": {
63
- "command": "docker",
64
- "args": ["run", "--rm", "-i", "yourusername/fpl-mcp:latest"]
65
- },
66
- "type": "stdio"
63
+ "command": "uvx",
64
+ "args": ["fpl-mcp-server"],
65
+ "type": "stdio"
66
+ }
67
67
  }
68
68
  }
69
69
  ```
70
70
 
71
- ---
71
+ ### Option 2: Docker
72
72
 
73
- ### Option 2: Run with uv
73
+ Use the official Docker image from GitHub Container Registry:
74
74
 
75
- 1. **Clone and install**:
75
+ ```json
76
+ {
77
+ "mcpServers": {
78
+ "fpl": {
79
+ "command": "docker",
80
+ "args": [
81
+ "run",
82
+ "--rm",
83
+ "-i",
84
+ "ghcr.io/nguyenanhducs/fpl-mcp:latest"
85
+ ],
86
+ "type": "stdio"
87
+ }
88
+ }
89
+ }
90
+ ```
76
91
 
77
- ```bash
78
- git clone https://github.com/nguyenanhducs/fpl-mcp.git
79
- cd fpl-mcp
80
- uv sync
81
- ```
92
+ ### Option 3: From Source
82
93
 
83
- 2. **Configure MCP Servers**:
94
+ For development or local customization:
84
95
 
85
- ```json
86
- {
87
- "mcpServers": {
88
- "fpl": {
89
- "command": "uv",
90
- "args": [
91
- "--directory",
92
- "/absolute/path/to/fpl-mcp",
93
- "run",
94
- "python",
95
- "-m",
96
- "src.main"
97
- ],
98
- "type": "stdio"
99
- }
100
- }
101
- }
102
- ```
96
+ ```bash
97
+ git clone https://github.com/nguyenanhducs/fpl-mcp.git
98
+ cd fpl-mcp
99
+ uv sync
100
+ ```
103
101
 
104
- Replace `/absolute/path/to/fpl-mcp` with the actual path.
102
+ Then configure:
105
103
 
106
- ## 📖 Usage & Documentation
104
+ ```json
105
+ {
106
+ "mcpServers": {
107
+ "fpl": {
108
+ "command": "uv",
109
+ "args": [
110
+ "--directory",
111
+ "/absolute/path/to/fpl-mcp",
112
+ "run",
113
+ "python",
114
+ "-m",
115
+ "src.main"
116
+ ],
117
+ "type": "stdio"
118
+ }
119
+ }
120
+ }
121
+ ```
122
+
123
+ For detailed installation instructions and more options, see **[Installation Guide](./docs/installation.md)**.
124
+
125
+ ## Usage & Documentation
107
126
 
108
127
  Once configured, you can interact with the FPL MCP server through Claude Desktop using natural language.
109
128
 
@@ -112,26 +131,16 @@ For detailed guidance, see:
112
131
  - **[Usage Examples](./docs/usage-examples.md)** - Natural language query examples for player analysis, fixtures, leagues, and strategy
113
132
  - **[Tool Selection Guide](./docs/tool-selection-guide.md)** - Choose the right tool for your analysis task
114
133
 
115
- ## ⚙️ Configuration
134
+ ## Configuration
116
135
 
117
136
  The server works out-of-the-box with sensible defaults, but you can customize cache durations, timeouts, and logging levels through environment variables.
118
137
 
119
138
  For detailed configuration instructions for both Docker and uv deployments, see **[Configuration Guide](./docs/configuration.md)**.
120
139
 
121
- ## Contributing
140
+ ## Data Sources
122
141
 
123
- We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
124
-
125
- **Quick contribution checklist:**
126
-
127
- - Fork the repository
128
- - Create a feature branch
129
- - Write tests for new features
130
- - Ensure all tests pass
131
- - Follow PEP 8 style guidelines
132
- - Use conventional commit messages
133
- - Submit a pull request
142
+ This server uses the official **Fantasy Premier League API**, see [here](./docs/fpl-api.md) for more details.
134
143
 
135
- ## 📊 Data Sources
144
+ ## Contributing
136
145
 
137
- This server uses the official **Fantasy Premier League API**, see [here](./docs/fpl-api.md) for more details.
146
+ We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
@@ -0,0 +1,35 @@
1
+ src/cache.py,sha256=SeJAmddaY9507Ac5YRnbBBXGOQw_OwpIefB-kn11lDI,4604
2
+ src/client.py,sha256=_Tv7TlXD5d3pvXb7AmMCgy3gbZqjOO9EedMORveRU4s,10493
3
+ src/config.py,sha256=hfjW-W0gdH0PxmC6gEg-o9SqraajJ6gNy1SIlIOG-F4,845
4
+ src/constants.py,sha256=8XkQH1rslnf6VWbJkVY6MmpgRhhS3wjFJhIoZWr91kg,839
5
+ src/exceptions.py,sha256=Q8waMbF8Sr1s6lOoAB8-doX0v6EvqZopwQHGxNQ7m-w,2972
6
+ src/formatting.py,sha256=aLiJWM2hJw68gyGJ1Nc1nPAyfoSIqwyjPE8svr-7ufo,10236
7
+ src/main.py,sha256=C6wX96rm0-b1jSvU2BrTv47hw2FGktkwcqJ5nEM8t5U,977
8
+ src/models.py,sha256=P5rIO-UjVQpLUlDQsDV5hw2Tn3s5Xcj6ye8xJkRizGc,10880
9
+ src/rate_limiter.py,sha256=GLk3ZRFFvEZxkZAQd-pZ7UxQdrAAUVch3pxe_aMU-J8,3450
10
+ src/state.py,sha256=seyygRhlz-K1GtG80os34tnNJ6UkAFA2rVFgupZG2tY,17531
11
+ src/utils.py,sha256=WhcWQIXpc1vIjU8hyrGDJyKJSlcbVoG938k_3UMDlCM,7340
12
+ src/validators.py,sha256=aU36TUNYWb26fvZH27Xnryrp8gve9DM2phvy7vEnAi8,6891
13
+ src/prompts/__init__.py,sha256=Sj7YgIL46wGrmkJq39rpJilPK3blK6oPI-hE2-lBdxY,535
14
+ src/prompts/captain_recommendation.py,sha256=1FI69uS9wNkOZZNnenFBW_JXg9HKU4bEUmixTn-6GJ0,5706
15
+ src/prompts/chips.py,sha256=zzv5bqr8HuUAkvXenonrTXVhwNYGMwH9OPSC-c-1Dtg,5524
16
+ src/prompts/league_analysis.py,sha256=bQN-tVC5FmrZEKTIfwM0eLaNc8mia42Qr34o4kaSJ1g,8297
17
+ src/prompts/player_analysis.py,sha256=7BgF_h0us_vxPC5JrqKPsMs-395xrUvfpW0VJ4Bgon8,5234
18
+ src/prompts/squad_analysis.py,sha256=H3COvcHt7uqPyWMm_2SEaN2lgTgwA20lKuotVOdMe3I,5209
19
+ src/prompts/team_analysis.py,sha256=7ypoaTUvrQQeKsysrhdwbzMzjtI2KldB1ztfSGCZArE,4222
20
+ src/prompts/team_selection.py,sha256=tDOiyQYTp-hyKlKVAdjGxZsr1xPfMgApWREjbMtNpXM,3847
21
+ src/prompts/transfers.py,sha256=Gsfey4XmjyYYJcRFfoDl0oNZnAOGsRCt_Ro0ePv43o8,5543
22
+ src/resources/__init__.py,sha256=i7nlLVSLtiIrLtOnyoMiK3KTFGEnct4LXApB4b6URFM,303
23
+ src/resources/bootstrap.py,sha256=ViZsGYtr5YqiTtvM_YTkbCr6R6Z9vUBiVSGGI9wwI3s,6970
24
+ src/tools/__init__.py,sha256=JjoMoMHrhFRMarpgtOS9AoS9604c0p-yFc0PXoITe-E,510
25
+ src/tools/fixtures.py,sha256=B5K_jtp4MDqI_Wd3_6blEkDn2Qki_mym2WmDSrhzccs,13155
26
+ src/tools/gameweeks.py,sha256=7skxUC6HoCj9hFC0YbjsMceVIhvvjFOoSdApe9JDfP0,8126
27
+ src/tools/leagues.py,sha256=uRUs2gC4Czj-S8qucomI5x4HQ-I7GxRZI4b3E6KObCM,38024
28
+ src/tools/players.py,sha256=_H2LP9s_yE9mD7zgcgVK__cwc4wdcHo9iUe3R6Llyn0,29691
29
+ src/tools/teams.py,sha256=DknehKi6HIu2TSlKBqg91VWNONxLP4NIy99cH5TrWqo,7924
30
+ src/tools/transfers.py,sha256=zpg0ueCRC6MhKiafhU4-gI0SzEzFYGvlZ2EnXqGoJkU,29466
31
+ fpl_mcp_server-0.1.7.dist-info/METADATA,sha256=m53_QwzJv3nkfvfsUgzE_urTaFhsX8jq4egiXr5bR8w,4788
32
+ fpl_mcp_server-0.1.7.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
33
+ fpl_mcp_server-0.1.7.dist-info/entry_points.txt,sha256=b3R5hBUMTLVnCGl07NfK7kyq9NCKtpn5Q8OsY79pMek,49
34
+ fpl_mcp_server-0.1.7.dist-info/licenses/LICENSE,sha256=HCDOcdX83voRU2Eip214yj6P_tEyjVjCsCW_sixZFPw,1071
35
+ fpl_mcp_server-0.1.7.dist-info/RECORD,,
src/client.py CHANGED
@@ -3,6 +3,13 @@ from typing import TYPE_CHECKING, Any, Optional
3
3
 
4
4
  import httpx
5
5
 
6
+ from .constants import (
7
+ TOP_DEFENDERS_COUNT,
8
+ TOP_FORWARDS_COUNT,
9
+ TOP_GOALKEEPERS_COUNT,
10
+ TOP_MIDFIELDERS_COUNT,
11
+ PlayerPosition,
12
+ )
6
13
  from .models import Player
7
14
  from .rate_limiter import rate_limiter
8
15
 
@@ -197,14 +204,24 @@ class FPLClient:
197
204
  """
198
205
  if not self._store or not self._store.bootstrap_data:
199
206
  logger.warning("Bootstrap data not available for top players")
200
- return {"GKP": [], "DEF": [], "MID": [], "FWD": []}
207
+ return {
208
+ PlayerPosition.GOALKEEPER.value: [],
209
+ PlayerPosition.DEFENDER.value: [],
210
+ PlayerPosition.MIDFIELDER.value: [],
211
+ PlayerPosition.FORWARD.value: [],
212
+ }
201
213
 
202
214
  data = self._store.bootstrap_data
203
215
  teams = {t.id: t.name for t in data.teams}
204
216
  types = {t.id: t.singular_name_short for t in data.element_types}
205
217
 
206
218
  # Group players by position
207
- players_by_position = {"GKP": [], "DEF": [], "MID": [], "FWD": []}
219
+ players_by_position = {
220
+ PlayerPosition.GOALKEEPER.value: [],
221
+ PlayerPosition.DEFENDER.value: [],
222
+ PlayerPosition.MIDFIELDER.value: [],
223
+ PlayerPosition.FORWARD.value: [],
224
+ }
208
225
 
209
226
  for element in data.elements:
210
227
  # Only include available players
@@ -237,26 +254,26 @@ class FPLClient:
237
254
 
238
255
  # Sort by points_per_game and take top N
239
256
  result = {
240
- "GKP": sorted(
241
- players_by_position["GKP"],
257
+ PlayerPosition.GOALKEEPER.value: sorted(
258
+ players_by_position[PlayerPosition.GOALKEEPER.value],
242
259
  key=lambda x: x["points_per_game"],
243
260
  reverse=True,
244
- )[:5],
245
- "DEF": sorted(
246
- players_by_position["DEF"],
261
+ )[:TOP_GOALKEEPERS_COUNT],
262
+ PlayerPosition.DEFENDER.value: sorted(
263
+ players_by_position[PlayerPosition.DEFENDER.value],
247
264
  key=lambda x: x["points_per_game"],
248
265
  reverse=True,
249
- )[:20],
250
- "MID": sorted(
251
- players_by_position["MID"],
266
+ )[:TOP_DEFENDERS_COUNT],
267
+ PlayerPosition.MIDFIELDER.value: sorted(
268
+ players_by_position[PlayerPosition.MIDFIELDER.value],
252
269
  key=lambda x: x["points_per_game"],
253
270
  reverse=True,
254
- )[:20],
255
- "FWD": sorted(
256
- players_by_position["FWD"],
271
+ )[:TOP_MIDFIELDERS_COUNT],
272
+ PlayerPosition.FORWARD.value: sorted(
273
+ players_by_position[PlayerPosition.FORWARD.value],
257
274
  key=lambda x: x["points_per_game"],
258
275
  reverse=True,
259
- )[:20],
276
+ )[:TOP_FORWARDS_COUNT],
260
277
  }
261
278
 
262
279
  return result
src/constants.py CHANGED
@@ -3,75 +3,15 @@ Constants and enums for the FPL MCP Server.
3
3
  """
4
4
 
5
5
  from enum import Enum
6
- from http import HTTPStatus
7
6
 
8
- # =============================================================================
9
- # HTTP Status Codes
10
- # =============================================================================
11
- SUCCESS_STATUS = HTTPStatus.OK
12
- NOT_FOUND_STATUS = HTTPStatus.NOT_FOUND
13
- SERVER_ERROR_STATUS = HTTPStatus.INTERNAL_SERVER_ERROR
14
- RATE_LIMIT_STATUS = HTTPStatus.TOO_MANY_REQUESTS
15
-
16
- # =============================================================================
17
7
  # Fuzzy Matching Constants
18
- # =============================================================================
19
8
  FUZZY_MATCH_THRESHOLD = 0.6 # Minimum similarity for fuzzy matches
20
9
  SUBSTRING_MATCH_PENALTY = 0.9 # Score multiplier for substring matches
21
10
  FUZZY_MATCH_PENALTY = 0.8 # Score multiplier for fuzzy matches
22
11
  PERFECT_MATCH_SCORE = 1.0 # Score for exact matches
23
12
 
24
- # =============================================================================
25
- # Cache TTL (Time To Live) in Seconds
26
- # =============================================================================
27
- DEFAULT_BOOTSTRAP_TTL = 14400 # 4 hours
28
- DEFAULT_FIXTURES_TTL = 14400 # 4 hours
29
- DEFAULT_PLAYER_SUMMARY_TTL = 300 # 5 minutes
30
-
31
- # =============================================================================
32
- # Rate Limiting
33
- # =============================================================================
34
- MAX_AUTH_ATTEMPTS = 5 # Maximum login attempts
35
- AUTH_WINDOW_SECONDS = 300 # Time window for rate limiting (5 minutes)
36
-
37
- # =============================================================================
38
- # API Timeouts
39
- # =============================================================================
40
- DEFAULT_HTTP_TIMEOUT = 30 # Default timeout for HTTP requests
41
- BROWSER_TIMEOUT = 15 # Browser automation timeout
42
-
43
-
44
- # =============================================================================
45
- # Difficulty Ratings
46
- # =============================================================================
47
- class FixtureDifficulty(Enum):
48
- """FPL fixture difficulty ratings"""
49
-
50
- VERY_EASY = 1
51
- EASY = 2
52
- MODERATE = 3
53
- HARD = 4
54
- VERY_HARD = 5
55
13
 
56
-
57
- # Difficulty emoji mapping
58
- DIFFICULTY_EMOJI = {
59
- FixtureDifficulty.VERY_EASY: "🟢",
60
- FixtureDifficulty.EASY: "🟢",
61
- FixtureDifficulty.MODERATE: "🟡",
62
- FixtureDifficulty.HARD: "🟠",
63
- FixtureDifficulty.VERY_HARD: "🔴",
64
- 1: "🟢",
65
- 2: "🟢",
66
- 3: "🟡",
67
- 4: "🟠",
68
- 5: "🔴",
69
- }
70
-
71
-
72
- # =============================================================================
73
14
  # Player Positions
74
- # =============================================================================
75
15
  class PlayerPosition(Enum):
76
16
  """FPL player positions"""
77
17
 
@@ -81,38 +21,14 @@ class PlayerPosition(Enum):
81
21
  FORWARD = "FWD"
82
22
 
83
23
 
84
- # =============================================================================
85
24
  # Top Players Count
86
- # =============================================================================
87
- TOP_GOALKEEPERS_COUNT = 3
88
- TOP_OUTFIELD_PLAYERS_COUNT = 10
25
+ TOP_GOALKEEPERS_COUNT = 5
26
+ TOP_DEFENDERS_COUNT = 20
27
+ TOP_MIDFIELDERS_COUNT = 20
28
+ TOP_FORWARDS_COUNT = 20
89
29
 
90
- # =============================================================================
91
30
  # Pagination
92
- # =============================================================================
93
- DEFAULT_PAGE_SIZE = 50 # FPL API default league standings page size
94
- DEFAULT_PAGINATION_LIMIT = 20 # MCP recommended default limit for tool responses
95
31
  MAX_PAGINATION_LIMIT = 100 # MCP recommended maximum limit
96
32
 
97
- # =============================================================================
98
33
  # MCP Response Configuration
99
- # =============================================================================
100
34
  CHARACTER_LIMIT = 25000 # Maximum response size in characters (MCP best practice)
101
-
102
- # =============================================================================
103
- # FPL URLs
104
- # =============================================================================
105
- FPL_BASE_URL = "https://fantasy.premierleague.com"
106
- FPL_API_BASE = f"{FPL_BASE_URL}/api"
107
-
108
- # =============================================================================
109
- # Logging
110
- # =============================================================================
111
- DEFAULT_LOG_LEVEL = "INFO"
112
- WEB_SERVER_LOG_LEVEL = "critical" # Quiet web server logs
113
-
114
- # =============================================================================
115
- # Server Configuration
116
- # =============================================================================
117
- DEFAULT_WEB_SERVER_HOST = "0.0.0.0"
118
- DEFAULT_WEB_SERVER_PORT = 8000
src/models.py CHANGED
@@ -161,9 +161,6 @@ class FixtureData(BaseModel):
161
161
  model_config = ConfigDict(extra="allow")
162
162
 
163
163
 
164
- # Models for element-summary endpoint (player details)
165
-
166
-
167
164
  class PlayerFixture(BaseModel):
168
165
  """Fixture information for a player"""
169
166
 
@@ -269,9 +266,6 @@ class ElementSummary(BaseModel):
269
266
  history_past: list[PlayerHistoryPast]
270
267
 
271
268
 
272
- # Models for entry endpoint (FPL manager/team info)
273
-
274
-
275
269
  class LeaguePhase(BaseModel):
276
270
  """Phase information within a league"""
277
271
 
@@ -370,9 +364,6 @@ class ManagerEntry(BaseModel):
370
364
  model_config = ConfigDict(extra="allow")
371
365
 
372
366
 
373
- # Models for league standings endpoint
374
-
375
-
376
367
  class LeagueStandingEntry(BaseModel):
377
368
  """Individual entry in league standings"""
378
369
 
@@ -408,9 +399,6 @@ class LeagueStandingsResponse(BaseModel):
408
399
  model_config = ConfigDict(extra="allow")
409
400
 
410
401
 
411
- # Models for manager gameweek picks endpoint
412
-
413
-
414
402
  class AutomaticSub(BaseModel):
415
403
  """Automatic substitution made during a gameweek"""
416
404
 
@@ -432,18 +420,15 @@ class PickElement(BaseModel):
432
420
  model_config = ConfigDict(extra="allow")
433
421
 
434
422
 
435
- # Models for /me endpoint (current user info)
436
-
437
-
438
423
  class UserPlayer(BaseModel):
439
424
  """Current user's player information from /me endpoint"""
440
425
 
441
426
  first_name: str
442
427
  last_name: str
443
428
  email: str
444
- entry: int # This is the user's team ID
429
+ entry: int
445
430
  region: int
446
- id: int # Player ID (not team ID)
431
+ id: int
447
432
 
448
433
  model_config = ConfigDict(extra="allow")
449
434
 
@@ -491,13 +476,13 @@ class ChipData(BaseModel):
491
476
  """Chip information from my-team endpoint"""
492
477
 
493
478
  id: int
494
- status_for_entry: str # "available", "played", "unavailable"
495
- played_by_entry: list[int] # List of gameweeks where chip was played
496
- name: str # "wildcard", "freehit", "bboost", "3xc"
497
- number: int # Chip number (1 or 2 for first/second half)
498
- start_event: int # First gameweek chip can be used
499
- stop_event: int # Last gameweek chip can be used
500
- chip_type: str # "team" or "transfer"
479
+ status_for_entry: str
480
+ played_by_entry: list[int]
481
+ name: str
482
+ number: int
483
+ start_event: int
484
+ stop_event: int
485
+ chip_type: str
501
486
  is_pending: bool
502
487
 
503
488
  model_config = ConfigDict(extra="allow")
@@ -506,12 +491,12 @@ class ChipData(BaseModel):
506
491
  class TransfersData(BaseModel):
507
492
  """Transfer information from my-team endpoint"""
508
493
 
509
- cost: int # Points cost for transfers
510
- status: str # "cost" or other status
511
- limit: int # Maximum number of free transfers that can accumulate
512
- made: int # Number of transfers made this gameweek
513
- bank: int # Money in bank (in tenths, divide by 10 for actual value)
514
- value: int # Total squad value (in tenths, divide by 10 for actual value)
494
+ cost: int
495
+ status: str
496
+ limit: int
497
+ made: int
498
+ bank: int
499
+ value: int
515
500
 
516
501
  model_config = ConfigDict(extra="allow")
517
502
 
src/prompts/__init__.py CHANGED
@@ -6,11 +6,13 @@ from ..tools import mcp
6
6
 
7
7
  # Import all prompt modules (this registers prompts with mcp) # noqa: E402
8
8
  from . import (
9
+ captain_recommendation, # noqa: F401
9
10
  chips, # noqa: F401
10
11
  league_analysis, # noqa: F401
11
12
  player_analysis, # noqa: F401
12
13
  squad_analysis, # noqa: F401
13
14
  team_analysis, # noqa: F401
15
+ team_selection, # noqa: F401
14
16
  transfers, # noqa: F401
15
17
  )
16
18
 
@@ -0,0 +1,149 @@
1
+ """
2
+ FPL MCP Prompts - Captain Recommendation.
3
+
4
+ Prompts guide the LLM in selecting optimal captain choices from the manager's squad
5
+ using form, fixtures, xGI metrics, and opponent defensive strength.
6
+ """
7
+
8
+ from ..tools import mcp
9
+
10
+
11
+ @mcp.prompt()
12
+ def recommend_captain(
13
+ team_id: int, gameweek: int | None = None, response_format: str = "markdown"
14
+ ) -> str:
15
+ """
16
+ Recommend optimal captain choices using xGI-based metrics and fixture analysis.
17
+
18
+ This prompt guides the LLM to analyze squad players and recommend the top 3
19
+ captain options based on form, fixtures, expected goals, and opponent strength.
20
+
21
+ Args:
22
+ team_id: Manager's FPL team ID
23
+ gameweek: Target gameweek (defaults to current/next if None)
24
+ response_format: Output format - 'markdown' (default) or 'json'
25
+ """
26
+ gameweek_text = f"gameweek {gameweek}" if gameweek else "the current/upcoming gameweek"
27
+ gameweek_display = f"{gameweek}" if gameweek else "Current"
28
+
29
+ return f"""Analyze captain options for team ID {team_id} in {gameweek_text}.
30
+ Act as an FPL Expert Analyst with 10+ years of experience. We do not play it safe; we play for points.
31
+
32
+ **OBJECTIVE: Identify top 3 captain choices using a weighted Pro-Level scoring model.**
33
+
34
+ ---
35
+
36
+ ## 🚦 **Workflow & Efficiency**
37
+
38
+ 1. **Tool**: `fpl_get_captain_recommendations(team_id={team_id}, gameweek={gameweek})`
39
+ *This tool automatically runs the Pro-Level Scoring Model defined below.*
40
+ 2. **Review**: Analyze the return values (Score, Rationale, Metrics).
41
+ 3. **Explain**: Use the framework below to justify the tool's recommendations.
42
+
43
+ ---
44
+
45
+ ## 📊 **Pro-Level Scoring Model (Max 100)**
46
+
47
+ The tool calculates the **Captain Suitability Score** using this weighted matrix. Use this context to explain the results:
48
+
49
+ ### **1. Projected Points (Weight: 40%)**
50
+ *The core engine. Can they score specific points this week?*
51
+ * **Metric**: Underlying stats (xG + xA) over last 5 GWs + Historical reliability.
52
+ * **Scoring**:
53
+ * **40pts**: Elite stats (xGI > 0.9/match) OR consistent returns (returned in 4/5 last).
54
+ * **30pts**: Good stats (xGI 0.6-0.8) OR decent form.
55
+ * **20pts**: Average stats but good player class.
56
+ * **10pts**: Poor underlying stats.
57
+
58
+ ### **2. Fixture Vulnerability (Weight: 30%)**
59
+ *Target specific defensive weaknesses, not just generic FDR.*
60
+ * **Metric**: Opponent strength & Home/Away advantage.
61
+ * **Scoring**:
62
+ * **30pts**: vs Weak Defense (bottom 5) + Home Game.
63
+ * **20pts**: vs Average Defense (Home) OR Weak Defense (Away).
64
+ * **10pts**: vs Strong Defense (Home).
65
+ * **0pts**: vs Elite Defense (Away).
66
+
67
+ ### **3. Nailedness & Minutes (Weight: 20%)**
68
+ *Can they hurt us if they don't start?*
69
+ * **Metric**: Minutes played in last 3 weeks + Status.
70
+ * **Scoring**:
71
+ * **20pts**: Nailed (90 mins every game).
72
+ * **15pts**: Secure starter (70-80 mins).
73
+ * **10pts**: Rotation Risk (Pep Roulette / Early Subs).
74
+ * **5pts**: Returning from injury (Start uncertain).
75
+ * **0pts**: benched/injured (Exclude).
76
+
77
+ ### **4. Explosiveness Bonus (Weight: 10%)**
78
+ *Do they have a 20-point ceiling?*
79
+ * **Metric**: Penalties, Set Pieces, Multi-goal history.
80
+ * **Scoring**:
81
+ * **10pts**: on Penalties + Hat-trick history.
82
+ * **5pts**: Goalscorer but no penalties.
83
+ * **0pts**: Defensive Midfielder / Low ceiling.
84
+
85
+ **Total Score = Sum of above factors.**
86
+
87
+ ---
88
+
89
+ ## ⚠️ **Critical Rules**
90
+
91
+ 1. **Risk Flags (Don't auto-exclude):**
92
+ * If a premium player (Price > £10.0m) has `status != 'a'` (available) or played 0 mins recently, **DO NOT** exclude them automatically.
93
+ * Instead, apply a **"Risk Flag"**: penalty to their *Nailedness* score but keep them in the ranking if their upside is huge.
94
+ * *Example:* Haaland returning from injury might play 60 mins but score 2 goals. He is a valid risky captain.
95
+
96
+ 2. **Differentials:**
97
+ * If scores are close (<5pts), favor the player with lower ownership (Differential) if chasing rank, or higher ownership (Shield) if protecting rank. Default to *Points Prediction*.
98
+
99
+ 3. **Ambiguity:**
100
+ * If stats are missing for a new signing, judge based on *Club Pedigree* and *Fixture* (Assumed 50% "Projected Points" score).
101
+
102
+ ---
103
+
104
+ ## 📝 **Output Format:**
105
+
106
+ **Top 3 Captain Recommendations for Gameweek {gameweek_display}**
107
+
108
+ 🥇 **1. [Player Name]** (Score: [Score]/100) | Confidence: [High/Medium/Low]
109
+ • **Projected Points**: [High/Med/Low] based on xGI & History
110
+ • **Fixture**: [Opponent] (H/A) - Difficulty: [FDR]/5 [⭐]
111
+ • **Nailedness**: [Secure/Risk] - [Minutes played last 3 GWs]
112
+ • **Explosiveness**: [Penalty Duties? / Haul Potential?]
113
+
114
+ **Why**: [2-3 sentence reasoning using the Scoring Model. E.g. "Points for Elite Stats (40pts) + Weak Defense (30pts)..."]
115
+ **Risk**: [Any rotation risk or injury flag? If none, say "None"]
116
+
117
+ **Confidence**: [Justification, e.g., "Clear data leader, 15pt gap to #2"]
118
+
119
+ 🥈 **2. [Player Name]** (Score: .../100)
120
+ ...
121
+
122
+ 🥉 **3. [Player Name]** (Score: .../100)
123
+ ...
124
+
125
+ ---
126
+ **Confidence Key:**
127
+ • High: Complete data, clear leader
128
+ • Medium: Close competition
129
+ • Low: Uncertain data / Risk factors
130
+ ```
131
+
132
+ **Use emojis for FDR:**
133
+ - FDR 1: ⭐ (very easy)
134
+ - FDR 2: ⭐⭐
135
+ - FDR 3: ⭐⭐⭐
136
+ - FDR 4: ⭐⭐⭐⭐
137
+ - FDR 5: ⭐⭐⭐⭐⭐ (very hard)
138
+
139
+ ---
140
+
141
+ ## 🔧 **Execution Plan**
142
+
143
+ 1. **Tool**: `fpl_get_captain_recommendations(team_id={team_id}, gameweek={gameweek})`
144
+ *Note: This tool handles the raw data fetching and scoring model calculation.*
145
+ 2. **Process**: Review the tool's `recommendations` list.
146
+ 3. **Output**: Format the top 3 recommendations as requested above.
147
+
148
+ **Begin Analysis Now.**
149
+ """