Language

Active

language · v1.1.0

Language-learning scenarios with dialogues, vocabulary lists, grammar notes, exercises, and cultural notes.

Schema Version:
1.1.0
Collection Type:
Course

Section Types

IDName
dialogueDialogue
vocabulary_listVocabulary List
grammar_noteGrammar Note
exerciseExercise
visualVisual
audioAudio
cultural_noteCultural Note
wikiWiki

MCP Tools

NameDescription
language_get_vocabularyReturn a flattened vocabulary list for the given scenario id or slug. Combines every vocabulary_list section into one array.
language_create_scenarioCreate a new language scenario in DRAFT status. Returns { scenarioId, slug, title, sectionIds[] }. Slug auto-generated. Required: title + targetLanguage (ISO 639-1/BCP-47) + nativeLanguage + level (CEFR A1..C2). When seedDefaults=true the 7 default sections (dialogue/vocabulary_list/grammar_note/exercise/visual/audio/cultural_note) are pre-populated; otherwise the scenario starts empty. Caller must be authenticated.
language_add_sectionAppend a typed section to an existing language scenario. Accepts scenarioId (cuid or slug) + sectionType (dialogue|vocabulary_list|grammar_note|exercise|visual|audio|cultural_note) + content (typed per sectionType — pass null/omit to use the type default) + optional chapterId (same scenario; sections read in chapter.order → section.order). EXERCISE content is INTERACTIVE + MULTI-QUESTION: { title, instructions?, questions[] } where each question is one of 5 types — fill_blank ({ prompt with {{1}}{{2}} placeholders (1-based, in order), gaps:[{answer, acceptable?[]}] }), multiple_choice ({ prompt, choices[], correctOption (0-based index of the correct choice — REQUIRED, and VARY its position, do not always make it 0/A) }), matching ({ prompt, pairs:[{left,right}] }), translate ({ prompt, source, acceptableAnswers[] }), short_answer ({ prompt, sampleAnswer }). Prefer several mixed questions per exercise over a single one. Returns { sectionId, key, order, typeId, versionId }. Validates moduleId === "language". Auto-assigns next order; key defaults to "<typeId>-<order>" if omitted. NOTE: authoring a multi-chapter scenario with parallel agents — split work by chapter (one writer per chapter) or use language_add_sections to write a whole chapter atomically.
language_add_sectionsAppend MULTIPLE typed sections to a language scenario in ONE atomic call — the array order IS the reading order, so parallel agents cannot interleave even within the same chapter. Accepts scenarioId (cuid or slug) + optional chapterId (same scenario; ALL sections placed there) + sections[] (1-50, each { sectionType, content?, label?, key? }; content null/omit → type default). EXERCISE content is INTERACTIVE + MULTI-QUESTION: { title, instructions?, questions[] } — each question one of fill_blank (prompt with {{1}} placeholders + gaps:[{answer, acceptable?[]}]), multiple_choice (choices[] + correctOption 0-based REQUIRED, vary its position), matching (pairs:[{left,right}]), translate (source + acceptableAnswers[]), short_answer (sampleAnswer). Prefer several mixed questions per exercise. Prefer one add_sections call per chapter when authoring a multi-chapter scenario. Returns { scenarioId, scenarioSlug, chapterId, sections: [{ sectionId, key, order, typeId, versionId }] }. Caller must be authenticated.
language_create_collectionCreate a new Course-typed collection (language module). Returns { collectionId, slug, title, type, itemCount, addedScenarioIds }. Slug auto-generated from title (collision-suffixed). Optionally pre-populate with caller-owned language scenarios (scenarios: id or slug, max 50; non-owned or non-language silently skipped). Caller must be authenticated; ownership = ctx.user.
language_scaffold_courseScaffold an ENTIRE language course skeleton in ONE call — a DRAFT scenario + N chapters, each pre-filled with one EMPTY (default-content) section per requested section type, ready for you to fill. Use this to lay out a multi-chapter curriculum fast; then author the real content with language_update_section on each returned sectionId. Required: title + level (CEFR A1..C2) + targetLanguage (ISO 639-1/BCP-47) + chapters[] (1-20, each { title, topic? }). Optional: nativeLanguage + sectionTypes[] (default dialogue/vocabulary_list/grammar_note/exercise/cultural_note; allowed dialogue|vocabulary_list|grammar_note|exercise|visual|audio|cultural_note). level/targetLanguage/nativeLanguage are stored as cefr:/lang:/native: tags (no dedicated DB column yet); targetLanguage also sets contentLanguage. Sections within each chapter sort in the given sectionTypes order; chapters sort in array order. Returns { scenarioId, slug, chapters: [{ chapterId, title, sectionIds: [{ id, key, typeId }] }], hint }. Scenario is created as DRAFT (publish separately with language_publish_scenario). Caller must be authenticated.
language_update_sectionUpdate a language section's content and/or label. content is FULL replace (no field merge) — caller sends whole content object, validated against the section's typeId schema (one of: dialogue, vocabulary_list, grammar_note, exercise, visual, audio, cultural_note). Creates new SectionVersion when content changes, no-op when hash matches. Caller must own the parent scenario. Returns { sectionId, versionId, version, contentHash, contentChanged, labelChanged }. At least one of content/label required. label:null removes the label.
language_convert_sectionConvert a language section to a DIFFERENT section type (e.g. exercise → dialogue) IN PLACE: order, chapterId and key are preserved so the section keeps its exact position in the scenario. Because typeId is immutable, this deletes the old section and recreates it at the same slot with the new type — the section's id changes and the OLD version history is discarded (expected, inherent to type change). content is the FULL new content object, validated against targetType's schema (one of: dialogue, vocabulary_list, grammar_note, exercise, visual, audio, cultural_note). targetType MUST differ from the current type (use language_update_section for same-type content edits). Caller must own the parent scenario. Returns { oldSectionId, newSectionId, fromType, toType, key, order, chapterId, versionId, version }.
language_delete_sectionDelete a language section and all its versions. Caller must own the parent scenario. Returns { deletedSectionId, scenarioId, scenarioSlug, deletedVersionCount }. Hard delete — irreversible. Use with care.
language_update_scenarioUpdate a language scenario's metadata (title/description/tags/status/contentLanguage). At least one field required. tags is PUT semantics. description:null clears stored summary. contentLanguage is a BCP-47 tag (e.g. 'de-DE', 'tr') = the scenario's target teaching language, used for audio-section TTS "Dinle" pronunciation (independent of the page UI locale); null clears it. status accepts DRAFT/PUBLISHED/ARCHIVED but use language_publish_scenario for the canonical publish path (it also creates a ScenarioVersion snapshot). Caller must own the scenario. Returns updated row { scenarioId, slug, title, status, tags, description }.
language_publish_scenarioPublish a language scenario — creates a new ScenarioVersion snapshot (sectionManifest pointer list) and flips status to PUBLISHED. Re-publishing is allowed (version monotonically increments). Empty scenarios are rejected. Caller must own the scenario. Returns { scenarioId, versionId, version, publishedAt, sectionCount }.
language_add_to_collectionAdd a scenario to a language-typed collection (type=Course). Caller must own the collection. Cross-module items allowed. Duplicate check: fails if the scenario is already in the collection. order optional — defaults to max(order)+1 (append). Returns { collectionId, scenarioId, itemId, order, scenarioModuleId }.
language_remove_from_collectionRemove a scenario from a language-typed collection (type=Course). Caller must own the collection. Returns { collectionId, scenarioId, removed:true }. Throws if the scenario is not in the collection. Other items keep their order (no compaction).
language_upgrade_exercisesUpgrade LEGACY (old single-question) exercise sections in a language scenario to the new structured questions[] format. Scans every exercise section; one already in questions[] form is skipped (no-op). mode='lossless' (default) PERMANENTLY writes the deterministic legacy→questions[] transform as a new SectionVersion (multiple_choice structure preserved, other types collapsed to short_answer — lossless but structurally weak). mode='claude-rewrite' writes NOTHING and instead returns each legacy section's RAW old content { sectionId, key, raw } so Claude can author a full structured questions[] and write it via language_update_section. dryRun=true reports without writing { scenarioId, total, legacyCount, alreadyNew, willConvert }. No LLM call — lossless is a pure deterministic transform. Caller must have edit access to the scenario. Returns (lossless apply) { scenarioId, converted, skipped }.
language_set_metaPersist a language scenario's CEFR level + language meta as STRUCTURAL tags (no migration needed). Today this meta is only validated then discarded at create-time; this tool writes it durably onto Scenario.tags as reserved prefixed tags: cefr:<level> (A1..C2), lang:<targetLanguage>, native:<nativeLanguage> — so list/search can filter by them. Accepts scenarioId (cuid or slug) + any of level / targetLanguage (ISO 639-1/BCP-47) / nativeLanguage. Only the provided fields are written; their old meta tags (same prefix) are replaced, other (non-meta) tags are preserved. When targetLanguage is given, Scenario.contentLanguage is also set (audio-section TTS "Dinle" pronunciation). At least one of level/targetLanguage/nativeLanguage required. Caller must own the scenario or hold an edit share. Returns { scenarioId, tags, contentLanguage }.
language_validate_scenarioRun a DETERMINISTIC rule-engine lint over a language scenario (id or slug) and return a structured report — NO LLM call, read-only. Scans every section via currentVersion.content and applies fixed checks per type: exercise (legacy single-question content → fix 'upgrade_exercises'; multiple_choice correctOption out of range; positional bias when every MC answer is option 0; fill_blank {{n}} placeholder count ≠ gaps length; empty questions[]), dialogue (lines missing translation/pronunciation), vocabulary_list (duplicate terms, missing pronunciation/exampleSentence ratio), audio (missing BCP-47 lang → wrong TTS voice), and structural checks (orphan sections with no chapter). Returns { scenarioId, ok, issues:[{sectionId?, key?, severity:'error'|'warn', code, message, fix?}], summary:{ byType, counts } }. ok=true only when there are zero 'error'-severity issues. Caller must be able to read the scenario (owner / public-published / shared).
language_add_wiki_sectionCreate a new EMPTY wiki section on a language scenario. The section starts with zero concepts — call language_wiki_add_concept for each glossary entry. Accepts scenarioId (cuid) or slug. Returns { sectionId, key, order, versionId, scenarioSlug }. Section label defaults to 'Kavramlar' when omitted. Caller must own the scenario.
language_wiki_add_conceptAppend a single concept card to a language scenario's wiki section. The section must already exist (call language_add_wiki_section first). slug must be unique within the section. definition is the 1-2 sentence collapsed-card summary; overview is the long markdown body. examples and references default to empty arrays. Creates a new SectionVersion. Returns { sectionId, conceptSlug, versionId, version, conceptCount }.
language_wiki_update_conceptPatch a single concept in a language scenario's wiki section. Identified by slug (slug itself is immutable). patch is partial: any field omitted is unchanged. Pass examples: [] or references: [] to clear arrays. Creates a new SectionVersion if content actually changed. Returns { sectionId, conceptSlug, versionId, version, contentChanged }.
language_wiki_remove_conceptRemove a single concept from a language wiki section by slug. The section itself stays (even if it becomes empty — drop via delete_section). Creates a new SectionVersion. Returns { sectionId, removedSlug, versionId, version, conceptCount }.
language_use_scenarioActivate a language scenario as a live LLM session by returning a FULLY-RESOLVED prompt string for you (Claude) to act on. This tool does NOT call any LLM — it renders the scenario to markdown and fills the chosen mode's prompt template, then hands the finished prompt back so YOU become the teacher (mode='study') or the role-partner (mode='roleplay'). Accepts scenarioId (cuid or slug) + mode (study|roleplay) + optional userMessage (learner turn) + optional targetSpeaker (roleplay character) + optional level / targetLanguage / nativeLanguage (CEFR + ISO 639-1 codes — not stored on the scenario, so pass them; otherwise they are recovered from 'cefr:'/'lang:'/'native:' tags, else left blank). roleplay requires the scenario to have a dialogue section (study requires dialogue + vocabulary_list); a clear error is returned if a required section type is missing. Returns { scenarioId, mode, prompt }. After calling, READ the returned prompt and continue the conversation as instructed by it.

Usage Modes

IDName
studyStudy
roleplayRoleplay

Example Scenarios