import { z } from "zod";
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { WhoopClient } from "../whoop-client";
export function registerHealthspanTools(
server: McpServer,
whoopClient: WhoopClient
) {
server.registerTool(
"whoop_get_healthspan",
{
title: "Get Whoop Healthspan (Biological Age)",
description:
"Get comprehensive healthspan analysis including WHOOP Age (biological age), pace of aging, and comparison to chronological age",
inputSchema: {
date: z
.string()
.optional()
.describe(
"Date in YYYY-MM-DD format (defaults to today if not provided)"
),
},
outputSchema: {
navigationTitle: z.string(),
navigationSubtitle: z.string(),
dateRange: z.string(),
isCalibrating: z.boolean(),
currentPeriod: z.object({
whoopAge: z.string(),
ageStatus: z.string(),
yearsDifference: z.string(),
paceOfAging: z.string(),
}),
previousPeriod: z.object({
whoopAge: z.string(),
paceOfAging: z.string(),
}),
},
},
async ({ date }) => {
try {
const data = await whoopClient.getHealthspan(date);
const unlockedContent = data.unlocked_content;
const currentAmoeba = unlockedContent.whoop_age_amoeba;
const previousAmoeba = unlockedContent.previous_whoop_age_amoeba;
const output = {
navigationTitle: data.navigation_title,
navigationSubtitle: data.navigation_subtitle,
dateRange: unlockedContent.date_picker.current_date_range_display,
isCalibrating: unlockedContent.is_calibrating,
currentPeriod: {
whoopAge: currentAmoeba.age_value_display,
ageStatus: currentAmoeba.age_subtitle_display,
yearsDifference: currentAmoeba.years_difference_value_display,
paceOfAging: currentAmoeba.pace_of_aging_display,
},
previousPeriod: {
whoopAge: previousAmoeba.age_value_display,
paceOfAging: previousAmoeba.pace_of_aging_display,
},
};
const lines = [
"𧬠HEALTHSPAN (WHOOP AGE)",
"βββββββββββββββββββββββ",
"",
`π
Period: ${output.dateRange}`,
`β° ${output.navigationSubtitle}`,
"",
];
if (output.isCalibrating) {
lines.push(
"βοΈ CALIBRATING",
" Your Healthspan is currently being calculated...",
""
);
} else {
lines.push(
"π― CURRENT PERIOD",
"βββββββββββββββββ",
` WHOOP Age: ${output.currentPeriod.whoopAge}`,
` Status: ${output.currentPeriod.ageStatus}`,
` Years Difference: ${output.currentPeriod.yearsDifference}`,
` Pace of Aging: ${output.currentPeriod.paceOfAging}`,
"",
"π PREVIOUS PERIOD",
"ββββββββββββββββββ",
` WHOOP Age: ${output.previousPeriod.whoopAge}`,
` Pace of Aging: ${output.previousPeriod.paceOfAging}`,
""
);
const paceValue = parseFloat(
output.currentPeriod.paceOfAging.replace("x", "")
);
if (!isNaN(paceValue)) {
lines.push("π‘ INTERPRETATION", "βββββββββββββββββ");
if (paceValue < 1.0) {
lines.push(
` You're aging slower than average (${output.currentPeriod.paceOfAging})`,
` This means you're gaining less than 1 biological year per chronological year.`,
""
);
} else if (paceValue === 1.0) {
lines.push(
` You're aging at an average pace (${output.currentPeriod.paceOfAging})`,
` This means you're gaining 1 biological year per chronological year.`,
""
);
} else {
lines.push(
` You're aging faster than average (${output.currentPeriod.paceOfAging})`,
` This means you're gaining more than 1 biological year per chronological year.`,
""
);
}
}
}
const formattedText = lines.join("\n");
return {
content: [{ type: "text", text: formattedText }],
structuredContent: output,
};
} catch (error) {
const errorMessage =
error instanceof Error ? error.message : "Unknown error";
return {
content: [
{
type: "text",
text: `Error fetching Whoop healthspan data: ${errorMessage}`,
},
],
isError: true,
};
}
}
);
}