Skip to main content
Glama
moonie0201
by moonie0201
README.md
# apify-utils-mcp

Four small utilities behind one MCP server: **PDF text, tables and OCR**, **YouTube
thumbnail URLs and files**, **sports scores and standings**, and **ATP/WTA tennis**.

Each tool is a thin client over a public [Apify](https://apify.com) Actor. Runs are
billed by Apify to **your own** account — see [Pricing](#pricing). This server never
proxies a call, never sees your token or your results, and never pays for a run on your
behalf.

## Install

Requires [uv](https://docs.astral.sh/uv/) and a free
[Apify](https://console.apify.com/settings/integrations) token.

```json
{
  "mcpServers": {
    "apify-utils": {
      "command": "uvx",
      "args": ["--from", "git+https://github.com/moonie0201/apify-utils-mcp", "apify-utils-mcp"],
      "env": { "APIFY_TOKEN": "apify_api_..." }
    }
  }
}
```

| Client | Where that JSON goes |
|---|---|
| Claude Desktop | `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) · `%APPDATA%\Claude\claude_desktop_config.json` (Windows) |
| Cursor | `~/.cursor/mcp.json`, or `.cursor/mcp.json` in a project |
| Claude Code | `claude mcp add apify-utils --env APIFY_TOKEN=apify_api_... -- uvx --from git+https://github.com/moonie0201/apify-utils-mcp apify-utils-mcp` |

## Tools

| Tool | What it does | Spend cap | Cost |
|---|---|---|---|
| `extract_pdf(urls, max_pages, output_mode?, page_range?, max_pages_per_pdf?, include_markdown?, extract_tables?, ocr?, max_ocr_pages_per_pdf?, chunk_size?, chunk_overlap?)` | Text, markdown and ruled tables per page, per document, or as RAG chunks with page and character offsets. Optional Tesseract OCR for pages with no text layer. | `max_pages` | $0.0003/page, $0.003/OCR page |
| `youtube_thumbnails(videos, max_videos, sizes?, image_format?, include_metadata?, save_images?)` | Thumbnail URLs (jpg and webp) for video URLs or bare IDs, with per-size availability, bytes and etag from a HEAD probe, plus title and channel. Optionally saves the files to your own key-value store. | `max_videos` | $0.005/video |
| `sports_scores(leagues, max_items, mode?, date_from?, date_to?, teams?, status?, season?, season_type?, event_ids?, include_odds?, timezone?)` | Scores, schedules, standings, team directories and game summaries across 33 leagues. | `max_items` | $0.002/game · $0.001/standings or team row · $0.004/summary |
| `tennis_scores(max_items, tours?, date_from?, date_to?, player?, status?, timezone?)` | ATP and WTA matches with per-set scores, round, seeds, country, court and result text. | `max_items` | $0.002/match |
| `list_supported_utilities()` | Every tool, the Actor behind it, its exact per-event price and its spend-cap argument. | — | free, no network |

Filters (`page_range`, `teams`, `status`, `max_pages_per_pdf`) are applied **before**
billing, so a narrow query is cheap rather than a big response you post-filter. The
spend-cap argument is required on every paid tool — there is no way to start an
unbounded run from here.

## Pricing

No Actor here charges a start fee, so a run that fails or finds nothing costs nothing.

| Tool | Event | Price | Free, always |
|---|---|---|---|
| `extract_pdf` | page | $0.0003 | document summary rows, error rows, pages outside `page_range`/`max_pages_per_pdf`, refused downloads |
| `extract_pdf` | ocr-page | $0.003 | image-only pages when `ocr` is off (delivered empty with `needsOcr`) |
| `youtube_thumbnails` | video | $0.005 | `not_found`, `invalid_input`, `duplicate`, `removed`, `playlist_not_supported`, `budget_exhausted` |
| `sports_scores`, `tennis_scores` | game | $0.002 | `league_summary` and `error` rows, games dropped by `teams`/`status`, off-season windows, unknown leagues or event ids |
| `sports_scores` | row | $0.001 | — |
| `sports_scores` | summary | $0.004 | — |

Worked examples: a 2-page invoice is **$0.0006**, a 100-page manual **$0.03**, 20 scanned
pages with OCR **$0.06**, 100 videos **$0.50**, today's NBA slate of 8 games **$0.016**,
500 game summaries **$2.00**.

Billing lands on the Apify account behind your own `APIFY_TOKEN`. The spend-cap
argument is not just documentation: the server turns it into the run's
`maxTotalChargeUsd`, so Apify enforces the dollar ceiling itself and stops the run when
it is reached. Because OCR pages draw on the same `max_pages` budget at ten times the
price, `max_pages=1000` means **$0.30** with `ocr` off and **$3.00** with it on, and the
ceiling sent to Apify follows whichever applies. Apify refuses a ceiling below an
Actor's own minimum ($0.05 for `extract_pdf`, $0.10 for the rest), so very small runs ask
for that floor — a ceiling, not a charge: a two-page PDF still costs $0.0006.

The run is also started with `timeout=290`, inside Apify's 300 s synchronous window, so a
run can never outlive the call and keep charging in the background.

## Sports data: read this first

> **Unofficial.** Not affiliated with, endorsed by or sponsored by ESPN, The Walt Disney
> Company or any league. Data comes from the unauthenticated JSON feeds that espn.com
> itself uses; they are undocumented, **Disney's Terms of Use for espn.com restrict
> automated access**, and ESPN **may change or block access without notice** — if that
> happens the Actor fails the run and charges nothing, and we stop within **48 h** of any
> notice from ESPN or Disney. Scores, schedules and standings are facts; ESPN's articles,
> video and images are ESPN's copyrighted content and are not included. Odds are one
> sportsbook's pregame line shown on ESPN, for information only — **not for wagering**.
> Team and league names and logos are trademarks of their owners.
> **Removal requests:** [TAKEDOWN.md](https://github.com/moonie0201/apify-utils/blob/main/TAKEDOWN.md) — honoured in 48 h.

`include_odds` defaults to **off** here, unlike the Actor. Turn it on only if you want the
pregame line copied into the row. `timezone` defaults to `UTC` and only affects the
`dateLocal` field; feed dates are UTC either way.

**Availability.** All four Actors are public: `acotr_moonie/pdf-text-extractor`,
`acotr_moonie/youtube-thumbnail-downloader`, `acotr_moonie/espn-sports-scraper` and
`acotr_moonie/tennis-scores-scraper` (the two sports listings since 2026-08-28). Every
tool was verified end to end against its live Actor.

`leagues` accepts: `nfl`, `ncaaf`, `nba`, `wnba`, `ncaab`, `ncaaw`, `mlb`, `nhl`, `mls`,
`nwsl`, `epl`, `championship`, `fa-cup`, `la-liga`, `serie-a`, `bundesliga`, `ligue-1`,
`eredivisie`, `primeira-liga`, `liga-mx`, `saudi-pro-league`, `wsl`, `ucl`, `uel`, `uecl`,
`nations-league`, `world-cup`, `copa-libertadores`, `atp`, `wta`, `pga`, `f1`, `ufc` — or
any raw ESPN path such as `soccer/bra.1`, which comes back as a free error row if unknown.

## YouTube

Nominative reference only: this reads the public `i.ytimg.com` thumbnail CDN and YouTube's
public oEmbed endpoint. Not affiliated with, endorsed by or sponsored by YouTube or
Google; the YouTube name and logo are trademarks of Google LLC. Thumbnails are the
copyright of the uploader or their licensors — the tool retrieves them, it does not grant
you a licence to republish them.

## What it will not do

- **Nothing is inferred.** Where a value cannot be determined the field is `null`.
- `extract_pdf` reads PDFs you point it at with a plain GET, no proxy and no login. You
  are responsible for the hosting site's terms and robots rules. PDFs whose owner disabled
  text copying are always skipped, with a free error row and no override.
- Markdown headings and paragraphs are heuristics over font size and line gaps, not a
  layout model. Table extraction finds tables drawn with ruling lines; borderless tables
  stay in the text.
- `youtube_thumbnails` does not expand playlist or channel URLs, and does not download
  video.
- The sports tools carry no news, articles, rosters, injuries, athlete bios, play-by-play
  or video, and no ITF or Challenger tennis.

## Development

```bash
uv venv && uv pip install -e ".[dev]"
python -m pytest tests -q       # offline: httpx is monkeypatched, nothing is billed
ruff check . && ruff format --check .
python -m apify_utils_mcp --list-tools
```

## Links

- Actor source, MIT: <https://github.com/moonie0201/apify-utils>
- Privacy policy: <https://github.com/moonie0201/apify-utils/blob/main/PRIVACY.md>
- Takedown policy: <https://github.com/moonie0201/apify-utils/blob/main/TAKEDOWN.md>

## Disclosure

I built this, and the four Actors behind it are paid. The adapter code is open and MIT
licensed.

TDQS

A4.4/5.0

Scored across 5 tools

Disambiguation3/5

Most tools are distinct, but sports_scores and tennis_scores both consume the same ESPN feed and overlap on tennis coverage, creating real selection ambiguity. The descriptions clarify the difference, but an agent could reasonably choose either tool for a tennis query.

Naming Consistency3/5

Names are all snake_case and readable, but conventions are mixed: extract_pdf and list_supported_utilities are verb_noun, while youtube_thumbnails, sports_scores, and tennis_scores are noun phrases. There is no consistent verb_noun pattern across the set.

Tool Count4/5

Five tools is a reasonable size for a utility aggregator, and most tools cover substantial functionality. The sports/tennis duplication makes one tool feel slightly redundant, but the count is not bloated or thin.

Completeness5/5

Relative to the advertised utilities, the tool surface is well covered: PDF extraction has multiple output modes and OCR, YouTube thumbnails cover sizes and storage, and sports data includes scoreboards, schedules, standings, teams, and summaries. list_supported_utilities prevents dead ends by exposing league keys, pricing, and reachability.

Maintenance

ActivityMaintained
ResponsivenessNo issues