Skip to main content
Glama
esreddy2

umich-dining-mcp

by esreddy2

umich-dining-mcp

npm CI Live site

An MCP server for the dining halls of the University of Michigan in Ann Arbor. It answers what is being served, which dishes are vegan or halal, what a dish contains, how many calories it has, and when each hall is open.

Every answer is read live from dining.umich.edu. Pages are kept in memory for a few minutes so that ten questions cost one visit, but nothing is written to disk and no menu is mirrored.

Transports

Local stdio and hosted Streamable HTTP

Runtime

Node.js 20.18.1 or newer

Halls

the ten dining halls

Registry

io.github.esreddy2/umich-dining-mcp

Install

npm install -g umich-dining-mcp

or run it without installing anything:

npx -y umich-dining-mcp

Claude Code

claude mcp add umich-dining -- npx -y umich-dining-mcp

Cursor

~/.cursor/mcp.json:

{
  "mcpServers": {
    "umich-dining": {
      "command": "npx",
      "args": ["-y", "umich-dining-mcp"]
    }
  }
}

VS Code

.vscode/mcp.json:

{
  "servers": {
    "umich-dining": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "umich-dining-mcp"]
    }
  }
}

Any other client that starts MCP servers over stdio takes the same mcpServers entry as Cursor, with npx -y umich-dining-mcp as the command.

Related MCP server: nutrition-mcp-server

Tools

Tool

What it does

list_locations

The ten halls with address, phone, e-mail, map link, today's service periods, whether they are open right now, and whether they have a gluten-free pantry.

get_menu

The menu of one hall for the meal it is serving right now: meals, stations and dishes, with the coded traits and allergens, the density and carbon tiers, the calories and the serving size. Name one meal or several to get them instead.

search_dishes

Find dishes by name, in the halls that are named or across all of them (case-insensitive substring match), on one day or over a range.

filter_dishes

Filter the menus by allergen, trait, nutrient density, carbon footprint, nutrients, calories and sodium, in the halls that are named or across all of them, on one day or over a range.

list_nutrition_fields

The supported nutrient names, their units and the Daily Value basis of the micronutrients.

get_hours

The service periods of a day plus the regular weekly schedule. A hall that cannot be read is reported in failures; the others are still returned.

find_open_now

Which halls are serving at a given time of day.

get_item_nutrition

The full nutrition panel of a single dish.

Resources

Resource

Content

umich://dining-halls

The hall registry as JSON, with the code of every hall.

umich://taxonomy

The 15 allergens and 14 traits with their codes and display labels, the trait implication closure and the allergen caveat.

Example questions

What is serving at Bursley for dinner tonight?

Which halls are open right now?

Find vegan dishes at South Quad that do not contain soy.

What are the ingredients of the Oatmeal at Bursley? How many calories?

When is Markley open on Saturday?

Show me dishes with more than 500 mg of sodium.

Which halls serve tiramisu between the 24th and the 26th?

The response contract

The rows of search_dishes and filter_dishes carry small integers instead of names, and a key block at the top of the response maps every code back to its slug. The key lists only what that response uses. The codes are frozen for the life of the contract.

{
  "key": { "halls": { "1": "bursley" }, "meals": { "3": "Lunch" },
           "stations": { "7": "Grill" }, "traits": { "5": "vegan" },
           "allergens": { "7": "milk" } },
  "units": { "calories": "kcal", "protein": "g" },
  "note": "Allergen codes: check key.allergens before reporting; site data is advisory.",
  "date": "2026-10-21",
  "matches": [
    [1, 3, 7, "Grilled Chicken", [5], [7], 3, 320, "1 Each (113g)", 113, 32]
  ]
}

A row is an array; its fixed positions are named in each tool description and the variable nutrient tail is carried once per response as nutrients. The member names of a named row are two and a half times the data of the row, repeated on every row: a named row cost 216 bytes, an array row costs 72.

  • The halls are 1..10 in the order of the registry below, the meals are 1 (Breakfast), 2 (Brunch), 3 (Lunch) and 4 (Dinner), the allergens are 1..15 and the six boolean traits are 1..6 (glutenfree, halal, kosher, spicy, vegan, vegetarian). A meal label the site invents takes the next free code, from 5. The stations have a frozen vocabulary too: the same station carries the same code in every response, so a code can be remembered.

  • mhealthyTier is 1 (Nutrient Dense Low) to 5 (Nutrient Dense High). The scale is fixed and described in the tool descriptions and in umich://taxonomy.

  • A row carries the carbon tier (carbonFootprint) only when the call constrains it with max_carbon or sorts by carbonFootprint; otherwise it is left out to keep the row small.

  • The traits array carries the six boolean traits only; the density tier is lifted into its own numeric field.

  • The units map gives the unit of every nutrient the response returns. A micronutrient is an amount like every other nutrient: the site publishes the percent of the Daily Value, and the row carries the amount that percent stands for — 15 %DV of an 18 mg Daily Value of iron is 2.7 in mg. The percent is still available under its own name, %DV, in a threshold.

  • A search or a filter takes the halls it covers: one hall, several halls, or no hall at all for every one of them. The rows come back in the order that was asked for, and limit takes the first of them: the default is 50 rows, and the answer says how many matched and how to see the rest.

  • The row always carries the calories and the serving size. Every other nutrient, the sodium included, is asked for by name with include_nutrients — the sodium has nothing that makes it more interesting than the protein. A nutrient a filter constrained is always returned, whether or not it was asked for.

  • A single-day response carries date; a range response carries dateRange and each row carries the dates it appeared on.

  • A dish without a published value is reported as null, never as zero. A trace or a < value is not a value at all.

get_menu and the sweep tools return the same compact row, so a row means the same thing wherever it is read. get_item_nutrition is the tool that returns the raw nutrition panel, of one dish.

A whole menu is far smaller this way: the menu of South Quad went from 60,266 bytes to 8,817, and the menu of Bursley from 42,141 to 6,573. The panel of a single dish is one call to get_item_nutrition.

The halls

id

Hall

id

Hall

bursley

Bursley

south-quad

South Quad

east-quad

East Quad

twigs-at-oxford

Twigs at Oxford

markley

Markley

wolverine-village

Wolverine Village

mosher-jordan

Mosher-Jordan

lawyers-club

Lawyers Club

north-quad

North Quad

martha-cook

Martha Cook

The id is what get_menu, get_hours and search_dishes expect. The code of a hall is its position in this list, counted from one.

Dates

The site publishes menus from three days ago to fourteen days ahead. Outside that range the site does not answer with an error, it answers with a different day's menu, so a date outside the range is refused before anything is fetched, with a message that names the range the site offers. When the page states which day it rendered, that day is compared with the one you asked for and a mismatch is an error rather than a wrong answer.

A range is asked for with from and to; to omitted means the last published day. The two cannot be combined with date. A range that does not fit in one call is read in windows with offset; the coverage block of the answer names the offset of the next window.

Time

Every time the server reports is campus time: the time zone of Ann Arbor, America/Detroit, which is Eastern Standard Time and Eastern Daylight Time in the summer. The day the site publishes, the mealtimes, and the "today" of a cache entry are all read in that zone.

The zone of the machine the server runs on does not matter. A server in Chicago and a server in UTC answer the same question the same way, and the test suite checks that by running the meal selection under several host zones. Set UMICH_DINING_TIMEZONE only to point the server at a mirror of the site in another zone.

Filters

Parameter

Meaning

exclude_allergens

Keeps only the dishes that do not carry any of the listed allergens.

require_traits

Keeps only the dishes that carry every listed trait.

min_mhealthy

Minimum nutrient-density tier, 1..5 (3 = "Nutrient Dense Medium or better").

max_carbon

Maximum carbon footprint: 1 (low), 2 (medium) or 3 (high).

nutrients

A range per nutrient, e.g. {"protein": {"min": 20, "unit": "g"}}. The unit defaults to the nutrient's own and is checked.

include_nutrients

The nutrients to return, by canonical key or by published name, or all. Defaults to the ones the filter used; a constrained nutrient is always returned.

query

A case-insensitive substring of the dish name.

meal, station

Narrow the sweep to one meal or one station.

sort_by, sort_order

The field to sort on and the direction.

A constraint on a nutrient excludes the dishes that publish no value for it: an unknown value is never a zero.

The cost of a range

A range query reads one page per hall per day, and the site is fetched at most two pages a second. A query that needs more upstream pages than UMICH_DINING_MAX_RANGE_FETCHES (default 12) returns the rows it could serve and a coverage block that says how much was served:

"coverage": { "requested": 30, "cached": 18, "fetchedNow": 12, "pending": 0, "failed": 0,
              "stale": 0, "offset": 0, "pages": 30, "nextOffset": null }

The numbers add up: every page the query asked for was cached, fetched, left pending or failed. nextOffset is where the rest of the range begins, so a wide range is read in windows: ask again with offset set to that number.

The persistent cache exists for this: the pages of the published window are kept on disk and warmed in the background, so a range query is usually served without touching the site.

Allergens

Allergen data is only as good as the site. The menu page flags the allergens the kitchen reported for a dish, but it does not distinguish "contains" from "may contain", there are no ingredient lists, and a missing flag is not an absence of the allergen. The site's own guidance is: "Look for the signs posted near each food serving area for a list of menu options with allergens highlighted in red." "Gluten Free" means the dish is made without gluten, not that it is safe for someone with coeliac disease. Dedicated gluten-free pantries exist at South Quad, East Quad, Mosher-Jordan and Bursley.

The caveat is in the description of every tool that returns allergen data and in umich://taxonomy. A response that carries allergens repeats one line reminding the reader to resolve the codes; the long caveat is not repeated in every body. No tool ever claims that a dish is safe.

Two further points about the traits, because the site is careful about them: a vegan dish is reported as vegetarian as well, since the site keeps the two apart, and no other trait implies another (halal does not imply vegetarian, and neither does kosher).

Configuration

Environment variable

Default

Meaning

UMICH_DINING_USER_AGENT

python-requests/2.32.3

The User-Agent to use.

UMICH_DINING_BASE_URL

https://dining.umich.edu

The site to read.

UMICH_DINING_TIMEZONE

America/Detroit

The time zone of the campus: the day the site publishes and the mealtimes are read in it.

UMICH_DINING_TIMEOUT_MS

