brightspace-mcp-server 3.1.0 → 3.2.0
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 -0
- package/build/index.js +4 -3
- package/build/index.js.map +1 -1
- package/build/tools/get-video-transcript.d.ts +13 -0
- package/build/tools/get-video-transcript.d.ts.map +1 -0
- package/build/tools/get-video-transcript.js +168 -0
- package/build/tools/get-video-transcript.js.map +1 -0
- package/build/tools/index.d.ts +1 -0
- package/build/tools/index.d.ts.map +1 -1
- package/build/tools/index.js +1 -0
- package/build/tools/index.js.map +1 -1
- package/build/tools/schemas.d.ts +7 -0
- package/build/tools/schemas.d.ts.map +1 -1
- package/build/tools/schemas.js +12 -0
- package/build/tools/schemas.js.map +1 -1
- package/build/utils/transcript/captions.d.ts +40 -0
- package/build/utils/transcript/captions.d.ts.map +1 -0
- package/build/utils/transcript/captions.js +63 -0
- package/build/utils/transcript/captions.js.map +1 -0
- package/build/utils/transcript/errors.d.ts +14 -0
- package/build/utils/transcript/errors.d.ts.map +1 -0
- package/build/utils/transcript/errors.js +20 -0
- package/build/utils/transcript/errors.js.map +1 -0
- package/build/utils/transcript/kaltura.d.ts +8 -0
- package/build/utils/transcript/kaltura.d.ts.map +1 -0
- package/build/utils/transcript/kaltura.js +94 -0
- package/build/utils/transcript/kaltura.js.map +1 -0
- package/build/utils/transcript/platform.d.ts +23 -0
- package/build/utils/transcript/platform.d.ts.map +1 -0
- package/build/utils/transcript/platform.js +98 -0
- package/build/utils/transcript/platform.js.map +1 -0
- package/build/utils/transcript/types.d.ts +22 -0
- package/build/utils/transcript/types.d.ts.map +1 -0
- package/build/utils/transcript/types.js +7 -0
- package/build/utils/transcript/types.js.map +1 -0
- package/build/utils/transcript/youtube.d.ts +8 -0
- package/build/utils/transcript/youtube.d.ts.map +1 -0
- package/build/utils/transcript/youtube.js +57 -0
- package/build/utils/transcript/youtube.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -116,6 +116,7 @@ npx -y brightspace-mcp-server@latest auth
|
|
|
116
116
|
| Course content | "Find the midterm review slides" · "Download every PDF from Module 5" · "What's new in this course since I last checked?" |
|
|
117
117
|
| Roster | "Who are the TAs for ECE 264?" · "Get me my instructor's email" |
|
|
118
118
|
| Discussions | "What are people saying in the final project thread?" · "Summarize the latest discussion posts" |
|
|
119
|
+
| Video transcripts | "What did the professor say about pinch-off in Tuesday's lecture recording?" · "Summarize last week's BoilerCast video" — works for Kaltura and YouTube embeds; other platforms report that they aren't supported yet |
|
|
119
120
|
| Planning | "Build me a study schedule based on my upcoming due dates" · "Which class needs the most attention right now?" — pulls from assignments, quizzes, and graded discussion topics (any topic with a due date) |
|
|
120
121
|
|
|
121
122
|
|
package/build/index.js
CHANGED
|
@@ -16,7 +16,7 @@ import { startUpdateChecks } from "./utils/update-checker.js";
|
|
|
16
16
|
import { readFileSync } from "node:fs";
|
|
17
17
|
import { fileURLToPath } from "node:url";
|
|
18
18
|
import { dirname, resolve } from "node:path";
|
|
19
|
-
import { registerGetMyCourses, registerGetUpcomingDueDates, registerGetMyGrades, registerGetAnnouncements, registerGetAssignments, registerGetAssignmentFiles, registerGetCourseContent, registerDownloadFile, registerGetClasslistEmails, registerGetRoster, registerGetSyllabus, registerGetDiscussions, } from "./tools/index.js";
|
|
19
|
+
import { registerGetMyCourses, registerGetUpcomingDueDates, registerGetMyGrades, registerGetAnnouncements, registerGetAssignments, registerGetAssignmentFiles, registerGetCourseContent, registerDownloadFile, registerGetClasslistEmails, registerGetRoster, registerGetSyllabus, registerGetDiscussions, registerGetVideoTranscript, } from "./tools/index.js";
|
|
20
20
|
const __filename = fileURLToPath(import.meta.url);
|
|
21
21
|
const __dirname = dirname(__filename);
|
|
22
22
|
const PKG_VERSION = (() => {
|
|
@@ -112,11 +112,12 @@ else {
|
|
|
112
112
|
registerGetRoster(server, apiClient);
|
|
113
113
|
registerGetSyllabus(server, apiClient);
|
|
114
114
|
registerGetDiscussions(server, apiClient);
|
|
115
|
-
|
|
115
|
+
registerGetVideoTranscript(server, apiClient);
|
|
116
|
+
log("DEBUG", "MCP tools registered (13 tools)");
|
|
116
117
|
// Connect stdio transport
|
|
117
118
|
const transport = new StdioServerTransport();
|
|
118
119
|
await server.connect(transport);
|
|
119
|
-
log("INFO", "Brightspace MCP Server by Rohan Muppa — running on stdio (
|
|
120
|
+
log("INFO", "Brightspace MCP Server by Rohan Muppa — running on stdio (13 tools registered)");
|
|
120
121
|
log("INFO", "Setup: see README.md for MCP client configuration (Claude Desktop, ChatGPT Desktop, Cursor, etc.)");
|
|
121
122
|
}
|
|
122
123
|
catch (error) {
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EACL,oBAAoB,EACpB,2BAA2B,EAC3B,mBAAmB,EACnB,wBAAwB,EACxB,sBAAsB,EACtB,0BAA0B,EAC1B,wBAAwB,EACxB,oBAAoB,EACpB,0BAA0B,EAC1B,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
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 { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
7
|
+
import { D2LApiClient } from "../api/index.js";
|
|
8
|
+
import type { FetchLike } from "../utils/transcript/types.js";
|
|
9
|
+
/**
|
|
10
|
+
* Register get_video_transcript tool
|
|
11
|
+
*/
|
|
12
|
+
export declare function registerGetVideoTranscript(server: McpServer, apiClient: D2LApiClient, fetchImpl?: FetchLike): void;
|
|
13
|
+
//# sourceMappingURL=get-video-transcript.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-video-transcript.d.ts","sourceRoot":"","sources":["../../src/tools/get-video-transcript.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,YAAY,EAAsB,MAAM,iBAAiB,CAAC;AAanE,OAAO,KAAK,EAAE,SAAS,EAAoB,MAAM,8BAA8B,CAAC;AA6FhF;;GAEG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,YAAY,EACvB,SAAS,GAAE,SAAiB,GAC3B,IAAI,CA2FN"}
|
|
@@ -0,0 +1,168 @@
|
|
|
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 { DEFAULT_CACHE_TTLS } from "../api/index.js";
|
|
7
|
+
import { GetVideoTranscriptSchema } from "./schemas.js";
|
|
8
|
+
import { toolResponse, errorResponse, sanitizeError } from "./tool-helpers.js";
|
|
9
|
+
import { cuesToText, paginateText } from "../utils/transcript/captions.js";
|
|
10
|
+
import { detectVideoPlatform, extractKalturaIds, extractYouTubeVideoId, } from "../utils/transcript/platform.js";
|
|
11
|
+
import { getKalturaTranscript } from "../utils/transcript/kaltura.js";
|
|
12
|
+
import { getYouTubeTranscript } from "../utils/transcript/youtube.js";
|
|
13
|
+
import { NoTranscriptError, TranscriptFetchError } from "../utils/transcript/errors.js";
|
|
14
|
+
import { log } from "../utils/logger.js";
|
|
15
|
+
const UNSUPPORTED_PLATFORM_LABEL = {
|
|
16
|
+
panopto: "Panopto",
|
|
17
|
+
yuja: "YuJa",
|
|
18
|
+
echo360: "Echo360",
|
|
19
|
+
vimeo: "Vimeo",
|
|
20
|
+
};
|
|
21
|
+
async function resolveVideoUrl(apiClient, courseId, topicId) {
|
|
22
|
+
const topic = await apiClient.get(apiClient.le(courseId, `/content/topics/${topicId}`), { ttl: DEFAULT_CACHE_TTLS.courseContent });
|
|
23
|
+
if (!topic.Url) {
|
|
24
|
+
return {
|
|
25
|
+
error: `Content topic "${topic.Title}" (id ${topicId}) has no URL Brightspace can resolve to a video. ` +
|
|
26
|
+
"This is common for audio or embedded objects with no direct link. Open it in Brightspace directly.",
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return { url: topic.Url };
|
|
30
|
+
}
|
|
31
|
+
async function fetchTranscript(platform, videoUrl, fetchImpl) {
|
|
32
|
+
switch (platform) {
|
|
33
|
+
case "kaltura": {
|
|
34
|
+
const ids = extractKalturaIds(videoUrl);
|
|
35
|
+
if (!ids) {
|
|
36
|
+
return {
|
|
37
|
+
failed: `Could not find a Kaltura entry ID and partner ID in this URL: ${videoUrl}`,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
return { result: await getKalturaTranscript(ids.partnerId, ids.entryId, fetchImpl) };
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
if (error instanceof NoTranscriptError)
|
|
45
|
+
return { noTranscript: error.message };
|
|
46
|
+
if (error instanceof TranscriptFetchError) {
|
|
47
|
+
return {
|
|
48
|
+
failed: `${error.message} This can happen when the video needs an authenticated Kaltura ` +
|
|
49
|
+
"session rather than an anonymous one. Open it in Brightspace directly.",
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
case "youtube": {
|
|
56
|
+
const videoId = extractYouTubeVideoId(videoUrl);
|
|
57
|
+
if (!videoId) {
|
|
58
|
+
return { failed: `Could not find a YouTube video ID in this URL: ${videoUrl}` };
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
return { result: await getYouTubeTranscript(videoId, fetchImpl) };
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
if (error instanceof NoTranscriptError)
|
|
65
|
+
return { noTranscript: error.message };
|
|
66
|
+
if (error instanceof TranscriptFetchError)
|
|
67
|
+
return { failed: error.message };
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
case "panopto":
|
|
72
|
+
case "yuja":
|
|
73
|
+
case "echo360":
|
|
74
|
+
case "vimeo":
|
|
75
|
+
return {
|
|
76
|
+
unsupported: `Video transcripts from ${UNSUPPORTED_PLATFORM_LABEL[platform]} are not supported yet. ` +
|
|
77
|
+
"Open the video in Brightspace directly.",
|
|
78
|
+
};
|
|
79
|
+
default:
|
|
80
|
+
return {
|
|
81
|
+
unsupported: `Could not identify a supported video platform for this URL: ${videoUrl}. ` +
|
|
82
|
+
"Open the video in Brightspace directly.",
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Register get_video_transcript tool
|
|
88
|
+
*/
|
|
89
|
+
export function registerGetVideoTranscript(server, apiClient, fetchImpl = fetch) {
|
|
90
|
+
server.registerTool("get_video_transcript", {
|
|
91
|
+
title: "Get Video Transcript",
|
|
92
|
+
description: "Read the transcript of a video embedded in course content, such as a recorded lecture or explainer clip. " +
|
|
93
|
+
"Call it with courseId and topicId from get_course_content (typeFilter: 'video' or 'other'), or with videoUrl " +
|
|
94
|
+
"directly if you already have the link. Returns transcript text with timestamps, plus title and duration when " +
|
|
95
|
+
"available. Currently supports Kaltura (e.g. BoilerCast) and YouTube; other platforms return a clear message " +
|
|
96
|
+
"naming what isn't supported yet. Use offset/maxChars to page through a long transcript. Read only — this " +
|
|
97
|
+
"never marks the video as watched.",
|
|
98
|
+
inputSchema: GetVideoTranscriptSchema,
|
|
99
|
+
}, async (args) => {
|
|
100
|
+
try {
|
|
101
|
+
log("DEBUG", "get_video_transcript tool called", { args });
|
|
102
|
+
const { courseId, topicId, videoUrl, offset, maxChars } = GetVideoTranscriptSchema.parse(args);
|
|
103
|
+
let resolvedUrl;
|
|
104
|
+
if (videoUrl) {
|
|
105
|
+
resolvedUrl = videoUrl;
|
|
106
|
+
}
|
|
107
|
+
else if (courseId !== undefined && topicId !== undefined) {
|
|
108
|
+
const resolved = await resolveVideoUrl(apiClient, courseId, topicId);
|
|
109
|
+
if ("error" in resolved) {
|
|
110
|
+
return toolResponse({ courseId, topicId, hasTranscript: false, message: resolved.error });
|
|
111
|
+
}
|
|
112
|
+
resolvedUrl = resolved.url;
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
return errorResponse("Provide either videoUrl, or both courseId and topicId to look up the video from course content.");
|
|
116
|
+
}
|
|
117
|
+
const platform = detectVideoPlatform(resolvedUrl);
|
|
118
|
+
const outcome = await fetchTranscript(platform, resolvedUrl, fetchImpl);
|
|
119
|
+
if ("unsupported" in outcome) {
|
|
120
|
+
return toolResponse({
|
|
121
|
+
courseId,
|
|
122
|
+
topicId,
|
|
123
|
+
videoUrl: resolvedUrl,
|
|
124
|
+
platform,
|
|
125
|
+
hasTranscript: false,
|
|
126
|
+
message: outcome.unsupported,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
if ("noTranscript" in outcome) {
|
|
130
|
+
return toolResponse({
|
|
131
|
+
courseId,
|
|
132
|
+
topicId,
|
|
133
|
+
videoUrl: resolvedUrl,
|
|
134
|
+
platform,
|
|
135
|
+
hasTranscript: false,
|
|
136
|
+
message: outcome.noTranscript,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
if ("failed" in outcome) {
|
|
140
|
+
return errorResponse(outcome.failed);
|
|
141
|
+
}
|
|
142
|
+
const { result } = outcome;
|
|
143
|
+
const fullText = cuesToText(result.cues);
|
|
144
|
+
const { window, truncated, nextOffset, totalChars } = paginateText(fullText, offset, maxChars);
|
|
145
|
+
log("INFO", `get_video_transcript: ${platform} transcript for ${resolvedUrl} (${result.cues.length} cues, ${totalChars} chars)`);
|
|
146
|
+
return toolResponse({
|
|
147
|
+
courseId,
|
|
148
|
+
topicId,
|
|
149
|
+
videoUrl: resolvedUrl,
|
|
150
|
+
platform,
|
|
151
|
+
hasTranscript: true,
|
|
152
|
+
title: result.title,
|
|
153
|
+
durationSeconds: result.durationSeconds,
|
|
154
|
+
language: result.language,
|
|
155
|
+
captionFormat: result.format,
|
|
156
|
+
cueCount: result.cues.length,
|
|
157
|
+
transcript: window,
|
|
158
|
+
truncated,
|
|
159
|
+
nextOffset,
|
|
160
|
+
totalChars,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
return sanitizeError(error);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=get-video-transcript.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-video-transcript.js","sourceRoot":"","sources":["../../src/tools/get-video-transcript.ts"],"names":[],"mappings":"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"}
|
package/build/tools/index.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export { registerGetClasslistEmails } from "./get-classlist-emails.js";
|
|
|
15
15
|
export { registerGetRoster } from "./get-roster.js";
|
|
16
16
|
export { registerGetSyllabus } from "./get-syllabus.js";
|
|
17
17
|
export { registerGetDiscussions } from "./get-discussions.js";
|
|
18
|
+
export { registerGetVideoTranscript } from "./get-video-transcript.js";
|
|
18
19
|
export { toolResponse, errorResponse, sanitizeError } from "./tool-helpers.js";
|
|
19
20
|
export * from "./schemas.js";
|
|
20
21
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AAGvE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC/E,cAAc,cAAc,CAAC"}
|
package/build/tools/index.js
CHANGED
|
@@ -16,6 +16,7 @@ export { registerGetClasslistEmails } from "./get-classlist-emails.js";
|
|
|
16
16
|
export { registerGetRoster } from "./get-roster.js";
|
|
17
17
|
export { registerGetSyllabus } from "./get-syllabus.js";
|
|
18
18
|
export { registerGetDiscussions } from "./get-discussions.js";
|
|
19
|
+
export { registerGetVideoTranscript } from "./get-video-transcript.js";
|
|
19
20
|
// Re-export shared helpers and schemas for convenience
|
|
20
21
|
export { toolResponse, errorResponse, sanitizeError } from "./tool-helpers.js";
|
|
21
22
|
export * from "./schemas.js";
|
package/build/tools/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,8CAA8C;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,8CAA8C;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AAEvE,uDAAuD;AACvD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC/E,cAAc,cAAc,CAAC"}
|
package/build/tools/schemas.d.ts
CHANGED
|
@@ -67,6 +67,13 @@ export declare const GetAssignmentFilesSchema: z.ZodObject<{
|
|
|
67
67
|
extractText: z.ZodDefault<z.ZodBoolean>;
|
|
68
68
|
maxChars: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
69
69
|
}, z.core.$strip>;
|
|
70
|
+
export declare const GetVideoTranscriptSchema: z.ZodObject<{
|
|
71
|
+
courseId: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
72
|
+
topicId: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
73
|
+
videoUrl: z.ZodOptional<z.ZodString>;
|
|
74
|
+
offset: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
75
|
+
maxChars: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
76
|
+
}, z.core.$strip>;
|
|
70
77
|
export declare const GetRosterSchema: z.ZodObject<{
|
|
71
78
|
courseId: z.ZodCoercedNumber<unknown>;
|
|
72
79
|
includeStudents: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../src/tools/schemas.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;GAIG;AAEH,eAAO,MAAM,kBAAkB;;iBAU7B,CAAC;AAEH,eAAO,MAAM,yBAAyB;;;iBAGpC,CAAC;AAEH,eAAO,MAAM,iBAAiB;;iBAE5B,CAAC;AAEH,eAAO,MAAM,sBAAsB;;;;iBAKjC,CAAC;AAEH,eAAO,MAAM,oBAAoB;;iBAG/B,CAAC;AAEH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;iBAWjC,CAAC;AAEH,eAAO,MAAM,wBAAwB;;iBAGnC,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;;;;;iBAa7B,CAAC;AAEH,eAAO,MAAM,iBAAiB;;;iBAK5B,CAAC;AAEH,eAAO,MAAM,oBAAoB;;;;iBAO/B,CAAC;AAEH,eAAO,MAAM,wBAAwB;;;;;;iBAWnC,CAAC;AAEH,eAAO,MAAM,eAAe;;;;;iBAS1B,CAAC"}
|
|
1
|
+
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../src/tools/schemas.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;GAIG;AAEH,eAAO,MAAM,kBAAkB;;iBAU7B,CAAC;AAEH,eAAO,MAAM,yBAAyB;;;iBAGpC,CAAC;AAEH,eAAO,MAAM,iBAAiB;;iBAE5B,CAAC;AAEH,eAAO,MAAM,sBAAsB;;;;iBAKjC,CAAC;AAEH,eAAO,MAAM,oBAAoB;;iBAG/B,CAAC;AAEH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;iBAWjC,CAAC;AAEH,eAAO,MAAM,wBAAwB;;iBAGnC,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;;;;;iBAa7B,CAAC;AAEH,eAAO,MAAM,iBAAiB;;;iBAK5B,CAAC;AAEH,eAAO,MAAM,oBAAoB;;;;iBAO/B,CAAC;AAEH,eAAO,MAAM,wBAAwB;;;;;;iBAWnC,CAAC;AAEH,eAAO,MAAM,wBAAwB;;;;;;iBAWnC,CAAC;AAEH,eAAO,MAAM,eAAe;;;;;iBAS1B,CAAC"}
|
package/build/tools/schemas.js
CHANGED
|
@@ -91,6 +91,18 @@ export const GetAssignmentFilesSchema = z.object({
|
|
|
91
91
|
maxChars: z.coerce.number().int().positive().max(100000).default(12000)
|
|
92
92
|
.describe("Maximum characters of extracted text to return. The response reports whether it was truncated."),
|
|
93
93
|
});
|
|
94
|
+
export const GetVideoTranscriptSchema = z.object({
|
|
95
|
+
courseId: z.coerce.number().int().positive().optional()
|
|
96
|
+
.describe("Course ID the video belongs to. Required together with topicId unless videoUrl is given directly."),
|
|
97
|
+
topicId: z.coerce.number().int().positive().optional()
|
|
98
|
+
.describe("Content topic ID (from get_course_content) whose embedded video to transcribe. Requires courseId."),
|
|
99
|
+
videoUrl: z.string().url().optional()
|
|
100
|
+
.describe("Direct video URL to transcribe, e.g. the url field get_course_content already returned. Use instead of courseId/topicId when you already have the link."),
|
|
101
|
+
offset: z.coerce.number().int().min(0).default(0)
|
|
102
|
+
.describe("Character offset into the transcript to resume from. Pass back nextOffset from a truncated response to fetch the next piece."),
|
|
103
|
+
maxChars: z.coerce.number().int().positive().max(100000).default(12000)
|
|
104
|
+
.describe("Maximum characters of transcript text to return in one call. The response reports whether it was truncated."),
|
|
105
|
+
});
|
|
94
106
|
export const GetRosterSchema = z.object({
|
|
95
107
|
courseId: z.coerce.number().int().positive()
|
|
96
108
|
.describe("Course ID to get roster for."),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../src/tools/schemas.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../src/tools/schemas.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
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
|
+
* Parsing for the two caption formats every platform adapter in
|
|
8
|
+
* src/utils/transcript/ ends up serving: WebVTT and SRT. Both are just
|
|
9
|
+
* "timestamp range, then text, blank line, repeat" — this module is the one
|
|
10
|
+
* place that knows the timestamp punctuation differs (`.` vs `,`) and that
|
|
11
|
+
* VTT can carry inline tags and cue settings SRT never does.
|
|
12
|
+
*/
|
|
13
|
+
export interface TranscriptCue {
|
|
14
|
+
startMs: number;
|
|
15
|
+
endMs: number;
|
|
16
|
+
text: string;
|
|
17
|
+
}
|
|
18
|
+
export type CaptionFormat = "vtt" | "srt";
|
|
19
|
+
/**
|
|
20
|
+
* Parse WebVTT or SRT text into cues. Format is detected from the WEBVTT
|
|
21
|
+
* header rather than taken on faith, since a caller only knows what the
|
|
22
|
+
* platform's API claims to have served.
|
|
23
|
+
*/
|
|
24
|
+
export declare function parseCaptions(raw: string): {
|
|
25
|
+
format: CaptionFormat;
|
|
26
|
+
cues: TranscriptCue[];
|
|
27
|
+
};
|
|
28
|
+
/** "H:MM:SS", matching how course-length recordings are usually captioned. */
|
|
29
|
+
export declare function formatTimestamp(ms: number): string;
|
|
30
|
+
/** One line per cue, timestamped, in reading order. */
|
|
31
|
+
export declare function cuesToText(cues: TranscriptCue[]): string;
|
|
32
|
+
export interface TextWindow {
|
|
33
|
+
window: string;
|
|
34
|
+
truncated: boolean;
|
|
35
|
+
nextOffset: number | null;
|
|
36
|
+
totalChars: number;
|
|
37
|
+
}
|
|
38
|
+
/** Character-offset paging, mirroring the maxChars/truncated convention used elsewhere for large text. */
|
|
39
|
+
export declare function paginateText(text: string, offset: number, maxChars: number): TextWindow;
|
|
40
|
+
//# sourceMappingURL=captions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"captions.d.ts","sourceRoot":"","sources":["../../../src/utils/transcript/captions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;GAMG;AAEH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,KAAK,CAAC;AAa1C;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,aAAa,EAAE,CAAA;CAAE,CAwB3F;AAED,8EAA8E;AAC9E,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAMlD;AAED,uDAAuD;AACvD,wBAAgB,UAAU,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,MAAM,CAExD;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,0GAA0G;AAC1G,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,CAKvF"}
|
|
@@ -0,0 +1,63 @@
|
|
|
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
|
+
/** "01:02:03.456" or "01:02:03,456" or the hours-omitted "02:03.456". */
|
|
7
|
+
function parseTimestamp(raw) {
|
|
8
|
+
const match = raw.trim().match(/^(?:(\d+):)?(\d{2}):(\d{2})[.,](\d{3})$/);
|
|
9
|
+
if (!match)
|
|
10
|
+
return NaN;
|
|
11
|
+
const [, hours, minutes, seconds, millis] = match;
|
|
12
|
+
return ((Number(hours ?? 0) * 3600 + Number(minutes) * 60 + Number(seconds)) * 1000 +
|
|
13
|
+
Number(millis));
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Parse WebVTT or SRT text into cues. Format is detected from the WEBVTT
|
|
17
|
+
* header rather than taken on faith, since a caller only knows what the
|
|
18
|
+
* platform's API claims to have served.
|
|
19
|
+
*/
|
|
20
|
+
export function parseCaptions(raw) {
|
|
21
|
+
const normalized = raw.replace(/^/, "").replace(/\r\n?/g, "\n");
|
|
22
|
+
const format = /^WEBVTT/.test(normalized.trimStart()) ? "vtt" : "srt";
|
|
23
|
+
const cues = [];
|
|
24
|
+
for (const block of normalized.split(/\n{2,}/)) {
|
|
25
|
+
const lines = block.split("\n").map((l) => l.trim()).filter((l) => l.length > 0);
|
|
26
|
+
const timingIndex = lines.findIndex((l) => l.includes("-->"));
|
|
27
|
+
if (timingIndex === -1)
|
|
28
|
+
continue;
|
|
29
|
+
const [startRaw, endRaw] = lines[timingIndex].split("-->");
|
|
30
|
+
const startMs = parseTimestamp(startRaw.trim().split(/\s+/)[0] ?? "");
|
|
31
|
+
const endMs = parseTimestamp((endRaw ?? "").trim().split(/\s+/)[0] ?? "");
|
|
32
|
+
if (Number.isNaN(startMs) || Number.isNaN(endMs))
|
|
33
|
+
continue;
|
|
34
|
+
const text = lines
|
|
35
|
+
.slice(timingIndex + 1)
|
|
36
|
+
.join(" ")
|
|
37
|
+
.replace(/<[^>]+>/g, "")
|
|
38
|
+
.trim();
|
|
39
|
+
if (text)
|
|
40
|
+
cues.push({ startMs, endMs, text });
|
|
41
|
+
}
|
|
42
|
+
return { format, cues };
|
|
43
|
+
}
|
|
44
|
+
/** "H:MM:SS", matching how course-length recordings are usually captioned. */
|
|
45
|
+
export function formatTimestamp(ms) {
|
|
46
|
+
const totalSeconds = Math.max(0, Math.floor(ms / 1000));
|
|
47
|
+
const hours = Math.floor(totalSeconds / 3600);
|
|
48
|
+
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
49
|
+
const seconds = totalSeconds % 60;
|
|
50
|
+
return `${hours}:${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`;
|
|
51
|
+
}
|
|
52
|
+
/** One line per cue, timestamped, in reading order. */
|
|
53
|
+
export function cuesToText(cues) {
|
|
54
|
+
return cues.map((cue) => `[${formatTimestamp(cue.startMs)}] ${cue.text}`).join("\n");
|
|
55
|
+
}
|
|
56
|
+
/** Character-offset paging, mirroring the maxChars/truncated convention used elsewhere for large text. */
|
|
57
|
+
export function paginateText(text, offset, maxChars) {
|
|
58
|
+
const totalChars = text.length;
|
|
59
|
+
const window = text.slice(offset, offset + maxChars);
|
|
60
|
+
const truncated = offset + maxChars < totalChars;
|
|
61
|
+
return { window, truncated, nextOffset: truncated ? offset + maxChars : null, totalChars };
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=captions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"captions.js","sourceRoot":"","sources":["../../../src/utils/transcript/captions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
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
|
+
/** The video exists and answered, but has no captions — an expected outcome, not a failure. */
|
|
7
|
+
export declare class NoTranscriptError extends Error {
|
|
8
|
+
constructor(message: string);
|
|
9
|
+
}
|
|
10
|
+
/** The platform's API could not be reached or rejected the request. */
|
|
11
|
+
export declare class TranscriptFetchError extends Error {
|
|
12
|
+
constructor(message: string);
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/utils/transcript/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,+FAA+F;AAC/F,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,OAAO,EAAE,MAAM;CAI5B;AAED,uEAAuE;AACvE,qBAAa,oBAAqB,SAAQ,KAAK;gBACjC,OAAO,EAAE,MAAM;CAI5B"}
|
|
@@ -0,0 +1,20 @@
|
|
|
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
|
+
/** The video exists and answered, but has no captions — an expected outcome, not a failure. */
|
|
7
|
+
export class NoTranscriptError extends Error {
|
|
8
|
+
constructor(message) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = "NoTranscriptError";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/** The platform's API could not be reached or rejected the request. */
|
|
14
|
+
export class TranscriptFetchError extends Error {
|
|
15
|
+
constructor(message) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.name = "TranscriptFetchError";
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/utils/transcript/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,+FAA+F;AAC/F,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAC1C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AAED,uEAAuE;AACvE,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAC7C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF"}
|
|
@@ -0,0 +1,8 @@
|
|
|
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 type { FetchLike, TranscriptResult } from "./types.js";
|
|
7
|
+
export declare function getKalturaTranscript(partnerId: string, entryId: string, fetchImpl: FetchLike): Promise<TranscriptResult>;
|
|
8
|
+
//# sourceMappingURL=kaltura.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kaltura.d.ts","sourceRoot":"","sources":["../../../src/utils/transcript/kaltura.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAoBH,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAqF9D,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,gBAAgB,CAAC,CAyB3B"}
|
|
@@ -0,0 +1,94 @@
|
|
|
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
|
+
* Kaltura transcript retrieval — the priority-one platform from issue #33,
|
|
8
|
+
* since Purdue's BoilerCast and many other D2L schools run on it.
|
|
9
|
+
*
|
|
10
|
+
* This does not reuse the Brightspace session: Kaltura is a separate SaaS
|
|
11
|
+
* tenant with its own auth, and an embedded player normally authenticates
|
|
12
|
+
* to it with a "widget session" (a KS token scoped read-only to the entries
|
|
13
|
+
* a partner has made embeddable), not the D2L cookie. That widget-session
|
|
14
|
+
* flow is the same mechanism generic Kaltura embed players use, and it is
|
|
15
|
+
* anonymous by design — it needs no Brightspace credential to obtain. A
|
|
16
|
+
* captions request that fails because the entry actually requires an
|
|
17
|
+
* authenticated (non-widget) session surfaces as TranscriptFetchError, which
|
|
18
|
+
* the tool turns into a "open it in Brightspace directly" message rather
|
|
19
|
+
* than a silent empty result.
|
|
20
|
+
*/
|
|
21
|
+
import { parseCaptions } from "./captions.js";
|
|
22
|
+
import { NoTranscriptError, TranscriptFetchError } from "./errors.js";
|
|
23
|
+
const KALTURA_API_BASE = "https://cdnapisec.kaltura.com/api_v3/service";
|
|
24
|
+
async function startWidgetSession(partnerId, fetchImpl) {
|
|
25
|
+
const res = await fetchImpl(`${KALTURA_API_BASE}/session/action/startWidgetSession?widgetId=_${encodeURIComponent(partnerId)}&format=1`);
|
|
26
|
+
if (!res.ok) {
|
|
27
|
+
throw new TranscriptFetchError(`Kaltura session request failed (HTTP ${res.status}).`);
|
|
28
|
+
}
|
|
29
|
+
const data = (await res.json());
|
|
30
|
+
if (data.error) {
|
|
31
|
+
throw new TranscriptFetchError(`Kaltura rejected the session request: ${data.error.message ?? "unknown error"}.`);
|
|
32
|
+
}
|
|
33
|
+
if (!data.ks) {
|
|
34
|
+
throw new TranscriptFetchError("Kaltura did not return a session token.");
|
|
35
|
+
}
|
|
36
|
+
return data.ks;
|
|
37
|
+
}
|
|
38
|
+
async function listCaptionAssets(ks, entryId, fetchImpl) {
|
|
39
|
+
const res = await fetchImpl(`${KALTURA_API_BASE}/caption_captionasset/action/list?format=1` +
|
|
40
|
+
`&ks=${encodeURIComponent(ks)}&filter:entryIdEqual=${encodeURIComponent(entryId)}`);
|
|
41
|
+
if (!res.ok) {
|
|
42
|
+
throw new TranscriptFetchError(`Kaltura caption list request failed (HTTP ${res.status}).`);
|
|
43
|
+
}
|
|
44
|
+
const data = (await res.json());
|
|
45
|
+
if (data.error) {
|
|
46
|
+
throw new TranscriptFetchError(`Kaltura rejected the caption list request: ${data.error.message ?? "unknown error"}.`);
|
|
47
|
+
}
|
|
48
|
+
return data.objects ?? [];
|
|
49
|
+
}
|
|
50
|
+
async function serveCaption(ks, captionAssetId, fetchImpl) {
|
|
51
|
+
const res = await fetchImpl(`${KALTURA_API_BASE}/caption_captionasset/action/serve?ks=${encodeURIComponent(ks)}` +
|
|
52
|
+
`&captionAssetId=${encodeURIComponent(captionAssetId)}`);
|
|
53
|
+
if (!res.ok) {
|
|
54
|
+
throw new TranscriptFetchError(`Kaltura caption download failed (HTTP ${res.status}).`);
|
|
55
|
+
}
|
|
56
|
+
return res.text();
|
|
57
|
+
}
|
|
58
|
+
/** Best-effort title/duration — a caption-only entry still has a usable transcript without this. */
|
|
59
|
+
async function fetchMediaInfo(ks, entryId, fetchImpl) {
|
|
60
|
+
try {
|
|
61
|
+
const res = await fetchImpl(`${KALTURA_API_BASE}/media/action/get?ks=${encodeURIComponent(ks)}&entryId=${encodeURIComponent(entryId)}`);
|
|
62
|
+
if (!res.ok)
|
|
63
|
+
return { title: null, durationSeconds: null };
|
|
64
|
+
const data = (await res.json());
|
|
65
|
+
if (data.error)
|
|
66
|
+
return { title: null, durationSeconds: null };
|
|
67
|
+
return { title: data.name ?? null, durationSeconds: typeof data.duration === "number" ? data.duration : null };
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return { title: null, durationSeconds: null };
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export async function getKalturaTranscript(partnerId, entryId, fetchImpl) {
|
|
74
|
+
const ks = await startWidgetSession(partnerId, fetchImpl);
|
|
75
|
+
const assets = await listCaptionAssets(ks, entryId, fetchImpl);
|
|
76
|
+
if (assets.length === 0) {
|
|
77
|
+
throw new NoTranscriptError("This Kaltura video has no captions available.");
|
|
78
|
+
}
|
|
79
|
+
const asset = assets.find((a) => a.isDefault) ?? assets[0];
|
|
80
|
+
const raw = await serveCaption(ks, asset.id, fetchImpl);
|
|
81
|
+
const { format, cues } = parseCaptions(raw);
|
|
82
|
+
if (cues.length === 0) {
|
|
83
|
+
throw new NoTranscriptError("This Kaltura video has a caption track, but it contained no readable cues.");
|
|
84
|
+
}
|
|
85
|
+
const media = await fetchMediaInfo(ks, entryId, fetchImpl);
|
|
86
|
+
return {
|
|
87
|
+
cues,
|
|
88
|
+
format,
|
|
89
|
+
language: asset.languageCode ?? asset.language ?? null,
|
|
90
|
+
title: media.title,
|
|
91
|
+
durationSeconds: media.durationSeconds,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=kaltura.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kaltura.js","sourceRoot":"","sources":["../../../src/utils/transcript/kaltura.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
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
|
+
* Which video platform a content topic's URL points at, and the identifiers
|
|
8
|
+
* each platform's transcript adapter needs. get_course_content's own
|
|
9
|
+
* `typeFilter: "video"` match is a blunt `youtube|vimeo|kaltura|video` regex
|
|
10
|
+
* on the URL; this is the more accurate classifier get_video_transcript
|
|
11
|
+
* needs before it can pick an adapter.
|
|
12
|
+
*/
|
|
13
|
+
export type VideoPlatform = "kaltura" | "youtube" | "panopto" | "yuja" | "echo360" | "vimeo" | "unknown";
|
|
14
|
+
export declare function detectVideoPlatform(url: string): VideoPlatform;
|
|
15
|
+
export interface KalturaIds {
|
|
16
|
+
partnerId: string;
|
|
17
|
+
entryId: string;
|
|
18
|
+
}
|
|
19
|
+
/** Kaltura embeds carry the entry and partner ID as query params or path segments; naming varies by embed generator. */
|
|
20
|
+
export declare function extractKalturaIds(url: string): KalturaIds | null;
|
|
21
|
+
/** youtube.com/watch?v=, youtu.be/, and /embed/ links. */
|
|
22
|
+
export declare function extractYouTubeVideoId(url: string): string | null;
|
|
23
|
+
//# sourceMappingURL=platform.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../../../src/utils/transcript/platform.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;GAMG;AAEH,MAAM,MAAM,aAAa,GACrB,SAAS,GACT,SAAS,GACT,SAAS,GACT,MAAM,GACN,SAAS,GACT,OAAO,GACP,SAAS,CAAC;AAoBd,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAgB9D;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wHAAwH;AACxH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CA6BhE;AAED,0DAA0D;AAC1D,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAmBhE"}
|
|
@@ -0,0 +1,98 @@
|
|
|
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
|
+
function safeHostname(url) {
|
|
7
|
+
try {
|
|
8
|
+
return new URL(url).hostname.toLowerCase();
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Kaltura's KAF "browseAndEmbed" front end (what a school's own branded
|
|
16
|
+
* domain, e.g. BoilerCast, typically uses) puts params as path segments
|
|
17
|
+
* rather than a query string: `/browseandembed/index/media/entry_id/1_abc/wid/_123`.
|
|
18
|
+
*/
|
|
19
|
+
function pathSegmentParam(pathname, name) {
|
|
20
|
+
const match = pathname.match(new RegExp(`/${name}/([^/]+)`, "i"));
|
|
21
|
+
return match?.[1] ?? null;
|
|
22
|
+
}
|
|
23
|
+
export function detectVideoPlatform(url) {
|
|
24
|
+
const host = safeHostname(url);
|
|
25
|
+
if (!host)
|
|
26
|
+
return "unknown";
|
|
27
|
+
// Kaltura is embedded either from its own multi-tenant domains (kaltura.com,
|
|
28
|
+
// mediaspace.kaltura.com) or from a school's own KAF front end (e.g.
|
|
29
|
+
// BoilerCast at Purdue), which is why entry_id/wid are also checked as
|
|
30
|
+
// query params or path segments before falling back to "unknown".
|
|
31
|
+
if (/kaltura/.test(host))
|
|
32
|
+
return "kaltura";
|
|
33
|
+
if (/youtube\.com$|youtu\.be$/.test(host))
|
|
34
|
+
return "youtube";
|
|
35
|
+
if (/panopto/.test(host))
|
|
36
|
+
return "panopto";
|
|
37
|
+
if (/yuja/.test(host))
|
|
38
|
+
return "yuja";
|
|
39
|
+
if (/echo360/.test(host))
|
|
40
|
+
return "echo360";
|
|
41
|
+
if (/vimeo/.test(host))
|
|
42
|
+
return "vimeo";
|
|
43
|
+
if (extractKalturaIds(url))
|
|
44
|
+
return "kaltura";
|
|
45
|
+
return "unknown";
|
|
46
|
+
}
|
|
47
|
+
/** Kaltura embeds carry the entry and partner ID as query params or path segments; naming varies by embed generator. */
|
|
48
|
+
export function extractKalturaIds(url) {
|
|
49
|
+
let parsed;
|
|
50
|
+
try {
|
|
51
|
+
parsed = new URL(url);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
const params = parsed.searchParams;
|
|
57
|
+
const pathname = parsed.pathname;
|
|
58
|
+
const pathEntryMatch = pathname.match(/\/(?:media\/t|id|entryid)\/([\w-]+)/i);
|
|
59
|
+
const entryId = params.get("entry_id") ??
|
|
60
|
+
params.get("entryId") ??
|
|
61
|
+
pathEntryMatch?.[1] ??
|
|
62
|
+
pathSegmentParam(pathname, "entry_id") ??
|
|
63
|
+
null;
|
|
64
|
+
const widParam = params.get("wid") ??
|
|
65
|
+
params.get("partner_id") ??
|
|
66
|
+
params.get("partnerId") ??
|
|
67
|
+
params.get("pid") ??
|
|
68
|
+
pathSegmentParam(pathname, "wid") ??
|
|
69
|
+
pathSegmentParam(pathname, "partner_id");
|
|
70
|
+
const partnerId = widParam ? widParam.replace(/^_/, "") : null;
|
|
71
|
+
if (!entryId || !partnerId)
|
|
72
|
+
return null;
|
|
73
|
+
return { partnerId, entryId };
|
|
74
|
+
}
|
|
75
|
+
/** youtube.com/watch?v=, youtu.be/, and /embed/ links. */
|
|
76
|
+
export function extractYouTubeVideoId(url) {
|
|
77
|
+
let parsed;
|
|
78
|
+
try {
|
|
79
|
+
parsed = new URL(url);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
const host = parsed.hostname.toLowerCase();
|
|
85
|
+
if (host === "youtu.be" || host.endsWith(".youtu.be")) {
|
|
86
|
+
return parsed.pathname.slice(1).split("/")[0] || null;
|
|
87
|
+
}
|
|
88
|
+
if (host.endsWith("youtube.com") || host.endsWith("youtube-nocookie.com")) {
|
|
89
|
+
const v = parsed.searchParams.get("v");
|
|
90
|
+
if (v)
|
|
91
|
+
return v;
|
|
92
|
+
const embedMatch = parsed.pathname.match(/\/embed\/([\w-]+)/);
|
|
93
|
+
if (embedMatch)
|
|
94
|
+
return embedMatch[1];
|
|
95
|
+
}
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=platform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform.js","sourceRoot":"","sources":["../../../src/utils/transcript/platform.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
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 type { CaptionFormat, TranscriptCue } from "./captions.js";
|
|
7
|
+
/** What every platform adapter (kaltura.ts, youtube.ts, ...) resolves to on success. */
|
|
8
|
+
export interface TranscriptResult {
|
|
9
|
+
cues: TranscriptCue[];
|
|
10
|
+
format: CaptionFormat;
|
|
11
|
+
language: string | null;
|
|
12
|
+
title: string | null;
|
|
13
|
+
durationSeconds: number | null;
|
|
14
|
+
}
|
|
15
|
+
/** Minimal fetch surface an adapter needs, so tests can inject a stub instead of touching global fetch. */
|
|
16
|
+
export type FetchLike = (url: string) => Promise<{
|
|
17
|
+
ok: boolean;
|
|
18
|
+
status: number;
|
|
19
|
+
json(): Promise<unknown>;
|
|
20
|
+
text(): Promise<string>;
|
|
21
|
+
}>;
|
|
22
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/utils/transcript/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAElE,wFAAwF;AACxF,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,aAAa,EAAE,CAAC;IACtB,MAAM,EAAE,aAAa,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,2GAA2G;AAC3G,MAAM,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IAC/C,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IACzB,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CACzB,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/utils/transcript/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,8 @@
|
|
|
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 type { FetchLike, TranscriptResult } from "./types.js";
|
|
7
|
+
export declare function getYouTubeTranscript(videoId: string, fetchImpl: FetchLike): Promise<TranscriptResult>;
|
|
8
|
+
//# sourceMappingURL=youtube.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"youtube.d.ts","sourceRoot":"","sources":["../../../src/utils/transcript/youtube.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAWH,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAyB9D,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA0B3G"}
|
|
@@ -0,0 +1,57 @@
|
|
|
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
|
+
* YouTube transcript retrieval via its public timedtext endpoint. No
|
|
8
|
+
* authentication is needed — this is the same caption track a signed-out
|
|
9
|
+
* browser can fetch — so unlike Kaltura there is no session to reuse or fail
|
|
10
|
+
* to obtain.
|
|
11
|
+
*/
|
|
12
|
+
import { parseCaptions } from "./captions.js";
|
|
13
|
+
import { NoTranscriptError, TranscriptFetchError } from "./errors.js";
|
|
14
|
+
const TIMEDTEXT_BASE = "https://www.youtube.com/api/timedtext";
|
|
15
|
+
async function listCaptionTracks(videoId, fetchImpl) {
|
|
16
|
+
const res = await fetchImpl(`${TIMEDTEXT_BASE}?type=list&v=${encodeURIComponent(videoId)}`);
|
|
17
|
+
if (!res.ok) {
|
|
18
|
+
throw new TranscriptFetchError(`YouTube caption list request failed (HTTP ${res.status}).`);
|
|
19
|
+
}
|
|
20
|
+
const xml = await res.text();
|
|
21
|
+
return [...xml.matchAll(/<track\b[^>]*\blang_code="([^"]+)"/g)].map((m) => m[1]);
|
|
22
|
+
}
|
|
23
|
+
async function fetchTitle(videoId, fetchImpl) {
|
|
24
|
+
try {
|
|
25
|
+
const watchUrl = `https://www.youtube.com/watch?v=${encodeURIComponent(videoId)}`;
|
|
26
|
+
const res = await fetchImpl(`https://www.youtube.com/oembed?url=${encodeURIComponent(watchUrl)}&format=json`);
|
|
27
|
+
if (!res.ok)
|
|
28
|
+
return null;
|
|
29
|
+
const data = (await res.json());
|
|
30
|
+
return data.title ?? null;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export async function getYouTubeTranscript(videoId, fetchImpl) {
|
|
37
|
+
const tracks = await listCaptionTracks(videoId, fetchImpl);
|
|
38
|
+
if (tracks.length === 0) {
|
|
39
|
+
throw new NoTranscriptError("This YouTube video has no caption tracks available.");
|
|
40
|
+
}
|
|
41
|
+
const lang = tracks.find((t) => t.startsWith("en")) ?? tracks[0];
|
|
42
|
+
const res = await fetchImpl(`${TIMEDTEXT_BASE}?lang=${encodeURIComponent(lang)}&v=${encodeURIComponent(videoId)}&fmt=vtt`);
|
|
43
|
+
if (!res.ok) {
|
|
44
|
+
throw new TranscriptFetchError(`YouTube caption download failed (HTTP ${res.status}).`);
|
|
45
|
+
}
|
|
46
|
+
const vtt = await res.text();
|
|
47
|
+
if (!vtt.trim()) {
|
|
48
|
+
throw new NoTranscriptError("This YouTube video has no caption tracks available.");
|
|
49
|
+
}
|
|
50
|
+
const { format, cues } = parseCaptions(vtt);
|
|
51
|
+
if (cues.length === 0) {
|
|
52
|
+
throw new NoTranscriptError("This YouTube video has a caption track, but it contained no readable cues.");
|
|
53
|
+
}
|
|
54
|
+
const title = await fetchTitle(videoId, fetchImpl);
|
|
55
|
+
return { cues, format, language: lang, title, durationSeconds: null };
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=youtube.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"youtube.js","sourceRoot":"","sources":["../../../src/utils/transcript/youtube.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": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
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",
|