untappd-mcp 2.1.0 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/dist/bundle.js +96 -21
- package/dist/tools/cache.js +3 -3
- package/dist/tools/checkin.js +5 -5
- package/dist/tools/friends.js +5 -1
- package/dist/tools/wishlist.js +2 -2
- package/dist/version.js +1 -1
- package/package.json +2 -2
- package/server.json +2 -2
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
},
|
|
8
8
|
"metadata": {
|
|
9
9
|
"description": "MCP server for Untappd — beers, breweries, venues, check-ins, wishlists, and your friend feed",
|
|
10
|
-
"version": "2.1.
|
|
10
|
+
"version": "2.1.1"
|
|
11
11
|
},
|
|
12
12
|
"plugins": [
|
|
13
13
|
{
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"displayName": "Untappd",
|
|
16
16
|
"source": "./",
|
|
17
17
|
"description": "MCP server for Untappd — search beers/breweries/venues, read profiles/check-ins/wishlists, and post check-ins, toasts, and comments",
|
|
18
|
-
"version": "2.1.
|
|
18
|
+
"version": "2.1.1",
|
|
19
19
|
"author": {
|
|
20
20
|
"name": "Chris Hall"
|
|
21
21
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "untappd-mcp",
|
|
3
3
|
"displayName": "Untappd",
|
|
4
|
-
"version": "2.1.
|
|
4
|
+
"version": "2.1.1",
|
|
5
5
|
"description": "MCP server for Untappd — search beers/breweries/venues, read check-ins and wishlists, and post check-ins, toasts, and comments",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Chris Hall",
|
package/dist/bundle.js
CHANGED
|
@@ -23302,6 +23302,20 @@ var require_v4 = __commonJS({
|
|
|
23302
23302
|
}
|
|
23303
23303
|
});
|
|
23304
23304
|
|
|
23305
|
+
// node_modules/@chrischall/mcp-utils/dist/cancel/index.js
|
|
23306
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
23307
|
+
var storage = new AsyncLocalStorage();
|
|
23308
|
+
function withCallSignal(signal, fn, request) {
|
|
23309
|
+
return signal ? storage.run({ signal, ...request ? { request } : {} }, fn) : fn();
|
|
23310
|
+
}
|
|
23311
|
+
|
|
23312
|
+
// node_modules/@chrischall/mcp-utils/dist/caller/index.js
|
|
23313
|
+
import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
|
|
23314
|
+
var storage2 = new AsyncLocalStorage2();
|
|
23315
|
+
function withCallerCapabilities(capabilities, fn) {
|
|
23316
|
+
return capabilities ? storage2.run(capabilities, fn) : fn();
|
|
23317
|
+
}
|
|
23318
|
+
|
|
23305
23319
|
// node_modules/@modelcontextprotocol/server/dist/chunk-Br0eD_fh.mjs
|
|
23306
23320
|
var __create2 = Object.create;
|
|
23307
23321
|
var __defProp2 = Object.defineProperty;
|
|
@@ -57749,17 +57763,73 @@ Hint: ${err.hint}`);
|
|
|
57749
57763
|
}
|
|
57750
57764
|
throw err;
|
|
57751
57765
|
}
|
|
57766
|
+
function mcpRequestFrom(args) {
|
|
57767
|
+
const ctx = args.at(-1);
|
|
57768
|
+
if (typeof ctx !== "object" || ctx === null)
|
|
57769
|
+
return void 0;
|
|
57770
|
+
const req = ctx.mcpReq;
|
|
57771
|
+
if (typeof req !== "object" || req === null)
|
|
57772
|
+
return void 0;
|
|
57773
|
+
return typeof req.notify === "function" ? req : void 0;
|
|
57774
|
+
}
|
|
57775
|
+
function callSignalFrom(args) {
|
|
57776
|
+
const ctx = args.at(-1);
|
|
57777
|
+
if (typeof ctx !== "object" || ctx === null)
|
|
57778
|
+
return void 0;
|
|
57779
|
+
const req = ctx.mcpReq;
|
|
57780
|
+
if (typeof req !== "object" || req === null)
|
|
57781
|
+
return void 0;
|
|
57782
|
+
const signal = req.signal;
|
|
57783
|
+
return signal instanceof AbortSignal ? signal : void 0;
|
|
57784
|
+
}
|
|
57785
|
+
function declaredCapabilitiesFrom(server) {
|
|
57786
|
+
const inner = server.server;
|
|
57787
|
+
if (typeof inner !== "object" || inner === null)
|
|
57788
|
+
return void 0;
|
|
57789
|
+
const read = inner.getClientCapabilities;
|
|
57790
|
+
if (typeof read !== "function")
|
|
57791
|
+
return void 0;
|
|
57792
|
+
try {
|
|
57793
|
+
const declared = read.call(inner);
|
|
57794
|
+
return typeof declared === "object" && declared !== null ? declared : void 0;
|
|
57795
|
+
} catch {
|
|
57796
|
+
return void 0;
|
|
57797
|
+
}
|
|
57798
|
+
}
|
|
57752
57799
|
function surfaceToolHints(server) {
|
|
57753
57800
|
const register2 = server.registerTool.bind(server);
|
|
57754
|
-
server.registerTool = (name, config2, cb) => register2(name, config2, (...args) =>
|
|
57755
|
-
|
|
57756
|
-
|
|
57757
|
-
|
|
57758
|
-
|
|
57759
|
-
|
|
57760
|
-
|
|
57761
|
-
|
|
57762
|
-
|
|
57801
|
+
server.registerTool = (name, config2, cb) => register2(name, config2, (...args) => (
|
|
57802
|
+
// THE CALLER'S CANCELLATION, made ambient for the whole handler
|
|
57803
|
+
// (`cancel/index.ts`). The SDK delivers it and the fleet ignored it:
|
|
57804
|
+
// measured against @modelcontextprotocol/server 2.0.0, a cancelled
|
|
57805
|
+
// call aborts `ctx.mcpReq.signal` with the caller's reason and the
|
|
57806
|
+
// handler runs to completion regardless — so the HTTP request stays
|
|
57807
|
+
// in flight, the child keeps burning metered CPU, and the upstream
|
|
57808
|
+
// keeps being hit for somebody who has gone. claude.ai sent 101
|
|
57809
|
+
// cancellations in the week to 2026-09-20.
|
|
57810
|
+
//
|
|
57811
|
+
// Here because this is the one wrapper every tool already passes
|
|
57812
|
+
// through: threading the signal by hand would mean editing several
|
|
57813
|
+
// hundred handlers and missing exactly the ones nobody edits.
|
|
57814
|
+
withCallSignal(callSignalFrom(args), () => (
|
|
57815
|
+
// WHAT THE CALLER CAN DO, made ambient for the same reason and in
|
|
57816
|
+
// the same place (`caller/index.ts`). Only the 2025-era half needs
|
|
57817
|
+
// the wrapper — a 2026-07-28 request answers for itself off its own
|
|
57818
|
+
// envelope — but a guarded tool that cannot tell whether the caller
|
|
57819
|
+
// can be shown a prompt returns one the SDK then refuses to deliver,
|
|
57820
|
+
// and that refusal reaches the caller as an unexplained protocol
|
|
57821
|
+
// error it had no chance to catch.
|
|
57822
|
+
withCallerCapabilities(declaredCapabilitiesFrom(server), () => {
|
|
57823
|
+
let result;
|
|
57824
|
+
try {
|
|
57825
|
+
result = cb(...args);
|
|
57826
|
+
} catch (err) {
|
|
57827
|
+
return hintResultOrRethrow(err);
|
|
57828
|
+
}
|
|
57829
|
+
return result instanceof Promise ? result.catch(hintResultOrRethrow) : result;
|
|
57830
|
+
})
|
|
57831
|
+
), mcpRequestFrom(args))
|
|
57832
|
+
));
|
|
57763
57833
|
}
|
|
57764
57834
|
async function createMcpServer(opts) {
|
|
57765
57835
|
const server = new McpServer({ name: opts.name, version: opts.version }, { supportedProtocolVersions: [...SERVER_PROTOCOL_VERSIONS] });
|
|
@@ -57912,12 +57982,13 @@ function toolAnnotations(opts = {}) {
|
|
|
57912
57982
|
...opts.title !== void 0 ? { title: opts.title } : {},
|
|
57913
57983
|
readOnlyHint: opts.readOnly ?? true,
|
|
57914
57984
|
...opts.idempotent !== void 0 ? { idempotentHint: opts.idempotent } : {},
|
|
57985
|
+
...opts.destructive !== void 0 ? { destructiveHint: opts.destructive } : {},
|
|
57915
57986
|
...opts.openWorld !== void 0 ? { openWorldHint: opts.openWorld } : {}
|
|
57916
57987
|
};
|
|
57917
57988
|
}
|
|
57918
57989
|
|
|
57919
57990
|
// src/version.ts
|
|
57920
|
-
var VERSION = "2.1.
|
|
57991
|
+
var VERSION = "2.1.1";
|
|
57921
57992
|
|
|
57922
57993
|
// src/client.ts
|
|
57923
57994
|
import { dirname, join } from "path";
|
|
@@ -59486,7 +59557,11 @@ function registerFriendActionTools(server, client2) {
|
|
|
59486
59557
|
{
|
|
59487
59558
|
title: action.title,
|
|
59488
59559
|
description: `${action.detail} Acts on YOUR account and affects a real relationship with another person. Without confirm: true it returns a dry-run preview and makes NO network call; with confirm: true it performs the action. Note: this endpoint path is taken from the Untappd app but is not otherwise independently verified.`,
|
|
59489
|
-
|
|
59560
|
+
// All four reach ANOTHER PERSON — the description says so itself: "affects
|
|
59561
|
+
// a real relationship with another person". A friend request cannot be
|
|
59562
|
+
// un-sent, and a rejection cannot be un-rejected, so none of them has an
|
|
59563
|
+
// inverse in this tool set.
|
|
59564
|
+
annotations: toolAnnotations({ title: action.title, readOnly: false, idempotent: true, openWorld: true, destructive: true }),
|
|
59490
59565
|
inputSchema: external_exports.object({
|
|
59491
59566
|
target_uid: TargetUidSchema,
|
|
59492
59567
|
confirm: schemaConfirm
|
|
@@ -59516,7 +59591,7 @@ function registerWishlistTools(server, client2) {
|
|
|
59516
59591
|
{
|
|
59517
59592
|
title: "Add a beer to your wishlist",
|
|
59518
59593
|
description: "Add a beer to YOUR Untappd wishlist by its bid. Without confirm: true it returns a dry-run preview and makes NO network call; with confirm: true it adds. Writes to your account.",
|
|
59519
|
-
annotations: toolAnnotations({ title: "Add a beer to your wishlist", readOnly: false, idempotent: true, openWorld: true }),
|
|
59594
|
+
annotations: toolAnnotations({ title: "Add a beer to your wishlist", readOnly: false, idempotent: true, openWorld: true, destructive: false }),
|
|
59520
59595
|
inputSchema: external_exports.object({
|
|
59521
59596
|
bid: BidSchema2,
|
|
59522
59597
|
confirm: schemaConfirm
|
|
@@ -59540,7 +59615,7 @@ function registerWishlistTools(server, client2) {
|
|
|
59540
59615
|
{
|
|
59541
59616
|
title: "Remove a beer from your wishlist",
|
|
59542
59617
|
description: "Remove a beer from YOUR Untappd wishlist by its bid. Without confirm: true it returns a dry-run preview and makes NO network call; with confirm: true it removes. Writes to your account.",
|
|
59543
|
-
annotations: toolAnnotations({ title: "Remove a beer from your wishlist", readOnly: false, idempotent: true, openWorld: true }),
|
|
59618
|
+
annotations: toolAnnotations({ title: "Remove a beer from your wishlist", readOnly: false, idempotent: true, openWorld: true, destructive: false }),
|
|
59544
59619
|
inputSchema: external_exports.object({
|
|
59545
59620
|
bid: BidSchema2,
|
|
59546
59621
|
confirm: schemaConfirm
|
|
@@ -59582,7 +59657,7 @@ function registerCheckinTools(server, client2) {
|
|
|
59582
59657
|
{
|
|
59583
59658
|
title: "Toast an Untappd check-in",
|
|
59584
59659
|
description: "Toast (like) a check-in on YOUR account. This endpoint is a TOGGLE: calling it on a check-in you have already toasted removes the toast. Without confirm: true it returns a dry-run preview and makes NO network call; with confirm: true it posts. Writes to your Untappd account and is visible to others.",
|
|
59585
|
-
annotations: toolAnnotations({ title: "Toast an Untappd check-in", readOnly: false, idempotent: false, openWorld: true }),
|
|
59660
|
+
annotations: toolAnnotations({ title: "Toast an Untappd check-in", readOnly: false, idempotent: false, openWorld: true, destructive: false }),
|
|
59586
59661
|
inputSchema: external_exports.object({
|
|
59587
59662
|
checkin_id: CheckinIdSchema,
|
|
59588
59663
|
confirm: schemaConfirm
|
|
@@ -59606,7 +59681,7 @@ function registerCheckinTools(server, client2) {
|
|
|
59606
59681
|
{
|
|
59607
59682
|
title: "Comment on an Untappd check-in",
|
|
59608
59683
|
description: "Post a comment on a check-in from YOUR account. Without confirm: true it returns a dry-run preview and makes NO network call; with confirm: true it posts. Writes to your Untappd account and is visible to others.",
|
|
59609
|
-
annotations: toolAnnotations({ title: "Comment on an Untappd check-in", readOnly: false, idempotent: false, openWorld: true }),
|
|
59684
|
+
annotations: toolAnnotations({ title: "Comment on an Untappd check-in", readOnly: false, idempotent: false, openWorld: true, destructive: false }),
|
|
59610
59685
|
inputSchema: external_exports.object({
|
|
59611
59686
|
checkin_id: CheckinIdSchema,
|
|
59612
59687
|
comment: external_exports.string().min(1).max(2e3).describe("Comment text to post"),
|
|
@@ -59632,7 +59707,7 @@ function registerCheckinTools(server, client2) {
|
|
|
59632
59707
|
{
|
|
59633
59708
|
title: "Delete a comment from an Untappd check-in",
|
|
59634
59709
|
description: "Delete one of YOUR comments by its comment id (the id from a check-in's comments list). Without confirm: true it returns a dry-run preview and makes NO network call; with confirm: true it deletes.",
|
|
59635
|
-
annotations: toolAnnotations({ title: "Delete a comment from an Untappd check-in", readOnly: false, idempotent: true, openWorld: true }),
|
|
59710
|
+
annotations: toolAnnotations({ title: "Delete a comment from an Untappd check-in", readOnly: false, idempotent: true, openWorld: true, destructive: true }),
|
|
59636
59711
|
inputSchema: external_exports.object({
|
|
59637
59712
|
comment_id: external_exports.number().int().positive().describe("Untappd comment id (from a check-in's comments.items)"),
|
|
59638
59713
|
confirm: schemaConfirm
|
|
@@ -59656,7 +59731,7 @@ function registerCheckinTools(server, client2) {
|
|
|
59656
59731
|
{
|
|
59657
59732
|
title: "Delete an Untappd check-in",
|
|
59658
59733
|
description: "Permanently delete one of YOUR check-ins by its id. This is destructive and cannot be undone. Without confirm: true it returns a dry-run preview and makes NO network call; with confirm: true it deletes.",
|
|
59659
|
-
annotations: toolAnnotations({ title: "Delete an Untappd check-in", readOnly: false, idempotent: true, openWorld: true }),
|
|
59734
|
+
annotations: toolAnnotations({ title: "Delete an Untappd check-in", readOnly: false, idempotent: true, openWorld: true, destructive: true }),
|
|
59660
59735
|
inputSchema: external_exports.object({
|
|
59661
59736
|
checkin_id: CheckinIdSchema,
|
|
59662
59737
|
confirm: schemaConfirm
|
|
@@ -59680,7 +59755,7 @@ function registerCheckinTools(server, client2) {
|
|
|
59680
59755
|
{
|
|
59681
59756
|
title: "Check in a beer on Untappd",
|
|
59682
59757
|
description: "Post a NEW beer check-in to YOUR Untappd account \u2014 this publishes to your public feed. Provide the beer id (bid) from untappd_search_beer; optionally a rating (0\u20135 in 0.25 steps), a shout (comment), a venue via foursquare_id, and a local photo via photo_path (JPEG/PNG). Without confirm: true it returns a dry-run preview of the exact fields and makes NO network call; with confirm: true it posts.",
|
|
59683
|
-
annotations: toolAnnotations({ title: "Check in a beer on Untappd", readOnly: false, idempotent: false, openWorld: true }),
|
|
59758
|
+
annotations: toolAnnotations({ title: "Check in a beer on Untappd", readOnly: false, idempotent: false, openWorld: true, destructive: false }),
|
|
59684
59759
|
inputSchema: external_exports.object({
|
|
59685
59760
|
bid: external_exports.number().int().positive().describe("Untappd beer id to check in (from untappd_search_beer)"),
|
|
59686
59761
|
rating: RatingSchema.optional().describe("Rating 0\u20135 in 0.25 increments (omit for no rating)"),
|
|
@@ -60194,7 +60269,7 @@ function registerCacheTools(server, client2, cacheProvider) {
|
|
|
60194
60269
|
{
|
|
60195
60270
|
title: "Sync a user's check-ins into the cache",
|
|
60196
60271
|
description: "Fetch a user's detailed check-ins (venue, date, comment) into the cache from user/checkins. Incremental and resumable: pages backwards up to max_pages per call, persisting progress every page; run again until another_run_needed is false. NOTE: Untappd only returns the ~50 most recent check-ins for accounts other than your own and will not page further \u2014 such a sync reports history_truncated and you should use untappd_sync_user_beers for full has-had coverage. backfill_complete is only reported once ~all of total_checkins is cached. Pass force_backfill: true to reset a cache wrongly marked complete and re-page the whole history (cached rows are kept). Omit username for your own account.",
|
|
60197
|
-
annotations: toolAnnotations({ title: "Sync a user's check-ins into the cache", readOnly: false, idempotent: false, openWorld: true }),
|
|
60272
|
+
annotations: toolAnnotations({ title: "Sync a user's check-ins into the cache", readOnly: false, idempotent: false, openWorld: true, destructive: false }),
|
|
60198
60273
|
inputSchema: external_exports.object({
|
|
60199
60274
|
username: UsernameArg2,
|
|
60200
60275
|
max_pages: external_exports.number().int().min(1).max(50).optional().describe("Pages (50 check-ins each) to fetch this run (default 10). Keep modest to respect the ~100 calls/hour rate limit."),
|
|
@@ -60215,7 +60290,7 @@ function registerCacheTools(server, client2, cacheProvider) {
|
|
|
60215
60290
|
{
|
|
60216
60291
|
title: "Sync a user's complete distinct-beers list into the cache",
|
|
60217
60292
|
description: `Fetch a user's COMPLETE distinct-beers list (every unique beer they've ever had, with their rating, times-had count, and first/last dates) into the cache from user/beers. This is the cheapest way to get full "has had" coverage \u2014 thousands of beers instead of tens of thousands of check-ins \u2014 and, unlike user/checkins, it pages fully for any public/friend account. Offset-paged and resumable: fetches max_pages per call and persists progress; run again until another_run_needed is false. Feeds the same untappd_cache_has_had / has_had_many / not_had tools. Omit username for your own account.`,
|
|
60218
|
-
annotations: toolAnnotations({ title: "Sync a user's complete distinct-beers list into the cache", readOnly: false, idempotent: false, openWorld: true }),
|
|
60293
|
+
annotations: toolAnnotations({ title: "Sync a user's complete distinct-beers list into the cache", readOnly: false, idempotent: false, openWorld: true, destructive: false }),
|
|
60219
60294
|
inputSchema: external_exports.object({
|
|
60220
60295
|
username: UsernameArg2,
|
|
60221
60296
|
max_pages: external_exports.number().int().min(1).max(50).optional().describe("Pages (50 beers each) to fetch this run (default 10). Keep modest to respect the ~100 calls/hour rate limit.")
|
|
@@ -60349,7 +60424,7 @@ function registerCacheTools(server, client2, cacheProvider) {
|
|
|
60349
60424
|
{
|
|
60350
60425
|
title: "Top-rated beers a user has NOT had, from a candidate list",
|
|
60351
60426
|
description: 'The "what should I order off this tap list?" tool. From a list of candidate beer ids, return the top N the user has NOT yet had, ranked by Untappd global rating, with an optional style filter. Not-had filtering uses the cache only (both sources, no API call). Beer ratings/styles come from a metadata cache; a beer/info API call is made only on a cache miss or if the cached metadata is >30 days old, capped at api_budget calls per run (~100 calls/hour limit) \u2014 if more are needed it returns partial: true / another_run_needed: true, so re-running fills the rest. Reports the same freshness/caveat block as untappd_cache_not_had. Omit username for your own account.',
|
|
60352
|
-
annotations: toolAnnotations({ title: "Top-rated beers a user has NOT had, from a candidate list", readOnly: false, idempotent: false, openWorld: true }),
|
|
60427
|
+
annotations: toolAnnotations({ title: "Top-rated beers a user has NOT had, from a candidate list", readOnly: false, idempotent: false, openWorld: true, destructive: false }),
|
|
60353
60428
|
inputSchema: external_exports.object({
|
|
60354
60429
|
username: UsernameArg2,
|
|
60355
60430
|
bids: external_exports.array(external_exports.number().int().positive()).min(1).max(100).describe("Candidate beer ids (1\u2013100)"),
|
package/dist/tools/cache.js
CHANGED
|
@@ -92,7 +92,7 @@ export function registerCacheTools(server, client, cacheProvider) {
|
|
|
92
92
|
'untappd_sync_user_beers for full has-had coverage. backfill_complete is only reported once ~all of ' +
|
|
93
93
|
'total_checkins is cached. Pass force_backfill: true to reset a cache wrongly marked complete and re-page ' +
|
|
94
94
|
'the whole history (cached rows are kept). Omit username for your own account.',
|
|
95
|
-
annotations: toolAnnotations({ title: "Sync a user's check-ins into the cache", readOnly: false, idempotent: false, openWorld: true }),
|
|
95
|
+
annotations: toolAnnotations({ title: "Sync a user's check-ins into the cache", readOnly: false, idempotent: false, openWorld: true, destructive: false }),
|
|
96
96
|
inputSchema: z.object({
|
|
97
97
|
username: UsernameArg,
|
|
98
98
|
max_pages: z
|
|
@@ -123,7 +123,7 @@ export function registerCacheTools(server, client, cacheProvider) {
|
|
|
123
123
|
'user/checkins, it pages fully for any public/friend account. Offset-paged and resumable: fetches max_pages ' +
|
|
124
124
|
'per call and persists progress; run again until another_run_needed is false. Feeds the same ' +
|
|
125
125
|
'untappd_cache_has_had / has_had_many / not_had tools. Omit username for your own account.',
|
|
126
|
-
annotations: toolAnnotations({ title: "Sync a user's complete distinct-beers list into the cache", readOnly: false, idempotent: false, openWorld: true }),
|
|
126
|
+
annotations: toolAnnotations({ title: "Sync a user's complete distinct-beers list into the cache", readOnly: false, idempotent: false, openWorld: true, destructive: false }),
|
|
127
127
|
inputSchema: z.object({
|
|
128
128
|
username: UsernameArg,
|
|
129
129
|
max_pages: z
|
|
@@ -271,7 +271,7 @@ export function registerCacheTools(server, client, cacheProvider) {
|
|
|
271
271
|
'run (~100 calls/hour limit) — if more are needed it returns partial: true / another_run_needed: true, so ' +
|
|
272
272
|
're-running fills the rest. Reports the same freshness/caveat block as untappd_cache_not_had. Omit username ' +
|
|
273
273
|
'for your own account.',
|
|
274
|
-
annotations: toolAnnotations({ title: 'Top-rated beers a user has NOT had, from a candidate list', readOnly: false, idempotent: false, openWorld: true }),
|
|
274
|
+
annotations: toolAnnotations({ title: 'Top-rated beers a user has NOT had, from a candidate list', readOnly: false, idempotent: false, openWorld: true, destructive: false }),
|
|
275
275
|
inputSchema: z.object({
|
|
276
276
|
username: UsernameArg,
|
|
277
277
|
bids: z.array(z.number().int().positive()).min(1).max(100).describe('Candidate beer ids (1–100)'),
|
package/dist/tools/checkin.js
CHANGED
|
@@ -28,7 +28,7 @@ export function registerCheckinTools(server, client) {
|
|
|
28
28
|
description: "Toast (like) a check-in on YOUR account. This endpoint is a TOGGLE: calling it on a check-in you have " +
|
|
29
29
|
'already toasted removes the toast. Without confirm: true it returns a dry-run preview and makes NO network ' +
|
|
30
30
|
'call; with confirm: true it posts. Writes to your Untappd account and is visible to others.',
|
|
31
|
-
annotations: toolAnnotations({ title: 'Toast an Untappd check-in', readOnly: false, idempotent: false, openWorld: true }),
|
|
31
|
+
annotations: toolAnnotations({ title: 'Toast an Untappd check-in', readOnly: false, idempotent: false, openWorld: true, destructive: false }),
|
|
32
32
|
inputSchema: z.object({
|
|
33
33
|
checkin_id: CheckinIdSchema,
|
|
34
34
|
confirm: schemaConfirm,
|
|
@@ -49,7 +49,7 @@ export function registerCheckinTools(server, client) {
|
|
|
49
49
|
title: 'Comment on an Untappd check-in',
|
|
50
50
|
description: 'Post a comment on a check-in from YOUR account. Without confirm: true it returns a dry-run preview and ' +
|
|
51
51
|
'makes NO network call; with confirm: true it posts. Writes to your Untappd account and is visible to others.',
|
|
52
|
-
annotations: toolAnnotations({ title: 'Comment on an Untappd check-in', readOnly: false, idempotent: false, openWorld: true }),
|
|
52
|
+
annotations: toolAnnotations({ title: 'Comment on an Untappd check-in', readOnly: false, idempotent: false, openWorld: true, destructive: false }),
|
|
53
53
|
inputSchema: z.object({
|
|
54
54
|
checkin_id: CheckinIdSchema,
|
|
55
55
|
comment: z.string().min(1).max(2000).describe('Comment text to post'),
|
|
@@ -72,7 +72,7 @@ export function registerCheckinTools(server, client) {
|
|
|
72
72
|
title: 'Delete a comment from an Untappd check-in',
|
|
73
73
|
description: 'Delete one of YOUR comments by its comment id (the id from a check-in\'s comments list). Without ' +
|
|
74
74
|
'confirm: true it returns a dry-run preview and makes NO network call; with confirm: true it deletes.',
|
|
75
|
-
annotations: toolAnnotations({ title: 'Delete a comment from an Untappd check-in', readOnly: false, idempotent: true, openWorld: true }),
|
|
75
|
+
annotations: toolAnnotations({ title: 'Delete a comment from an Untappd check-in', readOnly: false, idempotent: true, openWorld: true, destructive: true }),
|
|
76
76
|
inputSchema: z.object({
|
|
77
77
|
comment_id: z.number().int().positive().describe('Untappd comment id (from a check-in\'s comments.items)'),
|
|
78
78
|
confirm: schemaConfirm,
|
|
@@ -93,7 +93,7 @@ export function registerCheckinTools(server, client) {
|
|
|
93
93
|
title: 'Delete an Untappd check-in',
|
|
94
94
|
description: 'Permanently delete one of YOUR check-ins by its id. This is destructive and cannot be undone. Without ' +
|
|
95
95
|
'confirm: true it returns a dry-run preview and makes NO network call; with confirm: true it deletes.',
|
|
96
|
-
annotations: toolAnnotations({ title: 'Delete an Untappd check-in', readOnly: false, idempotent: true, openWorld: true }),
|
|
96
|
+
annotations: toolAnnotations({ title: 'Delete an Untappd check-in', readOnly: false, idempotent: true, openWorld: true, destructive: true }),
|
|
97
97
|
inputSchema: z.object({
|
|
98
98
|
checkin_id: CheckinIdSchema,
|
|
99
99
|
confirm: schemaConfirm,
|
|
@@ -116,7 +116,7 @@ export function registerCheckinTools(server, client) {
|
|
|
116
116
|
'(bid) from untappd_search_beer; optionally a rating (0–5 in 0.25 steps), a shout (comment), a venue via ' +
|
|
117
117
|
'foursquare_id, and a local photo via photo_path (JPEG/PNG). Without confirm: true it returns a dry-run ' +
|
|
118
118
|
'preview of the exact fields and makes NO network call; with confirm: true it posts.',
|
|
119
|
-
annotations: toolAnnotations({ title: 'Check in a beer on Untappd', readOnly: false, idempotent: false, openWorld: true }),
|
|
119
|
+
annotations: toolAnnotations({ title: 'Check in a beer on Untappd', readOnly: false, idempotent: false, openWorld: true, destructive: false }),
|
|
120
120
|
inputSchema: z.object({
|
|
121
121
|
bid: z.number().int().positive().describe('Untappd beer id to check in (from untappd_search_beer)'),
|
|
122
122
|
rating: RatingSchema.optional().describe('Rating 0–5 in 0.25 increments (omit for no rating)'),
|
package/dist/tools/friends.js
CHANGED
|
@@ -50,7 +50,11 @@ export function registerFriendActionTools(server, client) {
|
|
|
50
50
|
'Without confirm: true it returns a dry-run preview and makes NO network call; with confirm: true it ' +
|
|
51
51
|
'performs the action. Note: this endpoint path is taken from the Untappd app but is not otherwise ' +
|
|
52
52
|
'independently verified.',
|
|
53
|
-
|
|
53
|
+
// All four reach ANOTHER PERSON — the description says so itself: "affects
|
|
54
|
+
// a real relationship with another person". A friend request cannot be
|
|
55
|
+
// un-sent, and a rejection cannot be un-rejected, so none of them has an
|
|
56
|
+
// inverse in this tool set.
|
|
57
|
+
annotations: toolAnnotations({ title: action.title, readOnly: false, idempotent: true, openWorld: true, destructive: true }),
|
|
54
58
|
inputSchema: z.object({
|
|
55
59
|
target_uid: TargetUidSchema,
|
|
56
60
|
confirm: schemaConfirm,
|
package/dist/tools/wishlist.js
CHANGED
|
@@ -6,7 +6,7 @@ export function registerWishlistTools(server, client) {
|
|
|
6
6
|
title: 'Add a beer to your wishlist',
|
|
7
7
|
description: 'Add a beer to YOUR Untappd wishlist by its bid. Without confirm: true it returns a dry-run preview and ' +
|
|
8
8
|
'makes NO network call; with confirm: true it adds. Writes to your account.',
|
|
9
|
-
annotations: toolAnnotations({ title: 'Add a beer to your wishlist', readOnly: false, idempotent: true, openWorld: true }),
|
|
9
|
+
annotations: toolAnnotations({ title: 'Add a beer to your wishlist', readOnly: false, idempotent: true, openWorld: true, destructive: false }),
|
|
10
10
|
inputSchema: z.object({
|
|
11
11
|
bid: BidSchema,
|
|
12
12
|
confirm: schemaConfirm,
|
|
@@ -27,7 +27,7 @@ export function registerWishlistTools(server, client) {
|
|
|
27
27
|
title: 'Remove a beer from your wishlist',
|
|
28
28
|
description: 'Remove a beer from YOUR Untappd wishlist by its bid. Without confirm: true it returns a dry-run preview ' +
|
|
29
29
|
'and makes NO network call; with confirm: true it removes. Writes to your account.',
|
|
30
|
-
annotations: toolAnnotations({ title: 'Remove a beer from your wishlist', readOnly: false, idempotent: true, openWorld: true }),
|
|
30
|
+
annotations: toolAnnotations({ title: 'Remove a beer from your wishlist', readOnly: false, idempotent: true, openWorld: true, destructive: false }),
|
|
31
31
|
inputSchema: z.object({
|
|
32
32
|
bid: BidSchema,
|
|
33
33
|
confirm: schemaConfirm,
|
package/dist/version.js
CHANGED
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
// json's `extra-files`), and `versionSyncTest` guards that it stays equal to
|
|
4
4
|
// package.json. Import VERSION wherever the version is needed rather than
|
|
5
5
|
// re-declaring it.
|
|
6
|
-
export const VERSION = '2.1.
|
|
6
|
+
export const VERSION = '2.1.1'; // x-release-please-version
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "untappd-mcp",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"mcpName": "io.github.chrischall/untappd-mcp",
|
|
5
5
|
"description": "Untappd MCP server for Claude — developed and maintained by AI (Claude Code)",
|
|
6
6
|
"author": "Claude Code (AI) <https://www.anthropic.com/claude>",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@chrischall/mcp-utils": "^
|
|
48
|
+
"@chrischall/mcp-utils": "^2.2.0",
|
|
49
49
|
"@modelcontextprotocol/server": "^2.0.0",
|
|
50
50
|
"ai": "^7.0.19",
|
|
51
51
|
"dotenv": "^17.4.0",
|
package/server.json
CHANGED
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
"url": "https://github.com/chrischall/untappd-mcp",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "2.1.
|
|
9
|
+
"version": "2.1.1",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "untappd-mcp",
|
|
14
|
-
"version": "2.1.
|
|
14
|
+
"version": "2.1.1",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|