blackboard-mcp
Blackboard MCP is a local MCP server that gives AI assistants read (and optionally write) access to your Blackboard Learn Ultra account through your own browser session.
Identity & courses: see who you are (
bb_whoami), check session status, list courses, terms, rosters, and course detailsContent discovery: browse full course content trees, list folder contents, read item details, and search titles/bodies across one or all courses
File access: list, read (PDF/HTML/text) and download course files, bulk-download course materials, download submitted assignment files, and read Google Slides/Docs/Sheets linked as course material
Grades & feedback: list grades across courses, view grade detail with attempts and instructor feedback, summarize per-course standing, and review quiz attempts question-by-question
Deadlines & scheduling: get a triaged to-do list of overdue/upcoming work, view calendar events, and see recurring course meeting schedules
Communication: read announcements, the activity stream, conversation threads, discussion forums/replies, unread counts, and attendance records
Escape hatches: call any Blackboard API path directly (
bb_raw_request), batch multiple reads (bb_batch_request), and list known endpointsOptional writes (off by default): start/save/submit quiz attempts, submit text assignments, save drafts, and mark content reviewed
Reads Google Docs documents linked as course material in Blackboard, extracting their text through the provider's export endpoint so they can be handled like attached files.
Reads Google Slides presentations linked as course material in Blackboard, extracting their text through the provider's export endpoint so they can be handled like attached files.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@blackboard-mcp What do I have due this week?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
blackboard-mcp
An MCP server for Blackboard Learn (Ultra). Gives Claude, Codex, Cursor and any other MCP client read access to your courses, content, files, grades, deadlines, announcements and discussions, using your own browser session.
npx blackboard-mcp auth login # sign in once
npx blackboard-mcp install # register with your MCP clientThen ask your assistant things like:
What do I have due this week? Read me the lecture 4 slides from Machine Learning. How am I doing across all my courses? Catch me up, I've been away a week.
Why this exists
Blackboard's documented REST API requires an OAuth application registered and approved by your institution's Blackboard administrator. Most students and many staff can't get one.
This package targets the internal Ultra API instead: the surface the Blackboard web interface itself calls, authenticated with nothing but a session cookie. It also exposes more than the public API does, including to-do lists, the activity stream, conversations, discussion read state and attendance.
It is read-only in practice, and does not cover quizzes, rubrics or submitting work. See Limitations below.
Related MCP server: McGill myCourses MCP Server
Install
Requires Node.js 22.5+. Older versions work but must sign in with --paste.
npm install -g blackboard-mcpOr run it without installing, which is what the generated client config uses:
npx -y blackboard-mcpSigning in
blackboard-mcp auth loginThat's the whole flow. No URL, no cookies, no DevTools, no password.
It reads the session from the browser you're already signed in to. Blackboard's BbRouter cookie is emitted only by Blackboard Learn, so finding it identifies both that you have a session and which instance it belongs to. Candidates are verified against the live API before anything is stored.
$ blackboard-mcp auth login
Signed in as Ada Lovelace (a.lovelace@student.example.edu)
Instance: https://blackboard.example.edu
Imported by: browser (automatic)
Auto-refresh: ENABLEDWorks with Chrome, Edge, Brave, Chromium, Vivaldi, Opera and Firefox, including multiple profiles. To see what it can find:
blackboard-mcp auth browsersYou won't have to sign in again
Blackboard sessions expire after about three hours. Two mechanisms avoid re-authenticating:
Keep-alive. While the server runs it pings Blackboard's session endpoint, resetting the inactivity timer. An idle session never expires.
Silent renewal. If the session lapses anyway, the institution's SSO redirect chain is replayed against your identity provider. This is what your browser does when you reload after being logged out.
Renewal works because identity provider sessions outlive Blackboard's by weeks or months. auth login imports those cookies alongside Blackboard's, so renewal needs no human:
GET /ultra -> 302
GET / -> 302
GET /auth-saml/saml/login -> 302
GET login.microsoftonline.com/ -> 200 (auto-submit SAMLResponse)
POST /auth-saml/saml/SSO -> 302
GET /ultra -> 200 (new session)The implementation follows redirects and resubmits whatever SSO form comes back, so SAML, WS-Federation and Shibboleth all work without provider-specific code.
auth login verifies this before reporting Auto-refresh: ENABLED, by forcing one full chain through your provider. It then narrows the stored cookies to Blackboard plus your actual provider, discarding anything imported speculatively.
To renew manually:
blackboard-mcp auth refreshIf browser import can't work
Two cases, both reported with the fallback:
Chrome 127+ on Windows uses App-Bound Encryption, which by design can't be read by another process.
Node older than 22.5 lacks the built-in SQLite needed to read cookie stores.
The manual path:
blackboard-mcp auth login --pasteThis asks you to paste a "Copy as cURL" from DevTools (Network tab, right-click a request, Copy, Copy as cURL). A pasted request carries only Blackboard's cookies, not your provider's, so these sessions can't auto-renew and need signing in again every few hours.
Blackboard's session cookie is
HttpOnly, sodocument.cookiecan't see it. It only appears on a real request.
Non-interactive:
BLACKBOARD_COOKIE='BbRouter=...; JSESSIONID=...' \
blackboard-mcp auth login --url https://blackboard.your-university.eduTo check state:
blackboard-mcp auth status
blackboard-mcp doctor # full diagnosticsClients
Auth is not per client. blackboard-mcp auth login stores one encrypted session in ~/.blackboard-mcp/, and every client on that machine reads it. Sign in once, then register the server wherever you want it.
blackboard-mcp auth login # once, per machine
blackboard-mcp install # print config for every known client
blackboard-mcp install cursor --write # or merge it in automatically--write merges into the existing config rather than overwriting it.
What works where
This is a local MCP server. It runs on your machine over stdio, because it reads your browser session and your Blackboard files, neither of which exists on a server somewhere.
Client | Supported | How |
Claude Code (terminal) | yes |
|
Claude Code (desktop app) | yes | same config as the terminal |
Claude Desktop | yes |
|
Codex CLI | yes |
|
Cursor | yes |
|
Windsurf | yes |
|
VS Code (Copilot) | yes |
|
Zed | yes |
|
claude.ai in a browser | no | accepts remote servers only |
Claude for Work / Team / Enterprise (web) | no | remote only, plus admin approval |
ChatGPT (web) | no | remote only |
Codex cloud | no | runs server-side, no access to your machine |
The four "no" rows are all the same limitation, explained under Web clients below.
Claude Code
Terminal, and the desktop app's Code tab, share ~/.claude.json, so one command covers both:
claude mcp add blackboard --scope user -- npx -y blackboard-mcp--scope user makes it available in every project. Drop it to scope the server to the current directory only, or use --scope project to write a .mcp.json your teammates get too. Restart the desktop app to pick up a change made in the terminal.
Verify:
claude mcp listClaude Desktop
Edit claude_desktop_config.json:
macOS:
~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:
%APPDATA%\Claude\claude_desktop_config.jsonLinux:
~/.config/Claude/claude_desktop_config.json
{
"mcpServers": {
"blackboard": { "command": "npx", "args": ["-y", "blackboard-mcp"] }
}
}Restart Claude Desktop fully, then look for the tools under the attachments menu.
Codex CLI
Add to ~/.codex/config.toml. Note the key is mcp_servers, with an underscore:
[mcp_servers.blackboard]
command = "npx"
args = ["-y", "blackboard-mcp"]Or let the CLI write it:
codex mcp add blackboard -- npx -y blackboard-mcpCursor and Windsurf
Same shape as Claude Desktop, different file:
Cursor, all projects:
~/.cursor/mcp.jsonCursor, one project:
.cursor/mcp.jsonWindsurf:
~/.codeium/windsurf/mcp_config.json
{
"mcpServers": {
"blackboard": { "command": "npx", "args": ["-y", "blackboard-mcp"] }
}
}VS Code
.vscode/mcp.json in the workspace. The top-level key is servers, not mcpServers:
{
"servers": {
"blackboard": { "command": "npx", "args": ["-y", "blackboard-mcp"] }
}
}Zed
In settings.json, under context_servers:
{
"context_servers": {
"blackboard": {
"source": "custom",
"command": { "path": "npx", "args": ["-y", "blackboard-mcp"] }
}
}
}Zed's schema for this has changed between releases, so if it does not pick the server up, check Zed's current context-server docs. Every other client in this list uses the flat {"command": "npx", "args": [...]} form.
Any other MCP client
The server speaks MCP over stdio. Anything that can launch a subprocess can use it:
command: npx
args: ["-y", "blackboard-mcp"]Optional environment: BLACKBOARD_MCP_ALLOW_WRITES=1 to permit writes, BLACKBOARD_MCP_LOG_LEVEL=debug to troubleshoot. Everything else is read from ~/.blackboard-mcp/.
To confirm a client can talk to it, run the official inspector:
npx @modelcontextprotocol/inspector npx -y blackboard-mcpWeb clients
claude.ai in a browser, Claude for Work on the web, ChatGPT on the web and Codex cloud all reach MCP servers over HTTP, at a public URL. They cannot launch a process on your laptop, which is the only place your Blackboard session exists. So this server does not work in any of them today, and no configuration change makes it work.
Closing that gap means running the server as a hosted HTTP service, which has a consequence worth being explicit about: that service would hold your Blackboard session, and anyone who reached its URL could read your grades and coursework. It would need its own authentication in front of it, and you would be trusting a host with your student credentials.
If you want that, the honest options are:
Keep it local. Use a desktop or terminal client. This is what the package is designed for.
Run it yourself behind a tunnel plus authentication, with the session staying on hardware you control.
Use the official Blackboard REST API instead for anything hosted. It uses OAuth rather than a borrowed session, which is the right shape for a web integration, though it requires an app your institution's Blackboard administrator has approved.
Tools
Every course tool takes a courseId, an internal id like _12345_1 rather than the human course code. Get them from bb_list_courses.
Courses and identity
Tool | Purpose |
| Signed-in user and instance |
| Session validity, expiry, cookies |
| Enrolled courses with ids, terms, roles. Start here |
| Course detail and enabled tools |
| Academic terms |
| Participants and their roles |
Content
Tool | Purpose |
| Recursive content tree with folder paths. The main discovery tool |
| One level of a folder |
| Item detail: body text, attached file, link target, due date |
| Search titles and bodies, one course or all |
Files
Tool | Purpose |
| Download and extract text. Pages through long PDFs |
| Save a file to disk |
| Every readable document in a course |
| Bulk download or archive a course |
| Files submitted with an assignment attempt |
Grades
Tool | Purpose |
| Grades for one course or all |
| Score, letter grade, attempts, submissions, instructor feedback |
| Per-course standing and averages |
| Read a quiz back question by question, with your answers and scores |
| Definitive "has this been submitted?", with attempt id and timestamp |
Deadlines
Tool | Purpose |
| Overdue, due today and upcoming across all courses |
| Calendar events in a date range |
| A course's recurring meetings |
Communication
Tool | Purpose |
| Announcements with full text, one course or all |
| Recent changes across every course |
| Course message threads |
| Discussion forums, posts and replies |
| Unread counts across all courses |
| Attendance records |
Escape hatch
Tool | Purpose |
| Call any Blackboard API path directly |
| Up to 20 reads in one round trip |
| Every endpoint this server knows |
| Mark content reviewed (write, off by default) |
Writes
Off unless BLACKBOARD_MCP_ALLOW_WRITES=1 is set.
Tool | Purpose |
| Open an attempt on an assessment and list its questions |
| Answer one question. Overwritable until submitted |
| Save text as a draft, not visible to the instructor, reversible |
| Submit text for grading. Irreversible, requires |
| Submit an in-progress quiz. Irreversible, requires |
Both submit tools have three gates: writes must be enabled, confirm must be true, and an existing or already-submitted attempt is refused. Each returns Blackboard's receipt id, which is your proof of submission, and flags a late submission.
bb_submit_quiz_attempt only changes an attempt's status; answers must already be saved on it. An auto-graded test is scored the moment it is submitted, so there is no undo. Inspect the attempt with bb_review_quiz_attempt and get the user's explicit go-ahead first.
Assignment submission is text only, since the file upload flow is not implemented.
bb_save_quiz_answer resolves loose input against the question, so option numbers, option text, booleans for true/false, plain text for essays and numbers for numeric questions all work, and it echoes back how the input was read so you can check it before submitting. Answers are overwritable until the attempt is submitted.
Blackboard strips a question from a submitted attempt when the course hides results, so option resolution works only while an attempt is IN_PROGRESS. On a completed attempt, pass the raw givenAnswer instead.
The Ultra API is larger than what's wrapped here. bb_raw_request is the answer when the tool you need doesn't exist.
Prompts
Workflows your client surfaces as slash commands:
whats_duedeadlines, triaged, with submission statuscourse_briefingfull picture of one coursestudy_packfind, read and synthesise material on a topiccatch_upeverything that changed while you were awaygrade_reportstanding across all courses, with feedback themesfind_materiallocate a specific file or reading
Resources
blackboard://meyour profileblackboard://coursescourse listblackboard://course/{courseId}/outlinefull content tree as JSON
Reading files
bb_read_file extracts text from PDF, HTML and plain-text formats, including code, CSV, JSON, Markdown and subtitles.
Long documents are windowed rather than truncated. A PDF returns a page range plus a note telling the model how to continue, so a 300-page course reader is fully readable without flooding the context.
Office formats (.docx, .pptx, .xlsx) and archives can't be extracted. They're ZIP containers needing an unzip implementation Node doesn't ship, and a native dependency would break npx installs. They still download fine via bb_download_file.
Scanned PDFs with no text layer are detected and reported as needing OCR, rather than returning an empty string that looks like a bug.
Linked documents
Instructors often publish lecture material as a Google Slides, Docs or Sheets link rather than an uploaded file, leaving no bytes in Blackboard at all. bb_read_file resolves these through the provider's export endpoint, so a linked deck reads like an attached file, and bb_list_files lists them as course material.
Two constraints, because that URL is written by a third party and arrives as untrusted content:
Provider allowlist. Only Google Docs hosts with a documented export endpoint are fetched. Without this, a pasted link would turn the tool into an arbitrary URL fetcher.
No credentials. These fetches carry no Blackboard session and no Google auth, so only material the instructor already made link-shareable is reachable. A privately shared document reports that plainly instead of returning a sign-in page dressed up as slides.
Formats default to the cheapest to read (txt for decks and documents, csv for sheets). Pass format for pdf, pptx, docx or xlsx.
Timestamps are UTC
Every timestamp the API returns is true UTC, and the Z suffix means what it says. This is worth stating because the Ultra web interface renders in the viewer's timezone, which makes "local wall clock stamped as Z" a reasonable suspicion, and that is exactly the wrong conclusion to reach about a deadline.
Two worked examples from a live tenant:
A deadline shown in the UI as 23:59 Europe/Madrid comes back as
2026-09-16T21:59:00.000Z. The:59is the fingerprint of a correctly stored local 23:59.A submission made at 14:07 Madrid reads back as
submitted: 2026-09-18T12:07:53.407Z.
So convert for display, and never treat the value as local. Telling a student the wrong deadline is this library's highest-consequence silent failure.
Adapting to your institution
Learn releases and reverse proxies move endpoints around. If something 404s, record a browser session and import it:
blackboard-mcp har import ~/Downloads/blackboard.har --verboseThis detects your instance, compares every real path against the built-in templates, writes corrections to ~/.blackboard-mcp/endpoints.json, and lists the endpoints your tenant exposes that this package doesn't model. Those stay reachable through bb_raw_request.
To record a HAR: DevTools, Network tab, check Preserve log, browse Blackboard, then right-click and Save all as HAR with content.
Current Chrome strips cookies from HAR exports, so a HAR can't sign you in. That's a good default, since a HAR with cookies is a credential file. Treat one like a password.
Security
Read-only by default. Non-GET requests are refused unless
BLACKBOARD_MCP_ALLOW_WRITES=1is set. Two Blackboard read operations use non-GET verbs (the batch fan-out and the activity stream) and are explicitly allowed.Sessions are encrypted at rest with AES-256-GCM. The key lives in the macOS Keychain or Linux Secret Service, falling back to a
0600keyfile. State lives in~/.blackboard-mcp/.Browser cookies are read locally only. Cookie stores are copied, decrypted with a key the OS already grants this user, and never transmitted. Import pulls identity provider cookies broadly at first, since the provider isn't knowable before the SSO chain names it, so the first renewal prunes the stored jar down to Blackboard plus your actual provider.
Cookies never leave your instance. The HTTP client enforces a host allowlist across every redirect hop, so the session can't be sent to a third party even if a redirect or an instructor-pasted link points there.
Renewal is scoped by delegation. The SSO replay only sends cookies to your Blackboard host and to hosts Blackboard's own redirect chain named.
Untrusted input is treated as data. Server-supplied filenames are sanitised before touching the filesystem, and embedded links are accepted only as instance-relative paths.
bb_raw_requestis restricted to API path prefixes and rejects traversal.
Your Blackboard account governs what's visible. This server reads exactly what you can read in a browser, and nothing more.
A note on academic data
Grades, feedback and submissions are confidential personal data, and fall under GDPR in the EU and UK. Downloaded files land on your local disk unencrypted, so mind where they go and prefer the narrowest tool for the question. If you're staff acting on student data rather than your own, check your institution's data-handling policy first.
Configuration
Variable | Meaning |
| Instance origin, overriding stored config |
| Session cookie for non-interactive login |
|
|
| Where files are saved |
| Per-file ceiling, default 100 MB |
| Default list page size, default 50 |
|
|
| State directory, default |
Use as a library
The package is a usable Blackboard SDK on its own:
import { BlackboardClient } from 'blackboard-mcp';
const bb = await BlackboardClient.create();
for (const m of await bb.listCourses({ availableOnly: true })) {
console.log(m.course?.displayName);
}
// Recursive content tree, both roots
const items = await bb.walkContents('_12345_1');
// Fan out across courses in one request
const grades = await bb.batch([
{ method: 'GET', relativeUrl: 'v1/courses/_12345_1/gradebook/grades?userId=_1_1' },
]);CLI
blackboard-mcp [serve] Run the MCP server on stdio (default)
blackboard-mcp auth login Sign in, importing from your browser
blackboard-mcp auth status Session and connectivity status
blackboard-mcp auth browsers List browser profiles and sessions found
blackboard-mcp auth refresh Renew the session without signing in
blackboard-mcp auth logout [--purge] Forget the session
blackboard-mcp har import <file> Learn this tenant's endpoints
blackboard-mcp doctor Diagnose configuration
blackboard-mcp install [client] Register with an MCP client
blackboard-mcp courses List your courses
blackboard-mcp endpoints [filter] Show the endpoint mapTroubleshooting
Run blackboard-mcp doctor first.
NOT_CONFIGURED or NOT_AUTHENTICATED. Run blackboard-mcp auth login.
SESSION_EXPIRED. The session lapsed and couldn't be renewed silently. If auth status shows auto-refresh unavailable, re-run auth login without --paste to capture identity provider cookies. If it shows enabled, your provider session has itself expired: open Blackboard in a browser, sign in, then auth login again.
"No Blackboard session found in any browser". Sign in to Blackboard in a browser first. auth browsers shows what was scanned.
"The captured session was rejected". You copied a request from your SSO provider rather than the Blackboard host, or the tab had already logged out. Copy a request whose URL is your Blackboard hostname.
A tool 404s. Your tenant may differ. Run har import <har> --verbose, then use bb_raw_request for anything unmapped.
Empty course list. Courses you hid in Blackboard are excluded by default; pass includeHidden: true. Organizations are excluded too; pass organizations: "include".
bb_read_file returns nothing for a PDF. It's a scan with no text layer and needs OCR. If your institution has Blackboard Ally, the course may offer an accessible alternative format.
A linked Google deck won't read. It's shared privately rather than link-shared. Only material the instructor made publicly accessible can be fetched, since no credentials are used.
Development
pnpm install
pnpm build
pnpm test # protocol and unit tests
pnpm typecheck
pnpm inspect # MCP Inspector against the built serverLimitations
Read-only by default. Assignment submission exists but is off unless you enable writes, and it is text only. Posting discussion replies and sending messages aren't implemented.
No file attachments on submissions. The upload flow has not been captured, so a submission carries text only. Do not rely on it for work that must include a file.
Auto-renewal needs a browser-imported session. A
--pastesession has no identity provider cookies and will expire in a few hours.Office formats download but don't extract.
No OCR for scanned PDFs.
Ultra-oriented. Courses in the older Classic experience expose less through this API.
bb_raw_requestis the fallback.Unofficial. This uses an internal API with no stability guarantee. Blackboard may change it without notice, which is why HAR import exists.
Legal
Not affiliated with, endorsed by, or supported by Anthology Inc. or Blackboard. "Blackboard" and "Blackboard Learn" are trademarks of their respective owners.
This tool accesses your own account with your own credentials, reading the same data your browser shows you. Your institution's acceptable-use policy still applies. Don't use it to access data that isn't yours.
MIT
Available Tools
31 toolsbb_activity_streamBlackboard activity streamARead-only
The Ultra activity stream: recent grade postings, new content, announcements and due-date reminders across all courses, newest first. A good single call for "what changed recently?".
Inputs: limit, flushCache.
bb_announcementsRead Blackboard announcementsARead-only
Lists course announcements with their full text, newest first. Covers every enrolled course by default (via the batch API), or one course when courseId is given. Use this for "what did my instructors post?" or catching up after time away.
Inputs: limit, courseId, fullText, maxCourses, +1 more.
bb_attendanceGet course attendance recordsARead-only
Lists the attendance records recorded for the signed-in user in a course (present/absent/late/excused per session), when the instructor uses Blackboard attendance.
Inputs: courseId (required), limit.
bb_batch_requestCall several Blackboard endpoints at onceARead-only
Fans out up to 20 GET reads in a single round trip using Blackboard's own batch endpoint. Paths are version-relative, e.g. "v1/courses/_12345_1/groups". Much cheaper than repeated bb_raw_request calls when gathering the same data across many courses.
Inputs: paths (required), maxChars.
bb_browse_courseBrowse a course content treeARead-only
Walks the full content outline of a course recursively and returns every item with its folder path, type, and any attached file. This is the primary way to discover what material a course contains. Use maxDepth/maxNodes to bound very large courses.
Inputs: courseId (required), type, rootId, maxDepth, +2 more.
bb_calendarBlackboard calendar eventsARead-only
Lists calendar entries in a date range: class sessions, instructor-created events, and assignment due dates. Covers all courses by default. Use bb_todo instead when the question is specifically about assignment deadlines.
Inputs: days, limit, since, until, +1 more.
bb_course_scheduleGet a course meeting scheduleARead-only
Lists the recurring class meetings configured for a course (day, time, room). Empty for courses whose instructor never set one up.
Inputs: courseId (required).
bb_download_course_filesBulk download a course's filesARead-only
Walks a course and downloads every attached file to a local folder, organised by course. Use for archiving a course or grabbing all slides at once. Respects the configured size limit per file and skips files already on disk.
Inputs: courseId (required), maxFiles, maxNodes, extension.
bb_download_fileDownload a course file to diskARead-only
Downloads a file from a content item and saves it locally without extracting text. Use this for Office documents, images, archives, or anything the user wants to keep. Also handles content items that link to Google Slides/Docs/Sheets, fetching the export (pptx/docx/xlsx/pdf). Returns the saved path.
Inputs: courseId (required), contentId (required), all, format, +1 more.
bb_download_submissionDownload a submitted assignment fileARead-only
Downloads the files the student submitted with an assignment attempt. Use bb_get_grade_detail first to find the attemptId and columnId.
Inputs: columnId (required), courseId (required), attemptId (required).
bb_get_contentRead a course content itemARead-only
Full detail for one content item: its rendered body text, attached file metadata, external link target, due date, and any files embedded in the body HTML. Use this to actually read an announcement-style document or assignment brief.
Inputs: courseId (required), contentId (required), includeChildren.
bb_get_courseGet Blackboard course detailsARead-only
Full detail for one course: name, code, term, availability window, Ultra/Classic mode, and the tools enabled in it.
Inputs: courseId (required), includeTools.
bb_get_grade_detailGet grade detail with feedbackARead-only
Everything about one gradebook item: the score, rubric/points, due date, every attempt with its timestamp and status, the student's submitted text, and the instructor's written feedback. This is where feedback lives. The grade list does not carry it.
Inputs: columnId (required), courseId (required), includeAttempts.
bb_grade_summarySummarise grade standing per courseARead-only
Computes, per course, how many items are graded, the running points total, and the average percentage. Use this for "how am I doing overall?" questions rather than listing every item.
Inputs: maxCourses.
bb_list_contentList content in a course folderARead-only
Lists the immediate children of a course folder or lesson, or the top level of the course when no folder is given. Prefer bb_browse_course unless you specifically want one level.
Inputs: courseId (required), limit, contentId.
bb_list_conversationsList course messagesARead-only
Lists the message threads (Blackboard "conversations") in a course, and optionally the messages inside one thread.
Inputs: courseId (required), limit, conversationId.
bb_list_coursesList my Blackboard coursesARead-only
Lists the courses the signed-in user is enrolled in, with course id, name, term, role and last-access date. The returned courseId (like _12345_1) is what every other course tool needs. Start here.
Inputs: term, search, availableOnly, includeHidden, +1 more.
bb_list_discussionsRead course discussionsARead-only
Reads a discussion forum: its top-level posts, and the replies to one post when messageId is given. Find the forumId from a "discussion" item in bb_browse_course (its contentDetail carries conferenceId/id).
Inputs: forumId (required), courseId (required), limit, messageId.
bb_list_endpointsList known Blackboard endpointsARead-only
Shows every Blackboard API endpoint this server knows, with the operation name and its path template, plus any local overrides. Useful for discovering what to pass to bb_raw_request.
Inputs: filter.
bb_list_filesList downloadable files in a courseARead-only
Walks a course and lists every readable document: attached files, attachments, files embedded in page bodies, and content items that link to Google Slides, Docs or Sheets. Returns name, type, size and the contentId needed to fetch each one.
Inputs: courseId (required), deep, maxNodes, extension.
bb_list_gradesList Blackboard gradesARead-only
Lists grades for one course, or across every enrolled course when courseId is omitted. Shows each graded item, the score out of its total, and its status. Cross-course mode uses Blackboard's batch API so it costs roughly one request rather than one per course.
Inputs: courseId, gradedOnly, maxCourses.
bb_list_rosterList course participantsARead-only
Lists the people enrolled in a course with their roles. Useful for finding an instructor to contact, or identifying group members.
Inputs: courseId (required), role, limit.
bb_list_termsList Blackboard termsBRead-only
Lists academic terms defined on the instance, with their date ranges.
Inputs: limit.
bb_mark_reviewedMark course content as reviewedAIdempotent
Marks a reviewable content item as reviewed (the "Mark Reviewed" button in Ultra). Requires writes to be enabled with BLACKBOARD_MCP_ALLOW_WRITES=1; this server is read-only by default.
Inputs: courseId (required), contentId (required), reviewed.
bb_raw_requestCall a Blackboard API endpoint directlyA
Escape hatch: issues a request against any Blackboard API path using the stored session, and returns the raw JSON. Use this when no dedicated tool covers what you need. The Ultra internal API (/learn/api/v1/...) exposes far more than this server models. Call bb_list_endpoints first to see what is already wrapped.
Inputs: path (required), body, query, method, +1 more.
bb_read_fileRead a course file as textARead-only
Downloads a file attached to a content item and extracts its text. Also resolves content items that merely LINK to a Google Slides/Docs/Sheets document (common for lecture decks) by fetching the provider export, so reading works the same either way. PDFs are returned a page-window at a time (use fromPage to continue), so a long document will not flood the context. Handles PDF, HTML, and plain-text/code/CSV; Office formats download but cannot be extracted. This is the tool to use to actually read lecture notes or a handout.
Inputs: courseId (required), contentId (required), format, fileName, +4 more.
bb_search_contentSearch course contentARead-only
Searches content item titles and body text for a query string, in one course or across every enrolled course. Use this when the user asks where something is ("where are the lecture slides on transformers?"). Searching all courses walks each tree, so prefer a single courseId when you know it.
Inputs: query (required), limit, courseId, maxCourses, +1 more.
bb_session_statusBlackboard session statusARead-only
Reports how much longer the stored Blackboard session is valid, when it was captured, and which cookies it holds. Call this when other tools start failing with session errors.
Inputs: keepAlive.
bb_todoWhat is due on BlackboardARead-only
The student to-do list: everything overdue, due today, and coming up, across all courses, in one call. This is the right tool for "what do I have due?", "am I behind?", or "what should I work on?". Grouped by urgency and sorted by date.
Inputs: days, lookBackDays, includeOverdue.
bb_unread_countsUnread message and notification countsARead-only
Unread message counts across every course in a single call, plus the overall messages summary. Cheap. Use it to decide whether reading messages is worth it before calling bb_list_conversations.
Inputs: no named parameters.
bb_whoamiWho am I on BlackboardARead-only
Returns the signed-in Blackboard user (name, username, student id, email, institution roles) and the configured instance. Use this to confirm authentication is working before other calls.
Inputs: no named parameters.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 31 tools
Each tool has a clearly distinct purpose, with descriptions that explicitly differentiate overlapping functions (e.g., bb_list_content vs bb_browse_course, bb_read_file vs bb_download_file). The descriptions often include guidance on when to use one over another, eliminating ambiguity.
All tools share the 'bb_' prefix and use lowercase with underscores, but naming patterns vary slightly: most are verb_noun (e.g., bb_list_courses, bb_get_content), but a few deviate (bb_whoami, bb_session_status, bb_batch_request). Overall, the pattern is predictable and readable.
With 31 tools, the server exceeds the threshold for 'too many' (25+). While the Blackboard domain is broad, the large number may overwhelm agents and increase selection complexity, though each tool serves a specific purpose within the LMS.
The server covers the major student-facing workflows: course discovery, content browsing and reading, file downloads, grades, to-dos, calendar, messages, discussions, and announcements. Missing write operations (except mark_reviewed) are acknowledged by the read-only default, but the surface is comprehensive for a read-focused client.
Maintenance
Related MCP Connectors
Teachable MCP server for ChatGPT, Claude and any AI agent: update lecture, create coupon, send email, reply to comment and list enrollments in your own Teachable account. Cotlet works in the account through your Cloud Browser, a real Chrome where you sign in to Teachable yourself; Cotlet does not store your password and you need no Teachable API key. About the official Teachable API: Teachable has a public API, but only on the Growth plan and up, and it reads courses and lecture content and manages users, enrollments, pricing plans and transactions (checked 11 Oct 2026). Lesson editing, coupons, emails to students and comments are not in it. Setup and FAQ: https://cotlet.dev/integrations/teachable-api-mcp-server
LearnWorlds MCP server for ChatGPT, Claude and any AI agent: list users, list course learners, enroll users, unenroll users, update tags, send message, suspend user and grade assessment in your own LearnWorlds account. Cotlet works in the account through your Cloud Browser, a real Chrome where you sign in to LearnWorlds yourself; Cotlet does not store your password and you need no LearnWorlds API key. About the official LearnWorlds API: LearnWorlds has a REST API (v2) for courses, users, bundles, subscriptions, promotions, payments and certifications, but it comes with the Learning Center plan and higher, and you need your own code to use it (checked 5 Nov 2026). LearnWorlds has no official MCP server. Setup and FAQ: https://cotlet.dev/integrations/learnworlds-api-mcp-server
Absorb LMS MCP server for ChatGPT, Claude and any AI agent: list users, list course enrollments, list overdue learners, approve enrollment request, enroll users in a course, message learners, create user and deactivate user in your own Absorb LMS account. Cotlet works in the account through your Cloud Browser, a real Chrome where you sign in to Absorb LMS yourself; Cotlet does not store your password and you need no Absorb LMS API key. About the official Absorb LMS API: Absorb LMS has an Integration API, a REST API with JSON for learners, courses, departments and grades, but it needs a private key tied to your portal that your Absorb account team provides, and your own code (checked 20 Oct 2026). Absorb's Aura MCP for Claude and ChatGPT is planned for 27 Oct 2026 and is read and answer only. Setup and FAQ: https://cotlet.dev/integrations/absorb-lms-api-mcp-server
LearnUpon MCP server for ChatGPT, Claude and any AI agent: list users, invite users, add users to group, enroll group on course, enroll users on course, unenroll users, set enrollment complete and disable user in your own LearnUpon account. Cotlet works in the account through your Cloud Browser, a real Chrome where you sign in to LearnUpon yourself; Cotlet does not store your password and you need no LearnUpon API key. About the official LearnUpon API: LearnUpon has a REST API and a reporting MCP server, but neither covers day-to-day admin work from an AI agent (checked 20 Oct 2026). The REST API uses API keys that an admin generates under Settings > Integrations > API Keys, and Support grants them when the option is missing. Setup and FAQ: https://cotlet.dev/integrations/learnupon-api-mcp-server
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceEnables Claude to read Canvas LMS deadlines, announcements, and grades using an existing browser session, with no admin token required.14 npm4MIT
- AlicenseNot gradedqualityCmaintenanceEnables Claude Desktop to access your McGill University myCourses account, letting you ask about your courses and upcoming deadlines in plain language.Apache 2.0
- AlicenseNot gradedqualityBmaintenanceEnables AI assistants to browse your own university courses by downloading files, slides, announcements, deadlines, grades and lecture transcripts to your machine, then answering questions and searching across them through MCP tools. It logs in with your own account and refreshes only what changed.MIT
- AlicenseNot gradedqualityCmaintenanceConnects Claude, Cursor, Codex and other AI assistants to Canvas LMS through a normal browser sign-in (SSO and MFA included) instead of an access token, letting them read courses, assignments, rubrics, announcements, discussions, grades, calendar and inbox, and read or save course files locally. It is strictly read-only, sending only GET requests, and keeps all session data on the user's own machine.4MIT