A thin, headless course-management layer for Claude Code. The model authors all course content using its own tools — this server persists what the model produced to a local store, lists modules/lessons with statuses, lets the model edit the structure and update material, and publishes the finished course to a catalog.
Server has 7 tools with complete input schemas and descriptions. Naming follows verb_noun convention (course_create, course_list, course_get, course_save_lesson, course_set_structure, course_status, course_publish). Descriptions are substantive (100-250 chars), explaining WHAT each tool does and WHEN to use it. However, parameter descriptions are sparse or missing for nested objects (e.g., 'modules' in course_set_structure has only 'Top-level sections/modules' with no schema detail for nested node structure). Output schemas are not documented, callers cannot predict response structure. Error handling is minimal; no recovery guidance or actionable error messages visible in code. Security: credentials (CATALOG_UPLOAD_TOKEN) are env-injected, not exposed as params (good), but no audit logging or permission gates visible.
Create a course record in the local store (no content yet). Returns its id. Choose course_format up front — it drives structure shape and what gets published. Reference formats (encyclopedia/documentation) have no tests/homework.
Fetch a course record by id (metadata only; does not load all lesson content).
List all courses in the local store with their metadata (id, topic, title, language, format, status, created/updated timestamps).
Build a CatalogCoursePackage (schema v1) from the course and PUT it to a catalog server. Requires catalogUrl and bearer token (from params or env CATALOG_URL / CATALOG_UPLOAD_TOKEN). Fails if the course has no saved lessons.
Save a lesson's content (article, widgets, test, assignments, flashcards, sources, review notes) under a module/lesson id. Upsert: overwrites any prior content for that id.
Set or edit the course structure (modules → lessons; documentation nests to any depth). Idempotent upsert: pass an existing node's id to keep it (and its saved content), omit id for new nodes, drop a node to remove it (its content is discarded). Use this both to lay out the plan and to edit it later.
Output schemas not documented. Callers cannot predict response structure (e.g., what fields does course_status return? What is the shape of the module/lesson tree?). LLMs cannot plan downstream operations without knowing what data they receive.
Nested parameter schemas lack detail. 'modules' in course_set_structure is described as 'Top-level sections/modules' but the schema shows only type:array with no itemSchema. Callers cannot know what fields each module object must contain (id, title, lessons, etc.).
Error handling is absent. No visible error messages, recovery guidance, or categorization (retryable vs fatal). If course_publish fails (e.g., missing lessons, network error, auth failure), the LLM receives no actionable guidance on what to do next.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 67 | 2026-07-28+ | v2 |
Return the course's module/lesson tree with each node's status (pending = no content yet, ready = content saved) plus counts. Use to see what still needs work.
No pagination or result limits documented. course_list returns all courses with no limit or offset parameters. If a user has 1000 courses, the response could exhaust context window.
Destructive operations lack confirmation. course_set_structure can drop nodes (discarding content), and course_publish is irreversible. No dry-run or confirmation step visible to prevent accidental data loss.