20000

Per-request timeout.

UMICH_DINING_MAX_RETRIES

3

Retries after the first attempt.

UMICH_DINING_MAX_CONCURRENCY

2

Requests in flight.

UMICH_DINING_MIN_GAP_MS

500

Minimum gap between requests.

UMICH_DINING_TTL_TODAY_MS

900000

Cache lifetime of today's menu.

UMICH_DINING_TTL_FUTURE_MS

21600000

Cache lifetime of a future menu.

UMICH_DINING_TTL_PAST_MS

86400000

Cache lifetime of a past menu.

UMICH_DINING_TTL_REGULAR_HOURS_MS

86400000

Cache lifetime of the weekly schedule.

UMICH_DINING_MAX_RANGE_FETCHES

12

Upstream pages a single range query may fetch.

UMICH_DINING_CACHE_DIR

~/.cache/umich-dining-mcp

The persistent cache. off switches it off.

UMICH_DINING_CACHE_MAX_AGE_DAYS

30

How long a cache entry is kept.

UMICH_DINING_CACHE_MAX_SIZE_MB

200

The largest the persistent cache may grow.

UMICH_DINING_CACHE_PRUNE_INTERVAL_MS

3600000

How often the persistent cache is pruned.

How it treats the site

dining.umich.edu is somebody else's website, so the server stays gentle with it:

  • Two requests in flight, 500 ms apart at most. The limit is global to the process.

  • A cache with in-flight de-duplication. Ten questions about the same hall cost one request. Today's menu is cached for 15 minutes, a future menu for 6 hours, a past menu for 24 hours and the weekly hours for 24 hours.

  • Stale on error. If the site cannot be reached and a cached copy exists, the copy is served and marked as stale instead of failing the question.

  • One User-Agent. The site answers HTTP 200 to a small set of clients only; python-requests/2.32.3 is the one that has been measured to work, while a generic fetch agent and a headless browser both get 403. It is not the server's real identity, which is why it is configurable.

Occupancy

get_dining_occupancy reports real-time fullness for the halls that carry sensors (Bursley, East Quad, South Quad, Mosher-Jordan, Twigs at Oxford):

{ "hall": "bursley" }

It returns the current count, daily patron flow, total capacity, percent full, and the time of the reading. A hall with no sensor is simply omitted.

Short forms

Hall names, nutrients, and traits accept short, case-insensitive aliases:

  • Halls: mojo, south, east, lawyers, cook, twigs, wovlerine, ...

  • Nutrients: cals, kcals, carbs, fiber, protein/prot, na/salt, ...

  • Traits: gf, veg.

Descriptions are unchanged; the server resolves the alias before validating.

Data source

Menus, hours, locations, nutrition, and occupancy are read from the U-M dining mobile API, with the public site scraper retained as a fallback. Answers are still read live and cached for a few minutes.

Contributing

Pull requests are welcome. The test suite, the fixtures and the release process are described in CONTRIBUTING.md.

License

MIT, see LICENSE.

Available Tools

8 tools
filter_dishesFilter dishesB
Read-onlyIdempotent
Inspect

Filter dining hall menus by allergen, trait, nutrient density, carbon, calories, sodium and name. All params optional. Allergens/traits are slugs; read key for codes. min_mhealthy: keep tiers >= (1-5). max_carbon: keep tiers <= (1 low, 2 medium, 3 high). nutrients: range per nutrient. query: case-insensitive substring. Rows are coded arrays; read key. stale means expired cache; asOf data age. Allergens advisory.

NameRequiredDescriptionDefault
toNoThe last day of a range to filter. Defaults to the last published day.
dateNoA single day to filter. Cannot be combined with from/to.
fromNoThe first day of a range to filter.
hallNoHalls: one, a list, or none for all.
mealNoKeeps only that meal.
limitNoRows to return (default 50, max 500).
queryNoA case-insensitive substring of the dish name.
offsetNoPages of the range to skip.
sort_byNoSort field: a nutrient key, carbonFootprint, a micronutrient name, servingSize, mhealthyTier, or a ratio "numerator:denominator" (e.g. "protein:calories", "vitaminA:iron"). Legacy: proteinToCalorie, fiberToCalorie.
stationNoKeeps only that station.
nutrientsNoRange per nutrient, e.g. {"protein":{"min":20,"unit":"g"}}. A constraint drops dishes with no value.
max_carbonNoThe highest acceptable carbon footprint: 1 (low), 2 (medium) or 3 (high). The dishes the site did not tag are dropped.
sort_orderNoThe direction of the sort. It defaults to desc, so the biggest value comes first.
min_mhealthyNoThe lowest acceptable nutrient-density tier. The dishes the site did not tag are dropped.
require_traitsNoKeeps only the dishes that carry every one of these traits.
exclude_allergensNoKeeps only the dishes that carry none of these allergens.
include_nutrientsNoNutrients to return, by key/name, or ["all"].

Output Schema

NameRequiredDescription
keyYes
asOfNo
dateNo
noteNo
flagsNo
staleYes
unitsNo
filterNo
noMenuNo
matchesYes
coverageNo
failuresYes
dateRangeNo
nutrientsNo
truncatedYes
totalMatchesYes

TDQS

B3.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover read-only, idempotent, non-destructive and open-world behavior, so the bar is lower, yet the description still adds real context: rows come back as coded arrays that require the key, 'stale' marks expired cache with asOf indicating data age, and allergen filtering is advisory rather than a safety guarantee. These are behavior-facing facts an agent cannot get from annotations or schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose is front-loaded in the first sentence and the remaining telegraphic clauses cover 17 parameters in a compact block with little padding. Minor redundancy ('read key for codes' appears twice) and the fragment style cost it a point, but density is appropriate for the parameter count.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values needn't be explained, and the description does flag coded arrays and stale/asOf semantics. However, it leaves the 'key' reference ambiguous (presumably list_nutrition_fields), doesn't describe pagination interaction between limit/offset, and gives no indication of result size or ordering defaults beyond the schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents all 17 parameters, and most description clauses (min_mhealthy tier semantics, max_carbon tier mapping, query substring) largely restate it. The one genuinely additive note is that allergens and traits are slugs requiring a key lookup for codes, which the schema does not convey for free-text trait values.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence names a specific verb (filter) and resource (dining hall menus) and enumerates the filterable dimensions, which is clearly distinct from retrieval-style siblings like get_menu or get_item_nutrition. It never explicitly names an alternative, but the 'filter' framing makes the role unambiguous to an agent.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description says 'All params optional' and notes 'Allergens advisory', but gives no guidance on when to choose this over get_menu or get_item_nutrition, and no exclusion or prerequisite conditions. The agent must infer usage from the name and parameter list alone.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

find_open_nowFind halls that are open nowA
Read-onlyIdempotent
Inspect

The dining halls that are serving at the given time of day, and the ids of the ones that are not, with the service periods of the day for the halls that are open. Without arguments the current campus-local time is used, and the response says which time it resolved. open carries the hall details and today's periods; closed carries hall ids only. stale means a page was served from an expired cache entry; asOf is the age of the data.

NameRequiredDescriptionDefault
atNoThe campus-local time of day to look at. Defaults to the current time.
dateNoThe day to look at. Defaults to today.

Output Schema

NameRequiredDescription
atYes
asOfNo
dateYes
openYes
closedYes
failuresYes

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare this as a read-only, idempotent, non-destructive open-world operation, and the description adds useful behavior beyond that: default time resolution, open vs. closed response contents, stale-cache meaning, and asOf age. It does not contradict the annotations and gives strong context for interpreting the response.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose and then supplies response-field context. It is dense but avoids obvious repetition, and every clause appears to serve interpretation or default behavior.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the moderate complexity, annotations, complete input schema, and output schema, the description is complete enough to call correctly. It covers default time handling, response partitioning into open and closed, and cache-related fields.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents both `at` and `date`. The description adds the important default behavior when no arguments are supplied, but otherwise does not substantially extend parameter semantics beyond what the schema provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the resource and scope: dining halls serving at a given time, plus ids of closed halls. It is specific enough for an agent to understand the operation, though it does not explicitly contrast itself with siblings such as get_hours.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by the phrase 'dining halls that are serving at the given time of day,' and the default to current campus-local time is helpful. However, there is no explicit when-to-use guidance, no exclusions, and no named alternative such as get_hours.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_dining_occupancyDining hall occupancyA
Read-onlyIdempotent
Inspect

Real-time occupancy for monitored dining halls: current count, patron flow, total capacity, and percent full. Only halls with sensors are returned.

NameRequiredDescriptionDefault
hallNoKeep only this hall, or a list of halls.

Output Schema

NameRequiredDescription
readingsYes
observedAtYes

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already establish readOnly, idempotent, non-destructive, open-world behavior. The description adds useful behavioral context beyond that: the data is real-time, only sensor-equipped halls are returned, and the specific metrics included are listed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two compact sentences, front-loaded with the core purpose and then the coverage limitation. No filler or repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool is simple (one optional param), annotations cover safety, and an output schema exists. The description explains the key metrics and sensor coverage, though 'patron flow' remains somewhat ambiguous without relying on the output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single optional 'hall' parameter is fully documented in the schema, including support for a string or list. The description does not mention or add meaning to the parameter, so baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific resource (dining hall occupancy) and enumerates the returned metrics: current count, patron flow, capacity, and percent full. This is clearly distinct from sibling tools like get_menu, get_hours, and find_open_now.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by the real-time occupancy framing, but the description gives no explicit when-to-use guidance or contrasts with alternatives such as get_hours or find_open_now. The sensor-only caveat helps set expectations but is not route guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_hoursGet dining hall hoursA
Read-onlyIdempotent
Inspect

Get the service periods published for a dining hall on the requested day, plus the regular weekly schedule. Accepts one hall, a list, or none for all (like filter_dishes). today is the day's published service periods and regular is the weekly schedule. A hall that cannot be read is reported in the failures and the other halls are still returned. The response carries the weekday name of the requested date. stale means the data is from cache and may be slightly old, but is still the best available; asOf is the age. Re-call only if you need guaranteed-fresh data.

NameRequiredDescriptionDefault
dateNoThe day to read. Defaults to today.
hallNoHalls: one, a list, or none for all.

Output Schema

