mcpUPB
by olartgabo
README.md
<p align="center">
<img src="./assets/banner.svg" alt="mcp-upb" width="100%">
</p>
<p align="center">
<a href="https://modelcontextprotocol.io"><img src="https://img.shields.io/badge/MCP-server-1fb486" alt="MCP server"></a>
<img src="https://img.shields.io/badge/TypeScript-5.7-3178c6?logo=typescript&logoColor=white" alt="TypeScript">
<img src="https://img.shields.io/badge/Node-%E2%89%A518-339933?logo=node.js&logoColor=white" alt="Node >= 18">
<img src="https://img.shields.io/badge/Moodle-REST%20API-f98012?logo=moodle&logoColor=white" alt="Moodle REST API">
<a href="./LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue" alt="MIT License"></a>
</p>
<p align="center">
An <a href="https://modelcontextprotocol.io">MCP</a> server for <b>UPB Virtual</b> (Moodle) —
turn your university LMS into a structured knowledge source an AI assistant can query, sync and reason over.
</p>
---
> *"What's due this week?"* · *"Summarize the latest announcement"* · *"Build a study plan from this course"* · *"Sync all my Algorithms material to markdown"*
It talks to Moodle's official **Web Services REST API** (no browser scraping), so it's fast and
robust. Although it's tuned for UPB Virtual, it works against any Moodle site with web services
enabled — just change `MOODLE_BASE_URL`.
> ⚠️ **Personal tool.** It acts on *your* account with *your* token. Respect your institution's
> terms of service and only access data you're entitled to.
## How it works
```mermaid
flowchart LR
A["🤖 AI Assistant<br/>(Claude, mcpjam…)"] -- MCP / stdio --> B
subgraph B ["mcp-upb server"]
T["🛠️ Tools"]
R["📚 Resources<br/>upb://…"]
P["💬 Prompts"]
end
B --> C["Moodle REST client<br/>(token auth)"]
C -- "webservice/rest/server.php" --> M[("🎓 UPB Virtual<br/>Moodle")]
B --> V["🔄 Vault sync"]
V --> D["🗂️ vault/<br/>markdown + files"]
```
A typical request flows straight through to the LMS and back as clean JSON:
```mermaid
sequenceDiagram
participant U as You
participant AI as AI Assistant
participant S as mcp-upb
participant M as Moodle
U->>AI: "What's due this week?"
AI->>S: weekly_digest()
S->>M: core_calendar / forum / messages
M-->>S: JSON
S-->>AI: deadlines + announcements + alerts
AI-->>U: "3 things due, 1 overdue…"
```
## Features
### Tools
| Tool | Description |
|------|-------------|
| `whoami` | Verify the connection; return the authenticated user + site info |
| `list_courses` | All enrolled courses |
| `search_courses` | Search the site catalogue |
| `get_course` | Sections, activities and downloadable files of a course |
| `list_assignments` | Assignments (deadlines + attachments) for one or more courses |
| `get_assignment` | Full detail of one assignment |
| `submission_status` | Whether an assignment is submitted, plus grade/feedback |
| `get_grades` | Grade items and your grades for a course |
| `list_announcements` | Latest announcements for a course |
| `latest_announcements` | Latest announcements across all courses |
| `notifications` | Recent Moodle notifications |
| `upcoming_deadlines` | Calendar deadlines across all courses, sorted |
| `weekly_digest` | One overview: deadlines + announcements + unread notifications |
| `download_file` | Download a Moodle file by its `fileurl` to `./downloads` |
| `pdf_to_markdown` | Convert a local PDF to markdown (text layer) |
| `save_markdown` | Save markdown into the vault |
| `sync_course` | Download all new files of a course into the vault, converting PDFs (incremental) |
| `sync_all` | Sync every enrolled course |
### Resources
Browsable `upb://` URIs a client can attach as context:
- `upb://courses` — enrolled courses
- `upb://course/{id}` — a course's contents
- `upb://course/{id}/assignments` — a course's assignments
### Prompts
Ready-made commands: `weekly_summary`, `study_plan` (arg: `course`), `assignment_checklist` (arg: `assignment`).
## Setup
```bash
npm install
cp .env.example .env # Windows: copy .env.example .env
npm run get-token # enter your UPB username + password
```
`get-token` calls `login/token.php` and prints a `MOODLE_TOKEN=...` line. Paste it into `.env`.
Your password is **never stored** — only the token, which lives in `.env` (gitignored).
> If `get-token` fails with an invalid-login error, your account may use SSO/Google login, which
> can disable password-based tokens. In that case generate a token manually in Moodle under
> *Preferences → Security keys* and paste it into `.env`.
### Environment variables
| Variable | Default | Purpose |
|----------|---------|---------|
| `MOODLE_BASE_URL` | `https://www.upbvirtual.net/upbvirtual` | Moodle site root (no trailing slash) |
| `MOODLE_TOKEN` | — | Web-services token (required) |
| `DOWNLOAD_DIR` | `./downloads` | Where `download_file` saves |
| `VAULT_DIR` | `./vault` | Where synced material is written |
| `CACHE_DIR` | `./.cache` | Incremental-sync metadata |
## Testing with mcpjam
[mcpjam](https://www.mcpjam.com/) spawns the server as a stdio process and gives you a UI to run
tools, browse resources and chat against an LLM.
1. Launch the inspector (opens `http://127.0.0.1:6274`):
```bash
npm run inspect # = npx @mcpjam/inspector@latest
```
2. **Add Server → STDIO**:
| Field | Value |
|-------|-------|
| Transport | `STDIO` |
| Command | `npx` |
| Arguments | `tsx src/server.ts` |
| Working directory | the project root |
| Environment | `MOODLE_TOKEN=<token>` (most reliable; avoids `.env`/cwd issues) |
For the compiled build: `npm run build`, then Command `node`, Arguments `dist/server.js`.
3. Open **Tools** and start with `whoami`. Then `list_courses` → copy an `id` → `get_course`,
`list_assignments`, `get_grades`, etc.
## Use with Claude / other MCP clients
After `npm run build`, add to your client's MCP config:
```json
{
"mcpServers": {
"upb": {
"command": "node",
"args": ["C:/Users/User/Desktop/GitHub/mcpUPB/dist/server.js"],
"env": { "MOODLE_TOKEN": "your-token-here" }
}
}
}
```
## Scripts
| Script | What it does |
|--------|--------------|
| `npm run dev` | Run the server with tsx (stdio) |
| `npm run build` | Compile to `dist/` |
| `npm start` | Run the compiled server |
| `npm run get-token` | Exchange credentials for a token |
| `npm run inspect` | Launch mcpjam inspector |
## Notes & limitations
- `pdf_to_markdown` / `sync_course` extract the PDF **text layer** only (good for slides and notes;
no tables/math reconstruction). For high-fidelity conversion, plug in a
[Docling](https://github.com/DS4SD/docling) / PyMuPDF4LLM helper — the rest of the pipeline is
unchanged.
- Available data depends on what your Moodle role/capabilities expose via web services; some tools
may return errors if a function is disabled site-wide.
## Project structure
```
src/
server.ts MCP server entry (stdio)
config.ts env config
tools.ts tool registrations
resources.ts upb:// resources
prompts.ts prompt templates
moodle/
client.ts REST transport (token, params, file urls)
api.ts typed Moodle function wrappers
storage/
cache.ts incremental-sync cache
vault/
sync.ts sync_course / sync_all
pdf.ts pdf -> markdown
markdown.ts vault writer
scripts/
get-token.ts credentials -> token helper
```
## License
[MIT](./LICENSE)
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues