Skip to main content

UofT Timetable Builder MCP

A small Python MCP server for the public UofT Timetable Builder API. It exposes seven course-lookup tools over local stdio using the official MCP Python SDK.

No API key, database, web server, or environment variables are required. This is an unofficial wrapper; it does not enroll students, build schedules, or save timetables.

Connect an MCP Client

Install uv, then add this configuration to any client that supports mcpServers:

{
  "mcpServers": {
    "uoft-timetable": {
      "command": "uvx",
      "args": ["uoft-mcp@latest"],
      "env": {
        "UV_HTTP_TIMEOUT": "300"
      }
    }
  }
}

Restart the client after saving its configuration. On Windows, if the client cannot find uvx, restart it after installing uv or replace "uvx" with the absolute path reported by where.exe uvx.

uvx downloads the published package into an isolated environment and starts the uoft-mcp command. No repository clone, virtual environment setup, API key, server URL, or listening port is needed. The first start can take longer while uv downloads Python and the dependencies; later starts use its cache.

To pin a release instead of following the newest release, use "args": ["uoft-mcp==0.1.0"].

Local Development

From a clone of this repository:

uv python install 3.13
uv sync --locked --managed-python

uv sync creates .venv, installs the package and development tools, and uses the committed uv.lock. .python-version selects Python 3.13; the package supports Python 3.13 and newer.

Run the local checkout with:

uv run --locked python -m uoft_mcp

The installed uoft-mcp command is another entry point. The process waits for an MCP client on stdin; a blank terminal is expected. Use Ctrl+C to stop a manual run. Stdout carries protocol messages only, and logging goes to stderr.

Tools

Tool Arguments and purpose
get_current_sessions No arguments. Get current session IDs; skip entries with header: true.
get_reference_data No arguments. Get campus, division, delivery-mode, and sorting values.
get_divisions No arguments. List recognized faculty/division codes.
search_departments Required term keyword and divisions code.
search_course_titles Required term, divisions, and sessions strings. Optional lower_threshold=50, upper_threshold=200.
get_course_details Required course_code; optional section_code of F, S, or Y.
search_courses Optional code/title, section, description, division, session, campus, delivery, and pagination filters.

Each successful tool returns one text block containing the complete upstream JSON. The wrapper preserves fields and arrays, including upstream payload and status envelopes. It does not summarize, truncate, or reshape course data.

Example Workflow

  1. Call get_current_sessions with {} and select a non-header entry's value.
  2. Call get_divisions or get_reference_data for valid filter codes.
  3. Call search_course_titles with these arguments, substituting the session value:
{"term": "CSC108", "divisions": "ARTSC", "sessions": "SESSION_ID_FROM_STEP_1"}
  1. Use the returned exact course code in get_course_details:
{"course_code": "CSC108H1", "section_code": "F"}
  1. For filtered, paginated results, call search_courses:
{
  "course_code": "CSC108H1",
  "divisions": ["ARTSC"],
  "sessions": ["SESSION_ID_FROM_STEP_1"],
  "page": 1,
  "page_size": 2
}

search_courses also accepts course_title, course_section_code, search_course_description, campuses, delivery_modes, and direction (asc or desc). Pages start at 1, page size defaults to 20, and sorting defaults to asc. Omitted collection filters become empty arrays. Course codes should be exact; use autocomplete for prefixes or course_title for keyword searches.

Checks

uv run --locked pytest -q
uv run --locked ruff check .
uv run --locked ruff format --check .

The tests run offline. They cover all seven tools, request mapping, raw JSON preservation, validation, HTTP errors, timeouts, connection errors, invalid JSON, shared-client cleanup, MCP discovery, and actual stdio subprocesses.

Initial verification: 33 tests passed, and all seven tools returned successful live responses from UofT, including an exact-code search with page_size=2. Live requests are deliberately not part of the test suite, so tests remain reproducible.

API Notes

  • The supplied timetable_builder.json remains the original reference. Live checks found two missing details: pagination starts at 1, and paginated search requires an empty departmentProps array when not filtering by department. The wrapper supplies it.
  • Get division codes from the API. For example, the live API uses ERIN and SCAR for Mississauga and Scarborough, rather than the reference's UTM and UTSC examples.
  • Even one course can have a large response because all its sections are included. Choose narrow filters and small page sizes. The wrapper never fetches extra pages.
  • HTTP failures become MCP tool errors containing the endpoint and status code. UofT may return HTTP 404 for no matching courses. Timeouts, connection failures, and malformed JSON get their own readable errors. No automatic retries occur.
  • This API is not covered by an official support guarantee. Changes upstream may require updating the mappings. Successful HTTP responses are preserved as supplied, including any application-level status messages inside their JSON.

For a walkthrough of the code and how to extend it, read EXPLAINED.md.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

uoft_mcp-0.1.0.tar.gz (49.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

uoft_mcp-0.1.0-py3-none-any.whl (8.9 kB view details)

Uploaded Python 3

File details

Details for the file uoft_mcp-0.1.0.tar.gz.

File metadata

  • Download URL: uoft_mcp-0.1.0.tar.gz
  • Upload date:
  • Size: 49.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for uoft_mcp-0.1.0.tar.gz
Algorithm Hash digest
SHA256 bf3cca0c6fb65f05612e1b5e8a62b6e6c60da302a3f79e6eb1ba3c7ccd8f276f
MD5 0a97f81ca6957a0203ca199f093d945c
BLAKE2b-256 050cfb123811e6d52a9a358562388e8e4111e0a82853f0ab955fae17306c4f07

See more details on using hashes here.

File details

Details for the file uoft_mcp-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: uoft_mcp-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 8.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for uoft_mcp-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 693b1842fe1c11f21adc97fa1ff3b3541f6367c2828ca6f9c26086a5f54390d3
MD5 934aeacd213e13d8552511e1c13d699f
BLAKE2b-256 4832ebd6c3e1cdb1aa46179ed9c09d2cc9bd35c586daeab99ff8d4eb4f82662e

See more details on using hashes here.

Release history Release notifications | RSS feed

0.4.0

2 files

0.3.2

2 files

0.3.1

2 files

0.3.0

2 files

0.2.0

2 files

This release

0.1.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page