Skip to main content
Glama
Tavaresiqueira

duo-metrics-mcp

duo-metrics-mcp

Personal Duolingo metrics MCP server for AI assistants.

duo-metrics-mcp lets an MCP-compatible assistant answer daily language-learning questions such as:

  • Did I practice Duolingo today?

  • How much XP did I earn today?

  • How many sessions did I complete?

  • How much time did I spend practicing?

  • What is my current streak?

  • What did my last week or month of Duolingo activity look like?

The server uses Duolingo's unofficial web endpoints. Public profile lookup works without authentication. Daily XP summaries require an authenticated Duolingo web session cookie.

Status

This is an unofficial personal-use MCP server. Duolingo does not publish or support these endpoints for third-party API use, so endpoint behavior can change without notice.

The current implementation is intentionally lightweight:

  • no database

  • no background scheduler

  • no password login

  • live API reads on demand

  • optional local ignored session file for authenticated calls

Related MCP server: Strava MCP Server

Tools

duolingo_get_public_profile

Fetches public profile data by username.

Authentication: not required.

Useful for:

  • user id discovery

  • public streak data

  • total XP

  • active course

  • course XP split

Input:

{
  "username": "JoaoPedroS572669"
}

duolingo_get_authenticated_profile

Fetches the richer authenticated profile by user id.

Authentication: required.

Input:

{
  "userId": 955434155472097
}

duolingo_get_xp_summaries

Fetches daily XP summaries, including sessions, total practice time, and streak extension status.

Authentication: required.

Input:

{
  "userId": 955434155472097,
  "startDate": "2026-06-01",
  "endDate": "2026-06-20",
  "timezone": "America/Sao_Paulo",
  "readable": true
}

Example output:

{
  "userId": 955434155472097,
  "timezone": "America/Sao_Paulo",
  "summaries": [
    {
      "date": "2026-06-20",
      "gainedXp": 353,
      "numSessions": 11,
      "totalSessionTimeSeconds": 1057,
      "totalSessionTimeMinutes": 17.6,
      "streakExtended": true,
      "frozen": false,
      "repaired": false,
      "dailyGoalXp": 1,
      "shielded": false
    }
  ]
}

duolingo_today_status

Returns a compact daily status for assistant workflows.

Authentication: required.

Input:

{
  "userId": 955434155472097,
  "timezone": "America/Sao_Paulo"
}

Example output:

{
  "userId": 955434155472097,
  "date": "2026-06-20",
  "timezone": "America/Sao_Paulo",
  "playedToday": true,
  "xpToday": 353,
  "sessionsToday": 11,
  "minutesToday": 17.6,
  "streakExtended": true
}

duolingo_auth_help

Explains the supported authentication configuration to the assistant.

Authentication: not required.

Requirements

  • Node.js 20 or newer

  • npm

  • an MCP-compatible client that supports stdio servers

Installation

Clone and build:

git clone https://github.com/Tavaresiqueira/duo-metrics-mcp.git
cd duo-metrics-mcp
npm install
npm run build

Run the server manually:

npm start

For development:

npm run dev

Run the smoke test:

npm run smoke

The smoke test builds the project, starts the MCP server through stdio, lists the available tools, calls the public profile tool, and verifies the missing-auth path for authenticated tools.

Configuration

The server reads defaults from environment variables:

$env:DUOLINGO_USERNAME = "JoaoPedroS572669"
$env:DUOLINGO_USER_ID = "955434155472097"

These defaults let assistants call tools without repeating the username or user id on every request.

Authentication

Public profile data does not require authentication.

Daily XP summaries require an authenticated Duolingo session cookie. The server supports two auth modes:

  1. DUOLINGO_COOKIE environment variable

  2. .duolingo-session.json in the repo root

Environment Variable

Set the full Cookie header before starting the MCP server:

$env:DUOLINGO_COOKIE = "jwt_token=...; logged_out_uuid=...; ..."
npm start

Local Session File

