CLI and MCP server for Duolingo: profile, streak, XP, courses, words, friends, leaderboard
101
Read your Duolingo data from the terminal and from AI assistants: profile, streak, XP, courses, topics, known words, friends, leaderboard, shop and more.
The image contains the duolingo command line interface and an MCP server for AI assistants such as Claude. It is read-only and never changes your Duolingo account. It uses the unofficial Duolingo API.
Source code, full documentation and the npm package: github.com/udondan/duolingo
latest: newest releaseX.Y.Z: exactly this versionX.Y, X: newest release of this minor or major versionPlatforms: linux/amd64 and linux/arm64.
The credentials come from environment variables:
| Variable | Meaning |
|---|---|
DUOLINGO_USERNAME | Your Duolingo username |
DUOLINGO_JWT | Your Duolingo JWT token |
To get the JWT token, log in to duolingo.com, open the browser developer console (F12) and run:
document.cookie.match(new RegExp('(^| )jwt_token=([^;]+)'))[0].slice(11)
JWT tokens expire. If you get authentication errors, repeat this step.
The image runs the duolingo command. -e NAME without a value takes the variable from your shell:
docker run --rm -e DUOLINGO_USERNAME -e DUOLINGO_JWT udondan/duolingo streak
With an alias, the image behaves like an installed duolingo:
alias duolingo='docker run --rm -e DUOLINGO_USERNAME -e DUOLINGO_JWT udondan/duolingo'
duolingo --format markdown progress es
duolingo leaderboard --unit month
Output is JSON, or readable text with --format markdown. duolingo --help lists all commands: user, streak, xp, courses, friends, calendar, leaderboard, progress, known-words, known-topics, shop, health, currencies and more.
Without arguments, the image starts the MCP server (stdio). Entry for Claude Desktop:
{
"mcpServers": {
"duolingo": {
"command": "docker",
"args": ["run", "--rm", "-i", "-e", "DUOLINGO_USERNAME", "-e", "DUOLINGO_JWT", "udondan/duolingo"],
"env": {
"DUOLINGO_USERNAME": "your_username",
"DUOLINGO_JWT": "your_jwt_token"
}
}
}
}
With the Docker MCP Toolkit, the credentials are stored as secrets in Docker Desktop instead of in plain text in the client configuration:
mkdir -p ~/.docker/mcp/catalogs
curl -fsSL https://raw.githubusercontent.com/udondan/duolingo/main/docker-mcp.yml -o ~/.docker/mcp/catalogs/duolingo.yml
docker mcp profile create --name duolingo --id duolingo --server "file://$HOME/.docker/mcp/catalogs/duolingo.yml"
docker mcp secret set duolingo.username=your_username
docker mcp secret set duolingo.jwt=your_jwt_token
docker mcp client connect claude-desktop --profile duolingo
Details in the README.
The images are signed with cosign by the release workflow on GitHub:
cosign verify udondan/duolingo:latest \
--certificate-identity-regexp '^https://github\.com/udondan/duolingo/\.github/workflows/publish\.yml@refs/tags/v' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
Each image also carries SBOM and provenance attestations.
The container runs as the unprivileged user node (UID 1000). The image is based on the official Node.js Alpine image, without npm.
Content type
Image
Digest
sha256:65cc0cedd…
Size
64.7 MB
Last updated
4 days ago
docker pull udondan/duolingo