mcpField
U
UMich Dining

UMich Dining

ローカル
github.com/esreddy2ヘルスケア0今日更新

UMich Dining について

UMich Dining は University of Michigan の食堂情報を扱う MCP サーバーです。メニュー、料理の特性、アレルゲン、栄養、営業時間を調べる人向けで、サイトをリアルタイムに読み取り、ページをメモリーに短時間キャッシュします。

主な機能

  1. 01十食堂のメニューと提供時間の取得
  2. 02特性やアレルゲンによる料理検索・絞り込み
  3. 03栄養情報、カロリー、提供量の確認
  4. 04営業時間と営業中の食堂の確認
  5. 05ローカル stdio とホスト型 HTTP に対応

活用シーン

  1. 01指定した食堂と食事時間の料理を探す
  2. 02食事特性と除外アレルゲンで料理を絞り込む
  3. 03カロリー、ナトリウムなどの栄養値を比較
  4. 04食堂が現在営業中か確認

MCP 対応

メニュー、料理検索・絞り込み、栄養、営業時間のツールと、食堂一覧および分類リソースを MCP クライアントに提供します。ローカル stdio とホスト型 Streamable HTTP に対応します。

設定

ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。

mcp.json · 共通設定
{
"mcpServers": {
"esreddy2-umich-dining": {
"command": "npx",
"args": [
"-y",
"umich-dining-mcp"
]
}
}
}
起動コマンドnpx -y umich-dining-mcp

ローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。

パッケージ
npmumich-dining-mcp0.1.1

ツール

7

掲載時のツール一覧 · 1 週間前に更新

パラメーター型必須説明
datestringいいえYYYY-MM-DD 形式のカレンダー日付です。サイトでは今日の3日前から14日後までのメニューを公開しています。

詳細

umich-dining-mcp

npm CI Live site

ミシガン大学アナーバー校の食堂向けMCPサーバーです。提供中のメニュー、ビーガンまたはハラール対応の料理、料理に含まれる食材、カロリー数、各食堂の営業時間について回答します。

すべての回答は、dining.umich.eduからリアルタイムで取得します。10分ごとの質問に対してアクセスは1回で済むよう、ページは数分間メモリに保持されますが、ディスクには何も書き込まず、メニューのミラーも作成しません。

トランスポートローカルstdioおよびホスト型Streamable HTTP
ランタイムNode.js 20.18.1以降
食堂10か所の食堂
レジストリio.github.esreddy2/umich-dining-mcp

インストール

npm install -g umich-dining-mcp

または、何もインストールせずに実行できます。

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"]
    }
  }
}

stdio経由でMCPサーバーを起動するその他のクライアントでも、Cursorと同じmcpServersエントリーを使用し、コマンドにはnpx -y umich-dining-mcpを指定します。

ツール

ツール説明
list_locations10か所の食堂について、住所、電話番号、メールアドレス、地図へのリンク、本日の提供時間、現在営業中かどうか、グルテンフリーの食品棚があるかどうかを返します。
get_menu現在料理を提供している食堂1か所のメニューを返します。食事、ステーション、料理とともに、コード化された特性とアレルゲン、栄養密度と炭素の区分、カロリー、1食分の量を確認できます。食事を1つまたは複数指定すると、その内容を取得できます。
search_dishes指定した食堂、またはすべての食堂から、料理名で検索します(大文字と小文字を区別しない部分一致)。1日または期間を指定できます。
filter_dishes指定した食堂、またはすべての食堂のメニューを、アレルゲン、特性、栄養密度、カーボンフットプリント、栄養素、カロリー、ナトリウムで絞り込みます。1日または期間を指定できます。
list_nutrition_fields対応している栄養素名と単位、および微量栄養素の1日摂取基準値の基準を返します。
get_hoursその日の提供時間帯と通常の週間スケジュールを返します。読み取れない食堂はfailuresに報告されますが、ほかの食堂の情報は引き続き返されます。
find_open_now指定した時刻に料理を提供している食堂を返します。
get_item_nutrition料理1品の詳細な栄養成分表示を返します。
リソース
リソース内容
umich://dining-halls各食堂のコードを含む、JSON形式の食堂一覧です。
umich://taxonomy15種類のアレルゲンと14種類の特性について、各コードと表示ラベル、特性の含意関係の推移閉包、アレルゲンに関する注意事項を示します。
質問の例
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?

