Skip to main content
This page documents every tool the MCP server exposes. Each tool is filtered at registration time against your key’s scopes and your user’s permissions — so the AI sees only what it can actually invoke. If your tool list looks shorter than what’s documented here, that’s intentional: you don’t have the permission or license tier required. See the Permissions matrix for which role unlocks which tool.

Read tools

Available to any key with read scope (which is all keys).

find_user

Search for users by name or email substring. Case-insensitive.
query
string
required
Name or email substring to search for.
limit
integer
Max results (default 20, max 50).
Permission: user_view Example prompt: “Find a user named Sarah.” Backend: GET /api/v2/users?query=...&limit=...

get_user

Get full details for one user by ID — name, email, role, group memberships, status.
userId
integer
required
Internal user ID (from find_user or other tool).
Permission: user_view Example prompt: “Show me everything about user 42.” Backend: GET /api/v2/users/:userId

find_course

Search for courses by name. Returns matching courses (id, name, status, annotation).
query
string
required
Course name substring.
limit
integer
Max results (default 20, max 50).
Permission: course_view Example prompt: “Find the OSHA refresher course.” Backend: GET /api/v2/courses?query=...&limit=...

get_course

Full details for one course — name, structure, settings, publish state.
courseId
integer
required
Internal course ID (from find_course).
Permission: course_view Example prompt: “Show me the structure of course 17.” Backend: GET /api/v2/courses/:courseId

list_assignments

List course assignments for one user or one group (exactly one required). No top-level “all assignments” view — too much data; the v2 API scopes by user or group.
userId
integer
Filter by one user. Mutually exclusive with groupId.
groupId
integer
Filter by one group. Mutually exclusive with userId.
Permission: user_assign Example prompts:
  • “What is Jamie working on?” → uses userId
  • “What courses is the Engineering group assigned?” → uses groupId
Backend: GET /api/v2/users/:userId/courses/assignments or GET /api/v2/groups/:groupId/courses/assignments

list_my_assignments

Courses assigned to the current user (the key’s owner), with deadlines and completion status. Useful for “what training do I owe?” questions. No parameters. Permission: any role (learner+) Example prompt: “What training do I have due this week?” Backend: GET /api/v2/courses/assigned/me

get_compliance_status

The flagship audit tool. Returns compliance breakdown for one course: who’s assigned, who’s done, who’s overdue, completion percentages. Optionally scoped to one group.
courseId
integer
required
Course to check compliance against (e.g. OSHA refresher).
groupId
integer
Optional: scope to one group of users.
Permission: common_stat Example prompts:
  • “Pull a compliance report for OSHA confined-spaces training across all warehouse staff.”
  • “Are we ready for the SOC 2 audit on security training?”
Backend: GET /api/v2/courses/:courseId/statistics/users?groupId=...

list_certificates

All certificates earned by one user, with issue dates and (when set) expiry dates. Useful for recertification planning.
userId
integer
required
User whose certificates to list.
Permission: user_view Example prompt: “Show Sarah’s certifications and what’s expiring in the next 90 days.” Backend: GET /api/v2/users/:userId/certificates

get_statistics

High-level analytics — overall engagement, publishing rate, course-creation activity, insights, tag breakdowns.
scope
string
required
Which surface to query. One of: overview, publishing, courseCreation, activity, insights, tags.
Permission: common_stat Example prompt: “How are we doing on training engagement this quarter?” Backend: GET /api/v2/statistics/{scope} For per-course or per-user numbers prefer get_compliance_status or list_assignments.

get_leaderboard

Top learners by points/completion this period.
limit
integer
Top N learners (default 10, max 50).
Permission: common_stat Example prompt: “Who are our top 5 learners this week? I want to send them a thank-you.” Backend: GET /api/v2/statistics/leaders?limit=...

get_audit_log

Read the platform audit log with optional filters. Use for security investigations, compliance questions, and inspecting actions taken by other MCP agents.
authorUserId
integer
Filter by acting user.
fromDate
string
ISO date or YYYY-MM-DD — start of window.
toDate
string
ISO date or YYYY-MM-DD — end of window.
limit
integer
Max results (default 50, max 250).
offset
integer
Pagination offset.
Permission: audit_view Example prompt: “Pull all admin actions taken last Tuesday.” Backend: GET /api/v2/audit?fields[author]=...&fields[createdAt][from]=...&fields[createdAt][to]=...

Write tools

Available when the key has write scope AND your license tier is full (Business or Enterprise).

assign_training

Assign one course to one learner. Idempotent — re-assigning the same user is a no-op. For bulk operations use bulk_assign instead.
courseId
integer
required
Course to assign.
userId
integer
required
Learner to assign to.
deadlineAt
integer
Unix timestamp (seconds) when the assignment is due. Omit for no deadline.
assignAt
integer
Unix timestamp for scheduled future assignment. Omit to assign immediately.
Permission: user_assign Example prompts:
  • “Assign the new-hire onboarding to user 42, deadline two weeks from now.”
  • “Schedule the Q1 compliance refresher for the new sales rep, starting next Monday.”
