avios-cli 0.4.3__tar.gz → 0.6.0__tar.gz

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.
Files changed (62) hide show
  1. {avios_cli-0.4.3 → avios_cli-0.6.0}/CHANGELOG.md +75 -0
  2. {avios_cli-0.4.3 → avios_cli-0.6.0}/PKG-INFO +63 -19
  3. {avios_cli-0.4.3 → avios_cli-0.6.0}/README.md +57 -15
  4. avios_cli-0.6.0/docs/dashboard.svg +216 -0
  5. {avios_cli-0.4.3 → avios_cli-0.6.0}/docs/reward-flights.svg +107 -106
  6. {avios_cli-0.4.3 → avios_cli-0.6.0}/pyproject.toml +13 -3
  7. {avios_cli-0.4.3 → avios_cli-0.6.0}/scripts/screenshot.py +9 -3
  8. avios_cli-0.6.0/src/avios/__init__.py +7 -0
  9. {avios_cli-0.4.3 → avios_cli-0.6.0}/src/avios/cli.py +72 -23
  10. {avios_cli-0.4.3 → avios_cli-0.6.0}/src/avios/client.py +27 -4
  11. {avios_cli-0.4.3 → avios_cli-0.6.0}/src/avios/config.py +3 -1
  12. avios_cli-0.6.0/src/avios/mcp_entry.py +36 -0
  13. avios_cli-0.6.0/src/avios/mcp_server.py +675 -0
  14. avios_cli-0.6.0/src/avios/rewards.py +1396 -0
  15. {avios_cli-0.4.3 → avios_cli-0.6.0}/src/avios/session.py +19 -0
  16. {avios_cli-0.4.3 → avios_cli-0.6.0}/src/avios/tui/rewards.py +46 -22
  17. {avios_cli-0.4.3 → avios_cli-0.6.0}/tests/conftest.py +3 -0
  18. avios_cli-0.6.0/tests/fixtures/reward_search.rsc +6 -0
  19. {avios_cli-0.4.3 → avios_cli-0.6.0}/tests/test_cli.py +160 -69
  20. avios_cli-0.6.0/tests/test_mcp_server.py +623 -0
  21. avios_cli-0.6.0/tests/test_rewards.py +711 -0
  22. {avios_cli-0.4.3 → avios_cli-0.6.0}/tests/test_tui.py +80 -21
  23. {avios_cli-0.4.3 → avios_cli-0.6.0}/uv.lock +671 -2
  24. avios_cli-0.4.3/docs/dashboard.svg +0 -216
  25. avios_cli-0.4.3/src/avios/__init__.py +0 -6
  26. avios_cli-0.4.3/src/avios/rewards.py +0 -530
  27. avios_cli-0.4.3/tests/fixtures/reward_search.rsc +0 -3
  28. avios_cli-0.4.3/tests/test_rewards.py +0 -324
  29. {avios_cli-0.4.3 → avios_cli-0.6.0}/.editorconfig +0 -0
  30. {avios_cli-0.4.3 → avios_cli-0.6.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  31. {avios_cli-0.4.3 → avios_cli-0.6.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  32. {avios_cli-0.4.3 → avios_cli-0.6.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  33. {avios_cli-0.4.3 → avios_cli-0.6.0}/.github/dependabot.yml +0 -0
  34. {avios_cli-0.4.3 → avios_cli-0.6.0}/.github/workflows/ci.yml +0 -0
  35. {avios_cli-0.4.3 → avios_cli-0.6.0}/.github/workflows/publish.yml +0 -0
  36. {avios_cli-0.4.3 → avios_cli-0.6.0}/.gitignore +0 -0
  37. {avios_cli-0.4.3 → avios_cli-0.6.0}/.pre-commit-config.yaml +0 -0
  38. {avios_cli-0.4.3 → avios_cli-0.6.0}/.python-version +0 -0
  39. {avios_cli-0.4.3 → avios_cli-0.6.0}/CONTRIBUTING.md +0 -0
  40. {avios_cli-0.4.3 → avios_cli-0.6.0}/LICENSE +0 -0
  41. {avios_cli-0.4.3 → avios_cli-0.6.0}/SECURITY.md +0 -0
  42. {avios_cli-0.4.3 → avios_cli-0.6.0}/src/avios/accounts.py +0 -0
  43. {avios_cli-0.4.3 → avios_cli-0.6.0}/src/avios/aggregate.py +0 -0
  44. {avios_cli-0.4.3 → avios_cli-0.6.0}/src/avios/auth.py +0 -0
  45. {avios_cli-0.4.3 → avios_cli-0.6.0}/src/avios/endpoints.py +0 -0
  46. {avios_cli-0.4.3 → avios_cli-0.6.0}/src/avios/finnair.py +0 -0
  47. {avios_cli-0.4.3 → avios_cli-0.6.0}/src/avios/models.py +0 -0
  48. {avios_cli-0.4.3 → avios_cli-0.6.0}/src/avios/programmes.py +0 -0
  49. {avios_cli-0.4.3 → avios_cli-0.6.0}/src/avios/tui/__init__.py +0 -0
  50. {avios_cli-0.4.3 → avios_cli-0.6.0}/src/avios/tui/app.py +0 -0
  51. {avios_cli-0.4.3 → avios_cli-0.6.0}/src/avios/tui/art.py +0 -0
  52. {avios_cli-0.4.3 → avios_cli-0.6.0}/src/avios/tui/styles.tcss +0 -0
  53. {avios_cli-0.4.3 → avios_cli-0.6.0}/src/avios/tui/widgets.py +0 -0
  54. {avios_cli-0.4.3 → avios_cli-0.6.0}/tests/fixtures/balance.json +0 -0
  55. {avios_cli-0.4.3 → avios_cli-0.6.0}/tests/fixtures/transactions.json +0 -0
  56. {avios_cli-0.4.3 → avios_cli-0.6.0}/tests/test_accounts.py +0 -0
  57. {avios_cli-0.4.3 → avios_cli-0.6.0}/tests/test_aggregate.py +0 -0
  58. {avios_cli-0.4.3 → avios_cli-0.6.0}/tests/test_auth.py +0 -0
  59. {avios_cli-0.4.3 → avios_cli-0.6.0}/tests/test_client.py +0 -0
  60. {avios_cli-0.4.3 → avios_cli-0.6.0}/tests/test_finnair.py +0 -0
  61. {avios_cli-0.4.3 → avios_cli-0.6.0}/tests/test_models.py +0 -0
  62. {avios_cli-0.4.3 → avios_cli-0.6.0}/tests/test_session.py +0 -0
@@ -6,6 +6,81 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.6.0] - 2026-08-11
10
+
11
+ ### Added
12
+ - **MCP server (`avios-mcp`).** Exposes your Avios accounts and British Airways
13
+ reward availability to Claude and any other MCP client over stdio. Install with
14
+ `uv tool install 'avios-cli[mcp]'`; sessions come from `avios login`, so the
15
+ server never performs a login itself. Closes #45.
16
+
17
+ Tools: `list_accounts`, `get_balance`, `get_transactions`,
18
+ `get_pending_transactions`, `whoami`, `search_reward_flights`.
19
+
20
+ Design constraints worth stating, because they are what make it safe to point an
21
+ agent at:
22
+
23
+ - **Read-only.** Nothing books, spends, or mutates a session.
24
+ - **No credentials in output.** Every tool returns an explicit response model
25
+ rather than a raw API payload, so cookies, API keys and the `whoami` id token
26
+ never leave the process.
27
+ - **Reward search is batched and rate-limited.** BA blocks by IP address, so an
28
+ agent fanning out over routes could lock you out of the site. A whole return
29
+ trip goes through one batched, single-browser-session search; the server
30
+ enforces a cooldown between searches; and a block is reported as terminal and
31
+ explicitly not retryable.
32
+ - **MCP is an optional extra**, so a plain CLI install does not pull in the SDK's
33
+ web stack.
34
+
35
+ ## [0.5.0] - 2026-08-11
36
+
37
+ ### Fixed
38
+ - **BA reward-flight search returned nothing after British Airways rebuilt the
39
+ flight finder.** The new Next.js app moved each day's flights one level deeper
40
+ (`departureJourneys.<date>.journeys[].flights[]` instead of
41
+ `departureJourneys.<date>.flights[]`), so every day parsed as empty. Availability
42
+ parsing now follows the new shape, and the old flat shape still parses if BA
43
+ rolls back.
44
+ - **Business-class seats were always reported as zero.** BA's availability rows use
45
+ cabin code `J`; the client only looked for `C`. Both are now recognised, matching
46
+ the site's own `cabinClassCodeMap`.
47
+ - The request contract was re-derived from a live capture and is now reproduced
48
+ byte for byte — query parameters, both `next-router-state-tree` variants, `rsc`,
49
+ `next-url`, `accept`, and the full browser header set. A user-agent that
50
+ disagreed with the `sec-ch-ua` client hints (Chrome 126 vs 148) is fixed, since
51
+ the mismatch is itself a bot signal.
52
+
53
+ ### Added
54
+ - **Avios prices.** Searching an exact `--date` now calls the finder's
55
+ `fetchPricingAction` server action and shows the Avios cost per cabin for your
56
+ party, in both the CLI table and the TUI. Calendar (month) searches stay
57
+ seats-only so they remain one request per leg.
58
+ - Exact-date searches also re-read that date through
59
+ `getFlightResultsForSingleJourneyAction`, exactly as the website does when you
60
+ click a day, so seat counts are fresh rather than served from the month cache.
61
+ - Seats that only sell against a BA companion voucher (Business `rbd: I`) are
62
+ marked `†` instead of being counted as general availability.
63
+ - `AviosClient.search_reward_legs()` searches every leg of a trip over **one**
64
+ browser session, and reports failures per leg so one bad leg does not lose the
65
+ other. The CLI and TUI both use it.
66
+ - Akamai denials are now distinguished from an expired session: a bot-manager 403
67
+ or a 429 raises `RewardSearchBlockedError` telling you to wait and switch
68
+ network, rather than sending you to log in again.
69
+
70
+ ### Changed
71
+ - **Reward searches make far fewer requests.** Previously each leg launched its own
72
+ Chrome, navigated to the finder, and drove the search form. A search now warms
73
+ one browser navigation and issues in-page `fetch()` calls for everything after
74
+ it — a return trip costs one navigation and two fetches — with pacing between
75
+ requests. British Airways blocks by IP address, and page loads were what
76
+ triggered it.
77
+ - One availability request now returns the whole 13-month booking window, so an
78
+ out-of-range month reports the window BA actually offers.
79
+ - Dates beyond BA's rolling booking horizon are recognised (`availabilityLevel: 3`)
80
+ and no longer render as "no reward seats".
81
+ - `flights --json` reports days as `journeys[].flights[]`, following the upstream
82
+ shape, and includes the `price` attached to each cabin.
83
+
9
84
  ## [0.4.3] - 2026-07-27
10
85
 
11
86
  ### Changed
@@ -1,14 +1,14 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: avios-cli
3
- Version: 0.4.3
4
- Summary: A CLI and TUI for Avios balances, transactions, and BA reward-flight availability.
3
+ Version: 0.6.0
4
+ Summary: A CLI, TUI and MCP server for Avios balances, transactions, and BA reward-flight availability.
5
5
  Project-URL: Homepage, https://github.com/alexechoi/avios-cli
6
6
  Project-URL: Repository, https://github.com/alexechoi/avios-cli
7
7
  Project-URL: Issues, https://github.com/alexechoi/avios-cli/issues
8
8
  Author: Alex Choi
9
9
  License-Expression: MIT
10
10
  License-File: LICENSE
11
- Keywords: avios,british-airways,cli,loyalty,terminal,tui
11
+ Keywords: avios,british-airways,cli,loyalty,mcp,terminal,tui
12
12
  Classifier: Development Status :: 3 - Alpha
13
13
  Classifier: Environment :: Console
14
14
  Classifier: Intended Audience :: End Users/Desktop
@@ -31,6 +31,8 @@ Requires-Dist: rich>=13.7
31
31
  Requires-Dist: textual>=0.80
32
32
  Requires-Dist: typer>=0.12
33
33
  Provides-Extra: login
34
+ Provides-Extra: mcp
35
+ Requires-Dist: mcp<3,>=2.0; extra == 'mcp'
34
36
  Description-Content-Type: text/markdown
35
37
 
36
38
  # avios-cli
@@ -39,10 +41,10 @@ Description-Content-Type: text/markdown
39
41
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
40
42
  [![Python](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/)
41
43
 
42
- A **CLI and TUI for your Avios programmes** — check balances, browse transactions,
43
- and search British Airways reward-flight availability without leaving the terminal.
44
- British Airways, Iberia, and Aer Lingus use avios.com; Finnair Plus uses Finnair's
45
- own OAuth and loyalty API.
44
+ A **CLI, TUI and MCP server for your Avios programmes** — check balances, browse
45
+ transactions, and search British Airways reward-flight availability without leaving
46
+ the terminal, or hand the same data to an AI agent. British Airways, Iberia, and
47
+ Aer Lingus use avios.com; Finnair Plus uses Finnair's own OAuth and loyalty API.
46
48
 
47
49
  > ⚠️ **Unofficial.** This project is not affiliated with, authorised by, or endorsed by
48
50
  > Avios, British Airways, Finnair or IAG Loyalty. It drives the same private endpoints
@@ -130,10 +132,12 @@ Each programme session is stored at `~/.config/avios/accounts/<programme>.json`
130
132
  `avios logout <programme>` for one account or `avios logout` for all accounts.
131
133
  For BA, browser-assisted login also opens the separate reward-flight application.
132
134
  British Airways may show a second login prompt; keep the browser open until the
133
- CLI confirms success. Reward searches drive the site's own form in a background
134
- Chrome window because the flight-search route rejects plain HTTP and automated
135
- headless requests, so the `login` extra remains required when running
136
- `avios flights` or the Reward Flights TUI tab.
135
+ CLI confirms success. Reward searches run inside a background Chrome window: the
136
+ flight finder is behind Akamai Bot Manager, which rejects plain HTTP clients and
137
+ **blocks by IP address** — a handful of ordinary page loads from a shared office
138
+ network is enough to earn a site-wide 403. Every leg of a search is therefore
139
+ batched through a single browser navigation, paced, and served by in-page
140
+ `fetch()` calls. If you do get blocked, wait a few minutes and switch network.
137
141
 
138
142
  ## Usage
139
143
 
@@ -150,9 +154,9 @@ avios overview # dashboard summary
150
154
  avios whoami # name, tier, membership, email
151
155
  avios raw /shell/api/users/current/accounts # hit any endpoint directly
152
156
 
153
- # Direct British Airways reward-seat availability:
154
- avios flights LON ABZ --date 2026-11-05
155
- avios flights LON ABZ --date 2026-11-05 --return-date 2026-11-12
157
+ # Direct British Airways reward-seat availability (--date also prices in Avios):
158
+ avios flights LON HKG --date 2027-01-05
159
+ avios flights LON HKG --date 2027-01-05 --return-date 2027-01-12
156
160
  avios flights LON ABZ --month 2026-11 --cabin economy --cabin business
157
161
  avios flights LON ABZ --month 2026-11 --return-month 2026-12 --json
158
162
  ```
@@ -176,10 +180,48 @@ A tabbed full-screen application:
176
180
  Press `r` to refresh the dashboard and `q` to quit. Reward searches run only when
177
181
  you press Search or Enter.
178
182
 
179
- Reward search is an unofficial, availability-only view. It currently supports
180
- direct BA flights, three-letter airport/city codes, and seat counts by cabin. It
181
- does not price, book, or show taxes/fees or connecting flights. Return journeys
182
- are two independent one-way searches.
183
+ ## MCP server
184
+
185
+ Expose your accounts to Claude and other MCP clients, read-only:
186
+
187
+ ```bash
188
+ uv tool install 'avios-cli[mcp]'
189
+ avios login ba # sessions come from the CLI; the server never logs in
190
+ ```
191
+
192
+ ```jsonc
193
+ // Claude Desktop: claude_desktop_config.json
194
+ {
195
+ "mcpServers": {
196
+ "avios": { "command": "avios-mcp" }
197
+ }
198
+ }
199
+ ```
200
+
201
+ Or, for Claude Code:
202
+
203
+ ```bash
204
+ claude mcp add avios -- uvx --from 'avios-cli[mcp]' avios-mcp
205
+ ```
206
+
207
+ Tools: `list_accounts`, `get_balance`, `get_transactions`,
208
+ `get_pending_transactions`, `whoami`, `search_reward_flights`.
209
+
210
+ Every tool is read-only — nothing books, spends, or changes a session — and no
211
+ cookie or token is ever returned. `search_reward_flights` searches a whole return
212
+ trip in one call and is rate-limited server-side, because it drives a real browser
213
+ and British Airways blocks by IP address; an agent looping over routes could get
214
+ you locked out of the site.
215
+
216
+ ## Notes on reward search
217
+
218
+ Reward search is an unofficial view of BA's own flight finder. It supports direct
219
+ BA flights, three-letter airport/city codes, and seat counts by cabin. Searching
220
+ an exact `--date` also fetches the Avios price per cabin for your party; calendar
221
+ (month) searches show seats only, which keeps them to one request per leg. Seats
222
+ that need a BA companion voucher are marked `†`. It does not book, and it does
223
+ not show taxes/fees or connecting flights. Return journeys are two reverse-route
224
+ one-way searches sharing one browser session.
183
225
 
184
226
  ## Roadmap
185
227
 
@@ -191,6 +233,8 @@ are two independent one-way searches.
191
233
  - [x] Textual TUI dashboard
192
234
  - [x] Multiple accounts (BA, Iberia, Aer Lingus, Finnair) with combined views
193
235
  - [x] British Airways reward-flight **availability** search (CLI + TUI)
236
+ - [x] Avios pricing per cabin for an exact date
237
+ - [x] MCP server (`avios-mcp`) for AI agents
194
238
 
195
239
  ## Development
196
240
 
@@ -4,10 +4,10 @@
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
5
5
  [![Python](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/)
6
6
 
7
- A **CLI and TUI for your Avios programmes** — check balances, browse transactions,
8
- and search British Airways reward-flight availability without leaving the terminal.
9
- British Airways, Iberia, and Aer Lingus use avios.com; Finnair Plus uses Finnair's
10
- own OAuth and loyalty API.
7
+ A **CLI, TUI and MCP server for your Avios programmes** — check balances, browse
8
+ transactions, and search British Airways reward-flight availability without leaving
9
+ the terminal, or hand the same data to an AI agent. British Airways, Iberia, and
10
+ Aer Lingus use avios.com; Finnair Plus uses Finnair's own OAuth and loyalty API.
11
11
 
12
12
  > ⚠️ **Unofficial.** This project is not affiliated with, authorised by, or endorsed by
13
13
  > Avios, British Airways, Finnair or IAG Loyalty. It drives the same private endpoints
@@ -95,10 +95,12 @@ Each programme session is stored at `~/.config/avios/accounts/<programme>.json`
95
95
  `avios logout <programme>` for one account or `avios logout` for all accounts.
96
96
  For BA, browser-assisted login also opens the separate reward-flight application.
97
97
  British Airways may show a second login prompt; keep the browser open until the
98
- CLI confirms success. Reward searches drive the site's own form in a background
99
- Chrome window because the flight-search route rejects plain HTTP and automated
100
- headless requests, so the `login` extra remains required when running
101
- `avios flights` or the Reward Flights TUI tab.
98
+ CLI confirms success. Reward searches run inside a background Chrome window: the
99
+ flight finder is behind Akamai Bot Manager, which rejects plain HTTP clients and
100
+ **blocks by IP address** — a handful of ordinary page loads from a shared office
101
+ network is enough to earn a site-wide 403. Every leg of a search is therefore
102
+ batched through a single browser navigation, paced, and served by in-page
103
+ `fetch()` calls. If you do get blocked, wait a few minutes and switch network.
102
104
 
103
105
  ## Usage
104
106
 
@@ -115,9 +117,9 @@ avios overview # dashboard summary
115
117
  avios whoami # name, tier, membership, email
116
118
  avios raw /shell/api/users/current/accounts # hit any endpoint directly
117
119
 
118
- # Direct British Airways reward-seat availability:
119
- avios flights LON ABZ --date 2026-11-05
120
- avios flights LON ABZ --date 2026-11-05 --return-date 2026-11-12
120
+ # Direct British Airways reward-seat availability (--date also prices in Avios):
121
+ avios flights LON HKG --date 2027-01-05
122
+ avios flights LON HKG --date 2027-01-05 --return-date 2027-01-12
121
123
  avios flights LON ABZ --month 2026-11 --cabin economy --cabin business
122
124
  avios flights LON ABZ --month 2026-11 --return-month 2026-12 --json
123
125
  ```
@@ -141,10 +143,48 @@ A tabbed full-screen application:
141
143
  Press `r` to refresh the dashboard and `q` to quit. Reward searches run only when
142
144
  you press Search or Enter.
143
145
 
144
- Reward search is an unofficial, availability-only view. It currently supports
145
- direct BA flights, three-letter airport/city codes, and seat counts by cabin. It
146
- does not price, book, or show taxes/fees or connecting flights. Return journeys
147
- are two independent one-way searches.
146
+ ## MCP server
147
+
148
+ Expose your accounts to Claude and other MCP clients, read-only:
149
+
150
+ ```bash
151
+ uv tool install 'avios-cli[mcp]'
152
+ avios login ba # sessions come from the CLI; the server never logs in
153
+ ```
154
+
155
+ ```jsonc
156
+ // Claude Desktop: claude_desktop_config.json
157
+ {
158
+ "mcpServers": {
159
+ "avios": { "command": "avios-mcp" }
160
+ }
161
+ }
162
+ ```
163
+
164
+ Or, for Claude Code:
165
+
166
+ ```bash
167
+ claude mcp add avios -- uvx --from 'avios-cli[mcp]' avios-mcp
168
+ ```
169
+
170
+ Tools: `list_accounts`, `get_balance`, `get_transactions`,
171
+ `get_pending_transactions`, `whoami`, `search_reward_flights`.
172
+
173
+ Every tool is read-only — nothing books, spends, or changes a session — and no
174
+ cookie or token is ever returned. `search_reward_flights` searches a whole return
175
+ trip in one call and is rate-limited server-side, because it drives a real browser
176
+ and British Airways blocks by IP address; an agent looping over routes could get
177
+ you locked out of the site.
178
+
179
+ ## Notes on reward search
180
+
181
+ Reward search is an unofficial view of BA's own flight finder. It supports direct
182
+ BA flights, three-letter airport/city codes, and seat counts by cabin. Searching
183
+ an exact `--date` also fetches the Avios price per cabin for your party; calendar
184
+ (month) searches show seats only, which keeps them to one request per leg. Seats
185
+ that need a BA companion voucher are marked `†`. It does not book, and it does
186
+ not show taxes/fees or connecting flights. Return journeys are two reverse-route
187
+ one-way searches sharing one browser session.
148
188
 
149
189
  ## Roadmap
150
190
 
@@ -156,6 +196,8 @@ are two independent one-way searches.
156
196
  - [x] Textual TUI dashboard
157
197
  - [x] Multiple accounts (BA, Iberia, Aer Lingus, Finnair) with combined views
158
198
  - [x] British Airways reward-flight **availability** search (CLI + TUI)
199
+ - [x] Avios pricing per cabin for an exact date
200
+ - [x] MCP server (`avios-mcp`) for AI agents
159
201
 
160
202
  ## Development
161
203