hevy-mcp 6.1.1 → 6.1.2

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/dist/cli.mjs CHANGED
@@ -8,8 +8,8 @@
8
8
  n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "d805d34c-9cce-4622-8b67-728aa0cacb5d", e._sentryDebugIdIdentifier = "sentry-dbid-d805d34c-9cce-4622-8b67-728aa0cacb5d");
9
9
  } catch (e) {}
10
10
  })();
11
- import { i as flushTelemetry, r as MissingHevyApiKeyError, t as runServer } from "./runtime-CQ5qda5F.mjs";
12
- import { a as createSafeErrorDiagnostic } from "./src-c7i9L8Mm.mjs";
11
+ import { i as flushTelemetry, r as MissingHevyApiKeyError, t as runServer } from "./runtime-C0tBW0Rj.mjs";
12
+ import { a as createSafeErrorDiagnostic } from "./src-ITv7b8-Y.mjs";
13
13
  //#region src/cli.ts
14
14
  runServer().catch(async (error) => {
15
15
  if (error instanceof MissingHevyApiKeyError) console.error(error.message);
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  // Generated with tsdown
3
3
  // https://tsdown.dev
4
- import { o as createHevyClient, t as createHevyMcpServer } from "./src-c7i9L8Mm.mjs";
4
+ import { o as createHevyClient, t as createHevyMcpServer } from "./src-ITv7b8-Y.mjs";
5
5
  import { z } from "zod";
6
6
  //#region src/index.ts
7
7
  const serverConfigSchema = z.object({ apiKey: z.string().min(1, "Hevy API key is required").describe("Your Hevy API key (available in the Hevy app settings).") });
@@ -32,7 +32,7 @@ function createNodeMcpServer({ apiKey }, _transport = "stdio", lifecycleSignal)
32
32
  * does not evaluate the runtime bootstrap; it is loaded only when invoked.
33
33
  */
34
34
  async function runStdioServer() {
35
- const { runStdioServer: run } = await import("./runtime-CQ5qda5F.mjs").then((n) => n.n);
35
+ const { runStdioServer: run } = await import("./runtime-C0tBW0Rj.mjs").then((n) => n.n);
36
36
  return run();
37
37
  }
38
38
  /**
@@ -40,7 +40,7 @@ async function runStdioServer() {
40
40
  * does not evaluate the runtime bootstrap; it is loaded only when invoked.
41
41
  */
42
42
  async function runServer() {
43
- const { runServer: run } = await import("./runtime-CQ5qda5F.mjs").then((n) => n.n);
43
+ const { runServer: run } = await import("./runtime-C0tBW0Rj.mjs").then((n) => n.n);
44
44
  return run();
45
45
  }
46
46
  //#endregion
@@ -5,13 +5,13 @@
5
5
  try {
6
6
  var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {};
7
7
  var n = new e.Error().stack;
8
- n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "c292bf26-255c-46b3-9cb2-3343afe7b7ce", e._sentryDebugIdIdentifier = "sentry-dbid-c292bf26-255c-46b3-9cb2-3343afe7b7ce");
8
+ n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "74fe8f19-5598-43b9-8f97-71b400eea539", e._sentryDebugIdIdentifier = "sentry-dbid-74fe8f19-5598-43b9-8f97-71b400eea539");
9
9
  } catch (e) {}
10
10
  })();
11
- import { a as createSafeErrorDiagnostic, c as diagnosticEndpointIdentity, i as bucketCount, l as metricEndpointIdentity, n as createExecutionProjection, o as createHevyClient, r as mergeAbortSignals, s as SAFE_OBSERVATION_CODES, t as createHevyMcpServer, u as isHevyHttpError } from "./src-c7i9L8Mm.mjs";
11
+ import { a as createSafeErrorDiagnostic, c as diagnosticEndpointIdentity, i as bucketCount, l as metricEndpointIdentity, n as createExecutionProjection, o as createHevyClient, r as mergeAbortSignals, s as SAFE_OBSERVATION_CODES, t as createHevyMcpServer, u as isHevyHttpError } from "./src-ITv7b8-Y.mjs";
12
12
  import { ZodError, z } from "zod";
13
13
  import { deserializeMessage } from "@modelcontextprotocol/server";
