Skip to main content
Glama
gsypolt

MFL MCP Server

by gsypolt
README.md
# MFL MCP Server

**Talk to your MyFantasyLeague leagues from Claude, ChatGPT, Gemini, Cursor, and other AI assistants.**

This is a free, open-source [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server for [MyFantasyLeague.com](https://www.myfantasyleague.com) (MFL). Once connected, you can ask your AI assistant things like:

- "Show my roster and flag anyone injured."
- "Who owns Jahmyr Gibbs in my dynasty league?"
- "Which teams have the most 2027 first-round picks?"
- "List the top 10 free-agent linebackers by points this season."
- "Summarize every trade in my league over the last 30 days."
- "Compare my roster to Rival FC and suggest a fair trade."
- "What did my team look like at the end of last season?"

It works with **private leagues**, **dynasty and IDP leagues**, **multiple leagues**, and **current plus previous seasons**. It is **read-only**: it can never make moves, trades, or changes in MFL.

> Not affiliated with or endorsed by MyFantasyLeague.com. Please use the MFL API responsibly.

---

## Contents

1. [Choose your setup](#1-choose-your-setup)
2. [Find your MFL info (API client, League ID, API key, franchise ID)](#2-find-your-mfl-info)
3. [Install Node.js and run the setup wizard](#3-install-nodejs-and-run-the-setup-wizard)
4. [Connect your AI app](#4-connect-your-ai-app)
   - [Claude Desktop (one-click)](#claude-desktop-one-click-install) · [Claude Desktop (manual)](#claude-desktop-manual) · [Claude Code](#claude-code) · [Claude on the web and mobile](#claude-on-the-web-claudeai-and-mobile)
   - [ChatGPT](#chatgpt) · [Gemini CLI and Antigravity](#gemini) · [Cursor](#cursor) · [VS Code (GitHub Copilot)](#vs-code-github-copilot) · [Windsurf](#windsurf) · [Other apps](#other-apps)
5. [On-demand vs. scheduled routines](#5-on-demand-vs-scheduled-routines)
6. [Multiple leagues and previous seasons](#6-multiple-leagues-and-previous-seasons)
7. [Hosted mode (for cloud routines, claude.ai, and ChatGPT)](#7-hosted-mode)
8. [What the AI can do (tools)](#8-what-the-ai-can-do)
9. [Privacy and security](#9-privacy-and-security)
10. [Troubleshooting](#10-troubleshooting)
11. [For developers](#11-for-developers)

---

## 1. Choose your setup

There are two ways to run the server:

- **Local.** The server runs on your own computer, started automatically by your AI app whenever you use it. This is the easiest and most private option. Your API keys never leave your computer.
- **Hosted.** You run the server on a small cloud service and give your AI app a web address. You need this for apps that can only talk to web addresses (ChatGPT, Claude on the web/phone) and for routines that run in the cloud while your computer is off.

| AI app | Setup | Difficulty | Local or hosted |
|---|---|---|---|
| **Claude Desktop** | Download one file, double-click | ⭐ Easiest | Local |
| **Claude Desktop** (several leagues) | Setup wizard + paste a small config | ⭐⭐ | Local |
| **Claude Code** | Setup wizard + one command | ⭐⭐ | Local |
| **Claude web (claude.ai) and mobile** | Custom connector with a web address | ⭐⭐⭐ | Hosted |
| **ChatGPT** | Developer mode + custom connector | ⭐⭐⭐ | Hosted |
| **Google Antigravity** (Gemini with a personal Google account) | One install command + setup wizard (writes the config for you) | ⭐⭐ | Local |
| **Gemini CLI** (paid API key or work license only) | Setup wizard + paste a small config | ⭐⭐ | Local |
| **Cursor / VS Code / Windsurf** | Setup wizard + paste a small config | ⭐⭐ | Local |

**Not sure? Start with Claude Desktop.** Everything below is step by step.

---

## 2. Find your MFL info

You need up to four things from MFL. Write them down or keep the browser tab open.

### A. Register an MFL API client (one time)

MFL asks every app that uses its API to register a **client name**. The server sends that name with each request (as its `User-Agent`), so MFL knows who is calling. Unregistered clients may be throttled or blocked.

1. Log in at [myfantasyleague.com](https://www.myfantasyleague.com).
2. Open MFL's API client page: [`https://www41.myfantasyleague.com/2026/csetup?L=&C=APICLI`](https://www41.myfantasyleague.com/2026/csetup?L=&C=APICLI) (change `2026` to the current season if needed).
3. Register a client name, for example `mfl-mcp-yourname`, and write it down **exactly** as you entered it.

You only do this once. The same client name works for all your leagues and seasons.

### B. League ID

1. Log in at [myfantasyleague.com](https://www.myfantasyleague.com) and open your league.
2. Look at the web address in your browser. It looks like:
   `https://www47.myfantasyleague.com/2026/home/12345`
3. The **last number** (`12345` here) is your League ID. The `2026` is the season.

> The setup wizard also accepts the whole web address; it pulls out the League ID for you.

### C. API key (one per league, per season)

Private leagues need an API key. **Each season has its own key**, so if you want to look back at last season, you need last season's key too.

1. While logged in, open your league.
2. From the league menu choose **Help → Developer's API**. (You can also type this address, replacing the year and league ID: `https://api.myfantasyleague.com/2026/api_info?L=12345`.)
3. On that page, find the line that shows **your API key** for this league (it's labeled `APIKEY`). Copy the long string of letters and numbers.
4. **For a previous season:** change the year in the address (for example `2026` → `2025`), open the Developer's API page again, and copy that season's key.

> 🔒 Treat API keys like passwords. They let someone read your league's private data (not change it). Don't post them or commit them to GitHub.

> If your league is public, you can skip the API key.

### D. Franchise ID (your team's number)

This lets you say "my team" instead of your team name. **The easiest way is the setup wizard (next step): it shows a numbered list of teams and you pick yours.**

To find it by hand: in MFL, click your team name. The web address will include something like `F=0007`; `0007` is your franchise ID. IDs are four digits (`0001`, `0002`, ...).

---

## 3. Install Node.js and run the setup wizard

> **Skip this section** if you only use the one-click Claude Desktop install with a single league.

### Install Node.js (one time)

Node.js is the free engine that runs this server.

1. Go to [nodejs.org](https://nodejs.org) and download the **LTS** version for your computer.
2. Open the downloaded file and click through the installer with the default options.
3. Check it worked:
   - **Mac:** open **Terminal** (press ⌘+Space, type `Terminal`, press Enter).
   - **Windows:** open **PowerShell** (press the Windows key, type `PowerShell`, press Enter).
   - Type `node --version` and press Enter. You should see something like `v22.x.x`. Any version 20 or higher is fine.

### Run the setup wizard

In the same Terminal/PowerShell window, copy and paste this and press Enter:

```bash
npx -y mfl-mcp-server setup
```

The wizard asks for your MFL API client name, League ID, season, and API key, connects to MFL to check them, and shows your league's teams so you can pick yours. It then offers to add previous seasons (each with its own key) and more leagues. Finally, it detects which AI apps you have (Claude Desktop, Claude Code, Antigravity, Gemini CLI, Cursor, VS Code, Windsurf) and offers to connect them for you. At the end it saves everything to a file in your home folder:

- Mac/Linux: `~/.mfl-mcp/config.json`
- Windows: `C:\Users\<you>\.mfl-mcp\config.json`

It's outside this repo, so your keys are never committed. See [Reviewing and editing your settings](#reviewing-and-editing-your-settings) to change them later.

Check everything works at any time:

```bash
npx -y mfl-mcp-server doctor
```

You'll see a ✔ for each league and season that connected, or a ✘ with instructions to fix it.

### Running from a local copy (no npm or GitHub needed)

Use this if the package isn't on npm yet, or you're running your own modified copy. Your AI apps start the server straight from the folder on your computer; nothing needs to be pushed to GitHub or published.

1. Get the code: `git clone https://github.com/gsypolt/mfl-mcp-server.git`, or download and unzip it.
2. In that folder, build it once:

   ```bash
   cd mfl-mcp-server
   npm install
   npm run build
   ```

3. Everywhere this README says `npx -y mfl-mcp-server`, use `node dist/index.js` instead (run it from that folder). For example:

   ```bash
   node dist/index.js setup                              # the setup wizard
   node dist/index.js doctor                             # check your leagues
   node dist/index.js config claude-desktop --write      # connect an app
   ```

When run this way, `setup` and `config` automatically point your AI apps at this folder, using full paths to `node` and `dist/index.js`, so you don't have to edit any paths. After pulling new code, run `npm run build` again. If you move the folder or change Node versions (for example with nvm), re-run `node dist/index.js config <app> --write`.

> Only [Claude on the web/mobile](#claude-on-the-web-claudeai-and-mobile), ChatGPT, and cloud routines need more: they can't start programs on your computer, so they need [hosted mode](#7-hosted-mode).

---

## 4. Connect your AI app

After connecting, start a **new chat** and try: **"Show my MFL roster."**

### Claude Desktop (one-click install)

Best for a single league. No Node.js or wizard needed.

1. Install [Claude Desktop](https://claude.ai/download) if you don't have it, and sign in.
2. Go to this project's [**Releases** page](https://github.com/gsypolt/mfl-mcp-server/releases/latest) and download **`mfl-mcp-server.mcpb`**.
3. Double-click the downloaded file. Claude Desktop opens an install screen. (If double-clicking doesn't work, open Claude Desktop → **Settings → Extensions** and drag the file onto that window.)
4. Click **Install**, then fill in the form:
   - **MFL API client name** (from [step 2A](#a-register-an-mfl-api-client-one-time))
   - **League ID**, **Your franchise ID**, **Current season**
   - **API key (current season)**
   - **API key (previous season)** (optional)
   - **Config file** (optional): only if you ran the setup wizard for several leagues; choose your `config.json`.
5. Make sure the extension is switched **on**, then start a new chat.

### Claude Desktop (manual)

Use this if you ran the setup wizard (for example, for several leagues). If the wizard found Claude Desktop and you answered **Y**, this is already done: skip to step 3 below.

**Quickest: let the tool do it.**

1. **Fully quit** Claude Desktop (Mac: ⌘+Q; Windows: right-click the tray icon → Quit). It saves its own settings to the same file, so it could overwrite the change while running.
2. Run:

   ```bash
   npx -y mfl-mcp-server config claude-desktop --write
   ```

   (From a [local copy](#running-from-a-local-copy-no-npm-or-github-needed): `node dist/index.js config claude-desktop --write`.) This adds **mfl** to `claude_desktop_config.json` and keeps your other settings; the old file is saved as `claude_desktop_config.json.bak`.
3. Reopen Claude Desktop and click the tools/connectors icon in the chat box to confirm **mfl** is listed.

**Or edit the file yourself:**

1. Open Claude Desktop → **Settings → Developer → Edit Config**. This opens a file named `claude_desktop_config.json`.
2. Paste this in. If the file already has an `"mcpServers"` section, add just the `"mfl": {...}` part inside it.

   ```json
   {
     "mcpServers": {
       "mfl": {
         "command": "npx",
         "args": ["-y", "mfl-mcp-server"]
       }
     }
   }
   ```

3. Save the file, then **fully quit** Claude Desktop (Mac: ⌘+Q; Windows: right-click the tray icon → Quit) and reopen it.
4. Click the tools/connectors icon in the chat box to confirm **mfl** is listed.

> Tip: `npx -y mfl-mcp-server config claude-desktop` prints this snippet for you.

### Claude Code

Claude Code is Anthropic's terminal app (the `claude` command). It also powers the Claude Code extensions for VS Code and JetBrains, so adding the server here makes it available in those too.

1. **Install the Claude Code CLI** if you don't have it (see [Anthropic's setup guide](https://docs.claude.com/en/docs/claude-code/setup) for other options):
   - **Mac/Linux:**

     ```bash
     curl -fsSL https://claude.ai/install.sh | bash
     ```

   - **Windows (PowerShell):**

     ```powershell
     irm https://claude.ai/install.ps1 | iex
     ```

   - **Or with npm** (needs the Node.js you installed in step 3):

     ```bash
     npm install -g @anthropic-ai/claude-code
     ```

2. Check it worked: open a **new** Terminal/PowerShell window and run `claude --version`.
3. Run `claude` once and sign in with your Claude account when asked. Then type `/exit`.
4. Run the [setup wizard](#run-the-setup-wizard). If it finds Claude Code, answer **Y** and it runs the command below for you. Otherwise, add the server yourself:

   ```bash
   claude mcp add --scope user mfl -- npx -y mfl-mcp-server
   ```

   `--scope user` makes **mfl** available in every folder. Leave it off to add it only to the current project.

   From a [local copy](#running-from-a-local-copy-no-npm-or-github-needed), run `node dist/index.js config claude-code` instead: it prints this command with the full paths to your local build.
5. Confirm it's registered with `claude mcp list`, or start `claude` and type `/mcp`. **mfl** should show as connected.

### Claude on the web (claude.ai) and mobile

The web and phone apps can only connect to servers on the internet, so you'll need [hosted mode](#7-hosted-mode) first. Then:

1. Go to [claude.ai](https://claude.ai) → **Settings → Connectors**.
2. Click **Add custom connector**.
3. Name: `MFL`. URL: your hosted address, e.g. `https://your-app.onrender.com/mcp/YOUR_SECRET`.
4. Click **Add**. In a chat, open the tools menu and make sure **MFL** is turned on.

Connectors you add on claude.ai also appear in the Claude mobile apps. (Custom connector availability depends on your Claude plan; menu names can change over time.)

### ChatGPT

ChatGPT connects only to servers on the internet, so set up [hosted mode](#7-hosted-mode) first. You also need a plan that includes **developer mode** (at the time of writing: Plus, Pro, Business, Enterprise, or Edu, on the ChatGPT website). OpenAI moves these menus from time to time, so labels may differ slightly.

1. Go to [chatgpt.com](https://chatgpt.com) → **Settings → Apps** (or **Connectors**) → **Advanced settings**, and switch on **Developer mode**. On Business/Enterprise workspaces an admin may need to allow it first.
2. Back in **Settings → Apps** (or **Connectors**), click **Create**.
3. Fill in:
   - **Name:** `MFL`
   - **Description:** `My MyFantasyLeague fantasy football leagues: rosters, players, standings, transactions, draft picks.`
   - **MCP Server URL:** your hosted address, e.g. `https://your-app.onrender.com/mcp/YOUR_SECRET`
   - **Authentication:** **No authentication** (the secret in the web address protects it)
4. Tick the confirmation box and click **Create**.
5. In a new chat, click **+** → **Developer mode** (or **More**) and select **MFL**. Then ask about your roster.

### Gemini

To use Gemini with a personal Google account, use **Google Antigravity**. Since June 18, 2026, personal accounts (free, Google AI Pro, and Ultra) can't sign in to the older Gemini CLI. It fails with *"This client is no longer supported for Gemini Code Assist for individuals ... please migrate to the Antigravity suite."* Gemini CLI still works with a paid Gemini API key or a work Code Assist license; see [Gemini CLI](#gemini-cli-paid-api-key-or-work-account) below.

#### Google Antigravity (recommended)

Antigravity comes as a terminal app, **Antigravity CLI** (the `agy` command), and a desktop app (IDE). The CLI works on its own, without the IDE. Both read the same MCP settings file, so you only add **mfl** once.

1. **Install Antigravity CLI:**
   - **Mac/Linux:**

     ```bash
     curl -fsSL https://antigravity.google/cli/install.sh | bash
     ```

   - **Windows (PowerShell):**

     ```powershell
     irm https://antigravity.google/cli/install.ps1 | iex
     ```

   (Prefer the desktop app? Download it from [antigravity.google](https://antigravity.google) instead, or as well.)

2. **Sign in:** open a **new** terminal window and run `agy`. It opens your browser to sign in with your Google account. Once you're signed in, exit with Ctrl+C (inside `agy`, `?` lists all commands).

   > If you see `agy: command not found`, the installer put it in `~/.local/bin`, which isn't on your `PATH` yet. Run `echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc` (or `~/.bashrc`), then open a new window.

3. **Run the [setup wizard](#run-the-setup-wizard)** if you haven't already. At the end it lists the AI apps it found on your computer. Press Enter to connect them (or type `antigravity`), and answer **Y** to let it add **mfl** to Antigravity's settings and pre-approve the tools for you.

   Already ran the wizard? Just run:

   ```bash
   npx -y mfl-mcp-server config antigravity --write
   ```

   This does two things, keeping any settings already there (old files are saved with a `.bak` ending):

   - Adds **mfl** to `~/.gemini/config/mcp_config.json` (Windows: `C:\Users\<you>\.gemini\config\mcp_config.json`).
   - **Pre-approves the mfl tools** in `~/.gemini/antigravity-cli/settings.json` (`"allow": ["mcp(mfl/*)"]`), so `agy` doesn't ask permission every time. They're all read-only. It also adds a `deny` rule so the agent can't open `~/.mfl-mcp`, where your API keys are stored; the tools use the keys without the AI ever seeing them.

   > Running from a downloaded copy of this repo (before the package is on npm)? Use `node dist/index.js config antigravity --write` from the repo folder instead. It points Antigravity at your local build.

   <details>
   <summary>Prefer to edit the file yourself?</summary>

   Open `~/.gemini/config/mcp_config.json` (create the folder and file if needed), or use **Settings → Customizations → Installed MCP Servers** in the Antigravity app (IDE: **…** in the agent panel → **MCP Servers → Manage MCP Servers → View raw config**). Add:

   ```json
   {
     "mcpServers": {
       "mfl": {
         "command": "npx",
         "args": ["-y", "mfl-mcp-server"]
       }
     }
   }
   ```

   If the file already has an `"mcpServers"` section, add just the `"mfl": {...}` part inside it.
   </details>

4. **Check it:** start `agy` again (or restart the app) and type `/mcp`. **mfl** should be listed as connected.

5. **Ask away, from a normal folder.** Start `agy` from your home folder (`cd ~ && agy`), **not** from inside a code project like this repo. Inside a code folder, Antigravity treats "get my roster" as a coding task: it reads source files and writes scripts, and asks permission at every step. From your home folder it calls the mfl tools directly. Try **"Show my MFL roster."**

> If Antigravity says it can't find `npx`, open the config file and replace `"command": "npx"` with the full path: run `which npx` (Mac/Linux) or `where npx` (Windows).

#### Gemini CLI (paid API key or work account)

Only use this if you have a paid Gemini API key or a work Code Assist Standard/Enterprise license. Everyone else should use [Antigravity](#google-antigravity-recommended).

1. **Install Gemini CLI** if you don't have it (needs the Node.js you installed in [step 3](#install-nodejs-one-time)):

   ```bash
   npm install -g @google/gemini-cli@latest
   ```

   Check it worked with `gemini --version`.

   **Sign in.** Personal Google accounts no longer work here, so use one of these:

   - **Gemini API key (paid, billing enabled):** create a key in [Google AI Studio](https://aistudio.google.com/apikey), turn on billing for its project, then set it before starting Gemini CLI:
     - Mac/Linux: `export GEMINI_API_KEY="your-key"` (add it to `~/.zshrc` or `~/.bashrc` to keep it)
     - Windows (PowerShell): `setx GEMINI_API_KEY "your-key"`, then open a new window

     Run `gemini`, choose **Use Gemini API key** if asked, then type `/quit`.
   - **Work account with a Code Assist Standard/Enterprise license:** run `gemini`, choose **Sign in with Google**, and follow your organization's instructions.

2. Run the [setup wizard](#run-the-setup-wizard) if you haven't already.

3. **Add mfl to Gemini CLI's settings.** At the end of the setup wizard, include **`gemini-cli`** in the apps to connect and answer **Y**, or run:

   ```bash
   npx -y mfl-mcp-server config gemini-cli --write
   ```

   This adds **mfl** to `~/.gemini/settings.json` and keeps your other settings. To edit it by hand instead, add the same `"mcpServers"` block shown in the Antigravity steps above.

4. Start `gemini` and type `/mcp`. **mfl** should be listed as connected. Then try **"Show my MFL roster."**

#### Gemini web and mobile apps

These don't let you add your own MCP servers at the time of writing. Use Antigravity, or another app in this list.

### Cursor

After the setup wizard: open **Cursor Settings → MCP → Add new global MCP server** (this opens `~/.cursor/mcp.json`), paste the same block shown under [Antigravity](#google-antigravity-recommended) (or run `npx -y mfl-mcp-server config cursor --write`), save, and check that **mfl** shows a green dot.

### VS Code (GitHub Copilot)

After the setup wizard: open the Command Palette (Ctrl/⌘+Shift+P) → **MCP: Open User Configuration**, and paste:

```json
{
  "servers": {
    "mfl": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "mfl-mcp-server"]
    }
  }
}
```

Use Copilot Chat in **Agent** mode to call the tools.

### Windsurf

After the setup wizard: **Windsurf Settings → Cascade → MCP servers → View raw config** (`~/.codeium/windsurf/mcp_config.json`), paste the same block shown under [Antigravity](#google-antigravity-recommended) (or run `npx -y mfl-mcp-server config windsurf --write`), and refresh.

### Other apps

Any app that supports MCP can use this server:

- **Apps that start a local program** (most desktop and coding apps): command `npx`, arguments `-y mfl-mcp-server`.
- **Apps that take a web address:** use your [hosted](#7-hosted-mode) URL.

Run `npx -y mfl-mcp-server config all` to print ready-to-paste settings for every app listed here. For Claude Desktop, Antigravity, Gemini CLI, Cursor, and Windsurf, add `--write` (for example `config antigravity --write`) to have it update that app's settings file for you.

---

## 5. On-demand vs. scheduled routines

You don't turn on a separate "routine mode." The same server works both ways; what differs is **where the routine runs**.

| How you use it | What to set up |
|---|---|
| **On-demand:** you ask questions in a chat | Any local setup above. |
| **Scheduled tasks that run on your computer** (for example, scheduled tasks in the Claude Desktop app) | Local setup. Tasks run only while your computer is awake and the app is running. |
| **Routines that run in the cloud** (keep running while your computer is off), and ChatGPT/claude.ai | [Hosted mode](#7-hosted-mode), added as a connector on that service. |

The server includes three ready-made prompts that make good routines. In apps that show MCP prompts, you'll find them in the prompt or slash-command menu; in others, paste the text below as your scheduled task's instructions.

- **Daily roster check** (`mfl_daily_roster_check`):
  > Get my MFL roster, the injury report for my players, and league transactions from the last 2 days. For any position with an injured starter, list the top 5 free agents there. Report injuries first, then league moves, then pickup ideas.
- **Weekly recap** (`mfl_weekly_recap`):
  > Write a short, fun weekly recap of my MFL league: standings, every matchup result, my top and bottom scorers this week, and trades or adds from the last 7 days.
- **Trade prep** (`mfl_trade_prep`, asks for the other team):
  > Compare my roster, future picks, and points with [team]. Find each team's surplus and needs (offense and IDP), weigh player ages, and suggest 2-3 balanced dynasty offers.

---

## 6. Multiple leagues and previous seasons

### Where your settings and API keys are stored

The setup wizard saves everything (API client name, league IDs, franchise IDs, and **API keys**) to one file in your home folder, **not** in this repo or in any AI app's settings:

| System | File |
|---|---|
| Mac/Linux | `~/.mfl-mcp/config.json` |
| Windows | `C:\Users\<you>\.mfl-mcp\config.json` |

The file is created so only your user account can read it. The AI app configs (Claude Desktop, Antigravity, etc.) only contain the command that starts the server; the server reads your keys from this file when it starts. The folder also holds `cache/`, a copy of MFL's public player list (no keys).

### Reviewing and editing your settings

- **See what's set up without showing keys:** `npx -y mfl-mcp-server doctor` lists every league and season and checks each one against MFL. (In chat, "list my MFL leagues" shows the same list, without the connection check.)
- **Change things the easy way:** re-run `npx -y mfl-mcp-server setup`. Your other leagues are kept; entering a league with an existing nickname replaces that league's settings.
- **Edit the file directly:**
  - Mac: `open -e ~/.mfl-mcp/config.json` (TextEdit), or `code ~/.mfl-mcp/config.json` (VS Code), or `nano ~/.mfl-mcp/config.json` (terminal)
  - Windows: `notepad $HOME\.mfl-mcp\config.json`
  - Linux: `nano ~/.mfl-mcp/config.json`

  The file is shown below. Keep it valid JSON (quotes and commas matter).
- **After any change:** run `npx -y mfl-mcp-server doctor`, then fully quit and reopen your AI app (or restart `agy`) so the server re-reads the file.
- **Replacing a key** (new season, or a key you think was exposed): get the new key from the league's **Help → Developer's API** page for that season, and put it in `seasons."<year>".apiKey`, or re-run setup.

> 🔒 Don't paste this file or its keys into a chat, an issue, or a repo. Don't ask an AI agent to "look at my config"; use `doctor` instead, which never prints keys.

### File format

```json
{
  "userAgent": "YOUR_REGISTERED_CLIENT_NAME",
  "defaultLeague": "dynasty",
  "leagues": [
    {
      "alias": "dynasty",
      "name": "My Dynasty IDP League",
      "leagueId": "12345",
      "franchiseId": "0007",
      "defaultSeason": 2026,
      "seasons": {
        "2026": { "apiKey": "PASTE_2026_KEY" },
        "2025": { "apiKey": "PASTE_2025_KEY" }
      }
    },
    {
      "alias": "redraft",
      "leagueId": "67890",
      "franchiseId": "0003",
      "seasons": {
        "2026": { "apiKey": "PASTE_KEY" },
        "2025": { "apiKey": "PASTE_KEY", "leagueId": "54321", "franchiseId": "0011" }
      }
    }
  ]
}
```

| Field | Meaning |
|---|---|
| `alias` | Your nickname for the league. You can say "in my redraft league" in chat. |
| `leagueId` | MFL League ID. |
| `franchiseId` | Your team in that league (so "my team" works). Each league has its own. |
| `seasons` | One entry per season year, each with its own `apiKey`. Add `leagueId` or `franchiseId` inside a season if they were different that year (some commissioners start a new league each season). |
| `defaultSeason` | Season used when you don't mention one. Defaults to the newest season listed. |
| `defaultLeague` | League used when you don't mention one. |
| `userAgent` | Your registered MFL API client name (top level, shared by all leagues). |

In chat, just say which league and season you mean: *"Show the 2025 final standings in my redraft league."*

**Keeping keys out of the file (optional):** write `"apiKey": "env:MY_KEY_NAME"` and set an environment variable `MY_KEY_NAME` instead.

**Environment variables (single league, no file):** `MFL_USER_AGENT` (your registered client name), `MFL_LEAGUE_ID`, `MFL_FRANCHISE_ID`, `MFL_SEASON`, `MFL_API_KEY`, `MFL_PREVIOUS_SEASON_API_KEY`, `MFL_API_KEY_2024` (any year). Use `MFL_CONFIG=/path/to/file.json` to point at a config file somewhere else.

---

## 7. Hosted mode

Hosted mode runs the server on the internet so web-only apps (ChatGPT, claude.ai, phones) and cloud routines can use it. Your server is protected by a long **secret** that becomes part of its web address.

### Step 1: Create your secrets

On your own computer, after running the setup wizard:

```bash
npx -y mfl-mcp-server hosted-env
```

It prints two values, `MFL_MCP_SECRET` and `MFL_CONFIG_JSON`. Keep this window open; you'll paste them into your host. **Treat both like passwords.**

### Step 2: Deploy

Any service that can run a Docker container or a Node.js app works. Here is the general flow using [Render](https://render.com) as an example (Railway, Fly.io, and Google Cloud Run are similar):

1. Fork or push this repository to your GitHub account.
2. On Render: **New → Web Service → connect your GitHub repo**. Render detects the `Dockerfile` automatically.
3. Under **Environment**, add `MFL_MCP_SECRET` and `MFL_CONFIG_JSON` from Step 1, marked as secret.
4. Deploy. When it's live, open `https://<your-app>.onrender.com/healthz`; you should see `"ok": true`.
5. Your connector URL is: `https://<your-app>.onrender.com/mcp/<your MFL_MCP_SECRET>`

> Free tiers on some hosts "sleep" when idle, so the first request after a pause can take 30+ seconds. That's fine for routines; upgrade if it bothers you.

**Other ways to run hosted mode**

- **Docker anywhere:** `docker build -t mfl-mcp-server . && docker run -p 3000:3000 --env-file .env mfl-mcp-server` (see `.env.example`).
- **Node directly:** `MFL_MCP_SECRET=... MFL_HTTP_HOST=0.0.0.0 npx -y mfl-mcp-server serve --http --port 3000`
- **Quick test from your own computer** (only works while your computer is on): run `npx -y mfl-mcp-server serve --http`, then expose it with a tunnel such as [Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) (`cloudflared tunnel --url http://localhost:3000`), and set `MFL_MCP_SECRET` first.

Clients that support custom headers can use `https://<host>/mcp` with the header `Authorization: Bearer <MFL_MCP_SECRET>` instead of putting the secret in the address.

The server refuses to start on a public address without `MFL_MCP_SECRET`, so you can't accidentally expose your leagues.

---

## 8. What the AI can do

All tools are **read-only**. Every league tool accepts optional `league` (alias, name, or ID) and `season` (e.g. `2025`) arguments.

| Tool | What it answers |
|---|---|
| `mfl_list_leagues` | Which leagues/seasons are set up, your team in each, which have API keys |
| `mfl_get_league` | League settings, teams and owners, roster/taxi/IR sizes, starting lineup rules |
| `mfl_get_roster` | Your roster (default) or any/all teams', with position, NFL team, age, Active/Taxi/IR, salary and contract |
| `mfl_get_players` | Search all NFL players (offense and IDP) by name, position, or team; ages, draft capital, college, and who owns them |
| `mfl_get_standings` | Standings with record, points for and against |
| `mfl_get_schedule` | Matchups and results by week, for all teams or one |
| `mfl_get_transactions` | Trades, adds/drops, waivers, blind bids, IR/taxi moves, in plain English with draft picks decoded |
| `mfl_get_future_draft_picks` | Every team's future rookie picks, including acquired ones |
| `mfl_get_draft_results` | Rookie/startup draft results for any season |
| `mfl_get_injuries` | NFL injury report for your roster, all rostered players, or the whole NFL |
| `mfl_get_free_agents` | Available players ranked by points under your league's scoring |
| `mfl_get_player_scores` | Fantasy points by week, year to date, or average |
| `mfl_get_live_scoring` | Live matchup scores and players yet to play |
| `mfl_export` | Advanced: any other MFL *export* request (projections, trade bait, pending trades, ADP, and more) |

---

## 9. Privacy and security

- **Read-only by design.** The server only calls MFL's `export` API. It has no code that can submit lineups, trades, waivers, or any change.
- **Local mode keeps everything on your computer.** Your config file is created readable only by you. API keys are sent only to myfantasyleague.com.
- **API keys are never shown to the AI.** `mfl_list_leagues` reports only whether a key exists, and keys never appear in tool output.
- **Hosted mode** requires a secret; the server refuses to run publicly without one. Anyone with your full connector URL can read (not change) your configured leagues, so don't share it. If it leaks, change `MFL_MCP_SECRET` on your host and update the URL in your AI apps.
- **Your keys live outside the repo,** in `~/.mfl-mcp/config.json` (readable only by you). See [where settings are stored](#where-your-settings-and-api-keys-are-stored). AI app config files never contain keys.
- **Never commit real API keys.** `.gitignore` excludes `config.json`, `.env`, and `.mfl-mcp/`.
- **Hosted mode:** `hosted-env` *prints* your config (with keys) and a new secret for you to paste into your host's secret settings; it doesn't save them anywhere. Don't save them in a `.env` inside the repo folder.
- **Keep AI agents out of the file.** Coding agents that can read files (for example Antigravity started inside a code folder) may open `~/.mfl-mcp/config.json` and send your keys to the model. `config antigravity --write` adds a rule blocking this for Antigravity. If a key may have been exposed, replace it (see [Reviewing and editing](#reviewing-and-editing-your-settings)); keys can only read your league, not change it.
- **Be a good API citizen.** The server spaces out requests and caches the large player list for 12 hours. MFL monitors API usage and may throttle heavy callers. Always set your [registered client name](#a-register-an-mfl-api-client-one-time) as `"userAgent"` in your config (or `MFL_USER_AGENT`) so MFL can identify your requests.

---

## 10. Troubleshooting

| Problem | Fix |
|---|---|
| **"No API key is configured ... for the 2025 season"** | Each season needs its own key. Get that season's key from the league's Developer's API page (change the year in the address) and add it with the setup wizard. |
| **"API key ... was rejected"** | Re-copy the key, making sure you're viewing the right league **and season**. No extra spaces. |
| **"No franchiseId is configured"** | Re-run the setup wizard and pick your team, or add `"franchiseId": "0007"` to the league in `config.json`. |
| **The AI doesn't see the tools** | Fully quit and reopen the app after editing its config. Run `npx -y mfl-mcp-server doctor`. Make sure `node --version` shows 20 or newer. |
| **`npx` not found (Claude Desktop on Windows/Mac)** | Install Node.js from nodejs.org and restart your computer. If it still fails, replace `"command": "npx"` with the full path from `where npx` (Windows) or `which npx` (Mac). |
| **Requests blocked, or `doctor` warns "No registered MFL API client name"** | [Register an API client](#a-register-an-mfl-api-client-one-time) and enter the name exactly as registered: re-run the setup wizard, or set `"userAgent"` / `MFL_USER_AGENT`. |
| **Gemini CLI: "This client is no longer supported for Gemini Code Assist for individuals"** | Google ended personal-account sign-in for Gemini CLI. Switch to [Antigravity](#google-antigravity-recommended), or sign in with a paid Gemini API key. See [Gemini](#gemini). |
| **Antigravity reads files, runs `node`/`ls`, or writes scripts instead of answering** | **mfl** isn't connected (check `/mcp`; an empty `~/.gemini/config/mcp_config.json` means it was never added), or you started `agy` inside a code folder. Run `npx -y mfl-mcp-server config antigravity --write`, then start `agy` from your home folder. |
| **`agy: command not found`** | Add `~/.local/bin` to your `PATH` (see [Antigravity step 2](#google-antigravity-recommended)) and open a new terminal window. |
| **"MFL is rate-limiting requests"** | Wait a minute. Game-day afternoons are busiest; ask broader questions rather than many small ones. |
| **Wrong or empty data for a past season** | League IDs sometimes change between seasons. Add the older `leagueId` inside that season in `config.json`. MFL also supports some features only for the current year. |
| **Hosted: 401 Unauthorized** | The secret in your connector URL doesn't match `MFL_MCP_SECRET` on your host. |
| **Hosted: first request is slow** | Your host's free tier was asleep; it wakes in 30-60 seconds. |

Still stuck? [Open an issue](https://github.com/gsypolt/mfl-mcp-server/issues) with the output of `npx -y mfl-mcp-server doctor`. **Remove your API keys before posting.**

---

## 11. For developers

**Stack:** TypeScript, the official [MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk), Zod, and Express. It supports stdio (local) and stateless Streamable HTTP (hosted) transports, and ships as an npm package, a Docker image, and a Claude Desktop bundle (`.mcpb`).

```bash
git clone https://github.com/gsypolt/mfl-mcp-server.git
cd mfl-mcp-server
npm install
npm run build
npm test                       # end-to-end test against a mocked MFL API
npm run inspect                # MCP Inspector UI against the local build
node dist/index.js doctor      # live check against your real leagues
```

```
src/
  index.ts          CLI router: stdio (default), serve --http, setup, doctor, config, hosted-env
  server.ts         McpServer factory: tools, prompts, instructions
  http.ts           Stateless Streamable HTTP transport with secret-path / bearer auth
  config.ts         Config file + env loading, league/season/API-key resolution
  mfl/client.ts     Read-only MFL export client: host discovery, throttling, actionable errors
  mfl/players.ts    Player database cache (memory + disk, 12h)
  mfl/league.ts     League info cache, franchise resolution ("mine", ID, or team name)
  mfl/normalize.ts  MFL JSON quirks (single-item lists, $t text nodes, "Last, First" names)
  tools/*.ts        Tool implementations
manifest.json       Claude Desktop bundle (MCPB) manifest
evaluations/        LLM evaluation questions (fill in answers for your league)
```

**Releasing:** push a tag like `v1.0.1`. The Release workflow runs tests, publishes to npm (if the `NPM_TOKEN` repo secret is set), builds `mfl-mcp-server.mcpb`, and attaches it to a GitHub Release. Keep the version in `package.json`, `manifest.json`, and `src/constants.ts` in sync.

**Before npm publish:** until the package is on npm, users can [run from a local copy](#running-from-a-local-copy-no-npm-or-github-needed) (`node dist/index.js ...`), or replace `npx -y mfl-mcp-server` with `npx -y github:gsypolt/mfl-mcp-server` once the repo is public (slower first run, since it builds from source).

Contributions welcome. Please keep the server read-only.

---

## About

Built by a dynasty IDP player who wanted his AI assistant to actually know his league. Coming soon: **Dynasty Front Office**, a front office for dynasty leagues with MFL league import. ⭐ Star this repo to hear about it.

MIT licensed. MyFantasyLeague is a trademark of its owner; this project is independent and unofficial.

TDQS

A4/5.0

Scored across 14 tools

Disambiguation4/5

Most tools target a distinct MFL resource or action, but mfl_get_free_agents overlaps heavily with mfl_get_players using owner='available' and sort='points'; mfl_get_schedule and mfl_get_live_scoring also share completed-week matchup scoring. Descriptions help, but an agent could reasonably choose either in those cases.

Naming Consistency5/5

All tools use the mfl_ prefix with snake_case names and a predictable get/list/export verb pattern. The lone generic mfl_export still fits the namespace and read-only retrieval convention.

Tool Count5/5

14 tools is well-scoped for a fantasy-league data server, covering the main domains without obvious filler. The dedicated tools and one escape hatch are reasonable for the breadth of MFL exports.

Completeness5/5

The surface covers leagues, franchises, players, rosters, schedules, standings, drafts, future picks, transactions, injuries, free agents, scoring, live scoring, and a generic export fallback. For a read-only MFL analytics server, this leaves no major dead ends.

Maintenance

ActivityMaintained
ResponsivenessNo issues