Skip to main content
Glama
ZHAW Moodle MCP Server

ZHAW Moodle MCP Server

by Dathis

Moodle MCP for Swiss universities

PyPI CI License: MIT

Use your university's Moodle from Claude: courses, materials, downloads, deadlines and announcements. Works with ZHAW, FHNW, ETH, EPFL and the other Swiss universities below, and with any other Moodle 4 site. You log in yourself (usually with SWITCH edu-ID) — your password is never seen or stored, and everything stays on your computer.

Unofficial student project, not affiliated with any university. Course material is for personal study only.

Formerly zhaw-moodle-mcp. Existing setups keep working: uvx zhaw-moodle-mcp now installs this package, and your login and settings stay where they are. For the Claude Desktop extension, install the new swiss-moodle-<version>.mcpb over the old one.

Quick start

  1. Download swiss-moodle-<version>.mcpb from the latest release.

  2. Double-click it, or in Claude Desktop open Settings → Extensions → Advanced settings → Install Extension… and pick the file. Click Install.

  3. Enter your university under University: its short name from the table below (e.g. fhnw) or the web address of your Moodle. You can also leave it empty and simply tell Claude in the chat which university you study at.

  4. Open a new chat and ask "Which Moodle courses do I have?". The first start takes a few seconds; then a browser opens for the login.

To switch universities later, change University in the extension's settings (or, if you left it empty, ask Claude to switch). In the chat's + → prompts menu you find ready-made study sessions: study assistant, last lecture summary, deadlines overview, what's new, exam preparation.

Claude Code

