{
  "markdown": "# ao3-mcp\n\n<!-- mcp-name: io.github.ArturLys/ao3-mcp -->\n\n[![PyPI](https://img.shields.io/pypi/v/ao3-mcp)](https://pypi.org/project/ao3-mcp/)\n[![CI](https://github.com/ArturLys/ao3-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/ArturLys/ao3-mcp/actions/workflows/ci.yml)\n![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)\n![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)\n\n[![ao3-mcp MCP server](https://glama.ai/mcp/servers/ArturLys/ao3-mcp/badges/score.svg)](https://glama.ai/mcp/servers/ArturLys/ao3-mcp)\n\nAn [MCP](https://modelcontextprotocol.io/) (Model Context Protocol) server that connects AI agents — Claude, Cursor, or any MCP client — to the [Archive of Our Own](https://archiveofourown.org/). Search AO3 fanfiction with full filters, resolve fuzzy wording to canonical tags, and get fics *actually read* before they're recommended.\n\nThe trick: your agent never reads fic text. It delegates reading to a cheap secondary model (Gemini), which digests whole fics — even 150k-word novels — and returns structured reports. Your agent's context stays clean; the recommendations are based on the real text, not the blurb.\n\n```\nagent ──MCP──> server.py\n                 ├─ ao3.py     AO3 scraping (no public API exists) — throttled and polite\n                 └─ reader.py  Gemini reads the fics, reports back: plot, style,\n                               prose samples, content notes, a ranking\n```\n\n## Why this beats blurb-based recommendations\n\nAn AO3 blurb is an ad written by the author. This server's workflow is: search wide (40–60 results), have the reader model read the shortlist — up to 20 full fics in one call — and recommend only what was actually read, with verbatim prose samples so quality is judged from the text itself.\n\n## Not just for finding your next read\n\nIf you write with an AI — fanfic, original fiction, roleplay — this doubles as an inspiration engine. Mid-scene, your agent can pull up how real fic authors handle the exact beat you're on:\n\n```\nFind three highly-kudosed fics where rivals are forced to share a bed, read them,\nand tell me how each one builds the tension — pacing, POV, what they leave unsaid.\n```\n\nThe reader reports back with structure, style notes, and verbatim prose samples, so the model gets grounded in how the trope is actually written — not what it imagines fanfic sounds like. Works the same for roleplay: pull reports on fics that nail a character's voice and feed them in as style reference.\n\n## Install\n\nRequires **Python 3.10+** and a free **Gemini API key**:\n\n> Go to [aistudio.google.com/api-keys](https://aistudio.google.com/api-keys), sign in with any Google account, and click **\"Create API key\"**. The free tier is enough — no billing setup needed.\n\n```bash\npip install ao3-mcp\n```\n\n## Add to your agent\n\nPoint `command` at `ao3-mcp` and pass your key with `--api-key`:\n\n```json\n{\n  \"mcpServers\": {\n    \"ao3\": {\n      \"command\": \"ao3-mcp\",\n      \"args\": [\"--api-key\", \"YOUR_GEMINI_KEY\"]\n    }\n  }\n}\n```\n\nPrefer to keep the key out of the args list? Drop `--api-key` and pass it in an `env`\nblock instead — the server reads `GEMINI_API_KEY` from the environment as a fallback:\n\n```json\n\"env\": { \"GEMINI_API_KEY\": \"YOUR_GEMINI_KEY\" }\n```\n\n<details>\n<summary>Claude Code</summary>\n\n```bash\nclaude mcp add ao3 -- ao3-mcp --api-key YOUR_GEMINI_KEY\n```\n\n</details>\n\n<details>\n<summary>Cursor</summary>\n\n`Cursor Settings` → `MCP` → `New MCP Server`, paste the JSON config above.\n\n</details>\n\n<details>\n<summary>Google Antigravity</summary>\n\nAdd the JSON config above to `.gemini/antigravity/mcp_config.json`.\n\n</details>\n\n<details>\n<summary>VS Code / Copilot</summary>\n\n```bash\ncode --add-mcp '{\"name\":\"ao3\",\"command\":\"ao3-mcp\",\"args\":[\"--api-key\",\"YOUR_GEMINI_KEY\"]}'\n```\n\n</details>\n\nThen just ask:\n\n```\nFind me a completed enemies-to-lovers longfic in <fandom>, read the top candidates, and tell me which is best written.\n```\n\n### Launch params\n\n| Param             | Env var               | Default              | What it does                                  |\n| ----------------- | --------------------- | -------------------- | --------------------------------------------- |\n| `--api-key`       | `GEMINI_API_KEY`      | —                    | Gemini API key (required).                     |\n| `--model`         | `GEMINI_MODEL`        | `gemini-flash-latest`| Model the reader uses.                          |\n| `--backup-model`  | `GEMINI_MODEL_BACKUP` | `gemini-flash-lite-latest` | Fallback model when the main one is throttled. |\n| `--min-interval`  | `AO3_MIN_INTERVAL`    | `0.6`                | Minimum seconds between AO3 requests.           |\n\n## Tools\n\n| Tool           | What it does                                                                 |\n| -------------- | ---------------------------------------------------------------------------- |\n| `search_works` | Search AO3: fandom, ship, character, tags, rating, word count, completion, sorting. 20 results/page, up to 5 pages per call. The `query` field supports AO3's full search-operator syntax (`words>10000`, `kudos>500`, `sort:kudos`, …). |\n| `find_tags`    | Live autocomplete — fuzzy wording → canonical AO3 tag, fandom, ship, or character names. |\n| `get_work`     | Full metadata card for one work: tags, stats, summary, series info.          |\n| `read_works`   | Reads 1–20 full fics with the secondary model and returns a structured report per fic — plot, characters, style, verbatim prose samples, content notes — plus a comparison ranking them against your question. |\n\nFic downloads are cached locally for 24h, so re-reading a fic with a new question costs no AO3 requests.\n\n## Good to know\n\n- **AO3 has no API** — this scrapes its (clean) HTML, one request at a time, throttled to one every **0.6s** by default (tune with `--min-interval`) and honoring `Retry-After`. AO3 is volunteer-run; the politeness is deliberate.\n- **Cloudflare:** AO3 blocks plain HTTP clients. This uses `curl_cffi` with a mobile-Safari TLS fingerprint, which passes as of writing. If requests start failing with 403 + `cf-mitigated: challenge`, change `IMPERSONATE` in `ao3.py`.\n- **Privacy:** fic text goes to Google's Gemini API for reading; nothing else leaves your machine, no telemetry.\n- **Adult content:** AO3 hosts works across all ratings. The server passes through whatever your search scopes — use the `rating` filter and AO3's warning tags to control what gets fetched.\n\n## Make it yours\n\nIt's a small, single-purpose server — a few hundred readable lines with no framework magic. Fork it and edit anything: rewrite the reader's prompt, swap in a different model, change the throttle, add a tool. That's the intended way to use it.\n\nRun it from source:\n\n```bash\ngit clone https://github.com/ArturLys/ao3-mcp.git\ncd ao3-mcp\npython -m venv .venv\nsource .venv/bin/activate        # Windows: .venv\\Scripts\\activate\npip install -r requirements.txt\n\npython smoke_test.py YOUR_GEMINI_KEY   # end-to-end check: search → download → digest\npython server.py --api-key YOUR_GEMINI_KEY   # or point your client's command at this\n```\n\n## Credits\n\n- AO3 access approach builds on [ao3_api](https://github.com/wendytg/ao3_api) by wendytg.\n- All fanworks belong to their authors on the [Archive of Our Own](https://archiveofourown.org/), a project of the [Organization for Transformative Works](https://www.transformativeworks.org/).\n\n## License\n\nMIT\n",
  "bytes": 7427,
  "sha": "86a3e54646451682475ae59ec9cb14f6de9ca2975370737bd46cfcd26bbfa2de",
  "repo_slug": "arturlys/ao3-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_arturlys_ao3_mcp_2271a57b/readme"
}