Skip to main content
Glama
icampus-mcp

icampus-mcp

by cwon-z

skku-icampus

Keeps a copy of your own SKKU iCampus data and serves it to other programs over a REST API, and to AI assistants over MCP. That covers tasks and deadlines, assignment submission status, announcements, lectures and attendance, grades, and the files attached to announcements and assignments.

icampus      (FastAPI :9013)  logs in by itself, syncs 4×/day, stores everything in SQLite
icampus-mcp  (:8724/mcp)      MCP tools; only talks to the API, never sees your password

Unofficial, not affiliated with Sungkyunkwan University. It only reads your own account; follow your university's rules when you use it.

How it works

  • Login. A headless Chromium signs in through the normal SSO page, but only when the saved session has expired. Everything after that is plain GET requests: Canvas /api/v1 and the LearningX JSON API that My Page, 강의콘텐츠 and 출결현황 use themselves (notes).

  • Read-only. The browser works from an allowlist of pages and never loads item pages, because opening a lecture item in iCampus marks it complete. It never submits anything, starts quizzes or marks anything read.

  • Attachments, on request only. A sync records which files an announcement or assignment has (names, sizes, IDs), never the files. A file is downloaded only when someone asks for it, with the saved login, and only if a synced announcement or assignment points at it; lecture items are never opened. iCampus records a download as you opening the file, and if a linked file also sits in a course module, as viewing it there. Copies are kept in var/files and reused until a sync sees a new version (for 12 hours when iCampus gives none). A child process with a memory cap and a time limit reads the text out of them.

  • Careful with logins. At most 3 password logins a day. A rejected password, a locked account or a password-expiry notice stops automatic logins until you retry with an admin token (POST /api/v1/sync?retry_login=true).

  • Schedule. Syncs run at 07:30, 12:30, 18:00 and 22:30 KST (±10 min), plus on request. They show up as normal account activity in Canvas.

  • Failures. If part of a sync fails, the old data for that part is kept and its synced_at stays at the last good sync. stale turns true once that is older than 12 hours (ICAMPUS_STALE_HOURS); from then on /api/v1/status (and the Uptime Kuma push) reports unhealthy and names the datasets left behind, and a task status resting on that data says it is outdated. /api/v1/status shows per-run errors. An item that drops off the iCampus to-do list is not marked "done".

Related MCP server: mos-diary-mcp

Run it locally

uv sync
uv run playwright install chromium
cp .env.example .env && chmod 600 .env     # your 킹고ID + tokens (openssl rand -hex 24)
uv run icampus sync --headed               # one sync, watching the browser
uv run icampus serve                       # API on 127.0.0.1:9013 (+ the schedule)
uv run pytest

Swagger UI: http://127.0.0.1:9013/docs. icampus probe is a one-off read-only check of what the iCampus pages load. It writes its report to var/probe/, which is gitignored and holds personal data.

REST API

Send Authorization: Bearer <token> on every call. Tokens come from ICAMPUS_API_TOKENS (label:token,...). List responses look like {synced_at, stale, count, items}; when a list is cut short they add total and truncated. course accepts an ID, a course code or part of a name.

Endpoint

Notes

GET /health

no auth

GET /api/v1/status

last runs, freshness per dataset, login state, next run

POST /api/v1/sync

Returns 202 started, 409 running, 429 cooldown or 423 blocked. ?retry_login=true needs an admin token

GET /api/v1/courses

codes, instructors, current grade

GET /api/v1/tasks

merged to-do list: course, kind, status, due_within_days=14, past_days=0, include_done, include_inactive, limit

GET /api/v1/assignments

course, unsubmitted_only. /{id} adds the description and task status

GET /api/v1/announcements

course, since_days=30, unread_only, limit. /{id} gives the full text

GET /api/v1/files/{id}

an announcement or assignment attachment and its text: offset, max_chars=20000. Downloads it on first use

GET /api/v1/files/{id}/content

the file itself

GET /api/v1/lectures

course, week, kind, incomplete_only, available_only, upcoming_only, include_attendance, limit

GET /api/v1/grades

course

GET /api/v1/export

everything as one JSON document

