brightspace-mcp-server 5.1.32 → 5.1.33

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.
@@ -21,6 +21,15 @@ const TEACHING_ROLE_NAME = /\b(instructor|professor|lecturer|teaching assistant|
21
21
  function isTeachingRoleByName(user) {
22
22
  return TEACHING_ROLE_NAME.test(user.ClasslistRoleDisplayName ?? "");
23
23
  }
24
+ /**
25
+ * Whether a failed role route must be reported rather than skipped. A 403
26
+ * means the classlist is restricted for that role: nothing was missed.
27
+ * Anything else (a 404, a 5xx, a dropped connection) leaves a hole the caller
28
+ * would read as "this course has no TAs".
29
+ */
30
+ function isReportableFailure(error) {
31
+ return error?.status !== 403;
32
+ }
24
33
  /**
25
34
  * Fetch every classlist user matching the optional filters, across all pages.
26
35
  *
@@ -60,6 +69,7 @@ export function registerGetRoster(server, apiClient) {
60
69
  const allUsers = [];
61
70
  let authFailure;
62
71
  let roleFallbackUsed = false;
72
+ let unavailable = [];
63
73
  if (!includeStudents) {
64
74
  // Fetch instructors and TAs in parallel
65
75
  const [instructorResult, taResult] = await Promise.allSettled([
@@ -87,6 +97,10 @@ export function registerGetRoster(server, apiClient) {
87
97
  allUsers.push(...instructorResult.value);
88
98
  }
89
99
  else {
100
+ if (!isAuthUnavailable(instructorResult.reason) &&
101
+ isReportableFailure(instructorResult.reason)) {
102
+ unavailable.push("instructors");
103
+ }
90
104
  log("WARN", "get_roster: Failed to fetch instructors", {
91
105
  error: instructorResult.reason,
92
106
  });
@@ -95,6 +109,9 @@ export function registerGetRoster(server, apiClient) {
95
109
  allUsers.push(...taResult.value);
96
110
  }
97
111
  else {
112
+ if (!isAuthUnavailable(taResult.reason) && isReportableFailure(taResult.reason)) {
113
+ unavailable.push("TAs");
114
+ }
98
115
  log("WARN", "get_roster: Failed to fetch TAs", {
99
116
  error: taResult.reason,
100
117
  });
@@ -112,6 +129,9 @@ export function registerGetRoster(server, apiClient) {
112
129
  });
113
130
  allUsers.push(...everyone.filter(isTeachingRoleByName));
114
131
  roleFallbackUsed = true;
132
+ // The unfiltered fetch covered every role, so nothing the
133
+ // failed role routes would have returned is missing any more.
134
+ unavailable = [];
115
135
  }
116
136
  }
117
137
  else {
@@ -139,6 +159,17 @@ export function registerGetRoster(server, apiClient) {
139
159
  }));
140
160
  log("INFO", `get_roster: Retrieved ${users.length} users for course ${courseId}` +
141
161
  (authFailure ? " (sign-in pending for one route)" : ""));
162
+ const notices = [];
163
+ if (unavailable.length > 0) {
164
+ notices.push(`The ${unavailable.join(" and ")} for this course could not be read from ` +
165
+ "Brightspace, so they may be missing from this list. Do not report this " +
166
+ `course as having no ${unavailable.join(" or ")}; call get_roster again to retry.`);
167
+ }
168
+ if (authFailure) {
169
+ notices.push("Sign-in to Brightspace is still in progress, so part of the roster for this " +
170
+ `course could not be fetched yet. ${authPendingNotice(authFailure.reason)} Call ` +
171
+ "get_roster again once sign-in finishes.");
172
+ }
142
173
  return toolResponse({
143
174
  courseId,
144
175
  total,
@@ -153,14 +184,9 @@ export function registerGetRoster(server, apiClient) {
153
184
  }
154
185
  : {}),
155
186
  users,
156
- ...(authFailure
157
- ? {
158
- authPending: true,
159
- notice: "Sign-in to Brightspace is still in progress, so part of the roster for this " +
160
- `course could not be fetched yet. ${authPendingNotice(authFailure.reason)} Call ` +
161
- "get_roster again once sign-in finishes.",
162
- }
163
- : {}),
187
+ ...(unavailable.length > 0 ? { unavailable } : {}),
188
+ ...(authFailure ? { authPending: true } : {}),
189
+ ...(notices.length > 0 ? { notice: notices.join(" ") } : {}),
164
190
  });
165
191
  }
166
192
  catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brightspace-mcp-server",
3
- "version": "5.1.32",
3
+ "version": "5.1.33",
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",