unw-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@unw-mcp check my degree audit and what requirements I still need"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
unw-planner
A command-line and MCP client for planning courses at the University of
Northwestern – St. Paul. It signs in to UNW's Banner 9 Student Self-Service and
Ellucian Degree Works audit with an Entra ID + TOTP login, reads the degree
audit and course catalog, resolves remaining requirements against real sections,
checks time conflicts, and builds term or multi-term plans using Rate My
Professors ratings as a soft preference. The same domain layer is exposed as a
unwplanner CLI and a stdio MCP server for agent use.
This is an independent project. It is not affiliated with, endorsed by, or supported by the University of Northwestern, Ellucian, or Rate My Professors.
Requirements
Python 3.11+ (CI covers 3.11 and 3.12).
A UNW account with access to Banner 9 Student Self-Service and the Degree Works dashboard.
TOTP two-factor authentication. The login driver generates the current code from a shared secret. Push-notification-only accounts, or tenants that require number matching without a "use a verification code" fallback, cannot be automated.
Network access to
registration-ss.oci.unw.edu,degreeaudit.oci.unw.edu,login.microsoftonline.comandwww.ratemyprofessors.com.
Related MCP server: ewm-ops-mcp
One-command install
macOS / Linux:
curl -fsSL https://raw.githubusercontent.com/HenryGetz/unw-planner/main/bootstrap.sh | shWindows PowerShell:
irm https://raw.githubusercontent.com/HenryGetz/unw-planner/main/bootstrap.ps1 | iexThe bootstrap clones to ${UNW_PLANNER_HOME:-$HOME/.unw-planner} (or the
Windows equivalent), then runs the interactive installer. It attaches
/dev/tty to the setup prompts when available. In CI or another context with no
terminal, it refuses to start the interactive prompts and prints the checkout
alternative; use the non-interactive command below instead. It installs Python
dependencies and Playwright Chromium, writes .env, and optionally logs in.
If you prefer a checkout:
git clone https://github.com/HenryGetz/unw-planner.git
cd unw-planner
./install.sh # or: sh install.shAfter setup (from the project folder; Windows uses .venv\\Scripts\\unwplanner.exe):
.venv/bin/unwplanner advise --term 202620advise prints a shareable advising brief: remaining requirements, candidate
sections, a conflict-free draft and (with --roadmap) the multi-term plan. It
is name-free by default; --no-pii is accepted for scripts that want to be
explicit about it.
Non-interactive install (never logs in): pipe the password and provide the
other credentials; --no-login still writes .env:
printf '%s\n' "$UNW_PASS" | .venv/bin/unwplanner setup --yes --no-login \
--password-stdin --user "$UNW_USER" --totp-secret "$UNW_TOTP_SECRET"CLI
The current commands are listed below. Read-only planning commands beyond this
set (profile, remaining requirements, candidates, ratings, conflicts, draft,
roadmap, offering matrix) are available through the MCP server; see
docs/mcp.md. Every command reads the session written by
login; set UNW_AUTO_LOGIN=0 to guarantee no command starts a browser login.
command | what it does |
| Run the Entra ID + TOTP browser login and save the session state. |
| List Banner term codes and descriptions. |
| Search one term's sections. |
| List Banner Plan Ahead worksheets for one term (term-scoped). |
| Print the degree-audit groups, or all outstanding groups. |
| Build the one-shot advising brief from live data. |
| First-run wizard: install dependencies, write |
| Show registration time-ticket windows parsed from Banner's eligibility text (read-only). |
| Poll one term's eligibility and print changes (read-only). |
| Targeted registration run. Dry-run by default; |
| Create a plan worksheet. Writes to Banner. |
| Add one or more sections to a plan. Writes to Banner. |
| Delete a plan; without |
| Legacy raw plan dump; prefer |
MCP server
unw-mcp runs a stdio MCP server with 20 tools: session health, profile, audit,
remaining requirements, terms, search, course detail, candidates, RMP ratings,
conflicts, draft (with pins, minimum load and variable-credit hours), roadmap,
offering matrix, term-scoped plan operations, a read-only registration preview
and a read-only registration time-ticket window.
Plan writes are protected by enforced confirmation, not prose. The four write
tools require confirm: true; delete additionally requires confirm_name
equal to the plan's exact name. A call without them returns
refused: true, the intended effect and the current plan state, and performs no
write. Successful writes return a before/after diff read back from Banner.
Register it as a stdio server with an absolute path to <repo>/.venv/bin/unw-mcp
(<repo>\\.venv\\Scripts\\unw-mcp.exe on Windows). The shape is the same for
omp, Claude Desktop and Cursor:
{
"mcpServers": {
"unw-planner": {
"command": "/ABSOLUTE/PATH/TO/unw-planner/.venv/bin/unw-mcp",
"args": [],
"env": {"PYTHONUNBUFFERED": "1"}
}
}
}Config locations: ~/.omp/agent/mcp.json (omp), the Claude Desktop
claude_desktop_config.json, and ~/.cursor/mcp.json (Cursor). unwplanner setup --register-mcp merges this entry into the clients it finds; it preserves
other servers and backs up before writing. Restart the client after registering.
See docs/mcp.md for the tool table, real request/response
examples, error contract and session-recovery procedure.
What is verified vs unverified
area | status |
Entra ID + TOTP login, cookie replay, re-login | Verified live |
Term list, class search, section detail, term snapshots | Verified live (seven terms) |
Degree Works audit retrieval/parsing, profile, unmet requirements | Verified live |
Rate My Professors search and name matching (school 706) | Verified live; coverage varies by professor |
Conflict checking, draft, roadmap, offering matrix | Offline tests plus live snapshots |
Banner plan list/read and plan lifecycle | Verified live earlier on a throwaway plan |
MCP plan-write confirmation/refusal and add diff | Verified with a mocked Banner transport; not re-run against live plans |
Registration add/drop/register/withdraw | Unverified; deliberately not implemented |
Safety model
Credentials stay local.
UNW_USER,UNW_PASSandUNW_TOTP_SECRETlive only in.env(mode 600, gitignored). No code hardcodes them and no command prints them.The session state is a secret.
.state/unw_state.jsonis a replayable cookie jar for Banner, Entra ID and Degree Works. It is gitignored and must not be copied into tickets, chat or commits. Overwrite it withunwplanner login --forceif exposed.No registration writes by default. The MCP server never registers; only the explicit
unwplanner snipecommand can submit, and only with--liveplus--i-understandplus typing the exact term code on stdin. It is browser-driven, dry-run by default, never drops/withdraws, and has not been validated against a live registration window.windows/watchand the MCP registration preview are read-only.Plan writes are explicit. CLI plan writes require
--yes(and an exact typed plan name for deletes); MCP writes requireconfirm=trueand, for delete, the exactconfirm_name. They never run during read commands and never touch anything except Plan Ahead worksheets.Captures are never committed.
.state/,captures/,.venv/and caches are gitignored. Capture files may contain course data, screenshots or redacted request logs; keep them local.Be polite. The client reuses one session and caches term snapshots for 15 minutes. Do not run a second browser against the same session while an HTTP call is in flight; Banner invalidates the old session.
Known limitations
Registration is browser-driven and unverified. The direct add/drop endpoints were never observed, so
snipedrives the UI. It defaults to a dry run, requires explicit live authorization, and has not been executed against an eligible term. The MCP server has no registration write tool.Filtering is client-side. Banner ignores
txt_attribute,txt_instructor,chk_open_onlyand similar parameters on this deployment, so the server fetches a whole-term snapshot (cached for 15 minutes) and filters locally. Seat counts are a snapshot, not live guarantees.Plans are term-scoped and bounded. Plan Ahead only works for selectable terms; terms beyond Summer 2027 are visible in the catalog but cannot be planned. An empty plan list means "no plans for this term".
RMP coverage is thin. Many faculty have no Rate My Professors record or very few ratings. Unrated means unknown, not bad; n<3 is weak evidence.
Offering patterns are inferred. "Fall-only" or "every-term" comes from seven observed catalog terms, not a registrar guarantee.
Prerequisite parsing is heuristic. Banner's nested
and/orprerequisite text and grade/test clauses are parsed approximately; confirm with an advisor.One student per checkout. Settings and state are process-wide, not multi-user.
Porting
The tenant, Banner host, Degree Works host/screen code, RMP school id, term-code
convention, attribute vocabulary and login selectors are UNW-specific.
docs/porting.md lists every constant/function to change and
the tests to add. Contribution rules, including the fixture-scrubbing procedure,
are in CONTRIBUTING.md.
Repository layout
path | contents |
| Library: |
| Login, Banner API, audit, planning, RMP, MCP, porting and an index. |
| Login, probe, draft, advising artifacts, RMP probe and MCP smoke test. |
| Offline pytest suite, hermetic MCP stdio test and scrubbed fixtures. |
| Python 3.11/3.12 lint, tests and the hermetic MCP smoke. |
| Package metadata, dependencies, Ruff, coverage, pytest and entry points. |
Disclaimer
This is unofficial software. Use it only with your own account, at your own
risk. Course data, audit results and instructor ratings can be wrong or stale;
verify everything with your advisor and the official UNW systems before making
enrollment decisions. Respect the terms of service and rate limits of UNW,
Ellucian and Rate My Professors. The project is licensed under the MIT License
(see LICENSE).
Available Tools
20 toolsunw_auditB
Structured degree-audit requirement tree (groups -> blocks -> course
options, with applied/in-progress/transfer flags). group filters by a
case-insensitive substring of a group title/kind or block label.
Inputs: group.
unw_banner_plan_addA
Add a section (crn) or a course (subject+number) to a Banner plan (writes to Banner).
Confirmation is ENFORCED: confirm is required and must be true, otherwise
the tool names the exact section/course and current plan state and performs no
write. plan is an id or exact name; ambiguous names are rejected with
candidates. Successful writes return a before/after diff read back from Banner.
Inputs: plan (required), term (required), confirm (required), crn, +2 more.
unw_banner_plan_createA
Create a named Banner Plan Ahead worksheet for term (writes to Banner).
Confirmation is ENFORCED, not advisory: confirm is required and must be
true, otherwise the tool returns the intended effect and the current plan
count without writing. Verify the effect with the user first. The student may
hold at most five plans per term; names cannot be renamed later.
Inputs: name (required), term (required), confirm (required).
unw_banner_plan_deleteA
Delete an entire Banner plan (writes to Banner, irreversible).
Confirmation is ENFORCED twice: confirm must be true AND confirm_name
must equal the plan's exact name. Otherwise the tool reports the intended
deletion and current plan state and performs no write. Successful deletion
returns the removed plan, remaining plan count and a before/after diff read
back from Banner.
Inputs: plan (required), term (required), confirm (required), confirm_name (required).
unw_banner_plan_removeA
Remove one course row from a Banner plan (writes to Banner).
Confirmation is ENFORCED: confirm is required and must be true, otherwise
the tool names the exact row and projected credits and performs no write.
Identify the row by crn or subject+number; plan is an id or exact name.
Successful writes return a before/after diff read back from Banner.
Inputs: plan (required), term (required), confirm (required), crn, +2 more.
unw_banner_plansA
List the student's Banner Plan Ahead worksheets for one term. Plans are
TERM-SCOPED: this list only contains plans whose planHeader.term equals
term; an empty list means "no plans for THIS term", not "no plans exist"
(check other terms, and remember the session term must be bound).
Inputs: term (required).
unw_candidatesA
Resolve unmet requirements to sections offered in term (wraps the
catalog resolver). requirement matches an id, title, parent group or
target; omit it for every unmet requirement. Every empty result carries the
reason (never offered / all closed / already completed). limit caps
candidates per requirement (0=all); compact omits repeated section
detail. One requirement can be large, so prefer compact/limit for broad
queries.
Inputs: term (required), limit, compact, refresh, +2 more.
unw_conflictsB
Pairwise time conflicts for a CRN set, plus the ASCII week grid and the list of unscheduled (TBA/asynchronous) sections. Half-open intervals; linked lecture/lab pairs are exempt.
Inputs: crns (required), term (required), refresh.
unw_courseB
Full detail for one CRN: meetings, faculty with RMP evidence, attributes, catalog description, prerequisite/corequisite/restriction text plus the parsed prerequisite codes, linked lecture/lab CRNs, enrollment text and availability.
Inputs: crn (required), term (required), refresh.
unw_offering_matrixA
Offering pattern per course/attribute across every observed term: every-term, fall-only, spring-only, summer-only or never observed, with section counts, open counts and instructors per term. Accepts "CYS 4245", "ATTRIBUTE NATS" or "DAL *". Omit courses for every unmet requirement target. Use this before proposing a course for a future term.
Inputs: courses, refresh.
unw_plan_draftA
Draft a conflict-free term plan from the audit, prioritizing major-required courses, then major pools, then gen-ed by RMP rating.
required_crns/required_courses pin sections the student insists on;
each pin reports placed/unavailable/conflict/prereq_blocked/excluded/budget and
a failed pin makes ok=false. exclude_crns/exclude_courses remove
candidates. min_credits keeps filling elective pools until the load is met
(and reports min_credits_met). hours maps a CRN to the credit hours to
reserve for a variable-credit section (default: the low end). Pins apply to
this single-term draft only, not to unw_roadmap. include_summer=True also
drafts the following summer for requirements that did not fit.
Inputs: term (required), hours, latest, profile, +12 more.
unw_profileB
Student profile from Degree Works: name, id, classification, degree/school, catalog year(s), majors, minors, programs, college, advisors, credits earned and in progress, GPA, percent complete, anticipated graduation, academic standing and holds. Holds are not exposed by the mapped APIs: null = unknown.
Inputs: no named parameters.
unw_ratingsA
Batch Rate My Professors lookup. Accepts "Last, First" or "First Last".
Unrated professors return rating=null (never 0.0); weak_evidence flags n<3.
Cache entries expire after 7 days; refresh=True refetches now. Transient
RMP failures are never cached.
Inputs: names (required), refresh.
unw_register_previewA
DRY RUN ONLY: never posts add/drop/register. Returns Banner's real term
eligibility flags and failure text for term, then local checks for the
requested CRNs: seats/availability, time conflicts and prerequisites
(prereq_ok is null when unverified). If Banner reports the term as
ineligible, treat its failure text as the answer; never attempt real
registration.
Inputs: crns (required), term (required), refresh.
unw_registration_windowA
READ-ONLY registration time-ticket window(s). With term, returns that
term's window; without it, returns the configured current term and the next
selectable term. Each row carries Banner's verbatim eligibility failure text,
parse_status (parsed/no_ticket/not_eligible/unknown), America/Chicago
start/end, seconds until opening and a countdown. It NEVER registers, adds,
drops or withdraws; parse_status=unknown must be reported from raw_text.
Inputs: term.
unw_remainingA
Unmet requirements only: id, title, parent group, kind, credits remaining,
pick-N progress, course/attribute/wildcard options, status, priority class and
shared_title_with (other ids with the same title/options: double-counting
risk). This is the authoritative "what is left" list.
Inputs: no named parameters.
unw_roadmapA
Multi-term plan starting at start_term (default: the start term plus
three non-summer terms; summer only when include_summer). Carries requirements
and prerequisites forward, reports terms with no published catalog, and returns
graduation-risk notes against the audit's anticipated graduation term. Course
pins, minimum-load and instructor exclusions are draft-only: use
unw_plan_draft for those.
Inputs: start_term (required), terms, refresh, max_credits, +1 more.
unw_searchA
Search one term's sections (normalised rows: CRN, course, title, credits,
seats, days/times, faculty, attributes, availability). Banner ignores the
attribute/instructor/open-only query parameters, so filtering happens
client-side over a cached term snapshot. limit is capped at 200; when
limit_capped is true follow next_offset to page through the rest.
Inputs: term (required), limit, number, offset, +6 more.
unw_sessionA
Check the UNW session: authenticated (live check), degraded (state
exists but the live check failed), state-file age, cookie count and earliest
cookie expiry (values are never exposed), plus read_hint/write_hint
and the exact packaged CLI command that repairs an expired session. Call this
before any other tool. If unauthenticated but degraded, try one read tool
before asking for a login.
Inputs: no named parameters.
unw_termsA
Banner term codes with descriptions plus is_next, is_current, view_only and registration_eligible flags. Eligibility is probed through Banner's own mode=registration response (cached per process); refresh=True re-probes it. Failures are included verbatim.
Inputs: refresh.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 20 tools
Most tools target a clearly distinct resource or action, and the descriptions explicitly draw boundaries where overlap exists (unw_audit vs unw_remaining is 'authoritative what-is-left', unw_search vs unw_candidates is 'wraps the resolver', unw_plan_draft vs unw_roadmap is 'single-term with pins vs multi-term'). The remaining soft overlaps — unw_register_preview re-checking seats/conflicts/prereqs that unw_search and unw_conflicts already surface, and unw_banner_plans vs the local draft tools — are workable but could still cause misselection.
Nearly all names share the unw_ prefix and snake_case noun-oriented pattern, with the five banner_plan tools forming an internally consistent verb-suffixed cluster. Minor deviations: unw_search is the lone bare verb, unw_plan_draft uses a noun+noun order unlike its sibling unw_roadmap, and unw_register_preview vs unw_registration_window use different stems for the same domain.
Twenty tools is slightly above the comfortable range, but the surface spans several genuinely separate concerns (auth, audit, catalog search, RMP, drafting, Banner worksheet CRUD, registration checks), and each tool maps to a real operation. The only marginal additions are the near-paired audit/remaining and search/candidates tools.
The lifecycle is well covered: state check, profile, audit and unmet requirements, term catalog and course detail, candidate resolution, ratings, conflict checking, single- and multi-term planning, Banner worksheet create/add/remove/delete, and registration eligibility previews. The notable gap is that nothing ever performs a real add/drop/register or waitlist action — a deliberate safety boundary, but it leaves an agent at a dead end for the final registration step, and there is no schedule export.
Maintenance
Related MCP Connectors
Read-only checks for proposed orders against evidence and policy; no trading or payment authority.
Inspect outreach delivery, campaigns, leads and pipeline; prepare sequence drafts. Read-only.
Read-only CRE prospects, listings, campaigns, reporting, broker search, and resources.
Read-only agent-commerce audit, upgrade verification, diagnosis and x402 probing.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceEnables read-only inspection of Google Ads accounts through MCP, including account inventory, reporting, metadata, change history, and safe GAQL queries.Apache 2.0
- AlicenseNot gradedqualityCmaintenanceEnables warehouse operations agents to inspect tasks, deliveries, stock, and KPIs, and to attempt write operations in shadow mode with human approval and segregation of duties enforced as code.MIT
- FlicenseAqualityCmaintenanceEnables read-only interaction with CMU Student Information Online data, including student context, schedules, grades, enrollment, account activity, and campus life through MCP tools.8-
- FlicenseNot gradedqualityCmaintenanceEnables a study assistant to explain topics, build study plans, and generate revision checklists, with read-only access to course outline and status resources.-