get_exam_history
View completed practice exam attempts with scores, pass/fail status, and per-domain breakdowns to compare progress across attempts for certification preparation.
Instructions
View all completed practice exam attempts with scores, pass/fail status, and per-domain breakdowns. Compare your progress across attempts.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- src/tools/get-exam-history.ts:7-83 (handler)The handler registration function for 'get_exam_history', which defines the tool and implements the logic to fetch and format exam history for the user.
export function registerGetExamHistory(server: McpServer, db: Database.Database, userConfig: UserConfig): void { server.tool( 'get_exam_history', 'View all completed practice exam attempts with scores, pass/fail status, and per-domain breakdowns. Compare your progress across attempts.', {}, async () => { const userId = userConfig.userId; ensureUser(db, userId); const history = getExamHistory(db, userId); if (history.length === 0) { return { content: [{ type: 'text' as const, text: [ '═══ EXAM HISTORY ═══', '', 'No completed practice exams yet.', '', 'Use start_practice_exam to take your first 60-question practice exam.', 'Questions are weighted by domain — just like the real exam.', ].join('\n'), }], }; } const lines: string[] = [ '═══ EXAM HISTORY ═══', '', `Total Attempts: ${history.length}`, `Best Score: ${Math.max(...history.map(h => h.score))}/1000`, `Latest Score: ${history[0].score}/1000`, '', ]; for (const [i, attempt] of history.entries()) { const label = i === 0 ? ' (latest)' : ''; lines.push(`─── Attempt #${history.length - i}${label} ───`); lines.push(` Date: ${attempt.completedAt ?? attempt.startedAt}`); lines.push(` Score: ${attempt.score}/1000 ${attempt.passed ? '✅ PASSED' : '❌ FAILED'}`); lines.push(` Correct: ${attempt.correctAnswers}/${attempt.totalQuestions} (${Math.round((attempt.correctAnswers / attempt.totalQuestions) * 100)}%)`); lines.push(''); lines.push(' Domain Scores:'); const scores = attempt.domainScores; for (const key of Object.keys(scores).sort()) { const ds = scores[key]; lines.push(` D${ds.domainId}: ${ds.domainTitle} — ${ds.correctAnswers}/${ds.totalQuestions} (${ds.accuracyPercent}%)`); } // Show improvement from previous attempt if (i < history.length - 1) { const previous = history[i + 1]; const diff = attempt.score - previous.score; const arrow = diff > 0 ? '↑' : diff < 0 ? '↓' : '→'; lines.push(''); lines.push(` Change from previous: ${arrow} ${diff > 0 ? '+' : ''}${diff} points`); } lines.push(''); } // Trend summary if (history.length >= 2) { const latest = history[0].score; const first = history[history.length - 1].score; const totalImprovement = latest - first; lines.push('─── Overall Trend ───'); lines.push(` First attempt: ${first}/1000`); lines.push(` Latest attempt: ${latest}/1000`); lines.push(` Total improvement: ${totalImprovement > 0 ? '+' : ''}${totalImprovement} points`); } return { content: [{ type: 'text' as const, text: lines.join('\n') }] }; } ); } - src/db/exam-attempts.ts:76-81 (helper)The database helper function that retrieves and maps the completed exam attempts for a specific user from the SQLite database.
export function getExamHistory(db: Database.Database, userId: string): readonly ExamAttempt[] { const rows = db.prepare( 'SELECT * FROM exam_attempts WHERE userId = ? AND completedAt IS NOT NULL ORDER BY completedAt DESC' ).all(userId) as Record<string, unknown>[]; return rows.map(rowToExamAttempt); }