brightspace-mcp-server 3.9.2 → 3.9.3

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/README.md CHANGED
@@ -178,6 +178,21 @@ If this is a Docker or other headless setup with no `~/.brightspace-mcp/config.j
178
178
  | Calendar | "When is my midterm?" · "What's on my calendar this week?" · "Is lab cancelled on Thursday?" — reads exams, labs, review sessions, and deadlines instructors put only on the course calendar |
179
179
  | Planning | "Build me a study schedule based on my upcoming due dates" · "Which class needs the most attention right now?" — pulls from assignments, quizzes, graded discussion topics (any topic with a due date), and course calendar events such as exams and labs |
180
180
 
181
+ ### Prompts
182
+
183
+ Clients that show server-provided prompts (e.g. Claude Desktop's prompt picker) can also start from one of
184
+ four canned prompts instead of typing a question from scratch:
185
+
186
+ | Prompt | Arguments | What it asks for |
187
+ |--------|-----------|-------------------|
188
+ | `weekly_briefing` | — | A 7-day rollup of what's due, what's new, and what's changed in grades, across every course |
189
+ | `grade_audit` | `courseId` (optional) | Analyzes grades for one course, or all of them, and flags missing or low-scoring items |
190
+ | `study_planner` | `daysAhead` (optional, default 7) | Plans study time from upcoming due dates and calendar events |
191
+ | `course_summary` | `courseId` (required) | Syllabus, content outline, assignments, and grades for one course |
192
+
193
+ Each prompt is a single starter message built from the tools above — it doesn't add any new capability on
194
+ its own, just a one-click way to ask for a common combination of them.
195
+
181
196
  `get_course_content` reports `isAvailable`, `availabilityStatus` (`available`, `not_yet_open`, `ended`, `hidden`, or `locked`), `availabilityMessage`, `startDate`, and `endDate` for modules and topics. The effective release window includes restrictions inherited from enclosing modules.
182
197
 
183
198
  When a content-file download returns 403 or 404, `download_file` checks topic metadata and the course table of contents. Confirmed restrictions return `{ success: false, available: false, reason, message, startDate, endDate }` so the assistant can explain when content opens or why it has closed. Unexplained 404s and server/network failures retain their original errors.
package/build/index.js CHANGED
@@ -17,6 +17,7 @@ import { readFileSync } from "node:fs";
17
17
  import { fileURLToPath } from "node:url";
18
18
  import { dirname, resolve } from "node:path";
19
19
  import { registerGetMyCourses, registerGetUpcomingDueDates, registerGetCalendarEvents, registerGetMyGrades, registerGetAnnouncements, registerGetAssignments, registerGetAssignmentFiles, registerGetAnnouncementFiles, registerGetCourseContent, registerDownloadFile, registerGetClasslistEmails, registerGetRoster, registerGetSyllabus, registerGetDiscussions, registerGetVideoTranscript, registerGetServerInfo, } from "./tools/index.js";
20
+ import { registerWeeklyBriefingPrompt, registerGradeAuditPrompt, registerStudyPlannerPrompt, registerCourseSummaryPrompt, } from "./prompts/index.js";
20
21
  const __filename = fileURLToPath(import.meta.url);
21
22
  const __dirname = dirname(__filename);
22
23
  const PKG_VERSION = (() => {
@@ -132,10 +133,19 @@ else {
132
133
  registerGetVideoTranscript(server, apiClient);
133
134
  registerGetServerInfo(server, config, PKG_VERSION, apiClient);
134
135
  log("DEBUG", "MCP tools registered (16 tools)");
136
+ // Register MCP prompts — surfaced in clients (e.g. Claude Desktop) as a
137
+ // picker, distinct from tools. Each one is a canned user message that
138
+ // names our own tools by name, so a client with no idea what to ask
139
+ // for still gets a one-click starting point.
140
+ registerWeeklyBriefingPrompt(server);
141
+ registerGradeAuditPrompt(server);
142
+ registerStudyPlannerPrompt(server);
143
+ registerCourseSummaryPrompt(server);
144
+ log("DEBUG", "MCP prompts registered (4 prompts)");
135
145
  // Connect stdio transport
136
146
  const transport = new StdioServerTransport();
137
147
  await server.connect(transport);
138
- log("INFO", "Brightspace MCP Server by Rohan Muppa — running on stdio (16 tools registered)");
148
+ log("INFO", "Brightspace MCP Server by Rohan Muppa — running on stdio (16 tools, 4 prompts registered)");
139
149
  log("INFO", "Setup: see README.md for MCP client configuration (Claude Desktop, ChatGPT Desktop, Cursor, etc.)");
140
150
  }
141
151
  catch (error) {
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Purdue Brightspace MCP Server
3
+ * Copyright (c) 2026 Rohan Muppa. All rights reserved.
4
+ * Licensed under MIT — see LICENSE file for details.
5
+ */
6
+ import { z } from "zod";
7
+ /**
8
+ * Register the course_summary prompt.
9
+ *
10
+ * `courseId` is required — unlike the other three prompts this one is
11
+ * always about exactly one course, so there is no sensible "all courses"
12
+ * fallback the way get_my_grades or get_assignments have.
13
+ */
14
+ export function registerCourseSummaryPrompt(server) {
15
+ server.registerPrompt("course_summary", {
16
+ title: "Course Summary",
17
+ description: "A one-course rollup: syllabus, content outline, assignments, and current grades.",
18
+ argsSchema: {
19
+ courseId: z.coerce
20
+ .number()
21
+ .int()
22
+ .positive()
23
+ .describe("Course ID to summarize."),
24
+ },
25
+ }, async (args) => ({
26
+ messages: [
27
+ {
28
+ role: "user",
29
+ content: {
30
+ type: "text",
31
+ text: `Give me a summary of course ${args.courseId}. Call get_syllabus for the course ` +
32
+ `description and policies, get_course_content for the module and topic outline, ` +
33
+ `get_assignments for what's assigned and its due dates and submission status, and ` +
34
+ `get_my_grades for where I currently stand. Pull it together into one summary: what ` +
35
+ "the course covers, how it's structured, what's outstanding, and how my grades look " +
36
+ "so far.",
37
+ },
38
+ },
39
+ ],
40
+ }));
41
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Purdue Brightspace MCP Server
3
+ * Copyright (c) 2026 Rohan Muppa. All rights reserved.
4
+ * Licensed under MIT — see LICENSE file for details.
5
+ */
6
+ import { z } from "zod";
7
+ /**
8
+ * Register the grade_audit prompt.
9
+ *
10
+ * `courseId` is optional, same as the tools it drives (get_my_grades,
11
+ * get_assignments): omitted, it audits every enrolled course at once.
12
+ */
13
+ export function registerGradeAuditPrompt(server) {
14
+ server.registerPrompt("grade_audit", {
15
+ title: "Grade Audit",
16
+ description: "Analyze grades for one course or all of them, flagging missing, ungraded, or low-scoring items.",
17
+ argsSchema: {
18
+ courseId: z.coerce
19
+ .number()
20
+ .int()
21
+ .positive()
22
+ .optional()
23
+ .describe("Course ID to audit. If omitted, audits every enrolled course."),
24
+ },
25
+ }, async (args) => {
26
+ const scope = args.courseId !== undefined
27
+ ? `course ${args.courseId}`
28
+ : "every enrolled course";
29
+ const courseArg = args.courseId !== undefined ? `courseId: ${args.courseId}` : "no courseId (all courses)";
30
+ return {
31
+ messages: [
32
+ {
33
+ role: "user",
34
+ content: {
35
+ type: "text",
36
+ text: `Audit my grades for ${scope}. Call get_my_grades with ${courseArg} and ` +
37
+ `get_assignments with ${courseArg} and cross-reference them: flag any assignment ` +
38
+ "or quiz with no grade posted yet, anything graded well below the class or my own " +
39
+ "average, and any gradebook column from get_my_grades that matches no assignment " +
40
+ "(a gradeOnly item, such as a proctored exam). If no courseId was given, first call " +
41
+ "get_my_courses so you can label every finding with its course name, and summarize " +
42
+ "per course before giving an overall picture.",
43
+ },
44
+ },
45
+ ],
46
+ };
47
+ });
48
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Purdue Brightspace MCP Server
3
+ * Copyright (c) 2026 Rohan Muppa. All rights reserved.
4
+ * Licensed under MIT — see LICENSE file for details.
5
+ */
6
+ // Prompt registration functions - barrel export
7
+ export { registerWeeklyBriefingPrompt } from "./weekly-briefing.js";
8
+ export { registerGradeAuditPrompt } from "./grade-audit.js";
9
+ export { registerStudyPlannerPrompt } from "./study-planner.js";
10
+ export { registerCourseSummaryPrompt } from "./course-summary.js";
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Purdue Brightspace MCP Server
3
+ * Copyright (c) 2026 Rohan Muppa. All rights reserved.
4
+ * Licensed under MIT — see LICENSE file for details.
5
+ */
6
+ import { z } from "zod";
7
+ /**
8
+ * Register the study_planner prompt.
9
+ *
10
+ * `daysAhead` mirrors get_upcoming_due_dates' own argument (same name,
11
+ * same default) so the window the user asks about and the window the
12
+ * underlying tool call uses never drift apart.
13
+ */
14
+ export function registerStudyPlannerPrompt(server) {
15
+ server.registerPrompt("study_planner", {
16
+ title: "Study Planner",
17
+ description: "Plan study time from upcoming due dates and calendar events over the next N days (default 7).",
18
+ argsSchema: {
19
+ // .optional() (not just .default()) keeps this argument out of the
20
+ // "required" list in prompts/list — a bare .default() still shows up
21
+ // as required there even though a missing value falls back fine.
22
+ daysAhead: z.coerce
23
+ .number()
24
+ .int()
25
+ .min(1)
26
+ .max(90)
27
+ .optional()
28
+ .describe("Number of days ahead to plan for. Defaults to 7."),
29
+ },
30
+ }, async (args) => {
31
+ // args is undefined when the SDK's no-args path reaches this callback
32
+ // for all-optional schemas; args.daysAhead is undefined when the field
33
+ // itself was omitted. Either way, fall back to 7.
34
+ const days = args?.daysAhead ?? 7;
35
+ return {
36
+ messages: [
37
+ {
38
+ role: "user",
39
+ content: {
40
+ type: "text",
41
+ text: `Build me a study plan for the next ${days} days. Call ` +
42
+ `get_upcoming_due_dates with daysAhead: ${days} for assignments, quizzes, ` +
43
+ `and discussion due dates, and get_calendar_events for the same window to pick up ` +
44
+ "exams, labs, and other scheduled events. Group the work by day, put the heaviest or " +
45
+ "most time-sensitive items earliest, leave a buffer day before anything that looks " +
46
+ "like an exam, and call out any day with more due than looks reasonable to finish.",
47
+ },
48
+ },
49
+ ],
50
+ };
51
+ });
52
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Purdue Brightspace MCP Server
3
+ * Copyright (c) 2026 Rohan Muppa. All rights reserved.
4
+ * Licensed under MIT — see LICENSE file for details.
5
+ */
6
+ /**
7
+ * Register the weekly_briefing prompt.
8
+ *
9
+ * Takes no arguments: it asks for a rolled-up status of the coming week
10
+ * across every enrolled course, which is exactly the kind of thing a user
11
+ * opens their client just to ask, every Monday, without typing it out.
12
+ */
13
+ export function registerWeeklyBriefingPrompt(server) {
14
+ server.registerPrompt("weekly_briefing", {
15
+ title: "Weekly Briefing",
16
+ description: "A 7-day rollup of what's due, what's new, and what's changed in grades across every enrolled course.",
17
+ // No argsSchema: this prompt takes no arguments. An empty `argsSchema: {}`
18
+ // would make the SDK validate `request.params.arguments` against
19
+ // z.object({}), which rejects a GetPrompt call that omits `arguments`
20
+ // entirely (some MCP clients do). Omitting argsSchema takes the SDK's
21
+ // no-args path instead, which accepts both a missing and an empty
22
+ // `arguments` field.
23
+ }, async () => ({
24
+ messages: [
25
+ {
26
+ role: "user",
27
+ content: {
28
+ type: "text",
29
+ text: "Give me a briefing for the next 7 days across all my Brightspace courses. " +
30
+ "Use get_upcoming_due_dates (daysAhead: 7) for what's due, get_calendar_events " +
31
+ "(the next 7 days) for exams, labs, and other scheduled events, " +
32
+ "get_announcements (modifiedSince: 7 days ago) for anything new course staff " +
33
+ "posted, and get_my_grades to call out any grade that changed or any item that " +
34
+ "newly posted a score. Organize the result by course, lead with anything due in " +
35
+ "the next 48 hours, and flag announcements or grade changes that need a reply or " +
36
+ "a decision from me.",
37
+ },
38
+ },
39
+ ],
40
+ }));
41
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brightspace-mcp-server",
3
- "version": "3.9.2",
3
+ "version": "3.9.3",
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",