Skip to main content
Glama
gsypolt

MFL MCP Server

by gsypolt

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) server for 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

  2. Find your MFL info (API client, League ID, API key, franchise ID)

  3. Install Node.js and run the setup wizard

  4. Connect your AI app

  5. On-demand vs. scheduled routines

  6. Multiple leagues and previous seasons

  7. Hosted mode (for cloud routines, claude.ai, and ChatGPT)

  8. What the AI can do (tools)

  9. Privacy and security

  10. Troubleshooting

  11. For developers


Related MCP server: Sleeper MCP Server

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.

  2. Open MFL's API client page: 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 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 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:

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 to change them later.

Check everything works at any time:

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:

    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:

    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, ChatGPT, and cloud routines need more: they can't start programs on your computer, so they need 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 if you don't have it, and sign in.

  2. Go to this project's Releases page 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)

    • 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:

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

    (From a local copy: 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.

    {
      "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 for other options):

    • Mac/Linux:

      curl -fsSL https://claude.ai/install.sh | bash
    • Windows (PowerShell):

      irm https://claude.ai/install.ps1 | iex
    • Or with npm (needs the Node.js you installed in step 3):

      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. If it finds Claude Code, answer Y and it runs the command below for you. Otherwise, add the server yourself:

    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, 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 first. Then:

  1. Go to 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 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 → 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 below.

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:

      curl -fsSL https://antigravity.google/cli/install.sh | bash
    • Windows (PowerShell):

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

    (Prefer the desktop app? Download it from 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 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:

    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.

    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:

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

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

  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.

  1. Install Gemini CLI if you don't have it (needs the Node.js you installed in step 3):

    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, 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 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:

    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 (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:

{
  "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 (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 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, 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

{
  "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:

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 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 (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. 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); 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 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 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, or sign in with a paid Gemini API key. See 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) 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 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, 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).

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 (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.

Available Tools

14 tools
mfl_exportCall any MFL export request (advanced)A
Read-onlyIdempotent

Read-only escape hatch: call any MyFantasyLeague export request TYPE and get the raw JSON. Use this only when no dedicated mfl_ tool covers the need, for example: projectedScores, tradeBait, pendingTrades, salaries, accounting, playoffBrackets, weeklyResults, topAdds, topDrops, adp, aav, nflSchedule, playerProfile, messageBoard, rules.

The league ID and API key are added automatically. Parameter names are CASE SENSITIVE and must match MFL's docs (e.g. W, P, FRANCHISE, POSITION). This tool cannot change anything in MFL.

Args:

  • type (string): MFL export TYPE, e.g. "projectedScores".

  • params (object, optional): extra query parameters, e.g. { "W": "5" }.

  • league_scoped (boolean, default true): false for site-wide types like adp, nflSchedule, playerProfile.

  • league, season: optional.

ParametersJSON Schema
NameRequiredDescriptionDefault
typeYesMFL export TYPE.
leagueNoWhich league: a configured alias (see mfl_list_leagues), league name, or numeric MFL league ID. Omit for the default league.
paramsNoExtra MFL parameters, e.g. { "W": "5" }.
seasonNoSeason year, e.g. 2025 for last season. Omit for the league's default (usually current) season.
league_scopedNofalse for site-wide types (adp, nflSchedule, playerProfile...).

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive/openWorld, so safety is partly covered. The description adds genuinely useful context beyond that: creds are injected automatically, parameter names are CASE SENSITIVE and must match MFL docs, and site-wide vs league-scoped behavior. It stops short of describing output shape or error behavior for arbitrary exports.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the core framing ('Read-only escape hatch') and organizes the rest into purpose, credentials, and an Args list. Most sentences earn their place, though 'cannot change anything in MFL' mildly repeats the readOnly/destructive annotations.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For an open-ended passthrough tool with no output schema (raw MFL JSON) and 5 params, the description covers the routing decision, credential handling, param naming rules, and the league_scoped toggle. It could note that the return payload varies by type, but is otherwise complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% so the baseline is 3, and the description pushes past it by warning that param names are case-sensitive and must match MFL docs (e.g. W, P, FRANCHISE), which is not stated in the schema. The example param object and league_scoped usage reinforce but largely restate the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('call any MFL export request TYPE and get the raw JSON') and explicitly positions itself as an 'escape hatch' distinct from the dedicated sibling tools. An agent can immediately tell it apart from mfl_get_* tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit when-to-use gate ('Use this only when no dedicated mfl_ tool covers the need') plus a concrete list of example types that map to common use cases. It names the alternative category (mfl_ tools) and the condition that selects this one over them.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

mfl_get_draft_resultsGet MFL draft resultsA
Read-onlyIdempotent

Get the league's draft results for a season (rookie/startup draft): round, pick, the team that picked, and the player selected. Unmade picks show as "on the clock / pending".

Args:

  • league, season: optional. Use season to look at a past draft.

  • franchise (string, optional): "mine", a franchise ID, or a team name.

  • response_format: 'markdown' (default) or 'json'.

ParametersJSON Schema
NameRequiredDescriptionDefault
leagueNoWhich league: a configured alias (see mfl_list_leagues), league name, or numeric MFL league ID. Omit for the default league.
seasonNoSeason year, e.g. 2025 for last season. Omit for the league's default (usually current) season.
franchiseNo"mine", a franchise ID, or a team name.
response_formatNo'markdown' for readable output (default) or 'json' for structured data.markdown

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/openWorld/non-destructive, so the safety profile is covered. The description adds genuine behavioral value by noting that unmade picks appear as 'on the clock / pending' and that the tool covers both rookie and startup drafts — output nuances not captured by annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose, then a compact Args block. Two sentences and a short list, each carrying distinct information with no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description compensates by naming the returned fields and the pending-pick state. Complete enough to invoke correctly; only the absence of explicit alternative-tool routing keeps it from a 5.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all four parameters are already fully documented in the schema. The description only restates them plus the past-draft hint, adding marginal meaning beyond what the schema provides; baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Get the league's draft results for a season') and enumerates the returned fields (round, pick, picking team, player). The 'rookie/startup draft' qualifier and the 'on the clock / pending' behavior clearly separate it from siblings like mfl_get_future_draft_picks.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It hints at usage ('Use season to look at a past draft') and documents the franchise shorthand, but it never says when to use this tool versus alternatives such as mfl_get_future_draft_picks or mfl_get_players, nor any prerequisites. Usage is implied rather than explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

mfl_get_free_agentsGet MFL free agentsA
Read-onlyIdempotent

List players available (not on any roster) in the league, sorted by year-to-date fantasy points under the league's own scoring rules. Covers offense and IDP.

Args:

  • league, season: optional.

  • position (string, optional): e.g. "LB", "S", "WR".

  • limit (1-200, default 25), offset (default 0).

  • response_format: 'markdown' (default) or 'json'.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMax results to return (1-200, default 25).
leagueNoWhich league: a configured alias (see mfl_list_leagues), league name, or numeric MFL league ID. Omit for the default league.
offsetNoResults to skip, for paging (default 0).
seasonNoSeason year, e.g. 2025 for last season. Omit for the league's default (usually current) season.
positionNoFilter to one position, e.g. "LB".
response_formatNo'markdown' for readable output (default) or 'json' for structured data.markdown

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (readOnlyHint, idempotentHint, destructiveHint=false), so the bar is lower. The description adds genuinely useful traits beyond them: results are sorted by year-to-date fantasy points under the league's own scoring rules, and coverage spans offense and IDP.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core purpose in one sentence, then a compact Args list. The Args block duplicates the schema somewhat, keeping it just short of maximally efficient, but nothing is padded or verbose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description does the necessary work of stating what comes back: available players ordered by league-scored fantasy points. Pagination and format are covered by the schema, so an agent has enough to call it correctly; only the alternative-tool routing is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so every parameter including ranges, defaults, and the response_format enum is already documented. The Args block mostly restates schema content (limit range, offset default) without adding filter syntax or semantics beyond it, which is the expected baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('List players available (not on any roster) in the league') plus the sort order and scope (offense and IDP), which distinguishes it from the generic sibling mfl_get_players. It never names the sibling explicitly, so the differentiation is inferable rather than stated.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The parenthetical '(not on any roster)' implies the use case (finding waiver-wire pickups), but the description gives no explicit when-to-use, when-not, or pointer to alternatives such as mfl_get_players. Usage is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

mfl_get_future_draft_picksGet MFL future draft picksA
Read-onlyIdempotent

Get the future rookie draft picks each franchise owns (year, round, and whose original pick it is). Essential for dynasty trade analysis.

Args:

  • league, season: optional.

  • franchise (string, optional): "mine", "all" (default), a franchise ID, or a team name.

  • response_format: 'markdown' (default) or 'json'.

ParametersJSON Schema
NameRequiredDescriptionDefault
leagueNoWhich league: a configured alias (see mfl_list_leagues), league name, or numeric MFL league ID. Omit for the default league.
seasonNoSeason year, e.g. 2025 for last season. Omit for the league's default (usually current) season.
franchiseNo"mine", "all" (default), a franchise ID, or a team name.
response_formatNo'markdown' for readable output (default) or 'json' for structured data.markdown

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare this a safe, idempotent, non-destructive read (readOnlyHint=true, idempotentHint=true), so the safety profile is covered. The description adds the returned data shape (year, round, original pick), which is useful, but says nothing about pagination, rate limits, or how the year/round filtering behaves.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The opening sentence is front-loaded and earns its place. The Args block is somewhat redundant with the already-complete schema descriptions, but overall it stays short and readable with no wasted preamble.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only tool with no output schema, the description compensates by naming the returned fields and the default franchise scope. It is nearly complete, missing only guidance on how it relates to the draft-results sibling.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so every parameter is already documented in the schema. The description's Args block restates the same franchise and response_format options rather than adding new semantics, which lands at the baseline 3.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Get the future rookie draft picks each franchise owns') and even enumerates the returned fields (year, round, original pick). It is clearly distinct from peers like mfl_get_roster or mfl_get_players, though it does not explicitly contrast itself with the closest sibling, mfl_get_draft_results.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'Essential for dynasty trade analysis' implies a use context, but there is no explicit when-to-use guidance, no exclusions, and no named alternative (e.g., mfl_get_draft_results for completed drafts). Usage must be inferred.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

mfl_get_injuriesGet NFL injury report for your MFL playersA
Read-onlyIdempotent

Get the NFL injury report (status like Out/Doubtful/Questionable/IR, injury details, expected return) filtered to the players you care about.

Args:

  • scope ('mine' | 'league' | 'all'): 'mine' = your roster (default when a franchise is configured), 'league' = every rostered player in the league with their fantasy owner, 'all' = entire NFL report.

  • week (number, optional): report for a given week; omit for the latest.

  • league, season: optional.

  • response_format: 'markdown' (default) or 'json'.

ParametersJSON Schema
NameRequiredDescriptionDefault
weekNoNFL week number (1-22). Omit for the current week.
scopeNo'mine' (default if configured), 'league', or 'all'.
leagueNoWhich league: a configured alias (see mfl_list_leagues), league name, or numeric MFL league ID. Omit for the default league.
seasonNoSeason year, e.g. 2025 for last season. Omit for the league's default (usually current) season.
response_formatNo'markdown' for readable output (default) or 'json' for structured data.markdown

TDQS

A4.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, so the safety profile is covered. The description adds useful conditional defaults (scope defaults to 'mine' when a franchise is configured, week omitted = latest) but says nothing about auth requirements, rate limits, or result size.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded one-sentence purpose followed by a compact Args block; every line carries information. Slight redundancy with the schema descriptions, but nothing is wasted and the structure is easy to scan.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description compensates by naming the returned fields (status, injury details, expected return) and the two response formats. Nothing critical is missing for a read-only report tool, though output shape and pagination limits are not spelled out.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3, but the description genuinely enriches the scope parameter beyond the schema's terse 'mine (default if configured), league, or all' by explaining what each mode returns (own roster vs. every rostered player with fantasy owner vs. entire NFL report). Week and response_format are only echoed from the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Get the NFL injury report') and immediately scopes it ('filtered to the players you care about'), which cleanly separates it from roster, standings, and player-lookup siblings. The parenthetical listing of status values (Out/Doubtful/Questionable/IR) further pins down what the resource contains.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The scope arg is effectively a when-to-use guide: 'mine' = your roster, 'league' = every rostered player with owner, 'all' = entire NFL report, plus the conditional default. It gives clear context for each mode but never names an alternative sibling tool or states when not to call this.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

mfl_get_leagueGet MFL league settings and teamsA
Read-onlyIdempotent

Get a league's name, every franchise (ID, team name, owner, division), roster size, taxi squad and IR slots, starting lineup requirements, and season weeks.

Use this to map franchise IDs to team names, or to answer questions about league rules and lineup requirements.

Args:

  • league (string, optional): alias, name, or numeric league ID. Default league if omitted.

  • season (number, optional): e.g. 2025.

  • response_format: 'markdown' (default) or 'json'.

ParametersJSON Schema
NameRequiredDescriptionDefault
leagueNoWhich league: a configured alias (see mfl_list_leagues), league name, or numeric MFL league ID. Omit for the default league.
seasonNoSeason year, e.g. 2025 for last season. Omit for the league's default (usually current) season.
response_formatNo'markdown' for readable output (default) or 'json' for structured data.markdown

TDQS

A4.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint, so the safety profile is fully covered. The description adds only the defaulting behavior for omitted league/season, which the schema itself already states, so incremental value is limited.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the returned payload in the first sentence, then usage, then an arg list. No filler sentences; each element carries information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description takes on the burden of describing return content and does so concretely (franchises, roster size, taxi/IR, lineup requirements, weeks). Nothing essential for correct invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so all three parameters are fully documented in the schema, including the alias/name/ID options and the enum for response_format. The description's restatement adds nothing beyond that; baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Get) and resource (league settings and teams) and enumerates the payload: name, franchises with ID/team name/owner/division, roster size, taxi/IR slots, lineup requirements, season weeks. An agent can distinguish it from mfl_get_roster or mfl_list_leagues without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly names two use cases: mapping franchise IDs to team names, and answering league-rule/lineup questions. Clear context for when to reach for this tool, but it does not name a competing sibling (e.g. mfl_get_roster for per-player rosters) to rule out.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

mfl_get_live_scoringGet MFL live scoringA
Read-onlyIdempotent

Get live (or final) fantasy scores for every matchup in a week, including players yet to play and game time remaining.

Args:

  • week (number, optional): omit for the current week.

  • league, season: optional.

  • response_format: 'markdown' (default) or 'json'.

ParametersJSON Schema
NameRequiredDescriptionDefault
weekNoNFL week number (1-22). Omit for the current week.
leagueNoWhich league: a configured alias (see mfl_list_leagues), league name, or numeric MFL league ID. Omit for the default league.
seasonNoSeason year, e.g. 2025 for last season. Omit for the league's default (usually current) season.
response_formatNo'markdown' for readable output (default) or 'json' for structured data.markdown

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, non-destructive and open-world, so the safety profile is covered. The description adds meaningful behavioral context beyond that: results include players who have not yet played and remaining game time, which tells the agent the payload is partially-projected live data, not a settled result.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the purpose in one sentence, followed by a compact Args list. The Args block is largely redundant with the schema but is short and harmless; nothing is padded or buried.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With annotations covering the safety profile, no required parameters, and no output schema, the definition supplies enough to invoke correctly: scope, defaults for all four optional params, and the markdown/json output switch. Only the routing rationale versus similarly named siblings is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so every parameter is already documented in the schema. The Args block essentially restates week/league/season/response_format without adding format, constraint, or resolution detail beyond it, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (get) and resource (live/final fantasy scores for every matchup in a week), plus notable scope detail (players yet to play, game time remaining). It distinguishes the live-scoring nature from statically-oriented siblings like mfl_get_player_scores, but never names an alternative explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives implied context (omit week for the current week, omit league/season for defaults) but never states when to prefer this over mfl_get_player_scores or mfl_get_standings. Usage is inferable from the purpose rather than spelled out.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

mfl_get_playersSearch MFL playersA
Read-onlyIdempotent

Search MFL's player database (all NFL players, offense and IDP) by name, position, NFL team, or player ID. Returns ID, name, position, team, age, draft year/round/pick, college, and (by default) which fantasy team in your league owns each player.

Use this to find player IDs for other tools, check ages and draft capital for dynasty decisions, or answer "who owns X?".

Args:

  • name (string, optional): full or partial name, e.g. "bijan" or "St. Brown".

  • positions (string, optional): comma list, e.g. "RB,WR" or "DE,DT,LB".

  • teams (string, optional): comma list of MFL team codes, e.g. "KCC,BUF". "FA" = NFL free agent.

  • player_ids (string, optional): comma list of MFL player IDs.

  • rookies_only (boolean, optional): only players drafted in the selected season.

  • owner (string, optional): only players on this fantasy team: "mine", a franchise ID, or a team name; or "available" for unrostered players.

  • sort ('name' | 'points', default 'name'): 'points' ranks by year-to-date fantasy points under the league's scoring and adds a points column.

  • include_ownership (boolean, default true): add the fantasy owner in this league (one extra API call).

  • league, season: optional (season selects that year's player database).

  • limit (1-200, default 25), offset (default 0).

  • response_format: 'markdown' (default) or 'json'.

At least one filter is recommended; the full database has thousands of players. Combine filters instead of fetching a big list and filtering it yourself:

  • "My top rookies by points" -> { rookies_only: true, owner: "mine", sort: "points" }

  • "Best available IDP linebackers" -> { positions: "LB", owner: "available", sort: "points" }

ParametersJSON Schema
NameRequiredDescriptionDefault
nameNoFull or partial player name.
sortNo'points' = year-to-date fantasy points, highest first.name
limitNoMax results to return (1-200, default 25).
ownerNo"mine", a franchise ID, a team name, or "available".
teamsNoComma list of MFL team codes, e.g. "KCC,BUF".
leagueNoWhich league: a configured alias (see mfl_list_leagues), league name, or numeric MFL league ID. Omit for the default league.
offsetNoResults to skip, for paging (default 0).
seasonNoSeason year, e.g. 2025 for last season. Omit for the league's default (usually current) season.
positionsNoComma list, e.g. "QB" or "DE,DT,LB".
player_idsNoComma list of MFL player IDs.
rookies_onlyNoOnly players drafted in the selected season.
response_formatNo'markdown' for readable output (default) or 'json' for structured data.markdown
include_ownershipNoShow which fantasy team owns each player.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive, so the safety profile is covered. The description adds genuine behavior context beyond that: include_ownership triggers 'one extra API call', sort:'points' adds a points column and ranks under league scoring, and season selects that year's player database.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded summary sentence followed by returns, then a per-arg list and two example call shapes. The arg bullets largely restate the 100%-covered schema, which is wasted length, but the added examples ('bijan', 'RB,WR') and defaults earn most of it back.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the return burden itself and does so: it enumerates returned fields (ID, name, position, team, age, draft year/round/pick, college, ownership), documents defaults for limit/offset/sort/response_format, and warns about the unfiltered result size.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3; the description still adds value with concrete formats and semantics ('FA' = NFL free agent, owner accepts 'mine'/franchise ID/team name/'available', rookies_only keyed to the selected season). Only mild redundancy with the schema keeps this from a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (search) and resource (MFL's player database) with explicit scope: all NFL players, offense and IDP. It also names the return fields and the primary downstream use (find player IDs for other tools), so an agent can distinguish it from mfl_get_roster or mfl_get_free_agents at a glance.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives strong when-to-use context: 'at least one filter is recommended; the full database has thousands of players' plus two worked filter combinations for common intents. It falls short of naming when to prefer a sibling such as mfl_get_free_agents, whose purpose overlaps with owner:'available'.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

mfl_get_player_scoresGet MFL fantasy points for playersA
Read-onlyIdempotent

Get fantasy points under the league's scoring rules for a week, year-to-date total, or season average. Filter to a franchise's roster, specific players, or a position.

Args:

  • period ('week' | 'ytd' | 'avg'): default 'ytd'. With 'week', pass week.

  • week (number, optional): used when period='week'. Omit for the current week.

  • franchise (string, optional): "mine", a franchise ID, or a team name to score only that roster.

  • player_ids (string, optional): comma list of MFL player IDs (use mfl_get_players to find IDs).

  • position (string, optional): e.g. "LB".

  • league, season: optional.

  • limit (1-200, default 25), offset (default 0).

  • response_format: 'markdown' (default) or 'json'.

ParametersJSON Schema
NameRequiredDescriptionDefault
weekNoNFL week number (1-22). Omit for the current week.
limitNoMax results to return (1-200, default 25).
leagueNoWhich league: a configured alias (see mfl_list_leagues), league name, or numeric MFL league ID. Omit for the default league.
offsetNoResults to skip, for paging (default 0).
periodNo'week', 'ytd' (default), or 'avg'.ytd
seasonNoSeason year, e.g. 2025 for last season. Omit for the league's default (usually current) season.
positionNoOne position, e.g. "RB".
franchiseNo"mine", a franchise ID, or a team name.
player_idsNoComma list of MFL player IDs.
response_formatNo'markdown' for readable output (default) or 'json' for structured data.markdown

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, openWorldHint and non-destructive, so the safety profile is fully covered. The description adds the default period (ytd), default limit (25), and the ID-lookup cross-reference, but discloses nothing about result ordering, pagination behavior, or scoring-rule edge cases.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded one-sentence purpose followed by a compact Args list; no filler sentences. The Args block is somewhat redundant with the 100%-covered schema but remains scannable and each line maps to a real parameter.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 10-parameter, all-optional read tool with a full input schema, no output schema, and complete annotations, the description supplies everything needed to invoke it correctly, including period/week coupling and the default response format.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all 10 parameters, and the Args block largely restates it. The only added value beyond the schema is the cross-reference to mfl_get_players for player IDs and the 'mine' shorthand for franchise, which is marginal.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Get) plus resource (fantasy points under the league's scoring rules) and the three temporal scopes (week/ytd/avg). It does not differentiate itself from siblings like mfl_get_live_scoring, so an agent must infer the boundary, but the purpose itself is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description lists filtering options (franchise, players, position) and notes mfl_get_players for ID lookup, which implies usage. However it never states when to prefer this over mfl_get_live_scoring or mfl_get_roster, and gives no explicit when-not conditions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

mfl_get_rosterGet MFL roster(s)A
Read-onlyIdempotent

Get the players on a franchise's roster (or every roster in the league), with player name, position (offense and IDP), NFL team, age, roster status (Active, Taxi, IR), and salary/contract fields when the league uses them.

Defaults to YOUR franchise when one is configured. Use franchise="all" to see every team (useful for "who owns X", trade targets, or league-wide positional depth).

Args:

  • league, season: optional. Use season to see a previous season's final rosters.

  • franchise (string, optional): "mine" (default), "all", a franchise ID like "0007", or a team/owner name.

  • week (number, optional): roster as of a specific week.

  • position (string, optional): only show this position, e.g. "QB", "LB", "S".

  • status (string, optional): 'active' | 'taxi' | 'ir' to filter roster status.

  • response_format: 'markdown' (default) or 'json'.

Examples:

  • "Show my roster" -> {}

  • "Who has the most linebackers?" -> { franchise: "all", position: "LB" }

  • "What did my taxi squad look like last year?" -> { season: 2025, status: "taxi" }

ParametersJSON Schema
NameRequiredDescriptionDefault
weekNoNFL week number (1-22). Omit for the current week.
leagueNoWhich league: a configured alias (see mfl_list_leagues), league name, or numeric MFL league ID. Omit for the default league.
seasonNoSeason year, e.g. 2025 for last season. Omit for the league's default (usually current) season.
statusNoFilter by roster status.
positionNoFilter to one position, e.g. "RB" or "LB".
franchiseNo"mine" (default), "all", a franchise ID, or a team/owner name.
response_formatNo'markdown' for readable output (default) or 'json' for structured data.markdown

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint/idempotentHint/openWorldHint and destructiveHint=false, so the safety profile is covered. The description adds real behavioral context beyond that: the franchise defaulting rule, the season-override semantics for retrieving historical rosters, and the conditional presence of salary/contract fields ('when the league uses them').

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose and default behavior, and the examples earn their space by showing argument composition. The Args block largely restates the JSON schema descriptions verbatim, which is mild redundancy that keeps it from a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With 7 optional parameters, no output schema, and a conditional-field payload, the description compensates by enumerating the returned fields and documenting defaults and history access. Nothing needed to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description goes further by decoding the polymorphic 'franchise' parameter into four accepted forms and by mapping natural-language queries to concrete argument combinations in the examples ('Who has the most linebackers?' -> { franchise: 'all', position: 'LB' }).

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb+resource ('Get the players on a franchise's roster (or every roster in the league)') plus an enumeration of the exact returned fields (name, position, NFL team, age, roster status, salary/contract). The scope statement implicitly separates it from siblings like mfl_get_players (whole player universe) and mfl_get_free_agents (unrostered players).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

States the default behavior ('Defaults to YOUR franchise when one is configured') and gives explicit conditions selecting alternatives ('Use franchise="all" to see every team' for ownership questions, trade targets, positional depth; 'Use season to see a previous season's final rosters'). No explicit exclusions against sibling tools, but the usage context is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

mfl_get_scheduleGet MFL league schedule and resultsB
Read-onlyIdempotent

Get fantasy matchups by week, with scores and results for completed weeks.

Args:

  • league, season: optional.

  • week (number, optional): a single week. Omit for the full season.

  • franchise (string, optional): "mine", a franchise ID, or a team name to show only that team's games. Default: all teams.

  • response_format: 'markdown' (default) or 'json'.

ParametersJSON Schema
NameRequiredDescriptionDefault
weekNoNFL week number (1-22). Omit for the current week.
leagueNoWhich league: a configured alias (see mfl_list_leagues), league name, or numeric MFL league ID. Omit for the default league.
seasonNoSeason year, e.g. 2025 for last season. Omit for the league's default (usually current) season.
franchiseNo"mine", a franchise ID like "0007", or a team name. Omit for all teams.
response_formatNo'markdown' for readable output (default) or 'json' for structured data.markdown

TDQS

B3.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, openWorldHint, and non-destructive behavior, so the safety profile is covered. The description usefully notes that scores/results apply to completed weeks, but it contradicts the schema by saying omitting week returns the full season (schema says current week), which undermines confidence.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded and readable, but the Args block largely duplicates a schema that already has 100% description coverage, adding length without new information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description should carry more of the return-value burden; it only says scores and results for completed weeks and mentions a markdown/json format. The contradictory week-omission guidance leaves a key behavior unclear.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline would be 3, but the description actively conflicts with the schema on the week parameter ('Omit for the full season' vs schema's 'Omit for the current week'). That contradiction makes it worse than simply repeating the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb and resource (get fantasy matchups) and scopes it by week and completed-week results. It is clearly distinct from siblings like standings, roster, or player scores, though it never explicitly names an alternative tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives per-parameter usage hints (omit week for full season, franchise accepts 'mine'/ID/name, response_format default) but offers no explicit when-to-use/when-not guidance relative to tools like mfl_get_live_scoring. Usage is implied rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

mfl_get_standingsGet MFL league standingsA
Read-onlyIdempotent

Get league standings: head-to-head record, points for, points against, division, division record, streak, and any extra columns the league tracks (all-play, power rating).

In leagues with divisions, the markdown output has one table per division (ranked within the division) followed by the overall table, so questions like "standings for each division" need only this tool.

Args:

  • league, season: optional; see mfl_list_leagues.

  • response_format: 'markdown' (default) or 'json'.

ParametersJSON Schema
NameRequiredDescriptionDefault
leagueNoWhich league: a configured alias (see mfl_list_leagues), league name, or numeric MFL league ID. Omit for the default league.
seasonNoSeason year, e.g. 2025 for last season. Omit for the league's default (usually current) season.
response_formatNo'markdown' for readable output (default) or 'json' for structured data.markdown

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, non-destructive, open-world, so the safety profile is covered. The description adds genuinely useful behavior beyond that: the markdown layout is one table per division ranked within division followed by the overall table, and that extra league-tracked columns may appear. Return-format behavior like this is exactly the value-add expected when annotations carry the rest.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with what the tool returns, then the non-obvious division-table behavior, then a compact Args list. No filler sentences, though the Args block partially duplicates the fully-described schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, so the description carries the return-value burden itself and does so: it names the stat columns and explains the per-division versus overall markdown structure. With all three parameters optional and fully schema-documented, an agent has everything needed to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and every parameter is documented in the schema, including the league alias/name/ID options and the season default. The Args block mostly restates that plus the response_format enum values, adding a pointer to mfl_list_leagues but little semantic detail the schema lacks. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a precise verb+resource ('Get league standings') and enumerates exactly which metrics come back (head-to-head record, points for/against, division record, streak, extra columns). An agent knows what it will receive, though it doesn't explicitly differentiate from potentially overlapping siblings like mfl_get_live_scoring or mfl_get_league.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a concrete when-to-use signal: for division standings questions, this single tool suffices because markdown emits one table per division plus an overall table. It also routes the agent to mfl_list_leagues for league/season arguments. What's missing is any explicit statement of when NOT to use it (e.g., live/in-progress scoring).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

mfl_get_transactionsGet MFL league transactionsA
Read-onlyIdempotent

Get recent league transactions (trades, free-agent adds/drops, waiver and blind-bid claims, IR and taxi moves) in plain English, with player names and decoded draft picks.

Args:

  • type (optional): TRADE, FREE_AGENT, WAIVER, BBID_WAIVER, IR, TAXI, AUCTION_WON, DRAFT, or ALL (default).

  • franchise (string, optional): "mine", a franchise ID, or a team name.

  • days (number, optional): only the last N days.

  • count (number, default 50): max transactions (1-500).

  • league, season: optional.

  • response_format: 'markdown' (default) or 'json'.

Examples:

  • "Any trades this week?" -> { type: "TRADE", days: 7 }

  • "What has Team X added lately?" -> { franchise: "Team X", type: "FREE_AGENT", days: 14 }

ParametersJSON Schema
NameRequiredDescriptionDefault
daysNoOnly the last N days.
typeNoTransaction type filter (default ALL).ALL
countNoMax transactions (default 50).
leagueNoWhich league: a configured alias (see mfl_list_leagues), league name, or numeric MFL league ID. Omit for the default league.
seasonNoSeason year, e.g. 2025 for last season. Omit for the league's default (usually current) season.
franchiseNo"mine", a franchise ID, or a team name.
response_formatNo'markdown' for readable output (default) or 'json' for structured data.markdown

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, non-destructive, open-world, so the safety profile is covered. The description adds genuinely non-structured context: results are rendered in plain English with resolved player names and decoded draft picks, and that `count` caps total output. It does not discuss pagination or truncation behavior beyond the count cap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core purpose, then a compact arg list, then two examples — each section earns its place and there is no filler. The arg list duplicates the schema somewhat, which keeps it from a perfect score.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-required-parameter, read-only query tool with rich annotations and a fully documented schema, the description covers purpose, filters, output format, and result rendering. With no output schema, the note about plain-English rendering and decoded draft picks fills the main gap; remaining omissions (pagination, empty-result behavior) are minor.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all seven parameters are already documented in the schema, and the description's arg list largely restates that (enum values, count range, defaults). The examples do add a little semantic value by showing how `franchise` accepts a team name and how filters combine, but the baseline of 3 applies when the schema carries the load.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource ('Get recent league transactions') and enumerates the transaction categories it covers (trades, adds/drops, waivers, IR, taxi). It also notes the output is 'plain English, with player names and decoded draft picks,' which is a real distinguishing trait. It stops short of naming which sibling (e.g., mfl_get_free_agents) to use instead for overlapping queries.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Two worked examples map natural-language questions ('Any trades this week?', 'What has Team X added lately?') directly onto argument combinations, which is strong usage guidance for an agent. There is no explicit when-not-to-use statement or pointer to a sibling for free-agent lookups, so it falls short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

mfl_list_leaguesList configured MFL leaguesA
Read-onlyIdempotent

List the MFL leagues and seasons this server is configured for: alias, league ID, your franchise ID, which seasons have an API key, and which league is the default.

Call this first when the user mentions a league by nickname, asks about "last season", or when another tool reports an unknown league or missing API key. Never returns API keys.

Args:

  • response_format ('markdown' | 'json'): default 'markdown'.

ParametersJSON Schema
NameRequiredDescriptionDefault
response_formatNo'markdown' for readable output (default) or 'json' for structured data.markdown

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive/closed-world, so the safety profile is covered. The description adds genuinely useful context beyond them: the precise returned fields and the security guarantee that API keys are never returned. It stops short of describing ordering or error behavior, so a 4 rather than 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose, then the when-to-use triggers, then args — a sound order with no wasted prose. The Args block duplicates the schema's own description nearly verbatim, which is minor redundancy rather than a structural flaw.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema present, the description compensates by enumerating the returned fields and their meaning, and it covers triggers, safety, and defaults. An agent has everything needed to call and interpret this tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the single parameter is fully documented with default and enum, so the schema carries this dimension. The description's Args section merely repeats response_format without adding format-specific syntax or guidance, so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb (list) + resource (MFL leagues/seasons) plus the exact fields returned (alias, league ID, franchise ID, seasons with API key, default league). This clearly separates it from siblings like mfl_get_league or mfl_get_standings, which fetch league content rather than server configuration.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states when to call it: first when the user names a league by nickname, references 'last season', or when another tool reports an unknown league or missing API key. This is a concrete when-to-use rule coupled to observable triggers, not vague advice.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 14 tool updatesv1.0.0
    • First observedmfl_export
    • First observedmfl_get_draft_results
    • First observedmfl_get_free_agents
    • First observedmfl_get_future_draft_picks
    • First observedmfl_get_injuries
    • First observedmfl_get_league
    • First observedmfl_get_live_scoring
    • First observedmfl_get_player_scores
    • First observedmfl_get_players
    • First observedmfl_get_roster
    • First observedmfl_get_schedule
    • First observedmfl_get_standings
    • First observedmfl_get_transactions
    • First observedmfl_list_leagues

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

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI models to manage and query fantasy sports leagues through the Sleeper API, supporting tasks like player lookups, league activity, and draft management.
    117 npm
    MIT
  • F
    license
    A
    quality
    D
    maintenance
    Enables natural language interaction with Sleeper Fantasy Football API data, allowing queries about leagues, players, matchups, draft results, and trade analysis.
    13
    25
    -
  • A
    license
    Not graded
    quality
    B
    maintenance
    Provides read-only access to Sleeper fantasy football leagues, enabling team snapshots, available players, matchups, trade context, and league history through standardized MCP tools.
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Provides read-only access to Yahoo Fantasy Football league data through MCP, letting ChatGPT retrieve rosters, standings, scoreboards, draft results, transactions, and player stats without making any roster changes.
    1
    -