{"server":{"name":"Scormbusters","title":"Scormbusters course authoring","version":"1.2.0"},"endpoint":"https://scormbusters.com/api/mcp","transport":"streamable-http (stateless)","protocolVersions":["2025-11-25","2025-06-18","2025-03-26","2024-11-05"],"auth":{"bearer":["Personal access token (oc_pat_…)","API key (oc_live_…)","OAuth 2.1 access token (oc_at_…)"],"protectedResourceMetadata":"https://scormbusters.com/.well-known/oauth-protected-resource/api/mcp","scopes":["read:courses","write:courses"]},"rateLimit":{"requests":120,"windowSeconds":60,"scope":"per API key, or per OAuth client per person; global across instances"},"documentation":{"html":"https://scormbusters.com/docs/mcp","markdown":"https://scormbusters.com/docs/mcp.md"},"tools":[{"name":"list_courses","title":"List courses","description":"List the organization's courses (id, title, status, editor_mode, dates), newest first, one page at a time. Returns {courses, total, nextCursor}: total counts every match; while nextCursor is not null, call again with cursor: nextCursor to get the rest — never assume one page is the whole library. Filter by title with query.","inputSchema":{"type":"object","properties":{"status":{"type":"string","enum":["draft","published","archived"],"description":"Optional status filter"},"query":{"type":"string","description":"Optional: only courses whose title contains this text (case-insensitive)"},"limit":{"type":"integer","minimum":1,"maximum":100,"description":"Page size (default 50, max 100)"},"cursor":{"type":"string","description":"nextCursor from the previous page; omit for the first page"}},"additionalProperties":false},"annotations":{"title":"List courses","readOnlyHint":true,"destructiveHint":false,"openWorldHint":false},"requiredScope":"read:courses","example":{"arguments":{"status":"draft","query":"forklift","limit":1},"result":{"courses":[{"id":"3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11","title":"Forklift Safety Refresher","description":"Annual certification refresher for warehouse staff.","status":"draft","editor_mode":"classic","created_at":"2026-09-20T09:00:00.000Z","updated_at":"2026-09-25T10:00:00.000Z"}],"total":3,"nextCursor":"eyJvIjoxfQ"}},"sideEffects":"None.","errors":["cursor is not one list_courses returned; omit it to start from the first page.","status must be one of <statuses>."]},{"name":"get_course","title":"Get course structure","description":"Get a course's full outline: modules, lessons, and each lesson's block list (ids and types, not content). Use get_lesson to read block content. A Scenes course (kind: \"scenes\" — imported Storyline/Captivate courses, slide-based) returns its slides instead: id, name, order, objectCount, layerNames and a notes excerpt; read a slide's objects with get_scene_slide.","inputSchema":{"type":"object","properties":{"courseId":{"type":"string","description":"Course id (uuid)"}},"required":["courseId"],"additionalProperties":false},"annotations":{"title":"Get course structure","readOnlyHint":true,"destructiveHint":false,"openWorldHint":false},"requiredScope":"read:courses","example":{"arguments":{"courseId":"3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11"},"result":{"id":"3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11","title":"Forklift Safety Refresher","description":"Annual certification refresher for warehouse staff.","status":"draft","passing_score":80,"language":"en","flow_mode":"linear","updated_at":"2026-09-25T10:00:00.000Z","modules":[{"id":"8b2d4e61-1c3f-4a7e-b5d9-0e6f2a7c3d22","title":"Pre-operation checks","sort_order":0,"lessons":[{"id":"c41e7f83-5d2a-4b6c-8e1f-9a0b3c4d5e33","title":"The daily inspection","sort_order":0,"blocks":[{"id":"f7410216-805d-4e9f-b142-cd3e6f708166","type":"heading","sort_order":0},{"id":"0852132a-916e-4fa0-8253-de4f70819277","type":"image","sort_order":1},{"id":"19632438-a27f-4ab1-9364-ef508192a388","type":"multiple_choice","sort_order":2}]}]}],"editorUrl":"https://scormbusters.com/courses/3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11","previewUrl":"https://scormbusters.com/courses/3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11/preview"}},"sideEffects":"None.","errors":["Course <courseId> not found in your organization."]},{"name":"create_course","title":"Create course","description":"Create a course, optionally with its whole structure in one call: modules containing lessons containing blocks. This is the best way to build a course — draft the full structure first, then create it in one shot and refine with add_block/update_block. Read the tutorials (resources) before your first course: they cover which blocks to use and how to write good content for each. Courses start as drafts; publish with update_course.","inputSchema":{"type":"object","properties":{"title":{"type":"string","description":"Course title (1–255 chars, no control characters)"},"description":{"type":"string","description":"Optional course description shown in the catalog"},"structure":{"type":"object","description":"Optional full course structure, created with the course in one transaction (all or nothing)","properties":{"modules":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","description":"Module title (1–255 chars)"},"lessons":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","description":"Lesson title (1–255 chars)"},"questionPoolSize":{"type":["integer","null"],"minimum":1,"maximum":1000,"description":"Question pool: how many of the lesson's question blocks each learner attempt gets, drawn at random (stable when the attempt is resumed; scored out of the drawn questions only). Omit or null for every question."},"blocks":{"type":"array","items":{"type":"object","description":"One content block. Call list_block_types for the content schema of each type.","properties":{"type":{"type":"string","description":"Block type, e.g. \"paragraph\", \"heading\", \"multiple_choice\""},"content":{"type":"object","description":"Block content matching that type's schema","additionalProperties":true},"settings":{"type":"object","description":"Optional presentation settings","additionalProperties":true}},"required":["type"],"additionalProperties":false}}},"required":["title"],"additionalProperties":false}}},"required":["title"],"additionalProperties":false}}},"additionalProperties":false}},"required":["title"],"additionalProperties":false},"annotations":{"title":"Create course","readOnlyHint":false,"destructiveHint":false,"openWorldHint":false},"requiredScope":"write:courses","example":{"arguments":{"title":"Forklift Safety Refresher","description":"Annual certification refresher for warehouse staff.","structure":{"modules":[{"title":"Pre-operation checks","lessons":[{"title":"The daily inspection","blocks":[{"type":"heading","content":{"text":"Module 1: Hazard Identification","level":"h2"}},{"type":"image","content":{"url":"https://example.com/assets/forklift-inspection.jpg","alt":"A warehouse worker checking a forklift's tires during a pre-shift inspection","caption":"Daily pre-shift forklift inspection"}},{"type":"multiple_choice","content":{"question":"<p>You spot a small chemical spill in an aisle. What should you do first?</p>","options":[{"text":"Mop it up yourself right away","correct":false,"feedback":"Not until you know what the chemical is — check the label and SDS first."},{"text":"Secure the area and check the safety data sheet","correct":true,"feedback":"Right — identify the substance before anyone touches it."},{"text":"Ignore it if it is smaller than your hand","correct":false,"feedback":"Size doesn't determine hazard — some chemicals are dangerous in tiny amounts."}]}}]}]}]}},"result":{"id":"3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11","title":"Forklift Safety Refresher","description":"Annual certification refresher for warehouse staff.","status":"draft","passing_score":80,"language":"en","flow_mode":"linear","updated_at":"2026-09-25T10:00:00.000Z","modules":[{"id":"8b2d4e61-1c3f-4a7e-b5d9-0e6f2a7c3d22","title":"Pre-operation checks","sort_order":0,"lessons":[{"id":"c41e7f83-5d2a-4b6c-8e1f-9a0b3c4d5e33","title":"The daily inspection","sort_order":0,"blocks":[{"id":"f7410216-805d-4e9f-b142-cd3e6f708166","type":"heading","sort_order":0},{"id":"0852132a-916e-4fa0-8253-de4f70819277","type":"image","sort_order":1},{"id":"19632438-a27f-4ab1-9364-ef508192a388","type":"multiple_choice","sort_order":2}]}]}],"editorUrl":"https://scormbusters.com/courses/3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11","previewUrl":"https://scormbusters.com/courses/3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11/preview"}},"sideEffects":"Creates a draft course with its modules, lessons and blocks. A course with no modules gets \"Module 1\" / \"Lesson 1\"; a module with no lessons gets \"Lesson 1\".","errors":["<field> must be a string","<field> must be 1–255 characters","<field> must not contain control characters (tabs, newlines…)","description must be 5000 characters or fewer","structure.modules must be an array","structure.modules[<i>].lessons[<j>].blocks[<k>] must be an object with a string type","Unknown block type \"<type>\". Valid types: <list>. Call list_block_types for each type's content schema.","\"<lesson title>\": <type> needs content.<field> (<type>): <field description> Call list_block_types for the full reference.","\"<lesson title>\": content.<field> must be a <type>, not <actual>. Call list_block_types for the full reference.","\"<lesson title>\": multiple_choice needs exactly one option with correct: true (found <n>). Use multi_select for several.","block content too large (max 512KB)","block settings too large (max 512KB)"]},{"name":"update_course","title":"Update course","description":"Update a course's title, description, passing score (0–100), or status. Setting status to \"published\" makes it available to learners.","inputSchema":{"type":"object","properties":{"courseId":{"type":"string","description":"Course id (uuid)"},"title":{"type":"string","description":"New title (1–255 chars)"},"description":{"type":"string","description":"New description"},"status":{"type":"string","enum":["draft","published","archived"]},"passing_score":{"type":"integer","minimum":0,"maximum":100,"description":"Quiz pass threshold in percent"}},"required":["courseId"],"additionalProperties":false},"annotations":{"title":"Update course","readOnlyHint":false,"destructiveHint":true,"openWorldHint":false},"requiredScope":"write:courses","example":{"arguments":{"courseId":"3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11","status":"published","passing_score":80},"result":{"ok":true,"courseId":"3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11","applied":{"status":"published","passing_score":80}}},"sideEffects":"Updates the course row and pushes the change to any editor that has the course open. status \"published\" makes the course available to learners and fires the organization's `course.published` webhook, exactly as publishing in the editor does.","errors":["Course <courseId> not found in your organization.","<field> must be a string","<field> must be 1–255 characters","<field> must not contain control characters (tabs, newlines…)","description must be 5000 characters or fewer","status must be \"draft\", \"published\", or \"archived\"","passing_score must be an integer 0–100","Nothing to update."]},{"name":"add_module","title":"Add module","description":"Append a module (a chapter grouping lessons) to a course.","inputSchema":{"type":"object","properties":{"courseId":{"type":"string","description":"Course id (uuid)"},"title":{"type":"string","description":"Module title (1–255 chars)"}},"required":["courseId","title"],"additionalProperties":false},"annotations":{"title":"Add module","readOnlyHint":false,"destructiveHint":false,"openWorldHint":false},"requiredScope":"write:courses","example":{"arguments":{"courseId":"3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11","title":"Operating safely"},"result":{"id":"8b2d4e61-1c3f-4a7e-b5d9-0e6f2a7c3d22","title":"Operating safely","sort_order":1}},"sideEffects":"Appends a module at the end of the course.","errors":["<field> must be a string","<field> must be 1–255 characters","<field> must not contain control characters (tabs, newlines…)","Course <courseId> not found in your organization."]},{"name":"add_lesson","title":"Add lesson","description":"Append a lesson to a module. A lesson is a page of blocks the learner reads top to bottom.","inputSchema":{"type":"object","properties":{"moduleId":{"type":"string","description":"Module id (uuid)"},"title":{"type":"string","description":"Lesson title (1–255 chars)"}},"required":["moduleId","title"],"additionalProperties":false},"annotations":{"title":"Add lesson","readOnlyHint":false,"destructiveHint":false,"openWorldHint":false},"requiredScope":"write:courses","example":{"arguments":{"moduleId":"8b2d4e61-1c3f-4a7e-b5d9-0e6f2a7c3d22","title":"Check your knowledge"},"result":{"id":"d52f8094-6e3b-4c7d-9f20-ab1c4d5e6f44","title":"Check your knowledge","module_id":"8b2d4e61-1c3f-4a7e-b5d9-0e6f2a7c3d22","sort_order":1}},"sideEffects":"Appends an empty lesson at the end of the module.","errors":["<field> must be a string","<field> must be 1–255 characters","<field> must not contain control characters (tabs, newlines…)","Module <moduleId> not found in your organization."]},{"name":"get_lesson","title":"Get lesson content","description":"Get a lesson with the full content and settings of every block, in order.","inputSchema":{"type":"object","properties":{"lessonId":{"type":"string","description":"Lesson id (uuid)"}},"required":["lessonId"],"additionalProperties":false},"annotations":{"title":"Get lesson content","readOnlyHint":true,"destructiveHint":false,"openWorldHint":false},"requiredScope":"read:courses","example":{"arguments":{"lessonId":"c41e7f83-5d2a-4b6c-8e1f-9a0b3c4d5e33"},"result":{"id":"c41e7f83-5d2a-4b6c-8e1f-9a0b3c4d5e33","title":"The daily inspection","module_id":"8b2d4e61-1c3f-4a7e-b5d9-0e6f2a7c3d22","sort_order":0,"blocks":[{"id":"f7410216-805d-4e9f-b142-cd3e6f708166","type":"heading","content":{"text":"Module 1: Hazard Identification","level":"h2"},"settings":{},"sort_order":0},{"id":"0852132a-916e-4fa0-8253-de4f70819277","type":"image","content":{"url":"https://example.com/assets/forklift-inspection.jpg","alt":"A warehouse worker checking a forklift's tires during a pre-shift inspection","caption":"Daily pre-shift forklift inspection"},"settings":{},"sort_order":1}]}},"sideEffects":"None.","errors":["Lesson <lessonId> not found in your organization."]},{"name":"add_block","title":"Add block","description":"Append one content block to a lesson (or insert at a position). The content object must match the block type's schema — call list_block_types first if unsure.","inputSchema":{"type":"object","properties":{"lessonId":{"type":"string","description":"Lesson id (uuid)"},"type":{"type":"string","description":"Block type"},"content":{"type":"object","description":"Content matching the block type's schema","additionalProperties":true},"settings":{"type":"object","description":"Optional presentation settings","additionalProperties":true},"position":{"type":"integer","minimum":0,"description":"Optional sort position; defaults to the end"}},"required":["lessonId","type","content"],"additionalProperties":false},"annotations":{"title":"Add block","readOnlyHint":false,"destructiveHint":false,"openWorldHint":false},"requiredScope":"write:courses","example":{"arguments":{"lessonId":"d52f8094-6e3b-4c7d-9f20-ab1c4d5e6f44","type":"multiple_choice","content":{"question":"<p>You spot a small chemical spill in an aisle. What should you do first?</p>","options":[{"text":"Mop it up yourself right away","correct":false,"feedback":"Not until you know what the chemical is — check the label and SDS first."},{"text":"Secure the area and check the safety data sheet","correct":true,"feedback":"Right — identify the substance before anyone touches it."},{"text":"Ignore it if it is smaller than your hand","correct":false,"feedback":"Size doesn't determine hazard — some chemicals are dangerous in tiny amounts."}]},"position":0},"result":{"id":"19632438-a27f-4ab1-9364-ef508192a388","type":"multiple_choice","sort_order":0}},"sideEffects":"Inserts the block (at the end, or at position with the siblings renumbered 0..n-1) and pushes it to any editor that has the lesson open.","errors":["Unknown block type \"<type>\". Valid types: <list>. Call list_block_types for each type's content schema.","<type> needs content.<field> (<type>): <field description> Call list_block_types for the full reference.","content.<field> must be a <type>, not <actual>. Call list_block_types for the full reference.","multiple_choice needs exactly one option with correct: true (found <n>). Use multi_select for several.","content too large (max 512KB)","settings too large (max 512KB)","Lesson <lessonId> not found in your organization.","position must be a non-negative integer"]},{"name":"update_block","title":"Update block","description":"Replace a block's content and/or settings, or move it (sort_order). Content is replaced whole, not merged — send the complete object.","inputSchema":{"type":"object","properties":{"blockId":{"type":"string","description":"Block id (uuid)"},"content":{"type":"object","description":"Complete replacement content","additionalProperties":true},"settings":{"type":"object","description":"Complete replacement settings","additionalProperties":true},"sort_order":{"type":"integer","minimum":0}},"required":["blockId"],"additionalProperties":false},"annotations":{"title":"Update block","readOnlyHint":false,"destructiveHint":true,"openWorldHint":false},"requiredScope":"write:courses","example":{"arguments":{"blockId":"0852132a-916e-4fa0-8253-de4f70819277","content":{"url":"https://example.com/assets/forklift-inspection.jpg","alt":"A worker checking a forklift's tyre pressure before a shift","caption":"Daily pre-shift forklift inspection"}},"result":{"ok":true,"blockId":"0852132a-916e-4fa0-8253-de4f70819277","applied":["content"]}},"sideEffects":"Replaces content and/or settings whole (no merge) and/or moves the block, then pushes the change to open editors.","errors":["<type> needs content.<field> (<type>): <field description> Call list_block_types for the full reference.","content.<field> must be a <type>, not <actual>. Call list_block_types for the full reference.","multiple_choice needs exactly one option with correct: true (found <n>). Use multi_select for several.","Block <blockId> not found in your organization.","content too large (max 512KB)","settings too large (max 512KB)","sort_order must be a non-negative integer (the 0-based position)","Nothing to update."]},{"name":"delete_block","title":"Delete block","description":"Permanently delete one block from a lesson.","inputSchema":{"type":"object","properties":{"blockId":{"type":"string","description":"Block id (uuid)"}},"required":["blockId"],"additionalProperties":false},"annotations":{"title":"Delete block","readOnlyHint":false,"destructiveHint":true,"openWorldHint":false},"requiredScope":"write:courses","example":{"arguments":{"blockId":"19632438-a27f-4ab1-9364-ef508192a388"},"result":{"ok":true,"deleted":"19632438-a27f-4ab1-9364-ef508192a388"}},"sideEffects":"Permanently deletes the block. There is no undo over MCP.","errors":["Block <blockId> not found in your organization."]},{"name":"list_block_types","title":"List block types","description":"The authoritative reference for all 37 block types: category, description, exact content field schema, and a realistic example for each. Pass a type to get just that block, or a category (Text, Media, Layout, Interactive, Assessment) to browse.","inputSchema":{"type":"object","properties":{"type":{"type":"string","description":"Optional: one block type to describe in full"},"category":{"type":"string","enum":["Text","Media","Layout","Interactive","Assessment"]}},"additionalProperties":false},"annotations":{"title":"List block types","readOnlyHint":true,"destructiveHint":false,"openWorldHint":false},"requiredScope":"read:courses","example":{"arguments":{"type":"multiple_choice"},"result":{"type":"multiple_choice","label":"Multiple Choice","category":"Assessment","description":"Single correct answer quiz","contentFields":[{"name":"question","type":"string","required":true,"description":"Question text as an HTML string (TipTap)."},{"name":"options","type":"{ text: string; correct: boolean; feedback: string }[]","required":true,"description":"Answer options. Exactly ONE option should have correct: true (the editor enforces this with radio buttons; the grader accepts whichever index has correct === true). feedback is per-option text shown to the learner after submitting when settings.showFeedback is on; use an empty string when there is none. The editor caps options at 6. A true/false question is a multiple_choice with the two options \"True\" and \"False\"; there is no separate type."}],"example":{"question":"<p>You spot a small chemical spill in an aisle. What should you do first?</p>","options":[{"text":"Mop it up yourself right away","correct":false,"feedback":"Not until you know what the chemical is — check the label and SDS first."},{"text":"Secure the area and check the safety data sheet","correct":true,"feedback":"Right — identify the substance before anyone touches it."},{"text":"Ignore it if it is smaller than your hand","correct":false,"feedback":"Size doesn't determine hazard — some chemicals are dangerous in tiny amounts."}]},"notes":"GRADER AUTHORITY (lib/grading.ts): the learner response is the chosen option INDEX (number); options[chosen].correct === true wins. correct and feedback are stripped from learner-facing content by redactAnswers, so grading only happens server-side. settings.shuffleOptions: boolean shuffles display order; settings.showFeedback: boolean (default true) shows per-option feedback."}},"sideEffects":"None.","errors":["Unknown type \"<type>\". Valid types: <list>."]},{"name":"update_module","title":"Update module","description":"Rename a module or change its position (sort_order) within the course.","inputSchema":{"type":"object","properties":{"moduleId":{"type":"string","description":"Module id (uuid)"},"title":{"type":"string","description":"New title (1–255 chars)"},"sort_order":{"type":"integer","minimum":0,"description":"New position among the course's modules (0-based)"}},"required":["moduleId"],"additionalProperties":false},"annotations":{"title":"Update module","readOnlyHint":false,"destructiveHint":true,"openWorldHint":false},"requiredScope":"write:courses","example":{"arguments":{"moduleId":"8b2d4e61-1c3f-4a7e-b5d9-0e6f2a7c3d22","title":"Before you drive","sort_order":0},"result":{"ok":true,"moduleId":"8b2d4e61-1c3f-4a7e-b5d9-0e6f2a7c3d22","applied":{"title":"Before you drive","sort_order":0}}},"sideEffects":"Renames and/or moves the module; sibling modules are renumbered 0..n-1.","errors":["Module <moduleId> not found in your organization.","<field> must be a string","<field> must be 1–255 characters","<field> must not contain control characters (tabs, newlines…)","sort_order must be a non-negative integer (the 0-based position)","Nothing to update."]},{"name":"update_lesson","title":"Update lesson","description":"Rename a lesson, change its position (sort_order) within its module, or make it a question pool (question_pool_size: each learner attempt gets that many of the lesson's question blocks at random, is scored out of those, and keeps the same draw when resumed; null gives every question).","inputSchema":{"type":"object","properties":{"lessonId":{"type":"string","description":"Lesson id (uuid)"},"title":{"type":"string","description":"New title (1–255 chars)"},"sort_order":{"type":"integer","minimum":0,"description":"New position among the module's lessons (0-based)"},"question_pool_size":{"type":["integer","null"],"minimum":1,"maximum":1000,"description":"Question pool: how many of the lesson's question blocks each learner attempt gets, drawn at random (stable when the attempt is resumed; scored out of the drawn questions only). Omit or null for every question."}},"required":["lessonId"],"additionalProperties":false},"annotations":{"title":"Update lesson","readOnlyHint":false,"destructiveHint":true,"openWorldHint":false},"requiredScope":"write:courses","example":{"arguments":{"lessonId":"d52f8094-6e3b-4c7d-9f20-ab1c4d5e6f44","sort_order":1},"result":{"ok":true,"lessonId":"d52f8094-6e3b-4c7d-9f20-ab1c4d5e6f44","applied":{"sort_order":1}}},"sideEffects":"Renames and/or moves the lesson within its module; siblings are renumbered 0..n-1.","errors":["Lesson <lessonId> not found in your organization.","<field> must be a string","<field> must be 1–255 characters","<field> must not contain control characters (tabs, newlines…)","sort_order must be a non-negative integer (the 0-based position)","Nothing to update."]},{"name":"set_flow","title":"Set branching flow","description":"Turn a course into an adaptive path (or back to linear). Describe the graph in lessons and conditions — nodes reference lesson ids from get_course, edges carry conditions (assessment_score on the lesson the edge leaves, or none for the one fallback edge). Layout, geometry, and editor metadata are computed for you. Read opencourse://tutorials/branching first; pass flow_mode \"linear\" with no graph to switch branching off.","inputSchema":{"type":"object","properties":{"courseId":{"type":"string","description":"Course id (uuid)"},"flow_mode":{"type":"string","enum":["linear","branching"]},"graph":{"type":"object","description":"Required when flow_mode is \"branching\"","properties":{"nodes":{"type":"array","items":{"type":"object","properties":{"lessonId":{"type":"string","description":"A lesson id from get_course"},"isEntry":{"type":"boolean","description":"Exactly one node must be the entry"},"isExit":{"type":"boolean","description":"At least one node must be an exit"}},"required":["lessonId"],"additionalProperties":false}},"edges":{"type":"array","items":{"type":"object","properties":{"from":{"type":"string","description":"Source lesson id"},"to":{"type":"string","description":"Target lesson id"},"condition":{"type":"object","description":"Condition object, or omit for an unconditional edge. See the branching tutorial.","additionalProperties":true},"label":{"type":"string","description":"Short label shown on the edge, e.g. \"score ≥ 80%\""},"priority":{"type":"integer","description":"Lower evaluates first when several edges leave one node"}},"required":["from","to"],"additionalProperties":false}}},"required":["nodes","edges"],"additionalProperties":false}},"required":["courseId","flow_mode"],"additionalProperties":false},"annotations":{"title":"Set branching flow","readOnlyHint":false,"destructiveHint":true,"openWorldHint":false},"requiredScope":"write:courses","example":{"arguments":{"courseId":"3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11","flow_mode":"branching","graph":{"nodes":[{"lessonId":"c41e7f83-5d2a-4b6c-8e1f-9a0b3c4d5e33","isEntry":true},{"lessonId":"d52f8094-6e3b-4c7d-9f20-ab1c4d5e6f44","isExit":true},{"lessonId":"e6309105-7f4c-4d8e-a031-bc2d5e6f7055"}],"edges":[{"from":"c41e7f83-5d2a-4b6c-8e1f-9a0b3c4d5e33","to":"d52f8094-6e3b-4c7d-9f20-ab1c4d5e6f44"},{"from":"d52f8094-6e3b-4c7d-9f20-ab1c4d5e6f44","to":"e6309105-7f4c-4d8e-a031-bc2d5e6f7055","condition":{"type":"assessment_score","operator":"<","value":80},"label":"score < 80%"},{"from":"e6309105-7f4c-4d8e-a031-bc2d5e6f7055","to":"d52f8094-6e3b-4c7d-9f20-ab1c4d5e6f44","label":"try again"}]}},"result":{"ok":true,"courseId":"3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11","flow_mode":"branching","nodes":3,"edges":3,"editorUrl":"https://scormbusters.com/courses/3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11"}},"sideEffects":"Saves the course's flow mode and (for branching) its graph, laid out automatically, and pushes it to open editors. Switching to linear keeps the stored graph so it can be switched back on.","errors":["Course <courseId> not found in your organization.","flow_mode must be \"linear\" or \"branching\"","flow_mode \"branching\" requires a graph","The graph needs at least one node.","Each lesson can appear in the graph only once.","Node lesson <lessonId> is not a lesson of this course. Call get_course for valid lesson ids.","Exactly one node must have isEntry: true (got <n>). The entry is where every learner starts.","At least one node must have isExit: true — the lesson(s) where the course can complete.","edges[<i>].from (<id>) is not a node in the graph","edges[<i>].to (<id>) is not a node in the graph","edges[<i>].condition: compound conditions are not supported; use one assessment_score condition per edge.","edges[<i>].condition: condition type \"<type>\" is not supported. Valid: <always, assessment_score>.","edges[<i>].condition: assessment_score needs an operator (<operators>)","edges[<i>].condition: assessment_score needs a numeric value (0–100)","edges[<i>].condition: assessment_score tests the lesson this edge leaves, so its lessonId must be <from> (or omitted).","\"<lesson>\" has <n> unconditional edges; a lesson can have only one fallback.","\"<lesson>\" is an exit but has an unconditional edge out of it, so the course could never end there. Remove that edge, or make it conditional.","\"<lesson>\" is not an exit and has no unconditional edge, so a learner whose score matches no condition would be stranded there. Add a fallback edge, or mark it isExit.","Unreachable node(s): <titles>. Every node needs a path from the entry."]},{"name":"audit_course","title":"Audit course","description":"Check a whole course for accessibility and design problems: useless or missing alt text, uncaptioned video, broken quiz answer keys, heading-order violations, empty or overlong lessons. Returns findings by severity (error, warning, suggestion; Scenes courses report error, warning, info). Run this after building and fix every error before telling the human you're done. On a Scenes course it runs the same preflight the Scenes export runs (unnamed controls, images without alt text, broken trigger references, contrast, quiz keys…): findings carry slideId/objectId, and byRule says which tool fixes each rule (update_scene_object, update_scene_slide, or the editor). Findings are capped at 150 per call; filter with slideId or severity.","inputSchema":{"type":"object","properties":{"courseId":{"type":"string","description":"Course id (uuid)"},"slideId":{"type":"string","description":"Scenes courses only: just this slide's findings"},"severity":{"type":"string","enum":["error","warning","info"],"description":"Scenes courses only: just this severity"}},"required":["courseId"],"additionalProperties":false},"annotations":{"title":"Audit course","readOnlyHint":true,"destructiveHint":false,"openWorldHint":false},"requiredScope":"read:courses","example":{"arguments":{"courseId":"3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11"},"result":{"findings":[{"severity":"suggestion","rule":"course-description","message":"The course has no description. Learners see it in the catalog — one or two sentences on what they'll be able to do."},{"severity":"warning","rule":"heading-order","message":"Heading level jumps to h3 after h1. Levels must descend without skipping.","lessonId":"c41e7f83-5d2a-4b6c-8e1f-9a0b3c4d5e33","lessonTitle":"The daily inspection","blockId":"f7410216-805d-4e9f-b142-cd3e6f708166","blockType":"heading"},{"severity":"error","rule":"alt-text","message":"Alt text \"IMG_0042.jpg\" is a file name or a placeholder, not a description. Write what the image teaches.","lessonId":"c41e7f83-5d2a-4b6c-8e1f-9a0b3c4d5e33","lessonTitle":"The daily inspection","blockId":"0852132a-916e-4fa0-8253-de4f70819277","blockType":"image"},{"severity":"warning","rule":"empty-lesson","message":"Lesson has no blocks.","lessonId":"d52f8094-6e3b-4c7d-9f20-ab1c4d5e6f44","lessonTitle":"Check your knowledge"}],"summary":{"error":1,"warning":2,"suggestion":1}}},"sideEffects":"None.","errors":["Course <courseId> not found in your organization."]},{"name":"export_course","title":"Export course package","description":"Build a standards-compliant package (SCORM 1.2, SCORM 2004, cmi5, or xAPI) and return a download link that works for 24 hours. Hand the link to the human; the package uploads to any LMS. Block and Scenes courses both export. A Scenes course is refused, with the findings, while the preflight finds errors (as the editor's export is): fix them (audit_course says how) or pass force: true only when the human wants a work-in-progress package. When the human will upload the package over a course already in their LMS that this one was imported from (\"replace the original\", \"update the old course\", \"keep learners' completions\"), pass replaceOriginal: true in the original's format; otherwise leave it off, because the default package is a new course to the LMS.","inputSchema":{"type":"object","properties":{"courseId":{"type":"string","description":"Course id (uuid)"},"format":{"type":"string","enum":["scorm12","scorm2004","cmi5","xapi"],"description":"Defaults to scorm2004"},"locale":{"type":"string","description":"Optional BCP-47 locale to export a stored translation, e.g. \"de\" (block courses only)"},"languages":{"type":"array","items":{"type":"string"},"minItems":1,"description":"Block courses only: one package carrying the course's own language and its translations, with a language picker for the learner (LMS preference, then browser, then the course's language) and a switch in the player. Progress and score do not depend on the language. [\"all\"] takes every complete translation; a list of locales (e.g. [\"fr\", \"de\"]) takes those, complete or not (missing strings show in the course's language). The result's languages.notes name what was left out or incomplete; pass them on. Overrides locale."},"force":{"type":"boolean","description":"Scenes courses only: export even though the preflight finds errors. The result then carries a warning to pass on."},"replaceOriginal":{"type":"boolean","description":"Only for a course imported from an LMS package: keep the original package's identifiers so the LMS can take it as a new version of the old course. Refused when the course was not imported from a package, or when the original had no identity in this format (e.g. cmi5 for a SCORM original): export in the format the refusal names. The result's replaceOriginal.notes say what to check (a changed SCORM version, a multi-part original); pass them on. Tell the human to upload it through the LMS's replace workflow and to try a test copy first."}},"required":["courseId"],"additionalProperties":false},"annotations":{"title":"Export course package","readOnlyHint":true,"destructiveHint":false,"openWorldHint":false},"requiredScope":"read:courses","example":{"arguments":{"courseId":"3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11","format":"scorm12"},"result":{"downloadUrl":"<signed storage URL>","filename":"Forklift_Safety_Refresher_SCORM1.2.zip","format":"scorm12","sizeBytes":482113,"expiresIn":"24 hours"}},"sideEffects":"Builds the package and stores the zip in the organization's file storage (under exports/). Annotated read-only because course content is not changed.","errors":["Course <courseId> not found in your organization.","This course was not imported from an LMS package, so there is no original identity to keep.","The original was published as <original format>, not cmi5, so there is no cmi5 identity to keep. Export as <original format> to replace it."]},{"name":"get_scene_slide","title":"Get Scenes slide","description":"Read one slide of a Scenes course: its name and notes, its layers, and per object the id, type, name, layer, hidden flag, words (text: [{ path, label, value }], long values cut at 280 characters), alt_text, aria_label, aria_role, the accessibleName a screen reader will announce (null on a control that has none), and how many states and triggers it has. Geometry and trigger bodies are left out. 100 objects per call; the reply says how to page.","inputSchema":{"type":"object","properties":{"slideId":{"type":"string","description":"Slide id (uuid), from get_course or an audit_course finding"},"offset":{"type":"integer","minimum":0,"description":"Skip this many objects (for slides with more than 100)"}},"required":["slideId"],"additionalProperties":false},"annotations":{"title":"Get Scenes slide","readOnlyHint":true,"destructiveHint":false,"openWorldHint":false},"requiredScope":"read:courses","example":{"arguments":{"slideId":"3b84465a-c491-4cd3-b586-0172a314c5aa"},"result":{"slide":{"id":"3b84465a-c491-4cd3-b586-0172a314c5aa","courseId":"2a743549-b380-4bc2-a475-f0619203b499","name":"Leadership styles","order":4,"notes":""},"layers":[{"id":"<layer id>","name":"Autocratic"}],"objectCount":2,"objects":[{"id":"4c95576b-d5a2-4de4-8697-1283b425d6bb","type":"shape","name":"Rectangle 12","interactive":true,"accessibleName":null,"states":0,"triggers":1},{"id":"<object id>","type":"text","name":"Text_Caption_95","text":[{"path":"content.html","label":"Text","value":"Click each style to learn more"}],"states":0,"triggers":0}]}},"sideEffects":"None.","errors":["Slide <slideId> not found in your organization."]},{"name":"view_scene_images","title":"View a slide's pictures","description":"See the pictures on one Scenes slide (up to 6, undescribed ones first, downscaled) so you can write accurate alt text with update_scene_object — never describe an image you have not seen. Each picture comes with its objectId and current alt text.","inputSchema":{"type":"object","properties":{"slideId":{"type":"string","description":"Slide id (uuid), from get_course or an audit_course finding"},"objectIds":{"type":"array","items":{"type":"string"},"maxItems":6,"description":"Only these image objects (from get_scene_slide or the audit)"}},"required":["slideId"],"additionalProperties":false},"annotations":{"title":"View a slide's pictures","readOnlyHint":true,"destructiveHint":false,"openWorldHint":false},"requiredScope":"read:courses","example":{"arguments":{"slideId":"3b84465a-c491-4cd3-b586-0172a314c5aa"},"result":{"slide":{"id":"3b84465a-c491-4cd3-b586-0172a314c5aa","name":"PMBOK"},"images":[{"objectId":"4c95576b-d5a2-4de4-8697-1283b425d6bb","name":"book1","altText":null,"decorative":false,"image":"shown"}],"total":1,"next":"Describe each picture with update_scene_object { objectId, alt_text } …"}},"sideEffects":"None. The content also carries each picture as an MCP image block (JPEG, at most 768 px on its longer side).","errors":["Slide <slideId> not found in your organization.","objectIds must be an array of object ids from get_scene_slide.","None of those objectIds is an image on this slide."]},{"name":"update_scene_object","title":"Update Scenes object","description":"Change what an author would retype on one object of a Scenes course: its words (text: [{ path, value }] with a path from get_scene_slide — plain text is fine, it becomes paragraphs), alt_text (\"\" marks an image decorative), aria_label (the name a screen reader announces), aria_role, name, or hidden. Triggers, variables, states' behavior and geometry are never touched. Open editors update live, and the first edit in a session saves a restorable version.","inputSchema":{"type":"object","properties":{"objectId":{"type":"string","description":"Object id (uuid), from get_scene_slide or an audit_course finding"},"text":{"type":"array","description":"New words for existing text fields","items":{"type":"object","properties":{"path":{"type":"string","description":"A path from get_scene_slide's text list, e.g. \"content.html\" or \"content.options.0.text\""},"value":{"type":"string","description":"The new text (plain text, or HTML for an html path)"}},"required":["path","value"],"additionalProperties":false}},"alt_text":{"type":["string","null"],"description":"Image description (max 1000); \"\" for decorative, null to clear"},"aria_label":{"type":["string","null"],"description":"Accessible name for a control or group (max 1000); null to clear"},"aria_role":{"type":["string","null"],"enum":["none","button","link","image","heading","text","checkbox","radio",null],"description":"ARIA role, as the editor's Accessibility panel offers them; null to clear"},"name":{"type":"string","description":"Object name in the editor's layer list (1–255 chars)"},"hidden":{"type":"boolean","description":"Hidden at slide start (a trigger may still show it)"},"focusable":{"type":["boolean","null"],"description":"Whether it is a keyboard control. null (the default) infers it: a control when it has a click/hover trigger or is a native control. false for text or images an import wrongly made interactive; true only for a real control the inference misses."}},"required":["objectId"],"additionalProperties":false},"annotations":{"title":"Update Scenes object","readOnlyHint":false,"destructiveHint":true,"openWorldHint":false},"requiredScope":"write:courses","example":{"arguments":{"objectId":"4c95576b-d5a2-4de4-8697-1283b425d6bb","aria_label":"Show the Autocratic style"},"result":{"id":"4c95576b-d5a2-4de4-8697-1283b425d6bb","courseId":"2a743549-b380-4bc2-a475-f0619203b499","slideId":"3b84465a-c491-4cd3-b586-0172a314c5aa","changed":["aria_label"],"versionSaved":"Saved a restorable version \"Before assistant edits\" first.","accessibleName":"Show the Autocratic style"}},"sideEffects":"Updates the object and broadcasts the change to open Scenes editors. The first edit to a course in 30 minutes saves a version (\"Before assistant edits\") the author can restore.","errors":["Object <objectId> not found in your organization.","\"<path>\" is not a text field on this object. Use a path from get_scene_slide's text list: <paths>.","aria_role must be one of <roles> (or null).","Nothing to change: pass at least one of text, alt_text, aria_label, aria_role, name, hidden, focusable.","This picture is a control (it has a click trigger), often an invisible click area: decorative would hide it from keyboard users. Give it an aria_label saying what clicking it does."]},{"name":"update_scene_slide","title":"Update Scenes slide","description":"Rename a slide of a Scenes course or rewrite its notes (the narration script / speaker notes). Open editors update live.","inputSchema":{"type":"object","properties":{"slideId":{"type":"string","description":"Slide id (uuid)"},"name":{"type":"string","description":"Slide name (1–255 chars)"},"notes":{"type":"string","description":"Slide notes (max 20,000 chars; \"\" clears them)"}},"required":["slideId"],"additionalProperties":false},"annotations":{"title":"Update Scenes slide","readOnlyHint":false,"destructiveHint":true,"openWorldHint":false},"requiredScope":"write:courses","example":{"arguments":{"slideId":"3b84465a-c491-4cd3-b586-0172a314c5aa","name":"Six leadership styles"},"result":{"id":"3b84465a-c491-4cd3-b586-0172a314c5aa","courseId":"2a743549-b380-4bc2-a475-f0619203b499","changed":["name"]}},"sideEffects":"Updates the slide and broadcasts the change to open Scenes editors; saves a restorable version first, as update_scene_object does.","errors":["Slide <slideId> not found in your organization.","Nothing to change: pass name or notes."]},{"name":"upload_asset","title":"Upload asset","description":"Fetch a public https image, video, audio, or PDF (max 25MB) into the organization's media library and return its permanent URL — use that URL in image/video/audio block content. Counts against the plan's storage quota.","inputSchema":{"type":"object","properties":{"url":{"type":"string","description":"Public https URL of the file to import"},"filename":{"type":"string","description":"Optional filename hint, used for the extension"}},"required":["url"],"additionalProperties":false},"annotations":{"title":"Upload asset","readOnlyHint":false,"destructiveHint":false,"openWorldHint":true},"requiredScope":"write:courses","example":{"arguments":{"url":"https://example.com/assets/forklift-inspection.jpg"},"result":{"url":"<public storage URL>","mimeType":"image/jpeg","sizeBytes":184220}},"sideEffects":"Stores the file in the organization's media library. Counts against the plan's storage quota.","errors":["Could not use that URL: <reason> It must be a public https URL.","Content type \"<type>\" is not allowed. Images, video, audio, and PDF only.","This upload would exceed the organization's storage quota. Free space in the media library or upgrade the plan."]},{"name":"import_course","title":"Import legacy course","description":"Import a legacy e-learning package as a new draft course. A published .zip is recognized by its contents: Captivate (Classic 9–2019 and the all-new 12/13), Storyline, Rise 360, Lectora, iSpring, Articulate Studio (recognized; Flash reported), SCORM 1.2/2004, AICC, cmi5, xAPI, Adapt/Evolve, H5P and IMS Common Cartridge/QTI. Source files: .cptx, .story, .awt, .pptx, .h5p, .imscc and Moodle backups (.mbz). Pass a public https url to the file (max 100MB), or the storagePath of a file already staged in the app's course-imports storage. Returns the new courseId and the import report — what could not be recreated — so you can plan fixes: then audit_course, fix, and export_course. Limited to 10 imports per person (or API key) per 24 hours.","inputSchema":{"type":"object","properties":{"url":{"type":"string","description":"Public https URL of the package. Give this or storagePath, not both."},"storagePath":{"type":"string","description":"Path of a package already staged in course-imports storage (<org id>/<file>). Give this or url."},"filename":{"type":"string","description":"File name with extension, e.g. \"safety.zip\" — needed when the URL or path does not end in one; the extension picks the parser"}},"additionalProperties":false},"annotations":{"title":"Import legacy course","readOnlyHint":false,"destructiveHint":false,"openWorldHint":true},"requiredScope":"write:courses","example":{"arguments":{"url":"https://example.com/legacy/forklift-safety-scorm12.zip"},"result":{"courseId":"3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11","title":"Forklift Safety Refresher","sourceFormat":"scorm12","lessonCount":6,"assetCount":14,"report":{"notRecreated":[{"feature":"Flash interactions","count":2,"detail":"Rebuild them with native interactive blocks."}],"notes":[]},"warnings":[],"editorUrl":"https://scormbusters.com/courses/3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11","next":"Run audit_course on courseId, fix what it and report.notRecreated describe, then export_course."}},"sideEffects":"Creates a draft course from the package, uploads its media to the organization's media library, and deletes a staged storagePath file once read. Uses one of the 10 imports per 24 hours.","errors":["Pass exactly one of url or storagePath.","Cannot tell the package type from \"<name>\". Pass filename with one of these extensions: <extensions>.","storagePath must be a file in your organization's course-imports folder (<org id>/<file>).","No staged file at <storagePath>.","Could not use that URL: <reason> It must be a public https URL.","File too large (max 100MB)","Importing a course needs the member role or higher in this organization.","Import limit reached (<n> per 24 hours). Try again tomorrow.","Failed to parse file: <parser message>","Nothing in \"<title>\" could be converted into editable content, so no course was created. <reasons>"]},{"name":"create_review_link","title":"Create review link","description":"Mint a shareable review link for a course. Anyone with the link sees the content read-only — block courses as lessons, scenes courses in the real player — and leaves structured feedback (typed comments, suggested replacement wording, per-block or per-slide anchors) without signing in. Hand the URL to the human to send to their reviewer; links expire after 30 days and can be revoked in the editor's Share dialog.","inputSchema":{"type":"object","properties":{"courseId":{"type":"string","description":"Course id (uuid)"},"title":{"type":"string","description":"Optional label, e.g. \"Legal review — April\""}},"required":["courseId"],"additionalProperties":false},"annotations":{"title":"Create review link","readOnlyHint":false,"destructiveHint":false,"openWorldHint":false},"requiredScope":"write:courses","example":{"arguments":{"courseId":"3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11","title":"SME review — compliance pass"},"result":{"reviewUrl":"https://scormbusters.com/review/5a7b9c0d-1e2f-4a3b-8c4d-6e7f8091a2b3","sessionId":"4b6c8d9e-0f1a-4b2c-9d3e-5f60718293a4","title":"SME review — compliance pass","expiresAt":"2026-11-01T09:00:00.000Z","next":"Give reviewUrl to the human to send to their reviewer; later, read what came back with get_review_feedback."}},"sideEffects":"Creates a review link anyone can open without signing in (read-only content, comment-only). Expires after 30 days; revocable from the editor's Share dialog.","errors":["Course <courseId> not found in your organization.","Could not create the review link."]},{"name":"get_review_feedback","title":"Get review feedback","description":"Everything reviewers have said about a course, across all of its review links: comments sorted most-urgent first with their kind (factual error, missing content, wording, …), the reviewer's suggested replacement text where given, whether the content has changed or been deleted since (context_state), reply threads, resolution state, and per-link verdicts (approved / changes requested). Start here before editing in response to a review; a comment whose context_state is \"changed\" may no longer apply.","inputSchema":{"type":"object","properties":{"courseId":{"type":"string","description":"Course id (uuid)"}},"required":["courseId"],"additionalProperties":false},"annotations":{"title":"Get review feedback","readOnlyHint":true,"destructiveHint":false,"openWorldHint":false},"requiredScope":"read:courses","example":{"arguments":{"courseId":"3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11"},"result":{"sessions":[{"id":"4b6c8d9e-0f1a-4b2c-9d3e-5f60718293a4","title":"SME review — compliance pass","status":"changes_requested","expires_at":"2026-11-01T09:00:00.000Z","last_viewed_at":"2026-10-02T08:12:00.000Z","created_at":"2026-10-01T09:00:00.000Z","comment_count":2}],"comments":[{"id":"6c8d0e1f-2a3b-4c4d-ae5f-708192a3b4c5","kind":"factual","text":"The retention period is six years now, not five.","suggested_text":"Keep every record for six years from the date of issue.","author_name":"Dana (Legal)","block_id":"f7410216-805d-4e9f-b142-cd3e6f708166","lesson_id":"c41e7f83-5d2a-4b6c-8e1f-9a0b3c4d5e33","lesson_title":"Introduction","slide_id":null,"slide_title":null,"context_state":"current","context_excerpt":"Keep every record for five years from the date of issue.","resolved":false,"replies":[],"created_at":"2026-10-02T08:10:00.000Z"}],"summary":{"total":2,"actionable":1,"approvals":1,"questions":0,"unclassified":0,"byKind":{}},"unresolved_summary":{"total":1,"actionable":1,"approvals":0,"questions":0,"unclassified":0,"byKind":{}}}},"sideEffects":"None.","errors":["Course <courseId> not found in your organization."]},{"name":"apply_review_suggestion","title":"Apply review suggestion","description":"Accept a reviewer's suggested wording as written: replaces the text of the block the comment points at and marks the comment resolved. Refuses (409) when the block has been edited since the suggestion was written, when it was deleted, or when a concurrent edit lands first — never applies a suggestion onto words it was not about. On a refusal, read the comment and edit by hand with update_block instead.","inputSchema":{"type":"object","properties":{"courseId":{"type":"string","description":"Course id (uuid)"},"commentId":{"type":"string","description":"The review comment id, from get_review_feedback"}},"required":["courseId","commentId"],"additionalProperties":false},"annotations":{"title":"Apply review suggestion","readOnlyHint":false,"destructiveHint":true,"openWorldHint":false},"requiredScope":"write:courses","example":{"arguments":{"courseId":"3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11","commentId":"6c8d0e1f-2a3b-4c4d-ae5f-708192a3b4c5"},"result":{"blockId":"f7410216-805d-4e9f-b142-cd3e6f708166","revision":7,"resolved":true}},"sideEffects":"Replaces the anchored block's text with the reviewer's suggested wording (the block's revision advances, so a concurrent editor gets a conflict rather than losing work) and marks the comment resolved.","errors":["Course <courseId> not found in your organization.","Comment not found","This comment has no suggested wording","The block this suggestion was written for no longer exists","The block has been edited since this suggestion was written — review it by hand instead","This block has no text field the suggestion could replace","The block changed while applying — try again"]},{"name":"resolve_review_comment","title":"Resolve review comment","description":"Mark a reviewer's comment resolved (or reopen it). Resolve after the change it asked for has actually been made — the reviewer sees the resolution on their page, so a false resolve burns trust.","inputSchema":{"type":"object","properties":{"courseId":{"type":"string","description":"Course id (uuid)"},"commentId":{"type":"string","description":"The review comment id, from get_review_feedback"},"resolved":{"type":"boolean","description":"true to resolve, false to reopen"}},"required":["courseId","commentId","resolved"],"additionalProperties":false},"annotations":{"title":"Resolve review comment","readOnlyHint":false,"destructiveHint":true,"openWorldHint":false},"requiredScope":"write:courses","example":{"arguments":{"courseId":"3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11","commentId":"6c8d0e1f-2a3b-4c4d-ae5f-708192a3b4c5","resolved":true},"result":{"commentId":"6c8d0e1f-2a3b-4c4d-ae5f-708192a3b4c5","resolved":true}},"sideEffects":"Sets the comment's resolved flag; the reviewer sees the resolution on their page.","errors":["Course <courseId> not found in your organization.","Comment not found","Could not update the comment."]},{"name":"reply_review_comment","title":"Reply to review comment","description":"Post a reply in a review comment's thread. The reviewer sees it on their review page, labeled as coming from the author's side — use it to ask what a comment means or to say what was changed, instead of letting the question leak into email. Keep it short and concrete.","inputSchema":{"type":"object","properties":{"courseId":{"type":"string","description":"Course id (uuid)"},"commentId":{"type":"string","description":"The thread's first comment id, from get_review_feedback"},"text":{"type":"string","description":"The reply, plain text, max 5000 characters"}},"required":["courseId","commentId","text"],"additionalProperties":false},"annotations":{"title":"Reply to review comment","readOnlyHint":false,"destructiveHint":false,"openWorldHint":false},"requiredScope":"write:courses","example":{"arguments":{"courseId":"3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11","commentId":"6c8d0e1f-2a3b-4c4d-ae5f-708192a3b4c5","text":"Updated to six years — thanks for catching it."},"result":{"replyId":"7d9e1f20-3b4c-4d5e-bf60-8192a3b4c5d6","createdAt":"2026-10-02T09:30:00.000Z"}},"sideEffects":"Posts a reply into the comment's thread, visible on the reviewer's page and labeled as coming from the author's side.","errors":["Course <courseId> not found in your organization.","Comment not found","Reply text is required.","Reply must be 5000 characters or fewer.","Reply to the thread's first comment, not to a reply.","Could not post the reply."]},{"name":"search_library","title":"Search the library","description":"Enterprise. Find text across every course in the organization: block content (paragraphs, questions, options, feedback, captions, alt text…), Scenes slides (text objects, states, alt text, slide and layer names, notes) and course, module and lesson titles. Returns one row per occurrence with context, whether it can be replaced automatically, and an editorUrl that opens the editor at it. Use it to answer \"where do we still say X?\" before deciding on a replace_in_library.","inputSchema":{"type":"object","properties":{"find":{"type":"string","description":"Text to find (1–200 characters), or a pattern with regex: true"},"matchCase":{"type":"boolean","description":"Match upper and lower case exactly (default false)"},"wholeWord":{"type":"boolean","description":"Only whole words (default false)"},"regex":{"type":"boolean","description":"Treat find as a JavaScript regular expression (default false). Nested repetition like (a+)+ and backreferences are refused"},"courseIds":{"type":"array","items":{"type":"string"},"description":"Only these courses (uuids)"},"statuses":{"type":"array","items":{"type":"string","enum":["draft","published","archived"]},"description":"Only courses with these statuses"},"sources":{"type":"array","items":{"type":"string"},"description":"Only courses imported from these tools (e.g. \"storyline\", \"rise\"); \"none\" for courses built in Scormbusters"},"limit":{"type":"integer","minimum":1,"maximum":500,"description":"Most occurrences to list (default 100); totals always count every match"}},"required":["find"],"additionalProperties":false},"annotations":{"title":"Search the library","readOnlyHint":true,"destructiveHint":false,"openWorldHint":false},"requiredScope":"read:courses","example":{"arguments":{"find":"five years","wholeWord":true,"statuses":["published"]},"result":{"totals":{"courses":1,"occurrences":2,"replaceable":1,"needsManualEdit":1,"coursesSearched":12,"coursesInScope":12,"truncated":false,"partial":false,"skippedTooLong":0},"courses":[{"courseId":"3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11","title":"Forklift Safety Refresher","status":"published","source":null,"occurrences":2}],"matches":[{"occurrenceId":"3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11|block|f7410216-805d-4e9f-b142-cd3e6f708166|content:text|0|8e3f12a4","courseId":"3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11","courseTitle":"Forklift Safety Refresher","where":"The daily inspection › Heading › Text","before":"Keep every record for ","match":"five years","after":" from the date of issue.","replaceable":true,"editorUrl":"https://scormbusters.com/courses/3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11?lesson=c41e7f83-5d2a-4b6c-8e1f-9a0b3c4d5e33&block=f7410216-805d-4e9f-b142-cd3e6f708166"},{"occurrenceId":"3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11|block|19632438-a27f-4ab1-9364-ef508192a388|content:question|0|5b1d07e2","courseId":"3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11","courseTitle":"Forklift Safety Refresher","where":"Check your knowledge › Multiple Choice › Question","before":"How long do we keep records? (","match":"five years","after":")","replaceable":false,"reason":"spans-formatting","editorUrl":"https://scormbusters.com/courses/3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11?lesson=d52f8094-6e3b-4c7d-9f20-ab1c4d5e6f44&block=19632438-a27f-4ab1-9364-ef508192a388"}]}},"sideEffects":"None.","errors":["Enter something to find.","Search text must be <n> characters or fewer.","That pattern is not a valid regular expression: <reason>","That pattern repeats a group that itself repeats or alternates (like (a+)+ or (a|b)*), which can take minutes to run. Simplify it.","Backreferences are not supported in library search.","<field> must be a list of valid values.","Library search and replace need the member role or higher in this organization.","Library search and bulk replace — finding and changing text across every course at once — is an Enterprise feature. Find and edit within a course on every plan."]},{"name":"replace_in_library","title":"Replace across the library","description":"Enterprise. Replace text across many courses at once, in two calls. First call with dry_run: true — nothing is written; you get the before/after preview of every occurrence and a confirm_token. Show the human the preview. Only if they approve, call again with the same arguments, dry_run: false and the confirm_token. Rich text is only changed inside one run of text: a match that crosses formatting (part bold) is reported as needing a manual edit, never guessed at. Every changed lesson or Scenes course gets a version-history snapshot first, each course is audited, and the whole edit can be reversed with undo_library_replace.","inputSchema":{"type":"object","properties":{"find":{"type":"string","description":"Text to find (1–200 characters), or a pattern with regex: true"},"matchCase":{"type":"boolean","description":"Match upper and lower case exactly (default false)"},"wholeWord":{"type":"boolean","description":"Only whole words (default false)"},"regex":{"type":"boolean","description":"Treat find as a JavaScript regular expression (default false). Nested repetition like (a+)+ and backreferences are refused"},"courseIds":{"type":"array","items":{"type":"string"},"description":"Only these courses (uuids)"},"statuses":{"type":"array","items":{"type":"string","enum":["draft","published","archived"]},"description":"Only courses with these statuses"},"sources":{"type":"array","items":{"type":"string"},"description":"Only courses imported from these tools (e.g. \"storyline\", \"rise\"); \"none\" for courses built in Scormbusters"},"replace":{"type":"string","description":"Replacement text (may be empty to delete the matches). With regex: true, $1…$9 and $<name> insert groups"},"dry_run":{"type":"boolean","description":"true to preview without writing (required first); false to apply"},"confirm_token":{"type":"string","description":"The confirm_token from the dry run; required with dry_run: false"},"occurrenceIds":{"type":"array","items":{"type":"string"},"description":"Optional: replace only these occurrences (ids from the preview). Omit to replace every replaceable occurrence"},"limit":{"type":"integer","minimum":1,"maximum":200,"description":"Most preview rows to list (default 50)"}},"required":["find","replace","dry_run"],"additionalProperties":false},"annotations":{"title":"Replace across the library","readOnlyHint":false,"destructiveHint":true,"openWorldHint":false},"requiredScope":"write:courses","example":{"arguments":{"find":"five years","replace":"six years","wholeWord":true,"statuses":["published"],"dry_run":false,"confirm_token":"9c1e4f0a7b2d4c6e8f10a2b3c4d5e6f7"},"result":{"dry_run":false,"editId":"2a4c6e80-9b1d-4f3a-8c5e-7d9f0b1a2c3d","totals":{"courses":1,"replaced":1,"skipped":0},"courses":[{"courseId":"3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11","title":"Forklift Safety Refresher","replaced":1,"skipped":0}],"next":"Every changed lesson and Scenes course has a version-history snapshot labeled with this replace. To reverse the whole edit, call undo_library_replace with editId."}},"sideEffects":"dry_run: true writes nothing. dry_run: false first saves a version-history snapshot of every lesson and Scenes course it will change (labeled \"Bulk replace: '<find>' → '<replace>'\"), then rewrites the matching text, writes one audit-log entry per changed course, records the edit for undo_library_replace, and updates any editor that has the course open.","errors":["dry_run is required: call with dry_run: true first, check the preview with the human, then repeat with dry_run: false and the confirm_token.","confirm_token is required with dry_run: false. Run a dry run first and pass the confirm_token it returns.","The library changed since the dry run, or the arguments differ from it. Run replace_in_library with dry_run: true again and confirm the new preview.","replace must be a string (it may be empty, to delete the matches).","replace must be <n> characters or fewer.","Bulk edits are limited to <n> an hour. Try again later.","Library search and replace need the member role or higher in this organization.","Enter something to find."]},{"name":"undo_library_replace","title":"Undo a library replace","description":"Enterprise. Reverse one replace_in_library: every field it changed goes back to what it was, wherever the text is still what the replace wrote. Fields someone edited since are left alone and listed as conflicts. Only the person who made the edit, or an admin, can undo it.","inputSchema":{"type":"object","properties":{"editId":{"type":"string","description":"The editId replace_in_library returned"}},"required":["editId"],"additionalProperties":false},"annotations":{"title":"Undo a library replace","readOnlyHint":false,"destructiveHint":true,"openWorldHint":false},"requiredScope":"write:courses","example":{"arguments":{"editId":"2a4c6e80-9b1d-4f3a-8c5e-7d9f0b1a2c3d"},"result":{"editId":"2a4c6e80-9b1d-4f3a-8c5e-7d9f0b1a2c3d","restored":1,"courses":[{"courseId":"3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11","title":"Forklift Safety Refresher","restored":1,"conflicts":0}],"conflicts":[],"next":"The bulk edit is fully undone."}},"sideEffects":"Saves a \"Before undo\" version-history snapshot of each affected lesson and Scenes course, puts every changed field back to its value before the replace where it still holds what the replace wrote, audits each course, and marks the edit undone.","errors":["editId must be the id replace_in_library returned.","Bulk edit not found in your organization.","This bulk edit has already been undone.","Only the person who made this bulk edit, or an admin, can undo it.","Bulk edits are limited to <n> an hour. Try again later."]},{"name":"search","title":"Search course content","description":"Search the words in the organization's courses — titles, descriptions, lesson text, questions and Scenes slide text — and return up to 20 matching course outlines, lessons and slides, best first: {results: [{id, title, url}]}. Read one with fetch(id).","inputSchema":{"type":"object","properties":{"query":{"type":"string","description":"Words to look for, e.g. \"fire extinguisher types\""}},"required":["query"],"additionalProperties":false},"annotations":{"title":"Search course content","readOnlyHint":true,"destructiveHint":false,"openWorldHint":false},"requiredScope":"read:courses","example":{"arguments":{"query":"daily forklift inspection"},"result":{"results":[{"id":"lesson:3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11:c41e7f83-5d2a-4b6c-8e1f-9a0b3c4d5e33","title":"Forklift Safety Refresher › The daily inspection","url":"https://scormbusters.com/courses/3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11?lesson=c41e7f83-5d2a-4b6c-8e1f-9a0b3c4d5e33"},{"id":"course:3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11","title":"Forklift Safety Refresher","url":"https://scormbusters.com/courses/3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11"}]}},"sideEffects":"None.","errors":["query is required."]},{"name":"fetch","title":"Fetch course content","description":"Read the text of one search result — a whole course, a lesson or a slide — as {id, title, text, url, metadata}. A course is capped at 50,000 characters; fetch its lessons for the rest.","inputSchema":{"type":"object","properties":{"id":{"type":"string","description":"An id from search, e.g. \"course:<uuid>\" or \"lesson:<courseId>:<lessonId>\""}},"required":["id"],"additionalProperties":false},"annotations":{"title":"Fetch course content","readOnlyHint":true,"destructiveHint":false,"openWorldHint":false},"requiredScope":"read:courses","example":{"arguments":{"id":"lesson:3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11:c41e7f83-5d2a-4b6c-8e1f-9a0b3c4d5e33"},"result":{"id":"lesson:3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11:c41e7f83-5d2a-4b6c-8e1f-9a0b3c4d5e33","title":"Forklift Safety Refresher › The daily inspection","text":"# Forklift Safety Refresher › The daily inspection\nLesson · Lesson title: The daily inspection\nHeading · Text: Before you start","url":"https://scormbusters.com/courses/3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11?lesson=c41e7f83-5d2a-4b6c-8e1f-9a0b3c4d5e33","metadata":{"kind":"lesson","courseId":"3f6c1a52-7a0e-4f4b-9d2c-5b8e1f0a9c11","courseTitle":"Forklift Safety Refresher","status":"draft","editorMode":"classic","updatedAt":"2026-09-25T10:00:00.000Z","truncated":false}}},"sideEffects":"None.","errors":["Unknown id \"<id>\". Pass an id exactly as search returned it.","Nothing with id <id> in your organization."]}],"resources":[{"uri":"opencourse://tutorials/getting-started","name":"getting-started","title":"Getting started","description":"The mental model and the golden path: plan, create in one call, refine, publish. Read this first.","mimeType":"text/markdown"},{"uri":"opencourse://tutorials/course-design","name":"course-design","title":"Course design that works","description":"Instructional-design conventions: structure, lesson rhythm, writing style, accessibility rules.","mimeType":"text/markdown"},{"uri":"opencourse://tutorials/assessments","name":"assessments","title":"Writing assessments","description":"Choosing assessment blocks, question craft, feedback, and scoring.","mimeType":"text/markdown"},{"uri":"opencourse://tutorials/branching","name":"branching","title":"Branching: adaptive paths","description":"How to build an adaptive course graph with set_flow: the input shape, condition types, and design guidance.","mimeType":"text/markdown"},{"uri":"opencourse://tutorials/blocks","name":"blocks","title":"Block reference","description":"Every block type's exact content schema with a realistic example — generated from the editor's own definitions.","mimeType":"text/markdown"},{"uri":"opencourse://tutorials/publishing","name":"publishing","title":"Publishing and delivery","description":"Statuses, what the human can do with what you build, export formats, and agent etiquette.","mimeType":"text/markdown"},{"uri":"opencourse://tutorials/imported-courses","name":"imported-courses","title":"Fixing an imported course","description":"Imported Storyline/Captivate courses are Scenes courses (slides of objects): how to audit them, fix names, alt text and words, and export or replace the original in the LMS.","mimeType":"text/markdown"}],"prompts":[{"name":"build-course","title":"Build a course","description":"Plan and build a complete course on a topic, following Scormbusters' design conventions.","arguments":[{"name":"topic","description":"What the course teaches","required":true},{"name":"audience","description":"Who it is for","required":false},{"name":"length_minutes","description":"Rough target length in minutes","required":false}]},{"name":"improve-course","title":"Improve an existing course","description":"Audit a course for accessibility and design issues, then fix what can be fixed.","arguments":[{"name":"course","description":"Course title or id to improve","required":true}]},{"name":"fix-imported-course","title":"Fix an imported course","description":"Make a course imported from Storyline, Captivate or another slide tool pass its accessibility preflight, then export it — optionally to replace the original in the LMS.","arguments":[{"name":"course","description":"Course title or id","required":true},{"name":"replace_in_lms","description":"\"yes\" when the export will replace the original package in the LMS","required":false}]}]}