mcpField
A
apple-books-mcp

apple-books-mcp

github.com/vladmdgolamProductivity939 installsUpdated 2w ago
Repository

About apple-books-mcp

apple-books-mcp is an MCP server for accessing Apple Books titles and annotations, for users who organize reading notes or search book content. Its tools include color-based highlight lookup, annotation search, and full-text search across books.

Key features

  1. 01List books, collections, and annotations
  2. 02Inspect individual annotations and their colors
  3. 03Filter library-wide highlights by color
  4. 04Search highlighted text and notes
  5. 05Search book full text
  6. 06Retrieve recent annotations

Use cases

  1. 01Extract highlights from a reading list
  2. 02Find a quote across multiple books
  3. 03Collect highlights of a chosen color
  4. 04Organize book annotations into Markdown

MCP support

This MCP server exposes tools for Apple Books titles, annotations, collections, and full-text search to MCP clients.

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/vladmdgolam/agent-skills --skill apple-books-mcp

After installing, type/apple-books-mcpin Claude Code to confirm it loaded.

Details

From the project README

Apple Books MCP

MCP server: vgnshiyer/apple-books-mcp

Install: npx -y @anthropic-ai/claude-code mcp add apple-books -- uvx apple-books-mcp

Tools Reference

ToolPurpose
list_all_booksList all books (ID, title, author)
get_book_annotationsAll annotations for a book by ID. No color data.
describe_annotationFull details for one annotation including color
get_highlights_by_colorAll highlights of one color across entire library
search_highlighted_textSearch annotations by highlighted text
search_notesSearch by user-written notes
list_all_annotationsAll annotations across all books
list_all_collectionsList collections
get_collection_booksBooks in a collection
describe_book / describe_collectionDetails by ID
recent_annotationsRecently created annotations
full_text_searchFull text search across books

Critical: Color Extraction Strategy

get_book_annotations does NOT return colors. describe_annotation returns colors but one at a time — 150+ calls for a single book.

Solution: Call get_highlights_by_color once per color (5 total calls), then cross-reference annotation IDs programmatically.

Available colors: PINK, BLUE, YELLOW, GREEN, PURPLE
Underlines: color = null, is_underline = 1
Build the Color Map
import json, glob

# After calling get_highlights_by_color for PINK, BLUE, YELLOW, GREEN, PURPLE
# Results save to files when they exceed token limits

ann_color = {}
colors = ["PINK", "BLUE", "YELLOW", "GREEN", "PURPLE"]

for color_file, color in zip(sorted(glob.glob("path/to/results/*.txt")), colors):
    with open(color_file, 'r') as f:
        data = json.load(f)
    current_id = None
    for line in data.get("text", "").split("\n"):
        line = line.strip()
        if line.startswith("ID: "):
            current_id = line.split("ID: ")[1].strip()
        elif line.startswith("Selected text: ") and current_id:
            selected = line[len("Selected text: "):]
            if selected and selected != "None":
                ann_color[current_id] = color

# Look up: ann_color.get(str(annotation_id), None)  # None = underline

Workflow: Extract Highlights for a Book List

Step 1: Match Books

Call list_all_books and match against user's list. Tips:

  • Books may appear under translated titles (e.g., Russian editions)
  • PDFs often have garbled or filename-based titles
  • Use partial/fuzzy matching — "Vignelli Canon" may appear as just "canon"
  • Same book may exist in multiple editions (different IDs)
Step 2: Get Annotations per Book
get_book_annotations(book_id="531")

Returns: ID, selected_text, representative_text, note, chapter, location, modification date. Filter out entries where selected_text is None (empty bookmarks).

Step 3: Get Colors (Batch)
get_highlights_by_color(color="PINK")
get_highlights_by_color(color="BLUE")
get_highlights_by_color(color="YELLOW")
get_highlights_by_color(color="GREEN")
get_highlights_by_color(color="PURPLE")

Results are large (100k-400k chars). Use Python to parse.

Step 4: Export to Markdown
color_emoji = {
    "PINK": "🩷", "BLUE": "🔵", "YELLOW": "🟡",
    "GREEN": "🟢", "PURPLE": "🟣",
}

lines = [f"# {title}", f"**{author}**", "", "---", ""]
for ann_id, text in annotations:
    color = ann_color.get(str(ann_id), None)
    tag = color_emoji.get(color, "〰️")  # 〰️ for underlines
    lines.append(f"{tag} {text}")
    lines.append("")

Annotation Data Structure

From describe_annotation:

{
  "id": 2133,
  "selected_text": "be impeccable with your word",
  "representative_text": "The first agreement is to be impeccable...",
  "note": null,
  "is_underline": 0,
  "style": 4,
  "color": "PINK",
  "chapter": null,
  "location": "epubcfi(/6/12[c005]!/4/10,/1:26,/2/1:28)"
}
Style-to-Color Mapping
StyleColor
0Underline (no color)
1Green
2Blue
3Yellow
4Pink
5Purple

Examples

Example 1: Export All Highlights from a Reading List

User says: "Extract highlights from the books in my reading list"

  1. Read the user's list (file, note, etc.) to get book titles
  2. list_all_books → match titles to IDs
  3. For each matched book: get_book_annotations(book_id=ID) → collect annotation IDs + text
  4. get_highlights_by_color x5 → build color map
  5. Python script combines annotations + colors → writes .md files per book
Example 2: Search for a Quote Across All Books

User says: "Find where I highlighted something about shadow work"

  1. search_highlighted_text(text="shadow") → returns matching annotations with book context
  2. If color needed: describe_annotation(annotation_id=ID) for the few results
Example 3: Get All Pink Highlights

User says: "Show me all my pink highlights"

  1. get_highlights_by_color(color="PINK") → all pink highlights across library
  2. Group by book title for readability

Troubleshooting

SymptomCauseFix
list_all_books emptyApple Books never openedOpen Apple Books app once
No annotations for a bookBook was read but not highlightedExpected behavior
describe_annotation color is nullIt's an underlineCheck is_underline field
Color results too largeMany highlights in libraryResults auto-save to file; parse with Python
Book title doesn't matchDifferent edition/translationTry author name or partial title
selected_text is NoneBookmark, not a highlightFilter these out

Comments

Markdown supported