# LINGUATRACK — MACHINE-READABLE INTEGRATION GUIDE # https://lingotrack.duckdns.org # Everything an agent needs to connect and use this service. No HTML, no JS. ## WHAT THIS IS LinguaTrack is a persistent memory of a language learner's mistakes, exposed over the Model Context Protocol (MCP). An assistant connected to it can: - read what the learner keeps getting wrong, across sessions and across clients; - write down every correction it makes, so the next session starts informed; - report progress (CEFR level, weak areas, recurring errors). It works identically in text and voice sessions. ## ENDPOINTS MCP https://lingotrack.duckdns.org/mcp Streamable HTTP, stateless, JSON REST https://lingotrack.duckdns.org/api/v1 OpenAPI https://lingotrack.duckdns.org/openapi.json Docs https://lingotrack.duckdns.org/docs Health https://lingotrack.duckdns.org/health This file https://lingotrack.duckdns.org/llms.txt ## AUTHENTICATION Every MCP and REST call carries a bearer key: Authorization: Bearer The key IS the account — there is no password and no email. Whoever holds it owns that learner's error history. Do not print it into shared logs, commit it, or put it in a URL. ### Getting a key A key is issued on demand, with no signup: curl -sS -X POST https://lingotrack.duckdns.org/api/v1/auth/keys \ -H "Content-Type: application/json" \ -d '{"cefr_level":"B1","native_language":"ru"}' Response: { "access_token": "eyJhbGciOi...", "token_type": "bearer", "expires_in": 315360000, "user_id": "…uuid…", "mcp_url": "https://lingotrack.duckdns.org/mcp", "api_url": "https://lingotrack.duckdns.org/api/v1" } All body fields are optional; an empty POST works. `access_token` is the key. IMPORTANT FOR AGENTS: issue a key only when the user asks you to set LinguaTrack up, and show it to the user once so they can store it. Calling this endpoint again creates a NEW, EMPTY learner — it never recovers an existing history. If the user already has a key, use theirs. ## CONNECTING A CLIENT ### Claude Code claude mcp add --transport http lingotrack https://lingotrack.duckdns.org/mcp \ --header "Authorization: Bearer " ### Cursor (.cursor/mcp.json or ~/.cursor/mcp.json) { "mcpServers": { "lingotrack": { "url": "https://lingotrack.duckdns.org/mcp", "headers": { "Authorization": "Bearer " } } } } ### Gemini CLI (~/.gemini/settings.json) { "mcpServers": { "lingotrack": { "httpUrl": "https://lingotrack.duckdns.org/mcp", "headers": { "Authorization": "Bearer " } } } } ### Claude Desktop (stdio only — bridge with mcp-remote) { "mcpServers": { "lingotrack": { "command": "npx", "args": [ "mcp-remote", "https://lingotrack.duckdns.org/mcp", "--header", "Authorization: Bearer " ] } } } ### ChatGPT (Settings -> Connectors -> add custom connector, developer mode) URL: https://lingotrack.duckdns.org/mcp Header: Authorization: Bearer ### Any client / raw HTTP curl -sS https://lingotrack.duckdns.org/mcp \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' ## TOOLS whoami() Learner identity: id, email, cefr_level, native_language, session_count. Call it first to ground the conversation. list_errors(status?, category?, limit?, order_by?) Tracked mistakes. status active | improving | resolved category GRAMMAR | VOCABULARY | PRONUNCIATION | STYLE limit default 50 order_by frequency_desc (default) | last_seen_desc | created_desc save_errors(errors: [ErrorItem]) Persist corrections. Duplicates are matched and their frequency is bumped instead of creating new rows. ErrorItem: category GRAMMAR | VOCABULARY | PRONUNCIATION | STYLE (required) subcategory e.g. "articles", "tenses", "collocations" (required) student_said what the learner actually said, verbatim (required) correct_version the corrected form (required) explanation one short sentence on why (optional) severity low | medium | high (default medium) Returns: {saved, new, deduplicated, created_ids, updated_ids}. update_error_status(error_id, status) Move an error to active | improving | resolved. get_progress() Aggregated report: CEFR level, counts by status, weak areas, top recurring errors. start_session(mode?) mode: free_talk (default) | grammar_drill | review | roleplay | assessment Returns session_id. end_session(session_id, messages_count?, errors_found?, topic?, cefr_level_observed?, summary?) Sessions are optional — errors can be saved without an open session. ## HOW AN ASSISTANT SHOULD BEHAVE 1. At the start of a conversation call `whoami`, then `list_errors` or `get_progress`, and let what you find shape the session ("you tend to drop articles — watch for it"). 2. EVERY time you correct the learner, call `save_errors` in the same turn. A correction shown in chat but never saved is a failure: cumulative tracking is the entire product. 3. Batch corrections from one turn into a single `save_errors` call. 4. When the learner uses a previously broken construction correctly several times, call `update_error_status` with "improving", and later "resolved". 5. Never dump raw tool output at the user. Translate it into encouraging, natural language. 6. Do not invent errors. Only save what the learner actually produced. ## ONBOARDING PROMPT (hand this to an agent verbatim) Set up the LinguaTrack MCP server for me. Endpoint: https://lingotrack.duckdns.org/mcp (Streamable HTTP) Auth: Authorization: Bearer Steps: 1. Read https://lingotrack.duckdns.org/llms.txt for the full contract. 2. Register the server in this client's MCP configuration with the header above. If I have not given you a key, ask me for it — or, if I say I don't have one, POST to https://lingotrack.duckdns.org/api/v1/auth/keys to issue one and show it to me so I can save it. 3. Verify with tools/list, then call whoami and get_progress. 4. From now on: whenever you correct my language mistakes, save them with save_errors in the same turn, and start each session by loading what I already struggle with. ## ERROR RESPONSES 401 Invalid or expired key, or the Authorization header is missing. 403 Public key issuance is disabled on this deployment. 421 Host not in the server's allow-list (DNS-rebinding protection). 422 Bad payload — e.g. cefr_level outside A1…C2. 429 Rate limit. Key issuance is throttled per IP; back off and retry. ## LIMITS Tracked errors per learner are currently unlimited. A soft free-tier cap exists in the server config and is off by default; when enabled, `save_errors` keeps deduplicating and bumping existing errors but stops creating new rows and returns `skipped_over_limit`. No data is ever deleted by the cap. ## STACK FastAPI · PostgreSQL · MCP (Streamable HTTP) · nginx · single host, single domain. The REST API and the MCP server share one database, so the original ChatGPT Actions plugin and any MCP client see exactly the same errors.