BrightspaceMCP
Click on "Install 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., "@BrightspaceMCPwhat's due this week in all my courses?"
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.
Brightspace-MCP
An MCP server that can expose your Brightspace account as tools available for an LLM to call.
Some assignments confound me in format and feed because every professor has a different way of assigning things, being a quiz, a content item, something on the course calendar, or even something else. Each feed is individually incomplete when calling the API so there's availability to call batch functions for multi entry retrieval.
Tools
This section was written by Claude from the tool docstrings in
server.py.
All course-scoped tools take an orgid (the OrgUnit ID) from getClasses.
getBatch* variants take a list of orgids — a real array, a JSON-array string,
or a comma-separated string, since some MCP clients stringify array args — and
fan out across courses concurrently.
Account
getUser— the calling user's profile (whoami).getClasses— current enrollments. Passfalsefor a de-duped, current-term-only list (id/name/code); passtruefor the raw D2L enrollments feed including past and hidden courses. Preferfalseto save tokens.
Grades
getAssignedGrades— the user's grade values for one course.getAllGrades— the full grade objects (definitions + values) for one course.
What's due
getWeeklyTodo/getBatchWeeklyTodo— content-linked items due in the nextdays(default 7). Each item hasItemName,DueDate,ItemUrl.getAllDueItems/getBatchAllDueItems— content-linked items with no date window (past-due through everything upcoming).getWeeklyCalendarEvents/getBatchCalendarEvents— course calendar events in the nextdays(default 7), each with aCalendarEventViewUrl.getQuizzes/getBatchQuizzes— every quiz in the Quizzes tool, whether or not an instructor linked it into content. Inactive quizzes are hidden unlessinclude_inactive=true.getEverythingDue/getBatchEverythingDue— the merged content + quizzes + calendar picture, deduped byGradeItemId(then normalized title). Each entry carries aSourceslist naming the feeds it came from.days(default 180) bounds only the calendar window. Use this when nothing can be missed.
Content
getCourseToc— the course table of contents. Default is a flat list of topics (module path,Type,Url,TopicId,GradeItemId, availability fields);full=truereturns the raw nested D2L tree. The TOC has no due dates or completion state.getTopicFile— downloads the file backing a File-type content topic (GET /le/1.82/{orgid}/content/topics/{topicId}/file). Takesorgidplus atopicIdfromgetCourseToc(only works where the topic'sTypeis a file, not a link/URL topic). ReturnsContentType/FileName/Size, thenTextfor HTML/text/XML/JSON/CSV payloads orBase64for binary ones (PDFs, slide decks, images). Redirects to D2L's signed storage URLs are followed.getSyllabus— the course syllabus / content overview (GET /le/1.82/{orgid}/overview). ReturnsDescription(rich text) andHasAttachment; when an attachment exists it is downloaded too and returned underAttachmentin the sameContentType/FileName/Size/TextorBase64shape asgetTopicFile. Passinclude_attachment=falsefor just the metadata. Not every course uses the overview — if it comes back empty, look for a "Syllabus" File topic viagetCourseToc+getTopicFile.
Completed content items and inactive quizzes are filtered out by default;
include_completed / include_inactive bring them back. Calendar events carry
no completion state, so a calendar-only entry can't be filtered that way —
cross-check getAssignedGrades for submission/score status.
On any upstream failure a tool returns {"error": ..., "endpoint": ...} in
place of its normal payload (rather than a bare null); a 401/403 — usually
expired session cookies — adds a "hint" that says so.
getLink (Kaltura lecture-video transcription) is registered only when the
optional transcription extra is installed; getLTILink (LTI quicklink
redirects) is checked in but commented out. See Optional tools.
Related MCP server: Canvas Assignment Assistant
Architecture
Claude / MCP client
│ HTTPS + Authorization: Bearer <token>
▼
nginx ($MCP_PUBLIC_HOST, TLS termination) ← My setup, http streamable claude requires HTTPS so I used Cloudflare
│ HTTP, Host preserved
▼
brightspacemcp (streamable-http, 127.0.0.1:8008) ← this repo
│ session cookies + browser UA
▼
purdue.brightspace.com/d2l/apiTransport:
streamable-httpbound to loopback.TransportSecuritySettingspinsallowed_hosts/allowed_origins(fromMCP_PUBLIC_HOST, defaultmcp.xennick.com) so the SDK's DNS-rebinding protection accepts theHostnginx forwards.Inbound auth (MCP client → this server): the
RequireTokenmiddleware rejects any request withoutAuthorization: Bearer <MCP_INBOUND_TOKEN>(constant-time compare); the token lives in.envand is minted bymint_token.py.Outbound auth (this server → Brightspace):
auth.return_cookies()readsd2lSessionVal/d2lSecureSessionValfrom.env(viapython-dotenv). Those are a logged-in browser session's cookies; a separate process is expected to refresh them into.env. Requests also send a desktop-browserUser-Agent.Deploy:
deploy/brightspace-mcp.serviceruns thebrightspacemcpconsole script under systemd withuv run --frozen --no-sync(never touches the lockfile at boot) and a strict sandbox (ProtectSystem=strict,ProtectHome=read-only, restricted address families, private tmp).
Caveat
My inbound side has self-generated token auth at the moment and the outbound side talks to the D2L api with a scraped session cookie, not an OAuth 2.0 app.
"Unfortunately, we have not yet provided students with OAuth 2.0 access to Brightspace for personal use."
Because of this, it is single-user, tied to a single account, breaks on session expiry, and is likely against API terms. It is a personal tool, not a multi-user service. A future production version would also be able to register a D2L app and use the OAuth flow for the Brightspace call.
Optional tools
getLink — launches the course's Kaltura LTI in a headless Playwright
browser, grabs the video's index.m3u8, and runs it through openai-whisper
for a transcript. Its dependencies live in the transcription extra
(playwright + openai-whisper, which pulls PyTorch), kept out of the base
install because they're large and the transcription itself is slow on a small
host.
The base server imports fine without them;
server.pychecksimportlib.util.find_specat startup (_HAS_TRANSCRIPTION) and only callsmcp.tool()(getLink)when both are present, so a lean install advertises exactly the tools it can run.Called without the extra (e.g. registered by hand),
getLinkreturns{"error": "transcription extra not installed", "hint": ...}.
Enable it with:
uv sync --extra transcription
playwright install chromiumgetLTILink — resolves /d2l/common/dialogs/quickLink/... redirects (a thin
wrapper over a raw authenticated GET). Checked in with its @mcp.tool() line
commented out; un-comment to register it (no extra dependencies).
Setup
Requires uv. Python ≥ 3.14 is fetched by uv
automatically — you don't need it installed already.
Guided (recommended)
./setup.shIt's interactive and safe to re-run. It will:
install
uvif it's missing (offers to run the official installer),uv sync(and, if you say yes, the heavytranscriptionextra),prompt for your two Brightspace session cookies,
mint the inbound bearer token via
mint_token.py,write
.env, andprint the line to paste into your MCP client:
Copy this whole token for input: "Bearer <token>"
Then run the server:
uv run brightspacemcp # or: python -m brightspacemcpIt listens on http://127.0.0.1:8008. Point an MCP client at that (directly, or
through a TLS proxy as above).
Manual
uv syncThe base uv sync is lean — mcp, httpx2, python-dotenv. See
Optional tools for the transcription extra.
Create .env with a current browser session's cookies:
d2lSessionVal=...
d2lSecureSessionVal=...
MCP_INBOUND_TOKEN=... # bearer token MCP clients must send
MCP_PUBLIC_HOST=... # optional; public hostname nginx serves (default mcp.xennick.com)Copy the d2l* cookies from your browser's dev tools while logged into
purdue.brightspace.com (DevTools → Application / Storage → Cookies — the
entries named d2lSessionVal and d2lSecureSessionVal). For the token, run
uv run python mint_token.pywhich generates one, upserts MCP_INBOUND_TOKEN into .env (leaving your other
lines alone), and prints the Bearer … string. --show reprints the current
one; --force replaces it.
Then run the server as above.
Refreshing expired cookies
When tools start returning 401/403, your d2l* cookies have expired. Re-run
./setup.sh (press enter to keep the token and re-paste the two cookies), or
edit the two d2l* lines in .env by hand.
Deploy as a service
cp deploy/brightspace-mcp.service /etc/systemd/system/
systemctl daemon-reload
systemctl enable --now brightspace-mcp.serviceAdjust User, WorkingDirectory, and the uv path in the unit first. After
changing dependencies, run uv sync by hand — the unit deliberately runs
--frozen --no-sync.
Layout
src/brightspacemcp/
__init__.py exports main()
__main__.py python -m brightspacemcp
server.py MCPServer, all @mcp.tool() definitions, request helpers
(JSON / file download), feed-merge logic, RequireToken
auth.py Brightspace session cookies from .env (outbound)
setup.sh interactive first-run setup (deps + .env + token)
mint_token.py generate MCP_INBOUND_TOKEN and upsert it into .env
deploy/
brightspace-mcp.service
pyproject.toml uv_build, src layout, `brightspacemcp` console scriptThis server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to interact with Canvas LMS through 25 comprehensive tools. Supports course management, assignments, grades, messaging, calendar events, and file access through natural language.15912MIT
- FlicenseAqualityNot gradedmaintenanceEnables interaction with Canvas LMS courses and assignments directly from your LLM, allowing you to retrieve, search, and summarize course information, check due dates, and access assignment details without leaving your AI assistant.4159
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to interact with Canvas LMS and Gradescope, allowing users to query courses, assignments, modules, calendar events, and find relevant resources using natural language.19ISC
- AlicenseAqualityDmaintenanceEnables AI assistants to interact with D2L Brightspace LMS, providing access to assignments, grades, course content, calendar events, and announcements through automated SSO authentication.121710MIT
Related MCP Connectors
Provides cloud browser automation capabilities using Stagehand and Browserbase, enabling LLMs to i…
Gateway between LLM agents and world data through eight tools and a bundled endpoint catalog.
SaaS intelligence for AI agents. 5 unified tools cover 1,000+ services with 91-96% token savings.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/fishernick/BrightspaceMCP'
If you have feedback or need assistance with the MCP directory API, please join our Discord server