brightspace-mcp-server 4.0.4 → 4.0.6
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.
|
@@ -86,21 +86,23 @@ export function registerGetDropboxSubmissions(server, apiClient) {
|
|
|
86
86
|
const truncated = total > limit;
|
|
87
87
|
const kept = truncated ? rawSubmissions.slice(0, limit) : rawSubmissions;
|
|
88
88
|
// Optionally fetch feedback for each kept submitter, a bounded
|
|
89
|
-
// number at a time.
|
|
90
|
-
// simply has none in the map.
|
|
89
|
+
// number at a time. A 404 means no feedback yet, so that submitter
|
|
90
|
+
// simply has none in the map. Any other failure leaves their grading
|
|
91
|
+
// status unknown rather than "not graded", and the note names them.
|
|
91
92
|
const feedbackMap = new Map();
|
|
93
|
+
const feedbackUnread = new Set();
|
|
92
94
|
if (!ignoreFeedback) {
|
|
93
95
|
await mapWithConcurrency(kept, FEEDBACK_FETCH_CONCURRENCY, async (sub) => {
|
|
96
|
+
const userId = sub.SubmittedBy.Identifier;
|
|
94
97
|
try {
|
|
95
|
-
const userId = sub.SubmittedBy.Identifier;
|
|
96
98
|
const feedbackPath = apiClient.le(courseId, `/dropbox/folders/${folderId}/feedback/user/${userId}`);
|
|
97
99
|
const fb = await apiClient.get(feedbackPath);
|
|
98
100
|
feedbackMap.set(userId, fb);
|
|
99
101
|
}
|
|
100
|
-
catch {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
catch (error) {
|
|
103
|
+
if (!(error instanceof ApiError && error.status === 404)) {
|
|
104
|
+
feedbackUnread.add(userId);
|
|
105
|
+
}
|
|
104
106
|
}
|
|
105
107
|
});
|
|
106
108
|
}
|
|
@@ -125,21 +127,41 @@ export function registerGetDropboxSubmissions(server, apiClient) {
|
|
|
125
127
|
comment: sub.Comment?.Text ?? null,
|
|
126
128
|
};
|
|
127
129
|
if (!ignoreFeedback) {
|
|
128
|
-
entry.feedbackStatus =
|
|
129
|
-
?
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
130
|
+
entry.feedbackStatus = feedbackUnread.has(userId)
|
|
131
|
+
? null
|
|
132
|
+
: feedback
|
|
133
|
+
? {
|
|
134
|
+
isGraded: feedback.IsGraded,
|
|
135
|
+
score: feedback.Score,
|
|
136
|
+
maxScore,
|
|
137
|
+
hasFeedbackText: !!feedback.Feedback?.Text,
|
|
138
|
+
}
|
|
139
|
+
: { isGraded: false, score: null, maxScore, hasFeedbackText: false };
|
|
136
140
|
}
|
|
137
141
|
return entry;
|
|
138
142
|
});
|
|
139
|
-
// activeOnly: skip submissions that are already fully graded.
|
|
143
|
+
// activeOnly: skip submissions that are already fully graded. One
|
|
144
|
+
// whose feedback couldn't be read stays, since it may still need grading.
|
|
140
145
|
const filtered = activeOnly && !ignoreFeedback
|
|
141
146
|
? submissions.filter((s) => !s.feedbackStatus?.isGraded)
|
|
142
147
|
: submissions;
|
|
148
|
+
const unreadNames = kept
|
|
149
|
+
.filter((sub) => feedbackUnread.has(sub.SubmittedBy.Identifier))
|
|
150
|
+
.map((sub) => `"${sub.SubmittedBy.DisplayName || sub.SubmittedBy.Identifier}"`);
|
|
151
|
+
if (unreadNames.length > 0) {
|
|
152
|
+
log("INFO", "get_dropbox_submissions: Some submitters' feedback could not be read", {
|
|
153
|
+
courseId,
|
|
154
|
+
folderId,
|
|
155
|
+
userIds: [...feedbackUnread],
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
const notes = [
|
|
159
|
+
...(truncated ? [`Showing ${kept.length} of ${total} submissions. Raise the limit argument to see more.`] : []),
|
|
160
|
+
...(unreadNames.length > 0
|
|
161
|
+
? [`Couldn't read the feedback for ${unreadNames.join(", ")}, so whether they are graded is unknown ` +
|
|
162
|
+
"(feedbackStatus is null)."]
|
|
163
|
+
: []),
|
|
164
|
+
];
|
|
143
165
|
log("INFO", `get_dropbox_submissions: ${filtered.length} submissions (of ${total} total) for folder ${folderId}`, { truncated });
|
|
144
166
|
return toolResponse({
|
|
145
167
|
courseId,
|
|
@@ -150,9 +172,7 @@ export function registerGetDropboxSubmissions(server, apiClient) {
|
|
|
150
172
|
totalSubmissions: total,
|
|
151
173
|
returnedSubmissions: filtered.length,
|
|
152
174
|
truncated,
|
|
153
|
-
...(
|
|
154
|
-
? { note: `Showing ${kept.length} of ${total} submissions. Raise the limit argument to see more.` }
|
|
155
|
-
: {}),
|
|
175
|
+
...(notes.length > 0 ? { note: notes.join(" ") } : {}),
|
|
156
176
|
activeOnly,
|
|
157
177
|
submissions: filtered,
|
|
158
178
|
});
|
|
@@ -55,14 +55,20 @@ export function registerGetDropboxUserSubmissions(server, apiClient) {
|
|
|
55
55
|
note: "No submissions found for this user in the specified folder.",
|
|
56
56
|
});
|
|
57
57
|
}
|
|
58
|
+
// A 404 means no feedback yet, matching the "not graded yet" default
|
|
59
|
+
// below. Any other failure leaves the grading status unknown.
|
|
58
60
|
let feedback = null;
|
|
61
|
+
let feedbackUnread = false;
|
|
59
62
|
if (!ignoreFeedback) {
|
|
60
63
|
try {
|
|
61
64
|
const feedbackPath = apiClient.le(courseId, `/dropbox/folders/${folderId}/feedback/user/${userId}`);
|
|
62
65
|
feedback = await apiClient.get(feedbackPath);
|
|
63
66
|
}
|
|
64
|
-
catch {
|
|
65
|
-
|
|
67
|
+
catch (error) {
|
|
68
|
+
if (!(error instanceof ApiError && error.status === 404)) {
|
|
69
|
+
feedbackUnread = true;
|
|
70
|
+
log("INFO", "get_dropbox_user_submissions: Feedback could not be read", { courseId, folderId, userId });
|
|
71
|
+
}
|
|
66
72
|
}
|
|
67
73
|
}
|
|
68
74
|
const submissions = rawSubmissions.map((sub) => ({
|
|
@@ -79,14 +85,16 @@ export function registerGetDropboxUserSubmissions(server, apiClient) {
|
|
|
79
85
|
}));
|
|
80
86
|
const feedbackStatus = ignoreFeedback
|
|
81
87
|
? undefined
|
|
82
|
-
:
|
|
83
|
-
?
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
: feedbackUnread
|
|
89
|
+
? null
|
|
90
|
+
: feedback
|
|
91
|
+
? {
|
|
92
|
+
isGraded: feedback.IsGraded,
|
|
93
|
+
score: feedback.Score,
|
|
94
|
+
hasFeedbackText: !!feedback.Feedback?.Text,
|
|
95
|
+
feedbackText: feedback.Feedback?.Text ?? null,
|
|
96
|
+
}
|
|
97
|
+
: { isGraded: false, score: null, hasFeedbackText: false, feedbackText: null };
|
|
90
98
|
log("INFO", `get_dropbox_user_submissions: ${submissions.length} submissions for user ${userId} in folder ${folderId}`);
|
|
91
99
|
return toolResponse({
|
|
92
100
|
courseId,
|
|
@@ -94,6 +102,9 @@ export function registerGetDropboxUserSubmissions(server, apiClient) {
|
|
|
94
102
|
userId,
|
|
95
103
|
submissions,
|
|
96
104
|
feedbackStatus,
|
|
105
|
+
...(feedbackUnread
|
|
106
|
+
? { note: "Couldn't read this user's feedback, so whether this submission is graded is unknown (feedbackStatus is null)." }
|
|
107
|
+
: {}),
|
|
97
108
|
});
|
|
98
109
|
}
|
|
99
110
|
catch (error) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brightspace-mcp-server",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.6",
|
|
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",
|