Backend: POST /api/v2/courses/:courseId/assignments/users

bulk_assign

Assign multiple courses to a whole group at once. Use for onboarding bundles or compliance pushes.
groupId
integer
required
Group whose members get the assignments.
courseIds
integer[]
required
One or more courses to assign.
deadlineAt
integer
Unix-timestamp deadline applied to ALL assignments.
Permission: group_assign Example prompts:
  • “Assign all new-hire training to the Engineering group, due in 30 days.”
  • “Roll out the safety refresher to all warehouse staff.”
Backend: per-course POST /api/v2/courses/:courseId/assignments with {groups: [groupId]}

assign_chain

Assign an entire course chain (an ordered learning path) to users or groups. The caller must own the chain (per-chain ownership rule).
chainId
integer
required
Course-chain ID.
userIds
integer[]
Users to assign the chain to.
groupIds
integer[]
Groups to assign the chain to.
deadlineAt
integer
Unix-timestamp deadline for the whole chain.
Permission: user_assign + chain ownership Example prompt: “Put the new-hire learning path on Marco’s plate, due 45 days from start date.” Backend: POST /api/v2/courseChains/:chainId/assign

ban_user

Ban a user (revokes their login + course access, preserves history). Use for offboarding. Target must be below the caller’s role in the hierarchy.
userId
integer
required
User to ban.
Permission: user_ban + role hierarchy Example prompt: “Sarah left the company last Friday — disable her account.” Backend: POST /api/v2/users/banned

unban_user

Restore a previously banned user’s access. Used for reinstating offboarded learners (rehires, contractors who returned, etc.).
userId
integer
required
User to unban.
Permission: user_ban + role hierarchy Example prompt: “Marco’s back from sabbatical — re-enable his account.” Backend: DELETE /api/v2/users/banned/:userId

change_user_email

Update a user’s email address (e.g. after a name change or domain migration). Triggers the standard email-change notification.
userId
integer
required
User whose email is changing.
email
string
required
New email address.
Permission: user_edit + role hierarchy Example prompt: “Maria changed her name — update her email to maria.gomez@acme.com.” Backend: POST /api/v2/users/:userId/email/change

clone_course

Duplicate an existing course (creates an unpublished copy that you can then edit). Useful as the first step when forking a course for a different audience or location.
courseId
integer
required
Course to clone.
Permission: course_edit Example prompt: “Clone the Forklift Safety course for the new Phoenix warehouse — I’ll customize it for their layout.” Backend: POST /api/v2/courses/clone with {courseId} in body

AI course generation

Four tools that let an agent build a complete course from a prompt or from uploaded source materials. Available on Business and Enterprise (mcpAccess: "full" + mcpAiAccess: true). Subject to a separate, stricter quota — 5 calls per key per day, 50 per tenant per day. The typical workflow:
  1. upload_source_material — once per file. Returns a sessionId.
  2. create_course_from_files (with the sessionId) or create_course_from_prompt (no files). Returns a jobId.
  3. get_course_generation_status — poll every 3–5 seconds until status is completed, then read result.courseId.

upload_source_material

Read a local file off the user’s machine and upload it as a course source. Text is extracted and embedded immediately. PDF / DOC / DOCX / PNG / JPG / GIF / WebP, 20 MB max per file.
filePath
string
required
Absolute path to a local file on the user’s machine.
sessionId
string
Optional. Reuse the same sessionId across multiple uploads to bundle files into one course-generation context. Omit and the tool generates one.
Permission: course_edit + license mcpAiAccess Example prompt: “Use this OSHA confined-spaces PDF I just shared as the source for a new course.” Returns: { sessionId, filename, chunkCount, message } Backend: POST /api/v2/chat/source-materials/upload (multipart) then POST /api/v2/chat/source-materials/process

create_course_from_prompt

Generate a complete course (title, modules, lessons, quiz) from a plain-English description. Returns a jobId — the actual generation runs in the background and takes 10–30 seconds.
prompt
string
required
Plain-English description of the course. Be specific: include the topic, audience, scope.
chapters
integer
Optional. Target number of modules. Default 6.
language
string
Optional. ISO 639-1 code (en, es, fr, …). If omitted, the model uses the language of the prompt.
title
string
Optional. Override the AI-generated title.
Permission: course_edit + license mcpAiAccess Example prompt: “Build a compliance course on confined-space safety for warehouse staff. 6 lessons + a final quiz.” Returns: { jobId, status, message }status is always queued here; poll get_course_generation_status. Backend: POST /api/v2/ai/courses/generate with { prompt, options }

create_course_from_files

