@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,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Server setup and configuration
|
|
3
|
+
* Registers all tools and prompts with the server
|
|
4
|
+
*/
|
|
5
|
+
import * as dntShim from "../../_dnt.shims.js";
|
|
6
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
7
|
+
import { tools } from "./tools/index.js";
|
|
8
|
+
import { prompts } from "./prompts/index.js";
|
|
9
|
+
// Read version from deno.json if available
|
|
10
|
+
let version = "1.0.0";
|
|
11
|
+
try {
|
|
12
|
+
const denoJson = JSON.parse(await dntShim.Deno.readTextFile("./deno.json"));
|
|
13
|
+
version = denoJson.version || version;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
// Use default version if deno.json not found
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Create and configure the MCP server with all tools and prompts
|
|
20
|
+
*/
|
|
21
|
+
export function createServer() {
|
|
22
|
+
const server = new McpServer({
|
|
23
|
+
name: "canvas-lms-mcp",
|
|
24
|
+
version,
|
|
25
|
+
});
|
|
26
|
+
// Register all tools with annotations
|
|
27
|
+
for (const tool of tools) {
|
|
28
|
+
if (tool.annotations) {
|
|
29
|
+
server.tool(tool.name, tool.description, tool.schema, tool.annotations, tool.handler);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
server.tool(tool.name, tool.description, tool.schema, tool.handler);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// Register all prompts
|
|
36
|
+
for (const prompt of prompts) {
|
|
37
|
+
server.prompt(prompt.name, prompt.description, prompt.arguments, prompt.handler);
|
|
38
|
+
}
|
|
39
|
+
return server;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Get server metadata
|
|
43
|
+
*/
|
|
44
|
+
export function getServerInfo() {
|
|
45
|
+
return {
|
|
46
|
+
name: "canvas-lms-mcp",
|
|
47
|
+
version,
|
|
48
|
+
tools: tools.map((t) => t.name),
|
|
49
|
+
prompts: prompts.map((p) => p.name),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: get_courses
|
|
3
|
+
* List all active courses and current grades for the student
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { type ToolDefinition } from "../types.js";
|
|
7
|
+
export declare const schema: {
|
|
8
|
+
student_id: z.ZodOptional<z.ZodString>;
|
|
9
|
+
};
|
|
10
|
+
export declare const getCoursesTool: ToolDefinition<typeof schema>;
|
|
11
|
+
//# sourceMappingURL=get-courses.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-courses.d.ts","sourceRoot":"","sources":["../../../../src/src/mcp/tools/get-courses.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAEhE,eAAO,MAAM,MAAM;;CAElB,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,cAAc,CAAC,OAAO,MAAM,CAoBxD,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: get_courses
|
|
3
|
+
* List all active courses and current grades for the student
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { listCoursesWithGrades } from "../../api/courses.js";
|
|
7
|
+
import { jsonResponse } from "../types.js";
|
|
8
|
+
export const schema = {
|
|
9
|
+
student_id: z.string().optional().describe("Student ID (default: 'self')"),
|
|
10
|
+
};
|
|
11
|
+
export const getCoursesTool = {
|
|
12
|
+
name: "get_courses",
|
|
13
|
+
description: "List all active courses and current grades for the student",
|
|
14
|
+
schema,
|
|
15
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
16
|
+
handler: async ({ student_id }) => {
|
|
17
|
+
const courses = await listCoursesWithGrades(student_id || "self");
|
|
18
|
+
const simplified = courses.map((c) => ({
|
|
19
|
+
id: c.id,
|
|
20
|
+
name: c.name,
|
|
21
|
+
code: c.course_code,
|
|
22
|
+
current_grade: c.enrollment?.grades?.current_grade,
|
|
23
|
+
current_score: c.enrollment?.grades?.current_score,
|
|
24
|
+
final_grade: c.enrollment?.grades?.final_grade,
|
|
25
|
+
final_score: c.enrollment?.grades?.final_score,
|
|
26
|
+
}));
|
|
27
|
+
return jsonResponse(simplified);
|
|
28
|
+
},
|
|
29
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: get_due_this_week
|
|
3
|
+
* Get all assignments due in the next N days across ALL courses
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { type ToolDefinition } from "../types.js";
|
|
7
|
+
export declare const schema: {
|
|
8
|
+
student_id: z.ZodString;
|
|
9
|
+
days: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
10
|
+
hide_graded: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
11
|
+
};
|
|
12
|
+
export declare const getDueThisWeekTool: ToolDefinition<typeof schema>;
|
|
13
|
+
//# sourceMappingURL=get-due-this-week.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-due-this-week.d.ts","sourceRoot":"","sources":["../../../../src/src/mcp/tools/get-due-this-week.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAEhE,eAAO,MAAM,MAAM;;;;CAQlB,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,cAAc,CAAC,OAAO,MAAM,CA2E5D,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: get_due_this_week
|
|
3
|
+
* Get all assignments due in the next N days across ALL courses
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { listCourses } from "../../api/courses.js";
|
|
7
|
+
import { listSubmissions } from "../../api/submissions.js";
|
|
8
|
+
import { jsonResponse } from "../types.js";
|
|
9
|
+
export const schema = {
|
|
10
|
+
student_id: z.string().describe("Student ID"),
|
|
11
|
+
days: z.number().optional().default(7).describe("Number of days to look ahead (default: 7)"),
|
|
12
|
+
hide_graded: z
|
|
13
|
+
.boolean()
|
|
14
|
+
.optional()
|
|
15
|
+
.default(true)
|
|
16
|
+
.describe("Hide assignments that have already been graded (default: true)"),
|
|
17
|
+
};
|
|
18
|
+
export const getDueThisWeekTool = {
|
|
19
|
+
name: "get_due_this_week",
|
|
20
|
+
description: "Get all assignments due in the next N days across ALL courses for a student, with submission status",
|
|
21
|
+
schema,
|
|
22
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
23
|
+
handler: async ({ student_id, days, hide_graded }) => {
|
|
24
|
+
// Get all active courses
|
|
25
|
+
const courses = await listCourses({
|
|
26
|
+
enrollment_state: "active",
|
|
27
|
+
state: ["available"],
|
|
28
|
+
});
|
|
29
|
+
const now = new Date();
|
|
30
|
+
const endDate = new Date(now);
|
|
31
|
+
endDate.setDate(now.getDate() + days);
|
|
32
|
+
const results = [];
|
|
33
|
+
for (const course of courses) {
|
|
34
|
+
try {
|
|
35
|
+
// Get student's submissions with assignment data
|
|
36
|
+
const submissions = await listSubmissions({
|
|
37
|
+
course_id: course.id,
|
|
38
|
+
student_ids: [Number(student_id)],
|
|
39
|
+
include: ["assignment"],
|
|
40
|
+
});
|
|
41
|
+
for (const sub of submissions) {
|
|
42
|
+
const assignment = sub.assignment;
|
|
43
|
+
if (!assignment?.due_at)
|
|
44
|
+
continue;
|
|
45
|
+
const dueDate = new Date(assignment.due_at);
|
|
46
|
+
if (dueDate < now || dueDate > endDate)
|
|
47
|
+
continue;
|
|
48
|
+
results.push({
|
|
49
|
+
course_id: course.id,
|
|
50
|
+
course_name: course.name,
|
|
51
|
+
assignment_id: assignment.id,
|
|
52
|
+
assignment_name: assignment.name,
|
|
53
|
+
due_at: assignment.due_at,
|
|
54
|
+
points_possible: assignment.points_possible,
|
|
55
|
+
submitted: !!sub.submitted_at,
|
|
56
|
+
score: sub.score,
|
|
57
|
+
grade: sub.grade,
|
|
58
|
+
url: assignment.html_url,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// Skip courses we can't access
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// Filter out graded items if requested
|
|
67
|
+
let filteredResults = results;
|
|
68
|
+
if (hide_graded) {
|
|
69
|
+
filteredResults = results.filter((r) => r.score === null);
|
|
70
|
+
}
|
|
71
|
+
// Sort by due date
|
|
72
|
+
filteredResults.sort((a, b) => new Date(a.due_at).getTime() - new Date(b.due_at).getTime());
|
|
73
|
+
return jsonResponse(filteredResults);
|
|
74
|
+
},
|
|
75
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: get_missing_assignments
|
|
3
|
+
* Get missing assignments for a student (Canvas-flagged as missing)
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { type ToolDefinition } from "../types.js";
|
|
7
|
+
export declare const schema: {
|
|
8
|
+
student_id: z.ZodOptional<z.ZodString>;
|
|
9
|
+
course_id: z.ZodOptional<z.ZodNumber>;
|
|
10
|
+
};
|
|
11
|
+
export declare const getMissingAssignmentsTool: ToolDefinition<typeof schema>;
|
|
12
|
+
//# sourceMappingURL=get-missing-assignments.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-missing-assignments.d.ts","sourceRoot":"","sources":["../../../../src/src/mcp/tools/get-missing-assignments.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAEhE,eAAO,MAAM,MAAM;;;CAGlB,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,cAAc,CAAC,OAAO,MAAM,CAuBnE,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: get_missing_assignments
|
|
3
|
+
* Get missing assignments for a student (Canvas-flagged as missing)
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { getMissingSubmissions } from "../../api/users.js";
|
|
7
|
+
import { jsonResponse } from "../types.js";
|
|
8
|
+
export const schema = {
|
|
9
|
+
student_id: z.string().optional().describe("Student ID (default: 'self')"),
|
|
10
|
+
course_id: z.number().optional().describe("Filter by specific course ID"),
|
|
11
|
+
};
|
|
12
|
+
export const getMissingAssignmentsTool = {
|
|
13
|
+
name: "get_missing_assignments",
|
|
14
|
+
description: "Get missing assignments for a student (Canvas-flagged as missing)",
|
|
15
|
+
schema,
|
|
16
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
17
|
+
handler: async ({ student_id, course_id }) => {
|
|
18
|
+
const missing = await getMissingSubmissions({
|
|
19
|
+
studentId: student_id || "self",
|
|
20
|
+
courseIds: course_id ? [course_id] : undefined,
|
|
21
|
+
include: ["course"],
|
|
22
|
+
});
|
|
23
|
+
const simplified = missing.map((m) => ({
|
|
24
|
+
id: m.id,
|
|
25
|
+
name: m.name,
|
|
26
|
+
course: m.course?.name,
|
|
27
|
+
due_at: m.due_at,
|
|
28
|
+
points_possible: m.points_possible,
|
|
29
|
+
url: m.html_url,
|
|
30
|
+
}));
|
|
31
|
+
return jsonResponse(simplified);
|
|
32
|
+
},
|
|
33
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: get_stats
|
|
3
|
+
* Get late and missing assignment statistics by course
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { type ToolDefinition } from "../types.js";
|
|
7
|
+
export declare const schema: {
|
|
8
|
+
student_id: z.ZodString;
|
|
9
|
+
hide_empty: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
10
|
+
};
|
|
11
|
+
export declare const getStatsTool: ToolDefinition<typeof schema>;
|
|
12
|
+
//# sourceMappingURL=get-stats.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-stats.d.ts","sourceRoot":"","sources":["../../../../src/src/mcp/tools/get-stats.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAEhE,eAAO,MAAM,MAAM;;;CAOlB,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,cAAc,CAAC,OAAO,MAAM,CAetD,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: get_stats
|
|
3
|
+
* Get late and missing assignment statistics by course
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { getStudentStats } from "../../api/stats.js";
|
|
7
|
+
import { jsonResponse } from "../types.js";
|
|
8
|
+
export const schema = {
|
|
9
|
+
student_id: z.string().describe("Student ID"),
|
|
10
|
+
hide_empty: z
|
|
11
|
+
.boolean()
|
|
12
|
+
.optional()
|
|
13
|
+
.default(true)
|
|
14
|
+
.describe("Hide courses with no assignments (default: true)"),
|
|
15
|
+
};
|
|
16
|
+
export const getStatsTool = {
|
|
17
|
+
name: "get_stats",
|
|
18
|
+
description: "Get late and missing assignment statistics by course, showing percentages to identify problem areas",
|
|
19
|
+
schema,
|
|
20
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
21
|
+
handler: async ({ student_id, hide_empty }) => {
|
|
22
|
+
let stats = await getStudentStats(student_id);
|
|
23
|
+
if (hide_empty) {
|
|
24
|
+
stats = stats.filter((s) => s.total > 0);
|
|
25
|
+
}
|
|
26
|
+
return jsonResponse(stats);
|
|
27
|
+
},
|
|
28
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: get_todo
|
|
3
|
+
* Get the student's to-do list (planner items)
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { type ToolDefinition } from "../types.js";
|
|
7
|
+
export declare const schema: {
|
|
8
|
+
student_id: z.ZodString;
|
|
9
|
+
days: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
10
|
+
hide_submitted: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
11
|
+
};
|
|
12
|
+
export declare const getTodoTool: ToolDefinition<typeof schema>;
|
|
13
|
+
//# sourceMappingURL=get-todo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-todo.d.ts","sourceRoot":"","sources":["../../../../src/src/mcp/tools/get-todo.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAEhE,eAAO,MAAM,MAAM;;;;CAQlB,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,cAAc,CAAC,OAAO,MAAM,CA4CrD,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: get_todo
|
|
3
|
+
* Get the student's to-do list (planner items)
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { getPlannerItems } from "../../api/users.js";
|
|
7
|
+
import { jsonResponse } from "../types.js";
|
|
8
|
+
export const schema = {
|
|
9
|
+
student_id: z.string().describe("Student ID"),
|
|
10
|
+
days: z.number().optional().default(7).describe("Number of days to look ahead (default: 7)"),
|
|
11
|
+
hide_submitted: z
|
|
12
|
+
.boolean()
|
|
13
|
+
.optional()
|
|
14
|
+
.default(false)
|
|
15
|
+
.describe("Hide items that have been submitted"),
|
|
16
|
+
};
|
|
17
|
+
export const getTodoTool = {
|
|
18
|
+
name: "get_todo",
|
|
19
|
+
description: "Get the student's to-do list (planner items) showing upcoming assignments, quizzes, and tasks",
|
|
20
|
+
schema,
|
|
21
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
22
|
+
handler: async ({ student_id, days, hide_submitted }) => {
|
|
23
|
+
const startDate = new Date().toISOString().split("T")[0];
|
|
24
|
+
const endDate = new Date();
|
|
25
|
+
endDate.setDate(endDate.getDate() + days);
|
|
26
|
+
const endDateStr = endDate.toISOString().split("T")[0];
|
|
27
|
+
const items = await getPlannerItems({
|
|
28
|
+
studentId: student_id,
|
|
29
|
+
startDate,
|
|
30
|
+
endDate: endDateStr,
|
|
31
|
+
});
|
|
32
|
+
// Filter out submitted items if requested
|
|
33
|
+
let filteredItems = items;
|
|
34
|
+
if (hide_submitted) {
|
|
35
|
+
filteredItems = items.filter((item) => !item.submissions?.submitted);
|
|
36
|
+
}
|
|
37
|
+
// Sort by due date
|
|
38
|
+
filteredItems.sort((a, b) => {
|
|
39
|
+
return new Date(a.plannable_date).getTime() - new Date(b.plannable_date).getTime();
|
|
40
|
+
});
|
|
41
|
+
// Simplify for LLM output
|
|
42
|
+
const simplified = filteredItems.map((item) => ({
|
|
43
|
+
course_name: item.context_name,
|
|
44
|
+
title: item.plannable.title,
|
|
45
|
+
type: item.plannable_type,
|
|
46
|
+
due_at: item.plannable_date,
|
|
47
|
+
points_possible: item.plannable.points_possible,
|
|
48
|
+
submitted: item.submissions?.submitted || false,
|
|
49
|
+
missing: item.submissions?.missing || false,
|
|
50
|
+
graded: item.submissions?.graded || false,
|
|
51
|
+
url: item.html_url,
|
|
52
|
+
}));
|
|
53
|
+
return jsonResponse(simplified);
|
|
54
|
+
},
|
|
55
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: get_unsubmitted_past_due
|
|
3
|
+
* Get assignments that are past due but not submitted
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { type ToolDefinition } from "../types.js";
|
|
7
|
+
export declare const schema: {
|
|
8
|
+
student_id: z.ZodString;
|
|
9
|
+
course_id: z.ZodOptional<z.ZodNumber>;
|
|
10
|
+
};
|
|
11
|
+
export declare const getUnsubmittedPastDueTool: ToolDefinition<typeof schema>;
|
|
12
|
+
//# sourceMappingURL=get-unsubmitted-past-due.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-unsubmitted-past-due.d.ts","sourceRoot":"","sources":["../../../../src/src/mcp/tools/get-unsubmitted-past-due.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAEhE,eAAO,MAAM,MAAM;;;CAMlB,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,cAAc,CAAC,OAAO,MAAM,CAyDnE,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: get_unsubmitted_past_due
|
|
3
|
+
* Get assignments that are past due but not submitted
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { listCourses } from "../../api/courses.js";
|
|
7
|
+
import { listUnsubmittedPastDueForStudent } from "../../api/submissions.js";
|
|
8
|
+
import { jsonResponse } from "../types.js";
|
|
9
|
+
export const schema = {
|
|
10
|
+
student_id: z.string().describe("Student ID (required for this endpoint)"),
|
|
11
|
+
course_id: z
|
|
12
|
+
.number()
|
|
13
|
+
.optional()
|
|
14
|
+
.describe("Filter by specific course ID (if omitted, checks all courses)"),
|
|
15
|
+
};
|
|
16
|
+
export const getUnsubmittedPastDueTool = {
|
|
17
|
+
name: "get_unsubmitted_past_due",
|
|
18
|
+
description: "Get assignments that are past due but not submitted (catches items Canvas hasn't flagged as missing yet)",
|
|
19
|
+
schema,
|
|
20
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
21
|
+
handler: async ({ student_id, course_id }) => {
|
|
22
|
+
const courseIds = [];
|
|
23
|
+
if (course_id) {
|
|
24
|
+
courseIds.push(course_id);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
// Get all active courses
|
|
28
|
+
const courses = await listCourses({
|
|
29
|
+
enrollment_state: "active",
|
|
30
|
+
state: ["available"],
|
|
31
|
+
});
|
|
32
|
+
courseIds.push(...courses.map((c) => c.id));
|
|
33
|
+
}
|
|
34
|
+
const results = [];
|
|
35
|
+
for (const cid of courseIds) {
|
|
36
|
+
try {
|
|
37
|
+
const unsubmitted = await listUnsubmittedPastDueForStudent(cid, student_id);
|
|
38
|
+
for (const sub of unsubmitted) {
|
|
39
|
+
const assignment = sub.assignment;
|
|
40
|
+
if (!assignment)
|
|
41
|
+
continue;
|
|
42
|
+
results.push({
|
|
43
|
+
id: assignment.id,
|
|
44
|
+
name: assignment.name,
|
|
45
|
+
course_id: assignment.course_id,
|
|
46
|
+
due_at: assignment.due_at,
|
|
47
|
+
points_possible: assignment.points_possible,
|
|
48
|
+
url: assignment.html_url,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// Skip courses we can't access
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// Sort by due date (most recent first)
|
|
57
|
+
results.sort((a, b) => {
|
|
58
|
+
if (!a.due_at || !b.due_at)
|
|
59
|
+
return 0;
|
|
60
|
+
return new Date(b.due_at).getTime() - new Date(a.due_at).getTime();
|
|
61
|
+
});
|
|
62
|
+
return jsonResponse(results);
|
|
63
|
+
},
|
|
64
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: get_upcoming_assignments
|
|
3
|
+
* Get assignments due in the next N days for a single course
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { type ToolDefinition } from "../types.js";
|
|
7
|
+
export declare const schema: {
|
|
8
|
+
course_id: z.ZodNumber;
|
|
9
|
+
days: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
10
|
+
};
|
|
11
|
+
export declare const getUpcomingAssignmentsTool: ToolDefinition<typeof schema>;
|
|
12
|
+
//# sourceMappingURL=get-upcoming-assignments.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-upcoming-assignments.d.ts","sourceRoot":"","sources":["../../../../src/src/mcp/tools/get-upcoming-assignments.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAEhE,eAAO,MAAM,MAAM;;;CAGlB,CAAC;AAEF,eAAO,MAAM,0BAA0B,EAAE,cAAc,CAAC,OAAO,MAAM,CAmBpE,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: get_upcoming_assignments
|
|
3
|
+
* Get assignments due in the next N days for a single course
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { listUpcomingAssignments } from "../../api/assignments.js";
|
|
7
|
+
import { jsonResponse } from "../types.js";
|
|
8
|
+
export const schema = {
|
|
9
|
+
course_id: z.number().describe("Course ID"),
|
|
10
|
+
days: z.number().optional().default(7).describe("Number of days to look ahead (default: 7)"),
|
|
11
|
+
};
|
|
12
|
+
export const getUpcomingAssignmentsTool = {
|
|
13
|
+
name: "get_upcoming_assignments",
|
|
14
|
+
description: "Get assignments due in the next N days for a single course",
|
|
15
|
+
schema,
|
|
16
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
17
|
+
handler: async ({ course_id, days }) => {
|
|
18
|
+
const assignments = await listUpcomingAssignments(course_id, days);
|
|
19
|
+
const simplified = assignments.map((a) => ({
|
|
20
|
+
id: a.id,
|
|
21
|
+
name: a.name,
|
|
22
|
+
due_at: a.due_at,
|
|
23
|
+
points: a.points_possible,
|
|
24
|
+
submitted: a.submission?.submitted_at ? true : false,
|
|
25
|
+
url: a.html_url,
|
|
26
|
+
}));
|
|
27
|
+
return jsonResponse(simplified);
|
|
28
|
+
},
|
|
29
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool registry - exports all MCP tools
|
|
3
|
+
*/
|
|
4
|
+
import { getCoursesTool } from "./get-courses.js";
|
|
5
|
+
import { getMissingAssignmentsTool } from "./get-missing-assignments.js";
|
|
6
|
+
import { getUnsubmittedPastDueTool } from "./get-unsubmitted-past-due.js";
|
|
7
|
+
import { getUpcomingAssignmentsTool } from "./get-upcoming-assignments.js";
|
|
8
|
+
import { getDueThisWeekTool } from "./get-due-this-week.js";
|
|
9
|
+
import { listAssignmentsTool } from "./list-assignments.js";
|
|
10
|
+
import { getStatsTool } from "./get-stats.js";
|
|
11
|
+
import { getTodoTool } from "./get-todo.js";
|
|
12
|
+
import type { AnyToolDefinition } from "../types.js";
|
|
13
|
+
/**
|
|
14
|
+
* All available MCP tools
|
|
15
|
+
*/
|
|
16
|
+
export declare const tools: AnyToolDefinition[];
|
|
17
|
+
export { getCoursesTool, getMissingAssignmentsTool, getUnsubmittedPastDueTool, getUpcomingAssignmentsTool, getDueThisWeekTool, listAssignmentsTool, getStatsTool, getTodoTool, };
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/mcp/tools/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAC;AAC1E,OAAO,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD;;GAEG;AACH,eAAO,MAAM,KAAK,EAAE,iBAAiB,EASpC,CAAC;AAGF,OAAO,EACL,cAAc,EACd,yBAAyB,EACzB,yBAAyB,EACzB,0BAA0B,EAC1B,kBAAkB,EAClB,mBAAmB,EACnB,YAAY,EACZ,WAAW,GACZ,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool registry - exports all MCP tools
|
|
3
|
+
*/
|
|
4
|
+
import { getCoursesTool } from "./get-courses.js";
|
|
5
|
+
import { getMissingAssignmentsTool } from "./get-missing-assignments.js";
|
|
6
|
+
import { getUnsubmittedPastDueTool } from "./get-unsubmitted-past-due.js";
|
|
7
|
+
import { getUpcomingAssignmentsTool } from "./get-upcoming-assignments.js";
|
|
8
|
+
import { getDueThisWeekTool } from "./get-due-this-week.js";
|
|
9
|
+
import { listAssignmentsTool } from "./list-assignments.js";
|
|
10
|
+
import { getStatsTool } from "./get-stats.js";
|
|
11
|
+
import { getTodoTool } from "./get-todo.js";
|
|
12
|
+
/**
|
|
13
|
+
* All available MCP tools
|
|
14
|
+
*/
|
|
15
|
+
export const tools = [
|
|
16
|
+
getCoursesTool,
|
|
17
|
+
getMissingAssignmentsTool,
|
|
18
|
+
getUnsubmittedPastDueTool,
|
|
19
|
+
getUpcomingAssignmentsTool,
|
|
20
|
+
getDueThisWeekTool,
|
|
21
|
+
listAssignmentsTool,
|
|
22
|
+
getStatsTool,
|
|
23
|
+
getTodoTool,
|
|
24
|
+
];
|
|
25
|
+
// Re-export individual tools for direct access if needed
|
|
26
|
+
export { getCoursesTool, getMissingAssignmentsTool, getUnsubmittedPastDueTool, getUpcomingAssignmentsTool, getDueThisWeekTool, listAssignmentsTool, getStatsTool, getTodoTool, };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: list_assignments
|
|
3
|
+
* List assignments for a course with optional filtering
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { type ToolDefinition } from "../types.js";
|
|
7
|
+
export declare const schema: {
|
|
8
|
+
course_id: z.ZodNumber;
|
|
9
|
+
bucket: z.ZodOptional<z.ZodEnum<["past", "overdue", "undated", "ungraded", "unsubmitted", "upcoming", "future"]>>;
|
|
10
|
+
search_term: z.ZodOptional<z.ZodString>;
|
|
11
|
+
};
|
|
12
|
+
export declare const listAssignmentsTool: ToolDefinition<typeof schema>;
|
|
13
|
+
//# sourceMappingURL=list-assignments.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-assignments.d.ts","sourceRoot":"","sources":["../../../../src/src/mcp/tools/list-assignments.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAEhE,eAAO,MAAM,MAAM;;;;CAOlB,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,cAAc,CAAC,OAAO,MAAM,CA0B7D,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: list_assignments
|
|
3
|
+
* List assignments for a course with optional filtering
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { listAssignments } from "../../api/assignments.js";
|
|
7
|
+
import { jsonResponse } from "../types.js";
|
|
8
|
+
export const schema = {
|
|
9
|
+
course_id: z.number().describe("Course ID"),
|
|
10
|
+
bucket: z
|
|
11
|
+
.enum(["past", "overdue", "undated", "ungraded", "unsubmitted", "upcoming", "future"])
|
|
12
|
+
.optional()
|
|
13
|
+
.describe("Filter by bucket"),
|
|
14
|
+
search_term: z.string().optional().describe("Search by assignment name"),
|
|
15
|
+
};
|
|
16
|
+
export const listAssignmentsTool = {
|
|
17
|
+
name: "list_assignments",
|
|
18
|
+
description: "List assignments for a course with optional filtering",
|
|
19
|
+
schema,
|
|
20
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
21
|
+
handler: async ({ course_id, bucket, search_term }) => {
|
|
22
|
+
const assignments = await listAssignments({
|
|
23
|
+
course_id,
|
|
24
|
+
bucket: bucket,
|
|
25
|
+
search_term,
|
|
26
|
+
include: ["submission"],
|
|
27
|
+
});
|
|
28
|
+
const simplified = assignments.map((a) => ({
|
|
29
|
+
id: a.id,
|
|
30
|
+
name: a.name,
|
|
31
|
+
due_at: a.due_at,
|
|
32
|
+
bucket: bucket || "all",
|
|
33
|
+
score: a.submission?.score,
|
|
34
|
+
grade: a.submission?.grade,
|
|
35
|
+
submitted: !!a.submission?.submitted_at,
|
|
36
|
+
url: a.html_url,
|
|
37
|
+
}));
|
|
38
|
+
return jsonResponse(simplified);
|
|
39
|
+
},
|
|
40
|
+
};
|