Create .duolingo-session.json:

{
  "cookie": "jwt_token=...; logged_out_uuid=...; ...",
  "createdAt": "2026-06-20T18:00:00Z",
  "source": "manual browser session"
}

This file is ignored by git.

You can also create it from the environment variable:

$env:DUOLINGO_COOKIE = "jwt_token=...; logged_out_uuid=...; ..."
npm run save-session
Remove-Item Env:\DUOLINGO_COOKIE

Use a browser where you are already logged in to Duolingo:

  1. Open https://www.duolingo.com/learn.

  2. Open browser developer tools.

  3. Go to the Network tab.

  4. Reload the page.

  5. Select a request to www.duolingo.com.

  6. Copy the request Cookie header.

  7. Store it as DUOLINGO_COOKIE or in .duolingo-session.json.

Do not commit cookies, tokens, or session files.

MCP Client Setup

Use the built server over stdio.

Example config:

{
  "mcpServers": {
    "duo-metrics": {
      "command": "node",
      "args": [
        "C:\\Users\\joao.siqueira\\Documents\\duo-metrics-mcp\\dist\\index.js"
      ],
      "env": {
        "DUOLINGO_USERNAME": "JoaoPedroS572669",
        "DUOLINGO_USER_ID": "955434155472097"
      }
    }
  }
}

If you want authenticated tools without a .duolingo-session.json file, include DUOLINGO_COOKIE in the MCP environment block. Prefer the local session file for personal desktop use so the cookie does not sit in a shared config file.

Best Usage

This MCP works best as a small daily workflow source, not as a full Duolingo clone.

Good assistant prompts:

Check whether I completed Duolingo today.
Show my Duolingo XP for the last 7 days.
Include my Duolingo streak and today's XP in my evening shutdown.
Compare today's Duolingo effort against the last 14 days.
Before I stop working, confirm whether my Duolingo streak is safe.

Recommended workflow:

  1. Keep DUOLINGO_USERNAME and DUOLINGO_USER_ID configured.

  2. Keep .duolingo-session.json local and ignored.

  3. Let the assistant call duolingo_today_status during daily check-ins.

  4. Use duolingo_get_xp_summaries for weekly/monthly review prompts.

  5. Refresh the session cookie only when Duolingo starts returning 401.

Troubleshooting

Authenticated tools return missing session

Set DUOLINGO_COOKIE or create .duolingo-session.json.

Authenticated tools return 401

Your session probably expired. Log in to Duolingo in the browser again, copy a fresh Cookie header, and update .duolingo-session.json.

Public profile lookup fails

Check that the username is the Duolingo username, not the email address. The username is case-insensitive for lookup, but the returned profile may use Duolingo's canonical casing.

Dates look off by one day

Pass the timezone explicitly:

{
  "timezone": "America/Sao_Paulo"
}

Privacy

This server can access personal Duolingo account data when configured with a session cookie. Treat .duolingo-session.json like a secret.

The project intentionally avoids password-based login. It only uses an existing web session cookie that you provide.

Development

Useful commands:

npm run build
npm run typecheck
npm run smoke

Project layout:

src/index.ts            MCP server and tool registration
src/duolingoClient.ts   Duolingo endpoint client and normalization
src/config.ts           Environment/session-file configuration
src/types.ts            Shared TypeScript types
scripts/save-session.mjs
scripts/smoke-test.mjs

Limitations

  • Duolingo endpoints are unofficial.

  • Session cookies can expire.

  • Some browser cookies are HttpOnly, so they cannot be read from document.cookie.

  • The server does not currently persist long-term history.

  • The server does not currently automate login.

Available Tools

5 tools
duolingo_auth_helpDuolingo auth setup helpA

