brightspace-mcp-server 3.12.0 → 3.12.1
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/build/api/paginate.js
CHANGED
|
@@ -48,6 +48,7 @@ export async function fetchAllItems(apiClient, firstPath, options) {
|
|
|
48
48
|
}
|
|
49
49
|
/**
|
|
50
50
|
* Every object across every page of a { Objects, Next } endpoint, in order.
|
|
51
|
+
* A bare array response is taken as the complete list.
|
|
51
52
|
*
|
|
52
53
|
* Next arrives either as a full next-page URL or as a bare bookmark, so the
|
|
53
54
|
* absolute form is reduced to its path and query and anything else is treated
|
|
@@ -65,6 +66,11 @@ export async function fetchAllObjects(apiClient, firstPath, options) {
|
|
|
65
66
|
}
|
|
66
67
|
const response = await apiClient.get(path, options);
|
|
67
68
|
pages += 1;
|
|
69
|
+
// Some tenants answer a paged route with a bare array: that is the whole list.
|
|
70
|
+
if (Array.isArray(response)) {
|
|
71
|
+
objects.push(...response);
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
68
74
|
objects.push(...(response?.Objects ?? []));
|
|
69
75
|
const next = response?.Next;
|
|
70
76
|
if (!next)
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Licensed under MIT — see LICENSE file for details.
|
|
5
5
|
*/
|
|
6
6
|
import { DEFAULT_CACHE_TTLS } from "../api/index.js";
|
|
7
|
-
import { fetchAllItems } from "../api/paginate.js";
|
|
7
|
+
import { fetchAllItems, fetchAllObjects } from "../api/paginate.js";
|
|
8
8
|
import { GetAssignmentsSchema } from "./schemas.js";
|
|
9
9
|
import { toolResponse, sanitizeError, isAuthUnavailable, authPendingNotice } from "./tool-helpers.js";
|
|
10
10
|
import { convertHtmlToMarkdown } from "../utils/html-converter.js";
|
|
@@ -110,7 +110,10 @@ export async function fetchCourseAssignments(apiClient, courseId, baseUrl) {
|
|
|
110
110
|
// cannot be made until they have answered.
|
|
111
111
|
const [dropboxResult, quizResult, gradebookResult, contentResult] = await Promise.allSettled([
|
|
112
112
|
apiClient.get(apiClient.le(courseId, "/dropbox/folders/"), { ttl: DEFAULT_CACHE_TTLS.assignments }),
|
|
113
|
-
|
|
113
|
+
// Quizzes are paged; a course with many of them spills past page one.
|
|
114
|
+
fetchAllObjects(apiClient, apiClient.le(courseId, "/quizzes/"), {
|
|
115
|
+
ttl: DEFAULT_CACHE_TTLS.assignments,
|
|
116
|
+
}),
|
|
114
117
|
apiClient.get(apiClient.le(courseId, "/grades/"), {
|
|
115
118
|
ttl: DEFAULT_CACHE_TTLS.assignments,
|
|
116
119
|
}),
|
|
@@ -263,11 +266,7 @@ export async function fetchCourseAssignments(apiClient, courseId, baseUrl) {
|
|
|
263
266
|
// forbidden or unavailable, so a failed list starts from an empty set.
|
|
264
267
|
let quizzes = [];
|
|
265
268
|
if (quizResult.status === "fulfilled") {
|
|
266
|
-
|
|
267
|
-
// D2L quizzes API returns paged result { Objects: [...] } or a plain array
|
|
268
|
-
quizzes = Array.isArray(quizResponse)
|
|
269
|
-
? quizResponse
|
|
270
|
-
: quizResponse?.Objects ?? [];
|
|
269
|
+
quizzes = quizResult.value;
|
|
271
270
|
}
|
|
272
271
|
else {
|
|
273
272
|
log("DEBUG", `Failed to fetch quizzes for course ${courseId}`, quizResult.reason);
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Licensed under MIT — see LICENSE file for details.
|
|
5
5
|
*/
|
|
6
6
|
import { DEFAULT_CACHE_TTLS } from "../api/index.js";
|
|
7
|
-
import { fetchAllItems } from "../api/paginate.js";
|
|
7
|
+
import { fetchAllItems, fetchAllObjects } from "../api/paginate.js";
|
|
8
8
|
import { GetMyGradesSchema, } from "./schemas.js";
|
|
9
9
|
import { toolResponse, sanitizeError, errorResponse, isAuthUnavailable, authPendingNotice, } from "./tool-helpers.js";
|
|
10
10
|
import { log } from "../utils/logger.js";
|
|
@@ -27,8 +27,10 @@ const QUIZ_FEEDBACK_NOTE = "The gradebook has no comment for this item, but it i
|
|
|
27
27
|
*/
|
|
28
28
|
async function fetchQuizzes(apiClient, courseId) {
|
|
29
29
|
try {
|
|
30
|
-
|
|
31
|
-
return
|
|
30
|
+
// Quizzes are paged; a course with many of them spills past page one.
|
|
31
|
+
return await fetchAllObjects(apiClient, apiClient.le(courseId, "/quizzes/"), {
|
|
32
|
+
ttl: DEFAULT_CACHE_TTLS.assignments,
|
|
33
|
+
});
|
|
32
34
|
}
|
|
33
35
|
catch (error) {
|
|
34
36
|
log("DEBUG", `get_my_grades: quiz list unavailable for course ${courseId}`, error);
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Licensed under MIT — see LICENSE file for details.
|
|
5
5
|
*/
|
|
6
6
|
import { DEFAULT_CACHE_TTLS } from "../api/index.js";
|
|
7
|
+
import { fetchAllObjects } from "../api/paginate.js";
|
|
7
8
|
import { GetUpcomingDueDatesSchema, } from "./schemas.js";
|
|
8
9
|
import { toolResponse, toolResponseWithNotice, sanitizeError, isAuthUnavailable, authPendingNotice } from "./tool-helpers.js";
|
|
9
10
|
import { log } from "../utils/logger.js";
|
|
@@ -78,7 +79,10 @@ function calendarItems(events, items) {
|
|
|
78
79
|
async function fetchCourseDueItems(apiClient, baseUrl, course, from, to) {
|
|
79
80
|
const [dropboxResult, quizResult, discussionResult, calendarResult] = await Promise.allSettled([
|
|
80
81
|
apiClient.get(apiClient.le(course.id, "/dropbox/folders/"), { ttl: DEFAULT_CACHE_TTLS.assignments }),
|
|
81
|
-
|
|
82
|
+
// Quizzes are paged; a course with many of them spills past page one.
|
|
83
|
+
fetchAllObjects(apiClient, apiClient.le(course.id, "/quizzes/"), {
|
|
84
|
+
ttl: DEFAULT_CACHE_TTLS.assignments,
|
|
85
|
+
}),
|
|
82
86
|
fetchDiscussionDueTopics(apiClient, course.id),
|
|
83
87
|
fetchCourseCalendarEvents(apiClient, baseUrl, course, from, to),
|
|
84
88
|
]);
|
|
@@ -117,7 +121,7 @@ async function fetchCourseDueItems(apiClient, baseUrl, course, from, to) {
|
|
|
117
121
|
log("DEBUG", `get_upcoming_due_dates: failed to fetch dropbox folders for course ${course.id}`, dropboxResult.reason);
|
|
118
122
|
}
|
|
119
123
|
if (quizResult.status === "fulfilled") {
|
|
120
|
-
for (const quiz of
|
|
124
|
+
for (const quiz of quizResult.value) {
|
|
121
125
|
if (quiz.IsActive === false)
|
|
122
126
|
continue;
|
|
123
127
|
// Many instructors set only an End Date, which is the effective deadline.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brightspace-mcp-server",
|
|
3
|
-
"version": "3.12.
|
|
3
|
+
"version": "3.12.1",
|
|
4
4
|
"mcpName": "io.github.RohanMuppa/brightspace",
|
|
5
5
|
"description": "MCP server for Brightspace (D2L). Check grades, due dates, assignments, announcements, syllabus, rosters and more via Claude, ChatGPT, Cursor, Windsurf, or any MCP client.",
|
|
6
6
|
"type": "module",
|