umich-dining-mcp
Use this MCP server to answer live University of Michigan dining questions and inspect menus, nutrition, hours, allergens, and occupancy.
List the ten dining halls with contact/address details, daily service periods, open-now status, and gluten-free pantry availability.
Get a hall’s menu by date, meal, and station, including dishes, coded traits/allergens, nutrient-density tier, calories, serving size, and optional nutrients.
Search dishes by name across halls and dates, or filter by allergens, traits, nutrient ranges, calories, sodium, carbon footprint, nutrient-density tier, meal, and station.
List supported nutrition fields, units, alternative threshold units, and Daily Value bases for micronutrients.
Get daily service hours plus regular weekly schedules, and find which halls are open at a given or current campus-local time.
Get a full nutrition panel for one dish, including traits, allergens, tier, carbon footprint, and nutrition values.
Check real-time occupancy for sensor-equipped dining halls.
Use live cached data with stale/failure reporting, range-query coverage, and allergen advisory notes.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@umich-dining-mcpWhich dining halls are open right now?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
umich-dining-mcp
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 |
Install
npm install -g umich-dining-mcpor run it without installing anything:
npx -y umich-dining-mcpClaude Code
claude mcp add umich-dining -- npx -y umich-dining-mcpCursor
~/.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 |
| 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. |
| 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. |
| 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 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. |
| The supported nutrient names, their units and the Daily Value basis of the micronutrients. |
| The service periods of a day plus the regular weekly schedule. A hall that cannot be read is reported in |
| Which halls are serving at a given time of day. |
| The full nutrition panel of a single dish. |
Resources
Resource | Content |
| The hall registry as JSON, with the code of every hall. |
| 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.
mhealthyTieris 1 (Nutrient Dense Low) to 5 (Nutrient Dense High). The scale is fixed and described in the tool descriptions and inumich://taxonomy.A row carries the carbon tier (
carbonFootprint) only when the call constrains it withmax_carbonor sorts bycarbonFootprint; otherwise it is left out to keep the row small.The
traitsarray carries the six boolean traits only; the density tier is lifted into its own numeric field.The
unitsmap 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 is2.7in 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
limittakes 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 carriesdateRangeand each row carries thedatesit appeared on.A dish without a published value is reported as
null, never as zero. Atraceor 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 |
| South Quad |
| East Quad |
| Twigs at Oxford |
| Markley |
| Wolverine Village |
| Mosher-Jordan |
| Lawyers Club |
| North Quad |
| 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 |
| Keeps only the dishes that do not carry any of the listed allergens. |
| Keeps only the dishes that carry every listed trait. |
| Minimum nutrient-density tier, 1..5 (3 = "Nutrient Dense Medium or better"). |
| Maximum carbon footprint: |
| A range per nutrient, e.g. |
| The nutrients to return, by canonical key or by published name, or |
| A case-insensitive substring of the dish name. |
| Narrow the sweep to one meal or one station. |
| 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 |
|
| The User-Agent to use. |
|
| The site to read. |
|
| The time zone of the campus: the day the site publishes and the mealtimes are read in it. |
|
| Per-request timeout. |
|
| Retries after the first attempt. |
|
| Requests in flight. |
|
| Minimum gap between requests. |
|
| Cache lifetime of today's menu. |
|
| Cache lifetime of a future menu. |
|
| Cache lifetime of a past menu. |
|
| Cache lifetime of the weekly schedule. |
|
| Upstream pages a single range query may fetch. |
|
| The persistent cache. |
|
| How long a cache entry is kept. |
|
| The largest the persistent cache may grow. |
|
| 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.3is 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 toolsfilter_dishesFilter dishesBRead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| to | No | The last day of a range to filter. Defaults to the last published day. | |
| date | No | A single day to filter. Cannot be combined with from/to. | |
| from | No | The first day of a range to filter. | |
| hall | No | Halls: one, a list, or none for all. | |
| meal | No | Keeps only that meal. | |
| limit | No | Rows to return (default 50, max 500). | |
| query | No | A case-insensitive substring of the dish name. | |
| offset | No | Pages of the range to skip. | |
| sort_by | No | 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. | |
| station | No | Keeps only that station. | |
| nutrients | No | Range per nutrient, e.g. {"protein":{"min":20,"unit":"g"}}. A constraint drops dishes with no value. | |
| max_carbon | No | The highest acceptable carbon footprint: 1 (low), 2 (medium) or 3 (high). The dishes the site did not tag are dropped. | |
| sort_order | No | The direction of the sort. It defaults to desc, so the biggest value comes first. | |
| min_mhealthy | No | The lowest acceptable nutrient-density tier. The dishes the site did not tag are dropped. | |
| require_traits | No | Keeps only the dishes that carry every one of these traits. | |
| exclude_allergens | No | Keeps only the dishes that carry none of these allergens. | |
| include_nutrients | No | Nutrients to return, by key/name, or ["all"]. |
Output Schema
| Name | Required | Description |
|---|---|---|
| key | Yes | |
| asOf | No | |
| date | No | |
| note | No | |
| flags | No | |
| stale | Yes | |
| units | No | |
| filter | No | |
| noMenu | No | |
| matches | Yes | |
| coverage | No | |
| failures | Yes | |
| dateRange | No | |
| nutrients | No | |
| truncated | Yes | |
| totalMatches | Yes |
TDQS
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.
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.
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.
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.
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.
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 nowARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| at | No | The campus-local time of day to look at. Defaults to the current time. | |
| date | No | The day to look at. Defaults to today. |
Output Schema
| Name | Required | Description |
|---|---|---|
| at | Yes | |
| asOf | No | |
| date | Yes | |
| open | Yes | |
| closed | Yes | |
| failures | Yes |
TDQS
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.
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.
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.
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.
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.
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 occupancyARead-onlyIdempotentInspect
Real-time occupancy for monitored dining halls: current count, patron flow, total capacity, and percent full. Only halls with sensors are returned.
| Name | Required | Description | Default |
|---|---|---|---|
| hall | No | Keep only this hall, or a list of halls. |
Output Schema
| Name | Required | Description |
|---|---|---|
| readings | Yes | |
| observedAt | Yes |
TDQS
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.
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.
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.
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.
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.
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 hoursARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| date | No | The day to read. Defaults to today. | |
| hall | No | Halls: one, a list, or none for all. |
Output Schema
| Name | Required | Description |
|---|---|---|
| asOf | No | |
| date | Yes | |
| halls | Yes | |
| weekly | No | |
| weekday | No | |
| failures | Yes |
TDQS
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.
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.
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.
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.
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.
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 panelARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| date | No | Date YYYY-MM-DD. Site publishes today-3..+14 days. | |
| hall | Yes | The dining hall to read. | |
| item | Yes | The dish name. | |
| meal | No | Narrow the search to one meal. | |
| station | No | Narrow the search to one station. |
Output Schema
| Name | Required | Description |
|---|---|---|
| key | Yes | |
| asOf | No | |
| date | Yes | |
| hall | Yes | |
| meal | Yes | |
| name | Yes | |
| units | No | |
| traits | Yes | |
| station | Yes | |
| warning | Yes | |
| allergens | Yes | |
| nutrition | Yes | |
| mhealthyTier | Yes | |
| carbonFootprint | Yes |
TDQS
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.
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.
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.
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.
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.
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.
list_locationsList dining hallsARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| date | No | The day to read. Defaults to today. | |
| hall | No | Keep only this hall. |
Output Schema
| Name | Required | Description |
|---|---|---|
| date | Yes | |
| failures | Yes | |
| locations | Yes | |
| mapUrlTemplate | No |
TDQS
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.
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.
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.
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.
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.
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 fieldsARead-onlyIdempotentInspect
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".
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| notes | Yes | |
| fields | Yes | |
| sortFields | Yes | |
| acceptedUnits | Yes | |
| micronutrients | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, so the safety profile is covered; the description 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.
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.
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.
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.
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.
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.
6 tool updates
v2.0.0- Changed
filter_dishes2 fields changed- changed
Input schema / properties / hall / anyOfPrevious 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" + } +] - removed
Input schema / properties / require_traits / items / enumRemoved value: -[ - "carbonhigh", - "carbonlow", - "carbonmedium", - "glutenfree", - "halal", - "kosher", - "mhealthy1", - "mhealthy2", - "mhealthy3", - "mhealthy4", - "mhealthy5", - "spicy", - "vegan", - "vegetarian" -]
- Added
get_dining_occupancy - Changed
get_hours1 field changed- changed
Input schema / properties / hall / anyOfPrevious 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" + } +]
- Changed
get_item_nutrition1 field changed- removed
Input schema / properties / hall / enumRemoved value: -[ - "bursley", - "east-quad", - "markley", - "mosher-jordan", - "north-quad", - "south-quad", - "twigs-at-oxford", - "wolverine-village", - "lawyers-club", - "martha-cook" -]
- Changed
get_menu1 field changed- removed
Input schema / properties / hall / enumRemoved value: -[ - "bursley", - "east-quad", - "markley", - "mosher-jordan", - "north-quad", - "south-quad", - "twigs-at-oxford", - "wolverine-village", - "lawyers-club", - "martha-cook" -]
- Changed
list_locations1 field changed- removed
Input schema / properties / hall / enumRemoved value: -[ - "bursley", - "east-quad", - "markley", - "mosher-jordan", - "north-quad", - "south-quad", - "twigs-at-oxford", - "wolverine-village", - "lawyers-club", - "martha-cook" -]
8 tool updates
v0.1.1- Changed
filter_dishes46 fields changed- added
Input schema / additionalPropertiesAdded value: +false - changed
Input schema / properties / date / descriptionPrevious 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." - added
Input schema / properties / exclude_allergens / descriptionAdded value: +"Keeps only the dishes that carry none of these allergens." - added
Input schema / properties / fromAdded value: +{ + "description": "The first day of a range to filter.", + "pattern": "^\\d{4}-\\d{2}-\\d{2}$", + "type": "string" +} - added
Input schema / properties / hall / anyOfAdded 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" + } +] - added
Input schema / properties / hall / descriptionAdded value: +"Halls: one, a list, or none for all." - removed
Input schema / properties / hall / enumRemoved value: -[ - "bursley", - "east-quad", - "markley", - "mosher-jordan", - "north-quad", - "south-quad", - "twigs-at-oxford", - "wolverine-village", - "lawyers-club", - "martha-cook" -] - removed
Input schema / properties / hall / typeRemoved value: -"string" - added
Input schema / properties / include_nutrientsAdded value: +{ + "description": "Nutrients to return, by key/name, or [\"all\"].", + "items": { + "type": "string" + }, + "type": "array" +} - added
Input schema / properties / limit / descriptionAdded value: +"Rows to return (default 50, max 500)." - removed
Input schema / properties / max_caloriesRemoved value: -{ - "minimum": 0, - "type": "number" -} - added
Input schema / properties / max_carbon / descriptionAdded value: +"The highest acceptable carbon footprint: 1 (low), 2 (medium) or 3 (high). The dishes the site did not tag are dropped." - removed
Input schema / properties / max_carbon / enumRemoved value: -[ - "low", - "medium", - "high" -] - added
Input schema / properties / max_carbon / maximumAdded value: +3 - added
Input schema / properties / max_carbon / minimumAdded value: +1 - changed
Input schema / properties / max_carbon / typePrevious value: -"string"New value: +"integer" - removed
Input schema / properties / max_sodium_mgRemoved value: -{ - "minimum": 0, - "type": "number" -} - added
Input schema / properties / mealAdded value: +{ + "description": "Keeps only that meal.", + "enum": [ + "Breakfast", + "Brunch", + "Lunch", + "Dinner" + ], + "type": "string" +} - added
Input schema / properties / min_mhealthy / descriptionAdded value: +"The lowest acceptable nutrient-density tier. The dishes the site did not tag are dropped." - added
Input schema / properties / nutrientsAdded 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" +} - added
Input schema / properties / offsetAdded value: +{ + "description": "Pages of the range to skip.", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" +} - added
Input schema / properties / queryAdded value: +{ + "description": "A case-insensitive substring of the dish name.", + "type": "string" +} - added
Input schema / properties / require_traits / descriptionAdded value: +"Keeps only the dishes that carry every one of these traits." - added
Input schema / properties / sort_byAdded 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" +} - added
Input schema / properties / sort_orderAdded value: +{ + "description": "The direction of the sort. It defaults to desc, so the biggest value comes first.", + "enum": [ + "asc", + "desc" + ], + "type": "string" +} - added
Input schema / properties / stationAdded value: +{ + "description": "Keeps only that station.", + "type": "string" +} - added
Input schema / properties / toAdded 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" +} - added
Output schema / properties / asOfAdded value: +{ + "type": "string" +} - added
Output schema / properties / coverageAdded 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" +} - added
Output schema / properties / dateRangeAdded value: +{ + "additionalProperties": false, + "properties": { + "from": { + "type": "string" + }, + "to": { + "type": "string" + } + }, + "required": [ + "from", + "to" + ], + "type": "object" +} - added
Output schema / properties / filterAdded value: +{ + "additionalProperties": {}, + "propertyNames": { + "type": "string" + }, + "type": "object" +} - added
Output schema / properties / flagsAdded value: +{ + "additionalProperties": {}, + "propertyNames": { + "type": "string" + }, + "type": "object" +} - added
Output schema / properties / keyAdded value: +{ + "additionalProperties": { + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "propertyNames": { + "type": "string" + }, + "type": "object" +} - removed
Output schema / properties / matches / items / additionalPropertiesRemoved value: -false - added
Output schema / properties / matches / items / itemsAdded 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" + } + ] +} - removed
Output schema / properties / matches / items / propertiesRemoved 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" - } -} - removed
Output schema / properties / matches / items / requiredRemoved value: -[ - "hall", - "hallName", - "date", - "meal", - "station", - "name", - "traits", - "traitLabels", - "allergens", - "mhealthyTier", - "carbonFootprint", - "calories", - "sodiumMg" -] - changed
Output schema / properties / matches / items / typePrevious value: -"object"New value: +"array" - added
Output schema / properties / noMenuAdded value: +{ + "items": { + "additionalProperties": false, + "properties": { + "date": { + "type": "string" + }, + "hall": { + "type": "string" + } + }, + "required": [ + "hall", + "date" + ], + "type": "object" + }, + "type": "array" +} - added
Output schema / properties / noteAdded value: +{ + "type": "string" +} - added
Output schema / properties / nutrientsAdded value: +{ + "items": { + "type": "string" + }, + "type": "array" +} - added
Output schema / properties / staleAdded value: +{ + "type": "boolean" +} - added
Output schema / properties / truncatedAdded value: +{ + "type": "boolean" +} - added
Output schema / properties / unitsAdded value: +{ + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + }, + "type": "object" +} - removed
Output schema / properties / warningRemoved value: -{ - "type": "string" -} - changed
Output schema / requiredPrevious value: -[ - "date", - "totalMatches", - "matches", - "failures", - "warning" -]New value: +[ + "key", + "totalMatches", + "truncated", + "stale", + "matches", + "failures" +]
- Changed
find_open_now22 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / atAdded 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" +} - added
Input schema / properties / dateAdded value: +{ + "description": "The day to look at. Defaults to today.", + "pattern": "^\\d{4}-\\d{2}-\\d{2}$", + "type": "string" +} - added
Output schema / properties / asOfAdded value: +{ + "type": "string" +} - added
Output schema / properties / atAdded value: +{ + "type": "string" +} - removed
Output schema / properties / closed / items / additionalPropertiesRemoved value: -false - added
Output schema / properties / closed / items / enumAdded value: +[ + "bursley", + "east-quad", + "markley", + "mosher-jordan", + "north-quad", + "south-quad", + "twigs-at-oxford", + "wolverine-village", + "lawyers-club", + "martha-cook" +] - removed
Output schema / properties / closed / items / propertiesRemoved 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" - } -} - removed
Output schema / properties / closed / items / requiredRemoved value: -[ - "id", - "name", - "path", - "url", - "residentsOnly", - "glutenFreePantry", - "address", - "phone", - "email", - "mapUrl", - "meals", - "date", - "today", - "openNow", - "stale" -] - changed
Output schema / properties / closed / items / typePrevious value: -"object"New value: +"string" - removed
Output schema / properties / open / items / properties / addressRemoved value: -{ - "type": [ - "string", - "null" - ] -} - added
Output schema / properties / open / items / properties / asOfAdded value: +{ + "type": "string" +} - removed
Output schema / properties / open / items / properties / dateRemoved value: -{ - "type": "string" -} - removed
Output schema / properties / open / items / properties / emailRemoved value: -{ - "type": [ - "string", - "null" - ] -} - removed
Output schema / properties / open / items / properties / mapUrlRemoved value: -{ - "type": [ - "string", - "null" - ] -} - removed
Output schema / properties / open / items / properties / mealsRemoved value: -{ - "items": { - "enum": [ - "Breakfast", - "Lunch", - "Dinner" - ], - "type": "string" - }, - "type": "array" -} - removed
Output schema / properties / open / items / properties / pathRemoved value: -{ - "type": "string" -} - removed
Output schema / properties / open / items / properties / phoneRemoved value: -{ - "type": [ - "string", - "null" - ] -} - changed
Output schema / properties / open / items / properties / today / items / requiredPrevious value: -[ - "label", - "times", - "closed" -]New value: +[ + "label", + "times" +] - removed
Output schema / properties / open / items / properties / urlRemoved value: -{ - "type": "string" -} - changed
Output schema / properties / open / items / requiredPrevious 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" +] - changed
Output schema / requiredPrevious value: -[ - "date", - "open", - "closed", - "failures" -]New value: +[ + "date", + "at", + "open", + "closed", + "failures" +]
- Changed
get_hours17 fields changed- added
Input schema / additionalPropertiesAdded value: +false - changed
Input schema / properties / date / descriptionPrevious 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." - added
Input schema / properties / hall / anyOfAdded 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" + } +] - added
Input schema / properties / hall / descriptionAdded value: +"Halls: one, a list, or none for all." - removed
Input schema / properties / hall / enumRemoved value: -[ - "bursley", - "east-quad", - "markley", - "mosher-jordan", - "north-quad", - "south-quad", - "twigs-at-oxford", - "wolverine-village", - "lawyers-club", - "martha-cook" -] - removed
Input schema / properties / hall / typeRemoved value: -"string" - added
Output schema / properties / asOfAdded value: +{ + "type": "string" +} - added
Output schema / properties / failuresAdded 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" +} - added
Output schema / properties / halls / items / properties / asOfAdded value: +{ + "type": "string" +} - removed
Output schema / properties / halls / items / properties / regularRemoved 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" - } - ] -} - changed
Output schema / properties / halls / items / properties / today / items / requiredPrevious value: -[ - "label", - "times", - "closed" -]New value: +[ + "label", + "times" +] - added
Output schema / properties / halls / items / properties / weekdayAdded value: +{ + "type": "string" +} - added
Output schema / properties / halls / items / properties / weeklyAdded value: +{ + "type": [ + "string", + "null" + ] +} - changed
Output schema / properties / halls / items / requiredPrevious value: -[ - "hall", - "name", - "date", - "today", - "regular", - "stale" -]New value: +[ + "hall", + "name", + "date", + "today", + "weekly", + "stale" +] - added
Output schema / properties / weekdayAdded value: +{ + "type": "string" +} - added
Output schema / properties / weeklyAdded 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" +} - changed
Output schema / requiredPrevious value: -[ - "date", - "halls" -]New value: +[ + "date", + "halls", + "failures" +]
- Changed
get_item_nutrition22 fields changed- added
Input schema / additionalPropertiesAdded value: +false - changed
Input schema / properties / date / descriptionPrevious 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." - added
Input schema / properties / mealAdded value: +{ + "description": "Narrow the search to one meal.", + "enum": [ + "Breakfast", + "Brunch", + "Lunch", + "Dinner" + ], + "type": "string" +} - added
Input schema / properties / stationAdded value: +{ + "description": "Narrow the search to one station.", + "type": "string" +} - changed
Output schema / properties / allergens / items / typePrevious value: -"string"New value: +"number" - added
Output schema / properties / asOfAdded value: +{ + "type": "string" +} - changed
Output schema / properties / carbonFootprint / anyOfPrevious value: -[ - { - "enum": [ - "low", - "medium", - "high" - ], - "type": "string" - }, - { - "type": "null" - } -]New value: +[ + { + "maximum": 3, + "minimum": 1, + "type": "integer" + }, + { + "type": "null" + } +] - removed
Output schema / properties / hall / enumRemoved value: -[ - "bursley", - "east-quad", - "markley", - "mosher-jordan", - "north-quad", - "south-quad", - "twigs-at-oxford", - "wolverine-village", - "lawyers-club", - "martha-cook" -] - changed
Output schema / properties / hall / typePrevious value: -"string"New value: +"number" - removed
Output schema / properties / hallNameRemoved value: -{ - "type": "string" -} - added
Output schema / properties / keyAdded value: +{ + "additionalProperties": { + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "propertyNames": { + "type": "string" + }, + "type": "object" +} - removed
Output schema / properties / meal / enumRemoved value: -[ - "Breakfast", - "Lunch", - "Dinner" -] - changed
Output schema / properties / meal / typePrevious value: -"string"New value: +"number" - changed
Output schema / properties / nutrition / additionalPropertiesPrevious value: -falseNew value: +{} - removed
Output schema / properties / nutrition / propertiesRemoved 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" - ] - } -} - added
Output schema / properties / nutrition / propertyNamesAdded value: +{ + "type": "string" +} - removed
Output schema / properties / nutrition / requiredRemoved value: -[ - "servingSize", - "calories", - "totalFat", - "saturatedFat", - "transFat", - "cholesterol", - "sodium", - "totalCarbohydrate", - "dietaryFiber", - "sugars", - "protein", - "micronutrients" -] - changed
Output schema / properties / station / typePrevious value: -"string"New value: +"number" - removed
Output schema / properties / traitLabelsRemoved value: -{ - "additionalProperties": { - "type": "string" - }, - "propertyNames": { - "type": "string" - }, - "type": "object" -} - changed
Output schema / properties / traits / items / typePrevious value: -"string"New value: +"number" - added
Output schema / properties / unitsAdded value: +{ + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + }, + "type": "object" +} - changed
Output schema / requiredPrevious 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" +]
- Changed
get_menu23 fields changed- added
Input schema / additionalPropertiesAdded value: +false - changed
Input schema / properties / date / descriptionPrevious 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." - added
Input schema / properties / include_nutrientsAdded value: +{ + "description": "Nutrients to return, by key/name, or [\"all\"].", + "items": { + "type": "string" + }, + "type": "array" +} - added
Input schema / properties / meal / anyOfAdded value: +[ + { + "enum": [ + "Breakfast", + "Brunch", + "Lunch", + "Dinner" + ], + "type": "string" + }, + { + "items": { + "enum": [ + "Breakfast", + "Brunch", + "Lunch", + "Dinner" + ], + "type": "string" + }, + "minItems": 1, + "type": "array" + } +] - added
Input schema / properties / meal / descriptionAdded 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." - removed
Input schema / properties / meal / enumRemoved value: -[ - "Breakfast", - "Lunch", - "Dinner" -] - removed
Input schema / properties / meal / typeRemoved value: -"string" - added
Input schema / properties / stationAdded value: +{ + "description": "Keeps only that station.", + "type": "string" +} - added
Output schema / properties / asOfAdded value: +{ + "type": "string" +} - removed
Output schema / properties / hallNameRemoved value: -{ - "type": "string" -} - added
Output schema / properties / keyAdded value: +{ + "additionalProperties": { + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "propertyNames": { + "type": "string" + }, + "type": "object" +} - removed
Output schema / properties / mealLabelsRemoved value: -{ - "additionalProperties": { - "type": "string" - }, - "propertyNames": { - "type": "string" - }, - "type": "object" -} - removed
Output schema / properties / meals / additionalPropertiesRemoved value: -false - added
Output schema / properties / meals / itemsAdded 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" +} - removed
Output schema / properties / meals / propertiesRemoved 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" - } -} - removed
Output schema / properties / meals / requiredRemoved value: -[ - "Breakfast", - "Lunch", - "Dinner" -] - changed
Output schema / properties / meals / typePrevious value: -"object"New value: +"array" - added
Output schema / properties / noteAdded value: +{ + "type": "string" +} - added
Output schema / properties / nutrientsAdded value: +{ + "items": { + "type": "string" + }, + "type": "array" +} - changed
Output schema / properties / renderedDate / typePrevious value: -[ - "string", - "null" -]New value: +"string" - added
Output schema / properties / unitsAdded value: +{ + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + }, + "type": "object" +} - added
Output schema / properties / unknownMealLabelsAdded value: +{ + "items": { + "type": "string" + }, + "type": "array" +} - changed
Output schema / requiredPrevious value: -[ - "hall", - "hallName", - "date", - "mealLabels", - "meals", - "renderedDate", - "totalStations", - "totalItems", - "stale" -]New value: +[ + "hall", + "date", + "key", + "meals", + "unknownMealLabels", + "totalStations", + "totalItems", + "stale" +]
- Changed
list_locations13 fields changed- added
Input schema / additionalPropertiesAdded value: +false - changed
Input schema / properties / date / descriptionPrevious 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." - added
Input schema / properties / hallAdded 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" +} - added
Output schema / properties / locations / items / properties / asOfAdded value: +{ + "type": "string" +} - removed
Output schema / properties / locations / items / properties / dateRemoved value: -{ - "type": "string" -} - removed
Output schema / properties / locations / items / properties / mapUrlRemoved value: -{ - "type": [ - "string", - "null" - ] -} - removed
Output schema / properties / locations / items / properties / mealsRemoved value: -{ - "items": { - "enum": [ - "Breakfast", - "Lunch", - "Dinner" - ], - "type": "string" - }, - "type": "array" -} - removed
Output schema / properties / locations / items / properties / pathRemoved value: -{ - "type": "string" -} - changed
Output schema / properties / locations / items / properties / today / items / requiredPrevious value: -[ - "label", - "times", - "closed" -]New value: +[ + "label", + "times" +] - changed
Output schema / properties / locations / items / requiredPrevious 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" +] - added
Output schema / properties / mapUrlTemplateAdded value: +{ + "type": "string" +} - removed
Output schema / properties / warningRemoved value: -{ - "type": "string" -} - changed
Output schema / requiredPrevious value: -[ - "date", - "locations", - "failures", - "warning" -]New value: +[ + "date", + "locations", + "failures" +]
- Added
list_nutrition_fields - Removed
search_dishes
7 tool updates
v0.1.0- First observed
filter_dishes - First observed
find_open_now - First observed
get_hours - First observed
get_item_nutrition - First observed
get_menu - First observed
list_locations - First observed
search_dishes
TDQS
Scored across 8 tools
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.
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.
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.
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
Related MCP Connectors
Persistent food journal for AI assistants. Log meals, save recipes, plan meals and track nutrition.
Find restaurants and sourced dietary dish evidence. Free discovery; metered menus need an API key.
Look up a packaged food by barcode, search and compare products, and check listed allergens.
Log meals, check calories and macros, set up a nutrition plan, and search foods.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceProvides 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 npm1MIT
- AlicenseAqualityDmaintenanceEnables natural language access to USDA's FoodData Central database with 1M+ foods, supporting search, nutrition facts, food comparison, and daily value calculations.8MIT
- FlicenseNot gradedqualityDmaintenanceEnables logging food into MyFitnessPal diary via natural language, supporting search, log, quick add, and diary retrieval.-
- AlicenseNot gradedqualityCmaintenanceEnables querying Yale Hospitality dining menus, listing residential colleges, fetching meal offerings, and searching dishes across colleges via MCP tools.MIT