hevy-mcp 2.0.0 → 3.0.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/README.md CHANGED
@@ -103,6 +103,12 @@ The server uses stdio, so `-i` keeps standard input open for the MCP client.
103
103
  form forwards the variable from the host environment without putting the key
104
104
  in the command arguments.
105
105
 
106
+ The image uses the official Node.js LTS Alpine base, runs as the non-root
107
+ `node` user, and ships the application and its third-party runtime dependencies
108
+ as a standalone bundle. It does not include an application `/app/node_modules`
109
+ directory; the official Node base image may still contain its own globally
110
+ packaged npm or Corepack files.
111
+
106
112
  Use `latest` to follow the newest stable release. For reproducible deployments,
107
113
  pin the exact version shown on the release, using a tag such as
108
114
  `ghcr.io/chrisdoc/hevy-mcp:X.Y.Z`. Major (`:X`) and major.minor (`:X.Y`) tags
@@ -230,10 +236,6 @@ This bootstraps the `hevy-mcp` entry in your client config without manual JSON e
230
236
  Supply your Hevy API key via the `HEVY_API_KEY` environment variable (in
231
237
  `.env` or system environment).
232
238
 
233
- > ⚠️ CLI API key arguments (`--hevy-api-key=...`, `--hevyApiKey=...`,
234
- > `hevy-api-key=...`) are still accepted for backward compatibility, but are
235
- > deprecated and insecure. Use `HEVY_API_KEY` instead.
236
-
237
239
  Set `HEVY_MCP_API_TIMEOUT` to override the default 30-second Hevy API request
238
240
  timeout. Its value is in milliseconds.
239
241
 
@@ -337,9 +339,11 @@ Compatibility note: with MCP SDK v1.29.0, clients using the default must send
337
339
  - **Build**: `npm run build`
338
340
  - **Lint/Format**: `npm run check` (uses oxlint/oxfmt)
339
341
  - **Type Check**: `npm run check:types`
340
- - **Unit Tests**: `npx vitest run --exclude 'tests/integration/**'`
341
- - **Full Test Suite**: `npm test` (requires `HEVY_API_KEY`)
342
+ - **Unit Tests**: `npm run test:unit`
343
+ - **Full Vitest Discovery**: `npm test` (builds first; live tests skip when
344
+ `HEVY_API_KEY` is absent)
342
345
  - **Changeset Check**: `npm run check:changeset`
346
+ - **Tool Token Cost**: `npm run measure:tokens` ([measurement guide](./docs/token-cost-tracking.md))
343
347
 
344
348
  For a detailed senior engineer guide, please refer to [AGENTS.md](./AGENTS.md).
345
349
 
package/dist/cli.mjs CHANGED
@@ -4,12 +4,12 @@
4
4
  (function() {
5
5
  try {
6
6
  var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {};
7
- e.SENTRY_RELEASE = { id: "hevy-mcp@2.0.0" };
7
+ e.SENTRY_RELEASE = { id: "hevy-mcp@3.0.0" };
8
8
  var n = new e.Error().stack;
9
9
  n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "03cf150f-6466-4ca3-9cf1-e423cc0e3cd2", e._sentryDebugIdIdentifier = "sentry-dbid-03cf150f-6466-4ca3-9cf1-e423cc0e3cd2");
10
10
  } catch (e) {}
11
11
  })();
12
- import { r as runServer } from "./src-c3mB-R0m.mjs";
12
+ import { r as runServer } from "./src-BBzEvkOX.mjs";
13
13
  //#region src/cli.ts
