Engramo MCP agent

EngrAmo MCP server

by engramo-developer·MIT license·★ 2 Stars on the repo·GitHub ↗

Inside this agent

README.md · the author's own words
[![npm version](https://img.shields.io/npm/v/@engramo/mcp)](https://www.npmjs.com/package/@engramo/mcp)
[![CI](https://github.com/engramo-developer/engramo-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/engramo-developer/engramo-m…
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

# engramo-mcp

MCP server for [EngrAmo](https://engramo.app), the spaced-repetition flashcard platform.

## Hosted server

The hosted server at `https://mcp.engramo.app/` needs no installation. It supports OAuth 2.0 with Dynamic Client
Registration: your client sends you to the EngrAmo sign-in page, you sign in with your EngrAmo email and password
and approve — no API token to paste. There is no sign-up on that page, so create your account in the EngrAmo app
first. Setup guides: [Claude](#claude-hosted-connector) and [ChatGPT](#use-in-chatgpt-remote-mcp-over-streamable-http);
the public docs are at <https://engramo.app/connect/>. You can revoke access any time in the EngrAmo app under
Settings → Connected apps.

Word-for-word excerpt, not a result. Read the full README.md ↓

Files of Engramo MCP

engramo-developer/main1 file
README.md
Show the full text668 lines

npm version CI License: MIT

engramo-mcp

MCP server for EngrAmo, the spaced-repetition flashcard platform.

Hosted server

The hosted server at https://mcp.engramo.app/ needs no installation. It supports OAuth 2.0 with Dynamic Client Registration: your client sends you to the EngrAmo sign-in page, you sign in with your EngrAmo email and password and approve — no API token to paste. There is no sign-up on that page, so create your account in the EngrAmo app first. Setup guides: Claude and ChatGPT; the public docs are at https://engramo.app/connect/. You can revoke access any time in the EngrAmo app under Settings → Connected apps.

Prerequisites

  • An EngrAmo account
  • An EngrAmo API token — generate one from your account's Settings → API Tokens page. Only needed for the local (stdio) setups below and for remote clients without OAuth; the hosted connectors use OAuth instead.

Environments

engramo-mcp is environment-agnostic — the binary itself has no baked-in "dev" or "prod." Which server it talks to is controlled entirely by the ENGRAMO_API_URL you set in your client config, paired with a token minted from that same environment:

Environment ENGRAMO_API_URL MCP server URL (http transport only) Who it's for
Production (default in every example below) https://api.engramo.app https://mcp.engramo.app Real accounts — use this unless you have a specific reason not to
Dev https://api-engram.volmyr.com https://mcp-engramo.volmyr.com EngrAmo team / internal testing only

Dev and prod are separate backends with separate accounts. A token minted from one will not authenticate against the other — if you switch ENGRAMO_API_URL, you must also swap in a token generated from that same environment's Settings → API Tokens page.

ENGRAMO_API_URL vs the MCP server URL — these are not interchangeable. ENGRAMO_API_URL is the plain EngrAmo backend; it's never something a client connects to directly. In stdio config (Claude Desktop, Claude Code, Codex, VS Code, Cursor, Windsurf, Gemini CLI, Antigravity stdio below), the client sets ENGRAMO_API_URL together with ENGRAMO_API_TOKEN, since the locally-launched binary calls the backend itself. In http/remote config (Antigravity remote, ChatGPT), the client instead points serverUrl at the MCP server's own URL (mcp.engramo.app / mcp-engramo.volmyr.com above) and authenticates separately per session — via OAuth by default, or a static Authorization: Bearer header if you'd rather skip the login prompt. ENGRAMO_API_URL still matters in http mode, but only as an env var set by whoever deploys engramo-mcp http — a client never sets it.

Installation

Install the MCP server globally so it's available as a system command:

npm install -g @engramo/mcp

Prebuilt binaries ship for macOS (arm64, x64), Linux (arm64, x64) and Windows (x64). On other platforms, build from source with cargo build --release.

Verify the installation:

engramo-mcp --version

Alternatively, skip installation entirely and use npx -y @engramo/mcp in your client config — npm will download the binary automatically on first use.

Choosing a client

Any MCP client works. Local text-to-speech needs a stdio (locally launched) connection, so remote-only clients never get it.

Client Models Local TTS Setup
Claude Desktop Claude ✅ Claude Desktop — recommended for non-technical users: one-click extension, no Node.js or config editing; the free plan supports local extensions
Claude Code Claude ✅ Claude Code
Codex (CLI / IDE extension) OpenAI models — sign in with your ChatGPT account ✅ Codex
VS Code (GitHub Copilot) GPT / Claude / Gemini ✅ VS Code
Cursor GPT / Claude / Gemini ✅ Cursor
Windsurf GPT / Claude / Gemini ✅ Windsurf
Gemini CLI Gemini ✅ Gemini CLI
Antigravity Gemini / Claude / GPT ✅ stdio / ❌ remote Antigravity
Claude (claude.ai, Desktop, mobile) Claude ❌ — hosted connector only; local TTS intentionally unavailable Claude (hosted connector)
ChatGPT OpenAI models ❌ — remote connector only (OAuth); local TTS intentionally unavailable ChatGPT

Claude Desktop

  1. Download engramo.mcpb from the latest release (macOS on Intel and Apple Silicon, Windows x64, Linux x64 and arm64).
  2. Double-click it (or drag it onto Claude Desktop) and click Install. Claude Desktop warns that the developer isn't verified by Anthropic; it shows this for every extension installed from a file.
  3. Paste your EngrAmo API token, and optionally your Gemini API keys (comma-separated) to enable card audio. Claude Desktop stores both in the OS keychain.

No Node.js and no config file. Change the token or keys later under Settings → Extensions → EngrAmo → Configure. The extension doesn't auto-update: install the new engramo.mcpb to upgrade. Its tools are available in Chat conversations, not in Claude Desktop's Code mode. The bundle is built from mcpb/manifest.json by the release workflow. Verify a download with gh attestation verify engramo.mcpb -R engramo-developer/engramo-mcp --signer-workflow engramo-developer/engramo-mcp/.github/workflows/release.yml --source-ref refs/tags/vX.Y.Z (substituting the release tag), or compare it with the release's engramo.mcpb.sha256.

Manual config

Open Settings → Developer → Edit Config, or edit the file directly: ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):

Using npx (no prior installation needed):

{
  "mcpServers": {
    "engramo": {
      "command": "npx",
      "args": ["-y", "@engramo/mcp"],
      "env": {
        "ENGRAMO_API_URL": "https://api.engramo.app",
        "ENGRAMO_API_TOKEN": "your-token",
        "ENGRAMO_TTS_GEMINI_API_KEYS": "your-gemini-key"
      }
    }
  }
}

ENGRAMO_TTS_GEMINI_API_KEYS is optional — it enables list_tts_voices/generate_card_audio using your own Gemini quota; omit the line to disable. See Text-to-speech.

Using a global install (npm install -g @engramo/mcp):

{
  "mcpServers": {
    "engramo": {
      "command": "engramo-mcp",
      "env": {
        "ENGRAMO_API_URL": "https://api.engramo.app",
        "ENGRAMO_API_TOKEN": "your-token"
      }
    }
  }
}

After editing, fully quit Claude Desktop (⌘Q on macOS — closing the window isn't enough) and reopen it. If the server doesn't show up, check the logs at ~/Library/Logs/Claude/mcp-server-engramo.log (macOS) or %APPDATA%\Claude\logs\ (Windows). The Gemini key is never logged.

Claude (hosted connector)

Use the hosted server from claude.ai, Claude Desktop, or Claude mobile — no install, no token:

  1. Settings → Connectors → Add custom connector
  2. Paste https://mcp.engramo.app/
  3. Connect, sign in with your EngrAmo account, and approve.

All hosted tools are then available. Like every remote connection, it has no local text-to-speech; use the Claude Desktop extension for that.

Claude Code

Register the server once for all your projects (--scope user):

claude mcp add engramo --scope user \
  -e ENGRAMO_API_URL=https://api.engramo.app \
  -e ENGRAMO_API_TOKEN=your-token \
  -e ENGRAMO_TTS_GEMINI_API_KEYS=your-gemini-key \
  -- npx -y @engramo/mcp

ENGRAMO_TTS_GEMINI_API_KEYS is optional — it enables list_tts_voices/generate_card_audio using your own Gemini quota; omit the -e ENGRAMO_TTS_GEMINI_API_KEYS=… line to disable. See Text-to-speech.

With a global install, replace npx -y @engramo/mcp with engramo-mcp.

Codex

The OpenAI Codex CLI and the Codex IDE extension share one config file, ~/.codex/config.toml. This is the way to use your ChatGPT account's models with local TTS (the ChatGPT app's remote connector can't have it):

Using npx (no prior installation needed):

[mcp_servers.engramo]
command = "npx"
args = ["-y", "@engramo/mcp"]
tool_timeout_sec = 300  # default 60s; a 20-card generate_card_audio batch can take longer
env = { ENGRAMO_API_URL = "https://api.engramo.app", ENGRAMO_API_TOKEN = "your-token", ENGRAMO_TTS_GEMINI_API_KEYS = "your-gemini-key" }

ENGRAMO_TTS_GEMINI_API_KEYS is optional — it enables list_tts_voices/generate_card_audio using your own Gemini quota; omit it from env to disable. See Text-to-speech.

Using a global install (npm install -g @engramo/mcp):

[mcp_servers.engramo]
command = "engramo-mcp"
env = { ENGRAMO_API_URL = "https://api.engramo.app", ENGRAMO_API_TOKEN = "your-token" }

VS Code (GitHub Copilot agent mode)

Add to .vscode/mcp.json (workspace), or run MCP: Open User Configuration from the Command Palette for a user-wide config. Use inputs with "password": true so VS Code prompts for the secrets and stores them itself instead of you writing them into the file. Note the top-level key is servers (not mcpServers):

Using npx (no prior installation needed):

{
  "inputs": [
    { "type": "promptString", "id": "engramo-token", "description": "EngrAmo API token", "password": true },
    { "type": "promptString", "id": "gemini-key", "description": "Gemini API key (for TTS)", "password": true }
  ],
  "servers": {
    "engramo": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@engramo/mcp"],
      "env": {
        "ENGRAMO_API_URL": "https://api.engramo.app",
        "ENGRAMO_API_TOKEN": "${input:engramo-token}",
        "ENGRAMO_TTS_GEMINI_API_KEYS": "${input:gemini-key}"
      }
    }
  }
}

ENGRAMO_TTS_GEMINI_API_KEYS is optional — it enables list_tts_voices/generate_card_audio using your own Gemini quota; omit the line (and the gemini-key input) to disable. See Text-to-speech.

With a global install, use "command": "engramo-mcp" and drop args.

Cursor

Add to ~/.cursor/mcp.json:

Using npx (no prior installation needed):

{
  "mcpServers": {
    "engramo": {
      "command": "npx",
      "args": ["-y", "@engramo/mcp"],
      "env": {
        "ENGRAMO_API_URL": "https://api.engramo.app",
        "ENGRAMO_API_TOKEN": "your-token",
        "ENGRAMO_TTS_GEMINI_API_KEYS": "your-gemini-key"
      }
    }
  }
}

ENGRAMO_TTS_GEMINI_API_KEYS is optional — it enables list_tts_voices/generate_card_audio using your own Gemini quota; omit the line to disable. See Text-to-speech.

Using a global install (npm install -g @engramo/mcp):

{
  "mcpServers": {
    "engramo": {
      "command": "engramo-mcp",
      "env": {
        "ENGRAMO_API_URL": "https://api.engramo.app",
        "ENGRAMO_API_TOKEN": "your-token"
      }
    }
  }
}

Windsurf

Add to ~/.codeium/windsurf/mcp_config.json:

Using npx (no prior installation needed):

{
  "mcpServers": {
    "engramo": {
      "command": "npx",
      "args": ["-y", "@engramo/mcp"],
      "env": {
        "ENGRAMO_API_URL": "https://api.engramo.app",
        "ENGRAMO_API_TOKEN": "your-token",
        "ENGRAMO_TTS_GEMINI_API_KEYS": "your-gemini-key"
      }
    }
  }
}

ENGRAMO_TTS_GEMINI_API_KEYS is optional — it enables list_tts_voices/generate_card_audio using your own Gemini quota; omit the line to disable. See Text-to-speech.

Using a global install (npm install -g @engramo/mcp):

{
  "mcpServers": {
    "engramo": {
      "command": "engramo-mcp",
      "env": {
        "ENGRAMO_API_URL": "https://api.engramo.app",
        "ENGRAMO_API_TOKEN": "your-token"
      }
    }
  }
}

Gemini CLI

Add to ~/.gemini/settings.json:

Using npx (no prior installation needed):

{
  "mcpServers": {
    "engramo": {
      "command": "npx",
      "args": ["-y", "@engramo/mcp"],
      "env": {
        "ENGRAMO_API_URL": "https://api.engramo.app",
        "ENGRAMO_API_TOKEN": "your-token",
        "ENGRAMO_TTS_GEMINI_API_KEYS": "your-gemini-key"
      }
    }
  }
}

ENGRAMO_TTS_GEMINI_API_KEYS is optional — it enables list_tts_voices/generate_card_audio using your own Gemini quota; omit the line to disable. See Text-to-speech.

Using a global install (npm install -g @engramo/mcp):

{
  "mcpServers": {
    "engramo": {
      "command": "engramo-mcp",
      "env": {
        "ENGRAMO_API_URL": "https://api.engramo.app",
        "ENGRAMO_API_TOKEN": "your-token"
      }
    }
  }
}

Antigravity

Antigravity supports both transports directly via its own config file — no separate remote-connector UI needed like ChatGPT's. Add to ~/.gemini/config/mcp_config.json (global) or .agents/mcp_config.json (workspace-local):

stdio, via npx (no prior installation needed):

{
  "mcpServers": {
    "engramo": {
      "command": "npx",
      "args": ["-y", "@engramo/mcp"],
      "env": {
        "ENGRAMO_API_URL": "https://api.engramo.app",
        "ENGRAMO_API_TOKEN": "your-token"
      }
    }
  }
}

Remote, over Streamable HTTP (point at a running engramo-mcp http deployment — see below). engramo-mcp supports OAuth 2.1 dynamic client registration, so Antigravity can handle authentication automatically — no token to paste or manage:

{
  "mcpServers": {
    "engramo": {
      "serverUrl": "https://mcp.engramo.app/"
    }
  }
}

If you'd rather use a static token instead (no OAuth login prompt), add headers manually:

{
  "mcpServers": {
    "engramo": {
      "serverUrl": "https://mcp.engramo.app/",
      "headers": {
        "Authorization": "Bearer your-token"
      }
    }
  }
}

Text-to-speech is unavailable over the remote transport — use the stdio config above if you want generate_card_audio.

Use in ChatGPT (remote MCP over Streamable HTTP)

engramo-mcp also runs as a remote server, so it can be added to ChatGPT as a custom connector (developer mode) without installing anything locally. The hosted server at https://mcp.engramo.app/ already works this way. This is the same binary — the http subcommand instead of the default stdio — so a self-hosted deployment serves both Claude Desktop users (stdio) and ChatGPT users (HTTP) from one codebase.

ENGRAMO_API_URL=https://api.engramo.app MCP_BIND_ADDR=0.0.0.0:8080 engramo-mcp http

This serves MCP over Streamable HTTP at POST / (root). Unlike stdio mode, there is no global ENGRAMO_API_TOKEN — every session authenticates with its own Authorization: Bearer <token> header, so one deployment safely serves many users at once (each session's calls to the EngrAmo API use only that session's token). Requests without a well-formed, non-empty bearer token are rejected with 401 before a session is created, and once a session exists every later request on it must carry the same token that opened it.

http mode also serves an unauthenticated GET /version that returns {"name","version"} (this binary's build version, read from Cargo.toml at compile time) — handy for deployment health and version probes without an MCP handshake.

In ChatGPT, enable developer mode (Settings → Connectors → Advanced → Developer mode), then add an app pointing at https://mcp.engramo.app/ (or your own deployment's https://<host>/). ChatGPT signs you in through OAuth: sign in with your EngrAmo account and approve — no API token needs to be pasted. (Clients without OAuth can instead send an EngrAmo API token from Settings → API Tokens as a static Authorization: Bearer header.) Once connected, prompts like "Make me a 10-card Spanish restaurant deck" or "Turn this conversation into flashcards" call generate_catalog_with_cards directly; open the result at https://study.engramo.app/catalog/<shortId> to study it.

generate_card_audio is never available through a ChatGPT connector — it's a remote connection, and local text-to-speech is stdio-only by design. To use your ChatGPT account's models with local TTS, use Codex instead.

A listing in the public ChatGPT app directory is coming; until then, add the app in developer mode as above.

ChatGPT plugin package (maintainers)

The directory listing is submitted on platform.openai.com/plugins as a plugin ZIP built from chatgpt-plugin/: plugin.json holds the listing metadata and mcp.json points at https://mcp.engramo.app/ with OAuth via dynamic client registration (no client ID or secret). Build it with:

./chatgpt-plugin/build.sh   # → target/engramo-chatgpt-plugin.zip

The script copies the icon from mcpb/ and sets version from Cargo.toml. Upload a new ZIP (Plugins → EngrAmo → Upload new version) only when the listing metadata changes; tool and server changes are picked up by Rescan. The domain-verification token served at /.well-known/openai-apps-challenge comes from the portal and is set as the _OPENAI_APPS_CHALLENGE substitution on the prod Cloud Build trigger, not in this repo.

Bring-your-own-AI

Every deployment is bring-your-own-AI: the calling model (Claude, ChatGPT, …) does all generation — translation, dictionaries, phrasing — and engramo-mcp only persists the result via generate_card / generate_catalog_with_cards / generate_cards. This costs the EngrAmo account nothing beyond normal storage quotas, and needs no paid EngrAmo plan.

Environment variables

Variable Default Description
ENGRAMO_API_URL https://api.engramo.app Base URL of the EngrAmo API
ENGRAMO_API_TOKEN (required for stdio) Your EngrAmo API token. Unused in http mode — each session supplies its own via the Authorization: Bearer header.
MCP_BIND_ADDR 0.0.0.0:8080 Bind address for http mode
MCP_PUBLIC_URL (unset) http mode only — this deployment's own public URL (bare origin, no path — the endpoint is served at /), e.g. https://mcp.engramo.app. Also allowlists that host for inbound requests; without it, every request is rejected (see MCP_ALLOWED_HOSTS).
MCP_ALLOWED_HOSTS (unset) http mode only — extra comma-separated hostnames/host:port values to permit, on top of the one derived from MCP_PUBLIC_URL. Only needed for extra entry points (e.g. a Cloud Run service's own *.run.app fallback URL alongside its custom domain).
ENGRAMO_TTS_GEMINI_API_KEYS (unset → TTS tools absent) stdio only. Your own Gemini API key, or a comma-separated list. Enables list_tts_voices/generate_card_audio. Ignored (with a startup warning) in http mode — see Text-to-speech below.
ENGRAMO_TTS_PROVIDER gemini stdio only. TTS engine selector. Only gemini is supported today; an unrecognized value fails startup.
ENGRAMO_TTS_MODEL gemini-3.8-flash-tts stdio only. Gemini TTS model id.
ENGRAMO_TTS_VOICE Puck stdio only. Default voice used when a generate_card_audio call doesn't specify one.

Available tools

Server info
Tool Description
get_server_version Get this MCP server's own build version (not a catalog/card's version field)
Catalogs
Tool Description
list_catalogs List all flashcard catalogs
get_catalog Get a single catalog by ID
update_catalog Update a catalog's name or description
delete_catalog Delete a catalog
Cards
Tool Description
list_cards List cards in a catalog
get_card Get a single card by ID
update_card Update a card's content
delete_card Delete a card
Learning
Tool Description
get_due_cards Get cards due for review today
get_all_learning_cards Get all cards in the learning queue
add_card_to_learning Add a card to the learning queue
add_catalog_to_learning Add all cards from a catalog to the learning queue
Learning paths
Tool Description
list_learning_paths List all learning paths
get_learning_path Get a single learning path by ID
create_learning_path Create a new learning path
activate_learning_path Activate a learning path
deactivate_learning_path Deactivate a learning path
Tool Description
search_global Full-text search across all content
search_catalogs Search within a specific catalog
Media
Tool Description
list_media List uploaded media assets
upload_media Upload a file you already have (a voice recording, an image) and get back a media_id to attach to a card or catalog
AI generation (bring-your-own-AI)
Tool Description
generate_card Create a flashcard — the calling model does any translation/wording itself
generate_catalog_with_cards Create a catalog with cards in one call — same bring-your-own-AI model
generate_cards Add multiple cards to an existing catalog — same bring-your-own-AI model
Text-to-speech (stdio, opt-in)

Only present when ENGRAMO_TTS_GEMINI_API_KEYS is set (stdio mode only) — see Text-to-speech below.

Tool Description
list_tts_voices List the configured TTS engine, model, default voice, and available voices. No network call.
generate_card_audio Synthesize speech for the FACE side of up to 20 cards, upload it to your own media, and attach it — using your own Gemini key/quota

Rich cards: dictionary, styling, images, audio

Beyond plain text, a card's face/back can carry:

Field What it does
dictionary Word → translation map, rendered as clickable highlights in the app
rich_text Styled spans (bold, color, monospace) within the text
style Font/color/background/alignment for the whole face or back
audio_id Your own audio (a recording, a clip from your own TTS) — upload it with upload_media first, or set it automatically by calling generate_card_audio (stdio only, see below)
visual_id + visual_type Your own image/video, same pattern as audio_id

A catalog can also have image_id (cover image) set the same way. None of this needs a paid EngrAmo plan — dictionary/translation are done by the calling model, images are entirely bring-your-own via upload_media (max ~10MB per file), and face audio is either bring-your-own the same way or generated locally with your own TTS key via generate_card_audio. See engramo://card-schema for the full schema and four worked examples, and docs/prompt-examples.md for ready-to-paste prompts covering all of this end to end.

Adding a lot of cards/media at once? upload_media is one file per call, fine for a handful of files through a chat client. For bulk imports (many cards, many audio files, in one request) see docs/bulk-import.md — a direct API recipe for CLI/scripted use (Claude Code, a terminal, a script), not a chat-driven MCP tool.

Text-to-speech (bring your own key)

Set ENGRAMO_TTS_GEMINI_API_KEYS and two extra tools appear: list_tts_voices and generate_card_audio. Given a list of card ids, generate_card_audio synthesizes speech for each card's face text with Gemini TTS, encodes it to MP3, uploads it to your own EngrAmo media, and attaches it as that card's audio_id — the same place a manually recorded upload_media file would go, just done for you.

stdio only, and on purpose. The key is read once, locally, from your own machine's environment and is never sent to EngrAmo or logged. In http mode the server is a shared, multi-tenant deployment — there is no per-session place to put a secret key that stays on the caller's machine — so ENGRAMO_TTS_GEMINI_API_KEYS is read only by stdio; in http mode it is ignored entirely (with a startup warning naming the variable, never its value) and neither tool is registered.

Why a namespaced variable instead of the standard GEMINI_API_KEY? GEMINI_API_KEY is the de-facto standard name set by the Gemini CLI, Google's own SDKs, and many developers' shell profiles. If engramo-mcp read it too, a key already sitting in your environment for an unrelated tool could silently start spending itself the moment you ran engramo-mcp stdio. engramo-mcp never reads GEMINI_API_KEY — only the explicit, namespaced ENGRAMO_TTS_GEMINI_API_KEYS opts you in.

Whose quota does this spend? Yours, not EngrAmo's. This is a different mechanism from the paid generate_tts_for_cards tool (ENGRAMO_ENABLE_PAID_AI), which spends EngrAmo's own metered TTS quota — generate_card_audio spends only your own Gemini API quota/billing, same as if you'd called Gemini directly.

Multiple keys / rotation. ENGRAMO_TTS_GEMINI_API_KEYS accepts a comma-separated list. On each synthesis call the keys are tried in a random order; a key that's rate-limited, rejected (invalid or revoked), or hits a transient error is skipped in favor of the next one, so one bad key in the list doesn't fail the whole call.

Limits. Up to 20 cards per generate_card_audio call, up to 500 characters of face text per card (longer cards are skipped, not truncated). Cards that already have face audio are skipped unless you pass overwrite: true, in which case the previous audio is not deleted — it stays in your EngrAmo media storage and keeps showing up in list_media. Call list_tts_voices first to see the configured model and voice catalog.

Getting a key. Create one for free at Google AI Studio.

Where the key goes. Every stdio client section above shows the exact place for ENGRAMO_TTS_GEMINI_API_KEYS — see Choosing a client. It's always one more entry next to ENGRAMO_API_TOKEN in the server's env:

"env": {
  "ENGRAMO_API_URL": "https://api.engramo.app",
  "ENGRAMO_API_TOKEN": "your-token",
  "ENGRAMO_TTS_GEMINI_API_KEYS": "your-gemini-key"
}

Quick check. Ask the assistant to call list_tts_voices. If the tool is missing, the key isn't set (or the client wasn't restarted) or the client is using a remote connection.

Third-party licenses

The prebuilt binaries distributed via npm statically link LAME (LGPL-2.0) for the MP3 encoding generate_card_audio uses. See THIRD_PARTY_LICENSES for the full notice and source-availability terms.

Resources and Prompts

The server also exposes MCP Resources (live data readable as context):

URI Description
engramo://card-schema CardContent JSON schema with validation rules and examples
engramo://catalogs All catalogs (id, name, card_count)
engramo://learning/due Cards due for review today
engramo://learning/stats Learning stats (due_count, total_count)
engramo://learning-paths All learning paths (id, name)
engramo://subscription User subscription/plan information

And MCP Prompts (guided workflows):

Prompt Description
review_session Start a guided spaced-repetition review session
create_flashcard Create a high-quality flashcard for a topic
create_language_deck Create a styled, translated, dictionary-annotated language-learning deck — see docs/prompt-examples.md
explain_card Explain a flashcard in depth with examples
study_plan Build a structured study plan from your catalogs

Publishing to npm

git tag vx.y.z                                                                                                                                                                                                      
git push origin vx.y.z

The release workflow also publishes server.json to the official MCP Registry as app.engramo/mcp, after the GitHub release and npm packages exist. One-time setup, key rotation and bumping the pinned mcp-publisher are in docs/mcp-registry.md.

Contributing

Bug reports and pull requests are welcome at github.com/engramo-developer/engramo-mcp/issues.

1[![npm version](https://img.shields.io/npm/v/@engramo/mcp)](https://www.npmjs.com/package/@engramo/mcp)
2[![CI](https://github.com/engramo-developer/engramo-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/engramo-developer/engramo-mcp/actions/workflows/ci.yml)
3[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
4 
5# engramo-mcp
6 
7MCP server for [EngrAmo](https://engramo.app), the spaced-repetition flashcard platform.
8 
9## Hosted server
10 
11The hosted server at `https://mcp.engramo.app/` needs no installation. It supports OAuth 2.0 with Dynamic Client
12Registration: your client sends you to the EngrAmo sign-in page, you sign in with your EngrAmo email and password
13and approve — no API token to paste. There is no sign-up on that page, so create your account in the EngrAmo app
14first. Setup guides: [Claude](#claude-hosted-connector) and [ChatGPT](#use-in-chatgpt-remote-mcp-over-streamable-http);
15the public docs are at <https://engramo.app/connect/>. You can revoke access any time in the EngrAmo app under
16Settings → Connected apps.
17 
18## Prerequisites
19 
20- An EngrAmo account
21- An EngrAmo API token — generate one from your account's Settings → API Tokens page. Only needed for the local
22 (`stdio`) setups below and for remote clients without OAuth; the hosted connectors use OAuth instead.
23 
24## Environments
25 
26`engramo-mcp` is environment-agnostic — the binary itself has no baked-in "dev" or "prod." Which server it
27talks to is controlled entirely by the `ENGRAMO_API_URL` you set in your client config, paired with a token
28minted from that **same** environment:
29 
30| Environment | `ENGRAMO_API_URL` | MCP server URL (`http` transport only) | Who it's for |
31|---|---|---|---|
32| **Production** (default in every example below) | `https://api.engramo.app` | `https://mcp.engramo.app` | Real accounts — use this unless you have a specific reason not to |
33| **Dev** | `https://api-engram.volmyr.com` | `https://mcp-engramo.volmyr.com` | EngrAmo team / internal testing only |
34 
35**Dev and prod are separate backends with separate accounts.** A token minted from one will not authenticate
36against the other — if you switch `ENGRAMO_API_URL`, you must also swap in a token generated from that same
37environment's Settings → API Tokens page.
38 
39**`ENGRAMO_API_URL` vs the MCP server URL — these are not interchangeable.** `ENGRAMO_API_URL` is the plain
40EngrAmo backend; it's never something a client connects to directly. In `stdio` config (Claude Desktop,
41Claude Code, Codex, VS Code, Cursor, Windsurf, Gemini CLI, Antigravity stdio below), the client sets
42`ENGRAMO_API_URL` **together with** `ENGRAMO_API_TOKEN`, since the locally-launched binary calls the backend
43itself. In `http`/remote config (Antigravity remote, ChatGPT), the
44client instead points `serverUrl` at the MCP server's own URL (`mcp.engramo.app` / `mcp-engramo.volmyr.com`
45above) and authenticates separately per session — via OAuth by default, or a static `Authorization: Bearer`
46header if you'd rather skip the login prompt. `ENGRAMO_API_URL` still matters in `http` mode, but only as an
47env var set by whoever deploys `engramo-mcp http` — a client never sets it.
48 
49## Installation
50 
51Install the MCP server globally so it's available as a system command:
52 
53```bash
54npm install -g @engramo/mcp
55```
56 
57Prebuilt binaries ship for macOS (arm64, x64), Linux (arm64, x64) and Windows (x64). On other platforms, build
58from source with `cargo build --release`.
59 
60Verify the installation:
61 
62```bash
63engramo-mcp --version
64```
65 
66> Alternatively, skip installation entirely and use `npx -y @engramo/mcp` in your client config — npm will download the binary automatically on first use.
67 
68## Choosing a client
69 
70Any MCP client works. Local [text-to-speech](#text-to-speech-bring-your-own-key) needs a `stdio`
71(locally launched) connection, so remote-only clients never get it.
72 
73| Client | Models | Local TTS | Setup |
74|---|---|---|---|
75| Claude Desktop | Claude | ✅ | [Claude Desktop](#claude-desktop) — recommended for non-technical users: one-click extension, no Node.js or config editing; the free plan supports local extensions |
76| Claude Code | Claude | ✅ | [Claude Code](#claude-code) |
77| Codex (CLI / IDE extension) | OpenAI models — sign in with your ChatGPT account | ✅ | [Codex](#codex) |
78| VS Code (GitHub Copilot) | GPT / Claude / Gemini | ✅ | [VS Code](#vs-code-github-copilot-agent-mode) |
79| Cursor | GPT / Claude / Gemini | ✅ | [Cursor](#cursor) |
80| Windsurf | GPT / Claude / Gemini | ✅ | [Windsurf](#windsurf) |
81| Gemini CLI | Gemini | ✅ | [Gemini CLI](#gemini-cli) |
82| Antigravity | Gemini / Claude / GPT | ✅ stdio / ❌ remote | [Antigravity](#antigravity) |
83| Claude (claude.ai, Desktop, mobile) | Claude | ❌ — hosted connector only; local TTS intentionally unavailable | [Claude (hosted connector)](#claude-hosted-connector) |
84| ChatGPT | OpenAI models | ❌ — remote connector only (OAuth); local TTS intentionally unavailable | [ChatGPT](#use-in-chatgpt-remote-mcp-over-streamable-http) |
85 
86## Claude Desktop
87 
88### One-click extension (recommended)
89 
901. Download [`engramo.mcpb`](https://github.com/engramo-developer/engramo-mcp/releases/latest/download/engramo.mcpb)
91 from the latest release (macOS on Intel and Apple Silicon, Windows x64, Linux x64 and arm64).
922. Double-click it (or drag it onto Claude Desktop) and click **Install**. Claude Desktop warns that the
93 developer isn't verified by Anthropic; it shows this for every extension installed from a file.
943. Paste your **EngrAmo API token**, and optionally your Gemini API keys (comma-separated) to enable
95 [card audio](#text-to-speech-bring-your-own-key). Claude Desktop stores both in the OS keychain.
96 
97No Node.js and no config file. Change the token or keys later under **Settings → Extensions → EngrAmo →
98Configure**. The extension doesn't auto-update: install the new `engramo.mcpb` to upgrade. Its tools are
99available in **Chat** conversations, not in Claude Desktop's Code mode. The bundle is built from
100[`mcpb/manifest.json`](mcpb/manifest.json) by the release workflow. Verify a download with
101`gh attestation verify engramo.mcpb -R engramo-developer/engramo-mcp --signer-workflow engramo-developer/engramo-mcp/.github/workflows/release.yml --source-ref refs/tags/vX.Y.Z`
102(substituting the release tag), or compare it with the release's
103`engramo.mcpb.sha256`.
104 
105### Manual config
106 
107Open **Settings → Developer → Edit Config**, or edit the file directly:
108`~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or
109`%APPDATA%\Claude\claude_desktop_config.json` (Windows):
110 
111**Using npx** (no prior installation needed):
112```json
113{
114 "mcpServers": {
115 "engramo": {
116 "command": "npx",
117 "args": ["-y", "@engramo/mcp"],
118 "env": {
119 "ENGRAMO_API_URL": "https://api.engramo.app",
120 "ENGRAMO_API_TOKEN": "your-token",
121 "ENGRAMO_TTS_GEMINI_API_KEYS": "your-gemini-key"
122 }
123 }
124 }
125}
126```
127 
128`ENGRAMO_TTS_GEMINI_API_KEYS` is optional — it enables `list_tts_voices`/`generate_card_audio` using your own
129Gemini quota; omit the line to disable. See [Text-to-speech](#text-to-speech-bring-your-own-key).
130 
131**Using a global install** (`npm install -g @engramo/mcp`):
132```json
133{
134 "mcpServers": {
135 "engramo": {
136 "command": "engramo-mcp",
137 "env": {
138 "ENGRAMO_API_URL": "https://api.engramo.app",
139 "ENGRAMO_API_TOKEN": "your-token"
140 }
141 }
142 }
143}
144```
145 
146After editing, fully quit Claude Desktop (⌘Q on macOS — closing the window isn't enough) and reopen it.
147If the server doesn't show up, check the logs at `~/Library/Logs/Claude/mcp-server-engramo.log` (macOS) or
148`%APPDATA%\Claude\logs\` (Windows). The Gemini key is never logged.
149 
150## Claude (hosted connector)
151 
152Use the hosted server from claude.ai, Claude Desktop, or Claude mobile — no install, no token:
153 
1541. **Settings → Connectors → Add custom connector**
1552. Paste `https://mcp.engramo.app/`
1563. **Connect**, sign in with your EngrAmo account, and approve.
157 
158All hosted tools are then available. Like every remote connection, it has no local
159[text-to-speech](#text-to-speech-bring-your-own-key); use the [Claude Desktop](#claude-desktop) extension for that.
160 
161## Claude Code
162 
163Register the server once for all your projects (`--scope user`):
164 
165```bash
166claude mcp add engramo --scope user \
167 -e ENGRAMO_API_URL=https://api.engramo.app \
168 -e ENGRAMO_API_TOKEN=your-token \
169 -e ENGRAMO_TTS_GEMINI_API_KEYS=your-gemini-key \
170 -- npx -y @engramo/mcp
171```
172 
173`ENGRAMO_TTS_GEMINI_API_KEYS` is optional — it enables `list_tts_voices`/`generate_card_audio` using your own
174Gemini quota; omit the `-e ENGRAMO_TTS_GEMINI_API_KEYS=…` line to disable. See
175[Text-to-speech](#text-to-speech-bring-your-own-key).
176 
177With a global install, replace `npx -y @engramo/mcp` with `engramo-mcp`.
178 
179## Codex
180 
181The OpenAI Codex CLI and the Codex IDE extension share one config file, `~/.codex/config.toml`. This is the
182way to use your ChatGPT account's models **with** local TTS (the ChatGPT app's remote connector can't have it):
183 
184**Using npx** (no prior installation needed):
185```toml
186[mcp_servers.engramo]
187command = "npx"
188args = ["-y", "@engramo/mcp"]
189tool_timeout_sec = 300 # default 60s; a 20-card generate_card_audio batch can take longer
190env = { ENGRAMO_API_URL = "https://api.engramo.app", ENGRAMO_API_TOKEN = "your-token", ENGRAMO_TTS_GEMINI_API_KEYS = "your-gemini-key" }
191```
192 
193`ENGRAMO_TTS_GEMINI_API_KEYS` is optional — it enables `list_tts_voices`/`generate_card_audio` using your own
194Gemini quota; omit it from `env` to disable. See [Text-to-speech](#text-to-speech-bring-your-own-key).
195 
196**Using a global install** (`npm install -g @engramo/mcp`):
197```toml
198[mcp_servers.engramo]
199command = "engramo-mcp"
200env = { ENGRAMO_API_URL = "https://api.engramo.app", ENGRAMO_API_TOKEN = "your-token" }
201```
202 
203## VS Code (GitHub Copilot agent mode)
204 
205Add to `.vscode/mcp.json` (workspace), or run **MCP: Open User Configuration** from the Command Palette for a
206user-wide config. Use `inputs` with `"password": true` so VS Code prompts for the secrets and stores them
207itself instead of you writing them into the file. Note the top-level key is `servers` (not `mcpServers`):
208 
209**Using npx** (no prior installation needed):
210```json
211{
212 "inputs": [
213 { "type": "promptString", "id": "engramo-token", "description": "EngrAmo API token", "password": true },
214 { "type": "promptString", "id": "gemini-key", "description": "Gemini API key (for TTS)", "password": true }
215 ],
216 "servers": {
217 "engramo": {
218 "type": "stdio",
219 "command": "npx",
220 "args": ["-y", "@engramo/mcp"],
221 "env": {
222 "ENGRAMO_API_URL": "https://api.engramo.app",
223 "ENGRAMO_API_TOKEN": "${input:engramo-token}",
224 "ENGRAMO_TTS_GEMINI_API_KEYS": "${input:gemini-key}"
225 }
226 }
227 }
228}
229```
230 
231`ENGRAMO_TTS_GEMINI_API_KEYS` is optional — it enables `list_tts_voices`/`generate_card_audio` using your own
232Gemini quota; omit the line (and the `gemini-key` input) to disable. See
233[Text-to-speech](#text-to-speech-bring-your-own-key).
234 
235With a global install, use `"command": "engramo-mcp"` and drop `args`.
236 
237## Cursor
238 
239Add to `~/.cursor/mcp.json`:
240 
241**Using npx** (no prior installation needed):
242```json
243{
244 "mcpServers": {
245 "engramo": {
246 "command": "npx",
247 "args": ["-y", "@engramo/mcp"],
248 "env": {
249 "ENGRAMO_API_URL": "https://api.engramo.app",
250 "ENGRAMO_API_TOKEN": "your-token",
251 "ENGRAMO_TTS_GEMINI_API_KEYS": "your-gemini-key"
252 }
253 }
254 }
255}
256```
257 
258`ENGRAMO_TTS_GEMINI_API_KEYS` is optional — it enables `list_tts_voices`/`generate_card_audio` using your own
259Gemini quota; omit the line to disable. See [Text-to-speech](#text-to-speech-bring-your-own-key).
260 
261**Using a global install** (`npm install -g @engramo/mcp`):
262```json
263{
264 "mcpServers": {
265 "engramo": {
266 "command": "engramo-mcp",
267 "env": {
268 "ENGRAMO_API_URL": "https://api.engramo.app",
269 "ENGRAMO_API_TOKEN": "your-token"
270 }
271 }
272 }
273}
274```
275 
276## Windsurf
277 
278Add to `~/.codeium/windsurf/mcp_config.json`:
279 
280**Using npx** (no prior installation needed):
281```json
282{
283 "mcpServers": {
284 "engramo": {
285 "command": "npx",
286 "args": ["-y", "@engramo/mcp"],
287 "env": {
288 "ENGRAMO_API_URL": "https://api.engramo.app",
289 "ENGRAMO_API_TOKEN": "your-token",
290 "ENGRAMO_TTS_GEMINI_API_KEYS": "your-gemini-key"
291 }
292 }
293 }
294}
295```
296 
297`ENGRAMO_TTS_GEMINI_API_KEYS` is optional — it enables `list_tts_voices`/`generate_card_audio` using your own
298Gemini quota; omit the line to disable. See [Text-to-speech](#text-to-speech-bring-your-own-key).
299 
300**Using a global install** (`npm install -g @engramo/mcp`):
301```json
302{
303 "mcpServers": {
304 "engramo": {
305 "command": "engramo-mcp",
306 "env": {
307 "ENGRAMO_API_URL": "https://api.engramo.app",
308 "ENGRAMO_API_TOKEN": "your-token"
309 }
310 }
311 }
312}
313```
314 
315## Gemini CLI
316 
317Add to `~/.gemini/settings.json`:
318 
319**Using npx** (no prior installation needed):
320```json
321{
322 "mcpServers": {
323 "engramo": {
324 "command": "npx",
325 "args": ["-y", "@engramo/mcp"],
326 "env": {
327 "ENGRAMO_API_URL": "https://api.engramo.app",
328 "ENGRAMO_API_TOKEN": "your-token",
329 "ENGRAMO_TTS_GEMINI_API_KEYS": "your-gemini-key"
330 }
331 }
332 }
333}
334```
335 
336`ENGRAMO_TTS_GEMINI_API_KEYS` is optional — it enables `list_tts_voices`/`generate_card_audio` using your own
337Gemini quota; omit the line to disable. See [Text-to-speech](#text-to-speech-bring-your-own-key).
338 
339**Using a global install** (`npm install -g @engramo/mcp`):
340```json
341{
342 "mcpServers": {
343 "engramo": {
344 "command": "engramo-mcp",
345 "env": {
346 "ENGRAMO_API_URL": "https://api.engramo.app",
347 "ENGRAMO_API_TOKEN": "your-token"
348 }
349 }
350 }
351}
352```
353 
354## Antigravity
355 
356Antigravity supports both transports directly via its own config file — no separate remote-connector UI
357needed like ChatGPT's. Add to `~/.gemini/config/mcp_config.json` (global) or `.agents/mcp_config.json`
358(workspace-local):
359 
360**stdio, via npx** (no prior installation needed):
361```json
362{
363 "mcpServers": {
364 "engramo": {
365 "command": "npx",
366 "args": ["-y", "@engramo/mcp"],
367 "env": {
368 "ENGRAMO_API_URL": "https://api.engramo.app",
369 "ENGRAMO_API_TOKEN": "your-token"
370 }
371 }
372 }
373}
374```
375 
376**Remote, over Streamable HTTP** (point at a running `engramo-mcp http` deployment — see below).
377`engramo-mcp` supports OAuth 2.1 dynamic client registration, so Antigravity can handle
378authentication automatically — no token to paste or manage:
379```json
380{
381 "mcpServers": {
382 "engramo": {
383 "serverUrl": "https://mcp.engramo.app/"
384 }
385 }
386}
387```
388 
389If you'd rather use a static token instead (no OAuth login prompt), add `headers` manually:
390```json
391{
392 "mcpServers": {
393 "engramo": {
394 "serverUrl": "https://mcp.engramo.app/",
395 "headers": {
396 "Authorization": "Bearer your-token"
397 }
398 }
399 }
400}
401```
402 
403Text-to-speech is unavailable over the remote transport — use the stdio config above if you want
404`generate_card_audio`.
405 
406## Use in ChatGPT (remote MCP over Streamable HTTP)
407 
408`engramo-mcp` also runs as a **remote** server, so it can be added to ChatGPT as a custom connector (developer
409mode) without installing anything locally. The hosted server at `https://mcp.engramo.app/` already works this way. This is the same binary — the `http` subcommand instead of the
410default `stdio` — so a self-hosted deployment serves both Claude Desktop users (stdio) and ChatGPT users
411(HTTP) from one codebase.
412 
413```bash
414ENGRAMO_API_URL=https://api.engramo.app MCP_BIND_ADDR=0.0.0.0:8080 engramo-mcp http
415```
416 
417This serves MCP over Streamable HTTP at `POST /` (root). Unlike `stdio` mode, there is **no global
418`ENGRAMO_API_TOKEN`** — every session authenticates with its own `Authorization: Bearer <token>` header, so one
419deployment safely serves many users at once (each session's calls to the EngrAmo API use only that session's
420token). Requests without a well-formed, non-empty bearer token are rejected with `401` before a session is
421created, and once a session exists every later request on it must carry the same token that opened it.
422 
423`http` mode also serves an unauthenticated `GET /version` that returns `{"name","version"}` (this
424binary's build version, read from `Cargo.toml` at compile time) — handy for deployment health and
425version probes without an MCP handshake.
426 
427In ChatGPT, enable developer mode (**Settings → Connectors → Advanced → Developer mode**), then add an app
428pointing at `https://mcp.engramo.app/` (or your own deployment's `https://<host>/`). ChatGPT signs you in
429through OAuth: sign in with your EngrAmo account and approve — no API token needs to be pasted. (Clients
430without OAuth can instead send an EngrAmo API token from Settings → API Tokens as a static
431`Authorization: Bearer` header.) Once connected, prompts like *"Make me a 10-card Spanish restaurant deck"* or *"Turn this
432conversation into flashcards"* call `generate_catalog_with_cards` directly; open the result at
433`https://study.engramo.app/catalog/<shortId>` to study it.
434 
435> `generate_card_audio` is never available through a ChatGPT connector — it's a remote connection, and local
436> [text-to-speech](#text-to-speech-bring-your-own-key) is `stdio`-only by design. To use your ChatGPT
437> account's models with local TTS, use [Codex](#codex) instead.
438 
439> A listing in the public ChatGPT app directory is coming; until then, add the app in developer mode as above.
440 
441### ChatGPT plugin package (maintainers)
442 
443The directory listing is submitted on [platform.openai.com/plugins](https://platform.openai.com/plugins) as a
444plugin ZIP built from [`chatgpt-plugin/`](chatgpt-plugin/): `plugin.json` holds the listing metadata and
445`mcp.json` points at `https://mcp.engramo.app/` with OAuth via dynamic client registration (no client ID or
446secret). Build it with:
447 
448```bash
449./chatgpt-plugin/build.sh # → target/engramo-chatgpt-plugin.zip
450```
451 
452The script copies the icon from `mcpb/` and sets `version` from `Cargo.toml`. Upload a new ZIP (**Plugins →
453EngrAmo → Upload new version**) only when the listing metadata changes; tool and server changes are picked up
454by **Rescan**. The domain-verification token served at `/.well-known/openai-apps-challenge` comes from the
455portal and is set as the `_OPENAI_APPS_CHALLENGE` substitution on the prod Cloud Build trigger, not in this repo.
456 
457## Bring-your-own-AI
458 
459Every deployment is **bring-your-own-AI**: the calling model (Claude, ChatGPT, …) does all generation —
460translation, dictionaries, phrasing — and `engramo-mcp` only persists the result via `generate_card` /
461`generate_catalog_with_cards` / `generate_cards`. This costs the EngrAmo account nothing beyond normal
462storage quotas, and needs no paid EngrAmo plan.
463 
464## Environment variables
465 
466| Variable | Default | Description |
467|---|---|---|
468| `ENGRAMO_API_URL` | `https://api.engramo.app` | Base URL of the EngrAmo API |
469| `ENGRAMO_API_TOKEN` | *(required for `stdio`)* | Your EngrAmo API token. Unused in `http` mode — each session supplies its own via the `Authorization: Bearer` header. |
470| `MCP_BIND_ADDR` | `0.0.0.0:8080` | Bind address for `http` mode |
471| `MCP_PUBLIC_URL` | *(unset)* | `http` mode only — this deployment's own public URL (bare origin, no path — the endpoint is served at `/`), e.g. `https://mcp.engramo.app`. Also allowlists that host for inbound requests; without it, every request is rejected (see `MCP_ALLOWED_HOSTS`). |
472| `MCP_ALLOWED_HOSTS` | *(unset)* | `http` mode only — extra comma-separated hostnames/`host:port` values to permit, on top of the one derived from `MCP_PUBLIC_URL`. Only needed for extra entry points (e.g. a Cloud Run service's own `*.run.app` fallback URL alongside its custom domain). |
473| `ENGRAMO_TTS_GEMINI_API_KEYS` | *(unset → TTS tools absent)* | **`stdio` only.** Your own Gemini API key, or a comma-separated list. Enables `list_tts_voices`/`generate_card_audio`. Ignored (with a startup warning) in `http` mode — see [Text-to-speech](#text-to-speech-bring-your-own-key) below. |
474| `ENGRAMO_TTS_PROVIDER` | `gemini` | **`stdio` only.** TTS engine selector. Only `gemini` is supported today; an unrecognized value fails startup. |
475| `ENGRAMO_TTS_MODEL` | `gemini-3.8-flash-tts` | **`stdio` only.** Gemini TTS model id. |
476| `ENGRAMO_TTS_VOICE` | `Puck` | **`stdio` only.** Default voice used when a `generate_card_audio` call doesn't specify one. |
477 
478## Available tools
479 
480### Server info
481| Tool | Description |
482|---|---|
483| `get_server_version` | Get this MCP server's own build version (not a catalog/card's `version` field) |
484 
485### Catalogs
486| Tool | Description |
487|---|---|
488| `list_catalogs` | List all flashcard catalogs |
489| `get_catalog` | Get a single catalog by ID |
490| `update_catalog` | Update a catalog's name or description |
491| `delete_catalog` | Delete a catalog |
492 
493### Cards
494| Tool | Description |
495|---|---|
496| `list_cards` | List cards in a catalog |
497| `get_card` | Get a single card by ID |
498| `update_card` | Update a card's content |
499| `delete_card` | Delete a card |
500 
501### Learning
502| Tool | Description |
503|---|---|
504| `get_due_cards` | Get cards due for review today |
505| `get_all_learning_cards` | Get all cards in the learning queue |
506| `add_card_to_learning` | Add a card to the learning queue |
507| `add_catalog_to_learning` | Add all cards from a catalog to the learning queue |
508 
509### Learning paths
510| Tool | Description |
511|---|---|
512| `list_learning_paths` | List all learning paths |
513| `get_learning_path` | Get a single learning path by ID |
514| `create_learning_path` | Create a new learning path |
515| `activate_learning_path` | Activate a learning path |
516| `deactivate_learning_path` | Deactivate a learning path |
517 
518### Search
519| Tool | Description |
520|---|---|
521| `search_global` | Full-text search across all content |
522| `search_catalogs` | Search within a specific catalog |
523 
524### Media
525| Tool | Description |
526|---|---|
527| `list_media` | List uploaded media assets |
528| `upload_media` | Upload a file you already have (a voice recording, an image) and get back a `media_id` to attach to a card or catalog |
529 
530### AI generation (bring-your-own-AI)
531| Tool | Description |
532|---|---|
533| `generate_card` | Create a flashcard — the calling model does any translation/wording itself |
534| `generate_catalog_with_cards` | Create a catalog with cards in one call — same bring-your-own-AI model |
535| `generate_cards` | Add multiple cards to an existing catalog — same bring-your-own-AI model |
536 
537### Text-to-speech (stdio, opt-in)
538Only present when `ENGRAMO_TTS_GEMINI_API_KEYS` is set (`stdio` mode only) — see
539[Text-to-speech](#text-to-speech-bring-your-own-key) below.
540 
541| Tool | Description |
542|---|---|
543| `list_tts_voices` | List the configured TTS engine, model, default voice, and available voices. No network call. |
544| `generate_card_audio` | Synthesize speech for the FACE side of up to 20 cards, upload it to your own media, and attach it — using your own Gemini key/quota |
545 
546## Rich cards: dictionary, styling, images, audio
547 
548Beyond plain text, a card's `face`/`back` can carry:
549 
550| Field | What it does |
551|---|---|
552| `dictionary` | Word → translation map, rendered as clickable highlights in the app |
553| `rich_text` | Styled spans (bold, color, monospace) within the text |
554| `style` | Font/color/background/alignment for the whole face or back |
555| `audio_id` | Your own audio (a recording, a clip from your own TTS) — upload it with `upload_media` first, or set it automatically by calling `generate_card_audio` (`stdio` only, see below) |
556| `visual_id` + `visual_type` | Your own image/video, same pattern as `audio_id` |
557 
558A catalog can also have `image_id` (cover image) set the same way. None of this needs a paid EngrAmo
559plan — dictionary/translation are done by the calling model, images are entirely bring-your-own via
560`upload_media` (max ~10MB per file), and face audio is either bring-your-own the same way or
561generated locally with your own TTS key via `generate_card_audio`. See `engramo://card-schema` for
562the full schema and four worked examples, and [`docs/prompt-examples.md`](docs/prompt-examples.md)
563for ready-to-paste prompts covering all of this end to end.
564 
565**Adding a lot of cards/media at once?** `upload_media` is one file per call, fine for a handful of
566files through a chat client. For bulk imports (many cards, many audio files, in one request) see
567[`docs/bulk-import.md`](docs/bulk-import.md) — a direct API recipe for CLI/scripted use (Claude
568Code, a terminal, a script), not a chat-driven MCP tool.
569 
570## Text-to-speech (bring your own key)
571 
572Set `ENGRAMO_TTS_GEMINI_API_KEYS` and two extra tools appear: `list_tts_voices` and
573`generate_card_audio`. Given a list of card ids, `generate_card_audio` synthesizes speech for each
574card's **face** text with Gemini TTS, encodes it to MP3, uploads it to your own EngrAmo media, and
575attaches it as that card's `audio_id` — the same place a manually recorded `upload_media` file would
576go, just done for you.
577 
578**`stdio` only, and on purpose.** The key is read once, locally, from your own machine's
579environment and is never sent to EngrAmo or logged. In `http` mode the server is a shared,
580multi-tenant deployment — there is no per-session place to put a secret key that stays on the
581caller's machine — so `ENGRAMO_TTS_GEMINI_API_KEYS` is read only by `stdio`; in `http` mode it is
582ignored entirely (with a startup warning naming the variable, never its value) and neither tool is
583registered.
584 
585**Why a namespaced variable instead of the standard `GEMINI_API_KEY`?** `GEMINI_API_KEY` is the
586de-facto standard name set by the Gemini CLI, Google's own SDKs, and many developers' shell
587profiles. If `engramo-mcp` read it too, a key already sitting in your environment for an unrelated
588tool could silently start spending itself the moment you ran `engramo-mcp stdio`. `engramo-mcp`
589**never reads `GEMINI_API_KEY`** — only the explicit, namespaced `ENGRAMO_TTS_GEMINI_API_KEYS` opts
590you in.
591 
592**Whose quota does this spend?** Yours, not EngrAmo's. This is a different mechanism from the paid
593`generate_tts_for_cards` tool (`ENGRAMO_ENABLE_PAID_AI`), which spends EngrAmo's own metered TTS
594quota — `generate_card_audio` spends only your own Gemini API quota/billing, same as if you'd called
595Gemini directly.
596 
597**Multiple keys / rotation.** `ENGRAMO_TTS_GEMINI_API_KEYS` accepts a comma-separated list. On each
598synthesis call the keys are tried in a random order; a key that's rate-limited, rejected (invalid or
599revoked), or hits a transient error is skipped in favor of the next one, so one bad key in the list
600doesn't fail the whole call.
601 
602**Limits.** Up to 20 cards per `generate_card_audio` call, up to 500 characters of face text per
603card (longer cards are skipped, not truncated). Cards that already have face audio are skipped
604unless you pass `overwrite: true`, in which case the previous audio is **not** deleted — it stays
605in your EngrAmo media storage and keeps showing up in `list_media`. Call `list_tts_voices` first
606to see the configured model and voice catalog.
607 
608**Getting a key.** Create one for free at [Google AI Studio](https://aistudio.google.com/apikey).
609 
610**Where the key goes.** Every `stdio` client section above shows the exact place for
611`ENGRAMO_TTS_GEMINI_API_KEYS` — see [Choosing a client](#choosing-a-client). It's always one more entry
612next to `ENGRAMO_API_TOKEN` in the server's `env`:
613```json
614"env": {
615 "ENGRAMO_API_URL": "https://api.engramo.app",
616 "ENGRAMO_API_TOKEN": "your-token",
617 "ENGRAMO_TTS_GEMINI_API_KEYS": "your-gemini-key"
618}
619```
620 
621**Quick check.** Ask the assistant to call `list_tts_voices`. If the tool is missing, the key isn't set
622(or the client wasn't restarted) or the client is using a remote connection.
623 
624## Third-party licenses
625 
626The prebuilt binaries distributed via npm statically link [LAME](https://lame.sourceforge.io/)
627(LGPL-2.0) for the MP3 encoding `generate_card_audio` uses. See
628[`THIRD_PARTY_LICENSES`](THIRD_PARTY_LICENSES) for the full notice and source-availability terms.
629 
630## Resources and Prompts
631 
632The server also exposes **MCP Resources** (live data readable as context):
633 
634| URI | Description |
635|---|---|
636| `engramo://card-schema` | CardContent JSON schema with validation rules and examples |
637| `engramo://catalogs` | All catalogs (id, name, card_count) |
638| `engramo://learning/due` | Cards due for review today |
639| `engramo://learning/stats` | Learning stats (due_count, total_count) |
640| `engramo://learning-paths` | All learning paths (id, name) |
641| `engramo://subscription` | User subscription/plan information |
642 
643And **MCP Prompts** (guided workflows):
644 
645| Prompt | Description |
646|---|---|
647| `review_session` | Start a guided spaced-repetition review session |
648| `create_flashcard` | Create a high-quality flashcard for a topic |
649| `create_language_deck` | Create a styled, translated, dictionary-annotated language-learning deck — see [`docs/prompt-examples.md`](docs/prompt-examples.md) |
650| `explain_card` | Explain a flashcard in depth with examples |
651| `study_plan` | Build a structured study plan from your catalogs |
652 
653## Publishing to npm
654```bash
655git tag vx.y.z
656git push origin vx.y.z
657```
658 
659The release workflow also publishes `server.json` to the official
660[MCP Registry](https://registry.modelcontextprotocol.io) as `app.engramo/mcp`, after the GitHub release and npm
661packages exist. One-time setup, key rotation and bumping the pinned `mcp-publisher` are in
662[`docs/mcp-registry.md`](docs/mcp-registry.md).
663 
664## Contributing
665 
666Bug reports and pull requests are welcome at
667[github.com/engramo-developer/engramo-mcp/issues](https://github.com/engramo-developer/engramo-mcp/issues).
668 

Discussion

Alternatives