A local-first CLI + MCP server for ITPEC exam practice with question bank, progress tracking, and spaced-repetition scheduling
Strong tool naming (verb_noun pattern throughout) and comprehensive descriptions (avg 180+ chars). All 11 tools have explicit schemas with typed parameters and descriptions. Good composition: tools are single-responsibility and chainable (e.g., get_next_question → submit_answer). Key gaps: no error handling guidance (tools don't explain recovery steps), no input validation constraints (enums, ranges), no output pagination despite tools returning lists (get_history, get_sessions, get_progress_summary). Missing tool annotations (readOnlyHint, destructiveHint). Descriptions are clear but could be more concise for LLM token efficiency.
Return readable metadata (name, date, duration, question count) for one exam plus the user's own progress on it — both accuracy (attempt-based) and coverage (distinct questions seen out of the exam's total).
List past attempts (newest first), so the AI can reference specific questions the user already answered.
Return the next practice question, filtered by topic/exam/mode. The question text, diagrams, and answer choices are ONLY in the image at imageUrl — nothing here contains the question itself. You must fetch/view that image yourself to know what's actually being asked before answering or discussing it. When you relay the question to the user, transcribe it as-is — don't reword, summarize, or paraphrase it unless the user explicitly asks you to. If the question has visuals that can't be reliably described in text, call open_question_image to show it to the user directly. Never includes the answer. The tool result also embeds the image directly (always in original/light colors, regardless of imageUrl's dark default) as a fallback for clients that can't fetch imageUrl.
Return accuracy/streak/review-queue plus per-part (AM/PM), per-topic, and per-exam breakdowns, so the AI can meaningfully reference progress in conversation. AM and PM are never blended into one accuracy/timing number since they test very different material. Per-exam rows carry both accuracy (attempt-based) and coverage (distinct questions seen out of the exam's total), and list every exam in scope, including untouched ones (pass startedExamsOnly to omit those).
No error handling guidance. Tools return errors but don't explain recovery steps (e.g., 'sessionID not found, call get_sessions() to list available sessions'). LLMs cannot self-correct without actionable error messages.
List tools (get_history, get_sessions, get_progress_summary) lack pagination parameters (limit, offset, cursor) and return-value documentation. Unbounded lists risk context window exhaustion and token waste.
No tool annotations (readOnlyHint, destructiveHint, idempotentHint). LLMs cannot distinguish safe reads from destructive writes without explicit hints. submit_answer and undo_last_answer should be marked destructive.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 59 | 2025-06-18+ | v2 |
Look up one specific question by exam id + question number, e.g. question 34 of 2025A_FE-A — the same examId+number get_next_question returns, so you can look a question back up later (re-fetch, toggle lightMode, or reveal the answer). The question text, diagrams, and answer choices are ONLY in the image at imageUrl — nothing here contains the question itself; fetch/view that image yourself before answering or discussing it. When you relay the question to the user, transcribe it as-is — don't reword, summarize, or paraphrase it unless the user explicitly asks you to. If the question has visuals that can't be reliably described in text, call open_question_image to show it to the user directly. Set revealAnswer=true to also return the correct answer (no canned explanation text — explain it yourself) — in which case the question isn't submittable, there's no sessionId, since a revealed answer isn't meant to be graded. The tool result also embeds the image directly (always in original/light colors, regardless of imageUrl's dark default) as a fallback for clients that can't fetch imageUrl.
List past practice sessions (newest first) with their score and completion status, so the AI can reference how a study run went (e.g. a timed mock exam that was completed vs interrupted), not just individual answers.
List all known fine-grained question tags, so the AI can offer tag filtering on get_next_question rather than guessing tag names.
List available topics (grouped by AM/PM exam session, since AM and PM topics are unrelated) and exam IDs, so the AI can offer filtering rather than guessing.
Display this question's image, with its answer options, to the user directly, exactly as it is. Call this when the question has visuals — diagrams, charts, tables, code — that can't be reliably described in text alone.
Submit the user's stated answer letter for grading. Grading happens server-side; the AI is a conduit for the user's stated answer, not the judge of correctness — never invoke this with a letter the AI chose, guessed, or inferred instead of asking the user. If the user hasn't given an answer, or says they don't know, pass "idk" rather than guessing for them. Returns correct/correctAnswer/topic, no canned explanation — explain why yourself using your own knowledge of the topic.
Delete the most recently recorded attempt, undoing its grading. Use only when the user explicitly asks to undo/retract/redo their last answer — e.g. they mis-stated it or it was submitted by mistake.
Parameter constraints missing. 'mode' in get_next_question accepts 'normal' or 'sequential' but no enum constraint. 'order' in get_history accepts 'newest' or 'oldest' but no enum. Free-form strings invite hallucinated values.
Output schemas not documented in code. While tools return structured data (correct, correctAnswer, topic, etc.), the response schema is not formally declared. LLMs must infer field types from examples.