Skip to main content
Glama

fetch_due_cards_for_review

Retrieve Anki flashcards scheduled for review, optionally filtered by deck or date range, to support spaced repetition learning.

Instructions

Fetch cards due for review, formatted for an LLM to present.

Args: deck: Optional[str] - Filter by specific deck name. limit: int - Maximum number of cards to fetch (default 5). today_only: bool - If true, only fetch cards due today. If false, fetch cards due up to MAX_FUTURE_DAYS ahead (currently {MAX_FUTURE_DAYS}).

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
deckNo
limitNoMax cards to fetch.
today_onlyNoTrue=only today's cards, False=cards due up to MAX_FUTURE_DAYS ahead.

Implementation Reference

  • The core handler function that executes the tool: connects to Anki, finds due cards using helper, fetches details, formats for LLM, and returns embedded prompt.
    async def fetch_due_cards_for_review( deck: Optional[str] = None, limit: int = Field(default=5, ge=1, description="Max cards to fetch."), today_only: bool = Field(default=True, description="True=only today's cards, False=cards due up to MAX_FUTURE_DAYS ahead."), ) -> str: """Fetch cards due for review, formatted for an LLM to present. Args: deck: Optional[str] - Filter by specific deck name. limit: int - Maximum number of cards to fetch (default 5). today_only: bool - If true, only fetch cards due today. If false, fetch cards due up to MAX_FUTURE_DAYS ahead (currently {MAX_FUTURE_DAYS}). """ async with get_anki_client() as anki: # Determine the maximum relative day to check based on today_only flag # day=0 means today, day=MAX_FUTURE_DAYS means today up to MAX_FUTURE_DAYS from now max_day_to_check = 0 if today_only else MAX_FUTURE_DAYS # Use the helper function to find relevant card IDs card_ids = await _find_due_card_ids(anki, deck, day=max_day_to_check) # Limit the number of cards to fetch info for card_ids_to_fetch = card_ids[:limit] if not card_ids_to_fetch: deck_msg = f" in deck '{deck}'" if deck else "" when_msg = "today" if today_only else f"within the next {max_day_to_check} days" return f"No cards found due {when_msg}{deck_msg}." logger.debug(f"Fetching info for card IDs: {card_ids_to_fetch}") cards_info_list = await anki.cards_info(card_ids=card_ids_to_fetch) # Format cards using the helper function cards_text = _format_cards_for_llm(cards_info_list) # Inject the formatted cards into the review instructions prompt review_prompt = claude_review_instructions.replace("{{flashcards}}", cards_text) return review_prompt
  • Registers the tool using FastMCP's @mcp.tool() decorator, with error handling decorator.
    @handle_anki_connection_error # Apply decorator
  • Input schema defined via Pydantic Field annotations in the function signature.
    deck: Optional[str] = None, limit: int = Field(default=5, ge=1, description="Max cards to fetch."), today_only: bool = Field(default=True, description="True=only today's cards, False=cards due up to MAX_FUTURE_DAYS ahead."), ) -> str:
  • Key helper function to construct Anki search query for due cards and retrieve card IDs.
    async def _find_due_card_ids( client: AnkiConnectClient, deck: Optional[str] = None, day: Optional[int] = 0 ) -> List[int]: """Finds card IDs due on a specific day relative to today (0=today).""" if day < 0: raise ValueError("Day must be non-negative.") # Construct the search query # prop:due=0 means due today # prop:due=1 means due tomorrow (relative to review time) # prop:due<=N finds cards due today up to N days in the future. if day == 0: prop = "prop:due=0" # Due exactly today else: prop = f"prop:due<={day}" query = f"is:due -is:suspended {prop}" if deck: # Add deck to query, ensuring proper quoting for spaces query += f' "deck:{deck}"' logger.debug(f"Executing Anki card search query: {query}") card_ids = await client.find_cards(query=query) logger.info(f"Found {len(card_ids)} cards for query: {query}") return card_ids
  • Helper to format fetched card data into structured XML-like output for easy LLM parsing.
    def _format_cards_for_llm(cards_info: List[dict]) -> str: """Formats card information into an XML-like string for the LLM.""" formatted_cards = [] for card in cards_info: card_id = card.get('cardId', 'UNKNOWN_ID') fields = card.get('fields', {}) question_field_order = card.get('fieldOrder', 0) question_parts = [] answer_parts = [] sorted_field_items = sorted(fields.items(), key=lambda item: item[1].get('order', 0)) for name, field_data in sorted_field_items: field_value = field_data.get('value', '') field_order = field_data.get('order', -1) tag_name = name.lower().replace(" ", "_") if field_order == question_field_order: question_parts.append(f"<{tag_name}>{field_value}</{tag_name}>") else: answer_parts.append(f"<{tag_name}>{field_value}</{tag_name}>") question_str = "".join(question_parts) if question_parts else "<error>Question field not found</error>" answer_str = " ".join(answer_parts) if answer_parts else "<error>Answer fields not found</error>" formatted_cards.append( f"<card id=\"{card_id}\">\n" f" <question>{question_str}</question>\n" f" <answer>{answer_str}</answer>\n" f"</card>" ) return "\n\n".join(formatted_cards)

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/samefarrar/mcp-ankiconnect'

If you have feedback or need assistance with the MCP directory API, please join our Discord server