moodle-mcp
by 1alexandrer
README.md
# moodle-mcp
[](https://www.npmjs.com/package/moodle-mcp)
[](https://www.npmjs.com/package/moodle-mcp)
[](https://github.com/1alexandrer/moodle-mcp)
[](https://www.typescriptlang.org)
[](https://nodejs.org)
[](https://workers.cloudflare.com)
[](LICENSE)
> Give Claude full access to your Moodle โ courses, files, assignments, grades, quizzes, calendar, and more. Build Obsidian study vaults from your lecture notes in one command.
> ๐ฆ **[moodle-mcp on npm](https://www.npmjs.com/package/moodle-mcp)** โ `npx moodle-mcp`
**14 tools ยท 5 prompts ยท MCP Resources**
---
## Install
### Step 1 โ Get your Moodle token
See [Getting Your Token](#getting-your-token) below. You'll need this for any install method.
### Step 2 โ Pick your delivery mode
**Option A โ Local (zero hosting):** Runs `npx moodle-mcp` on your machine each time your MCP client starts. No server, no cost, nothing to deploy.
**Option B โ Hosted (Cloudflare Worker):** Deploy once, get a permanent URL. Your MCP client connects to the URL โ no `npx` on the client side.
[](https://deploy.workers.cloudflare.com/ )
After deploying, set `MOODLE_URL` and `MOODLE_TOKEN` as [secrets in the CF dashboard](https://dash.cloudflare.com/) or via:
```bash
npx wrangler secret put MOODLE_URL
npx wrangler secret put MOODLE_TOKEN
npm run deploy
```
Your URL will be `https://moodle-mcp.<your-subdomain>.workers.dev`.
### Step 3 โ Configure your MCP client
<details>
<summary><strong>Claude Desktop</strong></summary>
Config file:
- Mac: `~/Library/Application Support/Claude/claude_desktop_config.json`
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`
**Option A โ Local:**
```json
{
"mcpServers": {
"moodle": {
"command": "npx",
"args": ["-y", "moodle-mcp"],
"env": {
"MOODLE_URL": "https://moodle.yourschool.edu",
"MOODLE_TOKEN": "your_token_here"
}
}
}
}
```
**Option B โ Hosted:**
```json
{
"mcpServers": {
"moodle": {
"url": "https://moodle-mcp.your-subdomain.workers.dev"
}
}
}
```
</details>
<details>
<summary><strong>Claude Code (CLI)</strong></summary>
**Option A โ Local:**
```bash
claude mcp add moodle npx -- -y moodle-mcp \
-e MOODLE_URL=https://moodle.yourschool.edu \
-e MOODLE_TOKEN=your_token_here
```
**Option B โ Hosted:**
```bash
claude mcp add moodle --transport http https://moodle-mcp.your-subdomain.workers.dev
```
</details>
<details>
<summary><strong>Cursor</strong></summary>
Config file: `~/.cursor/mcp.json` (global) or `.cursor/mcp.json` (project)
**Option A โ Local:**
```json
{
"mcpServers": {
"moodle": {
"command": "npx",
"args": ["-y", "moodle-mcp"],
"env": {
"MOODLE_URL": "https://moodle.yourschool.edu",
"MOODLE_TOKEN": "your_token_here"
}
}
}
}
```
**Option B โ Hosted:**
```json
{
"mcpServers": {
"moodle": {
"url": "https://moodle-mcp.your-subdomain.workers.dev"
}
}
}
```
</details>
<details>
<summary><strong>VS Code</strong></summary>
Config file: `.vscode/mcp.json` in your project, or `settings.json` globally.
**Option A โ Local:**
```json
{
"servers": {
"moodle": {
"command": "npx",
"args": ["-y", "moodle-mcp"],
"env": {
"MOODLE_URL": "https://moodle.yourschool.edu",
"MOODLE_TOKEN": "your_token_here"
}
}
}
}
```
**Option B โ Hosted:**
```json
{
"servers": {
"moodle": {
"url": "https://moodle-mcp.your-subdomain.workers.dev"
}
}
}
```
</details>
<details>
<summary><strong>Windsurf</strong></summary>
Config file: `~/.codeium/windsurf/mcp_config.json`
**Option A โ Local:**
```json
{
"mcpServers": {
"moodle": {
"command": "npx",
"args": ["-y", "moodle-mcp"],
"env": {
"MOODLE_URL": "https://moodle.yourschool.edu",
"MOODLE_TOKEN": "your_token_here"
}
}
}
}
```
**Option B โ Hosted:**
```json
{
"mcpServers": {
"moodle": {
"url": "https://moodle-mcp.your-subdomain.workers.dev"
}
}
}
```
</details>
<details>
<summary><strong>Zed</strong></summary>
Config file: `~/.config/zed/settings.json`
**Option A โ Local:**
```json
{
"context_servers": {
"moodle": {
"command": {
"path": "npx",
"args": ["-y", "moodle-mcp"],
"env": {
"MOODLE_URL": "https://moodle.yourschool.edu",
"MOODLE_TOKEN": "your_token_here"
}
}
}
}
}
```
**Option B โ Hosted:**
```json
{
"context_servers": {
"moodle": {
"url": "https://moodle-mcp.your-subdomain.workers.dev"
}
}
}
```
</details>
<details>
<summary><strong>Continue.dev</strong></summary>
Config file: `~/.continue/config.json`
**Option A โ Local:**
```json
{
"mcpServers": [
{
"name": "moodle",
"command": "npx",
"args": ["-y", "moodle-mcp"],
"env": {
"MOODLE_URL": "https://moodle.yourschool.edu",
"MOODLE_TOKEN": "your_token_here"
}
}
]
}
```
**Option B โ Hosted:**
```json
{
"mcpServers": [
{
"name": "moodle",
"url": "https://moodle-mcp.your-subdomain.workers.dev"
}
]
}
```
</details>
<details>
<summary><strong>Cline</strong></summary>
Open the Cline sidebar in VS Code โ MCP Servers โ Add Server โ paste the JSON:
**Option A โ Local:**
```json
{
"moodle": {
"command": "npx",
"args": ["-y", "moodle-mcp"],
"env": {
"MOODLE_URL": "https://moodle.yourschool.edu",
"MOODLE_TOKEN": "your_token_here"
}
}
}
```
**Option B โ Hosted:**
```json
{
"moodle": {
"url": "https://moodle-mcp.your-subdomain.workers.dev"
}
}
```
</details>
<details>
<summary><strong>ChatGPT โ Coming soon</strong></summary>
OpenAI has announced MCP support for ChatGPT. Check the [OpenAI blog](https://openai.com/blog) for the release date. Once available, the hosted URL option (Option B) will work directly.
</details>
---
## Getting Your Token
### Option A โ Moodle profile page (works everywhere)
1. Log in to your school's Moodle in a browser
2. Go to **Profile โ Security keys** (URL: `https://moodle.yourschool.edu/user/managetoken.php`)
3. Find the **Moodle mobile web service** token and copy it
4. Set `MOODLE_TOKEN=<token>` in your MCP config
### Option B โ Get the token from
`https://moodle.yourschool.edu/login/token.php?username=<YOURUSERNAME>&password=<YOURPASSWORD>&service=moodle_mobile_app`
### Option C โ Username + password (not SSO schools)
If your school uses a regular username/password (not Microsoft/Google/SSO), you can skip the token step entirely:
```json
"env": {
"MOODLE_URL": "https://moodle.yourschool.edu",
"MOODLE_USERNAME": "your_username",
"MOODLE_PASSWORD": "your_password"
}
```
> โ ๏ธ **SSO schools**: If your school login page redirects to Microsoft, Google, or another identity provider, Option B won't work. Use Option A or C.
### Option D โ Extract from Moodle mobile app (SSO schools)
1. Install the **Moodle app** on your phone and log in with SSO
2. Go to **App settings โ About**
3. Tap the version number 5 times to enable developer mode
4. Go to **Developer options โ Copy token** and copy it
5. Use that token as `MOODLE_TOKEN` in Option A
---
## Tools
| Tool | Description | Params |
|------|-------------|--------|
| `moodle_get_site_info` | School name, Moodle version, which APIs are enabled | โ |
| `moodle_list_courses` | All your enrolled courses | โ |
| `moodle_get_course` | Sections and all activities in a course | `courseId` |
| `moodle_list_resources` | Files and links grouped by section โ returns opaque `fileId`s | `courseId` |
| `moodle_download_file` | Read a file by its `fileId` โ returns text for text/JSON/XML, base64 for PDFs/DOCX/images | `fileId` |
| `moodle_list_assignments` | Assignments with due dates, grouped by section | `courseId` |
| `moodle_get_assignment` | Submission status and grade feedback | `assignmentId` |
| `moodle_get_grades` | Full grade report with categories and feedback | `courseId` |
| `moodle_get_calendar_events` | Upcoming events across courses | `courseId?`, `daysAhead?` |
| `moodle_list_quizzes` | Quizzes with time limits and open dates | `courseId` |
| `moodle_get_quiz_attempts` | Your past attempt grades and states | `quizId` |
| `moodle_list_forums` | Forum activities in a course | `courseId` |
| `moodle_get_forum_discussions` | Recent discussions in a forum | `forumId` |
| `moodle_get_notifications` | Recent notifications (grades, feedback, replies) | `limit?` |
---
## Prompts
Use these in any MCP client that supports prompts (Claude Desktop, VS Code with Copilot, etc.):
| Prompt | Use case | Example |
|--------|----------|---------|
| `summarize-course` | Full course overview organized by section | `/summarize-course courseId=42` |
| `whats-due` | Prioritized due dates this week / next week | `/whats-due` or `/whats-due courseId=42` |
| `build-study-notes` | Build a linked Obsidian vault from course materials | `/build-study-notes courseId=42 vaultPath=~/obsidian/finals` |
| `exam-prep` | Topic-by-topic study guide based on grades and quiz results | `/exam-prep courseId=42` |
| `search-notes` | Natural language search across all course files | `/search-notes courseId=42 query="derivatives and limits"` |
---
## Obsidian Finals Prep
> Turn your entire semester into a linked knowledge graph in one command.
### Setup
1. **Install [Obsidian](https://obsidian.md)** (free, works on Mac/Windows/Linux)
2. Create a new vault, e.g. `~/obsidian/finals`
3. Make sure `moodle-mcp` is connected to your MCP client
### Build the vault
Use the `/build-study-notes` prompt in Claude Desktop:
```
/build-study-notes courseId=42 vaultPath=~/obsidian/finals
```
Or paste this directly into Claude:
```
Pull my [Course Name] (course ID 42), read all the lecture notes and slides,
and build a linked Obsidian vault at ~/obsidian/finals โ one note per topic,
with [[wikilinks]] between related concepts, a MOC.md index, and tags for each section.
```
Claude will:
1. Pull all your course sections, files, assignments, and grades
2. Read each PDF and document directly via the MCP resources protocol
3. Write one `.md` file per section with key concepts, definitions, and examples
4. Add `[[wikilinks]]` between related terms across notes
5. Create a `MOC.md` (Map of Content) index linking everything
### See the graph
**Option A โ Obsidian Graph View** (built-in, free)
1. Open the vault in Obsidian
2. Click **Graph View** (sidebar icon or `Cmd+G`)
3. Your entire course appears as a knowledge graph โ linked concepts cluster together, isolated topics stand out as things to review
**Option B โ Graphify** (richer visual graph)
1. Install [Graphify](https://graphify.app) โ it reads the same `.md` files Obsidian writes
2. Point it at your vault folder (`~/obsidian/finals`)
3. Drag to explore connections; click any node to open the note and ask Claude about it
Both tools read the same Markdown vault โ you can use both.
### Knowledge Graph preview
<img width="1565" height="947" alt="image" src="https://github.com/user-attachments/assets/382cf5ed-4806-4d3a-bfdc-6e4eeb15c3ec" />
*Your entire course as a linked knowledge graph โ built in one command. Run `/build-study-notes` once to generate this.*
### Query the graph with Claude
Once the vault exists on disk, you can ask Claude Code or Claude Desktop questions like:
```
Explain the relationship between [[topic A]] and [[topic B]] in my course notes at ~/obsidian/finals
```
```
Based on my notes in ~/obsidian/finals, which topics do I need to review most before the exam?
```
Claude reads your `.md` files directly and reasons across the full linked graph.
### Natural language search
Once the vault is built, you can ask Claude to find specific content:
```
/search-notes courseId=42 query="the central limit theorem and when to use it"
```
Claude will look through all your course materials, find the relevant files, read them, and synthesize a direct answer.
---
## Compatibility
Some tools require your Moodle admin to enable specific web services. Run `moodle_get_site_info` to see which tools are available on your school's Moodle.
| Tool | Required | Notes |
|------|----------|-------|
| `moodle_list_courses`, `moodle_get_course`, `moodle_list_resources`, `moodle_download_file` | Always available | Core Moodle WS |
| `moodle_list_assignments`, `moodle_get_assignment` | Admin must enable | `mod_assign` service |
| `moodle_get_grades` | Admin must enable | `gradereport_user` service |
| `moodle_get_calendar_events` | Usually available | `core_calendar` service |
| `moodle_list_quizzes`, `moodle_get_quiz_attempts` | Admin may need to enable | `mod_quiz` service |
| `moodle_get_forum_discussions` | Admin may need to enable | `mod_forum` service |
| `moodle_get_notifications` | Admin may need to enable | `message_popup` service |
If a tool isn't available, it returns a helpful message explaining what your admin needs to enable โ it won't crash the server.
---
## Security & file access (v0.2)
Tool responses never contain raw or authenticated Moodle file URLs. Instead, `moodle_list_resources` returns opaque `fileId`s โ AES-GCM-sealed envelopes bound to your Moodle account via the access token. Pass a `fileId` to `moodle_download_file`, and the server:
1. Decrypts the `fileId` and checks it was issued to you (not another user).
2. Re-checks with Moodle that the file is still visible to you (catches unenrolment, hidden modules, removed files).
3. Refuses anything that isn't a `pluginfile.php` URL on your Moodle host (no SSRF relay).
4. Fetches the file server-side with the token attached to the outbound request only โ the token never appears in anything returned to the MCP client.
5. Returns text for text/JSON/XML MIMEs, or the bytes as an MCP embedded resource (base64) for PDFs/DOCX/images.
This fixes the "domain not in the list of allowed fetch" error seen with Claude.ai's beta connectors when a chat tried to open a Moodle-hosted PDF: Claude no longer has to fetch anything cross-origin, because the content arrives inside the MCP response.
**Limits:** 25 MB per file by default (override with `MOODLE_MCP_MAX_FILE_MB=<positive number>`). File IDs expire after 24 hours. Rotating your Moodle token invalidates all outstanding IDs.
---
## Contributing
Issues and PRs welcome. Open an issue first for large changes.
MIT License โ ยฉ 2026 Alexandre Ribeiro
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues