cmucourses-connector
README.md
# CMU Courses — Claude Connector
A remote **MCP connector** that gives Claude live, structured access to **CMU Courses** public data so it can help students plan schedules with accurate course info: courses, units, descriptions, prerequisites/corequisites/crosslists, requisite trees, offered schedules (times, instructors, locations), instructor teaching history, gen-eds, and final-exam times.
- **Read-only** wrapper of the existing CMU Courses public API — it does **not** modify or run any part of the CMU Courses codebase.
- **Stateless**, **authless**, deployed to **Cloudflare Workers** (Streamable HTTP, MCP).
- Backend: `https://course.apis.scottylabs.org` (the live ScottyLabs course backend).
> **FCE (course evaluations / workload / ratings) is not included** in this version. That data is sign-in-gated behind Clerk, and a remote connector can't reach a user's browser session. See `src/auth/authProvider.ts` for the deferred design.
## Tools
| Tool | What it does |
|---|---|
| `search_courses` | Keyword + filter search (department, level, units, semester); paginated 10/page |
| `get_course` | Full details for one course by ID (optionally with schedules) |
| `get_courses` | Batch details for several courses |
| `get_requisites` | Prereqs (with AND/OR relation groups) + postreqs for a course |
| `get_course_schedules` | Offered lectures/sections for course(s): days, times, instructors, locations |
| `get_instructor_schedules` | Courses/semesters an instructor teaches |
| `find_courses` | Resolve a partial name/ID to matching courses (lightweight lookup) |
| `find_instructors` | Resolve a partial instructor name |
| `get_geneds` | Gen-ed-eligible courses for a school (SCS/CIT/MCS/Dietrich) |
| `get_finals` | Final-exam day/time/location (bundled per-semester snapshot) |
| `list_departments` | Department name ↔ short name ↔ number-prefix map |
## Develop
```bash
npm install
npm run typecheck # tsc --noEmit
npm test # unit tests (mocked backend) — 38 tests
npm run test:integration # live contract tests against the real backend
npm run dev # wrangler dev on http://127.0.0.1:8787/mcp
```
Drive it locally with the MCP Inspector:
```bash
npm run inspector # then connect to http://127.0.0.1:8787/mcp (transport: Streamable HTTP)
```
Or with Claude Code:
```bash
claude mcp add --transport http cmucourses http://127.0.0.1:8787/mcp
```
Stress test (mixed tools, live backend):
```bash
node scripts/stress.mjs http://127.0.0.1:8787/mcp 50 200
```
## Deploy (Cloudflare Workers)
```bash
npx wrangler login # one-time, uses your Cloudflare account
npx wrangler deploy # -> https://cmucourses-connector.<your-subdomain>.workers.dev
```
The backend URL is set in `wrangler.jsonc` (`vars.CMU_COURSES_BACKEND_URL`) and can be overridden per environment. An optional KV cache for the large `/courses/all` and `/instructors` lists is documented (commented) in `wrangler.jsonc`; the connector also caches these in-isolate by default, so KV is optional.
## Register in Claude
**Live deployment:** `https://cmucourses-connector.samethanmathew.workers.dev/mcp`
1. **Settings → Connectors → Add custom connector**.
2. Paste the URL above (note the `/mcp` path).
3. No login is required (public data). The tools appear immediately.
## Maintaining the finals snapshot
`src/reference/finals.snapshot.json` is a per-semester copy of the CMU Courses finals data (currently **Fall 2025**). When the semester changes, replace it from `cmucourses/apps/frontend/src/components/finals/finals.json` and update `SEMESTER_LABEL` in `src/tools/finals.ts`.
## Layout
```
src/
index.ts Worker entry + createServer()
mcp/ Minimal MCP server (JSON-RPC) + Streamable-HTTP transport
backend/ CMU Courses API client (encoding, normalization, retries, cache)
tools/ One module per tool group
reference/ Departments, gened schools, day map, finals snapshot
auth/ Deferred FCE seam (not wired in v1)
test/ Unit + live integration/contract tests
scripts/stress.mjs Concurrency load test
docs/EVALS.md Golden-answer eval prompts
```
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues