hevy-mcp 5.0.4 → 5.0.5
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 +2 -2
- package/dist/index.mjs +2 -2
- package/dist/{src-CJRjsomO.mjs → src-TBD9ENR3.mjs} +220 -157
- package/package.json +1 -1
- package/server.json +2 -2
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@5.0.
|
|
7
|
+
e.SENTRY_RELEASE = { id: "hevy-mcp@5.0.5" };
|
|
8
8
|
var n = new e.Error().stack;
|
|
9
9
|
n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "625c4c9c-e20d-40b3-96b1-4e799ef130f3", e._sentryDebugIdIdentifier = "sentry-dbid-625c4c9c-e20d-40b3-96b1-4e799ef130f3");
|
|
10
10
|
} catch (e) {}
|
|
11
11
|
})();
|
|
12
|
-
import { a as createSafeErrorDiagnostic, i as MissingHevyApiKeyError, n as runServer, o as flushTelemetry } from "./src-
|
|
12
|
+
import { a as createSafeErrorDiagnostic, i as MissingHevyApiKeyError, n as runServer, o as flushTelemetry } from "./src-TBD9ENR3.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
|
@@ -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@5.0.
|
|
7
|
+
e.SENTRY_RELEASE = { id: "hevy-mcp@5.0.5" };
|
|
8
8
|
var n = new e.Error().stack;
|
|
9
9
|
n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "e9496b31-626b-4ad1-9416-47ba4ffd2995", e._sentryDebugIdIdentifier = "sentry-dbid-e9496b31-626b-4ad1-9416-47ba4ffd2995");
|
|
10
10
|
} catch (e) {}
|
|
11
11
|
})();
|
|
12
|
-
import { n as runServer, r as runStdioServer, t as createNodeMcpServer } from "./src-
|
|
12
|
+
import { n as runServer, r as runStdioServer, t as createNodeMcpServer } from "./src-TBD9ENR3.mjs";
|
|
13
13
|
export { createNodeMcpServer, runServer, runStdioServer };
|
|
@@ -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@5.0.
|
|
7
|
+
e.SENTRY_RELEASE = { id: "hevy-mcp@5.0.5" };
|
|
8
8
|
var n = new e.Error().stack;
|
|
9
|
-
n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "
|
|
9
|
+
n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "f5270278-73ea-40fd-92e2-2ae5127e6780", e._sentryDebugIdIdentifier = "sentry-dbid-f5270278-73ea-40fd-92e2-2ae5127e6780");
|
|
10
10
|
} catch (e) {}
|
|
11
11
|
})();
|
|
12
12
|
import { createHmac, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
|
|
@@ -20,13 +20,13 @@ import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base";
|
|
|
20
20
|
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
|
|
21
21
|
import { MeterProvider, PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics";
|
|
22
22
|
import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
|
|
23
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
24
23
|
import { ZodError, z } from "zod";
|
|
25
24
|
import { McpServer, deserializeMessage } from "@modelcontextprotocol/server";
|
|
26
25
|
import { z as z$1 } from "zod/v4";
|
|
27
26
|
import { isIP } from "node:net";
|
|
28
27
|
import { createServer } from "node:http";
|
|
29
28
|
import { NodeStreamableHTTPServerTransport } from "@modelcontextprotocol/node";
|
|
29
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
30
30
|
import { mkdir, readFile, rename, unlink, writeFile } from "node:fs/promises";
|
|
31
31
|
import { homedir } from "node:os";
|
|
32
32
|
import { dirname, join } from "node:path";
|
|
@@ -79,6 +79,10 @@ function sanitizeSentryMcpSpan(span) {
|
|
|
79
79
|
* Sentry SDK: error events, performance traces, release tracking
|
|
80
80
|
* OTel Collector → Honeycomb: performance traces, metrics
|
|
81
81
|
*/
|
|
82
|
+
const PROCESS_FAILURE_TAXONOMY = {
|
|
83
|
+
uncaughtException: "uncaught_exception",
|
|
84
|
+
unhandledRejection: "unhandled_rejection"
|
|
85
|
+
};
|
|
82
86
|
const SAFE_EXCEPTION_TYPES = /* @__PURE__ */ new Set([
|
|
83
87
|
"AggregateError",
|
|
84
88
|
"DOMException",
|
|
@@ -109,10 +113,7 @@ const SAFE_EXCEPTION_CODES = /* @__PURE__ */ new Set([
|
|
|
109
113
|
]);
|
|
110
114
|
function normalizeTelemetryError(error) {
|
|
111
115
|
const candidate = error instanceof Error && typeof error.name === "string" ? error.name : void 0;
|
|
112
|
-
return {
|
|
113
|
-
name: candidate && SAFE_EXCEPTION_TYPES.has(candidate) ? candidate : "UnknownError",
|
|
114
|
-
...error instanceof Error && error.stack ? { stack: error.stack } : {}
|
|
115
|
-
};
|
|
116
|
+
return { name: candidate && SAFE_EXCEPTION_TYPES.has(candidate) ? candidate : "UnknownError" };
|
|
116
117
|
}
|
|
117
118
|
function getSafeExceptionCode(error) {
|
|
118
119
|
if (!error || typeof error !== "object" || !("code" in error)) return void 0;
|
|
@@ -125,7 +126,10 @@ function recordTelemetryException(error, attributes, span) {
|
|
|
125
126
|
const target = span ?? trace.getActiveSpan();
|
|
126
127
|
if (!target) return;
|
|
127
128
|
const normalized = normalizeTelemetryError(error);
|
|
128
|
-
target.
|
|
129
|
+
target.addEvent("exception", {
|
|
130
|
+
...attributes,
|
|
131
|
+
"exception.type": normalized.name
|
|
132
|
+
});
|
|
129
133
|
target.setAttribute("exception.type", normalized.name);
|
|
130
134
|
target.setAttribute("error.category", normalized.name);
|
|
131
135
|
if (attributes) target.setAttributes(attributes);
|
|
@@ -138,11 +142,12 @@ function installProcessExceptionTracking(processLike = process) {
|
|
|
138
142
|
try {
|
|
139
143
|
tracer.startActiveSpan(`mcp.process.${source}`, { attributes: { "mcp.span.category": "process" } }, (span) => {
|
|
140
144
|
try {
|
|
141
|
-
const normalized = normalizeTelemetryError(error);
|
|
142
145
|
const code = getSafeExceptionCode(error);
|
|
143
146
|
recordTelemetryException(error, {
|
|
144
147
|
"exception.source": source,
|
|
145
|
-
"
|
|
148
|
+
"mcp.failure.phase": PROCESS_FAILURE_TAXONOMY[source],
|
|
149
|
+
"error.type": "MCP_PROCESS_EXCEPTION",
|
|
150
|
+
"error.category": "McpProcessFailure",
|
|
146
151
|
...code ? { "error.code": code } : {}
|
|
147
152
|
}, span);
|
|
148
153
|
} finally {
|
|
@@ -164,7 +169,7 @@ function installProcessExceptionTracking(processLike = process) {
|
|
|
164
169
|
};
|
|
165
170
|
}
|
|
166
171
|
const name$1 = "hevy-mcp";
|
|
167
|
-
const version$1 = "5.0.
|
|
172
|
+
const version$1 = "5.0.5";
|
|
168
173
|
const telemetryEnabled = process.env.HEVY_MCP_TELEMETRY !== "0";
|
|
169
174
|
const collectorToken = "NH9vOela-HYreQxAbJa68cjEmORoEKM57EvneUDVcOo";
|
|
170
175
|
const COLLECTOR_ENDPOINT = "https://otel.chrisdoc.dev/v1";
|
|
@@ -2839,7 +2844,7 @@ function registerHevyResources(server, runtime) {
|
|
|
2839
2844
|
//#endregion
|
|
2840
2845
|
//#region ../core/src/server-metadata.ts
|
|
2841
2846
|
const SERVER_NAME = "hevy-mcp";
|
|
2842
|
-
const SERVER_VERSION = "5.0.
|
|
2847
|
+
const SERVER_VERSION = "5.0.5";
|
|
2843
2848
|
const SERVER_INSTRUCTIONS = [
|
|
2844
2849
|
"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.",
|
|
2845
2850
|
"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.",
|
|
@@ -5728,6 +5733,177 @@ function createInstrumentedStdioTransport(transport) {
|
|
|
5728
5733
|
return transport;
|
|
5729
5734
|
}
|
|
5730
5735
|
//#endregion
|
|
5736
|
+
//#region src/utils/sdk-observability.ts
|
|
5737
|
+
const sdkToolNameStorage = new AsyncLocalStorage();
|
|
5738
|
+
const SAFE_TOOL_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/u;
|
|
5739
|
+
const SDK_FAILURE_TAXONOMY = {
|
|
5740
|
+
protocol: {
|
|
5741
|
+
errorType: "UNKNOWN_ERROR",
|
|
5742
|
+
errorCategory: "McpSdkProtocolFailure"
|
|
5743
|
+
},
|
|
5744
|
+
tool_call: {
|
|
5745
|
+
errorType: "UNKNOWN_ERROR",
|
|
5746
|
+
errorCategory: "McpSdkToolCallFailure"
|
|
5747
|
+
},
|
|
5748
|
+
validation: {
|
|
5749
|
+
errorType: "VALIDATION_ERROR",
|
|
5750
|
+
errorCategory: "McpSdkValidationFailure"
|
|
5751
|
+
}
|
|
5752
|
+
};
|
|
5753
|
+
function createFailureAttributes(error, phase, errorType, errorCategory) {
|
|
5754
|
+
const diagnostic = createSafeErrorDiagnostic(error);
|
|
5755
|
+
return {
|
|
5756
|
+
"mcp.failure.phase": phase,
|
|
5757
|
+
"error.type": errorType,
|
|
5758
|
+
"error.category": errorCategory,
|
|
5759
|
+
...diagnostic.code ? { "error.code": diagnostic.code } : {},
|
|
5760
|
+
...diagnostic.status !== void 0 ? { "http.response.status_code": diagnostic.status } : {},
|
|
5761
|
+
...diagnostic.method ? { "http.request.method": diagnostic.method } : {},
|
|
5762
|
+
...diagnostic.endpoint ? { "hevy.api.endpoint": diagnostic.endpoint } : {}
|
|
5763
|
+
};
|
|
5764
|
+
}
|
|
5765
|
+
function enrichActiveSdkSpan(attributes) {
|
|
5766
|
+
try {
|
|
5767
|
+
trace.getActiveSpan()?.setAttributes(attributes);
|
|
5768
|
+
} catch {}
|
|
5769
|
+
}
|
|
5770
|
+
function getSdkToolName(request) {
|
|
5771
|
+
if (!request || typeof request !== "object") return "unknown";
|
|
5772
|
+
const candidate = request.params?.name;
|
|
5773
|
+
return typeof candidate === "string" && SAFE_TOOL_NAME_PATTERN.test(candidate) ? candidate : "unknown";
|
|
5774
|
+
}
|
|
5775
|
+
function markSdkToolFailure(span, error, toolName = sdkToolNameStorage.getStore() ?? "unknown", kind = "tool_call") {
|
|
5776
|
+
const taxonomy = SDK_FAILURE_TAXONOMY[kind];
|
|
5777
|
+
const attributes = createFailureAttributes(error, "sdk", taxonomy.errorType, taxonomy.errorCategory);
|
|
5778
|
+
span.addEvent("mcp.tool.failure", {
|
|
5779
|
+
"mcp.tool.name": toolName,
|
|
5780
|
+
...attributes
|
|
5781
|
+
});
|
|
5782
|
+
span.setAttribute("error.type", taxonomy.errorType);
|
|
5783
|
+
recordTelemetryException(error, attributes, span);
|
|
5784
|
+
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
5785
|
+
}
|
|
5786
|
+
function installProtocolErrorTracking(server, transport) {
|
|
5787
|
+
const protocol = server.server;
|
|
5788
|
+
if (!protocol) return;
|
|
5789
|
+
const previous = protocol.onerror;
|
|
5790
|
+
protocol.onerror = (error) => {
|
|
5791
|
+
const taxonomy = SDK_FAILURE_TAXONOMY.protocol;
|
|
5792
|
+
const attributes = createFailureAttributes(error, "sdk", taxonomy.errorType, taxonomy.errorCategory);
|
|
5793
|
+
const activeSpan = trace.getActiveSpan();
|
|
5794
|
+
const sessionId = getCurrentMcpSessionId();
|
|
5795
|
+
if (activeSpan) {
|
|
5796
|
+
activeSpan.addEvent("mcp.tool.failure", {
|
|
5797
|
+
"mcp.tool.name": sdkToolNameStorage.getStore() ?? "unknown",
|
|
5798
|
+
...attributes
|
|
5799
|
+
});
|
|
5800
|
+
recordTelemetryException(error, attributes, activeSpan);
|
|
5801
|
+
} else tracer.startActiveSpan("mcp.sdk.failure", { attributes: {
|
|
5802
|
+
"mcp.span.category": "protocol",
|
|
5803
|
+
"mcp.transport": transport,
|
|
5804
|
+
...sessionId ? { "mcp.session.id": sessionId } : {}
|
|
5805
|
+
} }, (span) => {
|
|
5806
|
+
span.addEvent("mcp.tool.failure", {
|
|
5807
|
+
"mcp.tool.name": "unknown",
|
|
5808
|
+
...attributes
|
|
5809
|
+
});
|
|
5810
|
+
recordTelemetryException(error, attributes, span);
|
|
5811
|
+
span.end();
|
|
5812
|
+
});
|
|
5813
|
+
try {
|
|
5814
|
+
previous?.(error);
|
|
5815
|
+
} catch {}
|
|
5816
|
+
};
|
|
5817
|
+
}
|
|
5818
|
+
function installValidationErrorTracking(server) {
|
|
5819
|
+
const toolErrorHost = server;
|
|
5820
|
+
const previousCreateToolError = toolErrorHost.createToolError;
|
|
5821
|
+
if (!previousCreateToolError) return;
|
|
5822
|
+
const createToolError = previousCreateToolError.bind(server);
|
|
5823
|
+
toolErrorHost.createToolError = (message) => {
|
|
5824
|
+
const result = createToolError(message);
|
|
5825
|
+
const activeSpan = trace.getActiveSpan();
|
|
5826
|
+
if (activeSpan) markSdkToolFailure(activeSpan, /* @__PURE__ */ new Error("MCP tool validation failed"), void 0, "validation");
|
|
5827
|
+
return result;
|
|
5828
|
+
};
|
|
5829
|
+
}
|
|
5830
|
+
function installInitializeEnrichment(handlers, transport) {
|
|
5831
|
+
const initializeHandler = handlers.get("initialize");
|
|
5832
|
+
if (!initializeHandler) return;
|
|
5833
|
+
handlers.set("initialize", (request, extra) => {
|
|
5834
|
+
enrichActiveSdkSpan({
|
|
5835
|
+
"mcp.span.category": "protocol",
|
|
5836
|
+
"mcp.transport": transport
|
|
5837
|
+
});
|
|
5838
|
+
return initializeHandler(request, extra);
|
|
5839
|
+
});
|
|
5840
|
+
}
|
|
5841
|
+
function installToolCallTracking(handlers, transport) {
|
|
5842
|
+
const toolHandler = handlers.get("tools/call");
|
|
5843
|
+
if (!toolHandler) return;
|
|
5844
|
+
handlers.set("tools/call", (request, extra) => {
|
|
5845
|
+
const sessionId = getCurrentMcpSessionId();
|
|
5846
|
+
const toolName = getSdkToolName(request);
|
|
5847
|
+
const attributes = {
|
|
5848
|
+
"mcp.span.category": "protocol",
|
|
5849
|
+
"mcp.transport": transport,
|
|
5850
|
+
"mcp.operation.kind": "tool",
|
|
5851
|
+
"mcp.tool.name": toolName,
|
|
5852
|
+
...sessionId ? { "mcp.session.id": sessionId } : {}
|
|
5853
|
+
};
|
|
5854
|
+
enrichActiveSdkSpan(attributes);
|
|
5855
|
+
return sdkToolNameStorage.run(toolName, () => tracer.startActiveSpan("mcp.sdk.tools.call", { attributes }, async (span) => {
|
|
5856
|
+
try {
|
|
5857
|
+
const result = await toolHandler(request, extra);
|
|
5858
|
+
if (result?.isError === true) {
|
|
5859
|
+
span.setAttribute("mcp.tool.outcome", "returned_error");
|
|
5860
|
+
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
5861
|
+
} else span.setStatus({ code: SpanStatusCode.OK });
|
|
5862
|
+
return result;
|
|
5863
|
+
} catch (error) {
|
|
5864
|
+
markSdkToolFailure(span, error, toolName);
|
|
5865
|
+
throw error;
|
|
5866
|
+
} finally {
|
|
5867
|
+
span.end();
|
|
5868
|
+
}
|
|
5869
|
+
}));
|
|
5870
|
+
});
|
|
5871
|
+
}
|
|
5872
|
+
function installDiscoveryTracking(handlers) {
|
|
5873
|
+
const discoveryHandler = handlers.get("server/discover");
|
|
5874
|
+
if (!discoveryHandler) return;
|
|
5875
|
+
handlers.set("server/discover", (request, extra) => {
|
|
5876
|
+
const sessionId = getCurrentMcpSessionId();
|
|
5877
|
+
return tracer.startActiveSpan("mcp.server.discover", { attributes: {
|
|
5878
|
+
"mcp.span.category": "discovery",
|
|
5879
|
+
"mcp.transport": getCurrentMcpTransport(),
|
|
5880
|
+
...sessionId ? { "mcp.session.id": sessionId } : {}
|
|
5881
|
+
} }, async (span) => {
|
|
5882
|
+
try {
|
|
5883
|
+
const result = await discoveryHandler(request, extra);
|
|
5884
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
5885
|
+
return result;
|
|
5886
|
+
} catch (error) {
|
|
5887
|
+
const attributes = createFailureAttributes(error, "discovery", "UNKNOWN_ERROR", "McpServerDiscoveryFailure");
|
|
5888
|
+
span.addEvent("mcp.discovery.failure", attributes);
|
|
5889
|
+
recordTelemetryException(error, attributes, span);
|
|
5890
|
+
throw error;
|
|
5891
|
+
} finally {
|
|
5892
|
+
span.end();
|
|
5893
|
+
}
|
|
5894
|
+
});
|
|
5895
|
+
});
|
|
5896
|
+
}
|
|
5897
|
+
function installSdkErrorTracking(server, transport) {
|
|
5898
|
+
installProtocolErrorTracking(server, transport);
|
|
5899
|
+
installValidationErrorTracking(server);
|
|
5900
|
+
const handlers = server.server?._requestHandlers;
|
|
5901
|
+
if (!(handlers instanceof Map)) return;
|
|
5902
|
+
installInitializeEnrichment(handlers, transport);
|
|
5903
|
+
installToolCallTracking(handlers, transport);
|
|
5904
|
+
installDiscoveryTracking(handlers);
|
|
5905
|
+
}
|
|
5906
|
+
//#endregion
|
|
5731
5907
|
//#region src/utils/version-check.ts
|
|
5732
5908
|
const CACHE_TTL_MS = 1440 * 60 * 1e3;
|
|
5733
5909
|
const REQUEST_TIMEOUT_MS = 3e3;
|
|
@@ -5917,158 +6093,45 @@ function getSafeValidationDiagnostic(error) {
|
|
|
5917
6093
|
const code = error.code;
|
|
5918
6094
|
return typeof code === "string" && SAFE_NETWORK_ERROR_CODES.has(code) ? code : void 0;
|
|
5919
6095
|
}
|
|
5920
|
-
|
|
6096
|
+
const LIFECYCLE_FAILURE_TAXONOMY = {
|
|
6097
|
+
config: {
|
|
6098
|
+
errorType: "MCP_SERVER_CONFIG_ERROR",
|
|
6099
|
+
errorCategory: "McpServerConfigFailure"
|
|
6100
|
+
},
|
|
6101
|
+
api_key_validation: {
|
|
6102
|
+
errorType: "MCP_API_KEY_VALIDATION_ERROR",
|
|
6103
|
+
errorCategory: "McpApiKeyValidationFailure"
|
|
6104
|
+
},
|
|
6105
|
+
build: {
|
|
6106
|
+
errorType: "MCP_SERVER_BUILD_ERROR",
|
|
6107
|
+
errorCategory: "McpServerBuildFailure"
|
|
6108
|
+
},
|
|
6109
|
+
connect: {
|
|
6110
|
+
errorType: "MCP_TRANSPORT_CONNECT_ERROR",
|
|
6111
|
+
errorCategory: "McpTransportConnectFailure"
|
|
6112
|
+
},
|
|
6113
|
+
run: {
|
|
6114
|
+
errorType: "MCP_SERVER_RUN_ERROR",
|
|
6115
|
+
errorCategory: "McpServerRunFailure"
|
|
6116
|
+
}
|
|
6117
|
+
};
|
|
6118
|
+
function createLifecycleFailureAttributes(error, phase) {
|
|
5921
6119
|
const diagnostic = createSafeErrorDiagnostic(error);
|
|
5922
|
-
const
|
|
6120
|
+
const taxonomy = LIFECYCLE_FAILURE_TAXONOMY[phase];
|
|
6121
|
+
return {
|
|
5923
6122
|
"mcp.failure.phase": phase,
|
|
5924
|
-
"error.type":
|
|
5925
|
-
"error.category":
|
|
6123
|
+
"error.type": taxonomy.errorType,
|
|
6124
|
+
"error.category": taxonomy.errorCategory,
|
|
5926
6125
|
...diagnostic.code ? { "error.code": diagnostic.code } : {},
|
|
5927
6126
|
...diagnostic.status !== void 0 ? { "http.response.status_code": diagnostic.status } : {},
|
|
5928
6127
|
...diagnostic.method ? { "http.request.method": diagnostic.method } : {},
|
|
5929
6128
|
...diagnostic.endpoint ? { "hevy.api.endpoint": diagnostic.endpoint } : {}
|
|
5930
6129
|
};
|
|
5931
|
-
span.addEvent("mcp.lifecycle.failure", {
|
|
5932
|
-
"error.type": diagnostic.category,
|
|
5933
|
-
"error.category": diagnostic.category,
|
|
5934
|
-
...diagnostic.code ? { "error.code": diagnostic.code } : {}
|
|
5935
|
-
});
|
|
5936
|
-
recordTelemetryException(error, attributes, span);
|
|
5937
|
-
}
|
|
5938
|
-
const sdkToolNameStorage = new AsyncLocalStorage();
|
|
5939
|
-
const SAFE_TOOL_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/u;
|
|
5940
|
-
function getSdkToolName(request) {
|
|
5941
|
-
if (!request || typeof request !== "object") return "unknown";
|
|
5942
|
-
const candidate = request.params?.name;
|
|
5943
|
-
return typeof candidate === "string" && SAFE_TOOL_NAME_PATTERN.test(candidate) ? candidate : "unknown";
|
|
5944
|
-
}
|
|
5945
|
-
function markSdkToolFailure(span, error, toolName = sdkToolNameStorage.getStore() ?? "unknown", errorTypeOverride) {
|
|
5946
|
-
const diagnostic = createSafeErrorDiagnostic(error);
|
|
5947
|
-
const errorType = errorTypeOverride ?? diagnostic.category;
|
|
5948
|
-
span.addEvent("mcp.tool.failure", {
|
|
5949
|
-
"mcp.tool.name": toolName,
|
|
5950
|
-
"error.type": errorType,
|
|
5951
|
-
"error.category": diagnostic.category,
|
|
5952
|
-
...diagnostic.code ? { "error.code": diagnostic.code } : {},
|
|
5953
|
-
...diagnostic.status !== void 0 ? { "http.response.status_code": diagnostic.status } : {},
|
|
5954
|
-
...diagnostic.method ? { "http.request.method": diagnostic.method } : {},
|
|
5955
|
-
...diagnostic.endpoint ? { "hevy.api.endpoint": diagnostic.endpoint } : {}
|
|
5956
|
-
});
|
|
5957
|
-
span.setAttribute("error.type", errorType);
|
|
5958
|
-
recordTelemetryException(error, {
|
|
5959
|
-
"mcp.failure.phase": "sdk",
|
|
5960
|
-
"error.type": errorType,
|
|
5961
|
-
"error.category": diagnostic.category,
|
|
5962
|
-
...diagnostic.code ? { "error.code": diagnostic.code } : {},
|
|
5963
|
-
...diagnostic.status !== void 0 ? { "http.response.status_code": diagnostic.status } : {}
|
|
5964
|
-
}, span);
|
|
5965
|
-
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
5966
6130
|
}
|
|
5967
|
-
function
|
|
5968
|
-
const
|
|
5969
|
-
|
|
5970
|
-
|
|
5971
|
-
protocol.onerror = (error) => {
|
|
5972
|
-
const diagnostic = createSafeErrorDiagnostic(error);
|
|
5973
|
-
const attributes = {
|
|
5974
|
-
"mcp.failure.phase": "sdk",
|
|
5975
|
-
"error.category": diagnostic.category,
|
|
5976
|
-
...diagnostic.code ? { "error.code": diagnostic.code } : {},
|
|
5977
|
-
...diagnostic.status !== void 0 ? { "http.response.status_code": diagnostic.status } : {}
|
|
5978
|
-
};
|
|
5979
|
-
const activeSpan = trace.getActiveSpan();
|
|
5980
|
-
const sessionId = getCurrentMcpSessionId();
|
|
5981
|
-
if (activeSpan) {
|
|
5982
|
-
activeSpan.addEvent("mcp.tool.failure", {
|
|
5983
|
-
"mcp.tool.name": sdkToolNameStorage.getStore() ?? "unknown",
|
|
5984
|
-
"error.type": "UNKNOWN_ERROR",
|
|
5985
|
-
"error.category": diagnostic.category,
|
|
5986
|
-
...diagnostic.code ? { "error.code": diagnostic.code } : {}
|
|
5987
|
-
});
|
|
5988
|
-
recordTelemetryException(error, attributes, activeSpan);
|
|
5989
|
-
} else tracer.startActiveSpan("mcp.sdk.failure", { attributes: { ...sessionId ? { "mcp.session.id": sessionId } : {} } }, (span) => {
|
|
5990
|
-
span.addEvent("mcp.tool.failure", {
|
|
5991
|
-
"mcp.tool.name": "unknown",
|
|
5992
|
-
"error.type": "UNKNOWN_ERROR",
|
|
5993
|
-
"error.category": diagnostic.category,
|
|
5994
|
-
...diagnostic.code ? { "error.code": diagnostic.code } : {}
|
|
5995
|
-
});
|
|
5996
|
-
recordTelemetryException(error, attributes, span);
|
|
5997
|
-
span.end();
|
|
5998
|
-
});
|
|
5999
|
-
try {
|
|
6000
|
-
previous?.(error);
|
|
6001
|
-
} catch {}
|
|
6002
|
-
};
|
|
6003
|
-
const toolErrorHost = server;
|
|
6004
|
-
const previousCreateToolError = toolErrorHost.createToolError;
|
|
6005
|
-
if (previousCreateToolError) {
|
|
6006
|
-
const createToolError = previousCreateToolError.bind(server);
|
|
6007
|
-
toolErrorHost.createToolError = (message) => {
|
|
6008
|
-
const result = createToolError(message);
|
|
6009
|
-
const activeSpan = trace.getActiveSpan();
|
|
6010
|
-
if (activeSpan) markSdkToolFailure(activeSpan, /* @__PURE__ */ new Error("MCP tool validation failed"), void 0, "VALIDATION_ERROR");
|
|
6011
|
-
return result;
|
|
6012
|
-
};
|
|
6013
|
-
}
|
|
6014
|
-
const handlers = protocol._requestHandlers;
|
|
6015
|
-
if (!(handlers instanceof Map)) return;
|
|
6016
|
-
const toolHandler = handlers.get("tools/call");
|
|
6017
|
-
if (toolHandler) handlers.set("tools/call", (request, extra) => {
|
|
6018
|
-
const sessionId = getCurrentMcpSessionId();
|
|
6019
|
-
const toolName = getSdkToolName(request);
|
|
6020
|
-
return sdkToolNameStorage.run(toolName, () => tracer.startActiveSpan("mcp.sdk.tools.call", { attributes: {
|
|
6021
|
-
"mcp.span.category": "protocol",
|
|
6022
|
-
"mcp.operation.kind": "tool",
|
|
6023
|
-
"mcp.tool.name": toolName,
|
|
6024
|
-
...sessionId ? { "mcp.session.id": sessionId } : {}
|
|
6025
|
-
} }, async (span) => {
|
|
6026
|
-
try {
|
|
6027
|
-
const result = await toolHandler(request, extra);
|
|
6028
|
-
if (result?.isError === true) {
|
|
6029
|
-
span.setAttribute("mcp.tool.outcome", "returned_error");
|
|
6030
|
-
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
6031
|
-
} else span.setStatus({ code: SpanStatusCode.OK });
|
|
6032
|
-
return result;
|
|
6033
|
-
} catch (error) {
|
|
6034
|
-
markSdkToolFailure(span, error, toolName);
|
|
6035
|
-
throw error;
|
|
6036
|
-
} finally {
|
|
6037
|
-
span.end();
|
|
6038
|
-
}
|
|
6039
|
-
}));
|
|
6040
|
-
});
|
|
6041
|
-
const discoveryHandler = handlers.get("server/discover");
|
|
6042
|
-
if (discoveryHandler) handlers.set("server/discover", (request, extra) => {
|
|
6043
|
-
const sessionId = getCurrentMcpSessionId();
|
|
6044
|
-
return tracer.startActiveSpan("mcp.server.discover", { attributes: {
|
|
6045
|
-
"mcp.span.category": "discovery",
|
|
6046
|
-
"mcp.transport": getCurrentMcpTransport(),
|
|
6047
|
-
...sessionId ? { "mcp.session.id": sessionId } : {}
|
|
6048
|
-
} }, async (span) => {
|
|
6049
|
-
try {
|
|
6050
|
-
const result = await discoveryHandler(request, extra);
|
|
6051
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
6052
|
-
return result;
|
|
6053
|
-
} catch (error) {
|
|
6054
|
-
const diagnostic = createSafeErrorDiagnostic(error);
|
|
6055
|
-
span.addEvent("mcp.discovery.failure", {
|
|
6056
|
-
"error.type": diagnostic.category,
|
|
6057
|
-
"error.category": diagnostic.category,
|
|
6058
|
-
...diagnostic.code ? { "error.code": diagnostic.code } : {}
|
|
6059
|
-
});
|
|
6060
|
-
recordTelemetryException(error, {
|
|
6061
|
-
"mcp.failure.phase": "discovery",
|
|
6062
|
-
"error.type": diagnostic.category,
|
|
6063
|
-
"error.category": diagnostic.category,
|
|
6064
|
-
...diagnostic.code ? { "error.code": diagnostic.code } : {}
|
|
6065
|
-
}, span);
|
|
6066
|
-
throw error;
|
|
6067
|
-
} finally {
|
|
6068
|
-
span.end();
|
|
6069
|
-
}
|
|
6070
|
-
});
|
|
6071
|
-
});
|
|
6131
|
+
function recordLifecycleFailure(span, error, phase) {
|
|
6132
|
+
const attributes = createLifecycleFailureAttributes(error, phase);
|
|
6133
|
+
span.addEvent("mcp.lifecycle.failure", attributes);
|
|
6134
|
+
recordTelemetryException(error, attributes, span);
|
|
6072
6135
|
}
|
|
6073
6136
|
async function validateApiKey(apiKey) {
|
|
6074
6137
|
const startupProbeClient = createHevyClient({
|
|
@@ -6108,7 +6171,7 @@ function buildServer(apiKey, transport = "stdio") {
|
|
|
6108
6171
|
observer: createNodeToolObserver(),
|
|
6109
6172
|
cacheObserver: createNodeCacheObserver()
|
|
6110
6173
|
});
|
|
6111
|
-
installSdkErrorTracking(server);
|
|
6174
|
+
installSdkErrorTracking(server, transport);
|
|
6112
6175
|
console.error("Hevy client initialized with API key");
|
|
6113
6176
|
span.setStatus({ code: SpanStatusCode.OK });
|
|
6114
6177
|
return server;
|
package/package.json
CHANGED
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": "5.0.
|
|
10
|
+
"version": "5.0.5",
|
|
11
11
|
"packages": [
|
|
12
12
|
{
|
|
13
13
|
"registryType": "npm",
|
|
14
14
|
"identifier": "hevy-mcp",
|
|
15
|
-
"version": "5.0.
|
|
15
|
+
"version": "5.0.5",
|
|
16
16
|
"transport": {
|
|
17
17
|
"type": "stdio"
|
|
18
18
|
},
|