360 Secure SkillHub
360 安全技能中心

untappd-mcp

Untappd MCP 服务器:用自有账号登录 Untappd 移动端 v4 API,提供 46 个工具搜索啤酒、酒厂、场馆及其菜单,读取用户资料、打卡、愿望清单、徽章、好友与好友动态;经确认后发布打卡、点赞和评论,并用本地 SQLite 缓存快速回答“是否喝过”类问题。

chrischall
chrischall
热度 67.96
最近更新 2026-10-10 07:30:07
分类:生活依赖:MCP 服务 / 第三方 API / 读写文件应用场景:推荐 / 社交媒体

安装技能

复制下面的话术发给你的 Agent,它会通过 secure-skills 检索并安装该技能。

执行命令安装此 skill: npx secure-skills-cli add untappd-mcp
Metadata
name
untappd-mcp
description
Search Untappd beers, breweries, and venues; read user profiles, check-ins, wishlists, distinct beers, badges, friends, and your friend activity feed; and post check-ins, toasts, and comments to your own Untappd account. Use when the user asks about beer ratings, what a beer or brewery is like on Untappd, someone's Untappd check-ins or wishlist, or wants to log/toast/comment on a beer.

Untappd MCP

Talks to Untappd's mobile (v4) API using your own account. Logs in via the app's xauth endpoint (username + password → access token) and calls the same endpoints the iPad app uses.

Setup

