camcors-mcp
# camcors-mcp
An unofficial MCP server for Cambridge's CamCORS (Online Reporting of
Supervisions) system.
The server uses a visible Chrome window for Raven sign-in and report previews.
It sends report requests to the same internal endpoints as the CamCORS web
pages. These endpoints are not a published API.
Raven credentials and CamCORS cookies stay in a dedicated Chrome profile. The
server does not accept them as tool arguments, print them to logs or store them
in this repository.
> [!CAUTION]
> CamCORS contains confidential student and payment information. Use this
> server only with an account you are authorised to use. Do not add real report
> data to the repository. Check each write action in the Chrome window.
## What it does
- Opens CamCORS in a persistent Chrome profile.
- Lists supervision and non-supervision reports.
- Reads a report by its CamCORS report ID.
- Prepares and creates supervision report drafts.
- Reads the editable fields from a Draft or Returned report.
- Edits report fields and supervision timings.
- Deletes Draft or Returned reports after a separate confirmation.
- Validates reports without submitting them.
- Submits reports after a separate confirmation.
- Discards an unused preview without changing CamCORS.
`camcors_create_supervision_drafts` creates drafts. It does not submit them.
Submission uses separate validation and confirmation tools.
## Requirements
- Node.js 22 or newer
- Google Chrome
- Access to `https://apps.casc.cam.ac.uk/ors/`
## Install
```bash
npm ci
npm run build
```
Run the tests and type checks:
```bash
npm test
npm run typecheck
```
## Configure an MCP client
Use the absolute path to `dist/index.js`. For example:
```json
{
"mcpServers": {
"camcors": {
"command": "node",
"args": ["/absolute/path/to/camcors-mcp/dist/index.js"],
"env": {
"CAMCORS_USER_DATA_DIR": "/absolute/path/to/.camcors-mcp/chrome-profile"
}
}
}
}
```
The default profile path is `~/.camcors-mcp/chrome-profile`. You can omit the
`env` block if you use that path.
## Sign in for the first time
1. Call `camcors_open`.
2. Sign in with Raven in the Chrome window.
3. Call `camcors_open` again.
4. Check that the result contains `"authenticated": true`.
The dedicated profile keeps the login between server runs. The server does not
copy cookies from your usual browser profile.
### Use an existing remote-debugging Chrome session
Set this variable if Chrome is already running with remote debugging:
```bash
CAMCORS_CDP_URL=http://127.0.0.1:9222
```
Recent Chrome versions require a non-default `--user-data-dir` for remote
debugging. On macOS, start a dedicated instance with:
```bash
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \
--remote-debugging-port=9222 \
--user-data-dir="$HOME/.camcors-mcp/chrome-profile"
```
Sign in to CamCORS in that window. Then start the server with
`CAMCORS_CDP_URL` set.
## Create, edit, delete and submit reports
### Create report drafts
1. Call `camcors_prepare_supervision_drafts`. It fills in the CamCORS form and
returns a preview token.
2. Check the students, term, Tripos part, paper and topic in CamCORS.
3. Call `camcors_create_supervision_drafts` with the token and `confirm: true`.
### Edit a report and set supervision timings
1. Call `camcors_get_editable_report` with a Draft or Returned report ID.
2. Use the returned field names and option values in
`camcors_prepare_report_edit`.
3. To replace the timings, pass the complete `groups` list. Set `size` to the
number of students in the group. Set `totalMinutes` to the total time taught
to groups of that size.
4. Check the CamCORS edit form.
5. Call `camcors_save_report_edit` with the token and `confirm: true`.
The server reads the editable fields from the live form. It does not use a
fixed list. A control without a form name has a key such as `#controlId`. This
applies to controls such as the visible payment option selector. CamCORS
updates the corresponding hidden values when these controls change.
The server applies the same basic timing checks as the CamCORS form:
- Group sizes are positive and unique.
- Durations are whole minutes and at least 15 minutes.
- An empty list requires `allowNoGroups: true`. CamCORS might still return a
warning.
### Delete a Draft or Returned report
1. Call `camcors_prepare_report_deletion` with the report IDs.
2. Check the exact reports in the CamCORS preview.
3. Call `camcors_delete_reports` with the returned `deletionToken` and
`confirm: true`.
The server checks that each report is still a Draft or Returned report. It
checks the reports again immediately before deletion and verifies that they no
longer appear afterwards. A deletion token is used once. If the request fails
without a clear result, inspect CamCORS before trying again.
### Validate and submit reports
1. Save all intended edits.
2. Call `camcors_prepare_report_submission` with one or more report IDs.
3. Fix each error and read each warning.
4. If validation passes, call `camcors_submit_reports` with the returned
`submissionToken` and `confirm: true`.
5. If validation returned warnings, also set `acknowledgeWarnings: true`.
The server calls the CamCORS validation action directly. This avoids the web
page's automatic submission behaviour when validation returns no warnings.
The server validates the reports again before submission. The result must
match the preview. It uses each submission token once and consumes it before
the network request. If the request fails without a clear result, check
CamCORS before trying again.
Preview tokens expire after 30 minutes. They are also lost when the MCP
process exits.
## How it connects to CamCORS
CamCORS has no published API for report submission. This server uses the
internal HTTP requests made by CamCORS v7:
- report search and report detail requests
- draft creation and report save form posts
- report deletion, validation and final submission actions
The request client shares Chrome's cookie jar. It does not copy cookies into
environment variables or MCP messages. Each request is restricted to the
configured CamCORS origin and `/ors/` path. Write requests include the
anti-forgery token when the current CamCORS form provides one.
The server still opens CamCORS pages when it needs Raven sign-in, a preview or
CamCORS form JavaScript. This includes student lookup and the timing controls
on the report edit form.
## Environment variables
| Variable | Default | Purpose |
| --- | --- | --- |
| `CAMCORS_BASE_URL` | `https://apps.casc.cam.ac.uk/ors/` | CamCORS application root |
| `CAMCORS_USER_DATA_DIR` | `~/.camcors-mcp/chrome-profile` | Dedicated persistent Chrome profile |
| `CAMCORS_HEADLESS` | `false` | Run Chrome without a visible window |
| `CAMCORS_CDP_URL` | unset | Attach to an existing remote-debugging Chrome |
| `CAMCORS_ACTION_TIMEOUT_MS` | `30000` | Browser action timeout |
## Security
- The server marks report text as untrusted data.
- It runs browser operations in sequence.
- It restricts report URLs to the configured CamCORS origin and `/ors/` path.
- Edit tools accept only fields found in the current CamCORS form.
- Deletion requires an exact report preview and separate confirmation.
- Submission requires validation and confirmation. Warnings also require
acknowledgement.
- Automated tests do not use the live site.
- Do not commit `.env` files, browser profiles, screenshots, downloaded
reports, CRSids or fixtures based on real reports.
See [SECURITY.md](SECURITY.md) for reporting and operating guidance.
## Known limits
The selectors and internal requests were checked against CamCORS v7 on 29 July
2026. CamCORS can change them without notice. Such a change might require an
update to this server.
The full edit and submission flow covers supervision reports. Non-supervision
reports and general claims currently have read support only.
TDQS
Scored across 14 tools
The tools have distinct purposes, with only a slight potential confusion between camcors_discard_report_preview (submission/deletion previews) and camcors_discard_preview (creation previews). Their descriptions clarify the difference, but the naming could be more distinct.
All tools follow a consistent verb_noun pattern with 'camcors_' prefix. Despite minor variation like 'discard_report_preview' vs 'discard_preview', the overall naming is predictable and logically structured.
With 14 tools, the server covers authentication, listing, reading, creation, editing, submission, and deletion workflows without being excessive. Each tool serves a clear step in the process, earning its place.
The tool set provides full lifecycle coverage for CamCORS reports: list, get, create, edit, submit, delete. The prepare/execute pattern ensures user confirmation steps are handled, leaving no obvious gaps in the standard workflow.