Metadata-Version: 2.4
Name: moodle-study-kit
Version: 0.2.6
Summary: Read-only Moodle toolkit for agents, MCP servers, and local scripts
License-Expression: MIT
Keywords: moodle,lms,education,study,mcp
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Education
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: platformdirs>=2.10
Requires-Dist: pymupdf>=1.23
Requires-Dist: rich>=13.0
Provides-Extra: mcp
Requires-Dist: mcp>=1.0; extra == "mcp"
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Dynamic: license-file

# moodle-study-kit

Read-only Moodle toolkit for students and agents. Provides a Python library, CLI, and MCP server for accessing Moodle course data without any write operations.

## Quick start

### Install

Pick whichever tool you already have:

```bash
uv tool install moodle-study-kit      # recommended — adds moodle-study to PATH automatically
pipx install moodle-study-kit         # alternative
pip install moodle-study-kit          # if you just want the library, or don't have uv/pipx
```

**Windows note:** If `moodle-study` is not recognised after `pip install`, the Python
Scripts folder may not be on your PATH. Either:

1. Add it manually — find the path with:
   ```
   py -c "import site; print(site.getusersitepackages())"
   ```
   Then add that directory to your PATH in **Windows Settings > System > Environment Variables**.

2. Or use the module form directly (works immediately, no PATH changes needed):
   ```
   py -m moodle_study_kit.cli courses
   ```

### Set up credentials

```bash
moodle-study setup
```

