Skip to main content
Glama
kevin0195

PointsYeah MCP Server

by kevin0195
README.md
# PointsYeah MCP Server (Python)

A Python MCP server that wraps [PointsYeah](https://pointsyeah.com) for award travel
search — rebuilt from the [original TypeScript implementation](https://github.com/pulsemcp/mcp-servers/tree/main/experimental/pointsyeah)
with additional tools.

---

## How it works

PointsYeah has no public API. Their search page encrypts parameters client-side
before sending them to `api2.pointsyeah.com`. This server handles that by:

1. **Auth** — Exchanges your Cognito refresh token (grabbed from the browser once)
   for short-lived access + ID tokens via AWS Cognito.
2. **Search task** — Launches a headless Playwright browser, injects your Cognito
   session cookies, navigates to the PointsYeah search URL, and intercepts the
   `create_task` API response to get a `task_id`.
3. **Polling** — Calls `api2.pointsyeah.com/flight/search/fetch_result` directly
   (plain HTTPS) until `status == "done"`, accumulating results in batches.

---

## Tools

| Tool | Auth needed | Description |
|------|:-----------:|-------------|
| `set_refresh_token` | — | Authenticate by providing your Cognito refresh token |
| `search_flights` | ✅ | Live award flight search across 20+ programs |
| `get_search_history` | ✅ | Your past PointsYeah searches |
| `compare_programs_for_route` | ✅ | Ranked points-cost table across all programs for a route |
| `estimate_points_value` | — | Estimate USD value of a points balance (offline CPP tables) |
| `calculate_cpp_breakeven` | — | Is a specific redemption worth it? (offline) |
| `get_server_status` | — | Server config and auth status |

---

## Installation

```bash
pip install mcp httpx playwright
python -m playwright install chromium
```

Python 3.10+ required.

---

## Getting your refresh token

1. Go to **https://www.pointsyeah.com/landing?route=signIn** and log in
2. Open **DevTools** (F12) → **Console** tab
3. Paste and run:
   ```js
   document.cookie.split('; ').find(c => c.includes('.refreshToken=')).split('=').slice(1).join('=')
   ```
4. Copy the long string output — that's your refresh token.

---

## Configuration

### Claude Desktop

Add to `~/.claude/claude_desktop_config.json` (macOS) or
`%APPDATA%\Claude\claude_desktop_config.json` (Windows):

```json
{
  "mcpServers": {
    "pointsyeah": {
      "command": "python",
      "args": ["/absolute/path/to/pointsyeah_mcp/server.py"],
      "env": {
        "POINTSYEAH_REFRESH_TOKEN": "your_refresh_token_here"
      }
    }
  }
}
```

You can also skip `POINTSYEAH_REFRESH_TOKEN` and call `set_refresh_token` in chat.

### Claude Code

```bash
cd pointsyeah_mcp
python server.py
```

---

## Example prompts

```
Find me business class award flights from JFK to Tokyo on October 1st, one-way.

Show me economy award options from SFO to London for 2 adults, returning Oct 15.

Compare all programs for LAX to Paris business class on November 10.

How much are my 80,000 Chase UR points worth if I use them for flights?

Is redeeming 60,000 United miles for a $900 ticket a good deal?

Show my past search history.
```

---

## Files

```
pointsyeah_mcp/
├── server.py      # MCP server + all tool definitions
├── auth.py        # Cognito token refresh
├── search.py      # Playwright task creation + result polling
├── state.py       # Server state (refresh token, cached tokens)
├── formatting.py  # Result formatters
└── README.md
```

---

## Notes

- Searches take **30–90 seconds** — PointsYeah queries 20+ airline programs in real time.
- Refresh tokens expire periodically. When one expires, repeat the browser step to get a new one.
- `estimate_points_value` and `calculate_cpp_breakeven` work fully offline — no token needed.