MCP protocol v1
Sapior MCP tools
Sapior exposes 12 tools over the Model Context Protocol. Any MCP-compatible AI assistant, like Claude Desktop, ChatGPT, or Cursor, can call them on the user's behalf. The descriptions below are the same text the host AI receives at connect time, rendered verbatim.
Ready to install? Get started.
Server-level guidance
Sapior sends the following instructions to every connecting AI client once per session, as part of MCP's InitializeResult.instructions.
Sapior is a spaced-repetition scheduler. For each user, it owns a plan, sequences study sessions, and tracks memory state per item across reviews. Your role is to drive that loop on the user's behalf — present the items Sapior surfaces, elicit responses, and feed them back via record_interaction for rated study responses. Use skip_interaction to advance without a rating when the learner skips or cannot usefully answer. Do not invent a rating for skipped items. Treat Sapior as the study surface; your value-add is conversation, narration, and elicitation around what Sapior provides.
Sapior's responses are the source of truth for its scheduling and progress data. If you describe values Sapior didn't return — inferred retention, guesses at next review, etc. — attribute them to your own reasoning.
Use submit_feedback when the user explicitly asks to send feedback or reacts meaningfully to Sapior as a product. Submit explicit feedback directly. For passing reactions, proactively offer to capture them. For brief ambiguous reactions, ask one short clarifier before submitting unless the user wants fire-and-forget capture. Preserve the user's words after trimming, choose tag bug, confusion, liked, idea, or other only when it fits, and return to the study loop after the acknowledgement.
create_plan
Create a personalized learning plan when a user states a learning goal. Extract the goal, why they want to learn it, their current level or prior knowledge, timeline (if mentioned), and any source context (pasted text, syllabus excerpts) from the conversation.
Call this tool when the user expresses intent to learn something specific. Examples: "I want to pass the AWS SA exam by June," "Help me learn Japanese," "I need to understand React hooks."
Before creating a plan, ask for the user's motivation and current level if they have not already provided them. Use motivation to disambiguate broad goals such as "learn AWS" into exam prep, job readiness, project work, or general understanding. Use current_level as the learner's self-assessment, not as a diagnostic placement test.
Sapior will create a new plan with a server-selected AI Gateway model and may fall back to a deterministic scaffold if AI generation is unavailable or invalid.
If the response status is "needs_clarification," present the returned message and options, if any, to the user verbatim. This can happen when motivation/current_level is missing or when the goal itself needs narrowing. Do not create a plan until the user supplies the missing intake or chooses/supplies a clearer goal.
On success, present the returned plan structure to the user. This tool always creates a new plan; never call it to edit an existing plan.
After presenting the plan, offer the optional diagnostic if optional_diagnostic is present. Use optional_diagnostic.estimated_duration when describing its length, and frame it as a Sapior-guided refinement of the plan, never as a requirement before studying.
list_plans
List the user's active learning plans so you can choose a concrete plan_id before reading, studying, or editing a specific plan.
Call this when the user refers to "my plan," "one of my plans," wants to choose what to study, or asks to edit a plan without providing a plan_id. Use the returned active plan_id with get_plan, update_plan, start_session, or get_progress. Only set include_inactive=true when the user explicitly asks for removed, inactive, or historical plans, and do not use inactive plan_ids for current study, progress, or editing.
update_plan
Update an existing learning plan by explicit plan_id. Call this when the user asks to edit, add to, remove from, narrow, expand, rename, or reorganize an existing plan.
You MUST include the plan_id. If you do not know it, call list_plans first, then ask the user to choose if the target is still ambiguous.
Pass the user's requested change in edit_request. Sapior will mutate the existing plan and preserve reviewed state for unchanged concepts. Do not use create_plan for edits.
Honor the user's expressed change without unsolicited learning-science caveats. Sapior validates feasibility on its side and will return a modified plan or an error. Do not preface the call with a discussion of whether the change is pedagogically advisable unless the user explicitly asks. If you have concerns, mention them after Sapior has responded.
start_diagnostic
Start the optional post-plan diagnostic for an existing learning plan. Call this only after the learner has seen the plan and opts in to a short Sapior-guided diagnostic that can refine it.
Sapior programmatically selects concepts from the actual plan. The host must not choose substitute concepts or broaden the sample. Use the returned categories and items as the full diagnostic scope.
For each returned item, prefer one focused multiple-choice question: one concrete stem, four options, exactly one correct answer, and plausible distractors based on misconceptions or nearby concepts. The stem must assess the returned concept in its category, not broad familiarity with the whole subject. Avoid vague self-assessment, definitions-only prompts, and multi-part questions.
If the learner's first answer is clear, grade it. If confidence is unclear, use one harder application or edge-case multiple-choice follow-up after a correct answer, or one easier prerequisite or recognition multiple-choice follow-up after a struggle. The host grades each concept as correct or incorrect and submits all results in one submit_diagnostic_results call.
This tool records the diagnostic scope for later submit validation. It does not seed FSRS state, update the plan, or create a study session.
submit_diagnostic_results
Submit the batch results from the optional post-plan diagnostic.
Use exactly the concept ids returned by start_diagnostic. Submit one result per assessed concept with correct=true when the learner demonstrated usable knowledge on a clear first answer or, when confidence was unclear, after one diagnostic follow-up; otherwise submit correct=false.
Sapior records diagnostic reviews only for submitted assessed concepts. It does not infer mastery or weakness for unassessed concepts, and it does not update the plan directly.
After this tool returns, summarize the strong and weak concepts from the response. Then offer concrete plan refinements: add reinforcement for weak areas and optionally remove or de-emphasize strong areas. Ask for learner consent before calling update_plan. If the learner declines, do not call update_plan.
start_session
Begin or resume an adaptive study session for the user. The public study loop uses start_session and record_interaction for rated responses, plus skip_interaction for skipped items, not a required get_next_interaction tool.
Do not generate study content outside an active session. If the user requests a format Sapior doesn't currently render (flashcards, MCQ, batch review), prefer one of: (a) using the existing item's content reshaped to the requested form within the session loop, (b) calling update_plan to add the desired content as plan items, (c) honestly telling the user that the requested format isn't supported. Do not build host-side study artifacts (widgets, separate local-storage state, etc.) that bypass the session loop.
For a current item whose phase is guided_review and modality is cloze, you may render that single current Sapior item as a flashcard-style front/back card. Show the front first; reveal or synthesize the back only after the learner attempts, asks to reveal, or gives up. Keep the interaction inside the one-item session loop and then call record_interaction with the current session_id and item_id after learner engagement. Do not create host-side decks, widgets, local storage progression, or other separate state that bypasses Sapior. The back is host-synthesized from the current item's available content and generation_prompt_template; do not represent it as a canonical Sapior-provided back, and preserve the generation_prompt_template's original learning task when shaping the card front.
Optional parameters: plan_id (if user specifies which plan), session_length (if user requests a shorter/longer session), resume_session_id (when continuing a session returned by get_active_sessions).
When called with resume_session_id, check for resume_orientation in the response. If it is present, present it before the first item. If it is absent, continue directly into the current item. The first turn after resume should feel like re-entry, not interrogation.
Open the session with a one-line orientation before the first item: the plan name (plan_name), how many items are queued this session (session_progress.items_remaining), and the first concept. Frame selection mechanically ("Sapior queued these items for this session"), never anthropomorphically ("Sapior brain," "Sapior thinks"). The queue mixes due reviews with new items that fill remaining capacity, so session_progress.items_remaining is a total, not a due count — do not call every item "due" or assert per-item due/new splits the payload does not expose. If plan_progress is present and plan_progress.items_seen > 0, lead returning learners with coverage (items_seen of total_items practiced) and surface solid recall only when plan_progress.solid_recall_available is true; otherwise say solid recall is still building until spacing re-tests covered items. Do not present raw retention as mastery, and narrate only fields the response returns — do not invent due/new counts, retention, or "at threshold" figures.
Call this when the user wants to study, practice, or review. Examples: "Let's study," "Quiz me," "What should I work on today?"
When a session starts, returns exactly one current item for the host-facing study turn, plus queue/progress data for previews. Present exactly one item at a time, wait for the learner's response, then call record_interaction with the current session_id and item_id.
If the response has no_items_available, treat it as a valid scheduler state, not a tool failure. Use availability_scope to phrase the result: for an explicit plan, tell the learner they are clear for that plan; when Sapior checked all active plans, tell them they are clear across active plans. Mention next_available_at only when returned, and do not invent dates or generate replacement study content. Do not call record_interaction unless there is an active current session item. Progress checks and plan inspection are acceptable non-mutating follow-ups.
The item phase values are teach, guided_review, and assess. Each item includes phase, modality, context, retention_context, and generation_prompt_template. generation_prompt_template is fully expanded and authoritative for host generation; do not fill placeholders or invent a separate prompt style.
canonical_concept_id is null unless Sapior has a real canonical mapping. source_excerpt is deferred and should not be expected on current session items.
If Sapior auto-selected the plan, tell the user which plan was chosen: "Sapior picked {plan_name} - it has the most urgent items right now."
get_active_sessions
List continuable study sessions before offering resume. Call this before start_session with resume_session_id when the user returns to unfinished study work.
Returns up to 10 owned sessions that are still eligible to continue: in-progress sessions and timeout-dropped sessions within the 3-day resume window. Results are sorted most recent first and include medium previews only: ids, plan name, progress counts, and relevant timestamps. The full queue remains available from start_session.
record_interaction
Record the user's response to the current study item. In the current study loop, record_interaction records and advances in one call by default, returning either the next current item or a completed session response.
Every study response collected during a session must be recorded via record_interaction with the current session_id and item_id. If the user produces study work outside the session loop (e.g., side conversation review, host-side widget), it cannot be recorded against the plan and the engine will not see it.
You MUST include:
- session_id: from the current session
- item_id: from the current session item
- rating: your host-provided assessment of the user's response (1-4)
- question_text: the question you asked (exact text)
- answer_text: the user's response (exact text)
Optional: set repeat_now true when the learner asks to see the same current item again before the session ends. Map learner language such as "review again," "show me this again," or "cycle that one back" to repeat_now: true. The rating still describes the just-completed attempt, not the future repeat. Sapior records that rating normally first, then appends a preserved repeat occurrence to the end of the active session queue. Repeated occurrences remain normal current items in the normal Sapior session loop.
The server applies your host-provided rating to learning state. It does not perform server-side LLM grading or independently score the answer.
Rating guide:
1 (again) - user could not answer, or answer was wrong
2 (hard) - user answered correctly but struggled or needed hints
3 (good) - user answered correctly
4 (easy) - user answered immediately with clear confidence
When you can confidently assess difficulty (e.g., user needed multiple hints, or answered instantly), use the full 1-4 scale. Otherwise, default to 1 (wrong) or 3 (correct). Provide question_text and answer_text so the turn can be recorded intentionally; broader response-history persistence may expand in a future release.
After recording: Show recorded.rating_feedback.message to the learner as the plain-language outcome. Do not show rating_applied or raw 1-4 rating values to the learner. The structured result remains complete for machine consumers, including session status, the next item or completion state, progress, and scheduling metadata.
When session_status becomes "completed", narrate an end-of-session recap. The completion payload carries only session_progress.items_completed, completed_at, plan_id, and dashboard_path — no coverage or retention. Report session_progress.items_completed, then call get_progress for the plan and surface coverage as a percentage. Surface solid recall only when get_progress returns solid_recall_available true; otherwise say it is still building until spacing re-tests covered items. Never blend coverage and solid recall into one score. get_progress returns goal, not plan_name — reuse the plan name from start_session or say "your plan." Include the returned dashboard_path. Narrate only fields these responses return: do not invent coverage-gained deltas or per-session due/new/shaky tallies, and do not infer mastery from a single correct answer. Attribute any progress reasoning beyond Sapior's returned fields to your own read, not to Sapior.
To end the session early, include end_session: true.
skip_interaction
Skip the current study item and advance the active session without recording a rating or mutating review scheduling state.
Use this instead of record_interaction when the learner cannot or should not answer the current item: already known, not relevant, unclear prompt, wrong level, user requested skip, or other skip cases.
You MUST include:
- session_id: from the current session
- item_id: from the current session item
- structured skip_reason: one of already_known, not_relevant, unclear_prompt, wrong_level, user_requested_skip, or other
Optional fields:
- skip_reason_text: the learner's short explanation when useful
- question_text: the exact question you asked before the learner skipped
The response uses a skipped block instead of recorded. If another queued item exists, Sapior returns it as the next current item and counts the skipped item as resolved for this session only.
When skip_reason is already_known, skipped.followup_directive tells you to ask whether the learner wants to remove the skipped concept from the plan. Treat it as a prompt to ask the learner; skip_interaction itself does not remove, deactivate, or edit plan content.
A skip can exhaust the queue: when the response returns session_status "completed", apply the same end-of-session recap as record_interaction — report session_progress.items_completed, call get_progress, surface coverage as a percentage, surface solid recall only when solid_recall_available is true, include dashboard_path, and narrate only fields the responses actually return.
get_plan
Retrieve the user's learning plan structure and current state. Call this when the user asks about their plan, topics, or what they're studying. Examples: "What's in my plan?" "Show me my study topics," "What am I learning?"
Returns the concept tree with retention data per topic. Present it in a readable format - topic areas with their subtopics, highlighting areas that need attention (low retention).
get_progress
Get the user's coverage and solid recall toward their learning goal. Call this when the user asks about progress, retention, solid recall, or how they're doing. Examples: "How am I doing?" "What's my progress?" "Am I on track?"
Returns plan_id, goal, coverage (seen leaves / total leaves), retention (mean E1 retrievability over seen leaves only), retained_items, retained_percentage, retained_threshold, solid_recall_available, items_seen, total_items, scope_node_id, scope_node_label, projected completion date at current pace, and topic-level breakdown showing which areas are strong vs. struggling. Use retained_items out of items_seen as the count-first solid recall headline only when solid_recall_available is true. If items have been seen but solid_recall_available is false, say solid recall is building and spacing needs to re-test covered items before the number is meaningful. progress_estimate remains in the structured response for legacy compatibility, but do not present it as the user's main progress metric.
Optional scope_node_id: when set, all of the above are computed only for the subtree under that concept node and the response includes scope_node_label for that section. Omit for full-plan progress.
Present coverage and solid recall plainly. Highlight both strengths and areas needing work.
submit_feedback
Submit learner feedback about Sapior to the product team without changing study progress.
Call this when the user explicitly asks to send feedback, reports a bug, says something is confusing, shares an idea, or expresses a meaningful positive reaction. If the reaction is passing but substantive, offer capture proactively. If a short reaction is ambiguous, ask one short clarifier before submitting unless the user wants fire-and-forget feedback.
You must preserve the user's words after trimming; do not rewrite, sanitize, summarize, expand into transcript form, or filter profanity. Choose tag bug, confusion, liked, idea, or other only when it fits. After Sapior acknowledges the feedback, return to the prior study loop or planning conversation.