A few fields to read carefully:

  • status sums up a task or lecture item: todo, done, missed (deadline and any late period passed), upcoming (not open yet) or unknown (iCampus can't tell, e.g. handed in on paper or through an external tool). Canvas decides for what you hand in, LearningX for what you watch or read. status_reason says which, and status_checked_at when that source last confirmed it.

  • in_remaining_list is what My Page shows. It does not mean you haven't submitted.

  • completed and submission are only filled in when iCampus reported them. null means unknown.

  • attendance is one of attendance (present), late, absent or none (not decided yet).

  • Attachment text comes out of PDF, Word, PowerPoint, Excel, HWPX, notebooks and text files. extract says when there is none: a picture, a scanned PDF, or the binary HWP format.

MCP

Tools: sync_status, list_courses, list_tasks, list_announcements, read_announcement, read_assignment, read_attachment, list_lectures, get_grades, refresh. All are read-only except refresh, which asks for a sync, and read_attachment, whose first read of a file downloads it from iCampus (so clients may ask before running it). It returns text, or the picture itself for images.

# over HTTP (icampus-mcp --http), with a token from ICAMPUS_MCP_TOKENS
claude mcp add --transport http icampus http://<server>:8724/mcp --header "Authorization: Bearer <token>"

# or locally over stdio against the API
claude mcp add icampus --env ICAMPUS_MCP_API_URL=http://<server>:9013 \
  --env ICAMPUS_MCP_API_TOKEN=<api token> -- uv run --directory "$PWD" icampus-mcp

Over HTTP, a request gets in with either a bearer token from ICAMPUS_MCP_TOKENS or a Cloudflare Access JWT. Without either one configured, the server won't start.

The Access route is how claude.ai and the mobile apps reach it:

  1. Put a public hostname behind an Access app with Managed OAuth, and proxy it to :8724.

  2. Set these variables:

    • ICAMPUS_MCP_ACCESS_TEAM, for example myteam.cloudflareaccess.com;

    • ICAMPUS_MCP_ACCESS_AUD, the app's AUD tag or tags, comma-separated;

    • ICAMPUS_MCP_ACCESS_EMAILS, the emails allowed in;

    • ICAMPUS_MCP_ALLOWED_HOSTS, which must include the public hostname.

Deploy with Docker

cp .env.example .env && chmod 600 .env    # fill it in
docker compose up -d --build              # ports on 127.0.0.1 only

To expose the ports on a server, copy compose.homelab.example.yaml to compose.homelab.yaml (gitignored), put in your addresses, and add COMPOSE_FILE=compose.yaml:compose.homelab.yaml to .env. Keep the API off the public internet, and put only the MCP port behind Cloudflare Access. The MCP container never gets your SSO password.

License

MIT — see LICENSE.

Repo

Path

What

src/icampus/

the program (browser.py login + allowlist, collect.py, sync.py, views.py task status, files.py + extract.py attachments, api.py, mcp_server.py)

docs/icampus-notes.md

how iCampus behaves: login flow, endpoints, side effects

tests/

offline tests; one runs a local Chromium against a fake login page, one downloads from a local server

var/ (the database, saved session, downloaded attachments, probe output), .env and private/ hold personal data and are gitignored.

Available Tools

8 tools
get_gradesB
Read-only

Course totals and per-assignment scores as Canvas shows them to you (hidden grades stay hidden).

Inputs: course.

list_announcementsA
Read-only

Recent course announcements (title, date, author, read state, a short preview), newest first. Use read_announcement with an id for the full text.

Inputs: course, since_days, unread_only.

list_coursesA
Read-only

This term's courses: id, code (e.g. CSE1001), name, instructors and the current grade if visible.

Inputs: no named parameters.

list_lecturesA
Read-only

Lecture videos/materials with completion and attendance as iCampus shows them, soonest deadline first. By default: items already open, not completed, whose deadline (incl. late period) has not passed.

Args:
    course: course ID, code or part of the name.
    week: week number (1 = 1주차).
    kind: e.g. video or material.
    incomplete_only: only items reported as not completed (unknown completion is left out).
    include_upcoming: also items that have not opened yet.
    include_overdue: also items whose deadline has passed (missed, possibly still viewable).
    include_attendance: add each course's official per-lesson attendance summary.
    limit: maximum items returned.

Inputs: kind, week, limit, course, +4 more.

list_tasksA
Read-only

Things to do across courses, soonest first: the iCampus remaining list merged with Canvas assignment/quiz submission status and lecture completion. Items with no due date come last.

Args:
    course: course ID, code (CSE1001) or part of the name. Omit for all courses.
    kind: only this kind of item.
    due_within_days: items due in the next N days (items without a due date are always included).
    past_days: also include items whose due date passed in the last N days (overdue/late window).
    include_done: also include submitted/completed items.
    limit: maximum items returned; `total` shows how many matched when truncated.

Inputs: kind, limit, course, past_days, +2 more.

read_announcementA
Read-only

Full text of one announcement (by the numeric id from list_announcements).

Inputs: announcement_id (required).

refreshA
Idempotent

Ask the collector to sync from iCampus now. Returns immediately; a sync takes about a minute. Limited to once every few minutes. Check sync_status afterwards.

Inputs: no named parameters.

sync_statusA
Read-only

When the data was last refreshed (per dataset), whether the last runs worked, and any login problem. Call this first if answers look stale or empty.

Inputs: no named parameters.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.9/5.0

    Scored across 8 tools

    Disambiguation4/5

    Most tools clearly target distinct resources: announcements, courses, tasks, lectures, grades, and sync status. The only mild overlap is list_tasks including lecture completion while list_lectures also reports completion, but their primary purposes are still distinguishable. refresh and sync_status are complementary rather than competing.

    Naming Consistency3/5

    The dominant list_* prefix creates a mostly readable pattern, and read_announcement and get_grades fit loosely within it. However, refresh and sync_status break the verb_noun style, and pluralization is inconsistent with list_announcements vs. read_announcement. The naming is understandable but not fully predictable.

    Tool Count5/5

    Eight tools is well within the ideal range for a campus portal integration. Each tool covers a distinct area—announcements, courses, tasks, lectures, grades, and sync—without redundancy or bloat.

    Completeness4/5

    The read-only scope is well covered: announcements have list/detail, the major coursework views have dedicated list endpoints, grades are exposed, and sync status is handled. Minor gaps exist such as no per-course detail or task/lecture detail endpoints, but common workflows around due work, lectures, and grades are fully supported.

    Maintenance

    ActivitySlowing
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      C
      maintenance
      Enables AI assistants to retrieve and work with Moscow Electronic School data, including schedules, homework, grades, rankings, school info, meals, passes, olympiads, and portfolio, via authenticated MCP tools.
      MIT
    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables AI assistants to read courses, upcoming deadlines, assignment details, grades, announcements, modules, files, inbox, and timetable from U of T Quercus and ACORN through read-only tools.
      1
      MIT
    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables AI assistants to browse your own university courses by downloading files, slides, announcements, deadlines, grades and lecture transcripts to your machine, then answering questions and searching across them through MCP tools. It logs in with your own account and refreshes only what changed.
      MIT