レスポンスの契約

search_dishes と filter_dishes の行では、名前の代わりに小さな整数を使用し、レスポンスの先頭にある key ブロックで各コードをスラッグに対応付けます。キーには、そのレスポンスで使用するものだけが 記載されます。コードは契約の存続期間中、固定されます。

{
  "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]
  ]
}

行は配列であり、固定位置の名前は各ツールの説明に記載されています。可変の栄養素データは、 レスポンスごとに一度だけ nutrients として返されます。名前付きの行では、行のデータ量の2.5倍に あたるメンバー名が各行に繰り返されます。名前付きの行は216バイト、配列の行は72バイトです。

  • 食堂は以下の一覧の順に1..10、食事は1(Breakfast)、2(Brunch)、3(Lunch)、4(Dinner)、 アレルゲンは1..15、6つのブール値の特性は1..6(glutenfree、halal、kosher、spicy、vegan、 vegetarian)です。サイトが新しい食事ラベルを作成すると、5から次の空きコードが割り当てられます。 ステーションにも固定された語彙があります。同じステーションにはすべてのレスポンスで同じコードが 割り当てられるため、コードを覚えておくことができます。
  • mhealthyTier は1(Nutrient Dense Low)から5(Nutrient Dense High)までです。この尺度は固定されており、 ツールの説明と umich://taxonomy に記載されています。
  • 呼び出しで max_carbon を指定するか、carbonFootprint で並べ替える場合に限り、行に炭素ティア (carbonFootprint)が含まれます。それ以外の場合は、行を小さく保つため省略されます。
  • traits 配列に含まれるのは6つのブール値の特性のみです。密度ティアは独立した数値フィールドに移されます。
  • units マップには、レスポンスに含まれる各栄養素の単位が示されます。微量栄養素も他の栄養素と同様に 量で表されます。サイトは1日の摂取基準値に対する割合を公開し、行にはその割合に相当する量が含まれます。 たとえば、鉄の1日の摂取基準値が18 mgの場合、15 %DVは mg 単位で 2.7 として示されます。しきい値では、 割合も %DV という独自の名前で引き続き利用できます。
  • 検索またはフィルターでは、対象とする食堂を指定します。各検索またはフィルターで、食堂を1つ、複数、 または指定しないことができます。行は指定された順序で返され、limit は先頭からその数だけ取得します。 デフォルトは50行で、レスポンスには一致した件数と、残りを表示する方法が記載されます。
  • 行には常にカロリーと1食分の量が含まれます。ナトリウムを含むその他の栄養素は、include_nutrients で 名前を指定して取得します。ナトリウムもタンパク質より特別な扱いを受けるわけではありません。フィルターで 条件に指定した栄養素は、指定の有無にかかわらず常に返されます。
  • 1日分のレスポンスには date が含まれ、期間のレスポンスには dateRange が含まれます。また、各行には その料理が登場した日付が dates として含まれます。
  • 公開値がない料理はゼロではなく、null として報告されます。trace や < の値は値として扱われません。

get_menu と一括取得ツールも同じコンパクトな行を返すため、どこで読み取っても行の意味は同じです。 get_item_nutrition は、1つの料理の生の栄養成分表示を返すツールです。

この方式なら、メニュー全体のデータ量を大幅に削減できます。South Quad のメニューは60,266バイトから 8,817バイトに、Bursley のメニューは42,141バイトから6,573バイトになりました。1つの料理の栄養成分表示は、 get_item_nutrition を1回呼び出すだけで取得できます。

食堂

id食堂id食堂
bursleyBursleysouth-quadSouth Quad
east-quadEast Quadtwigs-at-oxfordTwigs at Oxford
markleyMarkleywolverine-villageWolverine Village
mosher-jordanMosher-Jordanlawyers-clubLawyers Club
north-quadNorth Quadmartha-cookMartha Cook

get_menu、get_hours、search_dishes が受け取るのは id です。食堂のコードは、この一覧での位置を 1から数えた値です。

日付

このサイトでは、3日前から14日後までのメニューが公開されています。この範囲外の日付を指定しても、サイトはエラーを返さず、別の日のメニューを返します。そのため、取得を行う前に範囲外の日付を拒否し、サイトが提供する範囲を示すメッセージを返します。ページにレンダリングされた日付が記載されている場合は、その日付を指定した日付と照合し、一致しなければ誤った回答ではなくエラーとして扱います。

範囲は from と to で指定します。to を省略すると、最後に公開された日が指定されます。この2つを date と組み合わせることはできません。1回の呼び出しで収まらない範囲は、offset を使ってウィンドウ単位で読み込みます。回答の coverage ブロックには、次のウィンドウのオフセットが示されます。

時刻

サーバーが報告する時刻はすべてキャンパス時間、つまり Ann Arbor のタイムゾーン America/Detroit の時刻です。このタイムゾーンは、冬は東部標準時、夏は東部夏時間です。サイトが公開する日付、食事の時間帯、キャッシュエントリーの「今日」は、すべてこのタイムゾーンで読み取られます。

サーバーを実行しているマシンのタイムゾーンは関係ありません。Chicago のサーバーも UTC のサーバーも、同じ質問には同じように回答します。また、テストスイートでは複数のホストタイムゾーンで食事の選択を実行し、これを確認します。UMICH_DINING_TIMEZONE を設定するのは、別のタイムゾーンにあるサイトのミラーをサーバーに指定する場合だけです。

フィルター

パラメーター意味
exclude_allergens指定されたアレルゲンを1つも含まない料理だけを残します。
require_traits指定された特性をすべて備えた料理だけを残します。
min_mhealthy栄養密度の最低ランク。1~5(3 = 「中程度以上の栄養密度」)。
max_carbon炭素排出量の上限:1(低)、2(中)、3(高)。
nutrients栄養素ごとの範囲。例:{"protein": {"min": 20, "unit": "g"}}。単位を省略すると、その栄養素の既定の単位が使われ、単位の整合性が確認されます。
include_nutrients返す栄養素を、正規キー名または公開名で指定します。または all を指定します。既定ではフィルターで使用した栄養素が対象です。範囲を指定した栄養素は必ず返されます。
query料理名に含まれる、大文字と小文字を区別しない部分文字列。
meal、station対象を1つの食事時間帯または1つのステーションに絞ります。
sort_by、sort_order並べ替える項目と方向。

栄養素に条件を指定すると、その値が公開されていない料理は除外されます。不明な値をゼロとして扱うことはありません。

範囲クエリのコスト

範囲クエリでは、ホールごと、日ごとに1ページを読み込みます。サイトへの取得は1秒あたり最大2ページです。UMICH_DINING_MAX_RANGE_FETCHES(既定値は12)を超える数の上流ページが必要なクエリでは、提供できた行と、どこまで処理できたかを示す coverage ブロックが返されます。

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

数はすべて一致します。クエリで要求された各ページは、キャッシュ済み、取得済み、保留中、または失敗のいずれかです。nextOffset は範囲の残りが始まる位置です。そのため、広い範囲はウィンドウ単位で読み込み、その数値を offset に指定して再度問い合わせます。

このために永続キャッシュがあります。公開期間のページはディスクに保存され、バックグラウンドでウォームアップされるため、範囲クエリは通常、サイトにアクセスせずに処理されます。

アレルゲン

アレルゲン情報の正確さは、サイトの情報に依存します。メニューページには、厨房から報告された料理のアレルゲンが表示されますが、「含む」と「含む可能性がある」の区別はありません。原材料一覧もなく、表示がないからといってアレルゲンが含まれないわけではありません。サイト独自の案内は次のとおりです。「各料理提供エリアの近くに掲示された看板で、アレルゲンが赤字で強調表示されたメニューを確認してください。」「Gluten Free」は、料理にグルテンが使われていないことを意味しますが、セリアック病の方にとって安全であることを意味するものではありません。South Quad、East Quad、Mosher-Jordan、Bursleyには、グルテンフリー専用のパントリーがあります。

この注意事項は、アレルゲン情報を返す各ツールの説明とumich://taxonomyに記載されています。アレルゲン情報を含む応答には、コードの確認を促す一文が繰り返し記載されますが、長い注意事項は各本文には繰り返し記載されません。料理が安全だと主張するツールはありません。

サイトが慎重に扱っているため、特性についてもう2点補足します。ヴィーガン料理は、サイトがヴィーガンとベジタリアンを区別しているため、ベジタリアンとしても報告されます。また、ほかの特性が別の特性を意味することはありません(ハラールだからといってベジタリアンとは限らず、コーシャも同様です)。

設定

環境変数デフォルト意味
UMICH_DINING_USER_AGENTpython-requests/2.32.3使用するUser-Agentです。
UMICH_DINING_BASE_URLhttps://dining.umich.edu読み取り対象のサイトです。
UMICH_DINING_TIMEZONEAmerica/Detroitキャンパスのタイムゾーンです。サイトが公開する日付と食事時間は、このタイムゾーンで読み取られます。
UMICH_DINING_TIMEOUT_MS20000リクエストごとのタイムアウトです。
UMICH_DINING_MAX_RETRIES3初回試行後の再試行回数です。
UMICH_DINING_MAX_CONCURRENCY2同時に実行できるリクエスト数です。
UMICH_DINING_MIN_GAP_MS500リクエスト間の最小間隔です。
UMICH_DINING_TTL_TODAY_MS900000今日のメニューのキャッシュ保持期間です。
UMICH_DINING_TTL_FUTURE_MS21600000未来のメニューのキャッシュ保持期間です。
UMICH_DINING_TTL_PAST_MS86400000過去のメニューのキャッシュ保持期間です。
UMICH_DINING_TTL_REGULAR_HOURS_MS86400000週間スケジュールのキャッシュ保持期間です。
UMICH_DINING_MAX_RANGE_FETCHES121回の範囲クエリで取得できる上流ページ数です。
UMICH_DINING_CACHE_DIR~/.cache/umich-dining-mcp永続キャッシュの保存先です。offにすると無効になります。
UMICH_DINING_CACHE_MAX_AGE_DAYS30キャッシュエントリの保持期間です。
UMICH_DINING_CACHE_MAX_SIZE_MB200永続キャッシュの最大サイズです。
UMICH_DINING_CACHE_PRUNE_INTERVAL_MS3600000永続キャッシュの削除処理を実行する間隔です。

サイトへのアクセス方法

dining.umich.eduは他者が運営するウェブサイトなので、サーバーは負荷をかけないようにアクセスします。

  • 同時実行は2リクエストまで、リクエスト間隔は最低500 msです。 制限はプロセス全体に適用されます。
  • 実行中リクエストを重複排除するキャッシュを使用します。 同じホールについて10件の質問があっても、リクエストは1回だけです。今日のメニューは15分間、未来のメニューは6時間、過去のメニューは24時間、週間営業時間は24時間キャッシュされます。
  • エラー時には古いキャッシュを使用します。 サイトに接続できず、キャッシュが存在する場合は、質問への応答に失敗する代わりに、そのコピーを古いデータとして示して返します。
  • User-Agentは1種類です。 このサイトは限られたクライアントにのみHTTP 200を返します。動作が確認されているのはpython-requests/2.32.3のみで、汎用の取得エージェントとヘッドレスブラウザーはいずれも403を受け取ります。サーバーの実際の識別情報ではないため、変更可能です。

混雑状況

get_dining_occupancyは、センサーが設置されている食堂(Bursley、East Quad、South Quad、Mosher-Jordan、OxfordのTwigs)のリアルタイムの混雑状況を返します。

{ "hall": "bursley" }

現在の人数、1日の利用者数、総収容人数、混雑率、計測時刻を返します。センサーのない食堂は結果に含まれません。

略称

ホール名、栄養素、特性には、大文字と小文字を区別しない略称を使用できます。

  • ホール:mojo、south、east、lawyers、cook、twigs、wovlerine、...
  • 栄養素:cals、kcals、carbs、fiber、protein/prot、na/salt、...
  • 特性:gf、veg。

説明は変更されません。サーバーは検証前に略称を解決します。

データソース

メニュー、営業時間、所在地、栄養情報、混雑状況は U-M のダイニングモバイル API から取得し、公開サイトのスクレイパーはフォールバックとして引き続き利用します。回答は引き続きリアルタイムで取得され、数分間キャッシュされます。

貢献

プルリクエストを歓迎します。テストスイート、フィクスチャ、リリースプロセスについては、CONTRIBUTING.mdをご覧ください。

ライセンス

MIT。詳しくはLICENSEをご覧ください。

コメント

MCP は初めてですか?

プロトコルの概要から最初のサーバーの導入まで、よくある疑問にまとめて答えます。

AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。