NameRequiredDescription
asOfNo
dateYes
hallsYes
weeklyNo
weekdayNo
failuresYes

TDQS

A4.1/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the readOnly/idempotent annotations by disclosing partial-failure behavior (unreadable halls land in `failures` while others still return), cache staleness semantics with `stale`/`asOf`, and a re-call policy. That is exactly the behavioral context annotations can't express.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Dense and largely front-loaded, but the sentence 'today is the day's published service periods and regular is the weekly schedule' is ambiguous — it explains response keys but reads as if it describes the date parameter, which defaults to today. A little unearned confusion.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, yet the description still clarifies the meaning of `today`, `regular`, `failures`, `stale` and `asOf`, which removes interpretation risk. Coverage is strong for a two-parameter read tool; the only gap is sibling routing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3; the description still adds value by spelling out the tri-modal hall argument (single, list, or omitted for all) and the date default. Nothing beyond that is added for format or limits, so not a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: returns published service periods for a dining hall on a given day plus the regular weekly schedule. The scope (multiple halls, partial failure) is clear. It doesn't differentiate from siblings like get_menu or find_open_now, which is the only thing keeping it from a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete usage rules: pass one hall, a list, or none for all (with filter_dishes as the analogy), and only re-call when guaranteed-fresh data is required. It stops short of saying when to prefer this over get_menu or find_open_now.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_item_nutritionGet a dish nutrition panelA
Read-onlyIdempotent
Inspect

Get the full nutrition panel of one dish. Name matched case-insensitively; exact match wins, else unique substring. Dish row uses the same coded layout as the sweep tools. Panel values are numbers with one units map; micronutrient amount is the derived amount, with the published percent behind it. asOf data age. Allergens advisory. Use this only when you need the full panel for a single dish. For multiple dishes, use filter_dishes with include_nutrients instead.

NameRequiredDescriptionDefault
dateNoDate YYYY-MM-DD. Site publishes today-3..+14 days.
hallYesThe dining hall to read.
itemYesThe dish name.
mealNoNarrow the search to one meal.
stationNoNarrow the search to one station.

Output Schema

NameRequiredDescription
keyYes
asOfNo
dateYes
hallYes
mealYes
nameYes
unitsNo
traitsYes
stationYes
warningYes
allergensYes
nutritionYes
mhealthyTierYes
carbonFootprintYes

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the read-only annotations by disclosing matching semantics (case-insensitive, exact match wins, else unique substring), output shape (coded row layout, numbers plus one units map, derived micronutrient amount with published percent), asOf data age, and that allergens are advisory. It leaves out what happens on no match or ambiguous substring matches, so it stops short of full behavioral disclosure.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose is front-loaded, and every sentence carries information: matching rules, output semantics, data age, allergen caveat, and the sibling alternative. It is dense but not padded; moving the routing sentence earlier would improve scanability slightly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema and read-only annotations present, the description covers the remaining gaps an agent needs: disambiguation rules for the dish name, the meaning of the coded panel layout, and the correct alternative tool. It omits default date behavior and the error/ambiguity outcome when the substring match is not unique, which are meaningful for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description adds genuine meaning for the key 'item' parameter (case-insensitive matching, exact-match precedence, unique-substring fallback) that the schema's bare 'The dish name' does not provide; the remaining parameters are left to the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Get the full nutrition panel of one dish') and explicitly contrasts with the multi-dish sibling filter_dishes. An agent can distinguish this from get_menu and filter_dishes without inspecting any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly scopes use to the single-dish case ('Use this only when you need the full panel for a single dish') and names the alternative for multiple dishes ('use filter_dishes with include_nutrients instead'). Both when-to-use and when-not-to-use are covered.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_menuGet a dining hall menuA
Read-onlyIdempotent
Inspect

Get the menu of one dining hall: meals, stations and dishes. Rows: [name, traits, allergens, mhealthyTier, calories, servingSize, servingSizeGrams] plus nutrients. traits/allergens are codes; read key. With no meal, the meal being served now is returned (or next if closed). Date defaults to today; site publishes today-3..+14. stale means expired cache; asOf data age. Allergens advisory.

NameRequiredDescriptionDefault
dateNoThe day to read. Defaults to today.
hallYesThe dining hall to read.
mealNoKeeps only those meals: one name, or a list of them. When it is left out, the meal the hall is serving right now is used.
stationNoKeeps only that station.
include_nutrientsNoNutrients to return, by key/name, or ["all"].

Output Schema

NameRequiredDescription
keyYes
asOfNo
dateYes
hallYes
noteNo
mealsYes
staleYes
unitsNo
nutrientsNo
totalItemsYes
renderedDateNo
totalStationsYes
unknownMealLabelsYes

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/openWorld, and the description adds non-obvious runtime semantics on top: the fallback-meal behavior, the cache/publish window, what 'stale' means, that asOf reflects data age, and that allergens are advisory only. That is exactly the extra context annotations cannot convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose, then row shape, then behavioral caveats — a sensible ordering with almost no filler. The telegraphic fragments ('stale means expired cache; asOf data age') are efficient but slightly clipped.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Output schema exists, yet the description still names the row fields and the nutrients payload and covers cache freshness and allergen caveats — everything an agent needs to interpret a response correctly for a 5-parameter read tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3; the description still adds value by explaining the publication date window constraint and the meal-default behavior, plus how traits/allergens codes should be read via the key. It does not add syntax detail for station or include_nutrients beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Get the menu of one dining hall') and enumerates the payload (meals, stations, dishes), which separates it from list-oriented siblings like list_locations. It does not explicitly name filter_dishes as the alternative, so the differentiation is implied rather than stated.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives real operating guidance: meal is optional and falls back to the currently served meal (or next if closed), date defaults to today, and the site only publishes today-3..+14. It stops short of saying when to choose this over filter_dishes or get_item_nutrition.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_locationsList dining hallsA
Read-onlyIdempotent
Inspect

List the dining halls and their service periods for the day, with whether they are open now. openNow is evaluated at the current campus-local time. The entries are the halls and their service periods for the day. stale means a page was served from an expired cache entry; asOf is the age of the data. Cafes, markets, bakeries, grills, prices and meal plans are out of scope.

NameRequiredDescriptionDefault
dateNoThe day to read. Defaults to today.
hallNoKeep only this hall.

Output Schema

NameRequiredDescription
dateYes
failuresYes
locationsYes
mapUrlTemplateNo

TDQS

A3.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnly/idempotent annotations, the description discloses meaningful runtime behavior: openNow is computed at campus-local time, and it explains the stale/asOf response fields as cache-age signals. This is real added context an agent could not get from annotations. It does not mention caching TTL or freshness guarantees the agent might rely on when choosing stale data.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The scope and time semantics are front-loaded, but the sentence 'The entries are the halls and their service periods for the day' restates the opening clause almost verbatim. With an output schema present, that redundancy costs space without adding information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-required-param, read-only listing with an output schema, the description covers scope, time zone semantics, cache metadata, and exclusions. The main remaining ambiguity is how a supplied date interacts with 'open now' — whether openNow reflects today or the requested day — which an agent may need in order to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so both parameters (date, hall) are already documented with formats and defaults. The description adds only 'for the day' framing and does not clarify how date interacts with the openNow computation. Baseline 3 for full schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource with scope: 'List the dining halls and their service periods for the day, with whether they are open now.' It also draws a boundary against adjacent content (cafes, markets, prices, meal plans). It stops short of distinguishing itself from siblings like get_hours and find_open_now, which overlap heavily with 'service periods' and 'open now'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: the agent can infer this is the all-halls overview for a given day. Out-of-scope items are enumerated, which partially serves as a when-not list, but no alternative sibling is named for filtering to a single hall's hours or for finding open venues.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_nutrition_fieldsList nutrition fieldsA
Read-onlyIdempotent
Inspect

List the canonical nutrient identifiers, their units, the alternative units a threshold may be written in, and the Daily Value basis of the published micronutrients. A constraint on a nutrient excludes the dishes that publish no value for it, and a value the site writes as "trace" or "< 1%" is missing rather than zero. sortFields includes servingSize, mhealthyTier and ratio syntax "a:b".

NameRequiredDescriptionDefault

No parameters

Output Schema

NameRequiredDescription
notesYes
fieldsYes
sortFieldsYes
acceptedUnitsYes
micronutrientsYes

TDQS

