Skip to main content
Glama
README.md
# moodle-mcp

Let your AI assistant read your Moodle courses. Ask things like:

> *What do I have to hand in this week?*
> *Anything new on Moodle since last time?*
> *Summarize the latest slides of INFO-F403.*
> *Download the new exercise sheets of the crypto course into my OneDrive course folder.*

`moodle-mcp` is an [MCP](https://modelcontextprotocol.io) server: a small program that AI apps (Claude Code,
Claude Desktop, Codex, Cursor, Gemini CLI, Windsurf…) launch in the background to get extra tools. It talks to
Moodle with **your own** token, through the same API as the official Moodle mobile app, and only reads.

Made for the ULB (`uv.ulb.ac.be`, the default), but it works with any Moodle site that allows the mobile app.

## Install (5 minutes)

**1. Install [uv](https://docs.astral.sh/uv/)** (a Python tool installer). Skip this step if you already have it.

- macOS / Linux: `curl -LsSf https://astral.sh/uv/install.sh | sh`
- Windows (PowerShell): `powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"`

Then open a **new** terminal.

**2. Install moodle-mcp**

```sh
uv tool install git+https://github.com/Nicolas-Prn/moodle-mcp
```

**3. Run the setup**

```sh
moodle-mcp setup
```

It asks for your Moodle token (see below), checks it, then offers to register the server in every AI app it
finds on your computer. Restart Claude Desktop (or other open apps) afterwards. That's it.

### Getting your Moodle token

The token gives read access to your courses, as the Moodle app has. Keep it private.

**Option A: Security keys page** (easiest)

1. Log in to Moodle in your browser.
2. Open <https://uv.ulb.ac.be/user/managetoken.php> (*profile picture → Preferences → Security keys*).
3. Copy the key in the **Moodle mobile web service** row and paste it into `moodle-mcp setup`.

**Option B: if there is no such page or row**

1. Log in to Moodle in Chrome, Edge or Firefox.
2. Open the developer tools (F12, or Cmd+Option+I on a Mac) and select the **Network** tab.
3. In the same tab, go to
   `https://uv.ulb.ac.be/admin/tool/mobile/launch.php?service=moodle_mobile_app&passport=1&urlscheme=moodlemobile`
4. Click the `launch.php` request (it shows as failed, that's expected). Under *Response Headers*, copy the
   whole `location` value (`moodlemobile://token=…`) and paste it into `moodle-mcp setup`, which decodes it.

For another university, replace `uv.ulb.ac.be` with your Moodle address and run `moodle-mcp setup --url <address>`.

## Using it

Just ask your assistant in plain language, in any conversation and any folder. It picks the right tools:

| Tool | What it does |
|---|---|
| `list_courses` | Your courses (current ones, or past ones too) |
| `get_course_outline` | Sections, activities, links and files of a course, with file references |
| `get_deadlines` | Upcoming and overdue things to do (assignments, quizzes…) |
| `get_announcements` | Recent announcements and forum posts, across all courses or one |
| `read_discussion` | A full forum thread |
| `check_updates` | What is new / changed / removed since you last marked a course as seen |
| `mark_updates_seen` | Marks the current content as seen (the assistant does it once you've dealt with the changes) |
| `read_file` | Reads a file as text so the assistant can explain or summarize it (PDF, Word, PowerPoint, HTML, code…) |
| `download_files` | Saves chosen files into a folder you name, optionally renamed or sorted into sub-folders |
| `mirror_course` | Saves a whole course, mirroring its Moodle structure (`dry_run` shows the size first) |

A course can be named by its code (`F403`, `info-h417`), part of its name, or its id.

**Downloads never overwrite a file that already exists**, so annotating or editing downloaded files is safe.
When Moodle has a newer version of a file you already have, the assistant can save it next to yours as
`name (2).pdf`. `check_updates` compares Moodle with what it saw last time, not with your local files.

## Supported apps

`moodle-mcp setup` (or `moodle-mcp install` later) registers the server automatically in:
**Claude Code** (all projects), **Claude Desktop**, **Codex**, **Cursor**, **Gemini CLI** and **Windsurf**.

For any other app that supports local (stdio) MCP servers, add a server with the command that
`moodle-mcp status` prints, for example:

```json
{ "mcpServers": { "moodle": { "command": "/Users/you/.local/bin/moodle-mcp", "args": ["serve"] } } }
```

Use the full path: desktop apps do not see your terminal's `PATH`.

**Not supported yet:** ChatGPT and the claude.ai website or mobile app. They can only reach MCP servers hosted on
the internet, while this one runs on your computer (which is also why your token never leaves it).

## Commands

```sh
moodle-mcp setup              # save or replace your token, then register in your AI apps
moodle-mcp status             # check the token and see which apps were detected
moodle-mcp install [apps...]  # register again (e.g. after installing a new app): claude-code, claude-desktop, codex, cursor, gemini, windsurf
moodle-mcp uninstall          # unregister from the apps
uv tool upgrade moodle-mcp    # update to the latest version
```

To remove everything: `moodle-mcp uninstall`, `uv tool uninstall moodle-mcp`, then delete `~/.config/moodle-mcp`.

## Privacy and security

- The token is stored only on your computer, in `~/.config/moodle-mcp/config.json` (readable by you only).
  App configurations contain just the command, never the token. You can also provide it through the
  `MOODLE_TOKEN` (and `MOODLE_URL`) environment variables instead.
- The server never changes anything on Moodle: no submissions, no posts, no messages.
- The token is only ever sent to your Moodle site, and is removed from error messages.
- Forum posts, descriptions and files are written by other people. The server tells the assistant to treat them
  as information, not as instructions.
- To revoke access, use **Reset** on the Security keys page, then run `moodle-mcp setup --new-token`.

## Troubleshooting

- **The assistant doesn't see the Moodle tools**: restart the app, then run `moodle-mcp status`. In Claude Code,
  `/mcp` lists connected servers.
- **"invalidtoken" or "No Moodle token configured"**: run `moodle-mcp setup --new-token`.
- **A big `mirror_course` times out**: some apps stop waiting after a minute or two. Downloads already finished
  are kept, so asking again resumes where it stopped.

## Development

```sh
git clone https://github.com/Nicolas-Prn/moodle-mcp && cd moodle-mcp
uv sync
uv run pytest
uv run moodle-mcp status
npx @modelcontextprotocol/inspector uv run moodle-mcp serve   # try the tools in a web UI
```

Code layout (`src/moodle_mcp/`): `server.py` defines the MCP tools, `courses.py` the course and file model
(including file references), `client.py` the Moodle Web Service client, `updates.py` change detection,
`downloads.py` saving files, `text.py` text extraction, `config.py` settings and `cli.py` the commands.

License: MIT.

TDQS

A3.7/5.0

Scored across 10 tools

Disambiguation4/5

Tools are mostly distinct, but get_announcements and check_updates both surface new course content, and download_files and mirror_course both download files; descriptions clarify boundaries, but an agent could occasionally misselect.

Naming Consistency5/5

All tool names use a consistent snake_case verb_noun pattern (get_, list_, read_, check_, mark_, download_, mirror_), making the set predictable and easy to scan.

Tool Count5/5

10 tools is well-scoped for a Moodle course-access client, with no redundant or trivial tools; each covers a distinct capability.

Completeness4/5

The surface covers core read workflows (courses, outline, deadlines, announcements, discussions, files, updates, mirroring), but lacks search, grades, or assignment interaction, which are minor gaps for a read-only client.

Maintenance

ActivityMaintained
ResponsivenessNo issues