@mtgibbs/canvas-lms-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +539 -0
- package/esm/_dnt.shims.d.ts +6 -0
- package/esm/_dnt.shims.d.ts.map +1 -0
- package/esm/_dnt.shims.js +61 -0
- package/esm/agent.d.ts +10 -0
- package/esm/agent.d.ts.map +1 -0
- package/esm/agent.js +17 -0
- package/esm/cli.js +6 -0
- package/esm/package.json +3 -0
- package/esm/src/api/assignments.d.ts +40 -0
- package/esm/src/api/assignments.d.ts.map +1 -0
- package/esm/src/api/assignments.js +133 -0
- package/esm/src/api/client.d.ts +61 -0
- package/esm/src/api/client.d.ts.map +1 -0
- package/esm/src/api/client.js +179 -0
- package/esm/src/api/courses.d.ts +32 -0
- package/esm/src/api/courses.d.ts.map +1 -0
- package/esm/src/api/courses.js +85 -0
- package/esm/src/api/stats.d.ts +15 -0
- package/esm/src/api/stats.d.ts.map +1 -0
- package/esm/src/api/stats.js +58 -0
- package/esm/src/api/submissions.d.ts +33 -0
- package/esm/src/api/submissions.d.ts.map +1 -0
- package/esm/src/api/submissions.js +103 -0
- package/esm/src/api/users.d.ts +87 -0
- package/esm/src/api/users.d.ts.map +1 -0
- package/esm/src/api/users.js +139 -0
- package/esm/src/mcp/prompts/course-analysis.d.ts +7 -0
- package/esm/src/mcp/prompts/course-analysis.d.ts.map +1 -0
- package/esm/src/mcp/prompts/course-analysis.js +36 -0
- package/esm/src/mcp/prompts/daily-checkin.d.ts +7 -0
- package/esm/src/mcp/prompts/daily-checkin.d.ts.map +1 -0
- package/esm/src/mcp/prompts/daily-checkin.js +31 -0
- package/esm/src/mcp/prompts/grade-recovery.d.ts +7 -0
- package/esm/src/mcp/prompts/grade-recovery.d.ts.map +1 -0
- package/esm/src/mcp/prompts/grade-recovery.js +35 -0
- package/esm/src/mcp/prompts/index.d.ts +15 -0
- package/esm/src/mcp/prompts/index.d.ts.map +1 -0
- package/esm/src/mcp/prompts/index.js +20 -0
- package/esm/src/mcp/prompts/missing-work-audit.d.ts +7 -0
- package/esm/src/mcp/prompts/missing-work-audit.d.ts.map +1 -0
- package/esm/src/mcp/prompts/missing-work-audit.js +36 -0
- package/esm/src/mcp/prompts/week-planning.d.ts +7 -0
- package/esm/src/mcp/prompts/week-planning.d.ts.map +1 -0
- package/esm/src/mcp/prompts/week-planning.js +34 -0
- package/esm/src/mcp/server.d.ts +15 -0
- package/esm/src/mcp/server.d.ts.map +1 -0
- package/esm/src/mcp/server.js +51 -0
- package/esm/src/mcp/tools/get-courses.d.ts +11 -0
- package/esm/src/mcp/tools/get-courses.d.ts.map +1 -0
- package/esm/src/mcp/tools/get-courses.js +29 -0
- package/esm/src/mcp/tools/get-due-this-week.d.ts +13 -0
- package/esm/src/mcp/tools/get-due-this-week.d.ts.map +1 -0
- package/esm/src/mcp/tools/get-due-this-week.js +75 -0
- package/esm/src/mcp/tools/get-missing-assignments.d.ts +12 -0
- package/esm/src/mcp/tools/get-missing-assignments.d.ts.map +1 -0
- package/esm/src/mcp/tools/get-missing-assignments.js +33 -0
- package/esm/src/mcp/tools/get-stats.d.ts +12 -0
- package/esm/src/mcp/tools/get-stats.d.ts.map +1 -0
- package/esm/src/mcp/tools/get-stats.js +28 -0
- package/esm/src/mcp/tools/get-todo.d.ts +13 -0
- package/esm/src/mcp/tools/get-todo.d.ts.map +1 -0
- package/esm/src/mcp/tools/get-todo.js +55 -0
- package/esm/src/mcp/tools/get-unsubmitted-past-due.d.ts +12 -0
- package/esm/src/mcp/tools/get-unsubmitted-past-due.d.ts.map +1 -0
- package/esm/src/mcp/tools/get-unsubmitted-past-due.js +64 -0
- package/esm/src/mcp/tools/get-upcoming-assignments.d.ts +12 -0
- package/esm/src/mcp/tools/get-upcoming-assignments.d.ts.map +1 -0
- package/esm/src/mcp/tools/get-upcoming-assignments.js +29 -0
- package/esm/src/mcp/tools/index.d.ts +18 -0
- package/esm/src/mcp/tools/index.d.ts.map +1 -0
- package/esm/src/mcp/tools/index.js +26 -0
- package/esm/src/mcp/tools/list-assignments.d.ts +13 -0
- package/esm/src/mcp/tools/list-assignments.d.ts.map +1 -0
- package/esm/src/mcp/tools/list-assignments.js +40 -0
- package/esm/src/mcp/types.d.ts +83 -0
- package/esm/src/mcp/types.d.ts.map +1 -0
- package/esm/src/mcp/types.js +20 -0
- package/esm/src/types/canvas.d.ts +288 -0
- package/esm/src/types/canvas.d.ts.map +1 -0
- package/esm/src/types/canvas.js +5 -0
- package/esm/src/utils/config.d.ts +19 -0
- package/esm/src/utils/config.d.ts.map +1 -0
- package/esm/src/utils/config.js +54 -0
- package/esm/src/utils/init.d.ts +9 -0
- package/esm/src/utils/init.d.ts.map +1 -0
- package/esm/src/utils/init.js +20 -0
- package/manifest.json +91 -0
- package/package.json +49 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canvas Submissions API
|
|
3
|
+
*/
|
|
4
|
+
import { getClient } from "./client.js";
|
|
5
|
+
/**
|
|
6
|
+
* List submissions for a course (all students or specific students)
|
|
7
|
+
*/
|
|
8
|
+
export async function listSubmissions(options) {
|
|
9
|
+
const client = getClient();
|
|
10
|
+
const { course_id, ...rest } = options;
|
|
11
|
+
const params = {};
|
|
12
|
+
if (rest.assignment_ids?.length) {
|
|
13
|
+
params.assignment_ids = rest.assignment_ids.map(String);
|
|
14
|
+
}
|
|
15
|
+
if (rest.student_ids) {
|
|
16
|
+
params.student_ids = rest.student_ids === "all" ? "all" : rest.student_ids.map(String);
|
|
17
|
+
}
|
|
18
|
+
if (rest.grouped !== undefined) {
|
|
19
|
+
params.grouped = rest.grouped ? "true" : "false";
|
|
20
|
+
}
|
|
21
|
+
if (rest.include) {
|
|
22
|
+
params.include = rest.include;
|
|
23
|
+
}
|
|
24
|
+
if (rest.workflow_state) {
|
|
25
|
+
params.workflow_state = rest.workflow_state;
|
|
26
|
+
}
|
|
27
|
+
return client.getAll(`/courses/${course_id}/students/submissions`, params);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Get submission for a specific assignment and user
|
|
31
|
+
*/
|
|
32
|
+
export async function getSubmission(courseId, assignmentId, userId, include) {
|
|
33
|
+
const client = getClient();
|
|
34
|
+
const params = {};
|
|
35
|
+
if (include) {
|
|
36
|
+
params.include = include;
|
|
37
|
+
}
|
|
38
|
+
return client.get(`/courses/${courseId}/assignments/${assignmentId}/submissions/${userId}`, params);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* List all submissions for a specific user in a course
|
|
42
|
+
*/
|
|
43
|
+
export async function listUserSubmissions(courseId, userId, options) {
|
|
44
|
+
return listSubmissions({
|
|
45
|
+
course_id: courseId,
|
|
46
|
+
student_ids: [Number(userId)],
|
|
47
|
+
include: options?.include || ["assignment"],
|
|
48
|
+
workflow_state: options?.workflowState,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* List graded submissions for a user
|
|
53
|
+
*/
|
|
54
|
+
export async function listGradedSubmissions(courseId, userId) {
|
|
55
|
+
const submissions = await listUserSubmissions(courseId, userId, {
|
|
56
|
+
include: ["assignment"],
|
|
57
|
+
});
|
|
58
|
+
return submissions.filter((sub) => sub.workflow_state === "graded" && sub.grade !== null);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* List submissions with grades below a threshold
|
|
62
|
+
*/
|
|
63
|
+
export async function listSubmissionsBelowThreshold(courseId, userId, threshold) {
|
|
64
|
+
const submissions = await listGradedSubmissions(courseId, userId);
|
|
65
|
+
return submissions.filter((sub) => {
|
|
66
|
+
if (sub.score === null || sub.score === undefined)
|
|
67
|
+
return false;
|
|
68
|
+
const assignment = sub.assignment;
|
|
69
|
+
if (!assignment?.points_possible)
|
|
70
|
+
return false;
|
|
71
|
+
const percentage = (sub.score / assignment.points_possible) * 100;
|
|
72
|
+
return percentage < threshold;
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* List unsubmitted past-due assignments for a student
|
|
77
|
+
* Uses the submissions endpoint to get the student's actual submission status
|
|
78
|
+
*/
|
|
79
|
+
export async function listUnsubmittedPastDueForStudent(courseId, studentId) {
|
|
80
|
+
const submissions = await listUserSubmissions(courseId, studentId, {
|
|
81
|
+
include: ["assignment"],
|
|
82
|
+
});
|
|
83
|
+
const now = new Date();
|
|
84
|
+
return submissions.filter((sub) => {
|
|
85
|
+
// Must have an assignment with a due date
|
|
86
|
+
const assignment = sub.assignment;
|
|
87
|
+
if (!assignment?.due_at)
|
|
88
|
+
return false;
|
|
89
|
+
// Due date must be in the past
|
|
90
|
+
const dueDate = new Date(assignment.due_at);
|
|
91
|
+
if (dueDate >= now)
|
|
92
|
+
return false;
|
|
93
|
+
// Must not be submitted AND not graded
|
|
94
|
+
// Some assignments (on_paper, etc.) may have a grade but no submitted_at
|
|
95
|
+
if (sub.submitted_at)
|
|
96
|
+
return false;
|
|
97
|
+
if (sub.score !== null && sub.score !== undefined)
|
|
98
|
+
return false;
|
|
99
|
+
if (sub.grade !== null && sub.grade !== undefined)
|
|
100
|
+
return false;
|
|
101
|
+
return true;
|
|
102
|
+
});
|
|
103
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canvas Users API
|
|
3
|
+
* Includes missing submissions, upcoming events, etc.
|
|
4
|
+
*/
|
|
5
|
+
import type { MissingSubmission, UpcomingEvent, Submission, PlannerItem } from "../types/canvas.js";
|
|
6
|
+
/**
|
|
7
|
+
* Options for getMissingSubmissions
|
|
8
|
+
*/
|
|
9
|
+
export interface GetMissingOptions {
|
|
10
|
+
/** Student ID - use the numeric ID for observed students, or "self" for current user */
|
|
11
|
+
studentId?: string | number;
|
|
12
|
+
/** Filter to specific course IDs */
|
|
13
|
+
courseIds?: number[];
|
|
14
|
+
/** Include related data */
|
|
15
|
+
include?: Array<"planner_overrides" | "course">;
|
|
16
|
+
/** Filter options */
|
|
17
|
+
filter?: Array<"submittable" | "current_grading_period">;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Get missing submissions for a student
|
|
21
|
+
*
|
|
22
|
+
* For observers (parents): pass the student's numeric ID as studentId
|
|
23
|
+
* For students: pass "self" or omit studentId
|
|
24
|
+
*
|
|
25
|
+
* Note: The Canvas API requires the student ID in the URL path for observers.
|
|
26
|
+
* The observed_user_id parameter does NOT work for this endpoint.
|
|
27
|
+
*/
|
|
28
|
+
export declare function getMissingSubmissions(options?: GetMissingOptions): Promise<MissingSubmission[]>;
|
|
29
|
+
/**
|
|
30
|
+
* Get upcoming events for a user (assignments and calendar events)
|
|
31
|
+
*/
|
|
32
|
+
export declare function getUpcomingEvents(userId?: string | number): Promise<UpcomingEvent[]>;
|
|
33
|
+
/**
|
|
34
|
+
* Get todo items for a user (assignments needing submission)
|
|
35
|
+
*/
|
|
36
|
+
export declare function getTodoItems(userId?: string | number): Promise<Array<{
|
|
37
|
+
assignment: MissingSubmission;
|
|
38
|
+
context_name: string;
|
|
39
|
+
}>>;
|
|
40
|
+
/**
|
|
41
|
+
* Get recently graded submissions for a user
|
|
42
|
+
*/
|
|
43
|
+
export declare function getGradedSubmissions(userId?: string | number, options?: {
|
|
44
|
+
onlyPublished?: boolean;
|
|
45
|
+
}): Promise<Submission[]>;
|
|
46
|
+
/**
|
|
47
|
+
* Get missing submissions grouped by course
|
|
48
|
+
*/
|
|
49
|
+
export declare function getMissingSubmissionsByCourse(options?: GetMissingOptions): Promise<Map<number, MissingSubmission[]>>;
|
|
50
|
+
/**
|
|
51
|
+
* Get count of missing submissions per course
|
|
52
|
+
*/
|
|
53
|
+
export declare function getMissingCountsByCourse(options?: GetMissingOptions): Promise<Map<number, {
|
|
54
|
+
courseName: string;
|
|
55
|
+
count: number;
|
|
56
|
+
}>>;
|
|
57
|
+
/**
|
|
58
|
+
* Get observed students (for parent/observer accounts)
|
|
59
|
+
* Returns the list of users that the current user is observing
|
|
60
|
+
*/
|
|
61
|
+
export declare function getObservedStudents(userId?: string | number): Promise<import("../types/canvas.js").User[]>;
|
|
62
|
+
/**
|
|
63
|
+
* Options for getPlannerItems
|
|
64
|
+
*/
|
|
65
|
+
export interface GetPlannerOptions {
|
|
66
|
+
/** Student ID - required for observer accounts */
|
|
67
|
+
studentId?: string | number;
|
|
68
|
+
/** Start date (ISO 8601 or yyyy-mm-dd) */
|
|
69
|
+
startDate?: string;
|
|
70
|
+
/** End date (ISO 8601 or yyyy-mm-dd) */
|
|
71
|
+
endDate?: string;
|
|
72
|
+
/** Filter to specific course IDs */
|
|
73
|
+
courseIds?: number[];
|
|
74
|
+
/** Filter for new_activity only */
|
|
75
|
+
filter?: "new_activity";
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Get planner items (to-do list) for a student
|
|
79
|
+
*
|
|
80
|
+
* For observers (parents): pass the student's numeric ID as studentId
|
|
81
|
+
* For students: pass "self" or omit studentId
|
|
82
|
+
*
|
|
83
|
+
* Note: For observers, this endpoint requires context_codes. We automatically
|
|
84
|
+
* fetch active courses and include them as context_codes.
|
|
85
|
+
*/
|
|
86
|
+
export declare function getPlannerItems(options?: GetPlannerOptions): Promise<PlannerItem[]>;
|
|
87
|
+
//# sourceMappingURL=users.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../../src/src/api/users.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EACV,iBAAiB,EACjB,aAAa,EACb,UAAU,EACV,WAAW,EACZ,MAAM,oBAAoB,CAAC;AAG5B;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,wFAAwF;IACxF,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,oCAAoC;IACpC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,2BAA2B;IAC3B,OAAO,CAAC,EAAE,KAAK,CAAC,mBAAmB,GAAG,QAAQ,CAAC,CAAC;IAChD,qBAAqB;IACrB,MAAM,CAAC,EAAE,KAAK,CAAC,aAAa,GAAG,wBAAwB,CAAC,CAAC;CAC1D;AAED;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAiB9B;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,GAAE,MAAM,GAAG,MAAe,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAGlG;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,MAAM,GAAE,MAAM,GAAG,MAAe,GAC/B,OAAO,CAAC,KAAK,CAAC;IAAE,UAAU,EAAE,iBAAiB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CAKzE;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,GAAE,MAAM,GAAG,MAAe,EAChC,OAAO,CAAC,EAAE;IACR,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,GACA,OAAO,CAAC,UAAU,EAAE,CAAC,CASvB;AAED;;GAEG;AACH,wBAAsB,6BAA6B,CACjD,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC,CAAC,CAiB3C;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CAmB7D;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,GAAE,MAAM,GAAG,MAAe,GAC/B,OAAO,CAAC,OAAO,oBAAoB,EAAE,IAAI,EAAE,CAAC,CAG9C;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oCAAoC;IACpC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,mCAAmC;IACnC,MAAM,CAAC,EAAE,cAAc,CAAC;CACzB;AAED;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CACnC,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,WAAW,EAAE,CAAC,CAmCxB"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canvas Users API
|
|
3
|
+
* Includes missing submissions, upcoming events, etc.
|
|
4
|
+
*/
|
|
5
|
+
import { getClient } from "./client.js";
|
|
6
|
+
import { listCourses } from "./courses.js";
|
|
7
|
+
/**
|
|
8
|
+
* Get missing submissions for a student
|
|
9
|
+
*
|
|
10
|
+
* For observers (parents): pass the student's numeric ID as studentId
|
|
11
|
+
* For students: pass "self" or omit studentId
|
|
12
|
+
*
|
|
13
|
+
* Note: The Canvas API requires the student ID in the URL path for observers.
|
|
14
|
+
* The observed_user_id parameter does NOT work for this endpoint.
|
|
15
|
+
*/
|
|
16
|
+
export async function getMissingSubmissions(options) {
|
|
17
|
+
const client = getClient();
|
|
18
|
+
const studentId = options?.studentId ?? "self";
|
|
19
|
+
const params = {};
|
|
20
|
+
if (options?.courseIds?.length) {
|
|
21
|
+
params.course_ids = options.courseIds.map(String);
|
|
22
|
+
}
|
|
23
|
+
if (options?.include) {
|
|
24
|
+
params.include = options.include;
|
|
25
|
+
}
|
|
26
|
+
if (options?.filter) {
|
|
27
|
+
params.filter = options.filter;
|
|
28
|
+
}
|
|
29
|
+
return client.getAll(`/users/${studentId}/missing_submissions`, params);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Get upcoming events for a user (assignments and calendar events)
|
|
33
|
+
*/
|
|
34
|
+
export async function getUpcomingEvents(userId = "self") {
|
|
35
|
+
const client = getClient();
|
|
36
|
+
return client.getAll(`/users/${userId}/upcoming_events`);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Get todo items for a user (assignments needing submission)
|
|
40
|
+
*/
|
|
41
|
+
export async function getTodoItems(userId = "self") {
|
|
42
|
+
const client = getClient();
|
|
43
|
+
return client.getAll(`/users/${userId}/todo`);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Get recently graded submissions for a user
|
|
47
|
+
*/
|
|
48
|
+
export async function getGradedSubmissions(userId = "self", options) {
|
|
49
|
+
const client = getClient();
|
|
50
|
+
const params = {};
|
|
51
|
+
if (options?.onlyPublished) {
|
|
52
|
+
params.only_published_assignments = "true";
|
|
53
|
+
}
|
|
54
|
+
return client.getAll(`/users/${userId}/graded_submissions`, params);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Get missing submissions grouped by course
|
|
58
|
+
*/
|
|
59
|
+
export async function getMissingSubmissionsByCourse(options) {
|
|
60
|
+
const missing = await getMissingSubmissions({
|
|
61
|
+
...options,
|
|
62
|
+
include: ["course"],
|
|
63
|
+
});
|
|
64
|
+
const byCourse = new Map();
|
|
65
|
+
for (const submission of missing) {
|
|
66
|
+
const courseId = submission.course_id;
|
|
67
|
+
if (!byCourse.has(courseId)) {
|
|
68
|
+
byCourse.set(courseId, []);
|
|
69
|
+
}
|
|
70
|
+
byCourse.get(courseId).push(submission);
|
|
71
|
+
}
|
|
72
|
+
return byCourse;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Get count of missing submissions per course
|
|
76
|
+
*/
|
|
77
|
+
export async function getMissingCountsByCourse(options) {
|
|
78
|
+
const missing = await getMissingSubmissions({
|
|
79
|
+
...options,
|
|
80
|
+
include: ["course"],
|
|
81
|
+
});
|
|
82
|
+
const counts = new Map();
|
|
83
|
+
for (const submission of missing) {
|
|
84
|
+
const courseId = submission.course_id;
|
|
85
|
+
const courseName = submission.course?.name || `Course ${courseId}`;
|
|
86
|
+
if (!counts.has(courseId)) {
|
|
87
|
+
counts.set(courseId, { courseName, count: 0 });
|
|
88
|
+
}
|
|
89
|
+
counts.get(courseId).count++;
|
|
90
|
+
}
|
|
91
|
+
return counts;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Get observed students (for parent/observer accounts)
|
|
95
|
+
* Returns the list of users that the current user is observing
|
|
96
|
+
*/
|
|
97
|
+
export async function getObservedStudents(userId = "self") {
|
|
98
|
+
const client = getClient();
|
|
99
|
+
return client.getAll(`/users/${userId}/observees`);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Get planner items (to-do list) for a student
|
|
103
|
+
*
|
|
104
|
+
* For observers (parents): pass the student's numeric ID as studentId
|
|
105
|
+
* For students: pass "self" or omit studentId
|
|
106
|
+
*
|
|
107
|
+
* Note: For observers, this endpoint requires context_codes. We automatically
|
|
108
|
+
* fetch active courses and include them as context_codes.
|
|
109
|
+
*/
|
|
110
|
+
export async function getPlannerItems(options) {
|
|
111
|
+
const client = getClient();
|
|
112
|
+
const studentId = options?.studentId;
|
|
113
|
+
const params = {};
|
|
114
|
+
// For observers, we need context_codes with the observed_user_id
|
|
115
|
+
if (studentId && studentId !== "self") {
|
|
116
|
+
params.observed_user_id = String(studentId);
|
|
117
|
+
// Get active courses to build context_codes
|
|
118
|
+
let courseIds = options?.courseIds;
|
|
119
|
+
if (!courseIds?.length) {
|
|
120
|
+
const courses = await listCourses({
|
|
121
|
+
enrollment_state: "active",
|
|
122
|
+
state: ["available"],
|
|
123
|
+
});
|
|
124
|
+
courseIds = courses.map((c) => c.id);
|
|
125
|
+
}
|
|
126
|
+
// Build context_codes array (client adds [] automatically)
|
|
127
|
+
params.context_codes = courseIds.map((id) => `course_${id}`);
|
|
128
|
+
}
|
|
129
|
+
if (options?.startDate) {
|
|
130
|
+
params.start_date = options.startDate;
|
|
131
|
+
}
|
|
132
|
+
if (options?.endDate) {
|
|
133
|
+
params.end_date = options.endDate;
|
|
134
|
+
}
|
|
135
|
+
if (options?.filter) {
|
|
136
|
+
params.filter = options.filter;
|
|
137
|
+
}
|
|
138
|
+
return client.getAll("/planner/items", params);
|
|
139
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt: course-analysis
|
|
3
|
+
* Detailed analysis of a specific course - grades, missing work, and patterns
|
|
4
|
+
*/
|
|
5
|
+
import type { PromptDefinition } from "../types.js";
|
|
6
|
+
export declare const courseAnalysisPrompt: PromptDefinition;
|
|
7
|
+
//# sourceMappingURL=course-analysis.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"course-analysis.d.ts","sourceRoot":"","sources":["../../../../src/src/mcp/prompts/course-analysis.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,eAAO,MAAM,oBAAoB,EAAE,gBA+BlC,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt: course-analysis
|
|
3
|
+
* Detailed analysis of a specific course - grades, missing work, and patterns
|
|
4
|
+
*/
|
|
5
|
+
export const courseAnalysisPrompt = {
|
|
6
|
+
name: "course-analysis",
|
|
7
|
+
description: "Detailed analysis of a specific course - grades, missing work, and patterns",
|
|
8
|
+
arguments: [
|
|
9
|
+
{ name: "student_id", description: "Student ID", required: true },
|
|
10
|
+
{ name: "course_id", description: "Course ID to analyze", required: true },
|
|
11
|
+
],
|
|
12
|
+
handler: ({ student_id, course_id }) => ({
|
|
13
|
+
messages: [
|
|
14
|
+
{
|
|
15
|
+
role: "user",
|
|
16
|
+
content: {
|
|
17
|
+
type: "text",
|
|
18
|
+
text: `Analyze course ${course_id} in detail for student ${student_id}:
|
|
19
|
+
|
|
20
|
+
1. Get the current grade using get_courses
|
|
21
|
+
2. List all assignments using list_assignments with the course_id
|
|
22
|
+
3. Check for missing work in this course using get_missing_assignments with course_id filter
|
|
23
|
+
4. Get upcoming assignments using get_upcoming_assignments
|
|
24
|
+
|
|
25
|
+
Provide:
|
|
26
|
+
- Current grade and standing in the class
|
|
27
|
+
- Assignment completion rate (submitted vs total)
|
|
28
|
+
- Any patterns (consistently late? missing certain types of work?)
|
|
29
|
+
- Impact of missing assignments on the grade
|
|
30
|
+
- What would improve the grade most (quick wins)
|
|
31
|
+
- Upcoming work to watch out for`,
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
}),
|
|
36
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt: daily-checkin
|
|
3
|
+
* Get a quick daily overview of grades, missing work, and upcoming assignments
|
|
4
|
+
*/
|
|
5
|
+
import type { PromptDefinition } from "../types.js";
|
|
6
|
+
export declare const dailyCheckinPrompt: PromptDefinition;
|
|
7
|
+
//# sourceMappingURL=daily-checkin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daily-checkin.d.ts","sourceRoot":"","sources":["../../../../src/src/mcp/prompts/daily-checkin.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,eAAO,MAAM,kBAAkB,EAAE,gBA0BhC,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt: daily-checkin
|
|
3
|
+
* Get a quick daily overview of grades, missing work, and upcoming assignments
|
|
4
|
+
*/
|
|
5
|
+
export const dailyCheckinPrompt = {
|
|
6
|
+
name: "daily-checkin",
|
|
7
|
+
description: "Get a quick daily overview of grades, missing work, and upcoming assignments",
|
|
8
|
+
arguments: [{ name: "student_id", description: "Student ID", required: true }],
|
|
9
|
+
handler: ({ student_id }) => ({
|
|
10
|
+
messages: [
|
|
11
|
+
{
|
|
12
|
+
role: "user",
|
|
13
|
+
content: {
|
|
14
|
+
type: "text",
|
|
15
|
+
text: `Please give me a daily check-in for student ${student_id}:
|
|
16
|
+
|
|
17
|
+
1. First, get their current grades across all courses using get_courses
|
|
18
|
+
2. Then check for any missing assignments using get_missing_assignments
|
|
19
|
+
3. Check for unsubmitted past-due work using get_unsubmitted_past_due
|
|
20
|
+
4. Finally, show what's due in the next 7 days using get_due_this_week
|
|
21
|
+
|
|
22
|
+
Summarize with:
|
|
23
|
+
- Overall grade status (any concerns?)
|
|
24
|
+
- Missing/late work that needs immediate attention
|
|
25
|
+
- What's coming up this week
|
|
26
|
+
- A prioritized action list if there are issues to address`,
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
}),
|
|
31
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grade-recovery.d.ts","sourceRoot":"","sources":["../../../../src/src/mcp/prompts/grade-recovery.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,eAAO,MAAM,mBAAmB,EAAE,gBA8BjC,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt: grade-recovery
|
|
3
|
+
* Identify opportunities to improve grades across all courses
|
|
4
|
+
*/
|
|
5
|
+
export const gradeRecoveryPrompt = {
|
|
6
|
+
name: "grade-recovery",
|
|
7
|
+
description: "Identify opportunities to improve grades across all courses",
|
|
8
|
+
arguments: [{ name: "student_id", description: "Student ID", required: true }],
|
|
9
|
+
handler: ({ student_id }) => ({
|
|
10
|
+
messages: [
|
|
11
|
+
{
|
|
12
|
+
role: "user",
|
|
13
|
+
content: {
|
|
14
|
+
type: "text",
|
|
15
|
+
text: `Help identify grade recovery opportunities for student ${student_id}:
|
|
16
|
+
|
|
17
|
+
1. Get current grades using get_courses
|
|
18
|
+
2. Get statistics on late/missing work using get_stats
|
|
19
|
+
3. Find all missing assignments using get_missing_assignments
|
|
20
|
+
|
|
21
|
+
For each course, especially those below a B:
|
|
22
|
+
- Calculate the impact of missing assignments on the grade
|
|
23
|
+
- Identify which missing work could potentially still be submitted
|
|
24
|
+
- Prioritize by: points possible, likelihood of acceptance, and effort required
|
|
25
|
+
- Estimate potential grade improvement if completed
|
|
26
|
+
|
|
27
|
+
Create an action plan:
|
|
28
|
+
- Quick wins (high points, low effort)
|
|
29
|
+
- Important recovery items (high impact on grade)
|
|
30
|
+
- Long shots (may not be accepted but worth asking)`,
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
}),
|
|
35
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt registry - exports all MCP prompts
|
|
3
|
+
*/
|
|
4
|
+
import { dailyCheckinPrompt } from "./daily-checkin.js";
|
|
5
|
+
import { weekPlanningPrompt } from "./week-planning.js";
|
|
6
|
+
import { courseAnalysisPrompt } from "./course-analysis.js";
|
|
7
|
+
import { gradeRecoveryPrompt } from "./grade-recovery.js";
|
|
8
|
+
import { missingWorkAuditPrompt } from "./missing-work-audit.js";
|
|
9
|
+
import type { PromptDefinition } from "../types.js";
|
|
10
|
+
/**
|
|
11
|
+
* All available MCP prompts
|
|
12
|
+
*/
|
|
13
|
+
export declare const prompts: PromptDefinition[];
|
|
14
|
+
export { dailyCheckinPrompt, weekPlanningPrompt, courseAnalysisPrompt, gradeRecoveryPrompt, missingWorkAuditPrompt, };
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/mcp/prompts/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD;;GAEG;AACH,eAAO,MAAM,OAAO,EAAE,gBAAgB,EAMrC,CAAC;AAGF,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,EACpB,mBAAmB,EACnB,sBAAsB,GACvB,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt registry - exports all MCP prompts
|
|
3
|
+
*/
|
|
4
|
+
import { dailyCheckinPrompt } from "./daily-checkin.js";
|
|
5
|
+
import { weekPlanningPrompt } from "./week-planning.js";
|
|
6
|
+
import { courseAnalysisPrompt } from "./course-analysis.js";
|
|
7
|
+
import { gradeRecoveryPrompt } from "./grade-recovery.js";
|
|
8
|
+
import { missingWorkAuditPrompt } from "./missing-work-audit.js";
|
|
9
|
+
/**
|
|
10
|
+
* All available MCP prompts
|
|
11
|
+
*/
|
|
12
|
+
export const prompts = [
|
|
13
|
+
dailyCheckinPrompt,
|
|
14
|
+
weekPlanningPrompt,
|
|
15
|
+
courseAnalysisPrompt,
|
|
16
|
+
gradeRecoveryPrompt,
|
|
17
|
+
missingWorkAuditPrompt,
|
|
18
|
+
];
|
|
19
|
+
// Re-export individual prompts for direct access if needed
|
|
20
|
+
export { dailyCheckinPrompt, weekPlanningPrompt, courseAnalysisPrompt, gradeRecoveryPrompt, missingWorkAuditPrompt, };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"missing-work-audit.d.ts","sourceRoot":"","sources":["../../../../src/src/mcp/prompts/missing-work-audit.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,eAAO,MAAM,sBAAsB,EAAE,gBA+BpC,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt: missing-work-audit
|
|
3
|
+
* Comprehensive audit of all missing and late work
|
|
4
|
+
*/
|
|
5
|
+
export const missingWorkAuditPrompt = {
|
|
6
|
+
name: "missing-work-audit",
|
|
7
|
+
description: "Comprehensive audit of all missing and late work",
|
|
8
|
+
arguments: [{ name: "student_id", description: "Student ID", required: true }],
|
|
9
|
+
handler: ({ student_id }) => ({
|
|
10
|
+
messages: [
|
|
11
|
+
{
|
|
12
|
+
role: "user",
|
|
13
|
+
content: {
|
|
14
|
+
type: "text",
|
|
15
|
+
text: `Perform a comprehensive audit of missing work for student ${student_id}:
|
|
16
|
+
|
|
17
|
+
1. Get all Canvas-flagged missing assignments using get_missing_assignments
|
|
18
|
+
2. Get unsubmitted past-due work using get_unsubmitted_past_due (catches items Canvas missed)
|
|
19
|
+
3. Get late/missing statistics by course using get_stats
|
|
20
|
+
|
|
21
|
+
Create a report showing:
|
|
22
|
+
- Total missing assignments across all courses
|
|
23
|
+
- Breakdown by course (which classes have the most issues?)
|
|
24
|
+
- Oldest missing assignments (how far back does this go?)
|
|
25
|
+
- Total points at risk
|
|
26
|
+
- Courses with the highest missing percentage
|
|
27
|
+
|
|
28
|
+
Flag any concerning patterns:
|
|
29
|
+
- Specific courses with many missing items
|
|
30
|
+
- Recent spike in missing work
|
|
31
|
+
- High-point assignments that are missing`,
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
}),
|
|
36
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt: week-planning
|
|
3
|
+
* Plan the upcoming week with assignment priorities and daily breakdown
|
|
4
|
+
*/
|
|
5
|
+
import type { PromptDefinition } from "../types.js";
|
|
6
|
+
export declare const weekPlanningPrompt: PromptDefinition;
|
|
7
|
+
//# sourceMappingURL=week-planning.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"week-planning.d.ts","sourceRoot":"","sources":["../../../../src/src/mcp/prompts/week-planning.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,eAAO,MAAM,kBAAkB,EAAE,gBA6BhC,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt: week-planning
|
|
3
|
+
* Plan the upcoming week with assignment priorities and daily breakdown
|
|
4
|
+
*/
|
|
5
|
+
export const weekPlanningPrompt = {
|
|
6
|
+
name: "week-planning",
|
|
7
|
+
description: "Plan the upcoming week with assignment priorities and daily breakdown",
|
|
8
|
+
arguments: [
|
|
9
|
+
{ name: "student_id", description: "Student ID", required: true },
|
|
10
|
+
{ name: "days", description: "Days to look ahead (default: 7)", required: false },
|
|
11
|
+
],
|
|
12
|
+
handler: ({ student_id, days }) => ({
|
|
13
|
+
messages: [
|
|
14
|
+
{
|
|
15
|
+
role: "user",
|
|
16
|
+
content: {
|
|
17
|
+
type: "text",
|
|
18
|
+
text: `Help me plan the week for student ${student_id}:
|
|
19
|
+
|
|
20
|
+
1. Get assignments due in the next ${days || 7} days using get_due_this_week
|
|
21
|
+
2. Check the to-do list using get_todo
|
|
22
|
+
3. Look for any missing work that should be prioritized using get_missing_assignments
|
|
23
|
+
|
|
24
|
+
Create a day-by-day plan that:
|
|
25
|
+
- Prioritizes past-due work first (these should be done ASAP)
|
|
26
|
+
- Spreads out upcoming assignments reasonably
|
|
27
|
+
- Flags any heavy days with multiple deadlines
|
|
28
|
+
- Suggests what to work on each day
|
|
29
|
+
- Notes any assignments worth a lot of points`,
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
}),
|
|
34
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
/**
|
|
3
|
+
* Create and configure the MCP server with all tools and prompts
|
|
4
|
+
*/
|
|
5
|
+
export declare function createServer(): McpServer;
|
|
6
|
+
/**
|
|
7
|
+
* Get server metadata
|
|
8
|
+
*/
|
|
9
|
+
export declare function getServerInfo(): {
|
|
10
|
+
name: string;
|
|
11
|
+
version: string;
|
|
12
|
+
tools: string[];
|
|
13
|
+
prompts: string[];
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/src/mcp/server.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAapE;;GAEG;AACH,wBAAgB,YAAY,IAAI,SAAS,CAqBxC;AAED;;GAEG;AACH,wBAAgB,aAAa;;;;;EAO5B"}
|