Skip to main content
Glama

update-body-measurement

Update an existing body measurement entry for a specific date. Overwrites all provided fields; omitted fields set to null. Returns 404 if no entry exists.

Instructions

Update an existing body measurement entry for a given date. All fields are overwritten — omitted fields are set to null. Returns 404 if no entry exists for the date.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
dateYesThe date of the body measurement to update (YYYY-MM-DD). Must already exist — returns 404 otherwise.
weightKgNoBody weight in kilograms
leanMassKgNoLean body mass in kilograms
fatPercentNoBody fat percentage
neckCmNoNeck circumference in centimeters
shoulderCmNoShoulder circumference in centimeters
chestCmNoChest circumference in centimeters
leftBicepCmNoLeft bicep circumference in centimeters
rightBicepCmNoRight bicep circumference in centimeters
leftForearmCmNoLeft forearm circumference in centimeters
rightForearmCmNoRight forearm circumference in centimeters
abdomenNoAbdomen circumference in centimeters
waistNoWaist circumference in centimeters
hipsNoHips circumference in centimeters
leftThighNoLeft thigh circumference in centimeters
rightThighNoRight thigh circumference in centimeters
leftCalfNoLeft calf circumference in centimeters
rightCalfNoRight calf circumference in centimeters

Implementation Reference

  • The tool handler for 'update-body-measurement' - calls hevyClient.updateBodyMeasurement() with the date and measurement payload built from fields.
    server.tool(
    	"update-body-measurement",
    	"Update an existing body measurement entry for a given date. All fields are overwritten — omitted fields are set to null. Returns 404 if no entry exists for the date.",
    	updateBodyMeasurementSchema,
    	withErrorHandling(async (args: UpdateBodyMeasurementParams) => {
    		if (!hevyClient) {
    			throw new Error(
    				"API client not initialized. Please provide HEVY_API_KEY.",
    			);
    		}
    		const { date, ...fields } = args;
    		await hevyClient.updateBodyMeasurement(
    			date,
    			buildMeasurementPayload(fields),
    		);
    
    		return createTextResponse(
    			`Body measurement for ${date} updated successfully.`,
    		);
    	}, "update-body-measurement"),
    );
  • Zod schema for the update-body-measurement tool - requires date (YYYY-MM-DD format) and all optional measurement fields from bodyMeasurementFieldsSchema.
    const updateBodyMeasurementSchema = {
    	date: z
    		.string()
    		.regex(/^\d{4}-\d{2}-\d{2}$/, "Date must be in YYYY-MM-DD format")
    		.describe(
    			"The date of the body measurement to update (YYYY-MM-DD). Must already exist — returns 404 otherwise.",
    		),
    	...bodyMeasurementFieldsSchema,
    } as const;
    type UpdateBodyMeasurementParams = InferToolParams<
    	typeof updateBodyMeasurementSchema
    >;
  • Helper function that converts camelCase field names to snake_case for the API payload.
    function buildMeasurementPayload(args: {
    	weightKg?: number | null;
    	leanMassKg?: number | null;
    	fatPercent?: number | null;
    	neckCm?: number | null;
    	shoulderCm?: number | null;
    	chestCm?: number | null;
    	leftBicepCm?: number | null;
    	rightBicepCm?: number | null;
    	leftForearmCm?: number | null;
    	rightForearmCm?: number | null;
    	abdomen?: number | null;
    	waist?: number | null;
    	hips?: number | null;
    	leftThigh?: number | null;
    	rightThigh?: number | null;
    	leftCalf?: number | null;
    	rightCalf?: number | null;
    }) {
    	return {
    		weight_kg: args.weightKg ?? null,
    		lean_mass_kg: args.leanMassKg ?? null,
    		fat_percent: args.fatPercent ?? null,
    		neck_cm: args.neckCm ?? null,
    		shoulder_cm: args.shoulderCm ?? null,
    		chest_cm: args.chestCm ?? null,
    		left_bicep_cm: args.leftBicepCm ?? null,
    		right_bicep_cm: args.rightBicepCm ?? null,
    		left_forearm_cm: args.leftForearmCm ?? null,
    		right_forearm_cm: args.rightForearmCm ?? null,
    		abdomen: args.abdomen ?? null,
    		waist: args.waist ?? null,
    		hips: args.hips ?? null,
    		left_thigh: args.leftThigh ?? null,
    		right_thigh: args.rightThigh ?? null,
    		left_calf: args.leftCalf ?? null,
    		right_calf: args.rightCalf ?? null,
    	};
    }
  • Shared Zod schema for all optional body measurement fields (nullable numbers used across create and update tools).
    const bodyMeasurementFieldsSchema = {
    	weightKg: zNullableNumber.describe("Body weight in kilograms"),
    	leanMassKg: zNullableNumber.describe("Lean body mass in kilograms"),
    	fatPercent: zNullableNumber.describe("Body fat percentage"),
    	neckCm: zNullableNumber.describe("Neck circumference in centimeters"),
    	shoulderCm: zNullableNumber.describe("Shoulder circumference in centimeters"),
    	chestCm: zNullableNumber.describe("Chest circumference in centimeters"),
    	leftBicepCm: zNullableNumber.describe(
    		"Left bicep circumference in centimeters",
    	),
    	rightBicepCm: zNullableNumber.describe(
    		"Right bicep circumference in centimeters",
    	),
    	leftForearmCm: zNullableNumber.describe(
    		"Left forearm circumference in centimeters",
    	),
    	rightForearmCm: zNullableNumber.describe(
    		"Right forearm circumference in centimeters",
    	),
    	abdomen: zNullableNumber.describe("Abdomen circumference in centimeters"),
    	waist: zNullableNumber.describe("Waist circumference in centimeters"),
    	hips: zNullableNumber.describe("Hips circumference in centimeters"),
    	leftThigh: zNullableNumber.describe(
    		"Left thigh circumference in centimeters",
    	),
    	rightThigh: zNullableNumber.describe(
    		"Right thigh circumference in centimeters",
    	),
    	leftCalf: zNullableNumber.describe("Left calf circumference in centimeters"),
    	rightCalf: zNullableNumber.describe(
    		"Right calf circumference in centimeters",
    	),
    } as const;
  • Registration function that registers all body measurement tools on the MCP server. Called from src/index.ts line 79.
    export function registerBodyMeasurementTools(
    	server: McpServer,
    	hevyClient: HevyClient | null,
    ) {
    	// Get body measurements (paginated list)
    	const getBodyMeasurementsSchema = {
    		page: z.coerce.number().int().gte(1).default(1),
    		pageSize: z.coerce.number().int().gte(1).lte(10).default(10),
    	} as const;
    	type GetBodyMeasurementsParams = InferToolParams<
    		typeof getBodyMeasurementsSchema
    	>;
    
    	server.tool(
    		"get-body-measurements",
    		"Get a paginated list of body measurements for the authenticated user. Returns measurements including weight, body fat, and various circumference measurements.",
    		getBodyMeasurementsSchema,
    		withErrorHandling(async (args: GetBodyMeasurementsParams) => {
    			if (!hevyClient) {
    				throw new Error(
    					"API client not initialized. Please provide HEVY_API_KEY.",
    				);
    			}
    			const { page, pageSize } = args;
    			const data: GetV1BodyMeasurements200 =
    				await hevyClient.getBodyMeasurements({
    					page,
    					pageSize,
    				});
    
    			const measurements =
    				data?.body_measurements?.map((measurement: BodyMeasurement) =>
    					formatBodyMeasurement(measurement),
    				) || [];
    
    			if (measurements.length === 0) {
    				return createEmptyResponse(
    					"No body measurements found for the specified parameters",
    				);
    			}
    
    			return createJsonResponse(measurements);
    		}, "get-body-measurements"),
    	);
    
    	// Get single body measurement by date
    	const getBodyMeasurementSchema = {
    		date: z
    			.string()
    			.regex(/^\d{4}-\d{2}-\d{2}$/, "Date must be in YYYY-MM-DD format")
    			.describe("The date of the body measurement (YYYY-MM-DD)"),
    	} as const;
    	type GetBodyMeasurementParams = InferToolParams<
    		typeof getBodyMeasurementSchema
    	>;
    
    	server.tool(
    		"get-body-measurement",
    		"Get a single body measurement by date. Returns all measurement fields for the specified date.",
    		getBodyMeasurementSchema,
    		withErrorHandling(async (args: GetBodyMeasurementParams) => {
    			if (!hevyClient) {
    				throw new Error(
    					"API client not initialized. Please provide HEVY_API_KEY.",
    				);
    			}
    			const { date } = args;
    			const data: GetV1BodyMeasurementsDate200 =
    				await hevyClient.getBodyMeasurement(date);
    
    			if (!data) {
    				return createEmptyResponse(
    					`No body measurement found for date ${date}`,
    				);
    			}
    
    			return createJsonResponse(formatBodyMeasurement(data));
    		}, "get-body-measurement"),
    	);
    
    	// Create body measurement
    	const createBodyMeasurementSchema = {
    		date: z
    			.string()
    			.regex(/^\d{4}-\d{2}-\d{2}$/, "Date must be in YYYY-MM-DD format")
    			.describe(
    				"The date of the body measurement (YYYY-MM-DD). Must be unique — returns 409 if an entry already exists for this date.",
    			),
    		...bodyMeasurementFieldsSchema,
    	} as const;
    	type CreateBodyMeasurementParams = InferToolParams<
    		typeof createBodyMeasurementSchema
    	>;
    
    	server.tool(
    		"create-body-measurement",
    		"Create a body measurement entry for a given date. All measurement fields are optional. Returns 409 if an entry already exists for that date — use update-body-measurement instead.",
    		createBodyMeasurementSchema,
    		withErrorHandling(async (args: CreateBodyMeasurementParams) => {
    			if (!hevyClient) {
    				throw new Error(
    					"API client not initialized. Please provide HEVY_API_KEY.",
    				);
    			}
    			const { date, ...fields } = args;
    			await hevyClient.createBodyMeasurement({
    				date,
    				...buildMeasurementPayload(fields),
    			});
    
    			return createTextResponse(
    				`Body measurement for ${date} created successfully.`,
    			);
    		}, "create-body-measurement"),
    	);
    
    	// Update body measurement
    	const updateBodyMeasurementSchema = {
    		date: z
    			.string()
    			.regex(/^\d{4}-\d{2}-\d{2}$/, "Date must be in YYYY-MM-DD format")
    			.describe(
    				"The date of the body measurement to update (YYYY-MM-DD). Must already exist — returns 404 otherwise.",
    			),
    		...bodyMeasurementFieldsSchema,
    	} as const;
    	type UpdateBodyMeasurementParams = InferToolParams<
    		typeof updateBodyMeasurementSchema
    	>;
    
    	server.tool(
    		"update-body-measurement",
    		"Update an existing body measurement entry for a given date. All fields are overwritten — omitted fields are set to null. Returns 404 if no entry exists for the date.",
    		updateBodyMeasurementSchema,
    		withErrorHandling(async (args: UpdateBodyMeasurementParams) => {
    			if (!hevyClient) {
    				throw new Error(
    					"API client not initialized. Please provide HEVY_API_KEY.",
    				);
    			}
    			const { date, ...fields } = args;
    			await hevyClient.updateBodyMeasurement(
    				date,
    				buildMeasurementPayload(fields),
    			);
    
    			return createTextResponse(
    				`Body measurement for ${date} updated successfully.`,
    			);
    		}, "update-body-measurement"),
    	);
    }
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden. It discloses two critical behaviors: 'All fields are overwritten — omitted fields are set to null' and 'Returns 404 if no entry exists.' This is transparent, though it could mention idempotency or the success response format.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is exceptionally concise: three sentences that cover purpose, behavior, and error condition. Every sentence earns its place with no redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (18 parameters, no output schema), the description covers the main points: update behavior and 404 error. It could be improved by specifying the success response (e.g., returns the updated entry), but overall it's sufficient for an agent to use the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has 100% coverage with individual parameter descriptions. The description adds significant value by explaining the overwrite policy (omitted fields set to null), which is not apparent from the schema alone. This tells the agent that to preserve a field's current value, it must be explicitly included.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Update an existing body measurement entry for a given date.' It specifies the verb (update), resource (body measurement entry), and the key constraint (existing entry for a date). This distinguishes it from 'create-body-measurement' and 'get-body-measurement'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear usage context: it updates an existing entry and warns about overwrite behavior and 404 on missing date. However, it does not explicitly mention when to use this over 'create-body-measurement' or when alternatives are appropriate, which would strengthen guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/chrisdoc/hevy-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server