Set four environment variables (see the README for details):

  • UNTAPPD_USERNAME, UNTAPPD_PASSWORD — your Untappd login.
  • UNTAPPD_CLIENT_ID, UNTAPPD_CLIENT_SECRET — the Untappd mobile app client credentials (obtained by intercepting the app's traffic; see README).

Run untappd_healthcheck to confirm login works.

Read tools

  • untappd_search_beer / untappd_beer_info — find beers, then get full detail by bid.
  • untappd_search_brewery / untappd_brewery_info — breweries.
  • untappd_search_venue / untappd_venue_info — bars, breweries, restaurants.
  • untappd_venue_menu — a venue's verified beer menu, flattened. Use instead of venue_info for "what's on tap" — venue_info returns only the first section of each menu and under-reports large boards. This pages sections under a per-call max_pages budget (like the sync tools) and is resumable: it returns another_run_needed + next_section_offset when the budget runs out, or truncated if the upstream stops returning sections short of coverage.
  • untappd_user_info — a user's profile (omit username for your own).
  • untappd_user_checkins — recent check-ins (page with max_id).
  • untappd_user_wishlist — wishlist beers.
  • untappd_user_beers — distinct beers ever checked in.
  • untappd_user_badges / untappd_user_friends.
  • untappd_activity_feed — your friend feed (page with max_id).
  • untappd_checkin_info — full detail of one check-in.

Most user tools default username to your configured account when omitted.

Response shape (view)

Thirteen of this server's 46 tools take view: "compact" | "full", and compact is the DEFAULT — the slim rung is what you get without asking for it.

If you were told to pass compact: true, that advice is stale. It used to be true: the projection shipped as an opt-in boolean defaulting to false, and the tool descriptions asked the caller to please turn it on. An efficiency you have to request is one that mostly is not requested — and the caller paying for the fat record was the one least able to know a slim rung existed. So it flipped. The old parameter is gone; it is not declared anywhere, so zod drops the unknown key and the call succeeds. You get the compact rung — right answer, wrong reason. The same silence bites the other way: compact: false no longer buys you the full record either. It is dropped identically and you still get compact. view: "full" is the only way back.

Compact comes in two tiers here, and they are not the same thing:

A hand-written field projection — 9 tools.

  • Check-ins (untappd_activity_feed, untappd_user_checkins, untappd_beer_activity, untappd_venue_activity, untappd_local_checkins): each ~5 KB record becomes {checkin_id, created_at, user, rating, comment, beer{bid, name, style, abv}, brewery, venue, toasts, comments, has_photo}. A default page of 25 was upwards of 100 KB to learn what someone drank.
  • untappd_search_beer: each ~1.2 KB match becomes {bid, name, style, abv, ibu, brewery, checkin_count, have_had} — the long beer_description and the nested brewery record go.
  • untappd_user_wishlist: the same beer core plus added_at.
  • untappd_user_beers: the same beer core plus your_count, your_rating, global_rating, last_had.
  • untappd_brewery_beers: the same beer core plus rating, rating_count, checkin_count, have_had, your_count. It has its own projector rather than sharing untappd_search_beer's, and the reason is a trap worth knowing: the item shape is identically {beer:{…}}-wrapped, but this endpoint spells the two surrounding fields total_count / has_had where /search/beer says checkin_count / have_had. Sharing the projector would return beers with no check-ins that you had never had, and the drift guard would not fire — the container was where it was expected. Per page it also drops sorting_options and the copy of the same brewery object repeated on every row.

An upstream request for less — 4 tools. untappd_user_info, untappd_beer_info, untappd_brewery_info and untappd_venue_info forward compact=true to Untappd's own endpoint, which drops the embedded activity/list blocks server side. There is no local projection on these: the entity's own fields are byte-identical on both rungs. What compact saves is Untappd's embedded blocks — and the bandwidth, not just the context. Do not expect a shorter beer record from untappd_beer_info; expect the recent- activity block to be absent.

The projectors are drift-safe. Each keys off a documented container (checkins.items, beers.items); if that array is not where it is expected — this is a reverse-engineered API — the projector warns on stderr and returns the RAW response rather than an empty or wrong one. A short answer is never silently manufactured.

view: "full" returns Untappd's response untouched. There is deliberately no raw rung: nothing here re-serialises or normalises a payload, so full already IS the upstream response and a third value would silently alias one that exists.

The 33 tools without view

Each for its own reason — and none of them will tell you it ignored the parameter, because an undeclared key is dropped by zod without a warning:

  • The 12 confirmation-gated writes (untappd_checkin, untappd_toast, untappd_add_comment, the two deletes, the wishlist pair, the four friend actions, and the local untappd_cache_forget) answer with a confirmation preview or a receipt. Nothing in a receipt is decoration.

  • untappd_sync_checkins / untappd_sync_user_beers answer with sync PROGRESS — pages walked, another_run_needed, backfill_complete. Slimming a progress report is how you lose the field that says it is not finished.

  • The five cache tools (untappd_cache_has_had, …_has_had_many, …_not_had, untappd_cache_query, untappd_top_not_had) answer from the local SQLite mirror in a shape this repo already wrote — a verdict plus the freshness block that says whether a "not found" might be a false negative. There is no upstream payload behind them to project away from.

  • untappd_checkin_info exists to return the FULL record for one check-in — photos, badges earned, toasts, comments. The ~5 KB the check-in projection removes is exactly what you called this tool to get.

  • untappd_venue_menu is already its own hand-written projection, with a per-call page budget and a resumable next_section_offset contract. A second projection on top of it would fight the first.

  • untappd_resolve, untappd_open_url, untappd_healthcheck return a verdict or a diagnostic.

  • The remaining nine reads — untappd_trending, untappd_notifications, untappd_search_brewery, untappd_search_venue, untappd_user_badges, untappd_user_friends, untappd_user_venues, untappd_pending_friends, untappd_venue_by_foursquare — hand back Untappd's payload as it arrived. No projector has been written for their shapes, so there is no rung to ask for and no slim option exists.

    untappd_brewery_beers used to be tenth on this list and no longer is (#161) — it takes a view now, and its field shape is documented with the other projections above.

Write tools (confirmation-gated — these post to your public account)

Each asks the user to confirm first. Where the client can show a confirmation prompt, it does (unless the server sets MCP_CONFIRM_ELICITATION=off). Otherwise the first call makes NO network call and returns status: "confirmation-required" with a preview of the exact request and a confirmToken; show the preview to the user, and only after they approve call the tool again with the same arguments plus confirmToken. A token works once and only for those arguments (a change returns DRAFT_CHANGED with a fresh preview). MCP_CONFIRM_MODE on the server can make this auto or refuse.

  • untappd_toast — toast/like a check-in (this endpoint is a toggle).
  • untappd_add_comment — comment on a check-in.
  • untappd_checkin — post a new beer check-in to your feed (needs a bid from untappd_search_beer; optional rating 0–5 in 0.25 steps, shout, venue).

Photo attachment and wishlist add/remove are not yet supported.

Check-in cache

The API can't answer "has this user ever had beer X?" without paging their whole history (50/page, rate-limited). These tools keep a SQLite mirror so that question is answered instantly with no API calls. On the stdio server the mirror is a local file (UNTAPPD_CACHE_DB, default ~/.untappd-mcp/checkins.db); the store is injectable, so another deployment can back it differently. Same tools either way.

Sync first, then query. Two sources; both resumable (max_pages/call, progress saved per page, another_run_needed until done). Omit username for your own account; another user must be public or your friend.

  • untappd_sync_user_beers — start here for has-had questions. Pages the user's COMPLETE distinct-beers list (cheap, and pages fully for anyone).
  • untappd_sync_checkins — detailed check-ins (venue/date). Only your OWN account pages fully; for anyone else Untappd returns just the recent ~50 and the result reports history_truncated (it won't falsely claim backfill_complete). force_backfill: true resets a cache wrongly marked complete and re-pages (rows kept).

Query tools (has-had ones consult BOTH sources — a hit in either = had):

  • untappd_cache_has_had — has the user had a beer? By exact bid or a case-insensitive beer_name substring.
  • untappd_cache_has_had_many — batch had/not-had for a list of bids.
  • untappd_cache_not_had — from a list of bids, the ones NOT had.
  • untappd_top_not_had — from a list of bids, the top N NOT-had beers by Untappd rating, with an optional style filter ("what should I order off this tap list?"). Uses a beer_meta cache; calls beer/info only on miss/stale, capped at api_budget per run (partial/another_run_needed when exceeded).
  • untappd_cache_query — filter cached check-ins by brewery, style, min_rating, venue, and date range.

Retention. The cache keeps what you sync until you remove it — including friends' dated check-ins, comments and venues. untappd_cache_forget (confirmation-gated) deletes one user's check-ins, distinct beers and sync state from the LOCAL cache only; Untappd is untouched and a later sync can re-fetch. The file is created owner-only (dir 0700, file 0600).

Every cache read returns a freshness block reporting each source's completeness separately (plus coverage_complete and a caveat when incomplete), so you can flag a "not found" as possibly a false negative until the relevant sync finishes.