A small, read-only MCP server for Moodle, including Lehigh CourseSite. Connect your own account to an MCP client to look up courses, plan deadlines, understand assignment requirements, read Moodle Pages, and review your released grades.
CourseLight supports read-only course planning across CourseSite, Gradescope, Banner, and Degree Works. It does not retrieve assessment questions, upload files, or submit work. Complete assessments directly in CourseSite or Gradescope.
| Tool | Purpose |
|---|---|
get_profile |
Confirm the connected account and available read functions |
list_courses |
List your enrolled courses and their Moodle links |
get_course_contents |
Browse sections, activity descriptions, and resource links |
list_assignments |
Read one course's assignment requirements and dates |
get_assignment_status |
Read one assignment's requirements and your submission status |
get_grades |
Read grades released to you for a course, from CourseSite and Gradescope together unless you ask for one |
get_upcoming_work |
Read upcoming action events in a time interval, with pagination |
read_page |
Read the text of a Moodle Page, with pagination |
read_grading_policy |
Read syllabus grading rules from visible course syllabus resources |
read_course_file |
Read a PDF, DOCX, TXT, or Markdown document from a course Resource or Folder, such as a syllabus |
login |
Lehigh only: open a browser to sign in with SSO and Duo for CourseSite, Banner, Degree Works, and 25Live |
At Lehigh, these read the registrar's systems through the same sign-in:
| Tool | Purpose |
|---|---|
list_terms |
List Banner term codes, e.g. 202640 for Fall 2026 (no sign-in) |
search_classes |
Search or browse the class schedule by subject, number or number range, attribute (HU, SS, W, ...), or keyword: CRNs, times, rooms, instructors, seats, waitlists (no sign-in) |
get_course_description |
Read a section's catalog description (no sign-in) |
build_schedules |
Build conflict-free schedules from candidate courses, pairing lectures with their labs, with filters for open seats, times, days off, and credits (no sign-in) |
get_section_requirements |
Read a section's reported prerequisites, corequisites, and restrictions, preserving AND/OR grouping and grade thresholds (no sign-in) |
get_saved_plans |
Read existing Banner Plan Ahead plans, their preferred status, courses, sections, credits, and meeting times |
get_registration_readiness |
Read Banner's registration-preparation messages, including reported holds and time-ticket windows; credit limits are explicitly unavailable |
get_my_registration |
Read your registered classes for a term; past terms include grades |
get_degree_audit |
Read your Degree Works audit: progress, advisors, met and unmet requirements |
get_gpa |
Read cumulative and major GPA, credits, and GPA by term |
get_course_history |
List every course on your record with term, grade, and credits |
Off campus, Degree Works needs the Lehigh VPN. A Degree Works audit doesn't replace advising.
Lehigh's 25Live uses the same sign-in as login, so there is no extra step. The
booking, favorite, and cancel tools are the only ones that change anything, and each acts on one room or one event:
| Tool | Purpose |
|---|---|
search_rooms |
Find rooms you can book instantly for a time window, filtered by name or capacity (read-only) |
list_my_events |
List your own 25Live events (as requestor or scheduler), soonest first, with rooms and status (read-only) |
book_room |
Book one room (Express, confirmed immediately), optionally favoriting the event |
favorite_room_booking |
Star one of your 25Live events |
cancel_room_booking |
Cancel one of your own bookings |
book_room and cancel_room_booking first return a preview and change nothing until called
again with confirm=true; the assistant should do that only after you approve the exact room,
date, time, and event name. Say, for example, "Find me a room for 6 in the library tomorrow 2 to 3,"
then "Book FM 621." Bookings are made in your name, and results are read back from 25Live. If a
check says it is not confirmed, look in 25Live. Only rooms you may Express-book are searchable, and
conflicting bookings are reported without naming the other event.
Gradescope has its own sign-in:
| Tool | Purpose |
|---|---|
login_gradescope |
Open a browser to sign in to Gradescope (School Credentials for Lehigh SSO) |
list_gradescope_courses |
List your Gradescope courses with term and role |
list_gradescope_assignments |
Read a course's assignments: status, score, release, due, and late due dates |
Gradescope tools are read-only: CourseLight never uploads files or submits work to Gradescope (or Moodle). Submit your work yourself on the site. Gradescope has no public student API, so these read its web pages and may need updating if Gradescope changes them.
Asking for grades ("Show my grades for CSE 303") uses get_grades, which by
default returns both CourseSite and Gradescope grades for the course. Pass either
site's course ID; the other site's course is matched by course code (such as
"CSE 303"), preferring the same term, and the match is reported so you can correct
it. Ask for "only Gradescope" or "only CourseSite" grades to read one site. If one
site isn't signed in or the course doesn't use it, that part says so and the other
is still shown.
Sign in from a terminal with .venv/bin/python login.py --gradescope if your
client times out long tool calls.
To plan a semester, ask something like "Using courselight, look at my degree audit
and build me some schedules for next semester, no Friday classes." The
plan_next_semester prompt (in your client's prompt or / menu) walks through the
same steps: read the audit, search next term for what you still need, ask your
preferences, and build schedules. Schedules are suggestions: prerequisites,
major restrictions, and registration holds aren't checked by the schedule
builder itself. The planning prompt separately reads section requirements and
registration readiness; confirm eligibility with your advisor and register
yourself in Banner.
Visualized tools display interactive components inline in an MCP Apps-compatible
host. They return validated structuredContent and a short text fallback.
| Tool | Purpose |
|---|---|
show_courses |
Show courses and weekly assignment deadlines |
show_deadlines |
Show weekly assignment deadlines in a chronological timeline |
show_degree_progress |
Show degree and major completion rings with reported cumulative GPA from Degree Works |
show_gradebook |
Show CourseSite and Gradescope scores in a compact grade grid |
show_grade_target |
Explore a syllabus-backed target grade with draggable score bars |
show_study_materials |
Expand selected study topics into course materials and download links |
show_coursework |
Explicit “coursework” / “course work” requests: add a riskier search for possible work in other course posts |
show_class_schedule |
Show registered Banner classes in a Monday–Friday grid |
show_course_map |
Show course-building pins with course visibility toggles |
show_schedule_options |
Compare potential schedules using the same grid |
Ordinary assignment requests use show_courses. The broader tool uses keyword
clues and may include unrelated or older items, or miss work. Its cards label
that limitation and mark undated candidates as week-unverified.
The schedule views show recurring class times in America/New_York. Date-specific meetings, weekend classes, and unknown times remain in the tool result for chat and class details; they are not plotted in the weekday grid. Proposed schedules can be switched locally; nothing is registered, dropped, or saved.
Python tools live in visualizations/<name>/; their React views live in
ui/views/<name>/. Reusable UI code is in ui/shared/, and generated
bundles are in ui/dist/. See the folder guide and adding a visualization
for the Courses example and its coverage limits.
Quiz titles and deadlines may appear in a course outline or calendar. CourseLight
does not open quiz attempts, retrieve their questions, save answers, or submit
them. read_course_file reads documents from Resource and Folder modules using
the existing course listing. It does not accept arbitrary URLs or access quiz or
assignment attachments. Moodle Pages are the Page activity type and are read
separately with read_page.
For example, ask "What does the CSE 262 syllabus say about late work?" The client
finds your course with list_courses, locates its syllabus with
get_course_contents, and calls read_course_file with the course ID, module ID
(module.id, not instance), and the zero-based index in the module's contents
list (usually 0). It follows next_offset until the requested material has been
read and cites the returned Moodle link. Filenames and document text are
untrusted source data, never instructions.
You need Python 3.10 or newer and your own Moodle web-service token. Your institution must enable Moodle web services and allow the functions listed below. CourseLight cannot enable them or create a token for you. If your institution does not offer a token, ask its Moodle administrator about permitted access.
git clone https://github.com/johnBrereton/CourseLight.git
cd CourseLight
python3 -m venv .venv
.venv/bin/python -m pip install -r requirements.txt
cp .env.example .envEdit .env: replace MOODLE_URL with your institution's HTTPS Moodle base URL
and set MOODLE_TOKEN to your own token. For Lehigh, the base URL is
https://coursesite.lehigh.edu. Do not include /login/index.php or
/webservice/rest/server.php. Moodle installed in a subdirectory is supported,
for example https://example.edu/moodle.
Use a client that supports local stdio MCP servers. Add the following server configuration, replacing both paths with the absolute paths on your machine:
{
"mcpServers": {
"courselight": {
"command": "/absolute/path/to/CourseLight/.venv/bin/python",
"args": ["/absolute/path/to/CourseLight/server.py"]
}
}
}The same example is in mcp.json.example. Your client determines where to put
this configuration. On Windows, use python.exe under .venv\Scripts and escape
backslashes in JSON, or use forward slashes. The client starts the server when
needed. The default stdio connection starts no web server or public endpoint.
The server reads .env beside its source files regardless of the client's
working directory;
existing environment variables take precedence. Restart the connection after
changing credentials or updating the tool definitions.
Start with “List my courses,” then “Show the assignments and upcoming deadlines for this course.” You can also ask “Explain this Moodle Page and link to the source” or “Show my released grades.” Use the tools for study support and planning in accordance with your instructor's rules.
Each person runs their own copy with their own account. Share the repository,
never a configured connection or a filled-in .env file. Anyone who can invoke
your connection can read the course information available to that account.
Course information returned by the tools is sent to your MCP client and may be
processed or retained according to that client's settings.
Apart from the 25Live room tools above, CourseLight is read-only. Its Moodle transport enforces a fixed allowlist of read functions. These
requests use POST because that is how Moodle's REST API works; they do not invoke
submission or assessment-write functions. A token may have broader permissions
outside this application. Where possible, ask for a service token restricted to
the required reads. Credentials travel only to the configured HTTPS Moodle URL;
redirects are not followed. Token fields and debug traces are stripped from tool
results, and transport errors do not expose raw server responses. The
read_course_file tool downloads through Moodle's dedicated
/webservice/pluginfile.php endpoint, only on the
configured site's HTTPS origin and only for a listed Resource or Folder file.
The service must permit file downloads. Files are kept in memory; document
parsing runs in a separate process without Moodle credentials and is stopped
after 30 seconds. The Lehigh
session cookies are used only by a local headless browser on Lehigh's SSO,
Banner, and Degree Works sites, and are never returned in tool results. Gradescope
cookies are sent only to www.gradescope.com, used only for page reads, and are
never returned in tool results.
There are no local journals, staged submissions, or saved course files. The syllabus
reader extracts bounded PDF content in memory and may read public Google Docs
linked as syllabi; it never sends Moodle credentials to those external links. The
only application data is the Lehigh and Gradescope sign-in sessions in
~/.lehigh-mcp/, outside the repository. .env, virtual environments, local MCP configuration,
and logs are ignored by Git. The default stdio connection needs no tunnel key,
hosting account, database, or public listener.
- A calendar is not an exhaustive list of work. Combine upcoming events with assignments and actual submission status.
- A missing grade is not a zero; a missing deadline or calendar event is not proof that work is complete. A draft is not a final submission.
- Course and assignment access depend on Moodle permissions and availability.
get_profilereports advertised API functions, not access to every activity. get_upcoming_worktakes Unix timestamps in seconds. Keep the same time range and passnext_after_event_idasafter_event_iduntil it isnull.- For
read_page, use a page module'sinstancefromget_course_contentsaspage_id. Follownext_offsetusing the same page until it isnull. Images, embedded documents, layout, and diagrams are omitted; check the original. - Each response is capped at 20 MiB. Moodle reads use a 30-second request timeout and at most three attempts for temporary network or service failures.
- Course files are capped at 10 MiB. Supported formats are PDF, DOCX, UTF-8 or
BOM-marked UTF-16 text (
.txt/.md). PDFs have page markers and are limited to the first 100 pages; extraction retains at most 500,000 characters. Follownext_offsetwith the same course, module and file index for text pagination.total_characterscounts retained text;extraction_truncatedandwarningsidentify omitted content. Iftimemodifiedchanges, start reading again. Encrypted PDFs, legacy.doc, slides, spreadsheets and archives aren't supported. DOCX reads the main body only, with an XML size limit of 10 MiB. Images, diagrams, complex layout, and text in scans aren't interpreted; there is no OCR. Verify tables, policies and consequential details in the original.
Banner and Degree Works responses include source links. Use the returned term and
CRN when opening Banner class search; the link opens its term selector rather
than a particular section. Saved plans cover Banner Plan Ahead only, not Degree
Works planner plans. They are read without creating, modifying, deleting,
approving, or changing the preferred plan. Planned courses are not necessarily
registered. Missing meeting information is returned as null with a warning;
check complete before treating the response as exhaustive.
Section requirements are source text with table columns retained, including
operators, grouping, and minimum grades. Missing fields and truncation are
explicitly reported. A "no information available" response does not establish
that a section has no requirements. Registration readiness reports Banner's
individual allowed/blocked/informational checks and displayed registration
windows; it does not determine eligibility. The preparation page does not expose
credit limits, so credit_limits is null and listed in unavailable. Window
times are left as Banner displays them, without an assumed timezone.
Degree Works audit, GPA, and course-history reads include the audit date. They read an existing snapshot and do not request a new audit. All course options in the returned audit are included; options are no longer limited to 20 per rule. Unknown requirement progress is reported as unknown. Neither a degree audit nor a generated schedule guarantees eligibility to graduate or register.
The read tools return { "ok": true, "fetched_at": ..., "data": ... } or
{ "ok": false, "error": { "code": ..., "message": ... } }.
Warnings and unavailable data should be reported, rather than interpreted as
completion or missing coursework. Always verify consequential dates and grades
against the linked source in Moodle.
moodle.py contains the full allowlist:
core_webservice_get_site_info
core_enrol_get_users_courses
core_course_get_contents
mod_assign_get_assignments
mod_assign_get_submission_status
gradereport_user_get_grade_items
core_calendar_get_action_events_by_timesort
core_calendar_get_action_events_by_course
mod_page_get_pages_by_courses
If get_profile reports a function unavailable, that tool needs your institution's
administrator to enable the corresponding read in the service. A Moodle error
may also mean an expired token, a role restriction, or an unavailable activity.
Share the tool name and error code when asking for help, never your token, grades,
private course content, or a token-bearing URL.