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.
Files changed (171) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +372 -0
  3. package/build/api/cache.d.ts +15 -0
  4. package/build/api/cache.d.ts.map +1 -0
  5. package/build/api/cache.js +49 -0
  6. package/build/api/cache.js.map +1 -0
  7. package/build/api/client.d.ts +109 -0
  8. package/build/api/client.d.ts.map +1 -0
  9. package/build/api/client.js +356 -0
  10. package/build/api/client.js.map +1 -0
  11. package/build/api/errors.d.ts +23 -0
  12. package/build/api/errors.d.ts.map +1 -0
  13. package/build/api/errors.js +47 -0
  14. package/build/api/errors.js.map +1 -0
  15. package/build/api/index.d.ts +13 -0
  16. package/build/api/index.d.ts.map +1 -0
  17. package/build/api/index.js +17 -0
  18. package/build/api/index.js.map +1 -0
  19. package/build/api/rate-limiter.d.ts +17 -0
  20. package/build/api/rate-limiter.d.ts.map +1 -0
  21. package/build/api/rate-limiter.js +57 -0
  22. package/build/api/rate-limiter.js.map +1 -0
  23. package/build/api/types.d.ts +36 -0
  24. package/build/api/types.d.ts.map +1 -0
  25. package/build/api/types.js +16 -0
  26. package/build/api/types.js.map +1 -0
  27. package/build/api/version-discovery.d.ts +16 -0
  28. package/build/api/version-discovery.d.ts.map +1 -0
  29. package/build/api/version-discovery.js +56 -0
  30. package/build/api/version-discovery.js.map +1 -0
  31. package/build/auth/auth-runner.d.ts +26 -0
  32. package/build/auth/auth-runner.d.ts.map +1 -0
  33. package/build/auth/auth-runner.js +69 -0
  34. package/build/auth/auth-runner.js.map +1 -0
  35. package/build/auth/browser-auth.d.ts +56 -0
  36. package/build/auth/browser-auth.d.ts.map +1 -0
  37. package/build/auth/browser-auth.js +496 -0
  38. package/build/auth/browser-auth.js.map +1 -0
  39. package/build/auth/index.d.ts +11 -0
  40. package/build/auth/index.d.ts.map +1 -0
  41. package/build/auth/index.js +11 -0
  42. package/build/auth/index.js.map +1 -0
  43. package/build/auth/purdue-sso.d.ts +32 -0
  44. package/build/auth/purdue-sso.d.ts.map +1 -0
  45. package/build/auth/purdue-sso.js +185 -0
  46. package/build/auth/purdue-sso.js.map +1 -0
  47. package/build/auth/session-store.d.ts +45 -0
  48. package/build/auth/session-store.d.ts.map +1 -0
  49. package/build/auth/session-store.js +152 -0
  50. package/build/auth/session-store.js.map +1 -0
  51. package/build/auth/token-manager.d.ts +40 -0
  52. package/build/auth/token-manager.d.ts.map +1 -0
  53. package/build/auth/token-manager.js +83 -0
  54. package/build/auth/token-manager.js.map +1 -0
  55. package/build/auth-cli.d.ts +10 -0
  56. package/build/auth-cli.d.ts.map +1 -0
  57. package/build/auth-cli.js +82 -0
  58. package/build/auth-cli.js.map +1 -0
  59. package/build/index.d.ts +10 -0
  60. package/build/index.d.ts.map +1 -0
  61. package/build/index.js +157 -0
  62. package/build/index.js.map +1 -0
  63. package/build/setup.d.ts +10 -0
  64. package/build/setup.d.ts.map +1 -0
  65. package/build/setup.js +321 -0
  66. package/build/setup.js.map +1 -0
  67. package/build/tools/download-file.d.ts +12 -0
  68. package/build/tools/download-file.d.ts.map +1 -0
  69. package/build/tools/download-file.js +167 -0
  70. package/build/tools/download-file.js.map +1 -0
  71. package/build/tools/get-announcements.d.ts +13 -0
  72. package/build/tools/get-announcements.d.ts.map +1 -0
  73. package/build/tools/get-announcements.js +104 -0
  74. package/build/tools/get-announcements.js.map +1 -0
  75. package/build/tools/get-assignments.d.ts +13 -0
  76. package/build/tools/get-assignments.d.ts.map +1 -0
  77. package/build/tools/get-assignments.js +241 -0
  78. package/build/tools/get-assignments.js.map +1 -0
  79. package/build/tools/get-classlist-emails.d.ts +12 -0
  80. package/build/tools/get-classlist-emails.d.ts.map +1 -0
  81. package/build/tools/get-classlist-emails.js +48 -0
  82. package/build/tools/get-classlist-emails.js.map +1 -0
  83. package/build/tools/get-course-content.d.ts +12 -0
  84. package/build/tools/get-course-content.d.ts.map +1 -0
  85. package/build/tools/get-course-content.js +190 -0
  86. package/build/tools/get-course-content.js.map +1 -0
  87. package/build/tools/get-discussions.d.ts +12 -0
  88. package/build/tools/get-discussions.d.ts.map +1 -0
  89. package/build/tools/get-discussions.js +212 -0
  90. package/build/tools/get-discussions.js.map +1 -0
  91. package/build/tools/get-my-courses.d.ts +13 -0
  92. package/build/tools/get-my-courses.d.ts.map +1 -0
  93. package/build/tools/get-my-courses.js +51 -0
  94. package/build/tools/get-my-courses.js.map +1 -0
  95. package/build/tools/get-my-grades.d.ts +13 -0
  96. package/build/tools/get-my-grades.d.ts.map +1 -0
  97. package/build/tools/get-my-grades.js +100 -0
  98. package/build/tools/get-my-grades.js.map +1 -0
  99. package/build/tools/get-roster.d.ts +12 -0
  100. package/build/tools/get-roster.d.ts.map +1 -0
  101. package/build/tools/get-roster.js +108 -0
  102. package/build/tools/get-roster.js.map +1 -0
  103. package/build/tools/get-syllabus.d.ts +12 -0
  104. package/build/tools/get-syllabus.d.ts.map +1 -0
  105. package/build/tools/get-syllabus.js +162 -0
  106. package/build/tools/get-syllabus.js.map +1 -0
  107. package/build/tools/get-upcoming-due-dates.d.ts +13 -0
  108. package/build/tools/get-upcoming-due-dates.d.ts.map +1 -0
  109. package/build/tools/get-upcoming-due-dates.js +74 -0
  110. package/build/tools/get-upcoming-due-dates.js.map +1 -0
  111. package/build/tools/index.d.ts +19 -0
  112. package/build/tools/index.d.ts.map +1 -0
  113. package/build/tools/index.js +21 -0
  114. package/build/tools/index.js.map +1 -0
  115. package/build/tools/schemas.d.ts +66 -0
  116. package/build/tools/schemas.d.ts.map +1 -0
  117. package/build/tools/schemas.js +80 -0
  118. package/build/tools/schemas.js.map +1 -0
  119. package/build/tools/tool-helpers.d.ts +21 -0
  120. package/build/tools/tool-helpers.d.ts.map +1 -0
  121. package/build/tools/tool-helpers.js +70 -0
  122. package/build/tools/tool-helpers.js.map +1 -0
  123. package/build/types/index.d.ts +48 -0
  124. package/build/types/index.d.ts.map +1 -0
  125. package/build/types/index.js +7 -0
  126. package/build/types/index.js.map +1 -0
  127. package/build/update.d.ts +10 -0
  128. package/build/update.d.ts.map +1 -0
  129. package/build/update.js +130 -0
  130. package/build/update.js.map +1 -0
  131. package/build/utils/config-store.d.ts +23 -0
  132. package/build/utils/config-store.d.ts.map +1 -0
  133. package/build/utils/config-store.js +29 -0
  134. package/build/utils/config-store.js.map +1 -0
  135. package/build/utils/config.d.ts +9 -0
  136. package/build/utils/config.d.ts.map +1 -0
  137. package/build/utils/config.js +66 -0
  138. package/build/utils/config.js.map +1 -0
  139. package/build/utils/course-filter.d.ts +24 -0
  140. package/build/utils/course-filter.d.ts.map +1 -0
  141. package/build/utils/course-filter.js +39 -0
  142. package/build/utils/course-filter.js.map +1 -0
  143. package/build/utils/download-helpers.d.ts +31 -0
  144. package/build/utils/download-helpers.d.ts.map +1 -0
  145. package/build/utils/download-helpers.js +93 -0
  146. package/build/utils/download-helpers.js.map +1 -0
  147. package/build/utils/errors.d.ts +21 -0
  148. package/build/utils/errors.d.ts.map +1 -0
  149. package/build/utils/errors.js +36 -0
  150. package/build/utils/errors.js.map +1 -0
  151. package/build/utils/file-validator.d.ts +56 -0
  152. package/build/utils/file-validator.d.ts.map +1 -0
  153. package/build/utils/file-validator.js +134 -0
  154. package/build/utils/file-validator.js.map +1 -0
  155. package/build/utils/html-converter.d.ts +17 -0
  156. package/build/utils/html-converter.d.ts.map +1 -0
  157. package/build/utils/html-converter.js +36 -0
  158. package/build/utils/html-converter.js.map +1 -0
  159. package/build/utils/logger.d.ts +10 -0
  160. package/build/utils/logger.d.ts.map +1 -0
  161. package/build/utils/logger.js +42 -0
  162. package/build/utils/logger.js.map +1 -0
  163. package/build/utils/pdf-extractor.d.ts +14 -0
  164. package/build/utils/pdf-extractor.d.ts.map +1 -0
  165. package/build/utils/pdf-extractor.js +27 -0
  166. package/build/utils/pdf-extractor.js.map +1 -0
  167. package/build/utils/update-checker.d.ts +8 -0
  168. package/build/utils/update-checker.d.ts.map +1 -0
  169. package/build/utils/update-checker.js +33 -0
  170. package/build/utils/update-checker.js.map +1 -0
  171. 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"}