Skip to main content
Glama
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)

Maintenance

ActivityInactive
ResponsivenessNo issues