tabelog
tabelog-cli
A Tabelog CLI and MCP server. Tabelog has no public API and the Japanese site
sits behind a Cloudflare challenge that rejects anything but a real browser,
but the inbound locales (tabelog.com/en, /kr, /tw, /cn, /th) are served as
plain server-rendered HTML with schema.org JSON-LD. This reads those. No
browser, no headless Chrome, no runtime dependencies.
What it reads: restaurant search with Tabelog's own filters (area, genre, keyword, budget band, online-bookable at a date/time/party size) plus filters the site does not offer (radius around coordinates, open at a given time, minimum score or review count, feature tags, private room, parking); a restaurant page with structured weekly hours; reviews, including one reviewer's full text; the posted menu; the rating breakdown; photos; the online-booking calendar with time slots; set menus and the seat list; a place's popularity ranking; Tabelog's own nearest-restaurants list around a restaurant; and coordinates resolved to a Tabelog area. Reservation itself stays in the browser.
Install
Requires Bun.
bun install
bun link # registers the global `tabelog` commandUsage
# top ramen around Sannomiya station, Tabelog score order
tabelog search --area Sannomiya --genre ramen
# Japanese works for both filters and free text; --page walks 20 at a time
tabelog search --area 三宮 --keyword 焼鳥 --page 2
# other orderings the inbound site offers
tabelog search --area Namba --genre okonomiyaki --sort access # most viewed by overseas visitors
tabelog search --area Namba --genre okonomiyaki --sort reserved # most reserved
# budget per person (dinner by default), snapped to Tabelog's bands
tabelog search --area Sannomiya --genre ramen --budget-max 999
tabelog search --area Ginza --genre sushi --budget-meal lunch --budget-min 5000 --budget-max 9999
# only places with an online-bookable table then
tabelog search --area Sapporo --genre sushi --vacancy-date 2026-09-11 --vacancy-time 19:00 --vacancy-people 1
# radius around a point. --near alone picks the area itself: the nearest railway
# station Tabelog knows. Pages are walked one at a time (5 by default, up to 10)
# and the walk stops once --limit restaurants (20) are inside the circle
tabelog search --near 43.0553,141.3532 --radius-m 300 --genre sushi
tabelog search --near 34.6687,135.5013 --radius-m 200 --open-at now --limit 10
# open at a Japan wall-clock time, and the cheap card-level filters
tabelog search --area Susukino --open-at "2026-09-12 19:00" --min-rating 3.5 --min-review-count 100
tabelog search --area Susukino --genre ジンギスカン --feature "non smoking,credit card" --order review_count
tabelog search --area Susukino --award # Tabelog Award / Tabelog 100 holders only
# facilities from each restaurant's own page
tabelog search --area Sapporo --genre sushi --private-room --parking
# a restaurant page, by URL or by the id shown in search results
tabelog detail https://tabelog.com/hyogo/A2801/A280101/28043837/
tabelog detail 28043837
# reviews, newest visit first, lunch only; then one reviewer's full text
tabelog review 28043837 --by-visit --use-type lunch
tabelog review-read https://tabelog.com/en/hyogo/A2801/A280101/28043837/dtlrvwlst/B486164563/
# posted menu (food by default; lunch, drink), rating breakdown, photos
tabelog menu 28002413
tabelog menu 28002413 --kind drink
tabelog rating 27000401
tabelog photo 27000401 --mode owner
# online-booking calendar and time slots for a date and party size
tabelog vacancy 27000401 --date 2026-09-11 --people 1 --time 19:00
# set menus with prices and conditions, and the seat list
tabelog course 27000401
tabelog seating 1079755
# Tabelog's own popularity ranking for a place (not the score order)
tabelog ranking Susukino
# Tabelog's own 25 nearest restaurants around one place, with distances
tabelog nearby 1077287
tabelog nearby 1077287 --genre ramen --pages 2
# which Tabelog areas a GPS point falls in
tabelog locate 43.0553,141.3532
# what does a word resolve to?
tabelog suggest Sannomiya
# Korean page text (names, categories, transport); filters resolve the same way
tabelog search --area Namba --genre okonomiyaki --locale kr
TABELOG_LOCALE=kr tabelog detail 28043837
# machine-readable output for any command
tabelog search --area Sannomiya --genre ramen --jsonArea and genre names are matched against the suggest index, which knows English
and Japanese names only. A Korean area name returns nothing; use the English or
Japanese one and switch --locale kr for Korean output. Genres are pickier
than areas: the index has Tabelog's own labels, so 串カツ resolves where
kushikatsu does not. A genre that fails to resolve is searched as a keyword
instead, and the result header says so. Landmarks (Dotonbori) are not areas;
use the nearest station or pass --near with its coordinates.
Times are Japan time. --open-at reads each restaurant's weekly hours (any
locale; day names are normalised); a restaurant with no parsable hours is kept
and marked unknown, never dropped.
--near, --open-at, --private-room and --parking each read every
result's page, roughly two seconds per page of twenty, once per restaurant per
process. Distances are straight-line and the radius applies only to the pages
actually read: Tabelog orders the list by score, not by distance, so a radius
search walks pages sequentially and stops when --limit are inside; the
header says how many pages it read and when raising --pages is worth it.
Page numbers past the end of a list (photos, reviews) are reported as such
rather than silently serving page 1 again.
MCP
tabelog mcpServes the same commands as MCP tools over stdio: search, detail,
review, review_read, menu, rating, photo, vacancy, course,
seating, ranking, nearby, locate, suggest. The server is a hand-written JSON-RPC loop rather than the
official SDK, which pulls in a hundred packages for HTTP transports this never
uses. Register it with your host as command tabelog, arguments ["mcp"].
How it reads the site
Page | Source |
Search |
|
Area / genre resolution |
|
Detail | schema.org |
Reviews |
|
Menu |
|
Rating |
|
Photos |
|
Vacancy |
|
Courses |
|
Seating |
|
Ranking |
|
Nearby |
|
Coordinates to area | Railway stations from OpenStreetMap (Overpass), each verified against |
Distance / open now / facilities | Computed here from each result's JSON-LD coordinates, parsed hours and info-table rows; Tabelog's inbound site has none of these filters. |
Id to URL |
|
Coordinate search is the one thing Tabelog itself cannot do: lat/lon
parameters are ignored by the list page, and the JP-only radius search sits
behind the Cloudflare challenge. So an area still bounds every search, and the
radius is applied afterwards from real coordinates. When a card's own
"Station 450m" is measured from the same station the point was measured
against, it bounds the distance and the card is skipped without a fetch.
If Tabelog changes its markup the parsers here will need to follow. Every selector is a BEM class name the site has kept stable for years, and each command fails loudly rather than returning an empty page as success.
Restaurant pages are cached in memory for the life of the process, so a search that filters on distance, opening hours and facilities at once still fetches each restaurant once. Nothing is written to disk.
Tests
bun test # parsers against captured pages, plus the time and geo logic
bun run check # typecheck, lint and test
bun run fixture:refresh # re-capture every fixture from the live siteThe fixtures under test/fixture/ are real Tabelog pages, gzipped. The tests
assert values a user would notice going missing (this restaurant's score, that
price, the address, a menu item) rather than that an array is non-empty, so a
regex that still matches but grabs the neighbouring element fails. That is not
hypothetical: classText used a \b boundary, which made list-rst__price
match list-rst__price-tax, and the test for it is what found the bug.
License
MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/krisamin/tabelog-cli'
If you have feedback or need assistance with the MCP directory API, please join our Discord server