Skip to main content
Glama
README.md
## foreword
this is a proof of concept by claude and not suitable for production

-noah

# sio-mcp

Read-only MCP server over [CMU Student Information Online](https://s3.andrew.cmu.edu/sio/mpa/) (SIO), built as a thin wrapper around a reusable typed client library.

## Layout

```
src/sio_mcp/
  utils/session.py   auth: Playwright login (AndrewID + Duo), cookie persistence
  terms.py           term codes (F26 <-> fall-2026 <-> "Fall 2026")
  models.py          pydantic models; ISO dates, 24h times, decimal-string money
  parsers/           HTML parsers for SIO's server-rendered pages
  client.py          SIOClient: typed async API with TTL caching
  server.py          the MCP server (8 read-only tools)
  cli.py             `sio-login`
tests/fixtures/      real SIO page snapshots the parser tests run against
```

`SIOClient` is the reuse surface: the MCP server, a CLI, a cron job, or a RAG
ingestion script all call the same functions.

## Setup

```sh
uv sync
uv run sio-login   # AndrewID + password (env: ANDREW_ID/ANDREW_PASSWORD or prompts), approve the Duo push
```

Sessions expire on CMU's schedule; when a tool reports an authentication
error, re-run `sio-login`.

Register with Claude Code:

```sh
claude mcp add cmu-sio -- uv --directory /path/to/this/repo run sio-mcp
```

## Tools

| Tool | Returns |
|---|---|
| `get_student_context` | name, current term, class level, major, advisor, units |
| `get_schedule` | sections with days/times/rooms/instructors + add/drop deadlines |
| `get_schedule_ics` | official `.ics` export (authoritative semester dates) |
| `get_grades` | per-course grades + QPA for a semester |
| `get_advanced_placement` | AP/transfer credit and exam scores |
| `get_enrollment_status` | enrollment record for a semester |
| `get_account_activity` | student account ledger + balance |
| `get_campus_life` | housing assignment, Plaid Cash |

Conventions: times are `America/New_York` `HH:MM`; dates ISO `YYYY-MM-DD`;
money is a decimal string in USD (charges positive, payments/credits
negative); course codes are normalized to `15-122` form; `term` params accept
`F26`, `fall-2026`, or `Fall 2026`.

## Testing

```sh
uv run pytest
```

Parser tests run offline against `tests/fixtures/`. SIO redeploys weekly — if
a parser starts raising `UpstreamChangedError`, re-capture the page into the
fixtures and adjust.

## Non-goals (for now)

- **Writes.** Registration/drop actions live in SIO's legacy GWT app behind
  opaque GWT-RPC, and SIO explicitly warns that automated registration
  requests get access revoked. This server is deliberately read-only.
- The legacy `/sio/#...` app generally (invoices, pay-now, planning). The data
  worth reading is duplicated on the server-rendered pages this uses.

TDQS

A4.4/5.0

Scored across 8 tools

Disambiguation4/5

Each tool targets a distinct data domain (schedule, grades, billing, etc.), but get_student_context and get_enrollment_status overlap on class level, major, and advisor. The descriptions clarify when to use which, so confusion is unlikely.

Naming Consistency5/5

Every tool follows the exact same get_<domain> pattern with clear, descriptive nouns. This is perfectly consistent and predictable.

Tool Count5/5

Eight tools is well within the ideal range for a student data server. Each tool covers a meaningful data area without redundancy or bloat.

Completeness5/5

The server covers the full read-only student information surface: context, schedule, grades, credits, enrollment, billing, and campus life. No obvious missing queries for the stated purpose.

Maintenance

ActivityMaintained
ResponsivenessSyncing