brightspace-mcp-server 3.10.16 → 3.11.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 +1 -1
- package/build/setup.js +20 -1
- package/build/tools/get-video-transcript.js +2 -1
- package/build/tools/schemas.js +1 -1
- package/build/utils/config.js +5 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -95,7 +95,7 @@ All optional, set in your AI app's MCP `env` config or your shell. The full list
|
|
|
95
95
|
|
|
96
96
|
| Setting | What it does |
|
|
97
97
|
|---------|--------------|
|
|
98
|
-
| `D2L_REMEMBER_MFA=true` | Tick Microsoft's "Don't ask again" box so later sign-ins skip the second factor (off by default; not for shared computers) |
|
|
98
|
+
| `D2L_REMEMBER_MFA=true` | Tick Microsoft's "Don't ask again" box so later sign-ins skip the second factor (off by default; not for shared computers). `setup` asks this and saves it as `rememberMfa` in `config.json`; the env var overrides it |
|
|
99
99
|
| `D2L_HEADLESS=false` | Show the browser window during sign-in, for MFA methods that need a click |
|
|
100
100
|
| `D2L_DUO_PASSCODE=1` | On Duo, type a passcode instead of waiting for a push |
|
|
101
101
|
| `D2L_SESSION_COOKIE` / `D2L_ACCESS_TOKEN` | Skip the browser entirely with a pasted cookie or token ([how](docs/sign-in.md#no-browser-paste-a-session-cookie-or-token)) |
|
package/build/setup.js
CHANGED
|
@@ -355,6 +355,8 @@ export function buildConfigToSave(existing, answers) {
|
|
|
355
355
|
password: answers.password,
|
|
356
356
|
headless: answers.headless,
|
|
357
357
|
};
|
|
358
|
+
if (answers.rememberMfa !== undefined)
|
|
359
|
+
config.rememberMfa = answers.rememberMfa;
|
|
358
360
|
if (answers.campus)
|
|
359
361
|
config.campus = answers.campus;
|
|
360
362
|
return config;
|
|
@@ -484,8 +486,11 @@ async function main() {
|
|
|
484
486
|
console.log(" 1. I approve on my phone, or I type a code from an authenticator app (recommended)");
|
|
485
487
|
console.log(" 2. Something else — open a browser window I can use");
|
|
486
488
|
let savedHeadless;
|
|
489
|
+
let savedRememberMfa;
|
|
487
490
|
try {
|
|
488
|
-
|
|
491
|
+
const saved = configStoreExists() ? loadConfigStore() : undefined;
|
|
492
|
+
savedHeadless = saved?.headless;
|
|
493
|
+
savedRememberMfa = saved?.rememberMfa;
|
|
489
494
|
}
|
|
490
495
|
catch {
|
|
491
496
|
// An invalid old config is replaced by the setup values below.
|
|
@@ -502,12 +507,26 @@ async function main() {
|
|
|
502
507
|
? " Authentication will run without a browser window."
|
|
503
508
|
: " A browser window will open when authentication is needed."));
|
|
504
509
|
console.log("");
|
|
510
|
+
// Opt-in only: a shared computer must never skip MFA unless asked to.
|
|
511
|
+
const defaultRemember = savedRememberMfa === true ? "yes" : "no";
|
|
512
|
+
let rememberAnswer = "";
|
|
513
|
+
while (!/^(y(es)?|no?)$/i.test(rememberAnswer)) {
|
|
514
|
+
rememberAnswer = await ask(rl2, ` Remember this device so later sign-ins can skip the second factor? Not for shared computers. (yes/no) [${defaultRemember}]: `) || defaultRemember;
|
|
515
|
+
if (!/^(y(es)?|no?)$/i.test(rememberAnswer))
|
|
516
|
+
console.log(yellow(" Please enter yes or no."));
|
|
517
|
+
}
|
|
518
|
+
const rememberMfa = /^y/i.test(rememberAnswer);
|
|
519
|
+
console.log(dim(rememberMfa
|
|
520
|
+
? " Later sign-ins will ask Microsoft not to repeat the second factor on this device."
|
|
521
|
+
: " Every sign-in will ask for the second factor."));
|
|
522
|
+
console.log("");
|
|
505
523
|
// ── Step 5: Save config ──────────────────────────────────────────
|
|
506
524
|
const config = buildConfigToSave(readExistingConfig(), {
|
|
507
525
|
baseUrl,
|
|
508
526
|
username,
|
|
509
527
|
password,
|
|
510
528
|
headless,
|
|
529
|
+
rememberMfa,
|
|
511
530
|
campus: campus || undefined,
|
|
512
531
|
});
|
|
513
532
|
await saveSecureConfig(config);
|
|
@@ -112,7 +112,8 @@ export function registerGetVideoTranscript(server, apiClient, fetchImpl = fetch)
|
|
|
112
112
|
"Call it with courseId and topicId from get_course_content (typeFilter: 'video' or 'other'), or with videoUrl " +
|
|
113
113
|
"directly if you already have the link. Returns transcript text with timestamps, plus title and duration when " +
|
|
114
114
|
"available. Currently supports Kaltura (e.g. BoilerCast, including its Brightspace LTI links) and YouTube; other platforms return a clear message " +
|
|
115
|
-
"naming what isn't supported yet.
|
|
115
|
+
"naming what isn't supported yet. Each call returns at most maxChars characters (up to 100000); to read a whole " +
|
|
116
|
+
"transcript, call again with offset set to the returned nextOffset until truncated is false. Read only — this " +
|
|
116
117
|
"never marks the video as watched.",
|
|
117
118
|
inputSchema: GetVideoTranscriptSchema,
|
|
118
119
|
}, async (args) => {
|
package/build/tools/schemas.js
CHANGED
|
@@ -125,7 +125,7 @@ export const GetVideoTranscriptSchema = z.object({
|
|
|
125
125
|
offset: z.coerce.number().int().min(0).default(0)
|
|
126
126
|
.describe("Character offset into the transcript to resume from. Pass back nextOffset from a truncated response to fetch the next piece."),
|
|
127
127
|
maxChars: z.coerce.number().int().positive().max(100000).default(12000)
|
|
128
|
-
.describe("Maximum characters of transcript text to return in one call. The response reports whether it was truncated."),
|
|
128
|
+
.describe("Maximum characters of transcript text to return in one call, from 1 to 100000 (default 12000). The response reports whether it was truncated; to read past this limit, page with offset/nextOffset."),
|
|
129
129
|
});
|
|
130
130
|
export const GetRosterSchema = z.object({
|
|
131
131
|
courseId: z.coerce.number().int().positive()
|
package/build/utils/config.js
CHANGED
|
@@ -48,9 +48,11 @@ export async function loadConfig() {
|
|
|
48
48
|
?? store?.headless
|
|
49
49
|
?? true;
|
|
50
50
|
// Opt-in: ask Microsoft to skip the second factor for its "Don't ask again"
|
|
51
|
-
// window. Off unless
|
|
52
|
-
// remembers MFA without the user choosing it.
|
|
53
|
-
const rememberMfa = envBoolean(process.env.D2L_REMEMBER_MFA, "D2L_REMEMBER_MFA")
|
|
51
|
+
// window. Off unless the user said yes in setup or set D2L_REMEMBER_MFA=true,
|
|
52
|
+
// so a shared machine never remembers MFA without the user choosing it.
|
|
53
|
+
const rememberMfa = envBoolean(process.env.D2L_REMEMBER_MFA, "D2L_REMEMBER_MFA")
|
|
54
|
+
?? store?.rememberMfa
|
|
55
|
+
?? false;
|
|
54
56
|
// Resolve tokenTtl: env > store > default (3600)
|
|
55
57
|
const tokenTtl = positiveSeconds(process.env.D2L_TOKEN_TTL, "D2L_TOKEN_TTL")
|
|
56
58
|
?? positiveSeconds(store?.tokenTtl, "tokenTtl in config.json")
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brightspace-mcp-server",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.11.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",
|