EngrAmo MCP
README.md
[](https://www.npmjs.com/package/@engramo/mcp)
[](https://github.com/engramo-developer/engramo-mcp/actions/workflows/ci.yml)
[](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. EngrAmo is listed in the [Claude Connectors Directory](https://claude.ai/directory/engramo). 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.
## Set up with your AI assistant
Not a developer? An agentic AI app can do the whole setup for you, including card audio. Tested with
[Antigravity](#antigravity) in auto mode; other apps that can run terminal commands and edit files (Claude Code,
Codex, Cursor) should work the same way.
**Prepare two keys first:**
1. **EngrAmo API token**: sign in at <https://study.engramo.app>, open Settings → API Tokens, and create one.
2. **Gemini API key** (for card audio, free): create one at [Google AI Studio](https://aistudio.google.com/apikey).
Keep both somewhere you can copy them from. **Never paste them into the chat**; the setup asks for them in a
private pop-up instead.
**Then paste this prompt into your AI app:**
```text
Set up the EngrAmo MCP server for me, with card audio, following
https://github.com/engramo-developer/engramo-mcp. I'm not a developer, so do every step yourself and
tell me in plain words what you're doing.
1. Download the prebuilt engramo-mcp binary for my computer from the latest GitHub release
(https://github.com/engramo-developer/engramo-mcp/releases/latest/download/<file>, where <file> is
engramo-mcp-darwin-arm64, engramo-mcp-darwin-x64, engramo-mcp-linux-x64, engramo-mcp-linux-arm64
or engramo-mcp-win32-x64.exe). Save it to ~/.engramo/bin/ and make it executable. Don't install
Node.js or npm.
2. Add an "engramo" server to this app's MCP config file. Keep any servers already there. Use the
binary's full path as "command" and set three env values: ENGRAMO_API_URL=https://api.engramo.app,
ENGRAMO_API_TOKEN and ENGRAMO_TTS_GEMINI_API_KEYS.
3. For the two keys, never ask me to paste them into this chat. Ask for each key in my operating
system's own pop-up with a hidden input field (macOS: osascript "display dialog ... with hidden
answer"; Windows: Get-Credential in powershell.exe; Linux: zenity --password or kdialog --password),
and write the value straight into the config file from that same command. Never print, echo or
read back the keys. Only if no pop-up is possible, use a hidden terminal prompt instead. Use one
method at a time, and don't make me edit the config file.
4. Tell me how to reload the MCP servers in this app, and wait until I say done.
5. Check the connection: call get_server_version and list_tts_voices. If something fails, fix it.
6. When both work, say "Ready! What cards should we make?" with the server version.
```
**To check the setup later** (after an update, or if something stops working), paste:
```text
Check my EngrAmo connection: call get_server_version, list_tts_voices and get_subscription_usage.
Tell me in plain words the server version, whether card audio is ready (and the default voice), my
plan, and how many cards I can still create. If any call fails, explain why and how to fix it.
```
When it says ready, ask for cards in your own words, for example:
```text
Create a catalog "Job interview English" with 15 cards of useful interview phrases. Put the phrase on
the front and the meaning plus an example on the back, highlight the key words, and add audio to every
card.
```
More ready-to-paste prompts (cover images, adding audio to a deck, turning notes into cards, study
plans and more): [docs/prompt-examples.md](docs/prompt-examples.md).
## 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:
```bash
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:
```bash
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](#text-to-speech-bring-your-own-key) needs a `stdio`
(locally launched) connection, so remote-only clients never get it.
| Client | Models | Local TTS | Setup |
|---|---|---|---|
| Claude (claude.ai, Desktop, mobile) | Claude | ❌ — hosted connector only; local TTS intentionally unavailable | [Claude (hosted connector)](#claude-hosted-connector) — recommended: install from the Connectors Directory, nothing to download |
| Claude Desktop extension | Claude | ✅ | [Claude Desktop](#claude-desktop) — use it for card audio: one-click extension, no Node.js or config editing; the free plan supports local extensions |
| Claude Code | Claude | ✅ | [Claude Code](#claude-code) |
| Codex (CLI / IDE extension) | OpenAI models — sign in with your ChatGPT account | ✅ | [Codex](#codex) |
| VS Code (GitHub Copilot) | GPT / Claude / Gemini | ✅ | [VS Code](#vs-code-github-copilot-agent-mode) |
| Cursor | GPT / Claude / Gemini | ✅ | [Cursor](#cursor) |
| Windsurf | GPT / Claude / Gemini | ✅ | [Windsurf](#windsurf) |
| Gemini CLI | Gemini | ✅ | [Gemini CLI](#gemini-cli) |
| Antigravity | Gemini / Claude / GPT | ✅ stdio / ❌ remote | [Antigravity](#antigravity) |
| ChatGPT | OpenAI models | ❌ — remote connector only (OAuth); local TTS intentionally unavailable | [ChatGPT](#use-in-chatgpt-remote-mcp-over-streamable-http) |
## Claude Desktop
Most Claude Desktop users should add the [hosted connector](#claude-hosted-connector) from the Connectors Directory
instead: nothing to download, no token to paste, and it also works on claude.ai and mobile. Use the extension
below when you want local [card audio](#text-to-speech-bring-your-own-key), which only a local server can provide.
### One-click extension (for card audio)
1. Download [`engramo.mcpb`](https://github.com/engramo-developer/engramo-mcp/releases/latest/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 shows a red warning
that the extension gets access to everything on your computer and that the developer isn't verified by
Anthropic. It shows this for every extension installed from a file — the Connectors Directory no longer lists
desktop extensions — and it's accurate: the extension runs the `engramo-mcp` binary with your user permissions.
3. Paste your **EngrAmo API token**, and optionally your Gemini API keys (comma-separated) to enable
[card audio](#text-to-speech-bring-your-own-key). 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`](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):
```json
{
"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](#text-to-speech-bring-your-own-key).
**Using a global install** (`npm install -g @engramo/mcp`):
```json
{
"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. Open [EngrAmo in the Connectors Directory](https://claude.ai/directory/engramo) (or **Settings → Connectors →
Browse** and search for EngrAmo).
2. **Connect**, sign in with your EngrAmo account, and approve.
It's a community connector: Anthropic ran automated reviews but hasn't verified it, so Claude shows a short notice
before you connect. Without the directory — for example, if your organization restricts it — add it by URL
instead: **Settings → Connectors → Add custom connector**, paste `https://mcp.engramo.app/`, then **Connect**.
All hosted tools are then available. Like every remote connection, it has no local
[text-to-speech](#text-to-speech-bring-your-own-key); use the [Claude Desktop](#claude-desktop) extension for that.
## Claude Code
Register the server once for all your projects (`--scope user`):
```bash
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](#text-to-speech-bring-your-own-key).
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):
```toml
[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](#text-to-speech-bring-your-own-key).
**Using a global install** (`npm install -g @engramo/mcp`):
```toml
[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):
```json
{
"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](#text-to-speech-bring-your-own-key).
With a global install, use `"command": "engramo-mcp"` and drop `args`.
## Cursor
Add to `~/.cursor/mcp.json`:
**Using npx** (no prior installation needed):
```json
{
"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](#text-to-speech-bring-your-own-key).
**Using a global install** (`npm install -g @engramo/mcp`):
```json
{
"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):
```json
{
"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](#text-to-speech-bring-your-own-key).
**Using a global install** (`npm install -g @engramo/mcp`):
```json
{
"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):
```json
{
"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](#text-to-speech-bring-your-own-key).
**Using a global install** (`npm install -g @engramo/mcp`):
```json
{
"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):
```json
{
"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:
```json
{
"mcpServers": {
"engramo": {
"serverUrl": "https://mcp.engramo.app/"
}
}
}
```
If you'd rather use a static token instead (no OAuth login prompt), add `headers` manually:
```json
{
"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.
```bash
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](#text-to-speech-bring-your-own-key) is `stdio`-only by design. To use your ChatGPT
> account's models with local TTS, use [Codex](#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](https://platform.openai.com/plugins) as a
plugin ZIP built from [`chatgpt-plugin/`](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:
```bash
./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](#text-to-speech-bring-your-own-key) 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
35 tools are always available, and two more appear with [text-to-speech](#text-to-speech-bring-your-own-key)
(local `stdio` only).
For ready-to-paste prompts that use them, see [docs/prompt-examples.md](docs/prompt-examples.md).
### Server info
| Tool | Description |
|---|---|
| `get_server_version` | Get this MCP server's own build version (not a catalog/card's `version` field). No API call |
| `get_subscription_usage` | Your userId, plan and features, and every limit: used, remaining, unlimited or not included, its window (lifetime or monthly, plus daily/hourly sub-limits) and when it resets (UTC). Call it after a "Quota exceeded" or "Not included in your plan" error |
### Catalogs
| Tool | Description |
|---|---|
| `list_catalogs` | List your catalogs with id, name, description, tags, card count, visibility and version; `filter` (`own` or `shared`) limits it to catalogs you own or that others shared with you, and `speaking_only` to catalogs with shadowing on. Also filters by `front_languages` (language of the card fronts), `back_languages` (language of the backs; `zxx` = none), `topics`, `levels` (`A1`–`C2` or `beginner`/`intermediate`/`advanced`) and `tags`, together with free text `q` |
| `get_catalog_filter_options` | The allowed topics, levels, level groups and language codes (plus limits), and live counts of how many catalogs match each value under the same filters as `list_catalogs`. Call it before filtering or classifying a catalog |
| `get_catalog` | Get a single catalog by ID, including its description, tags and shadowing settings |
| `update_catalog` | Update a catalog's name, description, tags, visibility, cover image (`image_id`, from `upload_media`) or classification (`front_languages`, `back_languages`, `topics`, `levels`; each replaces the previous list); needs the current `version` |
| `set_catalog_shadowing` | Turn shadowing (speaking practice) on or off for a catalog, or change its language |
| `share_catalog` | Share a catalog you own with other users by user id (UUID, not email) as `viewer` (default) or `editor`; re-sharing changes their level. Returns the full collaborator list. Ask people for their user id; they can get it from `get_subscription_usage` |
| `unshare_catalog` | Remove users' access to a catalog you own. Returns the remaining collaborators |
| `list_catalog_shares` | List who a catalog is shared with and their access level (owner or editors) |
| `delete_catalog` | Delete a catalog. It is archived instead if it has cards, a cover image, or is in an active learning path; there is no restore |
### Cards
| Tool | Description |
|---|---|
| `list_cards` | List cards in a catalog |
| `get_card` | Get a single card by ID, with its face, back and catalog memberships |
| `update_card` | Update a card's face, back or catalog memberships (needs the current `version`) |
| `delete_card` | Delete a card; a card with learning progress is archived instead |
### Learning
| Tool | Description |
|---|---|
| `get_due_cards` | Get cards due for review today, sorted by priority |
| `get_all_learning_cards` | Get all cards in the learning queue (due and future) |
| `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 |
Reviews are graded in the EngrAmo app; there is no tool for submitting a review.
### Learning paths
| Tool | Description |
|---|---|
| `list_learning_paths` | List all learning paths |
| `get_learning_path` | Get a single learning path by ID, including its catalogs |
| `create_learning_path` | Create a learning path, optionally adding catalogs right away (`catalog_ids`) |
| `update_learning_path` | Update a path's name, description, tags or visibility (`public` or `private`; needs the current `version`) |
| `add_catalog_to_learning_path` | Add a catalog to a learning path |
| `remove_catalog_from_learning_path` | Remove a catalog from a learning path |
| `activate_learning_path` | Activate a learning path so its catalogs are included in daily reviews |
| `deactivate_learning_path` | Deactivate a learning path so its catalogs are left out of daily reviews |
### Search
| Tool | Description |
|---|---|
| `search_global` | Search across cards, catalogs and (on newer API versions) learning paths |
| `search_catalogs` | Search catalogs by name, description or short ID (the ~8-character code shown in the app) |
| `search_learning_paths` | Search learning paths by name or description |
### Media
| Tool | Description |
|---|---|
| `list_media` | List the files you uploaded, optionally filtered by type (`image`, `audio`, ...) |
| `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 |
### Creating cards (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, optionally with a cover image (`image_id`) and classification (`front_languages`, `back_languages`, `topics`, `levels`) — same bring-your-own-AI model. To add or replace the cover of an existing catalog, use `update_catalog` |
| `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](#text-to-speech-bring-your-own-key) 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 with `generate_catalog_with_cards` or later with `update_catalog` (a cover can be replaced, not removed). 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`](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`](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: `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](https://aistudio.google.com/apikey).
**Where the key goes.** Every `stdio` client section above shows the exact place for
`ENGRAMO_TTS_GEMINI_API_KEYS` — see [Choosing a client](#choosing-a-client). It's always one more entry
next to `ENGRAMO_API_TOKEN` in the server's `env`:
```json
"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](https://lame.sourceforge.io/)
(LGPL-2.0) for the MP3 encoding `generate_card_audio` uses. See
[`THIRD_PARTY_LICENSES`](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` | Your userId, plan, limits and usage (same view as `get_subscription_usage`) |
| `engramo://catalog-filters` | Allowed catalog topics, levels and language codes, plus limits (static, no counts; `get_catalog_filter_options` adds live counts) |
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`](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
```bash
git tag vx.y.z
git push origin vx.y.z
```
The release workflow also publishes `server.json` to the official
[MCP Registry](https://registry.modelcontextprotocol.io) 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`](docs/mcp-registry.md).
## Contributing
Bug reports and pull requests are welcome at
[github.com/engramo-developer/engramo-mcp/issues](https://github.com/engramo-developer/engramo-mcp/issues).
This server cannot be deployed
Maintenance
ActivityActive
ResponsivenessLimited data