Install uv, then (with your university's short name):

claude mcp add moodle -e MOODLE_MCP_INSTITUTION=fhnw -- uvx swiss-moodle-mcp@latest

Ask Claude

"Summarise the last lecture of Software Engineering 1", "Show all my deadlines as a table", "Sync all my courses", "What's new since Monday?". Files go to a folder named after your university in your home directory (e.g. ~/FHNW).

Related MCP server: NCCU Moodle MCP

Universities

University

Short name

Moodle

Status

ZHAW

zhaw

moodle.zhaw.ch

tested

BFH

bfh

moodle.bfh.ch

not tested yet

EPFL

epfl

moodle.epfl.ch

not tested yet

ETH

ethz

moodle-app2.let.ethz.ch

not tested yet

FFHS

ffhs

moodle.ffhs.ch

not tested yet

FHGR

fhgr

moodle.fhgr.ch

not tested yet

FHNW

fhnw

moodle.fhnw.ch

not tested yet

HES-SO

hes-so

cyberlearn.hes-so.ch

not tested yet

HFTM

hftm

moodle.hftm.ch

not tested yet

OST

ost

moodle.ost.ch

not tested yet

PHLU

phlu

moodle.phlu.ch

not tested yet

UNIFR

unifr

moodle.unifr.ch

not tested yet

UNIGE

unige

moodle.unige.ch

not tested yet

UNIL

unil

moodle.unil.ch

not tested yet

UNINE

unine

moodle.unine.ch

not tested yet

USI

usi

www.icorsi.ch

not tested yet

SUPSI

supsi

www.icorsi.ch

not tested yet

"Not tested yet": the site runs Moodle 4, but nobody has used this server there yet. It should work - you can help by running uvx swiss-moodle-mcp doctor, which tries every feature on one of your courses and prints a report without course names or personal data, and posting it as a compatibility report.

Not listed? Use the address of your Moodle instead of a short name (copy it from the browser while you are on your Moodle). The Moodle must be version 4.0 or newer; other learning platforms (ILIAS, OLAT, Canvas) are not supported.

Good to know

  • Browser: login uses your default browser if it is Chrome, Edge, Brave or Vivaldi, otherwise another installed one (Firefox and Safari are not supported).

  • Updates: the extension is updated by installing a newer .mcpb; with uvx ...@latest (Claude Code) updates install automatically when Claude starts.

  • Extension does not start: it runs with uv. If Claude Desktop reports that uv is missing, install uv and restart Claude completely (also from the tray).

  • Sync never deletes local files. Logging out (ask Claude, or uvx swiss-moodle-mcp logout) removes the stored session and the login browser profile; a running server notices it.

  • Session and settings live in ~/.swiss-moodle-mcp on Windows (outside AppData, so Claude from the Microsoft Store and the command line share them) and in the usual app folders on macOS/Linux, with a separate instances/<moodle host> folder per Moodle site. Folders named zhaw-moodle-mcp from older versions keep being used.

Configuration

Choose your university once with uvx swiss-moodle-mcp setup (a list to pick from, or setup fhnw, or setup <address of your Moodle>); uvx swiss-moodle-mcp universities lists the known ones and uvx swiss-moodle-mcp status shows what is set. You can also just tell Claude your university ("I study at FHNW"); it stores the choice for you. If you used this server before v0.5, ZHAW stays selected.

The extension asks for the university, download folder and browser in its settings. Otherwise run uvx swiss-moodle-mcp config-path to see where config.toml goes:

[moodle]
institution = "zhaw"  # or bfh, epfl, ethz, ffhs, fhgr, fhnw, hes-so, hftm, ost, phlu, unifr,
                      # unige, unil, unine, usi, supsi - or the address of any other Moodle
# download_directory = "~/Studium/{short}"  # default ~/ZHAW, ~/FHNW, ...

[browser]
name = "auto"  # or "chrome", "msedge", "brave", "vivaldi"
# executable_path = "C:/path/to/browser.exe"  # any other Chromium-based browser

Development

uv sync
uv run pytest
uv run ruff check .

In this folder Claude Code picks up the server from .mcp.json, plus a study assistant subagent (copy it to ~/.claude/agents/ to use it everywhere). Build the Claude Desktop extension with uv run python scripts/build_extension.py (needs Node.js). Pushing a vX.Y.Z tag that matches pyproject.toml publishes to PyPI and attaches the .mcpb to a GitHub release.

Available Tools

16 tools
moodle_auth_statusA
Read-onlyIdempotent

Check whether a valid ZHAW Moodle session exists. Never returns credentials.

Inputs: no named parameters. Returns: state, message, moodle_url, authenticated

moodle_download_resourceA
Idempotent

Download a file, all files of a folder, or files linked in a page/text block, and return the local paths.

    By default files go to the managed directory <download_directory>/<course>/<section>/,
    which moodle_sync_course also uses.

    Args:
        resource_id: id from moodle_list_resources ("<cmid>" or "<folder cmid>/<path>"),
            or a file link's resource_id from moodle_get_content ("<page/label id>/<file>");
            the id of a page or text block downloads all files linked in it
        destination: optional target directory; relative paths are resolved
            against the configured download directory
        overwrite: replace an existing local file (otherwise it is left as is)
    

Inputs: resource_id (required), overwrite, destination. Returns: files, failed, resource_id

moodle_get_announcementsA
Read-onlyIdempotent

Recent announcements ("Ankündigungen") posted by lecturers, newest first, with the message text of the most recent ones.

    Args:
        course_id: restrict to one course (default: all current courses)
        since: only announcements newer than this: ISO date/datetime (2026-09-14) or relative (7d, 12h, 2w)
        limit: maximum number of announcements
    

Inputs: limit, since, course_id. Returns: announcements

moodle_get_contentA
Read-onlyIdempotent

Read the text of a Moodle page ("Textseite") or text block ("Textfeld"/label) as Markdown, with the links it contains. Such texts often hold instructions, rules for assignments and exams, or reading lists. Opening a page counts as a view in Moodle.

    Args:
        activity_id: id (cmid) of a page or label from moodle_get_course or moodle_search
    

Inputs: activity_id (required). Returns: id, url, name, note, +8 more

moodle_get_courseA
Read-onlyIdempotent

Get the structure of a course: sections, nested subsections and all activities/materials (files, folders, links, pages, quizzes, assignments, ...). Text blocks (labels) include their text.

    Args:
        course_id: course id from moodle_list_courses
    

Inputs: course_id (required). Returns: course, sections

moodle_get_deadlinesA
Read-onlyIdempotent

Open to-dos with deadlines across all courses (assignment due dates, quiz closing times, ...), sorted by date. Answers "What do I need to submit this week?". Activities already completed are not listed.

    Args:
        days_ahead: how far to look ahead (days)
        course_id: restrict to one course
        include_overdue: also list overdue to-dos from the last 30 days
    

Inputs: course_id, days_ahead, include_overdue. Returns: now, note, until, deadlines

moodle_get_recent_changesA
Read-onlyIdempotent

What changed in Moodle since a point in time: new or updated materials and activities, new announcements, and new or changed deadlines, grouped by course. Answers "What is new in Moodle since Monday?".

    Args:
        since: ISO date/datetime (2026-09-14, 2026-09-14T08:00) or relative (7d, 12h, 2w)
        course_id: restrict to one course (default: all current courses)
    

Inputs: since, course_id. Returns: since, until, courses, unchanged_courses

moodle_list_assignmentsA
Read-onlyIdempotent

Assignments with opening date, deadline, submission and grading status and description. Without course_id all current courses are included (one request per assignment).

    Args:
        course_id: restrict to one course
    

Inputs: course_id. Returns: failed, assignments

moodle_list_coursesA
Read-onlyIdempotent

List the user's ZHAW Moodle courses.

    Args:
        status: "active" (current semester, default), "past", "future" or "all"
    

Inputs: status. Returns: courses

moodle_list_resourcesA
Read-onlyIdempotent

List learning materials of a course: files (pdf, powerpoint, word, excel, zip, ...), folders, external links and Moodle pages, with their section.

    Args:
        course_id: course id from moodle_list_courses
        include_folder_contents: also list the individual files inside folders
            (one extra request per folder)
    

Inputs: course_id (required), include_folder_contents. Returns: course_id, resources

moodle_loginA
Idempotent

Log in to ZHAW Moodle. Opens a browser window where the USER signs in with SWITCH edu-ID (incl. MFA) themselves; returns once login is detected. Never ask the user for their password. Other tools log in automatically when needed.

    Args:
        force: open the login browser even if the current session is still valid
    

Inputs: force. Returns: state, message, moodle_url, authenticated

moodle_logoutA
DestructiveIdempotent

Log out: end the Moodle session and delete the locally stored browser session and cookies. The next Moodle request will require a new login.

Inputs: no named parameters. Returns: message, logged_out, server_session_invalidated

moodle_read_fileA
Idempotent

Read the text of a course file (PDF, PowerPoint .pptx, Word .docx, HTML, text). Downloads the file first if needed. Use this to summarise or explain lecture slides, scripts and exercise sheets. Long files come in parts: continue with next_pages.

    Args:
        resource_id: id of a single file from moodle_list_resources, moodle_search or
            moodle_get_content (folder files: "<folder id>/<path>")
        pages: page/slide range for PDF and PowerPoint, e.g. "1-10", "5" or "11-"
        max_chars: maximum characters to return (1000-100000)
    

Inputs: resource_id (required), pages, max_chars. Returns: note, path, text, pages, +5 more

moodle_sync_allA
Idempotent

Synchronise all active (current semester) courses into the local download directory and return a per-course summary. Same rules as moodle_sync_course.

    Args:
        dry_run: only report what would change, download nothing
        update_changed: re-download files that changed on Moodle
    

Inputs: dry_run, update_changed. Returns: courses, dry_run, download_directory

moodle_sync_courseA
Idempotent

Synchronise all files of a course into the local download directory. Downloads new files, re-downloads changed ones and reports what changed. Files removed from Moodle are reported but never deleted locally.

    Args:
        course_id: course id from moodle_list_courses
        dry_run: only report what would change, download nothing
        update_changed: re-download files that changed on Moodle
    

Inputs: course_id (required), dry_run, update_changed. Returns: new, failed, dry_run, removed, +7 more

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4.1/5.0

    Scored across 16 tools

    Disambiguation4/5

    Most tools target a distinct Moodle action and resource type, and the descriptions make the differences clear. A few closely related pairs—such as list_resources vs get_course and get_deadlines vs list_assignments—could be confused at selection time, but the usage guidance separates them well.

    Naming Consistency4/5

    All tools share the moodle_ prefix and nearly all follow a verb_noun pattern such as list_courses, read_file, and get_announcements. The convention is broken slightly by moodle_auth_status and the bare verbs login/logout, though the overall pattern remains predictable.

    Tool Count4/5

    With 16 tools, the set is just above the typical well-scoped 3-15 range, but each tool serves a distinct workflow spanning auth, course navigation, content access, search, deadlines, announcements, and change tracking. No tool feels redundant, so the count is justified.

    Completeness5/5

    The server covers the full read-side workflow for a student-facing Moodle assistant: session handling, course discovery, structural overview, content extraction and download, offline syncing, search, deadlines, assignments, announcements, and recent changes. There are no obvious dead ends for the core workflows implied by the tool set.

    Maintenance

    ActivitySlowing
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers