brightspace-mcp-server 1.6.0 → 1.6.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/README.md
CHANGED
|
@@ -85,7 +85,8 @@ npx brightspace-mcp-server auth
|
|
|
85
85
|
|-------|---------|
|
|
86
86
|
| Grades | "Am I passing all my classes?" · "Compare my grades across all courses" |
|
|
87
87
|
| Assignments | "What's due in the next 48 hours?" · "Summarize every assignment I haven't turned in yet" · "Give me the link to submit HW 4" |
|
|
88
|
-
| Quizzes | "
|
|
88
|
+
| Quizzes | "Which quizzes close this week?" · "Is Quiz 3 timed, and does it have a grace period?" |
|
|
89
|
+
| Assignment files | "What does the lab 4 spec actually ask for?" · "Summarize the rubric attached to the project" |
|
|
89
90
|
| Exams | "Is there a midterm in the gradebook that isn't on my assignments list?" |
|
|
90
91
|
| Announcements | "Did any professor post something important today?" · "What did my CS prof announce this week?" |
|
|
91
92
|
| Course content | "Find the midterm review slides" · "Download every PDF from Module 5" |
|
|
@@ -131,6 +132,12 @@ If you ever suspect you're on an old version (the auth banner prints the version
|
|
|
131
132
|
npx clear-npx-cache
|
|
132
133
|
```
|
|
133
134
|
|
|
135
|
+
## What's new in 1.6.0
|
|
136
|
+
|
|
137
|
+
- **Read the files attached to an assignment.** The spec PDF, the starter workbook, the rubric. Ask what an assignment requires and the answer comes from the actual document, not just its one-line description. Handles PDF, Word, Excel, and PowerPoint.
|
|
138
|
+
- The roster no longer hides people: a class larger than the limit now reports the true total and says it was truncated, and the limit can be raised.
|
|
139
|
+
- Fixed a case where a class list or course list could stop short of the last page.
|
|
140
|
+
|
|
134
141
|
## What's new in 1.5.0
|
|
135
142
|
|
|
136
143
|
- Token refresh no longer opens a browser: the access token is re-minted from your session cookie in about 200 ms.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-store.d.ts","sourceRoot":"","sources":["../../src/auth/session-store.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,KAAK,EAAE,SAAS,EAA8B,MAAM,mBAAmB,CAAC;AAgB/E;;;GAGG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;gBAE7B,UAAU,CAAC,EAAE,MAAM;IAK/B;;;OAGG;IACH,OAAO,CAAC,eAAe;IAmBvB;;;OAGG;IACH,OAAO,CAAC,SAAS;
|
|
1
|
+
{"version":3,"file":"session-store.d.ts","sourceRoot":"","sources":["../../src/auth/session-store.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,KAAK,EAAE,SAAS,EAA8B,MAAM,mBAAmB,CAAC;AAgB/E;;;GAGG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;gBAE7B,UAAU,CAAC,EAAE,MAAM;IAK/B;;;OAGG;IACH,OAAO,CAAC,eAAe;IAmBvB;;;OAGG;IACH,OAAO,CAAC,SAAS;IAcjB;;;OAGG;IACH,OAAO,CAAC,OAAO;IAkBf;;;OAGG;IACH,OAAO,CAAC,OAAO;IAcf;;;OAGG;IACG,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAoC3C;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAuCvC;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAa7B"}
|
|
@@ -59,12 +59,16 @@ export class SessionStore {
|
|
|
59
59
|
* Uses a per-installation random salt to prevent precomputation attacks.
|
|
60
60
|
*/
|
|
61
61
|
deriveKey() {
|
|
62
|
+
// Deliberately NOT the hostname. On a campus network os.hostname() is a
|
|
63
|
+
// DHCP reverse-DNS name (pal-nat186-166-147.itap.purdue.edu), so it
|
|
64
|
+
// changes with the lease. Keying on it meant that moving between networks
|
|
65
|
+
// silently made the saved session undecryptable, and the user paid for it
|
|
66
|
+
// with a full MFA login. The per-install random salt already provides the
|
|
67
|
+
// uniqueness the hostname was there for, and it is stable.
|
|
62
68
|
const username = os.userInfo().username;
|
|
63
|
-
const hostname = os.hostname();
|
|
64
|
-
const keyMaterial = username + hostname;
|
|
65
69
|
const salt = this.getOrCreateSalt();
|
|
66
70
|
// Use scrypt to derive a 32-byte key (256 bits for AES-256)
|
|
67
|
-
return crypto.scryptSync(
|
|
71
|
+
return crypto.scryptSync(username, salt, 32);
|
|
68
72
|
}
|
|
69
73
|
/**
|
|
70
74
|
* Encrypt plaintext using AES-256-GCM.
|
|
@@ -154,6 +158,17 @@ export class SessionStore {
|
|
|
154
158
|
catch (error) {
|
|
155
159
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
156
160
|
log("WARN", `Failed to load session: ${err.message}`);
|
|
161
|
+
// A session this install cannot read is never going to become readable:
|
|
162
|
+
// it was written by an older build whose key derivation differed, or the
|
|
163
|
+
// file is damaged. Removing it means the next run does one clean login
|
|
164
|
+
// instead of logging the same warning on every start forever.
|
|
165
|
+
try {
|
|
166
|
+
await fs.rm(this.sessionFilePath, { force: true });
|
|
167
|
+
log("DEBUG", "Removed the unreadable session file, a fresh login is needed");
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
// Nothing more to do: the caller re-authenticates either way.
|
|
171
|
+
}
|
|
157
172
|
// Return null instead of throwing - graceful degradation
|
|
158
173
|
return null;
|
|
159
174
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-store.js","sourceRoot":"","sources":["../../src/auth/session-store.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,MAAM,MAAM,SAAS,CAAC;AAClC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAE9B,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAE3D,MAAM,mBAAmB,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,cAAc,CAAC,CAAC;AACpE,MAAM,iBAAiB,GAAG,cAAc,CAAC;AACzC,MAAM,eAAe,GAAG,CAAC,CAAC;AAE1B,uBAAuB;AACvB,MAAM,SAAS,GAAG,aAAa,CAAC;AAChC,MAAM,SAAS,GAAG,EAAE,CAAC,CAAC,4BAA4B;AAClD,MAAM,eAAe,GAAG,EAAE,CAAC,CAAC,sBAAsB;AAClD,MAAM,WAAW,GAAG,EAAE,CAAC;AACvB,MAAM,cAAc,GAAG,MAAM,CAAC;AAE9B;;;GAGG;AACH,MAAM,OAAO,YAAY;IACN,UAAU,CAAS;IACnB,eAAe,CAAS;IAEzC,YAAY,UAAmB;QAC7B,IAAI,CAAC,UAAU,GAAG,UAAU,IAAI,mBAAmB,CAAC;QACpD,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,iBAAiB,CAAC,CAAC;IACvE,CAAC;IAED;;;OAGG;IACK,eAAe;QACrB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;QAC5D,IAAI,CAAC;YACH,OAAO,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;QACvC,CAAC;QAAC,MAAM,CAAC;YACP,+DAA+D;YAC/D,MAAM,SAAS,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC;YAC/C,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,EAAE;gBAChC,SAAS,EAAE,IAAI;gBACf,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;aACtC,CAAC,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;YAC7C,MAAM,CAAC,aAAa,CAAC,QAAQ,EAAE,IAAI,EAAE;gBACnC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;aACtC,CAAC,CAAC;YACH,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED;;;OAGG;IACK,SAAS;QACf,
|
|
1
|
+
{"version":3,"file":"session-store.js","sourceRoot":"","sources":["../../src/auth/session-store.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brightspace-mcp-server",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.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",
|