Same as create_course_from_prompt but grounded in previously-uploaded source materials. The agent must call upload_source_material at least once in this conversation before calling this tool.
prompt
string
required
Plain-English direction for the course. The uploaded files are the primary source; the prompt sets tone, audience, scope.
sessionId
string
required
The sessionId returned by upload_source_material.
chapters
integer
Optional. Target number of modules.
language
string
Optional. ISO 639-1 code.
title
string
Optional. Override the title.
Permission: course_edit + license mcpAiAccess Example prompt: “Build a new-hire safety training based on these PDFs. 6 lessons, plain language, 10-question final quiz.” Backend: POST /api/v2/ai/courses/generate with { prompt, sessionId, options }

get_course_generation_status

Poll a queued generation job. Call every 3–5 seconds until status is completed (success — result.courseId is set) or failed (read error.message).
jobId
string
required
The jobId returned by create_course_from_prompt or create_course_from_files.
Permission: write scope (read-scope keys can’t enqueue a job they’re allowed to poll) Returns:
{
  "jobId": "ai-course-2381",
  "status": "queued" | "running" | "completed" | "failed" | "unknown",
  "progress": 0100,
  "result": { "courseId": 2419 },        // only when status="completed"
  "error":  { "message": "...", "attemptsMade": 1 } // only when status="failed"
}
Backend: GET /api/v2/ai/courses/generate/:jobId

AI course refinement

Three additional MCP tools that operate on courses you (or the agent) already generated. Same license tier as the generation tools (Business and Enterprise) and they share the same daily quota — 5 calls per key per day, 50 per tenant per day. Each call counts as one. The agent uses these three tools in addition to create_course_from_prompt / create_course_from_files to iterate on a course rather than starting fresh. Pick the narrowest tool for the user’s intent: regenerate_question for one bad question, regenerate_lesson to rethink a lesson’s brief, refine_course to add new structure to the whole course.

refine_course

Append new elements to an existing course. Append-only by design — this tool cannot delete or modify anything that already exists, only add. Use when the author says “add a section on X” or “add more practice” or “tack a survey at the end”.
courseId
integer
required
The course to extend. Get this from find_course or get_course.
feedback
string
required
Plain-English description of what to add. Examples: “Add a section on emergency procedures”, “Add two more practice quizzes after lesson 3”, “Add a final survey for course feedback”.
Permission: course_edit on the specific course (not just the role alias — the user must actually own / share / administer this course). Returns: { courseId, elementsAdded, transitionsAdded, message }. Example prompt: “For course 248, add a section on confined-space rescue procedures after the current safety lesson — 2 lessons + a quiz.” Backend: POST /api/v2/ai/courses/:courseId/refine with { feedback }

regenerate_question

Replace a single quiz question’s text and options. The new question stays on the same concept as the old one (we’re not drifting to a new subject — just rewriting). Previous content is preserved in your workspace audit log.
questionId
integer
required
The question to regenerate. Single-choice questions only.
feedback
string
Optional. What’s wrong with the current question and how to improve it. Examples: “Make it harder”, “The distractors are too obvious”, “Reword for clarity”. Omit for a generic “clearer version”.
Permission: course_edit on the parent course. Returns: { questionId, text, options, message } with the new question content. Example prompt: “Question #5821 in course 248 has confusing wording — make it clearer.” Backend: POST /api/v2/ai/questions/:questionId/regenerate with { feedback? }

regenerate_lesson

Regenerate the AI-authored brief that drives the lesson’s content. Safe by construction — this does NOT touch any pages the author has already created; it only updates the brief that the editor uses to bootstrap new content.
lessonId
integer
required
The lesson to regenerate the brief for.
feedback
string
Optional. What’s wrong with the current brief and how to improve it. Examples: “Add a section on the regulatory context”, “Reduce to 3 key points”, “Target supervisors, not learners”. Omit for a generic clarity pass.
Permission: course_edit on the parent course. Returns: { lessonId, brief } with the new brief content (topic, title, description, keyPoints, targetAudience). Example prompt: “Lesson 312’s brief is too theoretical — make it practical with concrete examples.” Backend: POST /api/v2/ai/lessons/:lessonId/regenerate with { feedback? }

Coming soon (not yet shipped)

extend_deadline + send_reminder (preview)

Push an assignment’s deadline back, or nudge overdue learners. Currently not shipped because no corresponding v2 backend endpoint exists.

Error handling

Every tool maps backend errors to LLM-readable strings:
Backend statusError shown to LLM
403”Permission denied — your user does not have rights for this action.”
404”Not found — check the ID exists.”
422”Invalid arguments:
429”Rate limit exceeded. Slow down and retry.”
OtherThe original error message
The MCP server automatically retries 429s up to 3 times with backoff per the Retry-After header. Network errors, 5xx, and connection resets are propagated as Error: ... for the LLM to surface to you.

Adding more tools

The tool catalog is intentionally focused — we ship what’s used, not what’s listable. If you’d find a specific tool valuable (e.g. “add to group”, “set custom attribute”, “trigger webhook”), the v2 REST API already exposes the endpoint; we just need to add a wrapper. Get in touch.