tock-mcp
MCP server for Tock (exploretock.com) — restaurant discovery and availability. Every request is relayed through the user's signed-in browser tab via the ContextMint Bridge browser extension, so there's no cookie paste, no bot-wall dance, and no password handling.
- npm: npmjs.com/package/tock-mcp
- Source: github.com/chrischall/tock-mcp
Tock does not publish an official consumer API, and exploretock.com sits behind a Cloudflare challenge. This server fetches the same server-rendered pages the Tock web app uses (parsing their embedded
window.$REDUX_STATEstore) through your own signed-in browser tab. It is read-only: Tock reservations are prepaid tickets, so booking is left to exploretock.com. Use at your own discretion.
Setup
The MCP server is half of the picture — the other half is the ContextMint Bridge browser extension that talks to Tock from your signed-in tab. Both are required.
1. Install the MCP server
Add to .mcp.json in your project or ~/.claude/mcp.json:
{
"mcpServers": {
"tock": {
"command": "npx",
"args": ["-y", "tock-mcp"]
}
}
}
Or from source:
git clone https://github.com/chrischall/tock-mcp
cd tock-mcp
npm install && npm run build
# then point .mcp.json at dist/bundle.js
2. Install ContextMint Bridge
tock-mcp shares a single browser extension, ContextMint Bridge, with every other fetchproxy-based MCP. Install it once from its releases page — in Chrome, unzip the chrome zip and load it unpacked (chrome://extensions → Developer mode → Load unpacked); Safari isn't available yet, so use Chrome for now. ContextMint Bridge is the fetchproxy extension under its new name, same maintainer; its source is public at https://github.com/nullnet-app/contextmint-bridge — build it yourself or check a release zip against its published .sha256 file. Then open exploretock.com and sign in (only needed for the account tools; discovery works signed-out).
3. Approve the one-time pair code
The first tool call prints a pair code to approve in the ContextMint Bridge popup (trust-on-first-use, per identity). Run tock_healthcheck to trigger it, approve the code, and you're paired for good.
Tools
| Tool | What it does |
|---|---|
tock_list_metros |
List Tock cities/metros (name, slug, business count). Filter by name/country. |
tock_search_restaurants |
List / search venues in a metro slug (cuisine, price, neighborhood, slug). |
tock_get_restaurant |
Venue details + its bookable experiences (prices, party sizes). |
tock_get_availability |
A venue's bookable calendar: experiences, prices, open dates/times. |
tock_list_reservations |
The signed-in user's purchases / reservations (needs a signed-in tab). |
tock_get_profile |
The signed-in user's profile (needs a signed-in tab). |
tock_verify_reservation |
After a booking attempt, re-query the account and return confirmed / cancelled / not_found / ambiguous (needs a signed-in tab). Use this instead of eyeballing a success screen. |
tock_healthcheck |
Round-trip the bridge; reports status + the pair code on first run. |
Response shape (view)
Two tools take view: "compact" | "full" — tock_get_restaurant and
tock_get_profile — and compact is the default, so you get the slim
rung without asking for it. The other six of this server's eight tools have no
view; each for its own reason, below.
Compact here is media stripping, not a field projection. src/view.ts
holds no hand-written field list, because this repo has no captured Tock
payload to derive one from honestly. What it does instead is subtractive: drop
keys whose value is a picture, plus two named explicitly —
profileImageUrl and heroImageUrl.
Naming those two is the load-bearing part, and it is worth knowing why. The
shared rule anchors its media noun at the START of the key, which is what
keeps a flag like hasThumbnail alive — and it is also why profileImageUrl
(starts profile) and heroImageUrl (starts hero) both slip past it. That
would leave only the fallback rule, which fires when a URL's path happens to
end in an image extension. A signed or extension-less Tock CDN URL would then
survive compact silently, with nothing in the response to say why. Naming the
keys removes the dependency on what a URL happens to look like.
Those two are the only image fields any parsed shape in this server carries —
they live on RestaurantDetails and nowhere else — and nothing is kept:
no tool here has a picture as its product, so no payload mixes decoration with
content.
Expect one specific non-effect: on tock_get_profile compact provably
removes nothing. The identity record is four fields (firstName,
lastName, email, id), none of them a picture, so both rungs serialise to
the same bytes. The rung is declared there for consistency, not for savings.
view: "full" returns the parsed record untouched. There is deliberately no
raw rung: full already IS the record this server parsed out of Tock's
page, so a third value would silently alias one that exists.
Why the other six have none:
tock_search_restaurantsreturnsRestaurantSummary, which carries no image key at all — the two image fields exist only on the details shape. That is exactly why one of the two restaurant tools has a rung and the other does not; it is not an omission.tock_list_metrosreturns hand-built metro records (name, slug, state, country, business count, coordinates). No picture, and no fatter upstream shape behind them to project away from.tock_get_availabilityreturns an ASSEMBLED calendar — experiences,openDates,openTimes— built by the parser from Tock's calendar slice, not a pass-through payload. There is no single upstream object to hand back or to slim.tock_list_reservationsreturns hand-built reservation records (venue, date/time, party size, experience, cancelled flag) with no media field.tock_verify_reservationreturns a VERDICT —verdict,match,searched,recheckAdvised,reportAs,summary. The verdict is the product, and there is nothing decorative in it to remove.tock_healthcheckreturns a bridge diagnostic, for the same reason.
Passing view to one of those is not an error and will not fail: the tool
does not declare it, so zod drops the unknown key and the call runs exactly as
it would have. You get no warning, so a successful call is not evidence the
rung was honoured.
Typical flow
tock_list_metros { query: "chicago" }→ find the metro slug.tock_search_restaurants { metro: "chicago", query: "tasting menu" }→ get venue slugs.tock_get_availability { slug: "alinea", date: "2026-07-10", party_size: 2 }→ see experiences and open dates/times.- To book, open
exploretock.com/<slug>— reservations are prepaid tickets and are completed on Tock.
Booking verification protocol
Booking happens outside these tools (on exploretock.com, by hand or by UI automation), but verification is this server's job. A booking counts as confirmed only when BOTH hold:
- a confirmation ID, receipt URL, or confirmation email was captured, and
tock_verify_reservation { venue, date, partySize, bookedMinutesAgo }returns verdictconfirmed.
Use tock_verify_reservation rather than reading tock_list_reservations
yourself: it checks the canceled and past lists too (a created-then-voided
booking appears only in canceled), and it applies the lag rule below for you,
returning recheckAdvised: true when an absence is still inconclusive. Pass
the venue's exact Tock slug when you have it: a partial name that matches more
than one restaurant on the date returns verdict ambiguous (with the
candidates), never confirmed — re-run with the slug. A venue query under 4
characters matches only a full name or slug; if it merely appears in a venue
booked that date, the result is not_found with venueQueryTooShort: true,
nearMatches and recheckAdvised: true — re-run with the full name, and never
read that not_found as proof the booking failed. Handle all four verdicts
(confirmed, cancelled, not_found, ambiguous); anything but confirmed
is reported per the rules below.
Anything less — including a screenshot of a success screen — must be reported as "attempted, unverified." Two Tock-specific traps make the stricter rule non-negotiable:
- The post-booking modal is not proof: a confirm submitted with a stale cart is a silent no-op that still renders the success modal.
- The reservations backend (
PatronReservationHistory) lags the Reservations tab by minutes. A single immediate re-read proving absence proves nothing; re-query after a couple of minutes (and once more before giving a verdict).
Notes
- Read-only. No booking, cancelling, or payment — Tock reservations are prepaid/Turnstile-gated checkouts left to the site.
- Discovery needs no login. Only
tock_list_reservations,tock_get_profileandtock_verify_reservationrequire a signed-in exploretock.com tab. - Errors are actionable: a Cloudflare challenge asks you to clear it in the signed-in tab; a signed-out account tool asks you to sign in.