14
14
  runServer().catch((error) => {
15
15
  console.error("Fatal error in main():", error);
package/dist/index.mjs CHANGED
@@ -4,10 +4,10 @@
4
4
  (function() {
5
5
  try {
6
6
  var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {};
7
- e.SENTRY_RELEASE = { id: "hevy-mcp@2.0.0" };
7
+ e.SENTRY_RELEASE = { id: "hevy-mcp@3.0.0" };
8
8
  var n = new e.Error().stack;
9
9
  n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "5b077b94-9ef8-4f24-a0b0-8dcfbf491be1", e._sentryDebugIdIdentifier = "sentry-dbid-5b077b94-9ef8-4f24-a0b0-8dcfbf491be1");
10
10
  } catch (e) {}
11
11
  })();
12
- import { n as createServer, r as runServer, t as configSchema } from "./src-c3mB-R0m.mjs";
12
+ import { n as createServer, r as runServer, t as configSchema } from "./src-BBzEvkOX.mjs";
13
13
  export { configSchema, createServer, createServer as default, runServer };
@@ -4,9 +4,9 @@
4
4
  (function() {
5
5
  try {
6
6
  var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {};
7
- e.SENTRY_RELEASE = { id: "hevy-mcp@2.0.0" };
7
+ e.SENTRY_RELEASE = { id: "hevy-mcp@3.0.0" };
8
8
  var n = new e.Error().stack;
9
- n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "17d5086b-9850-447d-9372-27bb2ce5dcc5", e._sentryDebugIdIdentifier = "sentry-dbid-17d5086b-9850-447d-9372-27bb2ce5dcc5");
9
+ n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "06533ca8-0b74-40dd-a418-fc98c764276c", e._sentryDebugIdIdentifier = "sentry-dbid-06533ca8-0b74-40dd-a418-fc98c764276c");
10
10
  } catch (e) {}
11
11
  })();
12
12
  import * as Sentry from "@sentry/node";
@@ -41,10 +41,10 @@ import semver from "semver";
41
41
  * OTel Collector → Honeycomb: performance traces, metrics
42
42
  */
43
43
  const name$1 = "hevy-mcp";
44
- const version$1 = "2.0.0";
44
+ const version$1 = "3.0.0";
45
45
  const collectorToken = "NH9vOela-HYreQxAbJa68cjEmORoEKM57EvneUDVcOo";
46
46
  const COLLECTOR_ENDPOINT = "https://otel.chrisdoc.dev/v1";
47
- const sentryRelease = process.env.SENTRY_RELEASE ?? `hevy-mcp@2.0.0`;
47
+ const sentryRelease = process.env.SENTRY_RELEASE ?? `hevy-mcp@3.0.0`;
48
48
  const resource = resourceFromAttributes({
49
49
  "service.name": name$1,
50
50
  "service.version": version$1
@@ -2110,43 +2110,20 @@ function registerWorkoutTools(server, hevyClient) {
2110
2110
  }, "update-workout-operation"));
2111
2111
  }
2112
2112
  //#endregion
2113
+ //#region src/tools/register.ts
2114
+ /** Register every Hevy tool in its production ordering. */
2115
+ function registerHevyTools(server, hevyClient, options = {}) {
2116
+ registerWorkoutTools(server, hevyClient);
2117
+ registerRoutineTools(server, hevyClient);
2118
+ registerTemplateTools(server, hevyClient, { logger: options.logger });
2119
+ registerFolderTools(server, hevyClient);
2120
+ registerBodyMeasurementTools(server, hevyClient);
2121
+ registerUserTools(server, hevyClient);
2122
+ }
2123
+ //#endregion
2113
2124
  //#region src/utils/config.ts
2114
- const DEPRECATED_CLI_ARGUMENT_WARNING = [
2115
- "DEPRECATION WARNING: Passing the Hevy API key via CLI arguments",
2116
- "(--hevy-api-key=..., --hevyApiKey=..., hevy-api-key=...) is",
2117
- "deprecated and insecure. Use the HEVY_API_KEY environment",
2118
- "variable instead."
2119
- ].join(" ");
2120
- /**
2121
- * Parse CLI arguments and environment to derive configuration.
2122
- * Priority order for API key: deprecated CLI flag forms > environment variable.
2123
- * Supported deprecated CLI arg forms:
2124
- * --hevy-api-key=KEY
2125
- * --hevyApiKey=KEY
2126
- * hevy-api-key=KEY (bare, e.g. when passed after npm start -- )
2127
- */
2128
- function parseConfig(argv, env) {
2129
- let apiKey = "";
2130
- let usedDeprecatedApiKeyArg = false;
2131
- const apiKeyArgPatterns = [
2132
- /^--hevy-api-key=(.+)$/i,
2133
- /^--hevyApiKey=(.+)$/i,
2134
- /^hevy-api-key=(.+)$/i
2135
- ];
2136
- for (const raw of argv) {
2137
- for (const pattern of apiKeyArgPatterns) {
2138
- const m = raw.match(pattern);
2139
- if (m) {
2140
- apiKey = m[1];
2141
- usedDeprecatedApiKeyArg = true;
2142
- break;
2143
- }
2144
- }
2145
- if (apiKey) break;
2146
- }
2147
- if (usedDeprecatedApiKeyArg) console.error(DEPRECATED_CLI_ARGUMENT_WARNING);
2148
- if (!apiKey) apiKey = env.HEVY_API_KEY || "";
2149
- return { apiKey };
2125
+ function parseConfig(env) {
2126
+ return { apiKey: env.HEVY_API_KEY || "" };
2150
2127
  }
2151
2128
  function assertApiKey(apiKey) {
2152
2129
  if (!apiKey) {
@@ -3555,16 +3532,13 @@ const HELP_TEXT = [
3555
3532
  "Options:",
3556
3533
  " -h, --help Show this help message and exit",
3557
3534
  " -v, --version Show version and exit",
3558
- " --hevy-api-key=<api-key> (deprecated, use HEVY_API_KEY env var)",
3559
3535
  "",
3560
3536
  "Environment:",
3561
3537
  " HEVY_API_KEY=<api-key> Hevy API key from Hevy app settings",
3562
3538
  " HEVY_MCP_DEBUG=1 Enable verbose diagnostics on stderr",
3563
3539
  "",
3564
3540
  "Examples:",
3565
- " HEVY_API_KEY=your-key npx hevy-mcp",
3566
- " npx hevy-mcp --hevy-api-key=your-key",
3567
- " npm start -- --hevy-api-key=your-key"
3541
+ " HEVY_API_KEY=your-key npx hevy-mcp"
3568
3542
  ].join("\n");
3569
3543
  function getCliAction(args) {
3570
3544
  for (const arg of args) {
@@ -3675,12 +3649,7 @@ function buildServer(apiKey) {
3675
3649
  tracer.startActiveSpan("mcp.tools.register", (toolsSpan) => {
3676
3650
  try {
3677
3651
  const counting = createToolCountingServer(server);
3678
- registerWorkoutTools(counting.server, hevyClient);
3679
- registerRoutineTools(counting.server, hevyClient);
3680
- registerTemplateTools(counting.server, hevyClient, { logger: clientLogger });
3681
- registerFolderTools(counting.server, hevyClient);
3682
- registerBodyMeasurementTools(counting.server, hevyClient);
3683
- registerUserTools(counting.server, hevyClient);
3652
+ registerHevyTools(counting.server, hevyClient, { logger: clientLogger });
3684
3653
  toolsSpan.setAttribute("mcp.tools.count", counting.getCount());
3685
3654
  } finally {
3686
3655
  toolsSpan.end();
@@ -3710,8 +3679,7 @@ async function createServer({ config }) {
3710
3679
  return buildServer(apiKey);
3711
3680
  }
3712
3681
  async function runServer() {
3713
- const args = process.argv.slice(2);
3714
- const cliAction = getCliAction(args);
3682
+ const cliAction = getCliAction(process.argv.slice(2));
3715
3683
  if (cliAction === "version") {
3716
3684
  console.error(`${name} v${version}`);
3717
3685
  return;
@@ -3723,7 +3691,7 @@ async function runServer() {
3723
3691
  serverStartups.add(1, { version });
3724
3692
  await tracer.startActiveSpan("mcp.server.run", { attributes: { "mcp.transport": "stdio" } }, async (span) => {
3725
3693
  try {
3726
- const apiKey = parseConfig(args, process.env).apiKey;
3694
+ const apiKey = parseConfig(process.env).apiKey;
3727
3695
  assertApiKey(apiKey);
3728
3696
  const server = await createServer({ config: { apiKey } });
3729
3697
  console.error("Starting MCP server in stdio mode");
@@ -3756,4 +3724,4 @@ async function runServer() {
3756
3724
  //#endregion
3757
3725
  export { createServer as n, runServer as r, configSchema as t };
3758
3726
 
3759
- //# sourceMappingURL=src-c3mB-R0m.mjs.map
3727
+ //# sourceMappingURL=src-BBzEvkOX.mjs.map