brightspace-mcp-server 1.0.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 +661 -0
- package/README.md +372 -0
- package/build/api/cache.d.ts +15 -0
- package/build/api/cache.d.ts.map +1 -0
- package/build/api/cache.js +49 -0
- package/build/api/cache.js.map +1 -0
- package/build/api/client.d.ts +109 -0
- package/build/api/client.d.ts.map +1 -0
- package/build/api/client.js +356 -0
- package/build/api/client.js.map +1 -0
- package/build/api/errors.d.ts +23 -0
- package/build/api/errors.d.ts.map +1 -0
- package/build/api/errors.js +47 -0
- package/build/api/errors.js.map +1 -0
- package/build/api/index.d.ts +13 -0
- package/build/api/index.d.ts.map +1 -0
- package/build/api/index.js +17 -0
- package/build/api/index.js.map +1 -0
- package/build/api/rate-limiter.d.ts +17 -0
- package/build/api/rate-limiter.d.ts.map +1 -0
- package/build/api/rate-limiter.js +57 -0
- package/build/api/rate-limiter.js.map +1 -0
- package/build/api/types.d.ts +36 -0
- package/build/api/types.d.ts.map +1 -0
- package/build/api/types.js +16 -0
- package/build/api/types.js.map +1 -0
- package/build/api/version-discovery.d.ts +16 -0
- package/build/api/version-discovery.d.ts.map +1 -0
- package/build/api/version-discovery.js +56 -0
- package/build/api/version-discovery.js.map +1 -0
- package/build/auth/auth-runner.d.ts +26 -0
- package/build/auth/auth-runner.d.ts.map +1 -0
- package/build/auth/auth-runner.js +69 -0
- package/build/auth/auth-runner.js.map +1 -0
- package/build/auth/browser-auth.d.ts +56 -0
- package/build/auth/browser-auth.d.ts.map +1 -0
- package/build/auth/browser-auth.js +496 -0
- package/build/auth/browser-auth.js.map +1 -0
- package/build/auth/index.d.ts +11 -0
- package/build/auth/index.d.ts.map +1 -0
- package/build/auth/index.js +11 -0
- package/build/auth/index.js.map +1 -0
- package/build/auth/purdue-sso.d.ts +32 -0
- package/build/auth/purdue-sso.d.ts.map +1 -0
- package/build/auth/purdue-sso.js +185 -0
- package/build/auth/purdue-sso.js.map +1 -0
- package/build/auth/session-store.d.ts +45 -0
- package/build/auth/session-store.d.ts.map +1 -0
- package/build/auth/session-store.js +152 -0
- package/build/auth/session-store.js.map +1 -0
- package/build/auth/token-manager.d.ts +40 -0
- package/build/auth/token-manager.d.ts.map +1 -0
- package/build/auth/token-manager.js +83 -0
- package/build/auth/token-manager.js.map +1 -0
- package/build/auth-cli.d.ts +10 -0
- package/build/auth-cli.d.ts.map +1 -0
- package/build/auth-cli.js +82 -0
- package/build/auth-cli.js.map +1 -0
- package/build/index.d.ts +10 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +157 -0
- package/build/index.js.map +1 -0
- package/build/setup.d.ts +10 -0
- package/build/setup.d.ts.map +1 -0
- package/build/setup.js +321 -0
- package/build/setup.js.map +1 -0
- package/build/tools/download-file.d.ts +12 -0
- package/build/tools/download-file.d.ts.map +1 -0
- package/build/tools/download-file.js +167 -0
- package/build/tools/download-file.js.map +1 -0
- package/build/tools/get-announcements.d.ts +13 -0
- package/build/tools/get-announcements.d.ts.map +1 -0
- package/build/tools/get-announcements.js +104 -0
- package/build/tools/get-announcements.js.map +1 -0
- package/build/tools/get-assignments.d.ts +13 -0
- package/build/tools/get-assignments.d.ts.map +1 -0
- package/build/tools/get-assignments.js +241 -0
- package/build/tools/get-assignments.js.map +1 -0
- package/build/tools/get-classlist-emails.d.ts +12 -0
- package/build/tools/get-classlist-emails.d.ts.map +1 -0
- package/build/tools/get-classlist-emails.js +48 -0
- package/build/tools/get-classlist-emails.js.map +1 -0
- package/build/tools/get-course-content.d.ts +12 -0
- package/build/tools/get-course-content.d.ts.map +1 -0
- package/build/tools/get-course-content.js +190 -0
- package/build/tools/get-course-content.js.map +1 -0
- package/build/tools/get-discussions.d.ts +12 -0
- package/build/tools/get-discussions.d.ts.map +1 -0
- package/build/tools/get-discussions.js +212 -0
- package/build/tools/get-discussions.js.map +1 -0
- package/build/tools/get-my-courses.d.ts +13 -0
- package/build/tools/get-my-courses.d.ts.map +1 -0
- package/build/tools/get-my-courses.js +51 -0
- package/build/tools/get-my-courses.js.map +1 -0
- package/build/tools/get-my-grades.d.ts +13 -0
- package/build/tools/get-my-grades.d.ts.map +1 -0
- package/build/tools/get-my-grades.js +100 -0
- package/build/tools/get-my-grades.js.map +1 -0
- package/build/tools/get-roster.d.ts +12 -0
- package/build/tools/get-roster.d.ts.map +1 -0
- package/build/tools/get-roster.js +108 -0
- package/build/tools/get-roster.js.map +1 -0
- package/build/tools/get-syllabus.d.ts +12 -0
- package/build/tools/get-syllabus.d.ts.map +1 -0
- package/build/tools/get-syllabus.js +162 -0
- package/build/tools/get-syllabus.js.map +1 -0
- package/build/tools/get-upcoming-due-dates.d.ts +13 -0
- package/build/tools/get-upcoming-due-dates.d.ts.map +1 -0
- package/build/tools/get-upcoming-due-dates.js +74 -0
- package/build/tools/get-upcoming-due-dates.js.map +1 -0
- package/build/tools/index.d.ts +19 -0
- package/build/tools/index.d.ts.map +1 -0
- package/build/tools/index.js +21 -0
- package/build/tools/index.js.map +1 -0
- package/build/tools/schemas.d.ts +66 -0
- package/build/tools/schemas.d.ts.map +1 -0
- package/build/tools/schemas.js +80 -0
- package/build/tools/schemas.js.map +1 -0
- package/build/tools/tool-helpers.d.ts +21 -0
- package/build/tools/tool-helpers.d.ts.map +1 -0
- package/build/tools/tool-helpers.js +70 -0
- package/build/tools/tool-helpers.js.map +1 -0
- package/build/types/index.d.ts +48 -0
- package/build/types/index.d.ts.map +1 -0
- package/build/types/index.js +7 -0
- package/build/types/index.js.map +1 -0
- package/build/update.d.ts +10 -0
- package/build/update.d.ts.map +1 -0
- package/build/update.js +130 -0
- package/build/update.js.map +1 -0
- package/build/utils/config-store.d.ts +23 -0
- package/build/utils/config-store.d.ts.map +1 -0
- package/build/utils/config-store.js +29 -0
- package/build/utils/config-store.js.map +1 -0
- package/build/utils/config.d.ts +9 -0
- package/build/utils/config.d.ts.map +1 -0
- package/build/utils/config.js +66 -0
- package/build/utils/config.js.map +1 -0
- package/build/utils/course-filter.d.ts +24 -0
- package/build/utils/course-filter.d.ts.map +1 -0
- package/build/utils/course-filter.js +39 -0
- package/build/utils/course-filter.js.map +1 -0
- package/build/utils/download-helpers.d.ts +31 -0
- package/build/utils/download-helpers.d.ts.map +1 -0
- package/build/utils/download-helpers.js +93 -0
- package/build/utils/download-helpers.js.map +1 -0
- package/build/utils/errors.d.ts +21 -0
- package/build/utils/errors.d.ts.map +1 -0
- package/build/utils/errors.js +36 -0
- package/build/utils/errors.js.map +1 -0
- package/build/utils/file-validator.d.ts +56 -0
- package/build/utils/file-validator.d.ts.map +1 -0
- package/build/utils/file-validator.js +134 -0
- package/build/utils/file-validator.js.map +1 -0
- package/build/utils/html-converter.d.ts +17 -0
- package/build/utils/html-converter.d.ts.map +1 -0
- package/build/utils/html-converter.js +36 -0
- package/build/utils/html-converter.js.map +1 -0
- package/build/utils/logger.d.ts +10 -0
- package/build/utils/logger.d.ts.map +1 -0
- package/build/utils/logger.js +42 -0
- package/build/utils/logger.js.map +1 -0
- package/build/utils/pdf-extractor.d.ts +14 -0
- package/build/utils/pdf-extractor.d.ts.map +1 -0
- package/build/utils/pdf-extractor.js +27 -0
- package/build/utils/pdf-extractor.js.map +1 -0
- package/build/utils/update-checker.d.ts +8 -0
- package/build/utils/update-checker.d.ts.map +1 -0
- package/build/utils/update-checker.js +33 -0
- package/build/utils/update-checker.js.map +1 -0
- package/package.json +73 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Purdue Brightspace MCP Server
|
|
3
|
+
* Copyright (c) 2026 Rohan Muppa. All rights reserved.
|
|
4
|
+
* Licensed under AGPL-3.0 — see LICENSE file for details.
|
|
5
|
+
*/
|
|
6
|
+
import { DEFAULT_CACHE_TTLS } from "../api/index.js";
|
|
7
|
+
import { GetMyGradesSchema, } from "./schemas.js";
|
|
8
|
+
import { toolResponse, sanitizeError } from "./tool-helpers.js";
|
|
9
|
+
import { log } from "../utils/logger.js";
|
|
10
|
+
import { applyCourseFilter } from "../utils/course-filter.js";
|
|
11
|
+
/**
|
|
12
|
+
* Register get_my_grades tool
|
|
13
|
+
*/
|
|
14
|
+
export function registerGetMyGrades(server, apiClient, config) {
|
|
15
|
+
server.registerTool("get_my_grades", {
|
|
16
|
+
title: "Get My Grades",
|
|
17
|
+
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.",
|
|
18
|
+
inputSchema: GetMyGradesSchema,
|
|
19
|
+
}, async (args) => {
|
|
20
|
+
try {
|
|
21
|
+
log("DEBUG", "get_my_grades tool called", { args });
|
|
22
|
+
// Parse and validate input
|
|
23
|
+
const { courseId } = GetMyGradesSchema.parse(args);
|
|
24
|
+
// Single course case
|
|
25
|
+
if (courseId) {
|
|
26
|
+
const path = apiClient.le(courseId, "/grades/values/myGradeValues/");
|
|
27
|
+
const gradeValues = await apiClient.get(path, {
|
|
28
|
+
ttl: DEFAULT_CACHE_TTLS.grades,
|
|
29
|
+
});
|
|
30
|
+
// Map to clean objects
|
|
31
|
+
const grades = gradeValues.map((gv) => ({
|
|
32
|
+
name: gv.GradeObjectName,
|
|
33
|
+
displayGrade: gv.DisplayedGrade,
|
|
34
|
+
pointsNumerator: gv.PointsNumerator,
|
|
35
|
+
pointsDenominator: gv.PointsDenominator,
|
|
36
|
+
weightedNumerator: gv.WeightedNumerator,
|
|
37
|
+
weightedDenominator: gv.WeightedDenominator,
|
|
38
|
+
comments: gv.Comments?.Text || null,
|
|
39
|
+
lastModified: gv.LastModified,
|
|
40
|
+
}));
|
|
41
|
+
log("INFO", `get_my_grades: Retrieved ${grades.length} grade items for course ${courseId}`);
|
|
42
|
+
return toolResponse({ courseId, grades });
|
|
43
|
+
}
|
|
44
|
+
// All courses case
|
|
45
|
+
// First, fetch enrolled courses
|
|
46
|
+
const enrollmentPath = apiClient.lp("/enrollments/myenrollments/?orgUnitTypeId=3&isActive=true");
|
|
47
|
+
const enrollmentResponse = await apiClient.get(enrollmentPath, { ttl: DEFAULT_CACHE_TTLS.enrollments });
|
|
48
|
+
// Apply course filter
|
|
49
|
+
const filteredEnrollments = applyCourseFilter(enrollmentResponse.Items.map(item => ({
|
|
50
|
+
id: item.OrgUnit.Id,
|
|
51
|
+
name: item.OrgUnit.Name,
|
|
52
|
+
code: item.OrgUnit.Code,
|
|
53
|
+
isActive: item.Access.IsActive,
|
|
54
|
+
...item,
|
|
55
|
+
})), config.courseFilter);
|
|
56
|
+
// Fetch grades for each course (handle 403s gracefully)
|
|
57
|
+
const gradePromises = filteredEnrollments.map(async (item) => {
|
|
58
|
+
try {
|
|
59
|
+
const path = apiClient.le(item.OrgUnit.Id, "/grades/values/myGradeValues/");
|
|
60
|
+
const gradeValues = await apiClient.get(path, {
|
|
61
|
+
ttl: DEFAULT_CACHE_TTLS.grades,
|
|
62
|
+
});
|
|
63
|
+
const grades = gradeValues.map((gv) => ({
|
|
64
|
+
name: gv.GradeObjectName,
|
|
65
|
+
displayGrade: gv.DisplayedGrade,
|
|
66
|
+
pointsNumerator: gv.PointsNumerator,
|
|
67
|
+
pointsDenominator: gv.PointsDenominator,
|
|
68
|
+
weightedNumerator: gv.WeightedNumerator,
|
|
69
|
+
weightedDenominator: gv.WeightedDenominator,
|
|
70
|
+
comments: gv.Comments?.Text || null,
|
|
71
|
+
lastModified: gv.LastModified,
|
|
72
|
+
}));
|
|
73
|
+
return {
|
|
74
|
+
courseId: item.OrgUnit.Id,
|
|
75
|
+
courseName: item.OrgUnit.Name,
|
|
76
|
+
grades,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
// 403 means no access (past course, etc) - log and skip
|
|
81
|
+
if (error?.status === 403) {
|
|
82
|
+
log("DEBUG", `get_my_grades: 403 Forbidden for course ${item.OrgUnit.Id} (${item.OrgUnit.Name}) - skipping`);
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
throw error; // Re-throw other errors
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
const results = await Promise.allSettled(gradePromises);
|
|
89
|
+
const courses = results
|
|
90
|
+
.filter((r) => r.status === "fulfilled" && r.value !== null)
|
|
91
|
+
.map((r) => r.value);
|
|
92
|
+
log("INFO", `get_my_grades: Retrieved grades for ${courses.length} courses (out of ${enrollmentResponse.Items.length} enrolled)`);
|
|
93
|
+
return toolResponse({ courses });
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
return sanitizeError(error);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=get-my-grades.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-my-grades.js","sourceRoot":"","sources":["../../src/tools/get-my-grades.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Purdue Brightspace MCP Server
|
|
3
|
+
* Copyright (c) 2025 Rohan Muppa. All rights reserved.
|
|
4
|
+
* Licensed under AGPL-3.0 — see LICENSE file for details.
|
|
5
|
+
*/
|
|
6
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
7
|
+
import { D2LApiClient } from "../api/index.js";
|
|
8
|
+
/**
|
|
9
|
+
* Register get_roster tool
|
|
10
|
+
*/
|
|
11
|
+
export declare function registerGetRoster(server: McpServer, apiClient: D2LApiClient): void;
|
|
12
|
+
//# sourceMappingURL=get-roster.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-roster.d.ts","sourceRoot":"","sources":["../../src/tools/get-roster.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,YAAY,EAAsB,MAAM,iBAAiB,CAAC;AAqEnE;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,YAAY,GACtB,IAAI,CA6EN"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Purdue Brightspace MCP Server
|
|
3
|
+
* Copyright (c) 2025 Rohan Muppa. All rights reserved.
|
|
4
|
+
* Licensed under AGPL-3.0 — see LICENSE file for details.
|
|
5
|
+
*/
|
|
6
|
+
import { DEFAULT_CACHE_TTLS } from "../api/index.js";
|
|
7
|
+
import { GetRosterSchema, } from "./schemas.js";
|
|
8
|
+
import { toolResponse, sanitizeError } from "./tool-helpers.js";
|
|
9
|
+
import { log } from "../utils/logger.js";
|
|
10
|
+
// Purdue-specific role IDs. These are institution-specific values.
|
|
11
|
+
// If using at another institution, you may need to adjust these.
|
|
12
|
+
// Discover by fetching classlist for a known course and inspecting RoleId values.
|
|
13
|
+
const INSTRUCTOR_ROLE_ID = 109;
|
|
14
|
+
const TA_ROLE_ID = 135;
|
|
15
|
+
/**
|
|
16
|
+
* Fetch a page of classlist users with optional filters
|
|
17
|
+
*/
|
|
18
|
+
async function fetchClasslistPage(apiClient, courseId, options) {
|
|
19
|
+
const params = new URLSearchParams();
|
|
20
|
+
if (options?.roleId !== undefined) {
|
|
21
|
+
params.append("roleId", options.roleId.toString());
|
|
22
|
+
}
|
|
23
|
+
if (options?.searchTerm) {
|
|
24
|
+
params.append("searchTerm", options.searchTerm);
|
|
25
|
+
}
|
|
26
|
+
const queryString = params.toString();
|
|
27
|
+
const path = apiClient.le(courseId, `/classlist/paged/${queryString ? "?" + queryString : ""}`);
|
|
28
|
+
const response = await apiClient.get(path, {
|
|
29
|
+
ttl: DEFAULT_CACHE_TTLS.roster,
|
|
30
|
+
});
|
|
31
|
+
if (response.Next) {
|
|
32
|
+
log("WARN", "get_roster: Pagination detected but not implemented. Some users may be missing.", { courseId, next: response.Next });
|
|
33
|
+
}
|
|
34
|
+
return response.Objects;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Register get_roster tool
|
|
38
|
+
*/
|
|
39
|
+
export function registerGetRoster(server, apiClient) {
|
|
40
|
+
server.registerTool("get_roster", {
|
|
41
|
+
title: "Get Course Roster",
|
|
42
|
+
description: "Fetch the roster for a course including instructors, TAs, and optionally students with their names, emails, and roles. Use this when the user asks about classmates, instructor contact info, TA emails, professor names, or who's in a class. By default returns only instructors and TAs for privacy. Use includeStudents to get full class list.",
|
|
43
|
+
inputSchema: GetRosterSchema,
|
|
44
|
+
}, async (args) => {
|
|
45
|
+
try {
|
|
46
|
+
log("DEBUG", "get_roster tool called", { args });
|
|
47
|
+
// Parse and validate input
|
|
48
|
+
const { courseId, includeStudents, searchTerm } = GetRosterSchema.parse(args);
|
|
49
|
+
let allUsers = [];
|
|
50
|
+
if (!includeStudents) {
|
|
51
|
+
// Fetch instructors and TAs in parallel
|
|
52
|
+
const [instructorResult, taResult] = await Promise.allSettled([
|
|
53
|
+
fetchClasslistPage(apiClient, courseId, {
|
|
54
|
+
roleId: INSTRUCTOR_ROLE_ID,
|
|
55
|
+
searchTerm,
|
|
56
|
+
}),
|
|
57
|
+
fetchClasslistPage(apiClient, courseId, {
|
|
58
|
+
roleId: TA_ROLE_ID,
|
|
59
|
+
searchTerm,
|
|
60
|
+
}),
|
|
61
|
+
]);
|
|
62
|
+
// Merge results
|
|
63
|
+
if (instructorResult.status === "fulfilled") {
|
|
64
|
+
allUsers.push(...instructorResult.value);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
log("WARN", "get_roster: Failed to fetch instructors", {
|
|
68
|
+
error: instructorResult.reason,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
if (taResult.status === "fulfilled") {
|
|
72
|
+
allUsers.push(...taResult.value);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
log("WARN", "get_roster: Failed to fetch TAs", {
|
|
76
|
+
error: taResult.reason,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
// Fetch all users
|
|
82
|
+
allUsers = await fetchClasslistPage(apiClient, courseId, {
|
|
83
|
+
searchTerm,
|
|
84
|
+
});
|
|
85
|
+
// Cap at 100 users to prevent MCP response size issues
|
|
86
|
+
if (allUsers.length > 100) {
|
|
87
|
+
log("WARN", "get_roster: Result set exceeds 100 users, truncating", {
|
|
88
|
+
total: allUsers.length,
|
|
89
|
+
returned: 100,
|
|
90
|
+
});
|
|
91
|
+
allUsers = allUsers.slice(0, 100);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// Map to clean output
|
|
95
|
+
const roster = allUsers.map((user) => ({
|
|
96
|
+
name: user.DisplayName,
|
|
97
|
+
email: user.Email || null,
|
|
98
|
+
role: user.ClasslistRoleDisplayName,
|
|
99
|
+
}));
|
|
100
|
+
log("INFO", `get_roster: Retrieved ${roster.length} users for course ${courseId}`);
|
|
101
|
+
return toolResponse(roster);
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
return sanitizeError(error);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=get-roster.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-roster.js","sourceRoot":"","sources":["../../src/tools/get-roster.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Purdue Brightspace MCP Server
|
|
3
|
+
* Copyright (c) 2026 Rohan Muppa. All rights reserved.
|
|
4
|
+
* Licensed under AGPL-3.0 — see LICENSE file for details.
|
|
5
|
+
*/
|
|
6
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
7
|
+
import { D2LApiClient } from "../api/index.js";
|
|
8
|
+
/**
|
|
9
|
+
* Register get_syllabus tool
|
|
10
|
+
*/
|
|
11
|
+
export declare function registerGetSyllabus(server: McpServer, apiClient: D2LApiClient): void;
|
|
12
|
+
//# sourceMappingURL=get-syllabus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-syllabus.d.ts","sourceRoot":"","sources":["../../src/tools/get-syllabus.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,YAAY,EAAgC,MAAM,iBAAiB,CAAC;AAgB7E;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,YAAY,GACtB,IAAI,CA8KN"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Purdue Brightspace MCP Server
|
|
3
|
+
* Copyright (c) 2026 Rohan Muppa. All rights reserved.
|
|
4
|
+
* Licensed under AGPL-3.0 — see LICENSE file for details.
|
|
5
|
+
*/
|
|
6
|
+
import { ApiError, DEFAULT_CACHE_TTLS } from "../api/index.js";
|
|
7
|
+
import { GetSyllabusSchema } from "./schemas.js";
|
|
8
|
+
import { toolResponse, sanitizeError, errorResponse } from "./tool-helpers.js";
|
|
9
|
+
import { convertHtmlToMarkdown } from "../utils/html-converter.js";
|
|
10
|
+
import { secureDownload } from "../utils/download-helpers.js";
|
|
11
|
+
import { MAX_FILE_SIZE } from "../utils/file-validator.js";
|
|
12
|
+
import { extractPdfText } from "../utils/pdf-extractor.js";
|
|
13
|
+
import { log } from "../utils/logger.js";
|
|
14
|
+
import path from "node:path";
|
|
15
|
+
import fs from "node:fs/promises";
|
|
16
|
+
/**
|
|
17
|
+
* Register get_syllabus tool
|
|
18
|
+
*/
|
|
19
|
+
export function registerGetSyllabus(server, apiClient) {
|
|
20
|
+
server.registerTool("get_syllabus", {
|
|
21
|
+
title: "Get Course Syllabus",
|
|
22
|
+
description: "Fetch the syllabus/overview text and optional attachment for a course. Returns the course overview description as markdown. If downloadPath is provided, also downloads the syllabus attachment (e.g. PDF). IMPORTANT: You MUST ask the user where they want to save the file before calling this tool with a downloadPath.",
|
|
23
|
+
inputSchema: GetSyllabusSchema,
|
|
24
|
+
}, async (args) => {
|
|
25
|
+
try {
|
|
26
|
+
log("DEBUG", "get_syllabus tool called", { args });
|
|
27
|
+
const { courseId, downloadPath } = GetSyllabusSchema.parse(args);
|
|
28
|
+
// Validate downloadPath if provided
|
|
29
|
+
if (downloadPath !== undefined) {
|
|
30
|
+
if (!path.isAbsolute(downloadPath)) {
|
|
31
|
+
return errorResponse("Download path must be an absolute path (e.g., /Users/username/Downloads on Mac or C:\\Users\\username\\Downloads on Windows)");
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
const stats = await fs.stat(downloadPath);
|
|
35
|
+
if (!stats.isDirectory()) {
|
|
36
|
+
return errorResponse(`Download path is not a directory: ${downloadPath}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
if (error?.code === "ENOENT") {
|
|
41
|
+
return errorResponse(`Download directory does not exist: ${downloadPath}`);
|
|
42
|
+
}
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// Fetch overview text
|
|
47
|
+
let overview = null;
|
|
48
|
+
try {
|
|
49
|
+
overview = await apiClient.get(apiClient.le(courseId, "/overview"), { ttl: DEFAULT_CACHE_TTLS.courseContent });
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
if (error instanceof ApiError && error.status === 404) {
|
|
53
|
+
return toolResponse({
|
|
54
|
+
courseId,
|
|
55
|
+
description: null,
|
|
56
|
+
hasAttachment: false,
|
|
57
|
+
message: "No syllabus/overview found for this course.",
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
// Convert description HTML to markdown
|
|
63
|
+
const description = overview?.Description?.Html
|
|
64
|
+
? convertHtmlToMarkdown(overview.Description.Html)
|
|
65
|
+
: null;
|
|
66
|
+
// Always attempt to fetch the attachment so we can extract PDF text
|
|
67
|
+
let attachmentBuffer = null;
|
|
68
|
+
let attachmentFilename = "syllabus";
|
|
69
|
+
let hasAttachment = false;
|
|
70
|
+
try {
|
|
71
|
+
const response = await apiClient.getRaw(apiClient.le(courseId, "/overview/attachment"));
|
|
72
|
+
if (response.ok) {
|
|
73
|
+
hasAttachment = true;
|
|
74
|
+
// Check Content-Length before downloading body
|
|
75
|
+
const contentLength = parseInt(response.headers.get("Content-Length") ?? "0", 10);
|
|
76
|
+
if (contentLength > MAX_FILE_SIZE) {
|
|
77
|
+
return errorResponse(`Attachment too large (${Math.round(contentLength / 1024 / 1024)}MB). Maximum allowed: ${MAX_FILE_SIZE / 1024 / 1024}MB`);
|
|
78
|
+
}
|
|
79
|
+
// Get filename from Content-Disposition header
|
|
80
|
+
const disposition = response.headers.get("Content-Disposition") ?? "";
|
|
81
|
+
const match = disposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/);
|
|
82
|
+
if (match?.[1]) {
|
|
83
|
+
attachmentFilename = match[1].replace(/['"]/g, "");
|
|
84
|
+
}
|
|
85
|
+
// Download body as buffer
|
|
86
|
+
attachmentBuffer = Buffer.from(await response.arrayBuffer());
|
|
87
|
+
if (attachmentBuffer.length > MAX_FILE_SIZE) {
|
|
88
|
+
return errorResponse(`Attachment too large (${Math.round(attachmentBuffer.length / 1024 / 1024)}MB). Maximum allowed: ${MAX_FILE_SIZE / 1024 / 1024}MB`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
if (error instanceof ApiError && error.status === 404) {
|
|
94
|
+
hasAttachment = false;
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
log("DEBUG", "Could not fetch syllabus attachment", error);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Extract text from PDF attachment if available
|
|
101
|
+
let syllabusText = null;
|
|
102
|
+
let totalPages;
|
|
103
|
+
if (attachmentBuffer && attachmentFilename.toLowerCase().endsWith(".pdf")) {
|
|
104
|
+
const extracted = await extractPdfText(attachmentBuffer);
|
|
105
|
+
if (extracted) {
|
|
106
|
+
syllabusText = extracted.text;
|
|
107
|
+
totalPages = extracted.totalPages;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// Save to disk if downloadPath provided
|
|
111
|
+
let download;
|
|
112
|
+
if (downloadPath && attachmentBuffer) {
|
|
113
|
+
try {
|
|
114
|
+
const result = await secureDownload({
|
|
115
|
+
targetDir: downloadPath,
|
|
116
|
+
filename: attachmentFilename,
|
|
117
|
+
data: attachmentBuffer,
|
|
118
|
+
});
|
|
119
|
+
log("INFO", `Syllabus attachment downloaded: ${result.path} (${result.size} bytes)`);
|
|
120
|
+
download = {
|
|
121
|
+
success: true,
|
|
122
|
+
filePath: result.path,
|
|
123
|
+
fileSize: result.size,
|
|
124
|
+
mimeType: result.mime,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
log("ERROR", "Failed to save syllabus attachment", error);
|
|
129
|
+
download = {
|
|
130
|
+
success: false,
|
|
131
|
+
error: "Failed to save attachment to disk.",
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
else if (downloadPath && !attachmentBuffer) {
|
|
136
|
+
download = {
|
|
137
|
+
success: false,
|
|
138
|
+
error: "No attachment found for this course's syllabus.",
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
log("INFO", `get_syllabus: Retrieved overview for course ${courseId}`);
|
|
142
|
+
// Build response
|
|
143
|
+
const result = { courseId, description };
|
|
144
|
+
if (syllabusText) {
|
|
145
|
+
result.syllabusText = syllabusText;
|
|
146
|
+
if (totalPages)
|
|
147
|
+
result.totalPages = totalPages;
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
result.hasAttachment = hasAttachment;
|
|
151
|
+
}
|
|
152
|
+
if (download) {
|
|
153
|
+
result.download = download;
|
|
154
|
+
}
|
|
155
|
+
return toolResponse(result);
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
return sanitizeError(error);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=get-syllabus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-syllabus.js","sourceRoot":"","sources":["../../src/tools/get-syllabus.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Purdue Brightspace MCP Server
|
|
3
|
+
* Copyright (c) 2025 Rohan Muppa. All rights reserved.
|
|
4
|
+
* Licensed under AGPL-3.0 — see LICENSE file for details.
|
|
5
|
+
*/
|
|
6
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
7
|
+
import { D2LApiClient } from "../api/index.js";
|
|
8
|
+
import type { AppConfig } from "../types/index.js";
|
|
9
|
+
/**
|
|
10
|
+
* Register get_upcoming_due_dates tool
|
|
11
|
+
*/
|
|
12
|
+
export declare function registerGetUpcomingDueDates(server: McpServer, apiClient: D2LApiClient, config: AppConfig): void;
|
|
13
|
+
//# sourceMappingURL=get-upcoming-due-dates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-upcoming-due-dates.d.ts","sourceRoot":"","sources":["../../src/tools/get-upcoming-due-dates.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,YAAY,EAAsB,MAAM,iBAAiB,CAAC;AAOnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AA2BnD;;GAEG;AACH,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,YAAY,EACvB,MAAM,EAAE,SAAS,GAChB,IAAI,CAuFN"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Purdue Brightspace MCP Server
|
|
3
|
+
* Copyright (c) 2025 Rohan Muppa. All rights reserved.
|
|
4
|
+
* Licensed under AGPL-3.0 — see LICENSE file for details.
|
|
5
|
+
*/
|
|
6
|
+
import { DEFAULT_CACHE_TTLS } from "../api/index.js";
|
|
7
|
+
import { GetUpcomingDueDatesSchema, } from "./schemas.js";
|
|
8
|
+
import { toolResponse, sanitizeError } from "./tool-helpers.js";
|
|
9
|
+
import { log } from "../utils/logger.js";
|
|
10
|
+
import { applyCourseFilter } from "../utils/course-filter.js";
|
|
11
|
+
/**
|
|
12
|
+
* Register get_upcoming_due_dates tool
|
|
13
|
+
*/
|
|
14
|
+
export function registerGetUpcomingDueDates(server, apiClient, config) {
|
|
15
|
+
server.registerTool("get_upcoming_due_dates", {
|
|
16
|
+
title: "Get Upcoming Due Dates",
|
|
17
|
+
description: "Fetch upcoming due dates across all your courses. Shows assignments, quizzes, and other items due within the specified time window. Use this when the user asks about deadlines, what's due, upcoming work, or what they need to do this week.",
|
|
18
|
+
inputSchema: GetUpcomingDueDatesSchema,
|
|
19
|
+
}, async (args) => {
|
|
20
|
+
try {
|
|
21
|
+
log("DEBUG", "get_upcoming_due_dates tool called", { args });
|
|
22
|
+
// Parse and validate input
|
|
23
|
+
const { daysAhead, courseId } = GetUpcomingDueDatesSchema.parse(args);
|
|
24
|
+
// Build time window
|
|
25
|
+
const now = new Date();
|
|
26
|
+
const endDate = new Date(now.getTime() + daysAhead * 24 * 60 * 60 * 1000);
|
|
27
|
+
const startDateTime = now.toISOString();
|
|
28
|
+
const endDateTime = endDate.toISOString();
|
|
29
|
+
// D2L calendar API requires orgUnitIdsCSV — fetch enrolled course IDs if not provided
|
|
30
|
+
let orgUnitIds;
|
|
31
|
+
if (courseId) {
|
|
32
|
+
orgUnitIds = String(courseId);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
const enrollments = await apiClient.get(apiClient.lp(`/enrollments/myenrollments/?orgUnitTypeId=3&isActive=true`), { ttl: DEFAULT_CACHE_TTLS.enrollments });
|
|
36
|
+
// Apply course filter
|
|
37
|
+
const filteredEnrollments = applyCourseFilter(enrollments.Items.map(item => ({
|
|
38
|
+
id: item.OrgUnit.Id,
|
|
39
|
+
name: item.OrgUnit.Name,
|
|
40
|
+
code: item.OrgUnit.Code,
|
|
41
|
+
isActive: item.Access.IsActive,
|
|
42
|
+
})), config.courseFilter);
|
|
43
|
+
orgUnitIds = filteredEnrollments.map((e) => e.id).join(",");
|
|
44
|
+
}
|
|
45
|
+
log("DEBUG", `get_upcoming_due_dates: querying orgUnitIds=${orgUnitIds}, window=${startDateTime} to ${endDateTime}`);
|
|
46
|
+
// Build path
|
|
47
|
+
const path = apiClient.leGlobal(`/calendar/events/myEvents/?startDateTime=${encodeURIComponent(startDateTime)}&endDateTime=${encodeURIComponent(endDateTime)}&orgUnitIdsCSV=${orgUnitIds}`);
|
|
48
|
+
// Fetch events — D2L returns ObjectListPage wrapper with "Objects" array (NOT "Items")
|
|
49
|
+
const response = await apiClient.get(path, {
|
|
50
|
+
ttl: DEFAULT_CACHE_TTLS.assignments,
|
|
51
|
+
});
|
|
52
|
+
const events = response.Objects ?? [];
|
|
53
|
+
log("DEBUG", `get_upcoming_due_dates: raw response keys=${Object.keys(response).join(",")}, event count=${events.length}`);
|
|
54
|
+
// Map to clean objects and sort by end date (soonest due first)
|
|
55
|
+
const mappedEvents = events
|
|
56
|
+
.map((event) => ({
|
|
57
|
+
id: event.CalendarEventId,
|
|
58
|
+
title: event.Title,
|
|
59
|
+
courseName: event.OrgUnitName,
|
|
60
|
+
courseId: event.OrgUnitId,
|
|
61
|
+
startDate: event.StartDateTime,
|
|
62
|
+
endDate: event.EndDateTime,
|
|
63
|
+
isAllDay: event.IsAllDayEvent,
|
|
64
|
+
}))
|
|
65
|
+
.sort((a, b) => new Date(a.endDate).getTime() - new Date(b.endDate).getTime());
|
|
66
|
+
log("INFO", `get_upcoming_due_dates: Retrieved ${mappedEvents.length} events`);
|
|
67
|
+
return toolResponse(mappedEvents);
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
return sanitizeError(error);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=get-upcoming-due-dates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-upcoming-due-dates.js","sourceRoot":"","sources":["../../src/tools/get-upcoming-due-dates.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Purdue Brightspace MCP Server
|
|
3
|
+
* Copyright (c) 2025 Rohan Muppa. All rights reserved.
|
|
4
|
+
* Licensed under AGPL-3.0 — see LICENSE file for details.
|
|
5
|
+
*/
|
|
6
|
+
export { registerGetMyCourses } from "./get-my-courses.js";
|
|
7
|
+
export { registerGetUpcomingDueDates } from "./get-upcoming-due-dates.js";
|
|
8
|
+
export { registerGetMyGrades } from "./get-my-grades.js";
|
|
9
|
+
export { registerGetAnnouncements } from "./get-announcements.js";
|
|
10
|
+
export { registerGetAssignments } from "./get-assignments.js";
|
|
11
|
+
export { registerGetCourseContent } from "./get-course-content.js";
|
|
12
|
+
export { registerDownloadFile } from "./download-file.js";
|
|
13
|
+
export { registerGetClasslistEmails } from "./get-classlist-emails.js";
|
|
14
|
+
export { registerGetRoster } from "./get-roster.js";
|
|
15
|
+
export { registerGetSyllabus } from "./get-syllabus.js";
|
|
16
|
+
export { registerGetDiscussions } from "./get-discussions.js";
|
|
17
|
+
export { toolResponse, errorResponse, sanitizeError } from "./tool-helpers.js";
|
|
18
|
+
export * from "./schemas.js";
|
|
19
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAG9D,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC/E,cAAc,cAAc,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Purdue Brightspace MCP Server
|
|
3
|
+
* Copyright (c) 2025 Rohan Muppa. All rights reserved.
|
|
4
|
+
* Licensed under AGPL-3.0 — see LICENSE file for details.
|
|
5
|
+
*/
|
|
6
|
+
// Tool registration functions - barrel export
|
|
7
|
+
export { registerGetMyCourses } from "./get-my-courses.js";
|
|
8
|
+
export { registerGetUpcomingDueDates } from "./get-upcoming-due-dates.js";
|
|
9
|
+
export { registerGetMyGrades } from "./get-my-grades.js";
|
|
10
|
+
export { registerGetAnnouncements } from "./get-announcements.js";
|
|
11
|
+
export { registerGetAssignments } from "./get-assignments.js";
|
|
12
|
+
export { registerGetCourseContent } from "./get-course-content.js";
|
|
13
|
+
export { registerDownloadFile } from "./download-file.js";
|
|
14
|
+
export { registerGetClasslistEmails } from "./get-classlist-emails.js";
|
|
15
|
+
export { registerGetRoster } from "./get-roster.js";
|
|
16
|
+
export { registerGetSyllabus } from "./get-syllabus.js";
|
|
17
|
+
export { registerGetDiscussions } from "./get-discussions.js";
|
|
18
|
+
// Re-export shared helpers and schemas for convenience
|
|
19
|
+
export { toolResponse, errorResponse, sanitizeError } from "./tool-helpers.js";
|
|
20
|
+
export * from "./schemas.js";
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,8CAA8C;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAE9D,uDAAuD;AACvD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC/E,cAAc,cAAc,CAAC"}
|