14
- import { randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
14
+ import { createHmac, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
15
15
  import * as Sentry from "@sentry/node";
16
16
  import { SpanStatusCode, context, metrics, trace } from "@opentelemetry/api";
17
17
  import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
@@ -365,7 +365,7 @@ function installProcessExceptionTracking(processLike = process) {
365
365
  };
366
366
  }
367
367
  const name$1 = "hevy-mcp";
368
- const version$1 = "6.1.1";
368
+ const version$1 = "6.1.2";
369
369
  const telemetryEnabled = process.env.HEVY_MCP_TELEMETRY !== "0";
370
370
  const collectorToken = "NH9vOela-HYreQxAbJa68cjEmORoEKM57EvneUDVcOo";
371
371
  const COLLECTOR_ENDPOINT = "https://otel.chrisdoc.dev/v1";
@@ -1364,6 +1364,7 @@ function createNodeCacheObserver() {
1364
1364
  //#endregion
1365
1365
  //#region src/utils/tool-observer.ts
1366
1366
  const DISCOVERY_TOOL_NAMES = /* @__PURE__ */ new Set(["search-routines"]);
1367
+ const SAFE_USER_HASH_PATTERN = /^[0-9a-f]{10}$/u;
1367
1368
  const WORKFLOW_PAGINATION_RESOURCES = /* @__PURE__ */ new Set([
1368
1369
  "workouts",
1369
1370
  "bodyMeasurements",
@@ -1384,7 +1385,7 @@ function metricAttributes(invocation, clientAttributes) {
1384
1385
  ...clientAttributes
1385
1386
  };
1386
1387
  }
1387
- function createAttributes(invocation) {
1388
+ function createAttributes(invocation, userHash) {
1388
1389
  const clientMetadata = getCurrentMcpClientMetadata();
1389
1390
  const isPrompt = invocation.kind === "prompt";
1390
1391
  const sessionId = getCurrentMcpSessionId();
@@ -1397,6 +1398,7 @@ function createAttributes(invocation) {
1397
1398
  "mcp.client.version": clientMetadata.version,
1398
1399
  "mcp.protocol.version": clientMetadata.protocolVersion,
1399
1400
  "mcp.transport": getCurrentMcpTransport(),
1401
+ ...userHash ? { "user.hash": userHash } : {},
1400
1402
  "mcp.tool.args.key_count_bucket": invocation.argumentKeyCountBucket ?? "unknown",
1401
1403
  "mcp.tool.args.keys": invocation.argumentKeys?.join(",") ?? "",
1402
1404
  ...sessionId ? { "mcp.session.id": sessionId } : {}
@@ -1452,7 +1454,8 @@ function bestEffort(operation) {
1452
1454
  } catch {}
1453
1455
  }
1454
1456
  /** Node-only adapter from core's privacy-safe observation contract to OTel. */
1455
- function createNodeToolObserver() {
1457
+ function createNodeToolObserver(options = {}) {
1458
+ const userHash = typeof options.userHash === "string" && SAFE_USER_HASH_PATTERN.test(options.userHash) ? options.userHash : void 0;
1456
1459
  return { start(invocation) {
1457
1460
  const startedAt = Date.now();
1458
1461
  const metrics = metricAttributes(invocation, recordMcpToolInvocation());
@@ -1462,7 +1465,7 @@ function createNodeToolObserver() {
1462
1465
  let thrownError;
1463
1466
  return {
1464
1467
  run(operation) {
1465
- return tracer.startActiveSpan(`mcp.tool.${invocation.name}`, { attributes: createAttributes(invocation) }, async (span) => {
1468
+ return tracer.startActiveSpan(`mcp.tool.${invocation.name}`, { attributes: createAttributes(invocation, userHash) }, async (span) => {
1466
1469
  activeSpan = span;
1467
1470
  try {
1468
1471
  return await operation();
@@ -1528,6 +1531,22 @@ function createNodeToolObserver() {
1528
1531
  } };
1529
1532
  }
1530
1533
  //#endregion
1534
+ //#region src/utils/user-hash.ts
1535
+ const USER_HASH_CONTEXT = "hevy-mcp:sentry-user-id:v1";
1536
+ const USER_HASH_LENGTH = 10;
1537
+ /**
1538
+ * Derive the short, deterministic HMAC pseudonym shared with the Worker
1539
+ * telemetry contract without exporting or logging the caller's Hevy API key.
1540
+ */
1541
+ function createNodeUserHash(apiKey) {
1542
+ if (apiKey.length === 0) return void 0;
1543
+ try {
1544
+ return createHmac("sha256", apiKey).update(USER_HASH_CONTEXT, "utf8").digest("hex").slice(0, USER_HASH_LENGTH);
1545
+ } catch {
1546
+ return;
1547
+ }
1548
+ }
1549
+ //#endregion
1531
1550
  //#region src/utils/stdio-observability.ts
1532
1551
  const UTF8_BOM = "";
1533
1552
  /** Maximum escaped characters included in a malformed stdin shape preview. */
@@ -2424,7 +2443,7 @@ function buildServer(apiKey, transport = "stdio", lifecycleSignal) {
2424
2443
  }),
2425
2444
  lifecycleSignal,
2426
2445
  onToolsRegistered: (count) => span.setAttribute("mcp.tools.count", count),
2427
- observer: createNodeToolObserver(),
2446
+ observer: createNodeToolObserver({ userHash: createNodeUserHash(apiKey) }),
2428
2447
  cacheObserver: createNodeCacheObserver()
2429
2448
  });
2430
2449
  installSdkErrorTracking(server, transport);
@@ -2527,4 +2546,4 @@ async function runServer() {
2527
2546
  //#endregion
2528
2547
  export { flushTelemetry as i, runtime_exports as n, MissingHevyApiKeyError as r, runServer as t };
2529
2548
 
2530
- //# sourceMappingURL=runtime-CQ5qda5F.mjs.map
2549
+ //# sourceMappingURL=runtime-C0tBW0Rj.mjs.map
@@ -4512,7 +4512,7 @@ function registerHevyResources(server, runtime) {
4512
4512
  //#endregion
4513
4513
  //#region ../core/src/server-metadata.ts
4514
4514
  const SERVER_NAME = "hevy-mcp";
4515
- const SERVER_VERSION = "6.1.1";
4515
+ const SERVER_VERSION = "6.1.2";
4516
4516
  const SERVER_INSTRUCTIONS = [
4517
4517
  "Hevy MCP connects clients to the authenticated user's Hevy workout-tracking data, including workouts, routines, exercise templates, routine folders, body measurements, and profile information. HEVY_API_KEY must contain a valid Hevy API key for local stdio use.",
4518
4518
  "Safety: all get-* and search-* tools are read-only. create-* and update-* tools mutate Hevy data. Creates are additive and non-idempotent, so repeating one can create duplicates. Updates can overwrite existing data. Delete operations are not available.",
@@ -5090,4 +5090,4 @@ function createHevyMcpServer(options) {
5090
5090
  //#endregion
5091
5091
  export { createSafeErrorDiagnostic as a, diagnosticEndpointIdentity as c, bucketCount as i, metricEndpointIdentity as l, createExecutionProjection as n, createHevyClient as o, mergeAbortSignals as r, SAFE_OBSERVATION_CODES as s, createHevyMcpServer as t, isHevyHttpError as u };
5092
5092
 
5093
- //# sourceMappingURL=src-c7i9L8Mm.mjs.map
5093
+ //# sourceMappingURL=src-ITv7b8-Y.mjs.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hevy-mcp",
3
- "version": "6.1.1",
3
+ "version": "6.1.2",
4
4
  "private": false,
5
5
  "description": "A Model Context Protocol (MCP) server implementation that interfaces with the Hevy fitness tracking app and its API.",
6
6
  "repository": {
package/server.json CHANGED
@@ -7,12 +7,12 @@
7
7
  "url": "https://github.com/chrisdoc/hevy-mcp",
8
8
  "source": "github"
9
9
  },
10
- "version": "6.1.1",
10
+ "version": "6.1.2",
11
11
  "packages": [
12
12
  {
13
13
  "registryType": "npm",
14
14
  "identifier": "hevy-mcp",
15
- "version": "6.1.1",
15
+ "version": "6.1.2",
16
16
  "transport": {
17
17
  "type": "stdio"
18
18
  },