You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Star0 (0)You must be signed in to star a repository
About
A Model Context Protocol + Skill for accessing UMD resources and similar sites, such as Testudo and Planet Terp, allowing students to utilize AI when interacting with the Schedule of Classes, ELMS, and more.
An MCP server exposing University of Maryland data: courses
and grades (PlanetTerp, Jupiterp, the Schedule of Classes, the Testudo student portal, ELMS),
dining menus and news, Shuttle-UM routes and timetables, athletics, the campus calendar, TerpLink
organizations and events, RecWell facilities and the ActiveTerp recreation portal, the University
Senate, and the campus directory.
Development
pnpm install
pnpm dev # run the server on stdio with hot reload
pnpm inspect # open the MCP Inspector against the dev server
pnpm test# run tests
pnpm check # typecheck + lint + format check + knip (dead code) + tests
pnpm build # emit dist/
Using with a client
Add to your MCP client config (e.g. Claude Desktop, Claude Code):
Some UMD services need a signed-in user. The login tool opens a browser window that umd-mcp
controls (Chrome or Edge, on its own profile under ~/.umd-mcp/browser-profile) at the UMD
Shibboleth IdP, with a CAS service URL pointing at a one-shot listener on 127.0.0.1. Once the
user finishes signing in (including Duo) the IdP redirects back with a service ticket, which the
server validates against serviceValidate to learn who signed in.
While that single sign-on session is fresh, login then visits every connected service (see
below) in the same window so each app can set its own session cookie, and copies those cookies
into a per-service Session. The window closes by itself. The profile persists, so later logins
are usually silent. logout forgets everything and clears the profile's cookies.
Why a browser: CAS only issues a ticket for the service named in the login URL, and each app
turns its ticket into a cookie for its own origin. The only way for the server to hold those
cookies is to be the browser that receives them.
The callback host is localtest.dev.umd.edu, a public DNS name UMD IT publishes that resolves
to 127.0.0.1. It is used instead of localhost because the IdP sits behind an AWS WAF that
rejects any service URL containing localhost with a 403.
Environment variables:
UMD_MCP_BROWSER: path to a Chromium executable, if Chrome or Edge are not installed.
UMD_MCP_PROFILE_DIR: where to keep the browser profile.
CANVAS_TOKEN: a Canvas personal access token (from ELMS profile settings). When set, the
ELMS tools use it as a bearer token and need no browser sign-in.
Tools
Tool names are <integration>_<method>, except the sign-in tools. Integrations marked
"(login)" need the login tool first, those marked "(optional login)" return more after it,
and the rest work anonymously.
shibboleth
Tool
Description
login
Sign in with a UMD Directory ID.
logout
Forget the signed-in user and every service session, and clear the sign-in browser so the next login prompts again.
whoami
Report the currently signed-in UMD user, or that nobody is signed in, and which services have a live session.
activeterp
Tool
Description
activeterp_list_program_filters
The classifications (e.g. Fitness, Aquatics, Esports) and tags (e.g. Adventure Trips) that activeterp.umd.edu programs are filed under.
activeterp_list_programs
Programs on activeterp.umd.edu (group fitness classes, swim lessons, adventure trips, clinics, camps, esports bookings) with their price, optionally within classifications or tags.
activeterp_search_programs
Search activeterp.umd.edu programs by name, as the site search bar does.
activeterp_get_program
One activeterp.umd.edu program: description, classification, price, whether a waiver is required, and how it is scheduled.
activeterp_list_program_offerings
An activeterp.umd.edu program's offerings in a semester: each dated session or series with its price, open spots, meeting pattern and cancelled dates.
activeterp_list_program_instances
An activeterp.umd.edu program's bookable time slots over the coming days: start and end, location, instructor, class size and open spots.
activeterp_list_facilities
Bookable facilities on activeterp.umd.edu (currently the Terps Esports Center stations) with their parent facility and blurb.
activeterp_get_facility
One activeterp.umd.edu facility: description, type, area, maximum occupancy and regular hours per weekday.
activeterp_get_facility_schedule
Bookings on the activeterp.umd.edu facility calendar in a date window, for one facility or all, with recurrence rules.
activeterp_list_calendars
The calendars the activeterp.umd.edu home page can show (e.g. Group Fitness Classes, Adventure Program).
activeterp_list_calendar_events
The activeterp.umd.edu home page calendar: every scheduled class, reservation slot and event over the next several days.
activeterp-member (login)
Tool
Description
activeterp_member_get_profile
The signed-in member's activeterp.umd.edu profile: name, University ID number, eligibility, date of birth, gender and contact details on file.
activeterp_member_list_my_memberships
The signed-in member's RecWell memberships, current and past: type, start and expiry dates, renewal terms and refund or cancellation status.
activeterp_member_get_access_history
The signed-in member's facility check-ins: facility, check-in station, entrance and exit devices, time, and whether access was granted.
activeterp_member_list_my_orders
The signed-in member's orders: order number, date, where it was placed, totals and whether it was voided.
activeterp_member_list_my_invoices
The signed-in member's invoices, all of them or only the unpaid ones: number, date, total, paid and owing amounts and a PDF link.
activeterp_member_get_invoice
One of the signed-in member's invoices: billing details, subtotal, tax, total, amount paid, outstanding balance and the line items.
activeterp_member_list_memberships
Memberships RecWell sells on activeterp.umd.edu (day passes, the free Group Fitness and Bouldering Zone memberships) with their blurb.
activeterp_member_get_membership
One membership RecWell sells with each purchasable term: name, billing, upfront price and the dates it would cover for the signed-in member.
activeterp_member_list_towel_services
Towel services RecWell sells on activeterp.umd.edu (semester and annual).
activeterp_member_get_towel_service
One towel service with each purchasable term: name, billing, upfront price and the dates it would cover for the signed-in member.
activeterp_member_list_multi_visit_passes
Multi-visit passes RecWell sells (personal training session packages, member visit passes) with their category list, price and any purchase requirement.
activeterp_member_get_multi_visit_pass
One multi-visit pass: category, price, full description and any purchase requirement.
athletics
Tool
Description
athletics_list_sports
Every varsity sport at Maryland (the Terps, umterps.com) with the ids the other athletics tools take.
athletics_list_seasons
Past and current seasons a sport has a schedule for, with the schedule id to pass to athletics_get_schedule for a past season.
athletics_get_schedule
A Maryland team's schedule and results: every game with date, time, opponent, venue, TV/streaming, and the score once played, plus the team's record.
athletics_get_game
One Maryland game by id (from athletics_get_schedule or athletics_get_calendar): opponent, venue, media links and result.
athletics_get_roster
A Maryland team's current roster: players with jersey number, position, class, height, weight, hometown and major, plus the coaching staff.
athletics_search_players
Find current and former Maryland athletes by last name, across all seasons on umterps.com, optionally within one sport.
athletics_get_coaches
A Maryland team's coaching staff with titles, email, phone and bio page links.
athletics_get_news
Latest Maryland Athletics news stories, newest first, optionally for one sport.
athletics_get_article
The full text of a Maryland Athletics news story (game recaps, previews, announcements) by story id.
athletics_get_calendar
Every Maryland game or event in a date range across all sports (or one sport), grouped by day, with opponents, venues, media links and results.
athletics_get_upcoming_events
A Maryland team's next few games with date, time, opponent, venue and where to watch.
calendar
Tool
Description
calendar_search_events
Events on the UMD campus calendar (calendar.umd.edu) in a date range, optionally narrowed by full-text query, event type, audience or featured status.
calendar_get_event
One event from the UMD campus calendar by id or slug, with its full description, location, contact and recurrence rule.
calendar_list_categories
The event-type, audience and status categories the UMD campus calendar files events under, with the slugs calendar_search_events accepts.
calendar_get_academic_calendar
The approved UMD semester calendars from the Office of the Provost: first and last day of classes, breaks, reading day, final exams, commencement and summer sessions for each academic year, several years ahead.
clarice
Tool
Description
clarice_search_events
Upcoming performances at The Clarice Smith Performing Arts Center (theclarice.umd.edu), optionally narrowed by title, genre, category or presenter.
clarice_get_event
One Clarice event by slug: description, every performance with its hall, prices, venue and seating, content advisories, and its ticketing id.
clarice-tickets
Tool
Description
clarice_tickets_list_events
Ticketed Clarice events (Spektrix) with a performance in a date range, optionally in one genre.
clarice_tickets_get_event
One ticketed Clarice event by ticketing id, with its description and first and last performance.
clarice_tickets_list_performances
Every performance of a ticketed Clarice event, with whether it is on sale or cancelled and its online sales window.
clarice_tickets_get_availability
Seats and wheelchair spaces still for sale at one Clarice performance, out of its capacity.
clarice_tickets_get_prices
Ticket prices at one Clarice performance by ticket type and seating section.
dining
Tool
Description
dining_get_busy_meter
Current crowd level (less, moderately or extremely busy) of the three UMD dining halls, from the service behind the "Dining Hall Status" page.
dining_get_calendar
Key dates for the current semester from UMD Dining Services: when dining plans go live, holiday and break hours, closures and Dining Dollar expiry.
dining_get_news
The newest posts on dining.umd.edu, mainly "The Dish" monthly newsletter, from its RSS feed.
directory (optional login)
Tool
Description
directory_search
Search the UMD campus directory for people by last name (prefix; "Pin*" wildcards work), full name, email address, Directory ID or phone number.
directory_search_advanced
Search the UMD campus directory by separate name parts, email, work phone, department, affiliation and institution.
directory_get_person
Look up one person in the UMD campus directory by Directory ID (the part of their email before @umd.edu).
elms (login)
Tool
Description
elms_whoami
The signed-in user as ELMS (Canvas) knows them: name, login id, email and time zone.
elms_list_courses
The signed-in student's courses on ELMS (Canvas) with term, instructors and current grade standing.
elms_get_course
One ELMS (Canvas) course with its syllabus, front page and the navigation tabs enabled for it, so you know which of assignments, modules, announcements, files or external tools (Zoom, Piazza, Gradescope) exist.
elms_list_assignments
Assignments in an ELMS (Canvas) course, ordered by due date, each with the signed-in student's submission status and score.
elms_get_submission
The signed-in student's submission for one ELMS (Canvas) assignment: status, score, grade and any instructor comments.
elms_get_grades
The signed-in student's current and final scores in every ELMS (Canvas) course they are enrolled in, or in one course.
elms_list_modules
The modules of an ELMS (Canvas) course with their items (assignments, files, pages, links) and completion state.
elms_list_announcements
Announcements posted in one or more ELMS (Canvas) courses within a date window (default: the last 14 days).
elms_get_todo
Assignments and classic quizzes the signed-in student still needs to submit, as ELMS (Canvas) lists them in the to-do sidebar.
elms_get_planner
Everything due or happening for the signed-in student across all ELMS (Canvas) courses in a date range (default: the next 14 days): assignments, quizzes, announcements, events and notes, with submission status.
elms_get_upcoming_events
Upcoming calendar events and assignment due dates across all ELMS (Canvas) courses, as the Canvas dashboard shows them.
elms_get_activity_stream
Recent activity across the signed-in student's active ELMS (Canvas) courses: new announcements, discussion posts, grades and messages.
elms_list_conversations
The signed-in student's ELMS (Canvas) Inbox: conversations with their subject, participants and last message.
elms_get_conversation
One ELMS (Canvas) Inbox conversation with every message in it.
go (login)
Tool
Description
go_list_links
The signed-in user's go.umd.edu short links across every collection they are in, newest first by default.
go_get_link
One of the signed-in user's go.umd.edu links with its stats page: destination, collection, note, click counts by hour, day and month, the busiest day and where clicks came from.
go_create_link
Create a go.umd.edu short link to a URL, with a chosen keyword or a generated one, in the personal space or one of the user's collections.
go_update_link
Change where one of the signed-in user's go.umd.edu links points, rename its keyword, move it to another collection or edit its note.
go_delete_link
Delete one of the signed-in user's go.umd.edu links.
go_get_qr_code
A PNG QR code that opens one of the signed-in user's go.umd.edu links.
go_list_collections
The collections the signed-in user is in on go.umd.edu, with how many links and members each has.
go_create_collection
Create a go.umd.edu collection with the signed-in user as its first member.
go_update_collection
Rename one of the signed-in user's go.umd.edu collections or change its description.
go_delete_collection
Delete one of the signed-in user's go.umd.edu collections (refused while it still has links).
go_list_collection_members
The people who can manage the links in one of the signed-in user's go.umd.edu collections.
go_add_collection_member
Give a UMD person access to one of the signed-in user's go.umd.edu collections, by Directory ID.
go_remove_collection_member
Take a person's access to one of the signed-in user's go.umd.edu collections away.
go_lookup_users
Find UMD people by name or Directory ID in go.umd.edu's own people search. No login needed.
go_list_transfer_requests
Pending offers to hand go.umd.edu links between people, to and from the signed-in user.
go_transfer_links
Offer some of the signed-in user's go.umd.edu links to another UMD person, who owns them once they accept.
go_accept_transfer_request
Accept links another person offered the signed-in user on go.umd.edu.
go_reject_transfer_request
Turn down links another person offered the signed-in user, or take back an offer the user made.
imleagues
Tool
Description
imleagues_list_leagues
UMD intramural sports this term on IMLeagues, with every league's registration status, sign-up deadlines and season dates.
imleagues_get_standings
Standings for a UMD intramural league on IMLeagues, for the whole league and within each division, plus the tiebreaker order.
imleagues_list_handbooks
Handbooks and manuals UMD Intramural Sports posts on IMLeagues, school-wide or for one sport.
imleagues-member (login)
Tool
Description
imleagues_member_list_my_teams
The signed-in member's UMD intramural teams on IMLeagues, with each team's captain.
imleagues_member_get_league
A UMD intramural league's rules, each division's time slot and remaining spots, and every team in each division with its roster size and captain.
imleagues_member_get_team
A UMD intramural team's league, division, record and scoring, its members' names and roles, and every regular season and playoff game with the result and venue.
imleagues_member_get_game
One UMD intramural game: when and where it is played, its status, both teams' records and standings, and the final and per-period scores.
jupiterp
Tool
Description
jupiterp_list_departments
Every four-letter department code on Jupiterp with its name.
jupiterp_list_courses
UMD courses from Jupiterp's scrape of the Schedule of Classes: title, credits, gen-eds, prerequisite and restriction notes and description.
jupiterp_list_sections
Sections of UMD courses in the current term from Jupiterp: instructors with their Jupiterp slugs, meeting days, times and rooms, and seat, waitlist and holdfile counts.
jupiterp_list_instructors
UMD instructors on Jupiterp with their average student rating (PlanetTerp and Jupiterp reviews blended) and the terms they have taught.
jupiterp_list_reviews
Approved student reviews of a UMD instructor on Jupiterp, including those imported from PlanetTerp.
jupiterp_get_grades
Grade distributions for individual UMD course sections from the Registrar's release on Jupiterp, fall and spring terms since Fall 2010.
jupiterp_get_grade_summary
Grade distributions on Jupiterp summed across sections: per course, per course and term, per course and instructor, per instructor, or per instructor and term.
jupiterp_list_grade_terms
Terms Jupiterp has grade data for, newest first, with section and course counts and the university-wide GPA.
maps
Tool
Description
maps_list_buildings
Buildings on the UMD campus map (maps.umd.edu) with the number and code Testudo uses for each, its class, category and location.
maps_get_building
One building on the UMD campus map by number or code: street address, gross and assignable square feet, ownership, years built and renovated, and occupants.
maps_list_parking_lots
Parking lots and garages on the UMD campus map with who each is for, when a permit is needed, the posted regulation, space and permit counts, and location.
maps_list_closures
Parking lot, parking garage and road closures posted on the UMD campus map, with what is closed, the dates and a link to the notice.
maps_list_amenities
All-gender or family restrooms, lactation rooms, showers, changing tables or elevators across campus, by building and room, from the UMD campus map.
maps_list_dining_locations
Dining halls with their stations, cafes, food courts with their vendors, restaurants, shops and the food pantry, from the UMD campus map.
maps_list_residence_halls
UMD residence halls with community, year built, layout, room sizes and kinds of shared bathroom, from the UMD campus map.
nutrition
Tool
Description
nutrition_get_menu
What a UMD dining hall is serving on a given day, by meal period and station, with allergens and dietary labels for each dish, from nutrition.umd.edu.
nutrition_get_recipe
The nutrition label for a dish on a UMD dining hall menu: serving size, calories, nutrition facts with daily values, ingredients and allergens.
planetterp
Tool
Description
planetterp_get_course
Look up a UMD course by its code on PlanetTerp.
planetterp_list_courses
List UMD courses on PlanetTerp in alphabetical order, optionally within one department.
planetterp_get_professor
Look up a UMD professor or teaching assistant by name on PlanetTerp.
planetterp_list_professors
List UMD professors and teaching assistants on PlanetTerp in alphabetical order.
planetterp_get_grades
Grade distributions from PlanetTerp for a course, a professor, or both, broken down by section.
planetterp_search
Search PlanetTerp for courses and professors whose code or name contains the query, as the site search bar does.
recwell
Tool
Description
recwell_get_facility_alerts
Current RecWell facility alerts: holiday and reduced hours, closures and protocol changes, as headed sections with any hours tables.
recwell_list_facilities
RecWell facilities with a one-paragraph description and link each, grouped as indoor or outdoor.
recwell_get_facility
A RecWell facility's page: description, regular hours of operation per season (one tab per semester, as tables), access rules, rental and parking information.
recwell_get_group_fitness_schedule
The weekly RecWell group fitness class schedule: class, location, instructor, start and end time and registration link, optionally for one weekday.
recwell_list_club_sports
Every RecWell club sport with its website, contact email and donation page.
senate
Tool
Description
senate_list_legislation
Bills before the University Senate (senate.umd.edu): the current academic year's legislation with where each bill stands and who is reviewing it, or the archive of past bills back to 2001.
senate_get_bill
One University Senate bill by id or document number: the proposal, sponsor, policy link, related bills, and every stage of its history with dates, decisions and the PDFs filed at each stage.
senate_list_senators
Current members of the University Senate with the seat, constituency, college and term end of each.
senate_get_constituent
How the University Senate files a member of the campus community, by UMD Directory ID: their college, department, title, population and constituency.
senate_list_committees
The University Senate's standing and special committees, the University councils it seats, and past councils and task forces, each with a one-paragraph summary.
senate_get_committee
One University Senate committee, University council, or past council or task force by name: its page as text (charge, chair, contact), current members with seats and colleges, and the bills it is reviewing.
senate_list_past_committee_legislation
Every bill each University Senate standing committee has reviewed, grouped by committee and academic year back to 2001.
senate_get_committee_meetings
A University Senate standing committee's meeting dates and times for an academic year, with the agendas posted for each.
senate_get_meetings
The University Senate meeting schedule for an academic year with the agenda, materials, slides and minutes posted for each meeting, and the years the archive covers.
terplink
Tool
Description
terplink_search_organizations
Search the roughly 1,000 active student organizations on TerpLink by name or keyword, optionally within categories from terplink_list_organization_categories.
terplink_get_organization
Full profile of one TerpLink student organization: description, email, type, primary contact, social links and mailing address.
terplink_list_organization_categories
The categories TerpLink files student organizations under (Academic, Cultural/Ethnic, Honor Society, ...).
terplink_search_events
Search TerpLink events by keyword, date range, hosting organization, category, theme or perk.
terplink_get_event
Full details of one TerpLink event: description, venue or meeting link, hosts, categories, perks and RSVP capacity.
terplink_list_event_categories
The categories TerpLink events are tagged with (Academic, Service, Sports and Recreation, ...).
terplink_get_news
News articles student organizations and departments post on TerpLink, newest first, optionally filtered by keyword or organization.
terplink_get_article
One TerpLink news article with its full body as plain text.
terplink_search_service_opportunities
Volunteer and community service opportunities listed for UMD students (mirrored from GivePulse), searchable by keyword.
testudo-soc
Tool
Description
testudo_soc_list_terms
Terms the UMD Schedule of Classes currently lists (about four: the current term plus the next few).
testudo_soc_list_departments
Departments (four-letter course prefixes) offering courses in a term, from the UMD Schedule of Classes.
testudo_soc_list_courses
Every course a department offers in a term, from the UMD Schedule of Classes: title, credits, grading methods, gen-ed codes, prerequisites and description.
testudo_soc_get_course
One course in a term from the UMD Schedule of Classes, with every section: instructors, seat counts, meeting days, times, rooms and delivery method.
testudo_soc_get_sections
Sections of one or more courses in a term, from the UMD Schedule of Classes: instructors, seat counts, meeting days, times, rooms and delivery method.
testudo_soc_search_courses
Search the UMD Schedule of Classes for a term the way its search form does.
testudo_soc_autocomplete_courses
Course ids and titles in a term whose id starts with the given text, from the UMD Schedule of Classes autocomplete.
testudo_soc_autocomplete_instructors
Instructors teaching in a term whose last or first name contains the given text, from the UMD Schedule of Classes autocomplete.
testudo_soc_list_gen_ed_categories
The general education categories and requirement codes (FSAW, DSHS, DVUP, ...) the UMD Schedule of Classes lists for a term.
testudo_soc_list_gen_ed_courses
Courses fulfilling one general education requirement in a term, from the UMD Schedule of Classes.
testudo_soc_list_syllabi
Past syllabi on file for a course in the UMD Schedule of Classes syllabus repository: the term and instructor of each.
testudo_soc_get_building
Look up a classroom building by the building code and room number a section lists: full name, campus building number and map links.
testudo (login)
Tool
Description
testudo_get_current_term
The current academic term at UMD with its registration status and key dates, from the Testudo student portal.
testudo_list_terms
Terms the signed-in student can use with a given Testudo feature: "schedule" lists terms with a class schedule (use with testudo_get_schedule), "grades" terms with posted grades, "enrollment_certification" terms an enrollment certification can be ordered for, "graduation" every term a graduation date can fall in, "graduation_application" terms open for a graduation application, and "grade_option" terms with an open pass/fail election window.
testudo_get_schedule
The signed-in student's class schedule for a term from the Testudo student portal: each registered section with its instructors, credits, delivery method and weekly meetings (days, times, building and room).
testudo_get_grades
The signed-in student's grades for a term from the Testudo student portal: final grades once posted, mid-term grades while the term runs, and the semester and cumulative GPA.
testudo_get_unofficial_transcript
The signed-in student's unofficial transcript from the Testudo student portal, as plain text: transfer credit, every past course with its grade, and current courses.
testudo_get_profile
The signed-in student's contact information on file with the university, from the Testudo student portal: name, email, phone numbers, local and permanent addresses and emergency contact.
testudo_get_registration_appointment
When the signed-in student may register for classes, from the Testudo student portal: the registration appointment for the upcoming term, any blocks on the account, and the majors, minors and certificates on record.
testudo_get_request_status
Status of the official transcript and enrollment certification orders the signed-in student has placed through the Testudo student portal, and any judicial or financial block that would stop new orders.
testudo_get_graduation_application_status
The signed-in student's graduation applications from the Testudo student portal: the term applied for, the diploma name and mailing address, and the status of each degree.
testudo_get_grade_options
The grading option (regular or pass/fail) the signed-in student has elected for each course in a term, from the Testudo student portal, with the pass/fail credit totals.
testudo_get_parent_access
Parent or guest accounts the signed-in student has granted access to their Testudo records.
transportation
Tool
Description
transportation_list_routes
Every Shuttle-UM bus route in the current timetable (regular routes such as 104 College Park Metro plus event routes), with whether each runs today, from the published GTFS feed.
transportation_get_route
One Shuttle-UM route with its stops in order (for the most common trip pattern on the given day) and the route polyline, from the published GTFS feed.
transportation_list_stops
Shuttle-UM bus stops from the published GTFS feed, filtered by a name fragment or by distance from a point.
transportation_get_stop
One Shuttle-UM bus stop with its location and every route that serves it, from the published GTFS feed.
transportation_get_schedule
Scheduled departures of a Shuttle-UM route on a date, optionally at one stop, from the published GTFS feed.
transportation_get_service_alerts
Current Shuttle-UM system updates and alerts (detours, schedule changes) and the modified-service notices linked from the DOTS schedules page.
transportation_get_service_calendar
The Shuttle-UM service calendar for the academic year: for each break, exam week and intersemester period, the dates and whether service is regular or modified, with the notice page for the detail.
Adding an integration
An integration is a folder under src/integrations/ that wraps one upstream and declares the
tools it contributes:
src/integrations/example/
index.ts # the Integration subclass, and nothing else
schemas.ts # input schemas, exported output schemas, and their inferred types
mappers.ts # Raw* types for the upstream payloads and the to*() functions (parsers.ts when scraping HTML)
An upstream with a public side and a signed-in side becomes two classes in sibling folders
(testudo/soc and testudo/portal, activeterp/catalog and activeterp/member), with
anything they share in a common.ts beside them.
Subclass Integration from src/integrations/base.ts, declare name and baseUrl, and mark
each tool method with @tool(). The MCP tool name is <name>_<method> (pass name in the
spec to override). Then add the class to createIntegrations() in src/integrations/index.ts.
import{z}from'zod';import{Integration,tool}from'../base.js';import{typeBuilding,buildingSchema}from'./schemas.js';exportclassExampleextendsIntegration{readonlyname='example';readonlybaseUrl='https://example.umd.edu/api';
@tool({title: 'Get campus building',description: 'Look up a campus building by its code. No login needed.',input: {code: z.string().describe('Building code, e.g. "IRB"')},output: buildingSchema.shape,})asyncget_building({ code }: {code: string}): Promise<Building>{returnthis.get<Building>(`buildings/${code}`);}}
Everything in the spec is advertised to the client so the model knows what a tool does, what
it takes, and what it returns before calling it:
description and title are passed through; annotations are merged over the defaults
(read-only, open-world).
input becomes the tool's inputSchema. The decorator checks at compile time that the
method's parameter type accepts the parsed shape.
output (optional) becomes the tool's outputSchema. The decorator checks at compile time
that the method returns a matching object. At runtime the value is validated against the
shape and returned both as structuredContent and as a JSON text block for clients that
only read text. Fields not in the shape are dropped.
Conventions the existing integrations follow:
.describe() every input and output field; the text ends up in the JSON Schema the model
reads. End descriptions with "No login needed." or "Requires login.".
Use z.enum wherever the upstream's value set is known, via a CODE: 'value' table and
decode() from src/common.ts, so an unexpected upstream value surfaces as a tool error.
Reuse the shared schemas in src/common.ts (term, courseId, sectionId, weekday,
isoDate, pagination, ...) and the helpers in src/lib/: text.ts (blank-to-null
trimming, joining), html.ts (HTML to plain text), scrape.ts (cheerio text, links and
tables), dates.ts (printed dates to YYYY-MM-DD). Reach for an npm package before writing
a parser by hand.
this.get(path, query) fetches JSON and this.getText() HTML relative to baseUrl;
this.postForm() and this.postJson() send what the site's own forms and scripts send, and
this.request() is the general form. A query value may be an array (the key repeats), and
every request times out after a minute. HTTP errors (with the server's own message when it
gives one), network failures and output-schema mismatches become tool error results
automatically; override handleError() to customise that.
An anonymous flow that still needs a server session (a search kept in the session, a token
tied to a cookie) overrides fetcher with cookieFetcher() from src/lib/http.ts. A value
read once per signed-in session (a CSRF token, an account id) goes through perSession()
from src/lib/session.ts.
Integrations behind single sign-on
If the upstream needs a UMD login, declare a service on the integration. login then signs
in to it along with everything else, and this.get() / this.getText() / this.request()
carry the app's cookies. Before the user signs in, or after the app rejects the session, they
throw AuthRequiredError, which becomes a tool error telling the model to call login.
exportclassStudentPortalextendsIntegration{readonlyname='testudo';readonlybaseUrl='https://app.testudo.umd.edu/services';overridereadonlyservice={name: 'testudo',// Page that sends an anonymous browser through single sign-on and back into the app.loginUrl: 'https://app.testudo.umd.edu/main/',// Optional: when the browser counts as signed in. Default is "same origin as loginUrl".signedIn: (url: URL)=>url.hash.startsWith('#/main'),// Optional: fields to POST to loginUrl for apps whose sign-in is a button, not a redirect.// loginForm: { login: 'Log in' },// Optional: a button to click on loginUrl when its form carries a per-page token the// browser must send (an anti-forgery token, a provider field).// loginClick: 'button.btn-sso-shibboleth',// Optional: when a response means the session is gone. Default: 401, or a redirect off// the app's origin or to signInPage.// expired: (response, requested, landed) => response.status === 403 || landed.pathname === '/expired',// Optional: the app's own sign-in page, for apps that bounce an expired session there// (same origin, HTTP 200) instead of answering 401 or redirecting to the IdP.// signInPage: (url: URL) => url.pathname === '/shortener/signin',};}
Project layout
src/
index.ts # stdio entrypoint
server.ts # createServer(): registers every integration
common.ts # shared zod schemas and small helpers (terms, course ids, weekdays, enums)
lib/ # HTTP helper, sign-in hub (auth.ts), per-service Session, browser driver,
# text/HTML/scraping helpers
integrations/
base.ts # Integration base class, @tool decorator, result helpers
index.ts # createIntegrations(): instantiate integrations here
<name>/ # one folder per integration (see above)
testudo/soc/ # public Schedule of Classes
testudo/portal/ # student portal (login)
grouper/NOTES.md # research only; Grouper is VPN-only and not implemented
About
A Model Context Protocol + Skill for accessing UMD resources and similar sites, such as Testudo and Planet Terp, allowing students to utilize AI when interacting with the Schedule of Classes, ELMS, and more.