A3.8/5.0
Behavior4/5

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 instead adds genuine domain behavior — that a constraint excludes dishes publishing no value for that nutrient, and that 'trace' or '< 1%' means missing rather than zero. That is exactly the kind of non-obvious semantics annotations cannot convey. It stops short of describing response ordering or cache/staleness behavior, keeping it at 4.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with the actual list contents, zero filler. The closing sortFields sentence is somewhat displaced — it describes a parameter of a different tool — but it is compact and earns its place as domain context.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return values need no explanation, and the description supplies the interpretive layer an agent needs: what the identifiers mean, how units and Daily Value baselines relate, and how absent/trace values behave. Only the explicit 'call this first' workflow link to filter_dishes is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Zero parameters, so the baseline is 4; the schema is empty and closed. The description does add meaning about fields consumed elsewhere (alternative threshold units, sortFields including servingSize and mhealthyTier with 'a:b' ratio syntax), which is useful even though none of it belongs to this tool's own input.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb and resource — 'List the canonical nutrient identifiers, their units, the alternative units a threshold may be written in, and the Daily Value basis' — which is far more precise than the title. It is clearly a reference/metadata lookup, distinguishable in kind from get_item_nutrition, though it never names a sibling to make the contrast explicit.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: an agent can infer this is the discovery step before writing a nutrient constraint or a sortFields expression. There is no explicit 'use this before calling filter_dishes' statement and no when-not guidance, so the routing must be reconstructed from the constraint and sortFields remarks.

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.

  1. 6 tool updatesv2.0.0
    • Changedfilter_dishes2 fields changed
      • changedInput schema / properties / hall / anyOf
        Previous value: -[
        -  {
        -    "enum": [
        -      "bursley",
        -      "east-quad",
        -      "markley",
        -      "mosher-jordan",
        -      "north-quad",
        -      "south-quad",
        -      "twigs-at-oxford",
        -      "wolverine-village",
        -      "lawyers-club",
        -      "martha-cook"
        -    ],
        -    "type": "string"
        -  },
        -  {
        -    "items": {
        -      "enum": [
        -        "bursley",
        -        "east-quad",
        -        "markley",
        -        "mosher-jordan",
        -        "north-quad",
        -        "south-quad",
        -        "twigs-at-oxford",
        -        "wolverine-village",
        -        "lawyers-club",
        -        "martha-cook"
        -      ],
        -      "type": "string"
        -    },
        -    "maxItems": 10,
        -    "type": "array"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "items": {
        +      "type": "string"
        +    },
        +    "maxItems": 10,
        +    "type": "array"
        +  }
        +]
      • removedInput schema / properties / require_traits / items / enum
        Removed value: -[
        -  "carbonhigh",
        -  "carbonlow",
        -  "carbonmedium",
        -  "glutenfree",
        -  "halal",
        -  "kosher",
        -  "mhealthy1",
        -  "mhealthy2",
        -  "mhealthy3",
        -  "mhealthy4",
        -  "mhealthy5",
        -  "spicy",
        -  "vegan",
        -  "vegetarian"
        -]
    • Addedget_dining_occupancy
    • Changedget_hours1 field changed
      • changedInput schema / properties / hall / anyOf
        Previous value: -[
        -  {
        -    "enum": [
        -      "bursley",
        -      "east-quad",
        -      "markley",
        -      "mosher-jordan",
        -      "north-quad",
        -      "south-quad",
        -      "twigs-at-oxford",
        -      "wolverine-village",
        -      "lawyers-club",
        -      "martha-cook"
        -    ],
        -    "type": "string"
        -  },
        -  {
        -    "items": {
        -      "enum": [
        -        "bursley",
        -        "east-quad",
        -        "markley",
        -        "mosher-jordan",
        -        "north-quad",
        -        "south-quad",
        -        "twigs-at-oxford",
        -        "wolverine-village",
        -        "lawyers-club",
        -        "martha-cook"
        -      ],
        -      "type": "string"
        -    },
        -    "maxItems": 10,
        -    "type": "array"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "items": {
        +      "type": "string"
        +    },
        +    "maxItems": 10,
        +    "type": "array"
        +  }
        +]
    • Changedget_item_nutrition1 field changed
      • removedInput schema / properties / hall / enum
        Removed value: -[
        -  "bursley",
        -  "east-quad",
        -  "markley",
        -  "mosher-jordan",
        -  "north-quad",
        -  "south-quad",
        -  "twigs-at-oxford",
        -  "wolverine-village",
        -  "lawyers-club",
        -  "martha-cook"
        -]
    • Changedget_menu1 field changed
      • removedInput schema / properties / hall / enum
        Removed value: -[
        -  "bursley",
        -  "east-quad",
        -  "markley",
        -  "mosher-jordan",
        -  "north-quad",
        -  "south-quad",
        -  "twigs-at-oxford",
        -  "wolverine-village",
        -  "lawyers-club",
        -  "martha-cook"
        -]
    • Changedlist_locations1 field changed
      • removedInput schema / properties / hall / enum
        Removed value: -[
        -  "bursley",
        -  "east-quad",
        -  "markley",
        -  "mosher-jordan",
        -  "north-quad",
        -  "south-quad",
        -  "twigs-at-oxford",
        -  "wolverine-village",
        -  "lawyers-club",
        -  "martha-cook"
        -]
  2. 8 tool updatesv0.1.1
    • Changedfilter_dishes46 fields changed
      • addedInput schema / additionalProperties
        Added value: +false
      • changedInput schema / properties / date / description
        Previous value: -"Calendar date in YYYY-MM-DD. The site publishes menus for today-3 days to today+14 days."New value: +"A single day to filter. Cannot be combined with from/to."
      • addedInput schema / properties / exclude_allergens / description
        Added value: +"Keeps only the dishes that carry none of these allergens."
      • addedInput schema / properties / from
        Added value: +{
        +  "description": "The first day of a range to filter.",
        +  "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
        +  "type": "string"
        +}
      • addedInput schema / properties / hall / anyOf
        Added value: +[
        +  {
        +    "enum": [
        +      "bursley",
        +      "east-quad",
        +      "markley",
        +      "mosher-jordan",
        +      "north-quad",
        +      "south-quad",
        +      "twigs-at-oxford",
        +      "wolverine-village",
        +      "lawyers-club",
        +      "martha-cook"
        +    ],
        +    "type": "string"
        +  },
        +  {
        +    "items": {
        +      "enum": [
        +        "bursley",
        +        "east-quad",
        +        "markley",
        +        "mosher-jordan",
        +        "north-quad",
        +        "south-quad",
        +        "twigs-at-oxford",
        +        "wolverine-village",
        +        "lawyers-club",
        +        "martha-cook"
        +      ],
        +      "type": "string"
        +    },
        +    "maxItems": 10,
        +    "type": "array"
        +  }
        +]
      • addedInput schema / properties / hall / description
        Added value: +"Halls: one, a list, or none for all."
      • removedInput schema / properties / hall / enum
        Removed value: -[
        -  "bursley",
        -  "east-quad",
        -  "markley",
        -  "mosher-jordan",
        -  "north-quad",
        -  "south-quad",
        -  "twigs-at-oxford",
        -  "wolverine-village",
        -  "lawyers-club",
        -  "martha-cook"
        -]
      • removedInput schema / properties / hall / type
        Removed value: -"string"
      • addedInput schema / properties / include_nutrients
        Added value: +{
        +  "description": "Nutrients to return, by key/name, or [\"all\"].",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / limit / description
        Added value: +"Rows to return (default 50, max 500)."
      • removedInput schema / properties / max_calories
        Removed value: -{
        -  "minimum": 0,
        -  "type": "number"
        -}
      • addedInput schema / properties / max_carbon / description
        Added value: +"The highest acceptable carbon footprint: 1 (low), 2 (medium) or 3 (high). The dishes the site did not tag are dropped."
      • removedInput schema / properties / max_carbon / enum
        Removed value: -[
        -  "low",
        -  "medium",
        -  "high"
        -]
      • addedInput schema / properties / max_carbon / maximum
        Added value: +3
      • addedInput schema / properties / max_carbon / minimum
        Added value: +1
      • changedInput schema / properties / max_carbon / type
        Previous value: -"string"New value: +"integer"
      • removedInput schema / properties / max_sodium_mg
        Removed value: -{
        -  "minimum": 0,
        -  "type": "number"
        -}
      • addedInput schema / properties / meal
        Added value: +{
        +  "description": "Keeps only that meal.",
        +  "enum": [
        +    "Breakfast",
        +    "Brunch",
        +    "Lunch",
        +    "Dinner"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / min_mhealthy / description
        Added value: +"The lowest acceptable nutrient-density tier. The dishes the site did not tag are dropped."
      • addedInput schema / properties / nutrients
        Added value: +{
        +  "additionalProperties": {
        +    "properties": {
        +      "max": {
        +        "description": "The highest acceptable value, in the unit below.",
        +        "type": "number"
        +      },
        +      "min": {
        +        "description": "The lowest acceptable value, in the unit below.",
        +        "type": "number"
        +      },
        +      "unit": {
        +        "description": "The unit of the bounds. It defaults to the nutrient's own; a micronutrient defaults to the published percent.",
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "description": "Range per nutrient, e.g. {\"protein\":{\"min\":20,\"unit\":\"g\"}}. A constraint drops dishes with no value.",
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedInput schema / properties / offset
        Added value: +{
        +  "description": "Pages of the range to skip.",
        +  "maximum": 9007199254740991,
        +  "minimum": 0,
        +  "type": "integer"
        +}
      • addedInput schema / properties / query
        Added value: +{
        +  "description": "A case-insensitive substring of the dish name.",
        +  "type": "string"
        +}
      • addedInput schema / properties / require_traits / description
        Added value: +"Keeps only the dishes that carry every one of these traits."
      • addedInput schema / properties / sort_by
        Added value: +{
        +  "description": "Sort field: a nutrient key, carbonFootprint, a micronutrient name, servingSize, mhealthyTier, or a ratio \"numerator:denominator\" (e.g. \"protein:calories\", \"vitaminA:iron\"). Legacy: proteinToCalorie, fiberToCalorie.",
        +  "type": "string"
        +}
      • addedInput schema / properties / sort_order
        Added value: +{
        +  "description": "The direction of the sort. It defaults to desc, so the biggest value comes first.",
        +  "enum": [
        +    "asc",
        +    "desc"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / station
        Added value: +{
        +  "description": "Keeps only that station.",
        +  "type": "string"
        +}
      • addedInput schema / properties / to
        Added value: +{
        +  "description": "The last day of a range to filter. Defaults to the last published day.",
        +  "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
        +  "type": "string"
        +}
      • addedOutput schema / properties / asOf
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / coverage
        Added value: +{
        +  "additionalProperties": false,
        +  "properties": {
        +    "cached": {
        +      "type": "number"
        +    },
        +    "failed": {
        +      "type": "number"
        +    },
        +    "fetchedNow": {
        +      "type": "number"
        +    },
        +    "nextOffset": {
        +      "type": [
        +        "number",
        +        "null"
        +      ]
        +    },
        +    "offset": {
        +      "type": "number"
        +    },
        +    "pages": {
        +      "type": "number"
        +    },
        +    "pending": {
        +      "type": "number"
        +    },
        +    "requested": {
        +      "type": "number"
        +    },
        +    "stale": {
        +      "type": "number"
        +    }
        +  },
        +  "required": [
        +    "requested",
        +    "cached",
        +    "fetchedNow",
        +    "pending",
        +    "failed",
        +    "stale",
        +    "offset",
        +    "pages",
        +    "nextOffset"
        +  ],
        +  "type": "object"
        +}
      • addedOutput schema / properties / dateRange
        Added value: +{
        +  "additionalProperties": false,
        +  "properties": {
        +    "from": {
        +      "type": "string"
        +    },
        +    "to": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "from",
        +    "to"
        +  ],
        +  "type": "object"
        +}
      • addedOutput schema / properties / filter
        Added value: +{
        +  "additionalProperties": {},
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / flags
        Added value: +{
        +  "additionalProperties": {},
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / key
        Added value: +{
        +  "additionalProperties": {
        +    "additionalProperties": {
        +      "type": "string"
        +    },
        +    "propertyNames": {
        +      "type": "string"
        +    },
        +    "type": "object"
        +  },
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • removedOutput schema / properties / matches / items / additionalProperties
        Removed value: -false
      • addedOutput schema / properties / matches / items / items
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "number"
        +    },
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "boolean"
        +    },
        +    {
        +      "type": "null"
        +    },
        +    {
        +      "items": {
        +        "type": "number"
        +      },
        +      "type": "array"
        +    },
        +    {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    {
        +      "additionalProperties": {
        +        "type": "number"
        +      },
        +      "propertyNames": {
        +        "type": "string"
        +      },
        +      "type": "object"
        +    }
        +  ]
        +}
      • removedOutput schema / properties / matches / items / properties
        Removed value: -{
        -  "allergens": {
        -    "items": {
        -      "type": "string"
        -    },
        -    "type": "array"
        -  },
        -  "calories": {
        -    "type": [
        -      "number",
        -      "null"
        -    ]
        -  },
        -  "carbonFootprint": {
        -    "anyOf": [
        -      {
        -        "enum": [
        -          "low",
        -          "medium",
        -          "high"
        -        ],
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  "date": {
        -    "type": "string"
        -  },
        -  "hall": {
        -    "enum": [
        -      "bursley",
        -      "east-quad",
        -      "markley",
        -      "mosher-jordan",
        -      "north-quad",
        -      "south-quad",
        -      "twigs-at-oxford",
        -      "wolverine-village",
        -      "lawyers-club",
        -      "martha-cook"
        -    ],
        -    "type": "string"
        -  },
        -  "hallName": {
        -    "type": "string"
        -  },
        -  "meal": {
        -    "enum": [
        -      "Breakfast",
        -      "Lunch",
        -      "Dinner"
        -    ],
        -    "type": "string"
        -  },
        -  "mhealthyTier": {
        -    "type": [
        -      "number",
        -      "null"
        -    ]
        -  },
        -  "name": {
        -    "type": "string"
        -  },
        -  "sodiumMg": {
        -    "type": [
        -      "number",
        -      "null"
        -    ]
        -  },
        -  "station": {
        -    "type": "string"
        -  },
        -  "traitLabels": {
        -    "additionalProperties": {
        -      "type": "string"
        -    },
        -    "propertyNames": {
        -      "type": "string"
        -    },
        -    "type": "object"
        -  },
        -  "traits": {
        -    "items": {
        -      "type": "string"
        -    },
        -    "type": "array"
        -  }
        -}
      • removedOutput schema / properties / matches / items / required
        Removed value: -[
        -  "hall",
        -  "hallName",
        -  "date",
        -  "meal",
        -  "station",
        -  "name",
        -  "traits",
        -  "traitLabels",
        -  "allergens",
        -  "mhealthyTier",
        -  "carbonFootprint",
        -  "calories",
        -  "sodiumMg"
        -]
      • changedOutput schema / properties / matches / items / type
        Previous value: -"object"New value: +"array"
      • addedOutput schema / properties / noMenu
        Added value: +{
        +  "items": {
        +    "additionalProperties": false,
        +    "properties": {
        +      "date": {
        +        "type": "string"
        +      },
        +      "hall": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "hall",
        +      "date"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / note
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / nutrients
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / stale
        Added value: +{
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / truncated
        Added value: +{
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / units
        Added value: +{
        +  "additionalProperties": {
        +    "type": "string"
        +  },
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • removedOutput schema / properties / warning
        Removed value: -{
        -  "type": "string"
        -}
      • changedOutput schema / required
        Previous value: -[
        -  "date",
        -  "totalMatches",
        -  "matches",
        -  "failures",
        -  "warning"
        -]New value: +[
        +  "key",
        +  "totalMatches",
        +  "truncated",
        +  "stale",
        +  "matches",
        +  "failures"
        +]
    • Changedfind_open_now22 fields changed
      • addedInput schema / additionalProperties
        Added value: +false
      • addedInput schema / properties / at
        Added value: +{
        +  "description": "The campus-local time of day to look at. Defaults to the current time.",
        +  "pattern": "^\\d{1,2}:\\d{2}(\\s*(am|pm))?$",
        +  "type": "string"
        +}
      • addedInput schema / properties / date
        Added value: +{
        +  "description": "The day to look at. Defaults to today.",
        +  "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
        +  "type": "string"
        +}
      • addedOutput schema / properties / asOf
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / at
        Added value: +{
        +  "type": "string"
        +}
      • removedOutput schema / properties / closed / items / additionalProperties
        Removed value: -false
      • addedOutput schema / properties / closed / items / enum
        Added value: +[
        +  "bursley",
        +  "east-quad",
        +  "markley",
        +  "mosher-jordan",
        +  "north-quad",
        +  "south-quad",
        +  "twigs-at-oxford",
        +  "wolverine-village",
        +  "lawyers-club",
        +  "martha-cook"
        +]
      • removedOutput schema / properties / closed / items / properties
        Removed value: -{
        -  "address": {
        -    "type": [
        -      "string",
        -      "null"
        -    ]
        -  },
        -  "date": {
        -    "type": "string"
        -  },
        -  "email": {
        -    "type": [
        -      "string",
        -      "null"
        -    ]
        -  },
        -  "glutenFreePantry": {
        -    "type": "boolean"
        -  },
        -  "id": {
        -    "enum": [
        -      "bursley",
        -      "east-quad",
        -      "markley",
        -      "mosher-jordan",
        -      "north-quad",
        -      "south-quad",
        -      "twigs-at-oxford",
        -      "wolverine-village",
        -      "lawyers-club",
        -      "martha-cook"
        -    ],
        -    "type": "string"
        -  },
        -  "mapUrl": {
        -    "type": [
        -      "string",
        -      "null"
        -    ]
        -  },
        -  "meals": {
        -    "items": {
        -      "enum": [
        -        "Breakfast",
        -        "Lunch",
        -        "Dinner"
        -      ],
        -      "type": "string"
        -    },
        -    "type": "array"
        -  },
        -  "name": {
        -    "type": "string"
        -  },
        -  "openNow": {
        -    "type": "boolean"
        -  },
        -  "path": {
        -    "type": "string"
        -  },
        -  "phone": {
        -    "type": [
        -      "string",
        -      "null"
        -    ]
        -  },
        -  "residentsOnly": {
        -    "type": "boolean"
        -  },
        -  "stale": {
        -    "type": "boolean"
        -  },
        -  "today": {
        -    "items": {
        -      "additionalProperties": false,
        -      "properties": {
        -        "closed": {
        -          "type": "boolean"
        -        },
        -        "label": {
        -          "type": "string"
        -        },
        -        "times": {
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "label",
        -        "times",
        -        "closed"
        -      ],
        -      "type": "object"
        -    },
        -    "type": "array"
        -  },
        -  "url": {
        -    "type": "string"
        -  }
        -}
      • removedOutput schema / properties / closed / items / required
        Removed value: -[
        -  "id",
        -  "name",
        -  "path",
        -  "url",
        -  "residentsOnly",
        -  "glutenFreePantry",
        -  "address",
        -  "phone",
        -  "email",
        -  "mapUrl",
        -  "meals",
        -  "date",
        -  "today",
        -  "openNow",
        -  "stale"
        -]
      • changedOutput schema / properties / closed / items / type
        Previous value: -"object"New value: +"string"
      • removedOutput schema / properties / open / items / properties / address
        Removed value: -{
        -  "type": [
        -    "string",
        -    "null"
        -  ]
        -}
      • addedOutput schema / properties / open / items / properties / asOf
        Added value: +{
        +  "type": "string"
        +}
      • removedOutput schema / properties / open / items / properties / date
        Removed value: -{
        -  "type": "string"
        -}
      • removedOutput schema / properties / open / items / properties / email
        Removed value: -{
        -  "type": [
        -    "string",
        -    "null"
        -  ]
        -}
      • removedOutput schema / properties / open / items / properties / mapUrl
        Removed value: -{
        -  "type": [
        -    "string",
        -    "null"
        -  ]
        -}
      • removedOutput schema / properties / open / items / properties / meals
        Removed value: -{
        -  "items": {
        -    "enum": [
        -      "Breakfast",
        -      "Lunch",
        -      "Dinner"
        -    ],
        -    "type": "string"
        -  },
        -  "type": "array"
        -}
      • removedOutput schema / properties / open / items / properties / path
        Removed value: -{
        -  "type": "string"
        -}
      • removedOutput schema / properties / open / items / properties / phone
        Removed value: -{
        -  "type": [
        -    "string",
        -    "null"
        -  ]
        -}
      • changedOutput schema / properties / open / items / properties / today / items / required
        Previous value: -[
        -  "label",
        -  "times",
        -  "closed"
        -]New value: +[
        +  "label",
        +  "times"
        +]
      • removedOutput schema / properties / open / items / properties / url
        Removed value: -{
        -  "type": "string"
        -}
      • changedOutput schema / properties / open / items / required
        Previous value: -[
        -  "id",
        -  "name",
        -  "path",
        -  "url",
        -  "residentsOnly",
        -  "glutenFreePantry",
        -  "address",
        -  "phone",
        -  "email",
        -  "mapUrl",
        -  "meals",
        -  "date",
        -  "today",
        -  "openNow",
        -  "stale"
        -]New value: +[
        +  "id",
        +  "name",
        +  "residentsOnly",
        +  "glutenFreePantry",
        +  "today",
        +  "openNow",
        +  "stale"
        +]
      • changedOutput schema / required
        Previous value: -[
        -  "date",
        -  "open",
        -  "closed",
        -  "failures"
        -]New value: +[
        +  "date",
        +  "at",
        +  "open",
        +  "closed",
        +  "failures"
        +]
    • Changedget_hours17 fields changed
      • addedInput schema / additionalProperties
        Added value: +false
      • changedInput schema / properties / date / description
        Previous value: -"Calendar date in YYYY-MM-DD. The site publishes menus for today-3 days to today+14 days."New value: +"The day to read. Defaults to today."
      • addedInput schema / properties / hall / anyOf
        Added value: +[
        +  {
        +    "enum": [
        +      "bursley",
        +      "east-quad",
        +      "markley",
        +      "mosher-jordan",
        +      "north-quad",
        +      "south-quad",
        +      "twigs-at-oxford",
        +      "wolverine-village",
        +      "lawyers-club",
        +      "martha-cook"
        +    ],
        +    "type": "string"
        +  },
        +  {
        +    "items": {
        +      "enum": [
        +        "bursley",
        +        "east-quad",
        +        "markley",
        +        "mosher-jordan",
        +        "north-quad",
        +        "south-quad",
        +        "twigs-at-oxford",
        +        "wolverine-village",
        +        "lawyers-club",
        +        "martha-cook"
        +      ],
        +      "type": "string"
        +    },
        +    "maxItems": 10,
        +    "type": "array"
        +  }
        +]
      • addedInput schema / properties / hall / description
        Added value: +"Halls: one, a list, or none for all."
      • removedInput schema / properties / hall / enum
        Removed value: -[
        -  "bursley",
        -  "east-quad",
        -  "markley",
        -  "mosher-jordan",
        -  "north-quad",
        -  "south-quad",
        -  "twigs-at-oxford",
        -  "wolverine-village",
        -  "lawyers-club",
        -  "martha-cook"
        -]
      • removedInput schema / properties / hall / type
        Removed value: -"string"
      • addedOutput schema / properties / asOf
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / failures
        Added value: +{
        +  "items": {
        +    "additionalProperties": false,
        +    "properties": {
        +      "error": {
        +        "type": "string"
        +      },
        +      "hall": {
        +        "enum": [
        +          "bursley",
        +          "east-quad",
        +          "markley",
        +          "mosher-jordan",
        +          "north-quad",
        +          "south-quad",
        +          "twigs-at-oxford",
        +          "wolverine-village",
        +          "lawyers-club",
        +          "martha-cook"
        +        ],
        +        "type": "string"
        +      },
        +      "hallName": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "hall",
        +      "hallName",
        +      "error"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / halls / items / properties / asOf
        Added value: +{
        +  "type": "string"
        +}
      • removedOutput schema / properties / halls / items / properties / regular
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "additionalProperties": false,
        -      "properties": {
        -        "hall": {
        -          "enum": [
        -            "bursley",
        -            "east-quad",
        -            "markley",
        -            "mosher-jordan",
        -            "north-quad",
        -            "south-quad",
        -            "twigs-at-oxford",
        -            "wolverine-village",
        -            "lawyers-club",
        -            "martha-cook"
        -          ],
        -          "type": "string"
        -        },
        -        "name": {
        -          "type": "string"
        -        },
        -        "url": {
        -          "type": [
        -            "string",
        -            "null"
        -          ]
        -        },
        -        "weekly": {
        -          "items": {
        -            "additionalProperties": false,
        -            "properties": {
        -              "closed": {
        -                "type": "boolean"
        -              },
        -              "days": {
        -                "items": {
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              },
        -              "periods": {
        -                "items": {
        -                  "additionalProperties": false,
        -                  "properties": {
        -                    "closed": {
        -                      "type": "boolean"
        -                    },
        -                    "label": {
        -                      "type": "string"
        -                    },
        -                    "times": {
        -                      "type": "string"
        -                    }
        -                  },
        -                  "required": [
        -                    "label",
        -                    "times",
        -                    "closed"
        -                  ],
        -                  "type": "object"
        -                },
        -                "type": "array"
        -              }
        -            },
        -            "required": [
        -              "days",
        -              "periods",
        -              "closed"
        -            ],
        -            "type": "object"
        -          },
        -          "type": "array"
        -        }
        -      },
        -      "required": [
        -        "hall",
        -        "name",
        -        "url",
        -        "weekly"
        -      ],
        -      "type": "object"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ]
        -}
      • changedOutput schema / properties / halls / items / properties / today / items / required
        Previous value: -[
        -  "label",
        -  "times",
        -  "closed"
        -]New value: +[
        +  "label",
        +  "times"
        +]
      • addedOutput schema / properties / halls / items / properties / weekday
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / halls / items / properties / weekly
        Added value: +{
        +  "type": [
        +    "string",
        +    "null"
        +  ]
        +}
      • changedOutput schema / properties / halls / items / required
        Previous value: -[
        -  "hall",
        -  "name",
        -  "date",
        -  "today",
        -  "regular",
        -  "stale"
        -]New value: +[
        +  "hall",
        +  "name",
        +  "date",
        +  "today",
        +  "weekly",
        +  "stale"
        +]
      • addedOutput schema / properties / weekday
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / weekly
        Added value: +{
        +  "additionalProperties": {
        +    "items": {
        +      "additionalProperties": false,
        +      "properties": {
        +        "closed": {
        +          "type": "boolean"
        +        },
        +        "days": {
        +          "items": {
        +            "type": "string"
        +          },
        +          "type": "array"
        +        },
        +        "periods": {
        +          "items": {
        +            "additionalProperties": false,
        +            "properties": {
        +              "closed": {
        +                "type": "boolean"
        +              },
        +              "label": {
        +                "type": "string"
        +              },
        +              "times": {
        +                "type": "string"
        +              }
        +            },
        +            "required": [
        +              "label",
        +              "times"
        +            ],
        +            "type": "object"
        +          },
        +          "type": "array"
        +        }
        +      },
        +      "required": [
        +        "days",
        +        "periods"
        +      ],
        +      "type": "object"
        +    },
        +    "type": "array"
        +  },
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "date",
        -  "halls"
        -]New value: +[
        +  "date",
        +  "halls",
        +  "failures"
        +]
    • Changedget_item_nutrition22 fields changed
      • addedInput schema / additionalProperties
        Added value: +false
      • changedInput schema / properties / date / description
        Previous value: -"Calendar date in YYYY-MM-DD. The site publishes menus for today-3 days to today+14 days."New value: +"Date YYYY-MM-DD. Site publishes today-3..+14 days."
      • addedInput schema / properties / meal
        Added value: +{
        +  "description": "Narrow the search to one meal.",
        +  "enum": [
        +    "Breakfast",
        +    "Brunch",
        +    "Lunch",
        +    "Dinner"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / station
        Added value: +{
        +  "description": "Narrow the search to one station.",
        +  "type": "string"
        +}
      • changedOutput schema / properties / allergens / items / type
        Previous value: -"string"New value: +"number"
      • addedOutput schema / properties / asOf
        Added value: +{
        +  "type": "string"
        +}
      • changedOutput schema / properties / carbonFootprint / anyOf
        Previous value: -[
        -  {
        -    "enum": [
        -      "low",
        -      "medium",
        -      "high"
        -    ],
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "maximum": 3,
        +    "minimum": 1,
        +    "type": "integer"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedOutput schema / properties / hall / enum
        Removed value: -[
        -  "bursley",
        -  "east-quad",
        -  "markley",
        -  "mosher-jordan",
        -  "north-quad",
        -  "south-quad",
        -  "twigs-at-oxford",
        -  "wolverine-village",
        -  "lawyers-club",
        -  "martha-cook"
        -]
      • changedOutput schema / properties / hall / type
        Previous value: -"string"New value: +"number"
      • removedOutput schema / properties / hallName
        Removed value: -{
        -  "type": "string"
        -}
      • addedOutput schema / properties / key
        Added value: +{
        +  "additionalProperties": {
        +    "additionalProperties": {
        +      "type": "string"
        +    },
        +    "propertyNames": {
        +      "type": "string"
        +    },
        +    "type": "object"
        +  },
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • removedOutput schema / properties / meal / enum
        Removed value: -[
        -  "Breakfast",
        -  "Lunch",
        -  "Dinner"
        -]
      • changedOutput schema / properties / meal / type
        Previous value: -"string"New value: +"number"
      • changedOutput schema / properties / nutrition / additionalProperties
        Previous value: -falseNew value: +{}
      • removedOutput schema / properties / nutrition / properties
        Removed value: -{
        -  "calories": {
        -    "type": [
        -      "number",
        -      "null"
        -    ]
        -  },
        -  "cholesterol": {
        -    "type": [
        -      "string",
        -      "null"
        -    ]
        -  },
        -  "dietaryFiber": {
        -    "type": [
        -      "string",
        -      "null"
        -    ]
        -  },
        -  "micronutrients": {
        -    "additionalProperties": {
        -      "type": "string"
        -    },
        -    "propertyNames": {
        -      "type": "string"
        -    },
        -    "type": "object"
        -  },
        -  "protein": {
        -    "type": [
        -      "string",
        -      "null"
        -    ]
        -  },
        -  "saturatedFat": {
        -    "type": [
        -      "string",
        -      "null"
        -    ]
        -  },
        -  "servingSize": {
        -    "type": [
        -      "string",
        -      "null"
        -    ]
        -  },
        -  "sodium": {
        -    "type": [
        -      "string",
        -      "null"
        -    ]
        -  },
        -  "sugars": {
        -    "type": [
        -      "string",
        -      "null"
        -    ]
        -  },
        -  "totalCarbohydrate": {
        -    "type": [
        -      "string",
        -      "null"
        -    ]
        -  },
        -  "totalFat": {
        -    "type": [
        -      "string",
        -      "null"
        -    ]
        -  },
        -  "transFat": {
        -    "type": [
        -      "string",
        -      "null"
        -    ]
        -  }
        -}
      • addedOutput schema / properties / nutrition / propertyNames
        Added value: +{
        +  "type": "string"
        +}
      • removedOutput schema / properties / nutrition / required
        Removed value: -[
        -  "servingSize",
        -  "calories",
        -  "totalFat",
        -  "saturatedFat",
        -  "transFat",
        -  "cholesterol",
        -  "sodium",
        -  "totalCarbohydrate",
        -  "dietaryFiber",
        -  "sugars",
        -  "protein",
        -  "micronutrients"
        -]
      • changedOutput schema / properties / station / type
        Previous value: -"string"New value: +"number"
      • removedOutput schema / properties / traitLabels
        Removed value: -{
        -  "additionalProperties": {
        -    "type": "string"
        -  },
        -  "propertyNames": {
        -    "type": "string"
        -  },
        -  "type": "object"
        -}
      • changedOutput schema / properties / traits / items / type
        Previous value: -"string"New value: +"number"
      • addedOutput schema / properties / units
        Added value: +{
        +  "additionalProperties": {
        +    "type": "string"
        +  },
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "hall",
        -  "hallName",
        -  "date",
        -  "meal",
        -  "station",
        -  "name",
        -  "traits",
        -  "traitLabels",
        -  "allergens",
        -  "mhealthyTier",
        -  "carbonFootprint",
        -  "nutrition",
        -  "warning"
        -]New value: +[
        +  "key",
        +  "hall",
        +  "date",
        +  "meal",
        +  "station",
        +  "name",
        +  "traits",
        +  "allergens",
        +  "mhealthyTier",
        +  "carbonFootprint",
        +  "nutrition",
        +  "warning"
        +]
    • Changedget_menu23 fields changed
      • addedInput schema / additionalProperties
        Added value: +false
      • changedInput schema / properties / date / description
        Previous value: -"Calendar date in YYYY-MM-DD. The site publishes menus for today-3 days to today+14 days."New value: +"The day to read. Defaults to today."
      • addedInput schema / properties / include_nutrients
        Added value: +{
        +  "description": "Nutrients to return, by key/name, or [\"all\"].",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / meal / anyOf
        Added value: +[
        +  {
        +    "enum": [
        +      "Breakfast",
        +      "Brunch",
        +      "Lunch",
        +      "Dinner"
        +    ],
        +    "type": "string"
        +  },
        +  {
        +    "items": {
        +      "enum": [
        +        "Breakfast",
        +        "Brunch",
        +        "Lunch",
        +        "Dinner"
        +      ],
        +      "type": "string"
        +    },
        +    "minItems": 1,
        +    "type": "array"
        +  }
        +]
      • addedInput schema / properties / meal / description
        Added value: +"Keeps only those meals: one name, or a list of them. When it is left out, the meal the hall is serving right now is used."
      • removedInput schema / properties / meal / enum
        Removed value: -[
        -  "Breakfast",
        -  "Lunch",
        -  "Dinner"
        -]
      • removedInput schema / properties / meal / type
        Removed value: -"string"
      • addedInput schema / properties / station
        Added value: +{
        +  "description": "Keeps only that station.",
        +  "type": "string"
        +}
      • addedOutput schema / properties / asOf
        Added value: +{
        +  "type": "string"
        +}
      • removedOutput schema / properties / hallName
        Removed value: -{
        -  "type": "string"
        -}
      • addedOutput schema / properties / key
        Added value: +{
        +  "additionalProperties": {
        +    "additionalProperties": {
        +      "type": "string"
        +    },
        +    "propertyNames": {
        +      "type": "string"
        +    },
        +    "type": "object"
        +  },
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • removedOutput schema / properties / mealLabels
        Removed value: -{
        -  "additionalProperties": {
        -    "type": "string"
        -  },
        -  "propertyNames": {
        -    "type": "string"
        -  },
        -  "type": "object"
        -}
      • removedOutput schema / properties / meals / additionalProperties
        Removed value: -false
      • addedOutput schema / properties / meals / items
        Added value: +{
        +  "additionalProperties": false,
        +  "properties": {
        +    "meal": {
        +      "maximum": 9007199254740991,
        +      "minimum": 1,
        +      "type": "integer"
        +    },
        +    "stations": {
        +      "items": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "items": {
        +            "items": {
        +              "items": {
        +                "anyOf": [
        +                  {
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "string"
        +                  },
        +                  {
        +                    "type": "boolean"
        +                  },
        +                  {
        +                    "type": "null"
        +                  },
        +                  {
        +                    "items": {
        +                      "type": "number"
        +                    },
        +                    "type": "array"
        +                  },
        +                  {
        +                    "items": {
        +                      "type": "string"
        +                    },
        +                    "type": "array"
        +                  },
        +                  {
        +                    "additionalProperties": {
        +                      "type": "number"
        +                    },
        +                    "propertyNames": {
        +                      "type": "string"
        +                    },
        +                    "type": "object"
        +                  }
        +                ]
        +              },
        +              "type": "array"
        +            },
        +            "type": "array"
        +          },
        +          "station": {
        +            "maximum": 9007199254740991,
        +            "minimum": 1,
        +            "type": "integer"
        +          }
        +        },
        +        "required": [
        +          "station",
        +          "items"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "meal",
        +    "stations"
        +  ],
        +  "type": "object"
        +}
      • removedOutput schema / properties / meals / properties
        Removed value: -{
        -  "Breakfast": {
        -    "items": {
        -      "additionalProperties": false,
        -      "properties": {
        -        "items": {
        -          "items": {
        -            "additionalProperties": false,
        -            "properties": {
        -              "allergens": {
        -                "items": {
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              },
        -              "carbonFootprint": {
        -                "anyOf": [
        -                  {
        -                    "enum": [
        -                      "low",
        -                      "medium",
        -                      "high"
        -                    ],
        -                    "type": "string"
        -                  },
        -                  {
        -                    "type": "null"
        -                  }
        -                ]
        -              },
        -              "mhealthyTier": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "name": {
        -                "type": "string"
        -              },
        -              "nutrition": {
        -                "anyOf": [
        -                  {
        -                    "additionalProperties": false,
        -                    "properties": {
        -                      "calories": {
        -                        "type": [
        -                          "number",
        -                          "null"
        -                        ]
        -                      },
        -                      "cholesterol": {
        -                        "type": [
        -                          "string",
        -                          "null"
        -                        ]
        -                      },
        -                      "dietaryFiber": {
        -                        "type": [
        -                          "string",
        -                          "null"
        -                        ]
        -                      },
        -                      "micronutrients": {
        -                        "additionalProperties": {
        -                          "type": "string"
        -                        },
        -                        "propertyNames": {
        -                          "type": "string"
        -                        },
        -                        "type": "object"
        -                      },
        -                      "protein": {
        -                        "type": [
        -                          "string",
        -                          "null"
        -                        ]
        -                      },
        -                      "saturatedFat": {
        -                        "type": [
        -                          "string",
        -                          "null"
        -                        ]
        -                      },
        -                      "servingSize": {
        -                        "type": [
        -                          "string",
        -                          "null"
        -                        ]
        -                      },
        -                      "sodium": {
        -                        "type": [
        -                          "string",
        -                          "null"
        -                        ]
        -                      },
        -                      "sugars": {
        -                        "type": [
        -                          "string",
        -                          "null"
        -                        ]
        -                      },
        -                      "totalCarbohydrate": {
        -                        "type": [
        -                          "string",
        -                          "null"
        -                        ]
        -                      },
        -                      "totalFat": {
        -                        "type": [
        -                          "string",
        -                          "null"
        -                        ]
        -                      },
        -                      "transFat": {
        -                        "type": [
        -                          "string",
        -                          "null"
        -                        ]
        -                      }
        -                    },
        -                    "required": [
        -                      "servingSize",
        -                      "calories",
        -                      "totalFat",
        -                      "saturatedFat",
        -                      "transFat",
        -                      "cholesterol",
        -                      "sodium",
        -                      "totalCarbohydrate",
        -                      "dietaryFiber",
        -                      "sugars",
        -                      "protein",
        -                      "micronutrients"
        -                    ],
        -                    "type": "object"
        -                  },
        -                  {
        -                    "type": "null"
        -                  }
        -                ]
        -              },
        -              "traitLabels": {
        -                "additionalProperties": {
        -                  "type": "string"
        -                },
        -                "propertyNames": {
        -                  "type": "string"
        -                },
        -                "type": "object"
        -              },
        -              "traits": {
        -                "items": {
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            },
        -            "required": [
        -              "name",
        -              "traits",
        -              "traitLabels",
        -              "allergens",
        -              "mhealthyTier",
        -              "carbonFootprint",
        -              "nutrition"
        -            ],
        -            "type": "object"
        -          },
        -          "type": "array"
        -        },
        -        "name": {
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "name",
        -        "items"
        -      ],
        -      "type": "object"
        -    },
        -    "type": "array"
        -  },
        -  "Dinner": {
        -    "items": {
        -      "additionalProperties": false,
        -      "properties": {
        -        "items": {
        -          "items": {
        -            "additionalProperties": false,
        -            "properties": {
        -              "allergens": {
        -                "items": {
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              },
        -              "carbonFootprint": {
        -                "anyOf": [
        -                  {
        -                    "enum": [
        -                      "low",
        -                      "medium",
        -                      "high"
        -                    ],
        -                    "type": "string"
        -                  },
        -                  {
        -                    "type": "null"
        -                  }
        -                ]
        -              },
        -              "mhealthyTier": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "name": {
        -                "type": "string"
        -              },
        -              "nutrition": {
        -                "anyOf": [
        -                  {
        -                    "additionalProperties": false,
        -                    "properties": {
        -                      "calories": {
        -                        "type": [
        -                          "number",
        -                          "null"
        -                        ]
        -                      },
        -                      "cholesterol": {
        -                        "type": [
        -                          "string",
        -                          "null"
        -                        ]
        -                      },
        -                      "dietaryFiber": {
        -                        "type": [
        -                          "string",
        -                          "null"
        -                        ]
        -                      },
        -                      "micronutrients": {
        -                        "additionalProperties": {
        -                          "type": "string"
        -                        },
        -                        "propertyNames": {
        -                          "type": "string"
        -                        },
        -                        "type": "object"
        -                      },
        -                      "protein": {
        -                        "type": [
        -                          "string",
        -                          "null"
        -                        ]
        -                      },
        -                      "saturatedFat": {
        -                        "type": [
        -                          "string",
        -                          "null"
        -                        ]
        -                      },
        -                      "servingSize": {
        -                        "type": [
        -                          "string",
        -                          "null"
        -                        ]
        -                      },
        -                      "sodium": {
        -                        "type": [
        -                          "string",
        -                          "null"
        -                        ]
        -                      },
        -                      "sugars": {
        -                        "type": [
        -                          "string",
        -                          "null"
        -                        ]
        -                      },
        -                      "totalCarbohydrate": {
        -                        "type": [
        -                          "string",
        -                          "null"
        -                        ]
        -                      },
        -                      "totalFat": {
        -                        "type": [
        -                          "string",
        -                          "null"
        -                        ]
        -                      },
        -                      "transFat": {
        -                        "type": [
        -                          "string",
        -                          "null"
        -                        ]
        -                      }
        -                    },
        -                    "required": [
        -                      "servingSize",
        -                      "calories",
        -                      "totalFat",
        -                      "saturatedFat",
        -                      "transFat",
        -                      "cholesterol",
        -                      "sodium",
        -                      "totalCarbohydrate",
        -                      "dietaryFiber",
        -                      "sugars",
        -                      "protein",
        -                      "micronutrients"
        -                    ],
        -                    "type": "object"
        -                  },
        -                  {
        -                    "type": "null"
        -                  }
        -                ]
        -              },
        -              "traitLabels": {
        -                "additionalProperties": {
        -                  "type": "string"
        -                },
        -                "propertyNames": {
        -                  "type": "string"
        -                },
        -                "type": "object"
        -              },
        -              "traits": {
        -                "items": {
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            },
        -            "required": [
        -              "name",
        -              "traits",
        -              "traitLabels",
        -              "allergens",
        -              "mhealthyTier",
        -              "carbonFootprint",
        -              "nutrition"
        -            ],
        -            "type": "object"
        -          },
        -          "type": "array"
        -        },
        -        "name": {
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "name",
        -        "items"
        -      ],
        -      "type": "object"
        -    },
        -    "type": "array"
        -  },
        -  "Lunch": {
        -    "items": {
        -      "additionalProperties": false,
        -      "properties": {
        -        "items": {
        -          "items": {
        -            "additionalProperties": false,
        -            "properties": {
        -              "allergens": {
        -                "items": {
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              },
        -              "carbonFootprint": {
        -                "anyOf": [
        -                  {
        -                    "enum": [
        -                      "low",
        -                      "medium",
        -                      "high"
        -                    ],
        -                    "type": "string"
        -                  },
        -                  {
        -                    "type": "null"
        -                  }
        -                ]
        -              },
        -              "mhealthyTier": {
        -                "type": [
        -                  "number",
        -                  "null"
        -                ]
        -              },
        -              "name": {
        -                "type": "string"
        -              },
        -              "nutrition": {
        -                "anyOf": [
        -                  {
        -                    "additionalProperties": false,
        -                    "properties": {
        -                      "calories": {
        -                        "type": [
        -                          "number",
        -                          "null"
        -                        ]
        -                      },
        -                      "cholesterol": {
        -                        "type": [
        -                          "string",
        -                          "null"
        -                        ]
        -                      },
        -                      "dietaryFiber": {
        -                        "type": [
        -                          "string",
        -                          "null"
        -                        ]
        -                      },
        -                      "micronutrients": {
        -                        "additionalProperties": {
        -                          "type": "string"
        -                        },
        -                        "propertyNames": {
        -                          "type": "string"
        -                        },
        -                        "type": "object"
        -                      },
        -                      "protein": {
        -                        "type": [
        -                          "string",
        -                          "null"
        -                        ]
        -                      },
        -                      "saturatedFat": {
        -                        "type": [
        -                          "string",
        -                          "null"
        -                        ]
        -                      },
        -                      "servingSize": {
        -                        "type": [
        -                          "string",
        -                          "null"
        -                        ]
        -                      },
        -                      "sodium": {
        -                        "type": [
        -                          "string",
        -                          "null"
        -                        ]
        -                      },
        -                      "sugars": {
        -                        "type": [
        -                          "string",
        -                          "null"
        -                        ]
        -                      },
        -                      "totalCarbohydrate": {
        -                        "type": [
        -                          "string",
        -                          "null"
        -                        ]
        -                      },
        -                      "totalFat": {
        -                        "type": [
        -                          "string",
        -                          "null"
        -                        ]
        -                      },
        -                      "transFat": {
        -                        "type": [
        -                          "string",
        -                          "null"
        -                        ]
        -                      }
        -                    },
        -                    "required": [
        -                      "servingSize",
        -                      "calories",
        -                      "totalFat",
        -                      "saturatedFat",
        -                      "transFat",
        -                      "cholesterol",
        -                      "sodium",
        -                      "totalCarbohydrate",
        -                      "dietaryFiber",
        -                      "sugars",
        -                      "protein",
        -                      "micronutrients"
        -                    ],
        -                    "type": "object"
        -                  },
        -                  {
        -                    "type": "null"
        -                  }
        -                ]
        -              },
        -              "traitLabels": {
        -                "additionalProperties": {
        -                  "type": "string"
        -                },
        -                "propertyNames": {
        -                  "type": "string"
        -                },
        -                "type": "object"
        -              },
        -              "traits": {
        -                "items": {
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            },
        -            "required": [
        -              "name",
        -              "traits",
        -              "traitLabels",
        -              "allergens",
        -              "mhealthyTier",
        -              "carbonFootprint",
        -              "nutrition"
        -            ],
        -            "type": "object"
        -          },
        -          "type": "array"
        -        },
        -        "name": {
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "name",
        -        "items"
        -      ],
        -      "type": "object"
        -    },
        -    "type": "array"
        -  }
        -}
      • removedOutput schema / properties / meals / required
        Removed value: -[
        -  "Breakfast",
        -  "Lunch",
        -  "Dinner"
        -]
      • changedOutput schema / properties / meals / type
        Previous value: -"object"New value: +"array"
      • addedOutput schema / properties / note
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / nutrients
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • changedOutput schema / properties / renderedDate / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +"string"
      • addedOutput schema / properties / units
        Added value: +{
        +  "additionalProperties": {
        +    "type": "string"
        +  },
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / unknownMealLabels
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "hall",
        -  "hallName",
        -  "date",
        -  "mealLabels",
        -  "meals",
        -  "renderedDate",
        -  "totalStations",
        -  "totalItems",
        -  "stale"
        -]New value: +[
        +  "hall",
        +  "date",
        +  "key",
        +  "meals",
        +  "unknownMealLabels",
        +  "totalStations",
        +  "totalItems",
        +  "stale"
        +]
    • Changedlist_locations13 fields changed
      • addedInput schema / additionalProperties
        Added value: +false
      • changedInput schema / properties / date / description
        Previous value: -"Calendar date in YYYY-MM-DD. The site publishes menus for today-3 days to today+14 days."New value: +"The day to read. Defaults to today."
      • addedInput schema / properties / hall
        Added value: +{
        +  "description": "Keep only this hall.",
        +  "enum": [
        +    "bursley",
        +    "east-quad",
        +    "markley",
        +    "mosher-jordan",
        +    "north-quad",
        +    "south-quad",
        +    "twigs-at-oxford",
        +    "wolverine-village",
        +    "lawyers-club",
        +    "martha-cook"
        +  ],
        +  "type": "string"
        +}
      • addedOutput schema / properties / locations / items / properties / asOf
        Added value: +{
        +  "type": "string"
        +}
      • removedOutput schema / properties / locations / items / properties / date
        Removed value: -{
        -  "type": "string"
        -}
      • removedOutput schema / properties / locations / items / properties / mapUrl
        Removed value: -{
        -  "type": [
        -    "string",
        -    "null"
        -  ]
        -}
      • removedOutput schema / properties / locations / items / properties / meals
        Removed value: -{
        -  "items": {
        -    "enum": [
        -      "Breakfast",
        -      "Lunch",
        -      "Dinner"
        -    ],
        -    "type": "string"
        -  },
        -  "type": "array"
        -}
      • removedOutput schema / properties / locations / items / properties / path
        Removed value: -{
        -  "type": "string"
        -}
      • changedOutput schema / properties / locations / items / properties / today / items / required
        Previous value: -[
        -  "label",
        -  "times",
        -  "closed"
        -]New value: +[
        +  "label",
        +  "times"
        +]
      • changedOutput schema / properties / locations / items / required
        Previous value: -[
        -  "id",
        -  "name",
        -  "path",
        -  "url",
        -  "residentsOnly",
        -  "glutenFreePantry",
        -  "address",
        -  "phone",
        -  "email",
        -  "mapUrl",
        -  "meals",
        -  "date",
        -  "today",
        -  "openNow",
        -  "stale"
        -]New value: +[
        +  "id",
        +  "name",
        +  "url",
        +  "residentsOnly",
        +  "glutenFreePantry",
        +  "address",
        +  "phone",
        +  "email",
        +  "today",
        +  "openNow",
        +  "stale"
        +]
      • addedOutput schema / properties / mapUrlTemplate
        Added value: +{
        +  "type": "string"
        +}
      • removedOutput schema / properties / warning
        Removed value: -{
        -  "type": "string"
        -}
      • changedOutput schema / required
        Previous value: -[
        -  "date",
        -  "locations",
        -  "failures",
        -  "warning"
        -]New value: +[
        +  "date",
        +  "locations",
        +  "failures"
        +]
    • Addedlist_nutrition_fields
    • Removedsearch_dishes
  3. 7 tool updatesv0.1.0
    • First observedfilter_dishes
    • First observedfind_open_now
    • First observedget_hours
    • First observedget_item_nutrition
    • First observedget_menu
    • First observedlist_locations
    • First observedsearch_dishes

TDQS

A3.9/5.0

Scored across 8 tools

Disambiguation3/5

Three tools (list_locations, get_hours, find_open_now) all return halls with service periods, and their boundaries rely on subtle distinctions like openNow vs. time-of-day filtering vs. weekly schedule. get_menu vs filter_dishes and get_item_nutrition vs list_nutrition_fields are better separated thanks to explicit cross-references in the descriptions, but the hours/location cluster remains overlapping.

Naming Consistency5/5

All eight tools follow a consistent snake_case verb_noun pattern (get_menu, list_locations, filter_dishes, find_open_now), with verb choice reflecting intent (get for single-resource, list for enumeration, filter/find for queries). No naming style mixing.

Tool Count5/5

Eight tools is well-scoped for a dining-hall domain: menu retrieval, filtering, hours, locations, occupancy, and nutrition each get focused coverage without redundancy in count. No tool feels like filler.

Completeness4/5

The surface covers menus, filtering, nutrition fields/panels, hours, location status, and occupancy, with cafes/markets/prices explicitly declared out of scope. Minor gaps: no multi-hall raw menu retrieval (only filter_dishes sweep) and dish lookup is name-based only, but agents can work around these.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Provides real-time access to menus from all six MIT Bon Appétit dining halls. It enables users to query daily or weekly schedules and filter options by specific dietary requirements such as vegan, halal, or gluten-free.
    47 npm
    1
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables querying Yale Hospitality dining menus, listing residential colleges, fetching meal offerings, and searching dishes across colleges via MCP tools.
    MIT