Skip to content

feat(mcp): accept a language for course generation - #598

Open
abdulrafey1 wants to merge 2 commits into
refey/feat/lang-09-title-languagefrom
refey/feat/lang-10-mcp-language
Open

feat(mcp): accept a language for course generation#598
abdulrafey1 wants to merge 2 commits into
refey/feat/lang-09-title-languagefrom
refey/feat/lang-10-mcp-language

Conversation

@abdulrafey1

@abdulrafey1 abdulrafey1 commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Part of: Sparkth UI, emails, API errors, and AI-generated content are English-only

Fourth of the phase-2 generation-language stack. Does not close the issue.

What

Lets an MCP caller name the language a generated course should be written in, and makes the
course-generation prompt state that language explicitly.

Changes

  • feat(mcp): optional language BCP 47 tag on CourseGenerationPromptRequest, resolved at the
    tool boundary
  • feat(mcp): the course-generation prompt names the output language and covers titles, lesson
    text, assessment questions, answer options and feedback
  • fix(mcp): remove "in the user's language" from the prompt — undefined on a path with no user
  • test(mcp): explicit, omitted and unsupported tags, each with a negative control, plus the
    published tool schema

How to Test

  1. uv run pytest tests/mcp/ -v — 19 tests pass.
  2. Call the tool over MCP with {"course_params": {"course_name": "...", "course_description": "...", "language": "es"}}
    and confirm the returned prompt names Spanish.
  3. Omit language, and separately pass a nonsense tag such as "klingon" — both return a prompt
    naming DEFAULT_LANGUAGE, and neither errors.
  4. Inspect the tool's published schema and confirm language is optional and its description
    states the fallback.

Notes

No migration, no env var, no dependency. Public MCP tool signature change — additive and
backward compatible: existing callers that omit language get the platform default.

The MCP server has an audit middleware but no identity layer, so there is no user to resolve a
stored preference from — the calling agent supplies the tag. This is why the two generation paths
are not symmetric.

The tag is validated by falling back, not by erroring: an omitted, misspelled or withdrawn tag
resolves to DEFAULT_LANGUAGE, so a bad value never fails a whole agent-driven generation run.
The published field description promises exactly that, and a test pins the promise.

The directive deliberately covers the course only, not the calling agent's own clarifying
questions. language is the course language and says nothing about what language the agent's
human speaks — an English speaker may commission a Spanish course, and the agent should keep
asking its questions in the language of its own conversation.

frontend/lib/api/generated.ts is unchanged: the MCP tool schema is not part of the REST OpenAPI
document, and make test.frontend.api reports no drift.

Manual smoke test. The tests mock nothing about the model's actual output, so before relying
on this: generate a full course through the MCP path in es and in fr, have a speaker review
register and terminology, and confirm assessment questions, answer options and feedback are all
translated.

This description was written with the assistance of an LLM (Claude).

abdulrafey1 and others added 2 commits August 14, 2026 02:04
get_course_generation_prompt_tool takes an optional BCP 47 language tag and names the
language in the prompt, covering titles, lesson text, assessment questions, answer
options and feedback.

The MCP server has no identity layer, so there is no user to resolve a stored preference
from and the calling agent supplies the tag instead. It is validated by falling back, not
by erroring: an omitted, misspelled or withdrawn tag resolves to the platform default, so
a bad tag never fails a whole generation run. The published field description is the
calling agent's only instruction, so it states the fallback explicitly.

Replaces "in the user's language", which was undefined on a path that has no user.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The fallback tests asserted only that the platform default's name appeared in the
prompt. The template's OUTPUT LANGUAGE section also carries the brief-mandated,
unconditional literal "...not a literal translation of English phrasing", so that
positive assertion alone could not tell the true default apart from the tool
wrongly resolving to some other valid tag.

Add a negative control to both the omitted- and unsupported-language tests:
assert that no OTHER supported language's name appears, derived from
get_settings() and SUPPORTED_LANGUAGES so it stays correct if either changes.
Also pin the schema test's fallback-promise sentence, not just its "BCP 47"
prefix, since that sentence is the calling agent's only instruction that a bad
tag is safe rather than an error.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@abdulrafey1 abdulrafey1 changed the title refey/feat/lang 10 mcp language feat(mcp): accept a language for course generation Aug 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants