uplus-mcp
README.md
# uplus-mcp
MCP server for the QingSoft U+ learning platform **with a built-in generic browser toolset**.
See [README.zh.md](README.zh.md) for the full Chinese guide (step-by-step install, run, and push-back-to-GitHub instructions).
## What's new in 0.4.2
- **Two-mode sign-in** (`uplus_login`): the model first asks the user whether to
sign in manually (open the portal and wait for the user to finish in the Edge
window) or automatically (ask for account, password and school name, fill the
school selector, account and password, submit and verify the session). Auto-mode
credentials live only for that call and are never persisted to config, reports
or logs, and never echoed back; missing fields, an unmatched school selector,
captchas, SMS codes or wrong-password prompts fall back to manual takeover.
- **Batched page actions** (`browse_act_batch`): run a short serial batch of
clicks, fills, presses, scrolls, waits, extracts and navigation; the batch
stops on the first failure or navigation and returns a
completed / remaining / failure / navigated receipt. Password-field values
are never extracted back. The original single-step `browse_*` tools are
unchanged.
- **Attachment question type** (`qsnType=7`) and a three-state experiment
status (submitted / outstanding / unknown) that hands unknown cards back for
manual review; expired courses are skipped during patrol by default.
### Earlier: 0.4.0
- **Merged browse toolset**: 17 single-step `browse_*` tools let the model drive any web
page directly (open, snapshot, click, fill, type, press, scroll, screenshot,
eval JS, tabs) on the same attached Edge session — the fallback when the
platform's REST contract changes or a step has no API.
- **Fixed the asyncio crash**: FastMCP calls sync tools on the event-loop
thread, where Playwright's sync API refuses to run. All browser work now runs
on one dedicated worker thread (`worker.py`); tools are async and await it.
- **Fixed 401 on every read API**: U+ requires an `x-access-token` header
(from `localStorage.AccessToken`) on each API call, not just cookies.
- **Fixed the Edge debug port that never listens**: Edge/Chromium 136+ ignores
`--remote-debugging-port` on the default user-data directory. `launcher.py`
copies the profile to a dedicated directory once (login survives) and starts
Edge there with the port; `browse_launch_edge` does it in one call.
An MCP server that patrols the [青软 U+](https://www.eduplus.net) learning platform: it lists courses, homework and experiments, reads objective questions into a structured brief, lets the connected MCP client model answer, fills the answer page, verifies selections and submits. Subjective questions, programming work, experiment reports and file attachments are explicitly handed back to the human.
> **Academic integrity notice** — This tool is a personal study and reminder helper. Use it to review questions, track deadlines and organize your own work. Experiment reports, group deliverables, programming assignments and open-ended answers must be completed by yourself. Follow your school's academic honesty rules and course instructor instructions. Do not use this tool in exams, closed-book tests or any assessment that prohibits assistance.
## Features
- The session attaches to the user's own Edge through CDP; the server stores no
passwords, cookies or login snapshots in the repository.
- Read-only REST calls reuse the in-page session; page writes follow the real human path (option click, confirmation dialog, post-submit button verification).
- Objective questions (single choice, multiple choice, true/false, fill-in) can be filled and submitted after the client model returns a normalized answer map.
- Patrol report in Markdown: submitted / pending / outstanding homework, experiments, and a takeover list for manual work.
- Works with any MCP-compatible client: Claude Desktop, Cursor, VS Code MCP, Doubao agent, and others.
- Unattended CLI for nightly scheduled patrol; it never answers or submits on its own.
## Architecture
```
MCP client ──stdio──▶ server.py (FastMCP tools)
│
engine.py (orchestration)
┌───────────────┼────────────────┐
platform.py operator.py report/solver
read-only REST page UI writes reports + normalization
└───────────────┼────────────────┘
browser.py (Playwright session)
```
See [`docs/architecture.md`](docs/architecture.md) for module responsibilities, [`docs/api-mapping.md`](docs/api-mapping.md) for the captured U+ endpoints and status rules, and [`docs/adapter-guide.md`](docs/adapter-guide.md) for adding another platform.
## Quick start
### 1. Install
```powershell
cd D:\u+小助手
python -m venv .venv
.venv\Scripts\Activate.ps1
pip install -e .
```
The server attaches to your own Edge over CDP; no bundled Chromium download is
required.
### 2. Configure personal courses (gitignored)
```powershell
Copy-Item config\courses.example.json config\courses.json
```
Edit `config/courses.json` with your actual `courseId` values and local paths.
### 3. Sign in
Ask the MCP client to run `uplus_login`:
- `mode="manual"`: the portal opens in the attached Edge window; finish signing
in yourself, and the tool waits until the session token appears.
- `mode="auto"`: the model first asks for your account, password and school
name, fills the school selector, account and password fields, submits and
verifies the session. Credentials are used only for that call and are never
saved or echoed back. If the form cannot be found, the school selector cannot
be matched, or a captcha / SMS code / wrong-password prompt appears, fall back
to manual mode.
If the debug port is not listening yet, call `browse_launch_edge` once; it
copies the Edge profile to a dedicated directory and starts Edge with the port.
### 4. Register the server in your MCP client
See [`docs/mcp-clients.md`](docs/mcp-clients.md) for Claude Desktop, Cursor and VS Code examples. Minimal stdio registration:
```json
{
"mcpServers": {
"uplus": {
"command": "uv",
"args": ["--directory", "C:\\Users\\you\\projects\\uplus-mcp", "run", "python", "-m", "uplus_mcp.server"],
"env": { "UPLUS_CONFIG": "config/courses.json" }
}
}
}
```
## Tools
### U+ workflow
| Tool | Description |
| --- | --- |
| `uplus_login` | Sign in by `manual` takeover or `auto` fill (account, password, school); ask the user which mode first |
| `uplus_check_login` | Verify whether the attached Edge session is signed in |
| `uplus_list_courses` | List courses under the signed-in account |
| `uplus_list_homeworks` | List homework status; open answer pages to verify button truth on demand |
| `uplus_list_experiments` | List experiments and submission state (submitted / outstanding / unknown) |
| `uplus_inspect_homework` | Return status and a structured question brief for the client model |
| `uplus_answer_homework` | Fill objective questions and optionally submit |
| `uplus_upload_attachment` | Attach a local file to a homework that requires upload |
| `uplus_patrol` | Full patrol, Markdown report, answer briefs and takeover list |
| `uplus_close` | Release the browser session held by this process |
### Generic browser (`browse_*`)
Single-step tools: `browse_launch_edge`, `browse_open`, `browse_snapshot`,
`browse_get_text`, `browse_click`, `browse_fill`, `browse_type`, `browse_press`,
`browse_scroll`, `browse_select_option`, `browse_upload`, `browse_screenshot`,
`browse_eval_js`, `browse_wait_for`, `browse_tabs`, `browse_switch_tab`,
`browse_back`.
`browse_act_batch` runs a short serial batch of those actions: click, fill,
press, hover, scroll, wait, extract, navigate, back. The batch stops on the
first failure or navigation and returns a completed / remaining / failure /
navigated receipt; `observe="summary"` skips the follow-up snapshot. Password
fields are never extracted back.
## Nightly patrol (unattended)
```powershell
.venv\Scripts\python.exe -m uplus_mcp.daily_patrol
```
The CLI writes `reports/patrol_YYYYMMDD_HHMM.md` and a `.brief.json` for outstanding objective questions. Exit code `2` means the login session expired; exit code `1` means a runtime failure. Register this command in Windows Task Scheduler (e.g. daily 21:30) or your system cron.
> The CLI never submits homework. Answer and submission happen through an MCP session after the model reviews the brief.
## Configuration reference
`config/courses.json`:
| Field | Default | Meaning |
| --- | --- | --- |
| `base_url` | `https://www.eduplus.net` | Platform root |
| `nav_timeout_ms` | `30000` | Page navigation timeout |
| `action_timeout_ms` | `15000` | UI action timeout |
| `deadline_warning_hours` | `72` | Highlight deadlines inside this window |
| `report_dir` | `reports` | Markdown report output folder |
| `auto_launch_edge` | `true` | Copy the Edge profile and launch Edge with the CDP port when no port listens |
| `profile_dir` | system profile copy | Dedicated Edge profile directory used for the CDP launch |
| `include_expired_courses` | `false` | Skip expired courses during patrol; set `true` to keep an archived view |
| `courses` | empty | `id` / `name` / `teacher` per course; empty falls back to the live API list |
## Development
```powershell
pip install -e ".[dev]"
pytest
```
- 62 unit tests cover model parsing, config loading, answer normalization, page
state rules, experiment classification, the two-mode login flow and the batch
action receipt.
- Browser and platform interactions are exercised against a real session in
read-only patrol mode; write actions require the authorized account and an
active course deadline.
## Repository layout
```
src/uplus_mcp/
browser.py CDP-attached Playwright session + in-page fetch
browse.py generic single-step and batched page actions
platform.py read-only REST client
operator.py page UI operations
engine.py shared orchestration
models.py domain objects and enums
config.py configuration loader
solver.py brief generation + answer normalization
report.py patrol report aggregation and Markdown render
utils.py HTML cleaning, time and answer normalization helpers
worker.py dedicated thread that runs all Playwright sync calls
launcher.py locate / launch Edge with the debug port
server.py FastMCP tools
daily_patrol.py unattended CLI
scripts/smoke_mcp.py stdio end-to-end smoke check
docs/ architecture, API mapping, client config, adapter guide
config/ personal config example (real file gitignored)
reports/ generated patrol reports (gitignored)
tests/ unit tests
```
## Safety and privacy
- Keep `config/courses.json` and `reports/` local; they are listed in `.gitignore`.
- Do not commit student IDs, names, phone numbers, email addresses, cookies or tokens.
- The server never persists your password; `uplus_login` auto-mode uses
credentials only for the current call and never writes them to config, reports
or logs or echoes them back in tool results.
## License
MIT, see [`LICENSE`](LICENSE).
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues