Skip to main content
Glama
SamEthanMathew

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
```