The setup command will prompt for your Moodle URL, API token, and user ID, then verify
the connection and save credentials. See [Getting a Moodle API token](#getting-a-moodle-api-token) below if you don't have a token yet.

Non-interactive setup (for scripts and agents):

```bash
moodle-study setup --url https://moodle.example.ac.uk --token YOUR_TOKEN
```

## Getting a Moodle API token

### Via the Moodle web interface (recommended)

1. Log in to your Moodle site in a browser.
2. Click your profile picture (top right) → **Preferences**.
3. Under **User account**, click **Security keys**.
4. Find the **Moodle mobile web service** row.
5. Click **Reset** to generate a new token (or copy the existing one if shown).
6. Copy the token string — this is the long alphanumeric value you need for setup.

> **Tip:** Copy the token value itself (a long string of letters and numbers), not the key name like "Webservice-A3JsY" shown in the table.

### Via the token URL (advanced)

If the method above doesn't work for your institution, you can request a token directly:

```
https://<your-moodle>/login/token.php?username=YOUR_USER&password=YOUR_PASS&service=moodle_mobile_app
```

**Note:** Only use this over HTTPS. Never share your token.

## Configuration

Credentials are resolved in this order:

1. **Explicit arguments** passed to `MoodleConfig.load(url=..., token=...)`
2. **Environment variables**: `MOODLE_URL`, `MOODLE_TOKEN`, `MOODLE_USERID`
3. **Config file** (first found):
   - `$MOODLE_CREDS_PATH` (if set)
   - Platform-native config directory (see below)
   - `~/.moodle_creds.json` (legacy fallback)

The config directory is determined by `platformdirs` so it follows each OS's conventions: `~/.config/moodle-study-kit/` on Linux, `~/Library/Application Support/moodle-study-kit/` on macOS, and `%APPDATA%\moodle-study-kit\` on Windows. Run `moodle-study config` to see the active path on your system, or `moodle-study config --json` for machine-readable output. Existing `~/.moodle_creds.json` files are still read as a fallback.

### Config file format

```json
{
  "url": "https://moodle.example.ac.uk",
  "token": "your_token_here",
  "userid": 12345
}
```

### Environment variables

```bash
export MOODLE_URL="https://moodle.example.ac.uk"
export MOODLE_TOKEN="your_token_here"
export MOODLE_USERID="12345"
```

## CLI usage

```
moodle-study courses              # List enrolled courses
moodle-study deadlines            # Show upcoming deadlines (14-day window)
moodle-study deadlines --days 7   # Shorter look-ahead
moodle-study contents 12345       # Show sections for course ID 12345
moodle-study contents EC100       # Look up by course short-code
moodle-study contents MG488       # Prefix match: finds MG488_2526 if unique
moodle-study contents EC100 --week 3    # Filter to a specific week
moodle-study materials EC100      # List all downloadable materials (discovery)
moodle-study materials EC100 --week 3   # Materials for week 3 only
moodle-study download EC100 --week 3 --match slides   # Download a file (authenticated)
moodle-study download EC100 --week 3 --index 0        # Download by index
moodle-study summary EC100 --week 3     # AI-generated study notes for a week
moodle-study setup                # Guided first-time setup
moodle-study update               # Show the safe upgrade command
```

Add `--json` before the command for machine-readable JSON output:

```
moodle-study --json courses
moodle-study --json deadlines
```

## MCP server

For use with Claude Code, OpenClaw, or other MCP-capable agents:

```bash
pip install "moodle-study-kit[mcp]"
python -m moodle_study_kit.mcp_server
```

The server runs as a stdio-based MCP server. Tools: `list_courses`, `get_deadlines`, `get_course_contents`, `get_week_materials` (discovery), `search_course_content`, `get_weekly_summary`, `download_material` (authenticated fetch).

**Claude Code**: Add to your Claude Code settings / MCP Servers config:
```json
{
  "mcpServers": {
    "moodle-study-kit": {
      "command": "python",
      "args": ["-m", "moodle_study_kit.mcp_server"]
    }
  }
}
```
Set `MOODLE_URL`, `MOODLE_TOKEN`, `MOODLE_USERID` as environment variables or in `~/.config/moodle-study-kit/config.json`.

**OpenClaw**: Add to your agent or gateway config:
```yaml
mcpServers:
  moodle:
    command: python
    args: ["-m", "moodle_study_kit.mcp_server"]
    env:
      MOODLE_URL: "https://your-moodle.example.ac.uk"
      MOODLE_TOKEN: "your_token_here"
      MOODLE_USERID: "12345"
```

## CI

Packaging and install smoke tests run automatically on every push and pull request across Linux, macOS, and Windows. The workflow builds both sdist and wheel, installs each in a clean virtual environment, and verifies the CLI entrypoints work.

## Development

To work on moodle-study-kit itself (contributors / developers):

```bash
git clone <repo-url> && cd moodle-study-kit
python -m venv .venv && source .venv/bin/activate   # Windows: .venv\Scripts\activate
pip install -e '.[dev]'
```

### Running tests

```bash
pytest

# On Windows, if pytest isn't found on PATH:
py -m pytest
```

## Safety

This package is **read-only by design**. Every Moodle API call is checked against a hardcoded allowlist in `ALLOWED_FUNCTIONS` inside the client module. Write-like operations — submitting assignments, posting forum replies, uploading files, creating events, deleting content — are blocked with a `SafetyError` before any network request is made.

- Your token cannot modify anything on Moodle, even accidentally.
- Agents (Claude Code, OpenClaw, etc.) can use these tools safely.
- Treat your Moodle API token like a password: never commit it to git, never share it, use HTTPS only.

### Known limitations

- **Token portability varies by institution.** Some Moodle instances require specific web-service configurations. Check with your Moodle administrator about enabling REST web services.
- **Rate limiting.** Moodle servers may throttle rapid API calls. The package handles errors gracefully but cannot bypass institutional limits.
- **Only Moodle REST API v2 is supported.**
- **Course discovery by short-code uses prefix matching** (e.g. "MG488" matches "MG488_2526") — see CLI usage above.

## For Agent Authors

moodle-study-kit is designed to be agent-friendly:

- Zero configuration needed for discovery — call `list_courses()` with no arguments to explore.
- Self-documenting tool names and clear purpose descriptions.
- Structured output by default — use `--json` on CLI, or rely on structured dict/JSON from the Python API.
- Graceful degradation with clear error messages when credentials are missing.

### Discovery vs. download

There are two distinct steps — **discovery** and **download** — with separate commands for each:

| Purpose | CLI | MCP tool |
|---------|-----|----------|
| **List** available files (metadata only) | `moodle-study materials` | `get_week_materials()` |
| **Download** a file (authenticated) | `moodle-study download` | `download_material()` |

`materials` / `get_week_materials` return metadata including a `file_url` field. This URL is the raw Moodle address retained for **provenance only** — do not fetch it directly, as it requires token authentication that is handled internally by `download` / `download_material`.

### Downloading materials

The `download` command (CLI) and `download_material` tool (MCP) provide authenticated file downloads without exposing the Moodle token. The flow:

1. **Discover** materials: `moodle-study materials EC100 --week 3`
2. **Download** one: `moodle-study download EC100 --week 3 --match slides`

If multiple materials match, you get a structured candidate list with indices:

```bash
moodle-study --json download EC100 --week 3
# → {"error": "3 materials match. Use --index ...", "candidates": [...]}

moodle-study --json download EC100 --week 3 --index 0
# → {"local_path": "/path/to/week3_slides.pdf", "file_name": "week3_slides.pdf", ...}
```

The same workflow is available via MCP:

```
get_week_materials(course_id=42, week="3")          # discover
download_material(course_id=42, week="3", match="slides")  # fetch
```

Example integration in an agent system prompt:
```
You have access to moodle-study-kit. First run list_courses() to see available courses,
then get_deadlines() to check upcoming work, then explore specific courses with
get_course_contents(). To see what files are available, use get_week_materials(). To
fetch a file, use download_material() — it handles authentication internally. Never
fetch file_url values directly; always use download_material().
```