Explain how to configure a Duolingo browser session cookie for authenticated tools.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full burden. It describes a non-destructive action (explaining) but does not explicitly state that it has no side effects or return format. Minimal but adequate for a help tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single, clear sentence that conveys the purpose without any extraneous words. Excellent conciseness.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple help tool with no parameters and no output schema, the description is complete. It covers what the tool does adequately.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There are zero parameters, and input schema coverage is 100% (trivially). The description does not need to add parameter info. Baseline score of 4 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Explain how to configure a Duolingo browser session cookie for authenticated tools.' It uses a specific verb ('Explain') and a unique resource ('Duolingo browser session cookie'), differentiating it from sibling tools that retrieve data.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage context by specifying 'for authenticated tools,' suggesting it should be used before accessing other tools that require authentication. However, it lacks explicit when-not or alternative guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

duolingo_get_authenticated_profileGet authenticated Duolingo profileC

Fetch the richer authenticated profile for a Duolingo user id.

ParametersJSON Schema
NameRequiredDescriptionDefault
userIdNoDuolingo numeric user id. Defaults to DUOLINGO_USER_ID.
usernameNoUsed only to resolve userId when no userId is provided.

TDQS

C2.9/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, and the description does not disclose any behavioral traits such as authentication requirements, rate limits, error conditions, or the structure of the returned data. For a tool fetching user data, this is a significant gap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single sentence with no wasted words. It could be longer to include more context, but as a concise statement it functions adequately.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool has no output schema and the description does not explain what the 'richer authenticated profile' contains. Missing information about prerequisites (e.g., authentication), error handling, and return structure. Not minimal viable for a profile fetch tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% with clear parameter descriptions. The description adds no extra meaning beyond the schema, so baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('Fetch') and the resource ('authenticated profile') for a given user id. It distinguishes from sibling tools like duolingo_get_public_profile by using 'authenticated' and 'richer', but does not explicitly differentiate from other siblings like duolingo_get_xp_summaries.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance on when to use this tool versus alternatives (e.g., when to use authenticated vs public profile, or when to use other tools). The user must infer context from the tool name and siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

duolingo_get_public_profileGet public Duolingo profileB

Fetch public Duolingo profile, streak, total XP, and courses by username.

ParametersJSON Schema
NameRequiredDescriptionDefault
usernameNoDuolingo username. Defaults to DUOLINGO_USERNAME.

TDQS

B3.4/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so description is the sole source. It discloses the fetched data types (profile, streak, XP, courses) but does not mention any side effects, error behavior (e.g., on missing username), rate limits, or that the data is public and requires no authentication. Behavioral traits like 'only public data' are implied but not explicitly stated.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

One clear sentence that states the action and what is fetched. It is concise but could be slightly more efficient by removing the word 'public' since it's in the tool name. No wasted words, but front-loading is adequate.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, so description should explain return values. It lists key return items (profile, streak, XP, courses) but is vague on format or additional metadata. For a simple fetch tool with 1 parameter, it is moderately complete but leaves questions about structure.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% (the only parameter 'username' has a description). The tool description adds 'Defaults to DUOLINGO_USERNAME' which is already in the schema description. No additional meaning beyond what the schema provides, so baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states verb 'Fetch' and resource 'public Duolingo profile, streak, total XP, and courses by username.' It distinguishes from siblings like 'duolingo_get_authenticated_profile' (which requires auth) and 'duolingo_get_xp_summaries' (which focuses on XP). The purpose is specific and unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage for fetching public profile by username but provides no explicit guidance on when to use vs alternatives (e.g., when to choose this over duolingo_get_authenticated_profile or duolingo_today_status). No when-not-to-use conditions are mentioned.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

duolingo_get_xp_summariesGet Duolingo XP summariesB

Fetch authenticated daily XP summaries with sessions and practice time.

ParametersJSON Schema
NameRequiredDescriptionDefault
userIdNoDuolingo numeric user id. Defaults to DUOLINGO_USER_ID.
endDateNoEnd date in YYYY-MM-DD.
readableNoReturn normalized date/minute fields.
timezoneNoAmerica/Sao_Paulo
usernameNoUsed only to resolve userId when no userId is provided.
startDateNoStart date in YYYY-MM-DD.

TDQS

B3.1/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description must disclose behavior. It only states 'Fetch authenticated daily XP summaries' without mentioning authentication requirements, rate limits, data freshness, or any side effects. This is insufficient for safe invocation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single concise sentence front-loaded with the core purpose. However, it could be slightly more informative without becoming verbose, hence 4 instead of 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool has 6 parameters and no output schema, yet the description does not mention return format, pagination, or limitations. It lacks completeness for an agent to understand the full context of usage.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is high (83%), so baseline is 3. The description adds no parameter-specific meaning beyond the schema; it does not explain how parameters like startDate/endDate affect results. No added value for parameter understanding.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool fetches 'daily XP summaries' with specific details 'sessions and practice time'. It uses a specific verb 'Fetch' and resource, distinguishing from sibling tools like duolingo_get_public_profile which focuses on public profile data.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit guidance on when to use this tool vs alternatives. It implies authenticated access (via 'authenticated') but does not mention prerequisites, when not to use, or differentiation from siblings like duolingo_today_status which may also return XP data.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

duolingo_today_statusGet today's Duolingo statusB

Return whether the user practiced today, XP gained, sessions, minutes, and streak status.

ParametersJSON Schema
NameRequiredDescriptionDefault
userIdNoDuolingo numeric user id. Defaults to DUOLINGO_USER_ID.
timezoneNoAmerica/Sao_Paulo
usernameNoUsed only to resolve userId when no userId is provided.

TDQS

B3.4/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description must cover behavioral traits. It does not mention if authentication is needed, rate limits, or side effects. The output fields are listed but not fully detailed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Single sentence of 15 words directly states the tool's purpose. No unnecessary words, front-loads the key action.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description fails to disclose the return format (e.g., types, structure). Lacks details on default behavior for parameters and error handling.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 67%. The description does not add meaning beyond listing output fields; the timezone parameter is unexplained despite having no schema description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool returns today's Duolingo status, including specific data fields like XP, sessions, and streak. It effectively distinguishes from siblings such as profile or XP summarization tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit guidance on when to use this tool versus alternatives. The use case is implied but not clarified, e.g., no mention of prerequisites or scenarios.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 5 tool updatesv0.1.0
    • First observedduolingo_auth_help
    • First observedduolingo_get_authenticated_profile
    • First observedduolingo_get_public_profile
    • First observedduolingo_get_xp_summaries
    • First observedduolingo_today_status

TDQS

A3.6/5.0

Scored across 5 tools

Disambiguation5/5

Each tool targets a distinct aspect of Duolingo data: public profile, authenticated profile, XP summaries, today's status, and auth configuration. There is no overlap in purpose.

Naming Consistency4/5

All tools share the 'duolingo_' prefix and use snake_case, but 'today_status' and 'auth_help' deviate from the 'get_' verb pattern used by the other three. Minor inconsistency.

Tool Count5/5

Five tools is ideal for a focused metrics server covering public info, authenticated details, daily summaries, and configuration. No tool feels redundant or missing.

Completeness4/5

Core Duolingo metrics (profile, XP, streak, daily activity) are covered. Missing historical trends or leaderboard data, but the set is practical for most use cases.

Maintenance

ActivityInactive
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    D
    maintenance
    Integrates with the Strava API to allow AI assistants to access fitness data including athlete profiles, activity history, and segment statistics. It enables users to query detailed performance metrics and explore geographic segment data through natural language commands.
    8
    43 npm
    MIT
  • A
    license
    B
    quality
    D
    maintenance
    Enables users to interact with their Strava data through natural language to analyze workouts, track fitness progress, and explore routes. It supports retrieving detailed activity stats, heart rate data, and segment insights directly within AI assistants.
    26
    338 npm
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI assistants to query live Garmin Connect health and fitness data, including daily metrics, activities, sleep analysis, and trends via natural language.
    MIT