untappd-mcp 1.8.7 → 1.9.0
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/README.md +3 -2
- package/dist/bundle.js +91 -53
- package/dist/client.js +30 -6
- package/dist/version.js +1 -1
- package/mint.yaml +68 -0
- package/package.json +7 -5
- 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": "1.
|
|
10
|
+
"version": "1.9.0"
|
|
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": "1.
|
|
18
|
+
"version": "1.9.0",
|
|
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": "1.
|
|
4
|
+
"version": "1.9.0",
|
|
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/README.md
CHANGED
|
@@ -26,8 +26,9 @@ it goes stale.
|
|
|
26
26
|
|
|
27
27
|
| Variable | Required | Description |
|
|
28
28
|
| --- | --- | --- |
|
|
29
|
-
| `
|
|
30
|
-
| `
|
|
29
|
+
| `UNTAPPD_ACCESS_TOKEN` | no | An access token you already hold. Supply this and **no password is needed** — the xauth login is skipped entirely. |
|
|
30
|
+
| `UNTAPPD_USERNAME` | if no token | Your Untappd username or login email. |
|
|
31
|
+
| `UNTAPPD_PASSWORD` | if no token | Your Untappd password (used only for the xauth login that mints a token). |
|
|
31
32
|
| `UNTAPPD_CLIENT_ID` | yes | The Untappd mobile app client id (see below). |
|
|
32
33
|
| `UNTAPPD_CLIENT_SECRET` | yes | The Untappd mobile app client secret. |
|
|
33
34
|
| `UNTAPPD_DEVICE_ID` | no | Stable device UUID the token is keyed to (a default is provided). |
|
package/dist/bundle.js
CHANGED
|
@@ -31000,53 +31000,6 @@ var StdioServerTransport = class {
|
|
|
31000
31000
|
}
|
|
31001
31001
|
};
|
|
31002
31002
|
|
|
31003
|
-
// node_modules/@chrischall/mcp-utils/dist/server/index.js
|
|
31004
|
-
async function createMcpServer(opts) {
|
|
31005
|
-
const server = new McpServer({ name: opts.name, version: opts.version });
|
|
31006
|
-
if (opts.banner !== void 0) {
|
|
31007
|
-
console.error(opts.banner);
|
|
31008
|
-
}
|
|
31009
|
-
const deps = opts.deps;
|
|
31010
|
-
for (const register of opts.tools) {
|
|
31011
|
-
await register(server, deps);
|
|
31012
|
-
}
|
|
31013
|
-
return server;
|
|
31014
|
-
}
|
|
31015
|
-
function withGracefulShutdown(server, opts = {}) {
|
|
31016
|
-
const shouldExit = opts.exit ?? true;
|
|
31017
|
-
let shuttingDown = false;
|
|
31018
|
-
const handler = (signal) => {
|
|
31019
|
-
if (shuttingDown)
|
|
31020
|
-
return;
|
|
31021
|
-
shuttingDown = true;
|
|
31022
|
-
void (async () => {
|
|
31023
|
-
try {
|
|
31024
|
-
if (opts.onSignal)
|
|
31025
|
-
await opts.onSignal(signal);
|
|
31026
|
-
await server.close();
|
|
31027
|
-
} catch (err) {
|
|
31028
|
-
console.error(`[mcp-utils] error during graceful shutdown on ${signal}: ${err instanceof Error ? err.message : String(err)}`);
|
|
31029
|
-
} finally {
|
|
31030
|
-
if (shouldExit)
|
|
31031
|
-
process.exit(0);
|
|
31032
|
-
}
|
|
31033
|
-
})();
|
|
31034
|
-
};
|
|
31035
|
-
process.on("SIGINT", () => handler("SIGINT"));
|
|
31036
|
-
process.on("SIGTERM", () => handler("SIGTERM"));
|
|
31037
|
-
}
|
|
31038
|
-
async function runMcp(opts) {
|
|
31039
|
-
const server = await createMcpServer(opts);
|
|
31040
|
-
const shutdown = opts.shutdown ?? true;
|
|
31041
|
-
if (shutdown !== false) {
|
|
31042
|
-
withGracefulShutdown(server, shutdown === true ? {} : shutdown);
|
|
31043
|
-
}
|
|
31044
|
-
const spec = opts.transport ?? "stdio";
|
|
31045
|
-
const transport = spec === "stdio" ? new StdioServerTransport() : spec;
|
|
31046
|
-
await server.connect(transport);
|
|
31047
|
-
return server;
|
|
31048
|
-
}
|
|
31049
|
-
|
|
31050
31003
|
// node_modules/@chrischall/mcp-utils/dist/errors/index.js
|
|
31051
31004
|
var DEFAULT_ERROR_MESSAGE_MAX = 500;
|
|
31052
31005
|
var McpToolError = class extends Error {
|
|
@@ -31133,6 +31086,81 @@ function textResult(data) {
|
|
|
31133
31086
|
content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
|
|
31134
31087
|
};
|
|
31135
31088
|
}
|
|
31089
|
+
function errorResult(message) {
|
|
31090
|
+
return {
|
|
31091
|
+
content: [{ type: "text", text: redactSecrets(message) }],
|
|
31092
|
+
isError: true
|
|
31093
|
+
};
|
|
31094
|
+
}
|
|
31095
|
+
|
|
31096
|
+
// node_modules/@chrischall/mcp-utils/dist/server/index.js
|
|
31097
|
+
function hintResultOrRethrow(err) {
|
|
31098
|
+
if (err instanceof McpToolError && err.hint) {
|
|
31099
|
+
return errorResult(`${err.message}
|
|
31100
|
+
|
|
31101
|
+
Hint: ${err.hint}`);
|
|
31102
|
+
}
|
|
31103
|
+
throw err;
|
|
31104
|
+
}
|
|
31105
|
+
function surfaceToolHints(server) {
|
|
31106
|
+
const register = server.registerTool.bind(server);
|
|
31107
|
+
server.registerTool = (name, config2, cb) => register(name, config2, (...args) => {
|
|
31108
|
+
let result;
|
|
31109
|
+
try {
|
|
31110
|
+
result = cb(...args);
|
|
31111
|
+
} catch (err) {
|
|
31112
|
+
return hintResultOrRethrow(err);
|
|
31113
|
+
}
|
|
31114
|
+
return result instanceof Promise ? result.catch(hintResultOrRethrow) : result;
|
|
31115
|
+
});
|
|
31116
|
+
}
|
|
31117
|
+
async function createMcpServer(opts) {
|
|
31118
|
+
const server = new McpServer({ name: opts.name, version: opts.version });
|
|
31119
|
+
if (opts.surfaceHints !== false)
|
|
31120
|
+
surfaceToolHints(server);
|
|
31121
|
+
if (opts.banner !== void 0) {
|
|
31122
|
+
console.error(opts.banner);
|
|
31123
|
+
}
|
|
31124
|
+
const deps = opts.deps;
|
|
31125
|
+
for (const register of opts.tools) {
|
|
31126
|
+
await register(server, deps);
|
|
31127
|
+
}
|
|
31128
|
+
return server;
|
|
31129
|
+
}
|
|
31130
|
+
function withGracefulShutdown(server, opts = {}) {
|
|
31131
|
+
const shouldExit = opts.exit ?? true;
|
|
31132
|
+
let shuttingDown = false;
|
|
31133
|
+
const handler = (signal) => {
|
|
31134
|
+
if (shuttingDown)
|
|
31135
|
+
return;
|
|
31136
|
+
shuttingDown = true;
|
|
31137
|
+
void (async () => {
|
|
31138
|
+
try {
|
|
31139
|
+
if (opts.onSignal)
|
|
31140
|
+
await opts.onSignal(signal);
|
|
31141
|
+
await server.close();
|
|
31142
|
+
} catch (err) {
|
|
31143
|
+
console.error(`[mcp-utils] error during graceful shutdown on ${signal}: ${err instanceof Error ? err.message : String(err)}`);
|
|
31144
|
+
} finally {
|
|
31145
|
+
if (shouldExit)
|
|
31146
|
+
process.exit(0);
|
|
31147
|
+
}
|
|
31148
|
+
})();
|
|
31149
|
+
};
|
|
31150
|
+
process.on("SIGINT", () => handler("SIGINT"));
|
|
31151
|
+
process.on("SIGTERM", () => handler("SIGTERM"));
|
|
31152
|
+
}
|
|
31153
|
+
async function runMcp(opts) {
|
|
31154
|
+
const server = await createMcpServer(opts);
|
|
31155
|
+
const shutdown = opts.shutdown ?? true;
|
|
31156
|
+
if (shutdown !== false) {
|
|
31157
|
+
withGracefulShutdown(server, shutdown === true ? {} : shutdown);
|
|
31158
|
+
}
|
|
31159
|
+
const spec = opts.transport ?? "stdio";
|
|
31160
|
+
const transport = spec === "stdio" ? new StdioServerTransport() : spec;
|
|
31161
|
+
await server.connect(transport);
|
|
31162
|
+
return server;
|
|
31163
|
+
}
|
|
31136
31164
|
|
|
31137
31165
|
// node_modules/@chrischall/mcp-utils/dist/config/index.js
|
|
31138
31166
|
var PLACEHOLDER_RE = /^\$\{[^}]*\}$/;
|
|
@@ -31232,7 +31260,7 @@ function toolAnnotations(opts = {}) {
|
|
|
31232
31260
|
}
|
|
31233
31261
|
|
|
31234
31262
|
// src/version.ts
|
|
31235
|
-
var VERSION = "1.
|
|
31263
|
+
var VERSION = "1.9.0";
|
|
31236
31264
|
|
|
31237
31265
|
// src/client.ts
|
|
31238
31266
|
import { dirname, join } from "path";
|
|
@@ -31324,11 +31352,10 @@ async function xauthLogin(creds, opts = {}) {
|
|
|
31324
31352
|
}
|
|
31325
31353
|
function missingCredsError() {
|
|
31326
31354
|
const missing = ["UNTAPPD_USERNAME", "UNTAPPD_PASSWORD", "UNTAPPD_CLIENT_ID", "UNTAPPD_CLIENT_SECRET"].filter((k) => !readEnvVar(k));
|
|
31355
|
+
const remedy = "Either set UNTAPPD_ACCESS_TOKEN (an access token you already hold \u2014 no password needed), or set UNTAPPD_USERNAME and UNTAPPD_PASSWORD to log in for one. Either way UNTAPPD_CLIENT_ID and UNTAPPD_CLIENT_SECRET (the Untappd mobile app client credentials) are required. See the README.";
|
|
31327
31356
|
return createHelpfulError(
|
|
31328
|
-
`Untappd credentials are not configured \u2014 missing ${missing.join(", ") || "credentials"}
|
|
31329
|
-
{
|
|
31330
|
-
hint: "Set UNTAPPD_USERNAME and UNTAPPD_PASSWORD (your Untappd login), plus UNTAPPD_CLIENT_ID and UNTAPPD_CLIENT_SECRET (the Untappd mobile app client credentials). See the README for how to obtain them."
|
|
31331
|
-
}
|
|
31357
|
+
`Untappd credentials are not configured \u2014 missing ${missing.join(", ") || "credentials"}. ${remedy}`,
|
|
31358
|
+
{ hint: remedy }
|
|
31332
31359
|
);
|
|
31333
31360
|
}
|
|
31334
31361
|
var UntappdClient = class {
|
|
@@ -31343,6 +31370,7 @@ var UntappdClient = class {
|
|
|
31343
31370
|
userAgent = readEnvVar("UNTAPPD_USER_AGENT") ?? DEFAULTS.userAgent;
|
|
31344
31371
|
token;
|
|
31345
31372
|
loginInFlight = null;
|
|
31373
|
+
tokenIsSupplied;
|
|
31346
31374
|
/**
|
|
31347
31375
|
* Defer the config error so the server can still start (and respond to the
|
|
31348
31376
|
* host's install-time tools/list smoke test) when credentials aren't set yet.
|
|
@@ -31350,7 +31378,8 @@ var UntappdClient = class {
|
|
|
31350
31378
|
*/
|
|
31351
31379
|
constructor(opts = {}) {
|
|
31352
31380
|
this.fetchImpl = opts.fetchImpl ?? fetch;
|
|
31353
|
-
this.token = opts.token ?? null;
|
|
31381
|
+
this.token = opts.token ?? readEnvVar("UNTAPPD_ACCESS_TOKEN") ?? null;
|
|
31382
|
+
this.tokenIsSupplied = this.token !== null;
|
|
31354
31383
|
this.clientId = opts.clientId ?? readEnvVar("UNTAPPD_CLIENT_ID") ?? null;
|
|
31355
31384
|
this.clientSecret = opts.clientSecret ?? readEnvVar("UNTAPPD_CLIENT_SECRET") ?? null;
|
|
31356
31385
|
this.username = opts.username ?? readEnvVar("UNTAPPD_USERNAME") ?? null;
|
|
@@ -31413,6 +31442,7 @@ var UntappdClient = class {
|
|
|
31413
31442
|
userAgent: this.userAgent
|
|
31414
31443
|
});
|
|
31415
31444
|
this.token = token;
|
|
31445
|
+
this.tokenIsSupplied = false;
|
|
31416
31446
|
return token;
|
|
31417
31447
|
}
|
|
31418
31448
|
async parseJson(res, method, path) {
|
|
@@ -31462,6 +31492,14 @@ var UntappdClient = class {
|
|
|
31462
31492
|
}
|
|
31463
31493
|
const res = await this.send(method, `${BASE_URL}${path}${qs}`, { headers, body });
|
|
31464
31494
|
if (res.status === 401 && !isRetry) {
|
|
31495
|
+
if (this.tokenIsSupplied && !(this.username && this.password)) {
|
|
31496
|
+
throw createHelpfulError(
|
|
31497
|
+
"Untappd rejected the access token (401) \u2014 UNTAPPD_ACCESS_TOKEN has expired or been revoked. Supply a fresh token, or set UNTAPPD_USERNAME and UNTAPPD_PASSWORD so a new one can be minted automatically.",
|
|
31498
|
+
{
|
|
31499
|
+
hint: "The token is stale, not missing. A pre-seeded token cannot be refreshed without a login."
|
|
31500
|
+
}
|
|
31501
|
+
);
|
|
31502
|
+
}
|
|
31465
31503
|
this.token = null;
|
|
31466
31504
|
return this.request(method, path, opts, true);
|
|
31467
31505
|
}
|
package/dist/client.js
CHANGED
|
@@ -112,10 +112,13 @@ export async function xauthLogin(creds, opts = {}) {
|
|
|
112
112
|
}
|
|
113
113
|
function missingCredsError() {
|
|
114
114
|
const missing = ['UNTAPPD_USERNAME', 'UNTAPPD_PASSWORD', 'UNTAPPD_CLIENT_ID', 'UNTAPPD_CLIENT_SECRET'].filter((k) => !readEnvVar(k));
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
115
|
+
// Both paths in the MESSAGE, not only `hint`: MCP serialization surfaces the
|
|
116
|
+
// message and drops the hint, so a token path mentioned only there is
|
|
117
|
+
// invisible exactly when someone is deciding what to configure.
|
|
118
|
+
const remedy = 'Either set UNTAPPD_ACCESS_TOKEN (an access token you already hold — no password needed), or set ' +
|
|
119
|
+
'UNTAPPD_USERNAME and UNTAPPD_PASSWORD to log in for one. Either way UNTAPPD_CLIENT_ID and ' +
|
|
120
|
+
'UNTAPPD_CLIENT_SECRET (the Untappd mobile app client credentials) are required. See the README.';
|
|
121
|
+
return createHelpfulError(`Untappd credentials are not configured — missing ${missing.join(', ') || 'credentials'}. ${remedy}`, { hint: remedy });
|
|
119
122
|
}
|
|
120
123
|
export class UntappdClient {
|
|
121
124
|
fetchImpl;
|
|
@@ -129,6 +132,7 @@ export class UntappdClient {
|
|
|
129
132
|
userAgent = readEnvVar('UNTAPPD_USER_AGENT') ?? DEFAULTS.userAgent;
|
|
130
133
|
token;
|
|
131
134
|
loginInFlight = null;
|
|
135
|
+
tokenIsSupplied;
|
|
132
136
|
/**
|
|
133
137
|
* Defer the config error so the server can still start (and respond to the
|
|
134
138
|
* host's install-time tools/list smoke test) when credentials aren't set yet.
|
|
@@ -136,7 +140,15 @@ export class UntappdClient {
|
|
|
136
140
|
*/
|
|
137
141
|
constructor(opts = {}) {
|
|
138
142
|
this.fetchImpl = opts.fetchImpl ?? fetch;
|
|
139
|
-
|
|
143
|
+
// Path 1 of the ladder: a token the consumer already holds. Reachable from
|
|
144
|
+
// the environment, not just from code — otherwise the only configuration a
|
|
145
|
+
// deployment can express is "hand over the password", which is the shape
|
|
146
|
+
// this exists to avoid.
|
|
147
|
+
this.token = opts.token ?? readEnvVar('UNTAPPD_ACCESS_TOKEN') ?? null;
|
|
148
|
+
// Whether that token was GIVEN to us rather than minted by a login. It
|
|
149
|
+
// decides what a later 401 means: a minted token can simply be re-minted,
|
|
150
|
+
// a supplied one can only be replaced by whoever supplied it.
|
|
151
|
+
this.tokenIsSupplied = this.token !== null;
|
|
140
152
|
this.clientId = opts.clientId ?? readEnvVar('UNTAPPD_CLIENT_ID') ?? null;
|
|
141
153
|
this.clientSecret = opts.clientSecret ?? readEnvVar('UNTAPPD_CLIENT_SECRET') ?? null;
|
|
142
154
|
this.username = opts.username ?? readEnvVar('UNTAPPD_USERNAME') ?? null;
|
|
@@ -203,6 +215,7 @@ export class UntappdClient {
|
|
|
203
215
|
userAgent: this.userAgent,
|
|
204
216
|
});
|
|
205
217
|
this.token = token;
|
|
218
|
+
this.tokenIsSupplied = false;
|
|
206
219
|
return token;
|
|
207
220
|
}
|
|
208
221
|
async parseJson(res, method, path) {
|
|
@@ -259,8 +272,19 @@ export class UntappdClient {
|
|
|
259
272
|
body = f.toString();
|
|
260
273
|
}
|
|
261
274
|
const res = await this.send(method, `${BASE_URL}${path}${qs}`, { headers, body });
|
|
262
|
-
// A 401 means the
|
|
275
|
+
// A 401 means the token went stale. Re-minting one needs a login, and a
|
|
276
|
+
// deployment that SUPPLIED the token may have no username/password to log
|
|
277
|
+
// in with — that fell through to `missingCredsError()` and told the
|
|
278
|
+
// operator to set the very variable they had set (CLAUDE.md, "a pre-seeded
|
|
279
|
+
// token is one-way"). Name what actually happened instead, and don't spend
|
|
280
|
+
// a second request discovering there is nothing to retry with.
|
|
263
281
|
if (res.status === 401 && !isRetry) {
|
|
282
|
+
if (this.tokenIsSupplied && !(this.username && this.password)) {
|
|
283
|
+
throw createHelpfulError('Untappd rejected the access token (401) — UNTAPPD_ACCESS_TOKEN has expired or been revoked. ' +
|
|
284
|
+
'Supply a fresh token, or set UNTAPPD_USERNAME and UNTAPPD_PASSWORD so a new one can be minted automatically.', {
|
|
285
|
+
hint: 'The token is stale, not missing. A pre-seeded token cannot be refreshed without a login.',
|
|
286
|
+
});
|
|
287
|
+
}
|
|
264
288
|
this.token = null;
|
|
265
289
|
return this.request(method, path, opts, true);
|
|
266
290
|
}
|
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 = '1.
|
|
6
|
+
export const VERSION = '1.9.0'; // x-release-please-version
|
package/mint.yaml
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
version: 1
|
|
2
|
+
name: Untappd
|
|
3
|
+
slug: untappd
|
|
4
|
+
summary: >-
|
|
5
|
+
Search Untappd beers, breweries, and venues; read profiles, check-ins,
|
|
6
|
+
wishlists, and your friend feed; and post check-ins, toasts, and comments
|
|
7
|
+
to your account
|
|
8
|
+
env:
|
|
9
|
+
- name: UNTAPPD_USERNAME
|
|
10
|
+
required: true
|
|
11
|
+
help: >-
|
|
12
|
+
Your Untappd username or login email.
|
|
13
|
+
- name: UNTAPPD_PASSWORD
|
|
14
|
+
secret: true
|
|
15
|
+
required: true
|
|
16
|
+
help: >-
|
|
17
|
+
Your Untappd account password (used only for xauth login).
|
|
18
|
+
- name: UNTAPPD_CLIENT_ID
|
|
19
|
+
secret: true
|
|
20
|
+
required: true
|
|
21
|
+
help: >-
|
|
22
|
+
Untappd mobile app client id (obtained by intercepting the app; see
|
|
23
|
+
README).
|
|
24
|
+
- name: UNTAPPD_CLIENT_SECRET
|
|
25
|
+
secret: true
|
|
26
|
+
required: true
|
|
27
|
+
help: >-
|
|
28
|
+
Untappd mobile app client secret.
|
|
29
|
+
- name: UNTAPPD_CACHE_DB
|
|
30
|
+
required: false
|
|
31
|
+
help: >-
|
|
32
|
+
Path to the on-disk check-in cache (defaults to
|
|
33
|
+
~/.untappd-mcp/checkins.db). Relates to state.dataDir below.
|
|
34
|
+
- name: UNTAPPD_DEVICE_ID
|
|
35
|
+
required: false
|
|
36
|
+
help: >-
|
|
37
|
+
A stable UUID that Untappd keys the returned access token to. Any stable
|
|
38
|
+
value works; set it to pin your own instead of the built-in default.
|
|
39
|
+
- name: UNTAPPD_USER_AGENT
|
|
40
|
+
required: false
|
|
41
|
+
help: >-
|
|
42
|
+
Overrides the User-Agent sent upstream. Leave unset unless the service
|
|
43
|
+
requires a specific one.
|
|
44
|
+
- name: UNTAPPD_UTV
|
|
45
|
+
required: false
|
|
46
|
+
help: >-
|
|
47
|
+
Overrides the Untappd app version string, which is sent on every request
|
|
48
|
+
(not only at login). Leave unset unless a version bump is needed to keep
|
|
49
|
+
the API accepting requests.
|
|
50
|
+
state:
|
|
51
|
+
dataDir: true
|
|
52
|
+
reason: >-
|
|
53
|
+
Persists the check-in cache SQLite database (UNTAPPD_CACHE_DB, default
|
|
54
|
+
~/.untappd-mcp/checkins.db) under $HOME. Without it every cold start begins
|
|
55
|
+
with an empty cache and has to re-sync from the API. The access token is
|
|
56
|
+
NOT persisted — it is held in memory only — so this is about avoiding
|
|
57
|
+
repeated syncs, not about surviving authentication.
|
|
58
|
+
egress:
|
|
59
|
+
allow:
|
|
60
|
+
# Only hosts the SERVER process actually fetches. Hosts that appear
|
|
61
|
+
# solely in a URL this server BUILDS and returns are excluded.
|
|
62
|
+
- api.untappd.com
|
|
63
|
+
#
|
|
64
|
+
# NOTE — this server also reaches at least one host determined at
|
|
65
|
+
# RUNTIME, which cannot appear as a literal here:
|
|
66
|
+
# - a signed upload URL returned by the API (often storage.googleapis.com / s3)
|
|
67
|
+
# Confirm the concrete host(s) against a live run and add them, or
|
|
68
|
+
# the isolated tier will block the call.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "untappd-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.0",
|
|
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>",
|
|
@@ -29,18 +29,20 @@
|
|
|
29
29
|
".claude-plugin",
|
|
30
30
|
"skills/",
|
|
31
31
|
".mcp.json",
|
|
32
|
-
"server.json"
|
|
32
|
+
"server.json",
|
|
33
|
+
"mint.yaml"
|
|
33
34
|
],
|
|
34
35
|
"scripts": {
|
|
35
36
|
"build": "tsc && npm run bundle",
|
|
36
37
|
"bundle": "esbuild src/index.ts --bundle --platform=node --format=esm --external:dotenv --outfile=dist/bundle.js",
|
|
37
38
|
"dev": "node dist/index.js",
|
|
38
|
-
"test": "vitest run",
|
|
39
|
+
"test": "npm run typecheck && vitest run",
|
|
39
40
|
"test:watch": "vitest",
|
|
40
|
-
"test:coverage": "vitest run --coverage"
|
|
41
|
+
"test:coverage": "npm run typecheck && vitest run --coverage",
|
|
42
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
41
43
|
},
|
|
42
44
|
"dependencies": {
|
|
43
|
-
"@chrischall/mcp-utils": "^0.
|
|
45
|
+
"@chrischall/mcp-utils": "^0.15.0",
|
|
44
46
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
45
47
|
"ai": "^7.0.19",
|
|
46
48
|
"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": "1.
|
|
9
|
+
"version": "1.9.0",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "untappd-mcp",
|
|
14
|
-
"version": "1.
|
|
14
|
+
"version": "1.9.0",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|