UofT Timetable Builder MCP
Click on "Install 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., "@UofT Timetable Builder MCPbuild a conflict-free CSC108 and MAT137 schedule, mornings preferred"
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.
UofT Timetable Builder MCP
A small Python MCP server for the public UofT Timetable Builder API. It exposes ten tools over local stdio using the official MCP Python SDK: seven course-lookup tools, a schedule solver wrapper, and share save/retrieve tools.
No API key, database, web server, or environment variables are required. This is an unofficial wrapper; it does not enroll students or write to ACORN. Saving a timetable creates an anonymous public share link on the Timetable Builder, not a personal account record.
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.2.0"].
Related MCP server: LettuceMeet MCP
Local Development
From a clone of this repository:
uv python install 3.13
uv sync --locked --managed-pythonuv 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_mcpThe 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 |
| No arguments. Get current session IDs; skip entries with |
| No arguments. Get campus, division, delivery-mode, and sorting values. |
| No arguments. List recognized faculty/division codes. |
| Required |
| Required |
| Required |
| Optional code/title, section, description, division, session, campus, delivery, and pagination filters. |
| Required |
| Required |
| Required |
Each successful lookup, generation, and retrieve call 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 or
truncate course data. save_timetable keeps the upstream share object and adds
share_url.
Example Workflow
Call
get_current_sessionswith{}and select a non-header entry'svalue.Call
get_divisionsorget_reference_datafor valid filter codes.Call
search_course_titleswith these arguments, substituting the session value:
{"term": "CSC108", "divisions": "ARTSC", "sessions": "SESSION_ID_FROM_STEP_1"}Use the returned exact course code in
get_course_details:
{"course_code": "CSC108H1", "section_code": "F"}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.
Copy each selected offering's
idfromget_course_detailsintogenerate_timetable. Activity types are the section types to fill, such asLecture,Tutorial, orPractical. Preference defaults tobalanced. Optional blocked intervals use weekday names and 24-hourHH:MMtimes:
{
"plans": [
{
"courses": [
{
"course_id": "COURSE_ID_FROM_STEP_4",
"activity_types": ["Lecture", "Tutorial"]
}
],
"preference": "early",
"blocked_times": [{"day": "Monday", "start": "8:00", "end": "10:00"}]
}
]
}Use one plan per term. A Fall and Winter year is two plans. The solver returns chosen sections; it does not enroll students.
Store a Timetable Builder state with
save_timetable. Thetimetableobject must includesessions,timetables, andplansin the frontend's serialized shape. The tool returnsidandshare_url(https://ttb.utoronto.ca/#!/?t=...).Reload that share later with
retrieve_timetable:
{"share_id": "SHARE_ID_FROM_STEP_7"}Checks
uv run --locked pytest -q
uv run --locked ruff check .
uv run --locked ruff format --check .The tests run offline. They cover all ten tools, request mapping, raw JSON preservation, validation, HTTP errors, timeouts, connection errors, invalid JSON, shared-client cleanup, MCP discovery, and actual stdio subprocesses.
Verification: 50 tests passed. Live checks of lookup, generateYear, tiny/shorten,
and tiny/retrieve succeeded, including generating CSC258H1 and CSC311H1, saving an
anonymous share, and retrieving that share. 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
departmentPropsarray when not filtering by department. The wrapper supplies it.generateYearaccepts an array of plans. Each plan needs courseidvalues fromget_course_details,sectionswithname: "*"and a type,fitnessFunctionOption(MORNING_WEIGHTED,BALANCED, orAFTERNOON_WEIGHTED), andblockedOffintervals using weekday numbers 1-5 (Monday-Friday) and milliseconds since midnight.tiny/shortenstores the officialhttps://ttb.utoronto.ca/#!/?URL for a serialized timetable and returns{ "id": "..." }.tiny/retrieve?id=loads it. These are anonymous share records, not ACORN enrolment.Get division codes from the API. For example, the live API uses
ERINandSCARfor Mississauga and Scarborough, rather than the reference'sUTMandUTSCexamples.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.
Available Tools
10 toolsgenerate_timetableARead-onlyIdempotent
Ask UofT's solver for conflict-free lecture, tutorial, and practical sections.
Each plan is one term. course_id values come from get_course_details. activity_types are the section types to fill, such as Lecture, Tutorial, or Practical. preference may be early, balanced, or late. Optional blocked_times use weekday names and 24-hour HH:MM clock times. This does not enroll students or write an ACORN timetable.
| Name | Required | Description | Default |
|---|---|---|---|
| plans | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive), and the description usefully reinforces that this is a planning-only operation that neither enrolls nor writes an ACORN timetable. It adds solver semantics and the one-plan-per-term grouping, but says nothing about how a result is shaped or any limits on plan size.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Roughly five sentences, each carrying distinct information: purpose first, then per-field meaning, then the negative scope caveat. No filler or restated title.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-argument tool with no output schema and clear annotations, the description covers purpose, inputs, and what it does not do. It is slightly thin on what the returned plans actually contain (sections, times, identifiers), which is the one thing only the description could supply.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With only one top-level parameter and low coverage in the reported schema descriptions, the description compensates well: it explains that each plan maps to one term, that activity_types are section types (Lecture/Tutorial/Practical), that preference is early/balanced/late, and that blocked_times use weekday names with 24-hour HH:MM values. Some of this restates schema enums/patterns, but the grouping and clock-format meaning go beyond the raw schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: asks the university's solver for conflict-free lecture, tutorial and practical sections. It also carves out a clear boundary against siblings ('This does not enroll students or write an ACORN timetable'), which separates it from save_timetable and retrieve_timetable without opening their schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit input dependency ('course_id values come from get_course_details') and a negative scope statement ruling out enrollment/timetable writing. It stops short of naming save_timetable as the follow-up step for persisting a generated plan, so the alternative is implied rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_course_detailsARead-onlyIdempotent
Get a full course code's sections, meetings, rooms, and instructors.
For example, course_code is CSC108H1. Optionally filter by F, S, or Y. This endpoint has no session parameter in the supplied API reference. Use the returned course id with generate_timetable.
| Name | Required | Description | Default |
|---|---|---|---|
| course_code | Yes | ||
| section_code | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, so the safety profile is covered. The description adds genuinely new context: the note that this endpoint has no session parameter, and the id-chaining hint toward generate_timetable.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the primary purpose, then example, filter, and downstream usage in short lines. The 'no session parameter in the supplied API reference' sentence is slightly meta but earns its place by preventing a wrong assumption.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, so the description's enumeration of returned fields (sections, meetings, rooms, instructors) is necessary and present. Coverage of error/empty-result behavior is absent but not critical for a read-only detail lookup.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must carry the load, and it does add value: a concrete course_code example (CSC108H1) and an explanation of the section_code filter. It does not spell out the pattern constraint (^[A-Za-z0-9]+$) that the schema enforces.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Get) and resource (course code's sections, meetings, rooms, instructors), and names the returned entities, which cleanly separates it from search_courses/search_course_titles lookups.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an example input (CSC108H1), clarifies the optional F/S/Y filter, and points to the downstream tool (generate_timetable) that consumes the returned course id. It lacks explicit when-not-to-use guidance versus search_courses, so it stops short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_current_sessionsARead-onlyIdempotent
Get active academic sessions. Use non-header entries' values as session IDs.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, so safety behavior is covered. The description adds useful context beyond annotations: it filters to active sessions only and explains that session IDs come from non-header entries' values.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with the core purpose front-loaded. The second sentence adds a concrete usage instruction without any filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 0-parameter read tool with no output schema, the description covers what the tool returns only partially. Saying to use non-header entries' values as session IDs gives some actionable guidance, but it does not describe the full return structure or entry format.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There are zero input parameters, so parameter semantics are not applicable and the baseline is 4. The description appropriately focuses on the output usage rather than inventing parameter details.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a clear verb and resource: 'Get active academic sessions.' It scopes the result to active sessions, which distinguishes it from a general reference-data or search tool. However, it does not explicitly contrast itself with any sibling tool, so it stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the scope: call this to obtain active academic sessions. The second sentence adds an instruction for using the returned values as session IDs, but there is no explicit when-to-use or when-not-to-use guidance versus alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_divisionsARead-onlyIdempotent
List faculty/division codes; use returned values rather than campus abbreviations.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint and destructiveHint=false, so the safety profile is covered. The description adds only the semantic caveat about preferring these codes over campus abbreviations, and says nothing about return shape or volume. With annotations carrying the behavioral load, a 3 is appropriate.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single semicolon-joined sentence with the action first and the usage caveat second. No filler and nothing buried.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-argument, non-destructive lookup with no output schema, the description is nearly sufficient: it says what is listed and how to use the values. It could note that the result is a code/name mapping, but nothing essential to calling it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to disambiguate and the baseline of 4 applies. No parameter behavior is misstated.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource: it lists faculty/division codes. An agent can tell it returns a code list rather than records. It does not name or distinguish itself from the nearest sibling (get_reference_data), so it falls short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The clause 'use returned values rather than campus abbreviations' gives one concrete usage rule, implying this is the lookup to run before supplying a division code elsewhere. It names no alternative tool and gives no when-not-to-use condition, so guidance is implied rather than explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_reference_dataARead-onlyIdempotent
Get division, campus, delivery-mode, and sorting reference values.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, so the safety profile is covered. The description adds that the tool surfaces four specific reference categories, but says nothing about return shape, caching, or how values are keyed. Slight added value over annotations-only, but modest.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence that enumerates the four value categories with no padding or repetition. Every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no input parameters, no output schema, and safety covered by annotations, the description's main job is to convey what the caller receives, which it does by naming the four reference sets. It would be stronger if it indicated the return structure or clarified the overlap with get_divisions.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is no parameter semantics to document; the baseline for a parameterless tool is 4. The description correctly implies no filtering input is required.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb ('Get') and resource ('reference data') and enumerates exactly which reference sets are returned (division, campus, delivery-mode, sorting). That is more informative than a tautology. However, it does not differentiate itself from the sibling get_divisions, which appears to overlap with the 'division' reference values it claims to return.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no guidance on when to call this tool versus alternatives, nor any mention of prerequisites or the overlapping get_divisions sibling. Usage must be inferred entirely from the noun phrase.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
retrieve_timetableARead-onlyIdempotent
Load a previously saved Timetable Builder state by its public share id.
| Name | Required | Description | Default |
|---|---|---|---|
| share_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint and destructiveHint=false, so safety and repeatability are covered. The description adds useful context about the state being previously saved and publicly shared (implying no mutation and no auth-scoped access), but says nothing about what is returned or error behavior for invalid ids.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One sentence, front-loaded with the verb and scoped by the parameter, with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter read tool with no output schema and annotations covering the safety profile, the description gives enough to invoke it correctly. A note on the source of the share id (e.g., returned by save_timetable) would make it fully complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% (only a pattern and minLength), so the description carries the burden; it explains that the single parameter is a 'public share id', giving semantic meaning beyond the bare format constraints. It omits where such an id comes from (presumably save_timetable).
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb ('Load') plus resource ('previously saved Timetable Builder state') and an explicit identifying parameter ('public share id'). It is distinguishable from save_timetable/generate_timetable, though it does not explicitly contrast with get_current_sessions.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'previously saved' implies the tool is for restoring an existing state when a share id is known, but there is no explicit when-to-use guidance, prerequisites, or named alternative such as get_current_sessions for live state.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
save_timetableA
Store a serialized Timetable Builder state and return a public share URL.
timetable must be the TTB state object with sessions, timetables, and plans. The wrapper posts the official ttb.utoronto.ca URL for that state and returns the upstream share id plus a https://ttb.utoronto.ca/#!/?t= link. This creates an anonymous share record only; it does not enroll students.
| Name | Required | Description | Default |
|---|---|---|---|
| timetable | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds real context beyond the annotations: it discloses that the wrapper posts to the upstream ttb.utoronto.ca service, returns an upstream share id and a share link, and that only an anonymous share record is created. It does not mention that repeated saves create duplicate records, which the non-idempotent annotation hints at but the prose never confirms.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and return value, then the parameter requirement, then scope caveats. It is slightly wordy about the upstream URL mechanics, but every sentence contributes to correct invocation.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description correctly documents the return shape (upstream share id plus an https://ttb.utoronto.ca/#!/?t= link). Annotations already cover the safety profile (write, non-idempotent, non-destructive), so remaining gaps are minor, e.g. behavior on repeated saves.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0% and the single parameter is an unconstrained nested object (additionalProperties: true), so the description carries the burden. It does so well by specifying that "timetable" must be the TTB state object containing sessions, timetables, and plans, giving the agent the shape the empty schema omits.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: it stores a serialized Timetable Builder state and returns a public share URL. That verb (store/save) plus the share-URL return clearly separates it from siblings like generate_timetable and retrieve_timetable, which produce or fetch rather than persist.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It clarifies one boundary explicitly ("creates an anonymous share record only; it does not enroll students"), which tells the agent this is not an enrollment action. However, it never says when to prefer this over siblings such as retrieve_timetable or what precondition the state must come from, so usage is only implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_coursesARead-onlyIdempotent
Search one page of courses using optional code/title and reference-code filters.
Page numbering starts at one; page_size defaults to 20. Get session IDs from get_current_sessions and other filter codes from get_reference_data. Use an exact course_code from autocomplete; use course_title for keywords. Sorting defaults to asc. No automatic pagination is performed.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | ||
| campuses | No | ||
| sessions | No | ||
| direction | No | asc | |
| divisions | No | ||
| page_size | No | ||
| course_code | No | ||
| course_title | No | ||
| delivery_modes | No | ||
| course_section_code | No | ||
| search_course_description | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish read-only, idempotent, non-destructive behavior, so the description is free to add operational context — and it does: page numbering starts at one, page_size defaults to 20, sort direction defaults to asc, and critically that no automatic pagination is performed. That last point materially changes how an agent must loop, which is real value beyond the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Tight and front-loaded: the primary action leads, then pagination mechanics, then data-source pointers, then parameter usage notes. Every sentence carries information, with only minor redundancy in the paging statements.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 11-parameter tool with zero schema documentation and no output schema, the description covers pagination and the two text filters well but leaves most reference-code filters opaque. Pointing to get_reference_data mitigates but does not close the gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% across 11 parameters, so the description must compensate. It documents page, page_size, course_code, course_title, and the sort default, and points to get_reference_data for filter codes, but campuses, sessions, divisions, delivery_modes, course_section_code, and search_course_description are never explained in either place.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Search one page of courses') and immediately scopes the result set with the filter types (code/title and reference-code). The 'one page' framing plus filter list differentiates it from content-oriented siblings like search_course_titles and get_course_details, though it never explicitly names a sibling to contrast against.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete routing guidance: session IDs come from get_current_sessions and other filter codes from get_reference_data, and it distinguishes exact course_code from keyword course_title. It lacks explicit when-not-to-use guidance, but the prerequisite sourcing is unusually actionable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_course_titlesBRead-onlyIdempotent
Autocomplete a course code/title using a division code and a current session ID.
Thresholds are upstream autocomplete tuning parameters, not pagination.
| Name | Required | Description | Default |
|---|---|---|---|
| term | Yes | ||
| sessions | Yes | ||
| divisions | Yes | ||
| lower_threshold | No | ||
| upper_threshold | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint and destructiveHint=false, so the safety profile is covered. The description adds one genuinely useful behavioral note (thresholds are upstream tuning, not pagination), but says nothing about result shape, ranking, or whether the match is prefix/substring.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences with the core action front-loaded and no filler. The second sentence is a targeted disambiguation, so every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, five undocumented parameters, and no annotation gaps explicitly addressed, the description leaves the caller guessing about input formats and what autocomplete returns (suggestions? ranked list?). It is adequate for a simple read-only lookup but not complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description carries the full burden. It partially compensates, clarifying that divisions/sessions select the autocomplete scope and that thresholds are tuning knobs — but it never explains term vs. course code/title, nor the expected format of divisions/sessions (single value vs. list).
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb and resource ('Autocomplete a course code/title') and lists the required inputs. It does not, however, distinguish this tool from the sibling search_courses, which an agent would plausibly consider for the same intent.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It implies prerequisites by stating the tool needs 'a division code and a current session ID', which quietly points at get_divisions and get_current_sessions. It never states when to prefer this over search_courses or when it should not be used.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_departmentsBRead-onlyIdempotent
Search departments by keyword and division code (for example computer, ARTSC).
| Name | Required | Description | Default |
|---|---|---|---|
| term | Yes | ||
| divisions | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish that this is a read-only, idempotent, non-destructive operation. The description adds that matching is keyword-based, which implies partial matching behavior, but does not disclose result limits, pagination, or exact match semantics beyond what annotations cover.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded sentence with no wasted words, and the examples are directly useful for understanding the expected inputs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the low complexity, two required string parameters, and annotations covering safety, the description is minimally adequate. However, with no output schema and no parameter descriptions, it leaves the return shape and the exact format of 'divisions' unspecified.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It maps 'term' to a keyword and 'divisions' to a division code, with examples 'computer' and 'ARTSC', but does not clarify whether 'divisions' accepts a single code or multiple codes (despite the plural name), nor the expected string format.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb (search), resource (departments), and filtering dimensions (keyword and division code), with concrete examples for the latter. It is clear what the tool does, though it does not explicitly distinguish itself from the sibling get_divisions, which likely returns unfiltered division data.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage through 'Search departments by keyword and division code', but gives no guidance on when to use this tool versus alternatives such as get_divisions or get_reference_data. There are no exclusions or prerequisite conditions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
10 tool updates
v0.2.0- First observed
generate_timetable - First observed
get_course_details - First observed
get_current_sessions - First observed
get_divisions - First observed
get_reference_data - First observed
retrieve_timetable - First observed
save_timetable - First observed
search_course_titles - First observed
search_courses - First observed
search_departments
TDQS
Scored across 10 tools
Most tools target distinct resources (sessions, courses, timetables), but there are two confusable pairs: get_reference_data also returns division codes that get_divisions produces, and search_course_titles (autocomplete) overlaps with search_courses (paged listing). Descriptions do explain the intended distinction, but boundaries require careful reading.
All ten tools follow a consistent snake_case verb_noun pattern (get_current_sessions, search_departments, generate_timetable, save_timetable, retrieve_timetable). Conventions are predictable throughout with no mixing of styles.
Ten tools is well-scoped for a timetable-building workflow, covering discovery, generation, and persistence without redundancy. Each tool earns its place in the pipeline.
The surface covers the full workflow: reference/session lookup, department and course search, course details, timetable generation, save, and retrieve. Minor gaps remain around managing saved shares (no update/delete) and enrollment is explicitly out of scope, which is reasonable.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Query SEC EDGAR filings, XBRL financials, and company data through MCP. STDIO & Streamable HTTP.
Read-only MCP server for ClassQuill, a tutoring-business-management platform.
Remote MCP for TehProf Booking: browse resources & availability, create & cancel reservations.
Render, verify, describe, and safely edit Mermaid diagrams through MCP.
Related MCP Servers
- FlicenseAqualityCmaintenanceLocal-first Rutgers course planning assistant that answers 'what should I take and when?' using a CP-SAT solver, real transcript data, and live SOC data, connected to Claude via MCP.13-
- FlicenseNot gradedqualityBmaintenanceUnofficial MCP tools for LettuceMeet to create polls, view responses, and find meeting overlaps via CLI or MCP server.-
- AlicenseNot gradedqualityAmaintenanceEnables querying stops, routes, real-time arrivals, vehicle positions, and schedules from OneBusAway transit APIs via MCP, supporting STDIO or Streamable HTTP.2641Apache 2.0
- FlicenseNot gradedqualityCmaintenanceRemote MCP connector providing live, structured access to CMU Courses public data including courses, prerequisites, schedules, instructors, gen-eds, and final-exam times to help students plan schedules.-