Get My Grades
get_my_gradesRetrieve your grade breakdown for a specific course or all enrolled courses, showing points, percentages, and comments for each grade item.
Instructions
Fetch your grade breakdown for a specific course or all enrolled courses. Shows grade items with points, percentages, and comments. Use this when the user asks about grades, scores, marks, GPA, academic performance, or how they're doing in a class.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| courseId | No | Course ID to get grades for. If omitted, returns grades for all enrolled courses. |
Implementation Reference
- src/tools/get-my-grades.ts:55-178 (handler)The main handler function `registerGetMyGrades` that registers the 'get_my_grades' tool on the MCP server. It handles two cases: fetching grades for a single course (by courseId) or fetching grades for all enrolled courses. It calls the Brightspace API endpoint /grades/values/myGradeValues and returns grade items with points, percentages, and comments.
export function registerGetMyGrades( server: McpServer, apiClient: D2LApiClient, config: AppConfig ): void { server.registerTool( "get_my_grades", { title: "Get My Grades", description: "Fetch your grade breakdown for a specific course or all enrolled courses. Shows grade items with points, percentages, and comments. Use this when the user asks about grades, scores, marks, GPA, academic performance, or how they're doing in a class.", inputSchema: GetMyGradesSchema, }, async (args: any) => { try { log("DEBUG", "get_my_grades tool called", { args }); // Parse and validate input const { courseId } = GetMyGradesSchema.parse(args); // Single course case if (courseId) { const path = apiClient.le(courseId, "/grades/values/myGradeValues/"); const gradeValues = await apiClient.get<GradeValue[]>(path, { ttl: DEFAULT_CACHE_TTLS.grades, }); // Map to clean objects const grades = gradeValues.map((gv) => ({ name: gv.GradeObjectName, displayGrade: gv.DisplayedGrade, pointsNumerator: gv.PointsNumerator, pointsDenominator: gv.PointsDenominator, weightedNumerator: gv.WeightedNumerator, weightedDenominator: gv.WeightedDenominator, comments: gv.Comments?.Text || null, lastModified: gv.LastModified, })); log("INFO", `get_my_grades: Retrieved ${grades.length} grade items for course ${courseId}`); return toolResponse({ courseId, grades }); } // All courses case // First, fetch enrolled courses const enrollmentPath = apiClient.lp( "/enrollments/myenrollments/?orgUnitTypeId=3&isActive=true" ); const enrollmentResponse = await apiClient.get<EnrollmentResponse>( enrollmentPath, { ttl: DEFAULT_CACHE_TTLS.enrollments } ); // Apply course filter const filteredEnrollments = applyCourseFilter( enrollmentResponse.Items.map(item => ({ id: item.OrgUnit.Id, name: item.OrgUnit.Name, code: item.OrgUnit.Code, isActive: item.Access.IsActive, ...item, })), config.courseFilter ); // Fetch grades for each course (handle 403s gracefully) const gradePromises = filteredEnrollments.map(async (item) => { try { const path = apiClient.le( item.OrgUnit.Id, "/grades/values/myGradeValues/" ); const gradeValues = await apiClient.get<GradeValue[]>(path, { ttl: DEFAULT_CACHE_TTLS.grades, }); const grades = gradeValues.map((gv) => ({ name: gv.GradeObjectName, displayGrade: gv.DisplayedGrade, pointsNumerator: gv.PointsNumerator, pointsDenominator: gv.PointsDenominator, weightedNumerator: gv.WeightedNumerator, weightedDenominator: gv.WeightedDenominator, comments: gv.Comments?.Text || null, lastModified: gv.LastModified, })); return { courseId: item.OrgUnit.Id, courseName: item.OrgUnit.Name, grades, }; } catch (error: any) { // 403 means no access (past course, etc) - log and skip if (error?.status === 403) { log( "DEBUG", `get_my_grades: 403 Forbidden for course ${item.OrgUnit.Id} (${item.OrgUnit.Name}) - skipping` ); return null; } throw error; // Re-throw other errors } }); const results = await Promise.allSettled(gradePromises); const courses = results .filter( (r): r is PromiseFulfilledResult<any> => r.status === "fulfilled" && r.value !== null ) .map((r) => r.value); log( "INFO", `get_my_grades: Retrieved grades for ${courses.length} courses (out of ${enrollmentResponse.Items.length} enrolled)` ); return toolResponse({ courses }); } catch (error) { return sanitizeError(error); } } ); } - src/tools/schemas.ts:24-26 (schema)Zod schema `GetMyGradesSchema` defining the input for the tool: an optional `courseId` (coerced positive integer). If omitted, grades are returned for all enrolled courses.
export const GetMyGradesSchema = z.object({ courseId: z.coerce.number().int().positive().optional().describe("Course ID to get grades for. If omitted, returns grades for all enrolled courses."), }); - src/index.ts:181-181 (registration)Registration call in the main server entry point where `registerGetMyGrades` is invoked with the server, API client, and config.
registerGetMyGrades(server, apiClient, config); - src/tools/index.ts:10-10 (registration)Barrel export re-exporting `registerGetMyGrades` from the get-my-grades module.
export { registerGetMyGrades } from "./get-my-grades.js";