"""
MCP Server for Medical Calculator
"""
import math
from scipy import stats
from mcp.server.fastmcp import FastMCP

import threading
import time

# Create FastMCP server instance
mcp = FastMCP()

# Constants for pediatric blood pressure percentile calculations
BP_COEFFICIENTS = {
    'male': {
        'systolic': {
            'intercept': 102.19768,
            'age_b1': 1.82416,
            'age_b2': 0.12776,
            'height_b': 0.25540,
            'sd': 10.7128
        },
        'diastolic': {
            'intercept': 61.01217,
            'age_b1': 0.68314,
            'age_b2': -0.09835,
            'height_b': 0.24912,
            'sd': 11.6032
        }
    },
    'female': {
        'systolic': {
            'intercept': 102.01027,
            'age_b1': 1.94397,
            'age_b2': 0.00598,
            'height_b': 0.14100,
            'sd': 10.4855
        },
        'diastolic': {
            'intercept': 60.50510,
            'age_b1': 1.01301,
            'age_b2': 0.01157,
            'height_b': 0.16031,
            'sd': 10.9573
        }
    }
}


@mcp.tool()
def egfr_epi(scr: float, age: int, male: bool) -> float:
    """
    Estimated Glomerular Filtration Rate (eGFR) using the EPI formula (version 2021)
    Reference: N Engl J Med. 2021 Nov 4;385(19):1737-1749
    
    Parameters:
    -----------
    scr : float
        serum creatinine level in mg/dL
    age : int
        Age in years
    male : bool
        true if Male
    
    Returns:
    --------
    float
        Estimated GFR in mL/min/1.73m^2
    """
    try:
        # 성별에 따른 κ와 α 값 설정
        k = 0.9 if male else 0.7
        a = -0.302 if male else -0.241
        return 142 * (0.9938 ** age) * (min(scr / k, 1) ** a) * (max(scr / k, 1) ** -1.2) * (1 if male else 1.012)
    except Exception as e:
        return {'error': str(e)}




@mcp.tool()
def egfr_epi_cr_cys(scr: float, scys: float, age: int, male: bool) -> float:
    """
    Estimated Glomerular Filtration Rate (eGFR) using the 2021 CKD-EPI Creatinine-Cystatin C equation
    Reference: N Engl J Med. 2021 Nov 4;385(19):1737-1749
    
    Parameters:
    -----------
    scr : float
        Serum creatinine level in mg/dL
    scys : float
        Serum cystatin C level in mg/L
    age : int
        Age in years
    male : bool
        True if patient is male, False if female
    
    Returns:
    --------
    efgr : float
        Estimated GFR in mL/min/1.73m^2
    """
    try:
        # Set parameters based on sex, creatinine level, and cystatin C level
        if male:
            k_cr = 0.9  # Parameter A
            k_cys = 0.8  # Parameter C
            
            if scr <= k_cr:
                alpha = -0.144  # Parameter B
            else:
                alpha = -0.544  # Parameter B
                
            if scys <= k_cys:
                beta = -0.323  # Parameter D
            else:
                beta = -0.778  # Parameter D
                
            sex_factor = 1.0
        else:  # female
            k_cr = 0.7  # Parameter A
            k_cys = 0.8  # Parameter C
            
            if scr <= k_cr:
                alpha = -0.219  # Parameter B
            else:
                alpha = -0.544  # Parameter B
                
            if scys <= k_cys:
                beta = -0.323  # Parameter D
            else:
                beta = -0.778  # Parameter D
                
            sex_factor = 0.963
        
        # Calculate eGFR using the 2021 CKD-EPI Creatinine-Cystatin C equation
        egfr = 135 * (scr / k_cr) ** alpha * (scys / k_cys) ** beta * (0.9961 ** age) * sex_factor
        
        # Return results
        return egfr
    except Exception as e:
        return {'error': str(e)}

@mcp.tool()
def mdrd_gfr(scr: float, age: int, is_black: bool, is_female: bool) -> float:
    """
    MDRD GFR Equation
    Estimates GFR in CKD patients using creatinine and patient characteristics.
    
    Parameters:
    -----------
    scr : float
        Serum creatinine level in mg/dL
    age : int
        Age in years
    is_black : bool
        True if patient is Black
    is_female : bool
        True if patient is female
    
    Returns:
    --------
    float
        Estimated GFR in mL/min/1.73m^2
    """
    try:
        # Base calculation
        gfr = 175 * (scr ** -1.154) * (age ** -0.203)
        
        # Apply race factor if patient is Black
        if is_black:
            gfr *= 1.212
        
        # Apply gender factor if patient is female
        if is_female:
            gfr *= 0.742
            
        return gfr
    except Exception as e:
        return {'error': str(e)}


@mcp.tool()
def bp_children(years: int, months: int, height: int, sex: str, systolic: int, diastolic: int) -> dict:
    """
    혈압 센타일(percentile)을 계산하는 함수
    
    Parameters:
    -----------
    years : int
        나이(년)
    months : int
        나이(월)
    height : int
        키(cm)
    sex : str
        성별 ('male' 또는 'female')
    systolic : int
        수축기 혈압(mmHg)
    diastolic : int
        이완기 혈압(mmHg)
    
    Returns:
    --------
    dict
        수축기 및 이완기 혈압 센타일 결과를 포함하는 딕셔너리
    """
    try:
        # 성별 확인 (입력값 정규화)
        if isinstance(sex, str):
            sex = sex.lower()
        
        if sex not in ['male', 'female']:
            raise ValueError("Sex must be 'male' or 'female'")
        
        # 나이 계산 (년)
        age = years + months/12.0
        
        # 키가 미터 단위로 입력되었는지 확인
        if height > 3:  # 미터가 아닌 센티미터 단위로 입력된 것 같음
            height = height / 100  # 센티미터를 미터로 변환
        
        # 혈압 회귀 파라미터
        bp_regression = {
            'male': {
                'systolic': {
                    'alpha': 102.19768,
                    'beta1': 1.82416,
                    'beta2': 0.12776,
                    'beta3': 0.00249,
                    'beta4': -0.00135,
                    'gamma1': 2.73157,
                    'gamma2': -0.19618,
                    'gamma3': -0.04659,
                    'gamma4': 0.00947,
                    'sigma': 10.7128
                },
                'diastolic': {
                    'alpha': 61.01217,
                    'beta1': 0.68314,
                    'beta2': -0.09835,
                    'beta3': 0.01711,
                    'beta4': 0.00045,
                    'gamma1': 1.46993,
                    'gamma2': -0.07849,
                    'gamma3': -0.03144,
                    'gamma4': 0.00967,
                    'sigma': 11.6032
                }
            },
            'female': {
                'systolic': {
                    'alpha': 102.01027,
                    'beta1': 1.94397,
                    'beta2': 0.00598,
                    'beta3': -0.00789,
                    'beta4': -0.00059,
                    'gamma1': 2.03526,
                    'gamma2': 0.02534,
                    'gamma3': -0.01884,
                    'gamma4': 0.00121,
                    'sigma': 10.4855
                },
                'diastolic': {
                    'alpha': 60.50510,
                    'beta1': 1.01301,
                    'beta2': 0.01157,
                    'beta3': 0.00424,
                    'beta4': -0.00137,
                    'gamma1': 1.16641,
                    'gamma2': 0.12795,
                    'gamma3': -0.03869,
                    'gamma4': -0.00079,
                    'sigma': 10.9573
                }
            }
        }
        
        # 키의 z-score 계산
        height_zscore = find_height_zscore(age, height, sex)
        
        # 수축기 혈압 센타일 계산
        sys_mu = calc_mu(age, height_zscore, bp_regression[sex]['systolic'])
        sys_zscore = (systolic - sys_mu) / bp_regression[sex]['systolic']['sigma']
        sys_percentile = stats.norm.cdf(sys_zscore) * 100
        
        # 이완기 혈압 센타일 계산
        dia_mu = calc_mu(age, height_zscore, bp_regression[sex]['diastolic'])
        dia_zscore = (diastolic - dia_mu) / bp_regression[sex]['diastolic']['sigma']
        dia_percentile = stats.norm.cdf(dia_zscore) * 100
        
        # 결과 반환
        return {
            'systolic': round(sys_percentile, 1),
            'diastolic': round(dia_percentile, 1)
        }
    except Exception as e:
        return {'error': str(e)}

def calc_mu(age, zht, params):
    """
    혈압의 평균(mu)을 계산
    
    Parameters:
    -----------
    age : float
        나이(년)
    zht : float
        키의 z-score
    params : dict
        BP 회귀 파라미터
        
    Returns:
    --------
    float
        혈압의 평균값
    """
    return (params['alpha'] +
            params['beta1'] * (age - 10) +
            params['beta2'] * (age - 10)**2 +
            params['beta3'] * (age - 10)**3 +
            params['beta4'] * (age - 10)**4 +
            params['gamma1'] * zht +
            params['gamma2'] * zht**2 +
            params['gamma3'] * zht**3 +
            params['gamma4'] * zht**4)


def find_height_zscore(age, height, sex):
    """
    성별과 연령에 따른 키의 z-score 계산
    
    Parameters:
    -----------
    age : float
        나이(년)
    height : float
        키(미터)
    sex : str
        성별('male' 또는 'female')
        
    Returns:
    --------
    float
        키의 z-score
    """
    # 연령을 개월로 변환
    age_months = age * 12
    
    # 키를 센티미터로 변환
    height_cm = height * 100
    
    # CDC 데이터에서 해당 연령대의 파라미터를 찾기
    params = find_height_parameters(age_months, sex)
    
    if params is None:
        # 파라미터를 찾을 수 없는 경우 기본값 0 반환
        return 0
    
    # 키의 z-score 계산
    if params['l'] == 0:
        return math.log(height_cm / params['m']) / params['s']
    else:
        return (math.pow(height_cm / params['m'], params['l']) - 1) / (params['l'] * params['s'])


def find_height_parameters(age_months, sex):
    """
    특정 연령대에 대한 CDC 신장 파라미터 찾기
    
    Parameters:
    -----------
    age_months : float
        개월 단위 나이
    sex : str
        성별('male' 또는 'female')
        
    Returns:
    --------
    dict 또는 None
        해당 연령대의 LMS 파라미터 (없으면 None)
    """
    # CDC 신장 데이터
    if age_months <= 36:
        ref_data = CDC_LENGTH_DATA[sex]
    else:
        ref_data = CDC_STATURE_DATA[sex]
    
    # 정확한 연령 또는 연령 범위 찾기
    for i in range(len(ref_data) - 1):
        if age_months == ref_data[i]['age']:
            return ref_data[i]
        elif age_months > ref_data[i]['age'] and age_months < ref_data[i+1]['age']:
            # 선형 보간
            weight = (age_months - ref_data[i]['age']) / (ref_data[i+1]['age'] - ref_data[i]['age'])
            
            exact = {
                'sex': sex,
                'age': age_months,
                'l': mean(ref_data[i]['l'], ref_data[i+1]['l'], weight),
                'm': mean(ref_data[i]['m'], ref_data[i+1]['m'], weight),
                's': mean(ref_data[i]['s'], ref_data[i+1]['s'], weight)
            }
            return exact
    
    # 찾지 못한 경우 None 반환
    return None


def mean(a, b, weight):
    """
    두 값의 가중 평균 계산
    
    Parameters:
    -----------
    a : float
        첫 번째 값
    b : float
        두 번째 값
    weight : float
        가중치(0~1)
        
    Returns:
    --------
    float
        가중 평균
    """
    return b * weight + a * (1 - weight)


# CDC 신장 데이터 (일부 표시)
CDC_LENGTH_DATA = {
    'male': [
        {'sex': 'male', 'age': 0,  'l': 1.2670042261, 'm': 49.988884079, 's': 0.0531121908},
        {'sex': 'male', 'age': 0.5,  'l': 0.5112376962, 'm': 52.695975301, 's': 0.0486926838},
        {'sex': 'male', 'age': 1.5,  'l': -0.45224446, 'm': 56.628428552, 's': 0.0441168302},
        {'sex': 'male', 'age': 2.5,  'l': -0.990594599, 'm': 59.608953427, 's': 0.0417955825},
        {'sex': 'male', 'age': 3.5,  'l': -1.285837689, 'm': 62.077000266, 's': 0.0404541256},
        {'sex': 'male', 'age': 4.5,  'l': -1.43031238, 'm': 64.216864104, 's': 0.0396338789},
        {'sex': 'male', 'age': 5.5,  'l': -1.47657547, 'm': 66.125314898, 's': 0.0391238128},
        {'sex': 'male', 'age': 6.5,  'l': -1.456837849, 'm': 67.860179904, 's': 0.0388119944},
        {'sex': 'male', 'age': 7.5,  'l': -1.391898768, 'm': 69.459084582, 's': 0.0386332091},
        {'sex': 'male', 'age': 8.5,  'l': -1.29571459, 'm': 70.948039123, 's': 0.0385468328},
        {'sex': 'male', 'age': 9.5,  'l': -1.177919048, 'm': 72.345861109, 's': 0.0385262623},
        {'sex': 'male', 'age': 10.5,  'l': -1.045326049, 'm': 73.666654103, 's': 0.038553387},
        {'sex': 'male', 'age': 11.5,  'l': -0.902800887, 'm': 74.921297174, 's': 0.0386155012},
        {'sex': 'male', 'age': 12.5,  'l': -0.753908107, 'm': 76.118375358, 's': 0.0387034611},
        {'sex': 'male', 'age': 13.5,  'l': -0.601263523, 'm': 77.264799111, 's': 0.0388105571},
        {'sex': 'male', 'age': 14.5,  'l': -0.446805039, 'm': 78.366223087, 's': 0.0389317838},
        {'sex': 'male', 'age': 15.5,  'l': -0.291974772, 'm': 79.427340501, 's': 0.0390633563},
        {'sex': 'male', 'age': 16.5,  'l': -0.13784767, 'm': 80.452094919, 's': 0.0392023816},
        {'sex': 'male', 'age': 17.5,  'l': 0.014776155, 'm': 81.443836034, 's': 0.0393466285},
        {'sex': 'male', 'age': 18.5,  'l': 0.1653041691, 'm': 82.405436434, 's': 0.0394943647},
        {'sex': 'male', 'age': 19.5,  'l': 0.3133018086, 'm': 83.339380627, 's': 0.0396442379},
        {'sex': 'male', 'age': 20.5,  'l': 0.4584554707, 'm': 84.247833944, 's': 0.0397951891},
        {'sex': 'male', 'age': 21.5,  'l': 0.6005446308, 'm': 85.132696575, 's': 0.0399463877},
        {'sex': 'male', 'age': 22.5,  'l': 0.7394389526, 'm': 85.995648803, 's': 0.0400971806},
        {'sex': 'male', 'age': 23.5,  'l': 0.8750004465, 'm': 86.838175097, 's': 0.0402470597},
        {'sex': 'male', 'age': 24.5,  'l': 1.0072080698, 'm': 87.661609339, 's': 0.0403956257},
        {'sex': 'male', 'age': 25.5,  'l': 0.8372513507, 'm': 88.452472817, 's': 0.0405775247},
        {'sex': 'male', 'age': 26.5,  'l': 0.681492975, 'm': 89.223264339, 's': 0.0407231216},
        {'sex': 'male', 'age': 27.5,  'l': 0.5387796541, 'm': 89.975492278, 's': 0.0408331942},
        {'sex': 'male', 'age': 28.5,  'l': 0.4076971531, 'm': 90.710408526, 's': 0.0409090589},
        {'sex': 'male', 'age': 29.5,  'l': 0.2867624533, 'm': 91.429077621, 's': 0.0409524329},
        {'sex': 'male', 'age': 30.5,  'l': 0.1744894848, 'm': 92.132423789, 's': 0.0409653301},
        {'sex': 'male', 'age': 31.5,  'l': 0.0694445205, 'm': 92.821271673, 's': 0.0409499758},
        {'sex': 'male', 'age': 32.5,  'l': -0.029720564, 'm': 93.496379457, 's': 0.0409087367},
        {'sex': 'male', 'age': 33.5,  'l': -0.124251789, 'm': 94.158465459, 's': 0.0408440616},
        {'sex': 'male', 'age': 34.5,  'l': -0.215288396, 'm': 94.808229231, 's': 0.0407584307},
        {'sex': 'male', 'age': 35.5,  'l': -0.30385434, 'm': 95.446369813, 's': 0.0406543122}],

        'female': [
        {'sex': 'female', 'age': 0,  'l': -1.295960857, 'm': 49.286396118, 's': 0.0500855601},
        {'sex': 'female', 'age': 0.5,  'l': -0.809249882, 'm': 51.683580573, 's': 0.0468185454},
        {'sex': 'female', 'age': 1.5,  'l': -0.050782985, 'm': 55.286128126, 's': 0.0434439},
        {'sex': 'female', 'age': 2.5,  'l': 0.4768514065, 'm': 58.093819061, 's': 0.0417161032},
        {'sex': 'female', 'age': 3.5,  'l': 0.8432996117, 'm': 60.459807634, 's': 0.0407051733},
        {'sex': 'female', 'age': 4.5,  'l': 1.0975622571, 'm': 62.536696555, 's': 0.0400797646},
        {'sex': 'female', 'age': 5.5,  'l': 1.2725096408, 'm': 64.406327624, 's': 0.0396868449},
        {'sex': 'female', 'age': 6.5,  'l': 1.3904288587, 'm': 66.118415533, 's': 0.0394445547},
        {'sex': 'female', 'age': 7.5,  'l': 1.466733925, 'm': 67.705744192, 's': 0.0393047376},
        {'sex': 'female', 'age': 8.5,  'l': 1.5123019758, 'm': 69.191236138, 's': 0.0392371101},
        {'sex': 'female', 'age': 9.5,  'l': 1.534950767, 'm': 70.591639237, 's': 0.0392216648},
        {'sex': 'female', 'age': 10.5,  'l': 1.5403908751, 'm': 71.919616727, 's': 0.0392446716},
        {'sex': 'female', 'age': 11.5,  'l': 1.5328528917, 'm': 73.185010399, 's': 0.0392964203},
        {'sex': 'female', 'age': 12.5,  'l': 1.5155094695, 'm': 74.395643786, 's': 0.0393698746},
        {'sex': 'female', 'age': 13.5,  'l': 1.4907650275, 'm': 75.557854397, 's': 0.0394598321},
        {'sex': 'female', 'age': 14.5,  'l': 1.460458255, 'm': 76.676858713, 's': 0.0395623818},
        {'sex': 'female', 'age': 15.5,  'l': 1.4260060091, 'm': 77.757009856, 's': 0.0396745415},
        {'sex': 'female', 'age': 16.5,  'l': 1.3885070954, 'm': 78.801984056, 's': 0.0397940102},
        {'sex': 'female', 'age': 17.5,  'l': 1.3488181274, 'm': 79.814918523, 's': 0.0399189943},
        {'sex': 'female', 'age': 18.5,  'l': 1.3076096543, 'm': 80.798515316, 's': 0.0400480838},
        {'sex': 'female', 'age': 19.5,  'l': 1.2654081486, 'm': 81.755120921, 's': 0.0401801621},
        {'sex': 'female', 'age': 20.5,  'l': 1.2226277319, 'm': 82.686788098, 's': 0.0403143396},
        {'sex': 'female', 'age': 21.5,  'l': 1.1795943654, 'm': 83.59532461, 's': 0.040449904},
        {'sex': 'female', 'age': 22.5,  'l': 1.1365644483, 'm': 84.48233206, 's': 0.0405862829},
        {'sex': 'female', 'age': 23.5,  'l': 1.0937319466, 'm': 85.349236238, 's': 0.0407230154},
        {'sex': 'female', 'age': 24.5,  'l': 1.0512729122, 'm': 86.197316902, 's': 0.0408597268},
        {'sex': 'female', 'age': 25.5,  'l': 1.041951175, 'm': 87.090263184, 's': 0.0411421607},
        {'sex': 'female', 'age': 26.5,  'l': 1.0125922357, 'm': 87.957141816, 's': 0.0413493986},
        {'sex': 'female', 'age': 27.5,  'l': 0.9705419086, 'm': 88.796018399, 's': 0.041500428},
        {'sex': 'female', 'age': 28.5,  'l': 0.9211299875, 'm': 89.605511504, 's': 0.0416105082},
        {'sex': 'female', 'age': 29.5,  'l': 0.8682213922, 'm': 90.38476689, 's': 0.0416917614},
        {'sex': 'female', 'age': 30.5,  'l': 0.8145441296, 'm': 91.133417221, 's': 0.0417536804},
        {'sex': 'female', 'age': 31.5,  'l': 0.7619579771, 'm': 91.851543603, 's': 0.0418035615},
        {'sex': 'female', 'age': 32.5,  'l': 0.7116602284, 'm': 92.539635196, 's': 0.0418468815},
        {'sex': 'female', 'age': 33.5,  'l': 0.6643233788, 'm': 93.198544285, 's': 0.041887626},
        {'sex': 'female', 'age': 34.5,  'l': 0.6202851017, 'm': 93.829453915, 's': 0.0419285678},
        {'sex': 'female', 'age': 35.5,  'l': 0.57955631, 'm': 94.433822779, 's': 0.0419715144},
    ]
}

CDC_STATURE_DATA = {
    'male': [
    {'sex': 'male', 'age': 24,  'l': 0.941523967, 'm': 86.45220101, 's': 0.040321528},
    {'sex': 'male', 'age': 24.5,  'l': 1.00720807, 'm': 86.86160934, 's': 0.040395626},
    {'sex': 'male', 'age': 25.5,  'l': 0.837251351, 'm': 87.65247282, 's': 0.040577525},
    {'sex': 'male', 'age': 26.5,  'l': 0.681492975, 'm': 88.42326434, 's': 0.040723122},
    {'sex': 'male', 'age': 27.5,  'l': 0.538779654, 'm': 89.17549228, 's': 0.040833194},
    {'sex': 'male', 'age': 28.5,  'l': 0.407697153, 'm': 89.91040853, 's': 0.040909059},
    {'sex': 'male', 'age': 29.5,  'l': 0.286762453, 'm': 90.62907762, 's': 0.040952433},
    {'sex': 'male', 'age': 30.5,  'l': 0.174489485, 'm': 91.33242379, 's': 0.04096533},
    {'sex': 'male', 'age': 31.5,  'l': 0.069444521, 'm': 92.02127167, 's': 0.040949976},
    {'sex': 'male', 'age': 32.5,  'l': -0.029720564, 'm': 92.69637946, 's': 0.040908737},
    {'sex': 'male', 'age': 33.5,  'l': -0.124251789, 'm': 93.35846546, 's': 0.040844062},
    {'sex': 'male', 'age': 34.5,  'l': -0.215288396, 'm': 94.00822923, 's': 0.040758431},
    {'sex': 'male', 'age': 35.5,  'l': -0.30385434, 'm': 94.64636981, 's': 0.040654312},
    {'sex': 'male', 'age': 36.5,  'l': -0.390918369, 'm': 95.27359106, 's': 0.04053412},
    {'sex': 'male', 'age': 37.5,  'l': -0.254801167, 'm': 95.91474929, 's': 0.040572876},
    {'sex': 'male', 'age': 38.5,  'l': -0.125654535, 'm': 96.54734328, 's': 0.04061691},
    {'sex': 'male', 'age': 39.5,  'l': -0.00316735, 'm': 97.17191309, 's': 0.040666414},
    {'sex': 'male', 'age': 40.5,  'l': 0.11291221, 'm': 97.78897727, 's': 0.040721467},
    {'sex': 'male', 'age': 41.5,  'l': 0.222754969, 'm': 98.3990283, 's': 0.040782045},
    {'sex': 'male', 'age': 42.5,  'l': 0.326530126, 'm': 99.00254338, 's': 0.040848042},
    {'sex': 'male', 'age': 43.5,  'l': 0.42436156, 'm': 99.599977, 's': 0.040919281},
    {'sex': 'male', 'age': 44.5,  'l': 0.516353108, 'm': 100.191764, 's': 0.040995524},
    {'sex': 'male', 'age': 45.5,  'l': 0.602595306, 'm': 100.7783198, 's': 0.041076485},
    {'sex': 'male', 'age': 46.5,  'l': 0.683170764, 'm': 101.3600411, 's': 0.041161838},
    {'sex': 'male', 'age': 47.5,  'l': 0.758158406, 'm': 101.9373058, 's': 0.041251224},
    {'sex': 'male', 'age': 48.5,  'l': 0.827636736, 'm': 102.5104735, 's': 0.041344257},
    {'sex': 'male', 'age': 49.5,  'l': 0.891686306, 'm': 103.0798852, 's': 0.041440534},
    {'sex': 'male', 'age': 50.5,  'l': 0.95039153, 'm': 103.645864, 's': 0.041539635},
    {'sex': 'male', 'age': 51.5,  'l': 1.003830006, 'm': 104.208713, 's': 0.041641136},
    {'sex': 'male', 'age': 52.5,  'l': 1.05213569, 'm': 104.7687256, 's': 0.041744602},
    {'sex': 'male', 'age': 53.5,  'l': 1.0953669, 'm': 105.3261638, 's': 0.041849607},
    {'sex': 'male', 'age': 54.5,  'l': 1.133652119, 'm': 105.8812823, 's': 0.041955723},
    {'sex': 'male', 'age': 55.5,  'l': 1.167104213, 'm': 106.4343146, 's': 0.042062532},
    {'sex': 'male', 'age': 56.5,  'l': 1.195845353, 'm': 106.9854769, 's': 0.042169628},
    {'sex': 'male', 'age': 57.5,  'l': 1.220004233, 'm': 107.534968, 's': 0.042276619},
    {'sex': 'male', 'age': 58.5,  'l': 1.239715856, 'm': 108.0829695, 's': 0.042383129},
    {'sex': 'male', 'age': 59.5,  'l': 1.255121285, 'm': 108.6296457, 's': 0.042488804},
    {'sex': 'male', 'age': 60.5,  'l': 1.266367398, 'm': 109.1751441, 's': 0.042593311},
    {'sex': 'male', 'age': 61.5,  'l': 1.273606657, 'm': 109.7195954, 's': 0.042696342},
    {'sex': 'male', 'age': 62.5,  'l': 1.276996893, 'm': 110.2631136, 's': 0.042797615},
    {'sex': 'male', 'age': 63.5,  'l': 1.276701119, 'm': 110.8057967, 's': 0.042896877},
    {'sex': 'male', 'age': 64.5,  'l': 1.272887366, 'm': 111.3477265, 's': 0.042993904},
    {'sex': 'male', 'age': 65.5,  'l': 1.265728536, 'm': 111.8889694, 's': 0.043088503},
    {'sex': 'male', 'age': 66.5,  'l': 1.255402281, 'm': 112.4295761, 's': 0.043180513},
    {'sex': 'male', 'age': 67.5,  'l': 1.242090871, 'm': 112.9695827, 's': 0.043269806},
    {'sex': 'male', 'age': 68.5,  'l': 1.225981067, 'm': 113.5090108, 's': 0.043356287},
    {'sex': 'male', 'age': 69.5,  'l': 1.207263978, 'm': 114.0478678, 's': 0.043439893},
    {'sex': 'male', 'age': 70.5,  'l': 1.186140222, 'm': 114.5861486, 's': 0.043520597},
    {'sex': 'male', 'age': 71.5,  'l': 1.162796198, 'm': 115.1238315, 's': 0.043598407},
    {'sex': 'male', 'age': 72.5,  'l': 1.137442868, 'm': 115.6608862, 's': 0.043673359},
    {'sex': 'male', 'age': 73.5,  'l': 1.110286487, 'm': 116.1972691, 's': 0.043745523},
    {'sex': 'male', 'age': 74.5,  'l': 1.081536236, 'm': 116.732925, 's': 0.043815003},
    {'sex': 'male', 'age': 75.5,  'l': 1.05140374, 'm': 117.2677879, 's': 0.043881929},
    {'sex': 'male', 'age': 76.5,  'l': 1.020102497, 'm': 117.8017819, 's': 0.043946461},
    {'sex': 'male', 'age': 77.5,  'l': 0.987847213, 'm': 118.3348215, 's': 0.044008785},
    {'sex': 'male', 'age': 78.5,  'l': 0.954853043, 'm': 118.8668123, 's': 0.044069112},
    {'sex': 'male', 'age': 79.5,  'l': 0.921334742, 'm': 119.397652, 's': 0.044127675},
    {'sex': 'male', 'age': 80.5,  'l': 0.887505723, 'm': 119.9272309, 's': 0.044184725},
    {'sex': 'male', 'age': 81.5,  'l': 0.85357703, 'm': 120.455433, 's': 0.044240532},
    {'sex': 'male', 'age': 82.5,  'l': 0.819756239, 'm': 120.9821362, 's': 0.044295379},
    {'sex': 'male', 'age': 83.5,  'l': 0.786246296, 'm': 121.5072136, 's': 0.044349559},
    {'sex': 'male', 'age': 84.5,  'l': 0.753244292, 'm': 122.0305342, 's': 0.044403374},
    {'sex': 'male', 'age': 85.5,  'l': 0.720940222, 'm': 122.5519634, 's': 0.04445713},
    {'sex': 'male', 'age': 86.5,  'l': 0.689515708, 'm': 123.0713645, 's': 0.044511135},
    {'sex': 'male', 'age': 87.5,  'l': 0.659142731, 'm': 123.588599, 's': 0.044565693},
    {'sex': 'male', 'age': 88.5,  'l': 0.629997853, 'm': 124.1035312, 's': 0.044621104},
    {'sex': 'male', 'age': 89.5,  'l': 0.602203984, 'm': 124.6160161, 's': 0.044677662},
    {'sex': 'male', 'age': 90.5,  'l': 0.575908038, 'm': 125.1259182, 's': 0.044735646},
    {'sex': 'male', 'age': 91.5,  'l': 0.55123134, 'm': 125.6331012, 's': 0.044795322},
    {'sex': 'male', 'age': 92.5,  'l': 0.528279901, 'm': 126.1374319, 's': 0.044856941},
    {'sex': 'male', 'age': 93.5,  'l': 0.507143576, 'm': 126.6387804, 's': 0.04492073},
    {'sex': 'male', 'age': 94.5,  'l': 0.487895344, 'm': 127.1370217, 's': 0.044986899},
    {'sex': 'male', 'age': 95.5,  'l': 0.470590753, 'm': 127.6320362, 's': 0.045055632},
    {'sex': 'male', 'age': 96.5,  'l': 0.455267507, 'm': 128.1237104, 's': 0.045127088},
    {'sex': 'male', 'age': 97.5,  'l': 0.441945241, 'm': 128.6119383, 's': 0.045201399},
    {'sex': 'male', 'age': 98.5,  'l': 0.430625458, 'm': 129.096622, 's': 0.045278671},
    {'sex': 'male', 'age': 99.5,  'l': 0.421291648, 'm': 129.5776723, 's': 0.045358979},
    {'sex': 'male', 'age': 100.5,  'l': 0.413909588, 'm': 130.0550101, 's': 0.045442372},
    {'sex': 'male', 'age': 101.5,  'l': 0.408427813, 'm': 130.5285669, 's': 0.045528869},
    {'sex': 'male', 'age': 102.5,  'l': 0.404778262, 'm': 130.9982857, 's': 0.045618459},
    {'sex': 'male', 'age': 103.5,  'l': 0.402877077, 'm': 131.4641218, 's': 0.045711105},
    {'sex': 'male', 'age': 104.5,  'l': 0.402625561, 'm': 131.9260439, 's': 0.045806742},
    {'sex': 'male', 'age': 105.5,  'l': 0.40391127, 'm': 132.3840348, 's': 0.045905281},
    {'sex': 'male', 'age': 106.5,  'l': 0.406609232, 'm': 132.838092, 's': 0.046006604},
    {'sex': 'male', 'age': 107.5,  'l': 0.410583274, 'm': 133.2882291, 's': 0.046110573},
    {'sex': 'male', 'age': 108.5,  'l': 0.415687443, 'm': 133.7344759, 's': 0.046217028},
    {'sex': 'male', 'age': 109.5,  'l': 0.421767514, 'm': 134.1768801, 's': 0.04632579},
    {'sex': 'male', 'age': 110.5,  'l': 0.428662551, 'm': 134.6155076, 's': 0.046436662},
    {'sex': 'male', 'age': 111.5,  'l': 0.436206531, 'm': 135.0504433, 's': 0.04654943},
    {'sex': 'male', 'age': 112.5,  'l': 0.44423, 'm': 135.4817925, 's': 0.046663871},
    {'sex': 'male', 'age': 113.5,  'l': 0.45256176, 'm': 135.9096813, 's': 0.046779748},
    {'sex': 'male', 'age': 114.5,  'l': 0.461030578, 'm': 136.3342577, 's': 0.046896817},
    {'sex': 'male', 'age': 115.5,  'l': 0.469466904, 'm': 136.7556923, 's': 0.047014827},
    {'sex': 'male', 'age': 116.5,  'l': 0.477704608, 'm': 137.1741794, 's': 0.047133525},
    {'sex': 'male', 'age': 117.5,  'l': 0.48558272, 'm': 137.5899378, 's': 0.047252654},
    {'sex': 'male', 'age': 118.5,  'l': 0.492947182, 'm': 138.0032114, 's': 0.047371961},
    {'sex': 'male', 'age': 119.5,  'l': 0.499652617, 'm': 138.4142703, 's': 0.047491194},
    {'sex': 'male', 'age': 120.5,  'l': 0.505564115, 'm': 138.8234114, 's': 0.047610108},
    {'sex': 'male', 'age': 121.5,  'l': 0.510559047, 'm': 139.2309592, 's': 0.047728463},
    {'sex': 'male', 'age': 122.5,  'l': 0.514528903, 'm': 139.6372663, 's': 0.04784603},
    {'sex': 'male', 'age': 123.5,  'l': 0.517381177, 'm': 140.042714, 's': 0.047962592},
    {'sex': 'male', 'age': 124.5,  'l': 0.519041285, 'm': 140.4477127, 's': 0.048077942},
    {'sex': 'male', 'age': 125.5,  'l': 0.519454524, 'm': 140.8527022, 's': 0.048191889},
    {'sex': 'male', 'age': 126.5,  'l': 0.518588072, 'm': 141.2581515, 's': 0.048304259},
    {'sex': 'male', 'age': 127.5,  'l': 0.516433004, 'm': 141.6645592, 's': 0.048414893},
    {'sex': 'male', 'age': 128.5,  'l': 0.513006312, 'm': 142.072452, 's': 0.048523648},
    {'sex': 'male', 'age': 129.5,  'l': 0.508352901, 'm': 142.4823852, 's': 0.048630402},
    {'sex': 'male', 'age': 130.5,  'l': 0.502547502, 'm': 142.8949403, 's': 0.04873505},
    {'sex': 'male', 'age': 131.5,  'l': 0.495696454, 'm': 143.3107241, 's': 0.048837504},
    {'sex': 'male', 'age': 132.5,  'l': 0.487939275, 'm': 143.7303663, 's': 0.048937694},
    {'sex': 'male', 'age': 133.5,  'l': 0.479449924, 'm': 144.1545167, 's': 0.049035564},
    {'sex': 'male', 'age': 134.5,  'l': 0.470437652, 'm': 144.5838414, 's': 0.049131073},
    {'sex': 'male', 'age': 135.5,  'l': 0.461147305, 'm': 145.0190192, 's': 0.049224189},
    {'sex': 'male', 'age': 136.5,  'l': 0.451858946, 'm': 145.4607359, 's': 0.049314887},
    {'sex': 'male', 'age': 137.5,  'l': 0.442886661, 'm': 145.9096784, 's': 0.049403145},
    {'sex': 'male', 'age': 138.5,  'l': 0.434576385, 'm': 146.3665278, 's': 0.049488934},
    {'sex': 'male', 'age': 139.5,  'l': 0.427302633, 'm': 146.8319513, 's': 0.049572216},
    {'sex': 'male', 'age': 140.5,  'l': 0.421464027, 'm': 147.3065929, 's': 0.049652935},
    {'sex': 'male', 'age': 141.5,  'l': 0.417477538, 'm': 147.7910635, 's': 0.049731004},
    {'sex': 'male', 'age': 142.5,  'l': 0.415771438, 'm': 148.2859294, 's': 0.0498063},
    {'sex': 'male', 'age': 143.5,  'l': 0.416777012, 'm': 148.7917006, 's': 0.04987865},
    {'sex': 'male', 'age': 144.5,  'l': 0.420919142, 'm': 149.3088178, 's': 0.049947823},
    {'sex': 'male', 'age': 145.5,  'l': 0.428606007, 'm': 149.8376391, 's': 0.050013518},
    {'sex': 'male', 'age': 146.5,  'l': 0.440218167, 'm': 150.3784267, 's': 0.050075353},
    {'sex': 'male', 'age': 147.5,  'l': 0.456097443, 'm': 150.9313331, 's': 0.050132858},
    {'sex': 'male', 'age': 148.5,  'l': 0.476536014, 'm': 151.4963887, 's': 0.050185471},
    {'sex': 'male', 'age': 149.5,  'l': 0.501766234, 'm': 152.0734897, 's': 0.050232532},
    {'sex': 'male', 'age': 150.5,  'l': 0.531951655, 'm': 152.6623878, 's': 0.050273285},
    {'sex': 'male', 'age': 151.5,  'l': 0.567179725, 'm': 153.2626819, 's': 0.050306885},
    {'sex': 'male', 'age': 152.5,  'l': 0.607456565, 'm': 153.8738124, 's': 0.050332406},
    {'sex': 'male', 'age': 153.5,  'l': 0.652704121, 'm': 154.495058, 's': 0.05034886},
    {'sex': 'male', 'age': 154.5,  'l': 0.702759868, 'm': 155.1255365, 's': 0.050355216},
    {'sex': 'male', 'age': 155.5,  'l': 0.757379106, 'm': 155.7642086, 's': 0.050350423},
    {'sex': 'male', 'age': 156.5,  'l': 0.816239713, 'm': 156.4098858, 's': 0.050333444},
    {'sex': 'male', 'age': 157.5,  'l': 0.878947416, 'm': 157.0612415, 's': 0.050303283},
    {'sex': 'male', 'age': 158.5,  'l': 0.945053486, 'm': 157.7168289, 's': 0.050259018},
    {'sex': 'male', 'age': 159.5,  'l': 1.014046108, 'm': 158.3750929, 's': 0.050199837},
    {'sex': 'male', 'age': 160.5,  'l': 1.085383319, 'm': 159.034399, 's': 0.050125062},
    {'sex': 'male', 'age': 161.5,  'l': 1.158487278, 'm': 159.6930501, 's': 0.05003418},
    {'sex': 'male', 'age': 162.5,  'l': 1.232768816, 'm': 160.3493168, 's': 0.049926861},
    {'sex': 'male', 'age': 163.5,  'l': 1.307628899, 'm': 161.0014586, 's': 0.049802977},
    {'sex': 'male', 'age': 164.5,  'l': 1.382473225, 'm': 161.6477515, 's': 0.04966261},
    {'sex': 'male', 'age': 165.5,  'l': 1.456720479, 'm': 162.2865119, 's': 0.049506051},
    {'sex': 'male', 'age': 166.5,  'l': 1.529810247, 'm': 162.9161202, 's': 0.049333801},
    {'sex': 'male', 'age': 167.5,  'l': 1.601219573, 'm': 163.535045, 's': 0.049146553},
    {'sex': 'male', 'age': 168.5,  'l': 1.670433444, 'm': 164.1418486, 's': 0.04894519},
    {'sex': 'male', 'age': 169.5,  'l': 1.736995571, 'm': 164.7352199, 's': 0.048730749},
    {'sex': 'male', 'age': 170.5,  'l': 1.800483802, 'm': 165.3139755, 's': 0.048504404},
    {'sex': 'male', 'age': 171.5,  'l': 1.860518777, 'm': 165.8770715, 's': 0.048267442},
    {'sex': 'male', 'age': 172.5,  'l': 1.916765525, 'm': 166.4236087, 's': 0.04802123},
    {'sex': 'male', 'age': 173.5,  'l': 1.968934444, 'm': 166.9528354, 's': 0.047767192},
    {'sex': 'male', 'age': 174.5,  'l': 2.016781776, 'm': 167.4641466, 's': 0.047506783},
    {'sex': 'male', 'age': 175.5,  'l': 2.060109658, 'm': 167.9570814, 's': 0.047241456},
    {'sex': 'male', 'age': 176.5,  'l': 2.098765817, 'm': 168.4313175, 's': 0.04697265},
    {'sex': 'male', 'age': 177.5,  'l': 2.132642948, 'm': 168.8866644, 's': 0.046701759},
    {'sex': 'male', 'age': 178.5,  'l': 2.16167779, 'm': 169.3230548, 's': 0.046430122},
    {'sex': 'male', 'age': 179.5,  'l': 2.185849904, 'm': 169.7405351, 's': 0.046159004},
    {'sex': 'male', 'age': 180.5,  'l': 2.205180153, 'm': 170.139255, 's': 0.045889585},
    {'sex': 'male', 'age': 181.5,  'l': 2.219728869, 'm': 170.5194567, 's': 0.045622955},
    {'sex': 'male', 'age': 182.5,  'l': 2.2295937, 'm': 170.881464, 's': 0.045360101},
    {'sex': 'male', 'age': 183.5,  'l': 2.234907144, 'm': 171.2256717, 's': 0.045101913},
    {'sex': 'male', 'age': 184.5,  'l': 2.235833767, 'm': 171.5525345, 's': 0.044849174},
    {'sex': 'male', 'age': 185.5,  'l': 2.232567138, 'm': 171.8625576, 's': 0.044602566},
    {'sex': 'male', 'age': 186.5,  'l': 2.2253265, 'm': 172.1562865, 's': 0.044362674},
    {'sex': 'male', 'age': 187.5,  'l': 2.214353232, 'm': 172.4342983, 's': 0.044129985},
    {'sex': 'male', 'age': 188.5,  'l': 2.199905902, 'm': 172.6971935, 's': 0.043904897},
    {'sex': 'male', 'age': 189.5,  'l': 2.182262864, 'm': 172.9455898, 's': 0.043687723},
    {'sex': 'male', 'age': 190.5,  'l': 2.161704969, 'm': 173.180112, 's': 0.043478698},
    {'sex': 'male', 'age': 191.5,  'l': 2.138524662, 'm': 173.4013896, 's': 0.043277987},
    {'sex': 'male', 'age': 192.5,  'l': 2.113023423, 'm': 173.6100518, 's': 0.043085685},
    {'sex': 'male', 'age': 193.5,  'l': 2.085490286, 'm': 173.8067179, 's': 0.042901835},
    {'sex': 'male', 'age': 194.5,  'l': 2.0562195, 'm': 173.9919998, 's': 0.042726424},
    {'sex': 'male', 'age': 195.5,  'l': 2.025496648, 'm': 174.1664951, 's': 0.042559396},
    {'sex': 'male', 'age': 196.5,  'l': 1.993598182, 'm': 174.3307855, 's': 0.042400652},
    {'sex': 'male', 'age': 197.5,  'l': 1.960789092, 'm': 174.4854344, 's': 0.042250063},
    {'sex': 'male', 'age': 198.5,  'l': 1.927320937, 'm': 174.6309856, 's': 0.042107465},
    {'sex': 'male', 'age': 199.5,  'l': 1.89343024, 'm': 174.7679617, 's': 0.041972676},
    {'sex': 'male', 'age': 200.5,  'l': 1.859337259, 'm': 174.8968634, 's': 0.041845488},
    {'sex': 'male', 'age': 201.5,  'l': 1.825245107, 'm': 175.0181691, 's': 0.041725679},
    {'sex': 'male', 'age': 202.5,  'l': 1.791339209, 'm': 175.1323345, 's': 0.041613015},
    {'sex': 'male', 'age': 203.5,  'l': 1.757787065, 'm': 175.2397926, 's': 0.041507249},
    {'sex': 'male', 'age': 204.5,  'l': 1.724738292, 'm': 175.340954, 's': 0.041408129},
    {'sex': 'male', 'age': 205.5,  'l': 1.692324905, 'm': 175.4362071, 's': 0.041315398},
    {'sex': 'male', 'age': 206.5,  'l': 1.660661815, 'm': 175.5259191, 's': 0.041228796},
    {'sex': 'male', 'age': 207.5,  'l': 1.629847495, 'm': 175.6104358, 's': 0.04114806},
    {'sex': 'male', 'age': 208.5,  'l': 1.599964788, 'm': 175.690083, 's': 0.041072931},
    {'sex': 'male', 'age': 209.5,  'l': 1.571081817, 'm': 175.7651671, 's': 0.04100315},
    {'sex': 'male', 'age': 210.5,  'l': 1.543252982, 'm': 175.8359757, 's': 0.040938463},
    {'sex': 'male', 'age': 211.5,  'l': 1.516519998, 'm': 175.9027788, 's': 0.040878617},
    {'sex': 'male', 'age': 212.5,  'l': 1.490912963, 'm': 175.9658293, 's': 0.040823368},
    {'sex': 'male', 'age': 213.5,  'l': 1.466451429, 'm': 176.0253641, 's': 0.040772475},
    {'sex': 'male', 'age': 214.5,  'l': 1.44314546, 'm': 176.081605, 's': 0.040725706},
    {'sex': 'male', 'age': 215.5,  'l': 1.420996665, 'm': 176.1347593, 's': 0.040682834},
    {'sex': 'male', 'age': 216.5,  'l': 1.399999187, 'm': 176.1850208, 's': 0.04064364},
    {'sex': 'male', 'age': 217.5,  'l': 1.380140651, 'm': 176.2325707, 's': 0.040607913},
    {'sex': 'male', 'age': 218.5,  'l': 1.361403047, 'm': 176.2775781, 's': 0.040575448},
    {'sex': 'male', 'age': 219.5,  'l': 1.343763564, 'm': 176.3202008, 's': 0.040546051},
    {'sex': 'male', 'age': 220.5,  'l': 1.327195355, 'm': 176.3605864, 's': 0.040519532},
    {'sex': 'male', 'age': 221.5,  'l': 1.311668242, 'm': 176.3988725, 's': 0.040495713},
    {'sex': 'male', 'age': 222.5,  'l': 1.297149359, 'm': 176.4351874, 's': 0.040474421},
    {'sex': 'male', 'age': 223.5,  'l': 1.283603728, 'm': 176.469651, 's': 0.040455493},
    {'sex': 'male', 'age': 224.5,  'l': 1.270994782, 'm': 176.5023751, 's': 0.040438773},
    {'sex': 'male', 'age': 225.5,  'l': 1.25928483, 'm': 176.533464, 's': 0.040424111},
    {'sex': 'male', 'age': 226.5,  'l': 1.248435461, 'm': 176.5630153, 's': 0.040411366},
    {'sex': 'male', 'age': 227.5,  'l': 1.23840791, 'm': 176.5911197, 's': 0.040400405},
    {'sex': 'male', 'age': 228.5,  'l': 1.229163362, 'm': 176.6178621, 's': 0.040391101},
    {'sex': 'male', 'age': 229.5,  'l': 1.220663228, 'm': 176.6433219, 's': 0.040383334},
    {'sex': 'male', 'age': 230.5,  'l': 1.212869374, 'm': 176.6675729, 's': 0.04037699},
    {'sex': 'male', 'age': 231.5,  'l': 1.20574431, 'm': 176.6906844, 's': 0.040371962},
    {'sex': 'male', 'age': 232.5,  'l': 1.199251356, 'm': 176.712721, 's': 0.040368149},
    {'sex': 'male', 'age': 233.5,  'l': 1.19335477, 'm': 176.733743, 's': 0.040365456},
    {'sex': 'male', 'age': 234.5,  'l': 1.188019859, 'm': 176.753807, 's': 0.040363795},
    {'sex': 'male', 'age': 235.5,  'l': 1.183213059, 'm': 176.7729657, 's': 0.04036308},
    {'sex': 'male', 'age': 236.5,  'l': 1.178901998, 'm': 176.7912687, 's': 0.040363233},
    {'sex': 'male', 'age': 237.5,  'l': 1.175055543, 'm': 176.8087622, 's': 0.040364179},
    {'sex': 'male', 'age': 238.5,  'l': 1.171643828, 'm': 176.8254895, 's': 0.04036585},
    {'sex': 'male', 'age': 239.5,  'l': 1.16863827, 'm': 176.8414914, 's': 0.04036818},
    {'sex': 'male', 'age': 240,  'l': 1.167279219, 'm': 176.8492322, 's': 0.040369574}],
    'female': [
    {'sex': 'female', 'age': 24,  'l': 1.07244896, 'm': 84.97555512, 's': 0.040791394},
    {'sex': 'female', 'age': 24.5,  'l': 1.051272912, 'm': 85.3973169, 's': 0.040859727},
    {'sex': 'female', 'age': 25.5,  'l': 1.041951175, 'm': 86.29026318, 's': 0.041142161},
    {'sex': 'female', 'age': 26.5,  'l': 1.012592236, 'm': 87.15714182, 's': 0.041349399},
    {'sex': 'female', 'age': 27.5,  'l': 0.970541909, 'm': 87.9960184, 's': 0.041500428},
    {'sex': 'female', 'age': 28.5,  'l': 0.921129988, 'm': 88.8055115, 's': 0.041610508},
    {'sex': 'female', 'age': 29.5,  'l': 0.868221392, 'm': 89.58476689, 's': 0.041691761},
    {'sex': 'female', 'age': 30.5,  'l': 0.81454413, 'm': 90.33341722, 's': 0.04175368},
    {'sex': 'female', 'age': 31.5,  'l': 0.761957977, 'm': 91.0515436, 's': 0.041803562},
    {'sex': 'female', 'age': 32.5,  'l': 0.711660228, 'm': 91.7396352, 's': 0.041846882},
    {'sex': 'female', 'age': 33.5,  'l': 0.664323379, 'm': 92.39854429, 's': 0.041887626},
    {'sex': 'female', 'age': 34.5,  'l': 0.620285102, 'm': 93.02945392, 's': 0.041928568},
    {'sex': 'female', 'age': 35.5,  'l': 0.57955631, 'm': 93.63382278, 's': 0.041971514},
    {'sex': 'female', 'age': 36.5,  'l': 0.54198094, 'm': 94.21335709, 's': 0.042017509},
    {'sex': 'female', 'age': 37.5,  'l': 0.511429832, 'm': 94.79643239, 's': 0.042104522},
    {'sex': 'female', 'age': 38.5,  'l': 0.482799937, 'm': 95.37391918, 's': 0.042199507},
    {'sex': 'female', 'age': 39.5,  'l': 0.455521041, 'm': 95.94692677, 's': 0.042300333},
    {'sex': 'female', 'age': 40.5,  'l': 0.429150288, 'm': 96.51644912, 's': 0.042405225},
    {'sex': 'female', 'age': 41.5,  'l': 0.403351725, 'm': 97.08337211, 's': 0.042512706},
    {'sex': 'female', 'age': 42.5,  'l': 0.377878239, 'm': 97.6484807, 's': 0.042621565},
    {'sex': 'female', 'age': 43.5,  'l': 0.352555862, 'm': 98.21246579, 's': 0.042730809},
    {'sex': 'female', 'age': 44.5,  'l': 0.327270297, 'm': 98.77593069, 's': 0.042839638},
    {'sex': 'female', 'age': 45.5,  'l': 0.301955463, 'm': 99.33939735, 's': 0.042947412},
    {'sex': 'female', 'age': 46.5,  'l': 0.276583851, 'm': 99.9033122, 's': 0.043053626},
    {'sex': 'female', 'age': 47.5,  'l': 0.251158446, 'm': 100.4680516, 's': 0.043157889},
    {'sex': 'female', 'age': 48.5,  'l': 0.225705996, 'm': 101.033927, 's': 0.043259907},
    {'sex': 'female', 'age': 49.5,  'l': 0.20027145, 'm': 101.6011898, 's': 0.043359463},
    {'sex': 'female', 'age': 50.5,  'l': 0.174913356, 'm': 102.1700358, 's': 0.043456406},
    {'sex': 'female', 'age': 51.5,  'l': 0.149700081, 'm': 102.7406094, 's': 0.043550638},
    {'sex': 'female', 'age': 52.5,  'l': 0.12470671, 'm': 103.3130077, 's': 0.043642107},
    {'sex': 'female', 'age': 53.5,  'l': 0.100012514, 'm': 103.8872839, 's': 0.043730791},
    {'sex': 'female', 'age': 54.5,  'l': 0.075698881, 'm': 104.4634511, 's': 0.043816701},
    {'sex': 'female', 'age': 55.5,  'l': 0.051847635, 'm': 105.0414853, 's': 0.043899867},
    {'sex': 'female', 'age': 56.5,  'l': 0.02853967, 'm': 105.6213287, 's': 0.043980337},
    {'sex': 'female', 'age': 57.5,  'l': 0.005853853, 'm': 106.2028921, 's': 0.044058171},
    {'sex': 'female', 'age': 58.5,  'l': -0.016133871, 'm': 106.7860583, 's': 0.04413344},
    {'sex': 'female', 'age': 59.5,  'l': -0.037351181, 'm': 107.3706841, 's': 0.044206218},
    {'sex': 'female', 'age': 60.5,  'l': -0.057729947, 'm': 107.9566031, 's': 0.044276588},
    {'sex': 'female', 'age': 61.5,  'l': -0.077206672, 'm': 108.5436278, 's': 0.044344632},
    {'sex': 'female', 'age': 62.5,  'l': -0.09572283, 'm': 109.1315521, 's': 0.044410436},
    {'sex': 'female', 'age': 63.5,  'l': -0.113225128, 'm': 109.7201531, 's': 0.044474084},
    {'sex': 'female', 'age': 64.5,  'l': -0.129665689, 'm': 110.3091934, 's': 0.044535662},
    {'sex': 'female', 'age': 65.5,  'l': -0.145002179, 'm': 110.8984228, 's': 0.044595254},
    {'sex': 'female', 'age': 66.5,  'l': -0.159197885, 'm': 111.4875806, 's': 0.044652942},
    {'sex': 'female', 'age': 67.5,  'l': -0.172221748, 'm': 112.0763967, 's': 0.044708809},
    {'sex': 'female', 'age': 68.5,  'l': -0.184048358, 'm': 112.6645943, 's': 0.044762936},
    {'sex': 'female', 'age': 69.5,  'l': -0.194660215, 'm': 113.2518902, 's': 0.044815402},
    {'sex': 'female', 'age': 70.5,  'l': -0.204030559, 'm': 113.8380006, 's': 0.044866288},
    {'sex': 'female', 'age': 71.5,  'l': -0.212174408, 'm': 114.4226317, 's': 0.044915672},
    {'sex': 'female', 'age': 72.5,  'l': -0.219069129, 'm': 115.0054978, 's': 0.044963636},
    {'sex': 'female', 'age': 73.5,  'l': -0.224722166, 'm': 115.5863089, 's': 0.045010259},
    {'sex': 'female', 'age': 74.5,  'l': -0.229140412, 'm': 116.1647782, 's': 0.045055624},
    {'sex': 'female', 'age': 75.5,  'l': -0.232335686, 'm': 116.7406221, 's': 0.045099817},
    {'sex': 'female', 'age': 76.5,  'l': -0.234324563, 'm': 117.3135622, 's': 0.045142924},
    {'sex': 'female', 'age': 77.5,  'l': -0.235128195, 'm': 117.8833259, 's': 0.045185036},
    {'sex': 'female', 'age': 78.5,  'l': -0.234772114, 'm': 118.4496481, 's': 0.045226249},
    {'sex': 'female', 'age': 79.5,  'l': -0.233286033, 'm': 119.0122722, 's': 0.045266662},
    {'sex': 'female', 'age': 80.5,  'l': -0.230703633, 'm': 119.5709513, 's': 0.045306383},
    {'sex': 'female', 'age': 81.5,  'l': -0.227062344, 'm': 120.1254495, 's': 0.045345524},
    {'sex': 'female', 'age': 82.5,  'l': -0.222403111, 'm': 120.6755427, 's': 0.045384203},
    {'sex': 'female', 'age': 83.5,  'l': -0.216770161, 'm': 121.22102, 's': 0.045422551},
    {'sex': 'female', 'age': 84.5,  'l': -0.210210748, 'm': 121.7616844, 's': 0.045460702},
    {'sex': 'female', 'age': 85.5,  'l': -0.202774891, 'm': 122.2973542, 's': 0.045498803},
    {'sex': 'female', 'age': 86.5,  'l': -0.194515104, 'm': 122.827864, 's': 0.045537012},
    {'sex': 'female', 'age': 87.5,  'l': -0.185486099, 'm': 123.3530652, 's': 0.045575495},
    {'sex': 'female', 'age': 88.5,  'l': -0.175744476, 'm': 123.8728276, 's': 0.045614432},
    {'sex': 'female', 'age': 89.5,  'l': -0.165348396, 'm': 124.38704, 's': 0.045654016},
    {'sex': 'female', 'age': 90.5,  'l': -0.15435722, 'm': 124.8956114, 's': 0.04569445},
    {'sex': 'female', 'age': 91.5,  'l': -0.142831123, 'm': 125.398472, 's': 0.045735953},
    {'sex': 'female', 'age': 92.5,  'l': -0.130830669, 'm': 125.895574, 's': 0.045778759},
    {'sex': 'female', 'age': 93.5,  'l': -0.118416354, 'm': 126.3868929, 's': 0.045823114},
    {'sex': 'female', 'age': 94.5,  'l': -0.105648092, 'm': 126.8724284, 's': 0.04586928},
    {'sex': 'female', 'age': 95.5,  'l': -0.092584657, 'm': 127.3522056, 's': 0.045917535},
    {'sex': 'female', 'age': 96.5,  'l': -0.079283065, 'm': 127.8262759, 's': 0.045968169},
    {'sex': 'female', 'age': 97.5,  'l': -0.065797888, 'm': 128.2947187, 's': 0.04602149},
    {'sex': 'female', 'age': 98.5,  'l': -0.0521805, 'm': 128.757642, 's': 0.046077818},
    {'sex': 'female', 'age': 99.5,  'l': -0.03847825, 'm': 129.2151839, 's': 0.046137487},
    {'sex': 'female', 'age': 100.5,  'l': -0.024733545, 'm': 129.6675143, 's': 0.046200842},
    {'sex': 'female', 'age': 101.5,  'l': -0.010982868, 'm': 130.1148354, 's': 0.04626824},
    {'sex': 'female', 'age': 102.5,  'l': 0.002744306, 'm': 130.5573839, 's': 0.046340046},
    {'sex': 'female', 'age': 103.5,  'l': 0.016426655, 'm': 130.995432, 's': 0.046416629},
    {'sex': 'female', 'age': 104.5,  'l': 0.030052231, 'm': 131.4292887, 's': 0.046498361},
    {'sex': 'female', 'age': 105.5,  'l': 0.043619747, 'm': 131.8593015, 's': 0.046585611},
    {'sex': 'female', 'age': 106.5,  'l': 0.05713988, 'm': 132.2858574, 's': 0.046678741},
    {'sex': 'female', 'age': 107.5,  'l': 0.070636605, 'm': 132.7093845, 's': 0.046778099},
    {'sex': 'female', 'age': 108.5,  'l': 0.08414848, 'm': 133.1303527, 's': 0.04688401},
    {'sex': 'female', 'age': 109.5,  'l': 0.097729873, 'm': 133.5492749, 's': 0.046996769},
    {'sex': 'female', 'age': 110.5,  'l': 0.111452039, 'm': 133.9667073, 's': 0.047116633},
    {'sex': 'female', 'age': 111.5,  'l': 0.125404005, 'm': 134.3832499, 's': 0.047243801},
    {'sex': 'female', 'age': 112.5,  'l': 0.13969316, 'm': 134.7995463, 's': 0.047378413},
    {'sex': 'female', 'age': 113.5,  'l': 0.154445482, 'm': 135.2162826, 's': 0.047520521},
    {'sex': 'female', 'age': 114.5,  'l': 0.169805275, 'm': 135.634186, 's': 0.047670085},
    {'sex': 'female', 'age': 115.5,  'l': 0.185934346, 'm': 136.0540223, 's': 0.047826946},
    {'sex': 'female', 'age': 116.5,  'l': 0.203010488, 'm': 136.4765925, 's': 0.04799081},
    {'sex': 'female', 'age': 117.5,  'l': 0.2212252, 'm': 136.9027281, 's': 0.048161228},
    {'sex': 'female', 'age': 118.5,  'l': 0.240780542, 'm': 137.3332846, 's': 0.04833757},
    {'sex': 'female', 'age': 119.5,  'l': 0.261885086, 'm': 137.7691339, 's': 0.048519011},
    {'sex': 'female', 'age': 120.5,  'l': 0.284748919, 'm': 138.2111552, 's': 0.048704503},
    {'sex': 'female', 'age': 121.5,  'l': 0.309577733, 'm': 138.6602228, 's': 0.048892759},
    {'sex': 'female', 'age': 122.5,  'l': 0.336566048, 'm': 139.1171933, 's': 0.049082239},
    {'sex': 'female', 'age': 123.5,  'l': 0.365889711, 'm': 139.5828898, 's': 0.049271137},
    {'sex': 'female', 'age': 124.5,  'l': 0.397699038, 'm': 140.0580848, 's': 0.049457371},
    {'sex': 'female', 'age': 125.5,  'l': 0.432104409, 'm': 140.5434787, 's': 0.049638596},
    {'sex': 'female', 'age': 126.5,  'l': 0.46917993, 'm': 141.0396832, 's': 0.049812203},
    {'sex': 'female', 'age': 127.5,  'l': 0.508943272, 'm': 141.5471945, 's': 0.049975355},
    {'sex': 'female', 'age': 128.5,  'l': 0.551354277, 'm': 142.0663731, 's': 0.050125012},
    {'sex': 'female', 'age': 129.5,  'l': 0.596307363, 'm': 142.59742, 's': 0.050257992},
    {'sex': 'female', 'age': 130.5,  'l': 0.643626542, 'm': 143.1403553, 's': 0.050371024},
    {'sex': 'female', 'age': 131.5,  'l': 0.693062173, 'm': 143.6949981, 's': 0.050460835},
    {'sex': 'female', 'age': 132.5,  'l': 0.744289752, 'm': 144.2609497, 's': 0.050524236},
    {'sex': 'female', 'age': 133.5,  'l': 0.79691098, 'm': 144.8375809, 's': 0.050558224},
    {'sex': 'female', 'age': 134.5,  'l': 0.85045728, 'm': 145.4240246, 's': 0.050560083},
    {'sex': 'female', 'age': 135.5,  'l': 0.904395871, 'm': 146.0191748, 's': 0.050527494},
    {'sex': 'female', 'age': 136.5,  'l': 0.958138449, 'm': 146.621692, 's': 0.050458634},
    {'sex': 'female', 'age': 137.5,  'l': 1.011054559, 'm': 147.2300177, 's': 0.050352269},
    {'sex': 'female', 'age': 138.5,  'l': 1.062474568, 'm': 147.8423918, 's': 0.050207825},
    {'sex': 'female', 'age': 139.5,  'l': 1.111727029, 'm': 148.4568879, 's': 0.050025434},
    {'sex': 'female', 'age': 140.5,  'l': 1.158135105, 'm': 149.0714413, 's': 0.049805967},
    {'sex': 'female', 'age': 141.5,  'l': 1.201050821, 'm': 149.6838943, 's': 0.049551023},
    {'sex': 'female', 'age': 142.5,  'l': 1.239852328, 'm': 150.2920328, 's': 0.049262895},
    {'sex': 'female', 'age': 143.5,  'l': 1.274006058, 'm': 150.8936469, 's': 0.048944504},
    {'sex': 'female', 'age': 144.5,  'l': 1.303044695, 'm': 151.4865636, 's': 0.048599314},
    {'sex': 'female', 'age': 145.5,  'l': 1.326605954, 'm': 152.0686985, 's': 0.048231224},
    {'sex': 'female', 'age': 146.5,  'l': 1.344443447, 'm': 152.6380955, 's': 0.047844442},
    {'sex': 'female', 'age': 147.5,  'l': 1.356437773, 'm': 153.1929631, 's': 0.047443362},
    {'sex': 'female', 'age': 148.5,  'l': 1.362602695, 'm': 153.7317031, 's': 0.04703243},
    {'sex': 'female', 'age': 149.5,  'l': 1.363085725, 'm': 154.2529332, 's': 0.046616026},
    {'sex': 'female', 'age': 150.5,  'l': 1.358162799, 'm': 154.755501, 's': 0.046198356},
    {'sex': 'female', 'age': 151.5,  'l': 1.348227142, 'm': 155.2384904, 's': 0.04578335},
    {'sex': 'female', 'age': 152.5,  'l': 1.333772923, 'm': 155.7012216, 's': 0.045374597},
    {'sex': 'female', 'age': 153.5,  'l': 1.315374704, 'm': 156.1432438, 's': 0.044975281},
    {'sex': 'female', 'age': 154.5,  'l': 1.293664024, 'm': 156.564323, 's': 0.044588148},
    {'sex': 'female', 'age': 155.5,  'l': 1.269304678, 'm': 156.9644258, 's': 0.044215488},
    {'sex': 'female', 'age': 156.5,  'l': 1.242968236, 'm': 157.3436995, 's': 0.043859135},
    {'sex': 'female', 'age': 157.5,  'l': 1.21531127, 'm': 157.7024507, 's': 0.04352048},
    {'sex': 'female', 'age': 158.5,  'l': 1.186955477, 'm': 158.0411233, 's': 0.043200497},
    {'sex': 'female', 'age': 159.5,  'l': 1.158471522, 'm': 158.3602756, 's': 0.042899776},
    {'sex': 'female', 'age': 160.5,  'l': 1.130367088, 'm': 158.6605588, 's': 0.042618565},
    {'sex': 'female', 'age': 161.5,  'l': 1.103079209, 'm': 158.9426964, 's': 0.042356812},
    {'sex': 'female', 'age': 162.5,  'l': 1.076970655, 'm': 159.2074654, 's': 0.042114211},
    {'sex': 'female', 'age': 163.5,  'l': 1.052329922, 'm': 159.455679, 's': 0.041890247},
    {'sex': 'female', 'age': 164.5,  'l': 1.029374161, 'm': 159.688172, 's': 0.04168424},
    {'sex': 'female', 'age': 165.5,  'l': 1.008254396, 'm': 159.9057871, 's': 0.041495379},
    {'sex': 'female', 'age': 166.5,  'l': 0.989062282, 'm': 160.1093647, 's': 0.041322765},
    {'sex': 'female', 'age': 167.5,  'l': 0.971837799, 'm': 160.299733, 's': 0.041165437},
    {'sex': 'female', 'age': 168.5,  'l': 0.95657215, 'm': 160.4776996, 's': 0.041022401},
    {'sex': 'female', 'age': 169.5,  'l': 0.94324228, 'm': 160.6440526, 's': 0.040892651},
    {'sex': 'female', 'age': 170.5,  'l': 0.931767062, 'm': 160.7995428, 's': 0.040775193},
    {'sex': 'female', 'age': 171.5,  'l': 0.922058291, 'm': 160.9448916, 's': 0.040669052},
    {'sex': 'female', 'age': 172.5,  'l': 0.914012643, 'm': 161.0807857, 's': 0.040573288},
    {'sex': 'female', 'age': 173.5,  'l': 0.907516917, 'm': 161.2078755, 's': 0.040487005},
    {'sex': 'female', 'age': 174.5,  'l': 0.902452436, 'm': 161.3267744, 's': 0.040409354},
    {'sex': 'female', 'age': 175.5,  'l': 0.898698641, 'm': 161.4380593, 's': 0.040339537},
    {'sex': 'female', 'age': 176.5,  'l': 0.896143482, 'm': 161.5422726, 's': 0.040276811},
    {'sex': 'female', 'age': 177.5,  'l': 0.894659668, 'm': 161.639917, 's': 0.040220488},
    {'sex': 'female', 'age': 178.5,  'l': 0.89413892, 'm': 161.7314645, 's': 0.040169932},
    {'sex': 'female', 'age': 179.5,  'l': 0.894475371, 'm': 161.8173534, 's': 0.040124562},
    {'sex': 'female', 'age': 180.5,  'l': 0.895569834, 'm': 161.8979913, 's': 0.040083845},
    {'sex': 'female', 'age': 181.5,  'l': 0.897330209, 'm': 161.9737558, 's': 0.040047295},
    {'sex': 'female', 'age': 182.5,  'l': 0.899671635, 'm': 162.0449969, 's': 0.040014473},
    {'sex': 'female', 'age': 183.5,  'l': 0.902516442, 'm': 162.1120386, 's': 0.03998498},
    {'sex': 'female', 'age': 184.5,  'l': 0.905793969, 'm': 162.17518, 's': 0.039958458},
    {'sex': 'female', 'age': 185.5,  'l': 0.909440266, 'm': 162.2346979, 's': 0.039934584},
    {'sex': 'female', 'age': 186.5,  'l': 0.913397733, 'm': 162.2908474, 's': 0.039913066},
    {'sex': 'female', 'age': 187.5,  'l': 0.91761471, 'm': 162.343864, 's': 0.039893644},
    {'sex': 'female', 'age': 188.5,  'l': 0.922045055, 'm': 162.3939652, 's': 0.039876087},
    {'sex': 'female', 'age': 189.5,  'l': 0.926647697, 'm': 162.4413513, 's': 0.039860185},
    {'sex': 'female', 'age': 190.5,  'l': 0.931386217, 'm': 162.4862071, 's': 0.039845754},
    {'sex': 'female', 'age': 191.5,  'l': 0.93622842, 'm': 162.5287029, 's': 0.039832629},
    {'sex': 'female', 'age': 192.5,  'l': 0.941145943, 'm': 162.5689958, 's': 0.039820663},
    {'sex': 'female', 'age': 193.5,  'l': 0.94611388, 'm': 162.6072309, 's': 0.039809725},
    {'sex': 'female', 'age': 194.5,  'l': 0.95111043, 'm': 162.6435418, 's': 0.0397997},
    {'sex': 'female', 'age': 195.5,  'l': 0.956116576, 'm': 162.6780519, 's': 0.039790485},
    {'sex': 'female', 'age': 196.5,  'l': 0.961115792, 'm': 162.7108751, 's': 0.039781991},
    {'sex': 'female', 'age': 197.5,  'l': 0.966093766, 'm': 162.7421168, 's': 0.039774136},
    {'sex': 'female', 'age': 198.5,  'l': 0.971038162, 'm': 162.7718741, 's': 0.03976685},
    {'sex': 'female', 'age': 199.5,  'l': 0.975938391, 'm': 162.8002371, 's': 0.03976007},
    {'sex': 'female', 'age': 200.5,  'l': 0.980785418, 'm': 162.8272889, 's': 0.039753741},
    {'sex': 'female', 'age': 201.5,  'l': 0.985571579, 'm': 162.8531067, 's': 0.039747815},
    {'sex': 'female', 'age': 202.5,  'l': 0.99029042, 'm': 162.8777619, 's': 0.039742249},
    {'sex': 'female', 'age': 203.5,  'l': 0.994936555, 'm': 162.9013208, 's': 0.039737004},
    {'sex': 'female', 'age': 204.5,  'l': 0.999505539, 'm': 162.9238449, 's': 0.039732048},
    {'sex': 'female', 'age': 205.5,  'l': 1.003993753, 'm': 162.9453912, 's': 0.039727352},
    {'sex': 'female', 'age': 206.5,  'l': 1.0083983, 'm': 162.9660131, 's': 0.03972289},
    {'sex': 'female', 'age': 207.5,  'l': 1.012716921, 'm': 162.9857599, 's': 0.03971864},
    {'sex': 'female', 'age': 208.5,  'l': 1.016947912, 'm': 163.0046776, 's': 0.039714581},
    {'sex': 'female', 'age': 209.5,  'l': 1.021090055, 'm': 163.0228094, 's': 0.039710697},
    {'sex': 'female', 'age': 210.5,  'l': 1.025142554, 'm': 163.0401953, 's': 0.039706971},
    {'sex': 'female', 'age': 211.5,  'l': 1.029104983, 'm': 163.0568727, 's': 0.039703391},
    {'sex': 'female', 'age': 212.5,  'l': 1.032977233, 'm': 163.0728768, 's': 0.039699945},
    {'sex': 'female', 'age': 213.5,  'l': 1.036759475, 'm': 163.0882404, 's': 0.039696623},
    {'sex': 'female', 'age': 214.5,  'l': 1.040452117, 'm': 163.1029943, 's': 0.039693415},
    {'sex': 'female', 'age': 215.5,  'l': 1.044055774, 'm': 163.1171673, 's': 0.039690313},
    {'sex': 'female', 'age': 216.5,  'l': 1.047571238, 'm': 163.1307866, 's': 0.039687311},
    {'sex': 'female', 'age': 217.5,  'l': 1.050999451, 'm': 163.1438776, 's': 0.039684402},
    {'sex': 'female', 'age': 218.5,  'l': 1.054341482, 'm': 163.1564644, 's': 0.039681581},
    {'sex': 'female', 'age': 219.5,  'l': 1.057598512, 'm': 163.1685697, 's': 0.039678842},
    {'sex': 'female', 'age': 220.5,  'l': 1.060771808, 'm': 163.1802146, 's': 0.039676182},
    {'sex': 'female', 'age': 221.5,  'l': 1.063862715, 'm': 163.1914194, 's': 0.039673596},
    {'sex': 'female', 'age': 222.5,  'l': 1.066872639, 'm': 163.202203, 's': 0.039671082},
    {'sex': 'female', 'age': 223.5,  'l': 1.069803036, 'm': 163.2125835, 's': 0.039668635},
    {'sex': 'female', 'age': 224.5,  'l': 1.072655401, 'm': 163.2225779, 's': 0.039666254},
    {'sex': 'female', 'age': 225.5,  'l': 1.075431258, 'm': 163.2322024, 's': 0.039663936},
    {'sex': 'female', 'age': 226.5,  'l': 1.078132156, 'm': 163.2414722, 's': 0.039661679},
    {'sex': 'female', 'age': 227.5,  'l': 1.080759655, 'm': 163.2504019, 's': 0.039659481},
    {'sex': 'female', 'age': 228.5,  'l': 1.083315329, 'm': 163.2590052, 's': 0.039657339},
    {'sex': 'female', 'age': 229.5,  'l': 1.085800751, 'm': 163.2672954, 's': 0.039655252},
    {'sex': 'female', 'age': 230.5,  'l': 1.088217496, 'm': 163.2752848, 's': 0.039653218},
    {'sex': 'female', 'age': 231.5,  'l': 1.090567133, 'm': 163.2829854, 's': 0.039651237},
    {'sex': 'female', 'age': 232.5,  'l': 1.092851222, 'm': 163.2904086, 's': 0.039649306},
    {'sex': 'female', 'age': 233.5,  'l': 1.095071313, 'm': 163.297565, 's': 0.039647424},
    {'sex': 'female', 'age': 234.5,  'l': 1.097228939, 'm': 163.304465, 's': 0.039645591},
    {'sex': 'female', 'age': 235.5,  'l': 1.099325619, 'm': 163.3111185, 's': 0.039643804},
    {'sex': 'female', 'age': 236.5,  'l': 1.101362852, 'm': 163.3175349, 's': 0.039642063},
    {'sex': 'female', 'age': 237.5,  'l': 1.103342119, 'm': 163.3237231, 's': 0.039640367},
    {'sex': 'female', 'age': 238.5,  'l': 1.105264876, 'm': 163.3296918, 's': 0.039638715},
    {'sex': 'female', 'age': 239.5,  'l': 1.107132561, 'm': 163.3354491, 's': 0.039637105},
    {'sex': 'female', 'age': 240,  'l': 1.108046193, 'm': 163.338251, 's': 0.039636316}
    ]
}

@mcp.tool()
def bmi_calculator(weight: float, height: float) -> float:
    """
    Calculates Body Mass Index (BMI) and Body Surface Area (BSA)
    
    Parameters:
    -----------
    weight : float
        Weight in kilograms
    height : float
        Height in centimeters (default) or meters
    height_unit : str
        Unit of height measurement ('cm' or 'm', default is 'cm')
    
    Returns:
    --------
    bmi: float
        Body Mass Index (kg/m²)
    """
    # Normalize height to meters for calculations
    try:
        height_unit = "cm"
        if height_unit.lower() == "cm":
            height_m = height / 100
        elif height_unit.lower() == "m":
            height_m = height
        else:
            raise ValueError("Height unit must be 'cm' or 'm'")
        
        # Calculate BMI: weight(kg) / height(m)²
        bmi = weight / (height_m * height_m)
        
        # Calculate BSA using Mosteller formula: √(height(cm) × weight(kg) / 3600)
        height_cm = height_m * 100
        bsa = math.sqrt((height_cm * weight) / 3600)
        
        # Determine BMI classification
        bmi_classification = ""
        if bmi < 18.5:
            bmi_classification = "Underweight"
        elif bmi < 25:
            bmi_classification = "Normal weight"
        elif bmi < 30:
            bmi_classification = "Overweight"
        elif bmi < 35:
            bmi_classification = "Obesity class I"
        elif bmi < 40:
            bmi_classification = "Obesity class II"
        else:
            bmi_classification = "Obesity class III"
        
        # Return results
        return bmi
    except Exception as e:
        return {
            "error": str(e)
        }

@mcp.tool()
def bsa_calculator(weight: float, height: float) -> float:
    """
    Calculates Body Mass Index (BMI) and Body Surface Area (BSA)
    
    Parameters:
    -----------
    weight : float
        Weight in kilograms
    height : float
        Height in centimeters (default) or meters
    height_unit : str
        Unit of height measurement ('cm' or 'm', default is 'cm')
    
    Returns:
    --------
    bmi: float
        Body Mass Index (kg/m²)
    """
    # Normalize height to meters for calculations
    try:
        height_unit = "cm"
        if height_unit.lower() == "cm":
            height_m = height / 100
        elif height_unit.lower() == "m":
            height_m = height
        else:
            raise ValueError("Height unit must be 'cm' or 'm'")
        
        # Calculate BMI: weight(kg) / height(m)²
        bmi = weight / (height_m * height_m)
        
        # Calculate BSA using Mosteller formula: √(height(cm) × weight(kg) / 3600)
        height_cm = height_m * 100
        bsa = math.sqrt((height_cm * weight) / 3600)
        
        # Determine BMI classification
        bmi_classification = ""
        if bmi < 18.5:
            bmi_classification = "Underweight"
        elif bmi < 25:
            bmi_classification = "Normal weight"
        elif bmi < 30:
            bmi_classification = "Overweight"
        elif bmi < 35:
            bmi_classification = "Obesity class I"
        elif bmi < 40:
            bmi_classification = "Obesity class II"
        else:
            bmi_classification = "Obesity class III"
        
        # Return results
        return bsa
    except Exception as e:
        return {
            "error": str(e)
        }


@mcp.tool()
def crcl_cockcroft_gault(age: int, weight: float, height: float, scr: float, sex: str) -> float:
    """
    Calculate Creatinine Clearance using the Cockcroft-Gault formula
    
    Parameters:
    -----------
    age : int
        Age in years
    weight : float
        Actual body weight in kg
    height : float
        Height in inches
    scr : float
        Serum creatinine in mg/dL
    sex : str
        Gender ('male' or 'female')
    
    Returns:
    --------
    crcl : float
        Creatinine clearance in mL/min
    """
    try:

    # Normalize sex input
        if isinstance(sex, str):
            sex = sex.lower()
        
        if sex not in ['male', 'female']:
            raise ValueError("Sex must be 'male' or 'female'")
        
        # Calculate Ideal Body Weight (IBW) using Devine equation
        if sex == 'male':
            ibw = 50 + (2.3 * (height - 60))
        else:
            ibw = 45.5 + (2.3 * (height - 60))
        
        # Calculate Adjusted Body Weight (ABW)
        abw = ibw + 0.4 * (weight - ibw)
        
        # Calculate BMI (convert height from inches to meters first)
        height_m = height * 0.0254  # Convert inches to meters
        bmi = weight / (height_m * height_m)
        
        # Determine which weight to use for CrCl calculation based on BMI category
        if bmi < 18.5:  # Underweight
            calc_weight = weight  # Use actual/total body weight
            weight_used = "Actual (Underweight BMI)"
            range_weight = weight
        elif bmi < 25:  # Normal weight
            calc_weight = min(ibw,weight)  # Use minimum of actual weiideal body weight for calculation
            weight_used = "IBW (Normal BMI)"
            range_weight = weight  # Use actual body weight for range
        else:  # Overweight/obese
            calc_weight = abw  # Use adjusted body weight for calculation
            weight_used = "ABW (Overweight/Obese BMI)"
            range_weight = ibw  # Use ideal body weight for range
        
        # Calculate Creatinine Clearance using Cockcroft-Gault formula
        crcl = (140 - age) * calc_weight
        if sex == 'female':
            crcl *= 0.85  # Apply correction factor for females
        crcl /= (72 * scr)
        
        # Return results
        return crcl
    except Exception as e:
        return {
            "error": str(e)
        }
@mcp.tool()
def map_calculator(sbp: int, dbp: int) -> float:
    """
    Calculate Mean Arterial Pressure (MAP)
    
    Parameters:
    -----------
    sbp : int
        Systolic Blood Pressure in mmHg
    dbp : int
        Diastolic Blood Pressure in mmHg
    
    Returns:
    --------
    MAP : float
        Mean Arterial Pressure (MAP) in mmHg
        Dictionary containing MAP result and input values
    """
    try:
        # Calculate Mean Arterial Pressure
        map_value = (1/3) * sbp + (2/3) * dbp
        
        # Return results
        return map_value
    except Exception as e:
        return {
            "error": str(e)
        }

@mcp.tool()
def chads2_vasc_score(age: int, female: bool, chf: bool, hypertension: bool, 
                      stroke_history: bool, vascular_disease: bool, diabetes: bool) -> int:
    """
    Calculate CHA₂DS₂-VASc Score for Atrial Fibrillation Stroke Risk
    
    Parameters:
    -----------
    age : int
        Age in years
    female : bool
        True if patient is female, False if male
    chf : bool
        True if patient has history of congestive heart failure
    hypertension : bool
        True if patient has history of hypertension
    stroke_history : bool
        True if patient has history of stroke, TIA, or thromboembolism
    vascular_disease : bool
        True if patient has history of vascular disease (prior MI, peripheral artery disease, or aortic plaque)
    diabetes : bool
        True if patient has history of diabetes mellitus
    
    Returns:
    --------
    score: int
        CHA₂DS₂-VASc score
    """
    try:
        # Initialize score
        score = 0
        
        # Calculate points for each risk factor
        
        # Age points
        age_points = 0
        if age >= 75:
            age_points = 2
        elif age >= 65:
            age_points = 1
        score += age_points
        
        # Sex points
        sex_points = 1 if female else 0
        score += sex_points
        
        # Congestive heart failure
        chf_points = 1 if chf else 0
        score += chf_points
        
        # Hypertension
        htn_points = 1 if hypertension else 0
        score += htn_points
        
        # Stroke/TIA/thromboembolism history
        stroke_points = 2 if stroke_history else 0
        score += stroke_points
        
        # Vascular disease
        vascular_points = 1 if vascular_disease else 0
        score += vascular_points
        
        # Diabetes
        diabetes_points = 1 if diabetes else 0
        score += diabetes_points
        
        # Determine stroke risk category based on score
        risk_category = ""
        annual_risk = ""
        
        if score == 0:
            risk_category = "Low"
            annual_risk = "0.2%"
        elif score == 1:
            risk_category = "Low-Moderate"
            annual_risk = "0.6%"
        elif score == 2:
            risk_category = "Moderate"
            annual_risk = "2.2%"
        elif score == 3:
            risk_category = "Moderate-High"
            annual_risk = "3.2%"
        elif score == 4:
            risk_category = "High"
            annual_risk = "4.8%"
        elif score == 5:
            risk_category = "High"
            annual_risk = "7.2%"
        elif score == 6:
            risk_category = "High"
            annual_risk = "9.7%"
        elif score == 7:
            risk_category = "High"
            annual_risk = "11.2%"
        elif score == 8:
            risk_category = "High"
            annual_risk = "10.8%"
        else:  # score >= 9
            risk_category = "High"
            annual_risk = "12.2%"
        
        # Return results
        return score
    except Exception as e:
        return {
            "error": str(e)
        }

@mcp.tool()
def prevent_cvd_risk(age: int, female: bool, tc: float, hdl: float, sbp: int, 
                     diabetes: bool, current_smoker: bool, egfr: float,
                     using_antihtn: bool, using_statins: bool) -> float:
    """
    Predicting Risk of Cardiovascular Disease EVENTs (PREVENT)
    Predicts 10-year risk of CVD in patients aged 30-79 without known CVD.
    
    Parameters:
    -----------
    age : int
        Age in years (30-79)
    female : bool
        True if patient is female, False if male
    tc : float
        Total cholesterol in mmol/L
    hdl : float
        HDL cholesterol in mmol/L
    sbp : int
        Systolic blood pressure in mmHg
    diabetes : bool
        True if patient has diabetes
    current_smoker : bool
        True if patient is a current smoker
    egfr : float
        Estimated glomerular filtration rate in mL/min/1.73m²
    using_antihtn : bool
        True if patient is using antihypertensive drugs
    using_statins : bool
        True if patient is using statins
    
    Returns:
    --------
    float
        10-year CVD risk as a percentage
    """
    try:
        # Input validation
        if age < 30 or age > 79:
            raise ValueError("Age must be between 30 and 79 years")
        
        # Variable transformations
        cage = (age - 55) / 10
        cnhdl = tc - hdl - 3.5
        chdl = (hdl - 1.3) / 0.3
        csbp = (min(sbp, 110) - 110) / 20
        csbp2 = (max(sbp, 110) - 130) / 20
        cegfr = (min(egfr, 60) - 60) / -15
        cegfr2 = (max(egfr, 60) - 90) / -15
        
        # Convert boolean inputs to 0/1
        diabetes_val = 1 if diabetes else 0
        smoker_val = 1 if current_smoker else 0
        antihtn_val = 1 if using_antihtn else 0
        statin_val = 1 if using_statins else 0
        
        # Calculate interaction terms
        sbp_antihtn = csbp2 * antihtn_val
        chol_statin = cnhdl * statin_val
        age_chol1 = cage * cnhdl
        age_chol2 = cage * chdl
        age_sbp = cage * csbp2
        age_diabetes = cage * diabetes_val
        age_smoking = cage * smoker_val
        age_egfr = cage * cegfr
        
        # Select coefficients based on sex
        if female:
            # Female coefficients
            coef_age = 0.7939
            coef_cnhdl = 0.0305
            coef_chdl = -0.1607
            coef_csbp = -0.2394
            coef_csbp2 = 0.36
            coef_diabetes = 0.8668
            coef_smoker = 0.5361
            coef_cegfr = 0.6046
            coef_cegfr2 = 0.0434
            coef_antihtn = 0.3152
            coef_statin = -0.1478
            coef_sbp_antihtn = -0.0664
            coef_chol_statin = 0.1198
            coef_age_chol1 = -0.082
            coef_age_chol2 = 0.0307
            coef_age_sbp = -0.0946
            coef_age_diabetes = -0.2706
            coef_age_smoking = -0.0787
            coef_age_egfr = -0.1638
            constant = -3.3077
        else:
            # Male coefficients
            coef_age = 0.7689
            coef_cnhdl = 0.0736
            coef_chdl = -0.0954
            coef_csbp = -0.4347
            coef_csbp2 = 0.3363
            coef_diabetes = 0.7693
            coef_smoker = 0.4387
            coef_cegfr = 0.5379
            coef_cegfr2 = 0.0165
            coef_antihtn = 0.2889
            coef_statin = -0.1337
            coef_sbp_antihtn = -0.0476
            coef_chol_statin = 0.1503
            coef_age_chol1 = -0.0518
            coef_age_chol2 = 0.0191
            coef_age_sbp = -0.1049
            coef_age_diabetes = -0.2252
            coef_age_smoking = -0.0895
            coef_age_egfr = -0.1543
            constant = -3.0312
        
        # Calculate the sum of beta * transformed variables
        x = constant
        x += coef_age * cage
        x += coef_cnhdl * cnhdl
        x += coef_chdl * chdl
        x += coef_csbp * csbp
        x += coef_csbp2 * csbp2
        x += coef_diabetes * diabetes_val
        x += coef_smoker * smoker_val
        x += coef_cegfr * cegfr
        x += coef_cegfr2 * cegfr2
        x += coef_antihtn * antihtn_val
        x += coef_statin * statin_val
        x += coef_sbp_antihtn * sbp_antihtn
        x += coef_chol_statin * chol_statin
        x += coef_age_chol1 * age_chol1
        x += coef_age_chol2 * age_chol2
        x += coef_age_sbp * age_sbp
        x += coef_age_diabetes * age_diabetes
        x += coef_age_smoking * age_smoking
        x += coef_age_egfr * age_egfr
        
        # Calculate 10-year risk
        risk_10yr = math.exp(x) / (1 + math.exp(x)) * 100
        
        # Return results
        return risk_10yr
    except Exception as e:
        return {
            "error": str(e)
        }
def get_cvd_risk_category(risk):
    """Helper function to categorize CVD risk"""
    if risk < 5:
        return "Low"
    elif risk < 7.5:
        return "Borderline"
    elif risk < 20:
        return "Intermediate"
    else:
        return "High"


@mcp.tool()
def corrected_calcium(serum_calcium: float, patient_albumin: float, normal_albumin: float = 4.0) -> float:
    """
    Calcium Correction for Hypoalbuminemia and Hyperalbuminemia
    Calculates a corrected calcium level for patients with abnormal albumin levels.
    
    Parameters:
    -----------
    serum_calcium : float
        Patient's measured serum calcium level in mg/dL
    patient_albumin : float
        Patient's serum albumin level in g/dL
    normal_albumin : float, optional
        Normal/reference albumin level in g/dL, default is 4.0 g/dL
    
    Returns:
    --------
    float
        Corrected calcium level in mg/dL
        
    Formula:
    --------
    Corrected Calcium = (0.8 * (Normal Albumin - Patient's Albumin)) + Serum Calcium
    
    References:
    -----------
    Payne RB, et al. Br Med J. 1973;4(5893):643-646.
    """

    # Input validation
    # if serum_calcium <= 0:
    #     raise ValueError("Serum calcium must be a positive number")
    # if patient_albumin < 0:
    #     raise ValueError("Patient albumin cannot be negative")
    # if normal_albumin <= 0:
    #     raise ValueError("Normal albumin must be a positive number")
    
    # Calculate corrected calcium
    try:

        corrected_ca = (0.8 * (normal_albumin - patient_albumin)) + serum_calcium
        
        # Determine calcium status
        if corrected_ca < 8.5:
            interpretation = "Hypocalcemia"
        elif corrected_ca > 10.5:
            interpretation = "Hypercalcemia"
        else:
            interpretation = "Normocalcemia"
        
        # Determine albumin status
        if patient_albumin < normal_albumin - 0.5:
            albumin_status = "Hypoalbuminemia"
        elif patient_albumin > normal_albumin + 0.5:
            albumin_status = "Hyperalbuminemia"
        else:
            albumin_status = "Normal albumin"
        
        # Return results
        return corrected_ca
            
    except Exception as e:
        return {
            "error": str(e)
        }

@mcp.tool()
def qtc_calculator(qt_interval: float, heart_rate: float, formula: str = "bazett") -> float:
    """
    Corrected QT Interval (QTc) Calculator
    Corrects the QT interval for heart rate extremes using various formulas.
    
    Parameters:
    -----------
    qt_interval : float
        Measured QT interval in milliseconds (ms)
    heart_rate : float
        Heart rate in beats per minute (bpm)
    formula : str, optional
        Formula to use for correction (default: "bazett")
        Options: "bazett", "fridericia", "framingham", "hodges", "rautaharju"
    
    Returns:
    --------
    qtc : float
        Corrected QT interval in milliseconds (ms)
        
    Formulas:
    ---------
    RR interval = 60 / heart_rate (in seconds)
    Bazett: QTc = QT / √(RR)
    Fridericia: QTc = QT / (RR)^(1/3)
    Framingham: QTc = QT + 154 × (1 - RR)
    Hodges: QTc = QT + 1.75 × (heart_rate - 60)
    Rautaharju: QTc = QT × (120 + heart_rate) / 180
    
    References:
    -----------
    Bazett HC. Heart. 1920;7:353-370
    Fridericia LS. Acta Med Scand. 1920;53:469-486
    Sagie A, et al. Am J Cardiol. 1992;70(7):797-801 (Framingham)
    Hodges M, et al. J Electrocardiol. 1983;16(1):17-24
    Rautaharju PM, et al. J Am Coll Cardiol. 2004;44(3):594-600
    """
    try:
        # Calculate RR interval in seconds
        rr_interval = 60 / heart_rate
        
        # Initialize variables
        qtc = 0
        calculation_steps = ""
        
        # Calculate QTc based on selected formula
        formula = formula.lower()
        
        if formula == "bazett":
            qtc = qt_interval / (rr_interval ** 0.5)
            calculation_steps = f"QT / √(RR) = {qt_interval} / √({rr_interval:.3f}) = {qtc:.1f} ms"
        
        elif formula == "fridericia":
            qtc = qt_interval / (rr_interval ** (1/3))
            calculation_steps = f"QT / (RR)^(1/3) = {qt_interval} / ({rr_interval:.3f})^(1/3) = {qtc:.1f} ms"
        
        elif formula == "framingham":
            qtc = qt_interval + 154 * (1 - rr_interval)
            calculation_steps = f"QT + 154 × (1 - RR) = {qt_interval} + 154 × (1 - {rr_interval:.3f}) = {qtc:.1f} ms"
        
        elif formula == "hodges":
            qtc = qt_interval + 1.75 * (heart_rate - 60)
            calculation_steps = f"QT + 1.75 × (HR - 60) = {qt_interval} + 1.75 × ({heart_rate} - 60) = {qtc:.1f} ms"
        
        elif formula == "rautaharju":
            qtc = qt_interval * (120 + heart_rate) / 180
            calculation_steps = f"QT × (120 + HR) / 180 = {qt_interval} × (120 + {heart_rate}) / 180 = {qtc:.1f} ms"
        
        else:
            # Default to Bazett if formula not recognized
            qtc = qt_interval / (rr_interval ** 0.5)
            calculation_steps = f"QT / √(RR) = {qt_interval} / √({rr_interval:.3f}) = {qtc:.1f} ms (Bazett - default)"
        
        # Interpret QTc result
        if qtc < 350:
            interpretation = "Short QT interval"
            risk = "May indicate genetic channelopathies associated with risk of arrhythmias"
        elif qtc <= 450:
            interpretation = "Normal QTc interval"
            risk = "No increased risk"
        elif qtc <= 470 and formula == "bazett":
            interpretation = "Borderline QTc interval"
            risk = "Mild increased risk of arrhythmias"
        elif qtc <= 500:
            interpretation = "Prolonged QTc interval"
            risk = "Moderate increased risk of Torsades de Pointes and sudden cardiac death"
        else:
            interpretation = "Severely prolonged QTc interval"
            risk = "High risk of Torsades de Pointes and sudden cardiac death"
        
        # Return results
        return qtc
    except Exception as e:
        return {
            "error": str(e)
        }

@mcp.tool()
def wells_pe_criteria(
    clinical_signs_dvt: bool = False,
    alternative_diagnosis_less_likely: bool = False, 
    heart_rate_over_100: bool = False,
    immobilization_or_surgery: bool = False,
    previous_dvt_or_pe: bool = False,
    hemoptysis: bool = False,
    malignancy: bool = False
) -> float:
    """
    Wells' Criteria for Pulmonary Embolism
    Objectifies risk of pulmonary embolism based on clinical criteria.
    Reference: Wells PS, et al. Thromb Haemost. 2000;83(3):416-20.
    
    Parameters:
    -----------
    clinical_signs_dvt: bool
        Clinical signs and symptoms of DVT (leg swelling, pain with palpation)
    alternative_diagnosis_less_likely: bool
        Alternative diagnosis less likely than PE
    heart_rate_over_100: bool
        Heart rate > 100 beats per minute
    immobilization_or_surgery: bool
        Immobilization or surgery in the previous four weeks
    previous_dvt_or_pe: bool
        Previous DVT/PE
    hemoptysis: bool
        Hemoptysis
    malignancy: bool
        Malignancy (treatment ongoing, treated in last 6 months, or palliative)
    
    Returns:
    --------
    points: float
        Total points based on Wells' criteria

    """
    try:
        # Calculate points based on criteria
        points = 0
        
        if clinical_signs_dvt:
            points += 3.0
        if alternative_diagnosis_less_likely:
            points += 3.0
        if heart_rate_over_100:
            points += 1.5
        if immobilization_or_surgery:
            points += 1.5
        if previous_dvt_or_pe:
            points += 1.5
        if hemoptysis:
            points += 1.0
        if malignancy:
            points += 1.0
        
        # Determine risk category (Three-tier model)
        if points <= 1:
            three_tier_risk = "Low Risk"
        elif points <= 6:
            three_tier_risk = "Moderate Risk"
        else:
            three_tier_risk = "High Risk"
        
        # Determine risk category (Two-tier model)
        if points <= 4:
            two_tier_risk = "PE Unlikely (consider D-dimer testing)"
        else:
            two_tier_risk = "PE Likely (proceed to CTA)"
        
        # Return comprehensive results
        return points
    except Exception as e:
        return {
            "error": str(e)
        }

@mcp.tool()
def nihss_score(
    loc_alert: int = 0,  # 0=Alert, 1=Not alert but arousable, 2=Not alert requires repeated stimuli, 3=Unresponsive
    loc_questions: int = 0,  # 0–2 (2 = both incorrect)
    loc_commands: int = 0,  # 0–2 (2 = both incorrect)
    best_gaze: int = 0,  # 0–2
    visual_fields: int = 0,  # 0–3
    facial_palsy: int = 0,  # 0–3
    motor_arm_left: int = 0,  # 0–4
    motor_arm_right: int = 0,  # 0–4
    motor_leg_left: int = 0,  # 0–4
    motor_leg_right: int = 0,  # 0–4
    limb_ataxia: int = 0,  # 0–2
    sensory: int = 0,  # 0–2
    best_language: int = 0,  # 0–3
    dysarthria: int = 0,  # 0–2
    extinction_inattention: int = 0  # 0–2
) -> int:
    """
    NIH Stroke Scale (NIHSS)
    Quantifies stroke severity by assigning a score to various neurologic exam components.

    Parameters:
    -----------
    Each parameter corresponds to an NIHSS item. All values must be integers within valid scoring ranges.

    Returns:
    --------
    total_score: int
        Total NIHSS score (0-42)
    """
    try:
        total_score = (
            loc_alert +
            loc_questions +
            loc_commands +
            best_gaze +
            visual_fields +
            facial_palsy +
            motor_arm_left +
            motor_arm_right +
            motor_leg_left +
            motor_leg_right +
            limb_ataxia +
            sensory +
            best_language +
            dysarthria +
            extinction_inattention
        )

        if total_score == 0:
            severity = "No Stroke Symptoms"
        elif 1 <= total_score <= 4:
            severity = "Minor Stroke"
        elif 5 <= total_score <= 15:
            severity = "Moderate Stroke"
        elif 16 <= total_score <= 20:
            severity = "Moderate to Severe Stroke"
        else:
            severity = "Severe Stroke"

        return total_score
    except Exception as e:
        return {
            "error": str(e)
        }

@mcp.tool()
def ibw_calculator(weight_kg: float, height_cm: float, male: bool) -> float:
    """
    Ideal Body Weight and Adjusted Body Weight Calculator
    Calculates ideal body weight (Devine formula) and adjusted body weight.
    
    Parameters:
    -----------
    weight_kg : float
        Actual body weight in kilograms
    height_inches : float
        Height in inches
    male : bool
        True if patient is male, False if female
    
    Returns:
    --------
    ibw: float
        Ideal body weight in kilograms
        
    Formulas:
    ---------
    Ideal Body Weight (IBW) (Devine formula):
    - Men: IBW = 50 kg + 2.3 kg × (height in inches - 60)
    - Women: IBW = 45.5 kg + 2.3 kg × (height in inches - 60)
    
    Adjusted Body Weight (ABW):
    - ABW = IBW + 0.4 × (actual weight - IBW)
    
    References:
    -----------
    Devine BJ. Gentamicin therapy. Drug Intell Clin Pharm. 1974;8:650-655.
    Pai MP. Drug Dosing Based on Weight and Body Surface Area: Mathematical Assumptions and Limitations in Obese Adults. Pharmacotherapy. 2012;32(9):856-868.
    """
    # Calculate ideal body weight (IBW)
    try:
        ibw = 0
        ibw_notes = []

        height_inches = height_cm / 2.54  # Convert cm to inches
        
        if height_inches >= 60:
            # Standard Devine formula
            if male:
                ibw = 50 + 2.3 * (height_inches - 60)
            else:
                ibw = 45.5 + 2.3 * (height_inches - 60)
        else:
            # Modification for height under 60 inches
            # Using 2.3 kg (5 lbs) reduction per inch below 60 inches
            if male:
                ibw = 50 - 2.3 * (60 - height_inches)
                ibw_notes.append("Modified formula used for height < 60 inches")
            else:
                ibw = 45.5 - 2.3 * (60 - height_inches)
                ibw_notes.append("Modified formula used for height < 60 inches")
        
        # Ensure IBW is not negative
        if ibw <= 0:
            ibw = weight_kg * 0.5  # Fallback for extremely short heights
            ibw_notes.append("Standard formula not applicable. Approximation used.")
        
        # Calculate adjusted body weight (ABW) if patient is obese
        abw = ibw
        obesity_status = "Non-obese"
        
        if weight_kg > ibw * 1.2:  # Common threshold for obesity (>120% of IBW)
            abw = ibw + 0.4 * (weight_kg - ibw)
            obesity_status = "Obese (>120% of IBW)"
        
        # Calculate percentage of IBW
        percent_ibw = (weight_kg / ibw) * 100
        
        # Return results
        return ibw
    except Exception as e:
        return {
            "error": str(e)
        }

@mcp.tool()
def abw_calculator(weight_kg: float, height_cm: float, male: bool) -> float:
    """
    Ideal Body Weight and Adjusted Body Weight Calculator
    Calculates ideal body weight (Devine formula) and adjusted body weight.
    
    Parameters:
    -----------
    weight_kg : float
        Actual body weight in kilograms
    height_inches : float
        Height in inches
    male : bool
        True if patient is male, False if female
    
    Returns:
    --------
    abw: float
        Adjusted body weight in kilograms
        
    Formulas:
    ---------
    Ideal Body Weight (IBW) (Devine formula):
    - Men: IBW = 50 kg + 2.3 kg × (height in inches - 60)
    - Women: IBW = 45.5 kg + 2.3 kg × (height in inches - 60)
    
    Adjusted Body Weight (ABW):
    - ABW = IBW + 0.4 × (actual weight - IBW)
    
    References:
    -----------
    Devine BJ. Gentamicin therapy. Drug Intell Clin Pharm. 1974;8:650-655.
    Pai MP. Drug Dosing Based on Weight and Body Surface Area: Mathematical Assumptions and Limitations in Obese Adults. Pharmacotherapy. 2012;32(9):856-868.
    """
    # Calculate ideal body weight (IBW)
    try:
        ibw = 0
        ibw_notes = []

        height_inches = height_cm / 2.54  # Convert cm to inches
        
        if height_inches >= 60:
            # Standard Devine formula
            if male:
                ibw = 50 + 2.3 * (height_inches - 60)
            else:
                ibw = 45.5 + 2.3 * (height_inches - 60)
        else:
            # Modification for height under 60 inches
            # Using 2.3 kg (5 lbs) reduction per inch below 60 inches
            if male:
                ibw = 50 - 2.3 * (60 - height_inches)
                ibw_notes.append("Modified formula used for height < 60 inches")
            else:
                ibw = 45.5 - 2.3 * (60 - height_inches)
                ibw_notes.append("Modified formula used for height < 60 inches")
        
        # Ensure IBW is not negative
        if ibw <= 0:
            ibw = weight_kg * 0.5  # Fallback for extremely short heights
            ibw_notes.append("Standard formula not applicable. Approximation used.")
        
        # Calculate adjusted body weight (ABW) if patient is obese
        abw = ibw
        obesity_status = "Non-obese"
        
        if weight_kg > ibw * 1.2:  # Common threshold for obesity (>120% of IBW)
            abw = ibw + 0.4 * (weight_kg - ibw)
            obesity_status = "Obese (>120% of IBW)"
        
        # Calculate percentage of IBW
        percent_ibw = (weight_kg / ibw) * 100
        
        # Return results
        return abw
    except Exception as e:
        return {
            "error": str(e)
        }


@mcp.tool()
def pregnancy_calculator(
    calculation_method: str,
    date_value: str,
    cycle_length: int = 28,
    gestational_age_weeks: int = None,
    gestational_age_days: int = None
) -> dict:
    """
    Pregnancy Due Dates Calculator
    Calculates pregnancy dates from last period, gestational age, or date of conception.
    
    Parameters:
    -----------
    calculation_method : str
        Method used for calculation: "lmp" (last menstrual period), "conception", or "ultrasound"
    date_value : str
        Date in format 'YYYY-MM-DD' (date of LMP, conception, or ultrasound)
    cycle_length : int, optional
        Length of menstrual cycle in days (default: 28)
    gestational_age_weeks : int, optional
        Weeks of gestational age at ultrasound (required if calculation_method is "ultrasound")
    gestational_age_days : int, optional
        Days of gestational age at ultrasound (required if calculation_method is "ultrasound")
    
    Returns:
    --------
    dict
        Dictionary containing calculated pregnancy dates and information
        
    Formulas:
    ---------
    - EGA (Estimated Gestational Age) = time since 1st day of LMP
    - EDC (Estimated Date of Conception) = LMP + 2 weeks (adjusted for cycle length)
    - EDD (Estimated Due Date) = LMP + 40 weeks (adjusted for cycle length)
    
    For non-28 day cycles:
    - Adjustment = (cycle_length - 28) days
    - EDD = LMP + 40 weeks + Adjustment
    """
    try:
        from datetime import datetime, timedelta
        
        # Parse input date
        input_date = datetime.strptime(date_value, '%Y-%m-%d')
        today = datetime.now()
        
        # Initialize variables
        lmp_date = None
        conception_date = None
        due_date = None
        
        # Calculate dates based on method
        if calculation_method.lower() == "lmp":
            # Last menstrual period provided
            lmp_date = input_date
            
            # Calculate conception date (LMP + ~2 weeks, adjusted for cycle length)
            cycle_adjustment = (cycle_length - 28) if cycle_length > 28 else 0
            conception_offset = 14 + cycle_adjustment
            conception_date = lmp_date + timedelta(days=conception_offset)
            
            # Calculate due date (LMP + 40 weeks, adjusted for cycle length)
            due_date = lmp_date + timedelta(days=280 + cycle_adjustment)
            
        elif calculation_method.lower() == "conception":
            # Conception date provided
            conception_date = input_date
            
            # Calculate LMP date (conception - ~2 weeks)
            cycle_adjustment = (cycle_length - 28) if cycle_length > 28 else 0
            lmp_date = conception_date - timedelta(days=14 + cycle_adjustment)
            
            # Calculate due date (conception + 38 weeks)
            due_date = conception_date + timedelta(days=266)
            
        elif calculation_method.lower() == "ultrasound":
            # Ultrasound date provided with gestational age
            if gestational_age_weeks is None or gestational_age_days is None:
                return {"error": "Gestational age weeks and days are required for ultrasound method"}
            
            # Calculate LMP date from gestational age at ultrasound
            ga_days_total = (gestational_age_weeks * 7) + gestational_age_days
            lmp_date = input_date - timedelta(days=ga_days_total)
            
            # Calculate conception date (LMP + ~2 weeks)
            cycle_adjustment = (cycle_length - 28) if cycle_length > 28 else 0
            conception_date = lmp_date + timedelta(days=14 + cycle_adjustment)
            
            # Calculate due date (LMP + 40 weeks, adjusted for cycle length)
            due_date = lmp_date + timedelta(days=280 + cycle_adjustment)
        
        # Calculate current gestational age
        if lmp_date:
            days_since_lmp = (today - lmp_date).days
            current_ga_weeks = days_since_lmp // 7
            current_ga_days = days_since_lmp % 7
        else:
            current_ga_weeks = None
            current_ga_days = None
        
        # Format dates for output
        format_date = lambda d: d.strftime('%Y-%m-%d') if d else None
        
        return {
            "lmp_date": format_date(lmp_date),
            "conception_date": format_date(conception_date),
            "due_date": format_date(due_date),
            "current_gestational_age": f"{current_ga_weeks}w{current_ga_days}d" if current_ga_weeks is not None else None,
            "current_trimester": get_trimester(current_ga_weeks) if current_ga_weeks is not None else None,
            "cycle_length_used": cycle_length,
            "calculation_method": calculation_method
        }
    except Exception as e:
        return {"error": str(e)}
    
def get_trimester(weeks):
    """Helper function to determine trimester based on gestational age in weeks"""
    if weeks < 13:
        return "First trimester"
    elif weeks < 27:
        return "Second trimester"
    else:
        return "Third trimester"

@mcp.tool()
def heart_score(history: int, ekg: int, age: int, risk_factors: int, troponin: int) -> int:
    """
    HEART Score for Major Cardiac Events
    Predicts 6-week risk of major adverse cardiac events in patients with chest pain.
    
    Parameters:
    -----------
    history : int
        Patient history rating (0: Slightly suspicious, 1: Moderately suspicious, 2: Highly suspicious)
    ekg : int
        EKG findings (0: Normal, 1: Non-specific repolarization disturbance, 2: Significant ST deviation)
    age : int
        Age rating (0: <45 years, 1: 45-64 years, 2: ≥65 years)
    risk_factors : int
        Cardiovascular risk factors (0: None known, 1: 1-2 risk factors, 2: ≥3 risk factors or history of atherosclerotic disease)
    troponin : int
        Initial troponin level (0: ≤normal limit, 1: 1-3× normal limit, 2: >3× normal limit)
    
    Returns:
    --------
    total_score : int
        Total HEART score (0-10)
    """
    try:
        # Calculate total HEART score
        total_score = history + ekg + age + risk_factors + troponin
        
        # Risk stratification
        if total_score <= 3:
            risk_category = "Low risk"
            risk_percentage = "0.9-1.7%"
            recommendation = "Consider discharge with follow-up"
        elif total_score in [4, 5, 6]:
            risk_category = "Moderate risk"
            risk_percentage = "12-16.6%"
            recommendation = "Consider observation and further testing"
        else:  # score 7-10
            risk_category = "High risk"
            risk_percentage = "50-65%"
            recommendation = "Consider early invasive strategies"
        
        return total_score
    except Exception as e:
        return {'error': str(e)}


@mcp.tool()
def revised_cardiac_risk_index(
    high_risk_surgery: bool = False,
    ischemic_heart_disease: bool = False,
    congestive_heart_failure: bool = False,
    cerebrovascular_disease: bool = False,
    insulin_treatment: bool = False,
    creatinine_over_2mg: bool = False
) -> int:
    """
    Revised Cardiac Risk Index for Pre-Operative Risk
    Estimates risk of cardiac complications after noncardiac surgery.
    
    Parameters:
    -----------
    high_risk_surgery : bool
        Intraperitoneal, intrathoracic, or suprainguinal vascular surgery
    ischemic_heart_disease : bool
        History of MI, positive exercise test, current chest pain considered due to myocardial 
        ischemia, use of nitrate therapy, or ECG with pathological Q waves
    congestive_heart_failure : bool
        Pulmonary edema, bilateral rales, S3 gallop, paroxysmal nocturnal dyspnea, or 
        CXR showing pulmonary vascular redistribution
    cerebrovascular_disease : bool
        Prior transient ischemic attack (TIA) or stroke
    insulin_treatment : bool
        Pre-operative treatment with insulin
    creatinine_over_2mg : bool
        Pre-operative creatinine >2 mg/dL (176.8 µmol/L)
    
    Returns:
    --------
    score : int
        RCRI score (0-6)
        
    References:
    -----------
    Lee TH, et al. Circulation. 1999;100(10):1043-1049.
    Canadian Cardiovascular Society (CCS) Guidelines, 2017.
    European Society of Cardiology (ESC) Guidelines, 2022.
    """
    # Calculate RCRI score
    try:

        score = 0
        risk_factors = []
        
        if high_risk_surgery:
            score += 1
            risk_factors.append("High-risk surgery")
        
        if ischemic_heart_disease:
            score += 1
            risk_factors.append("History of ischemic heart disease")
        
        if congestive_heart_failure:
            score += 1
            risk_factors.append("History of congestive heart failure")
        
        if cerebrovascular_disease:
            score += 1
            risk_factors.append("History of cerebrovascular disease")
        
        if insulin_treatment:
            score += 1
            risk_factors.append("Pre-operative treatment with insulin")
        
        if creatinine_over_2mg:
            score += 1
            risk_factors.append("Pre-operative creatinine >2 mg/dL")
        
        # Determine risk percentage based on score
        risk_percentages = {
            0: 3.9,
            1: 6.0,
            2: 10.1,
            3: 15.0,
            4: 15.0,
            5: 15.0,
            6: 15.0
        }
        
        risk_percent = risk_percentages.get(score, 15.0)
        
        # Determine risk category
        if score == 0:
            risk_category = "Low risk"
        elif score == 1:
            risk_category = "Intermediate risk"
        elif score == 2:
            risk_category = "Elevated risk"
        else:  # score >= 3
            risk_category = "High risk"
        
        # Return results
        return score
    except Exception as e:
        return {
            "error": str(e)
        }

@mcp.tool()
def child_pugh_score(
    bilirubin: float,
    albumin: float,
    inr: float,
    ascites: str,
    encephalopathy_grade: int
) -> int:
    """
    Calculates the Child-Pugh Score for cirrhosis mortality assessment.

    Parameters:
    -----------
    bilirubin : float
        Total bilirubin in mg/dL.
    albumin : float
        Albumin in g/dL.
    inr : float
        International Normalized Ratio (INR) for prothrombin time.
    ascites : str
        One of: "absent", "slight", "moderate".
    encephalopathy_grade : int
        Hepatic encephalopathy grade: 0 (none), 1-2 (mild), 3-4 (severe).

    Returns:
    --------
    int
        Total Child-Pugh score (5–15).
    """
    try:
        # Bilirubin points
        bil_points = (
            1 if bilirubin < 2 else
            2 if 2 <= bilirubin <= 3 else
            3
        )

        # Albumin points
        alb_points = (
            1 if albumin > 3.5 else
            2 if 2.8 <= albumin <= 3.5 else
            3
        )

        # INR points
        inr_points = (
            1 if inr < 1.7 else
            2 if 1.7 <= inr <= 2.3 else
            3
        )

        # Ascites points
        ascites = ascites.lower()
        ascites_points = {
            "absent": 1,
            "slight": 2,
            "moderate": 3
        }.get(ascites, 3)  # Default to 3 if unknown

        # Encephalopathy points
        if encephalopathy_grade == 0:
            enceph_points = 1
        elif 1 <= encephalopathy_grade <= 2:
            enceph_points = 2
        else:
            enceph_points = 3

        return bil_points + alb_points + inr_points + ascites_points + enceph_points
    except Exception as e:
        return {
            "error": str(e)
        }

@mcp.tool()
def phq9_score(
    interest: int,
    feeling_down: int,
    sleep: int,
    tired: int,
    appetite: int,
    feeling_bad: int,
    concentration: int,
    movement: int,
    self_harm: int
) -> int:
    """
    PHQ-9 (Patient Health Questionnaire-9)
    Objectifies degree of depression severity.
    
    Parameters:
    -----------
    interest : int
        Little interest or pleasure in doing things
        (0: Not at all, 1: Several days, 2: More than half the days, 3: Nearly every day)
    feeling_down : int
        Feeling down, depressed, or hopeless
        (0: Not at all, 1: Several days, 2: More than half the days, 3: Nearly every day)
    sleep : int
        Trouble falling or staying asleep, or sleeping too much
        (0: Not at all, 1: Several days, 2: More than half the days, 3: Nearly every day)
    tired : int
        Feeling tired or having little energy
        (0: Not at all, 1: Several days, 2: More than half the days, 3: Nearly every day)
    appetite : int
        Poor appetite or overeating
        (0: Not at all, 1: Several days, 2: More than half the days, 3: Nearly every day)
    feeling_bad : int
        Feeling bad about yourself or that you are a failure or have let yourself or family down
        (0: Not at all, 1: Several days, 2: More than half the days, 3: Nearly every day)
    concentration : int
        Trouble concentrating on things, such as reading the newspaper or watching television
        (0: Not at all, 1: Several days, 2: More than half the days, 3: Nearly every day)
    movement : int
        Moving or speaking so slowly that other people could have noticed, or being fidgety or restless
        (0: Not at all, 1: Several days, 2: More than half the days, 3: Nearly every day)
    self_harm : int
        Thoughts that you would be better off dead, or thoughts of hurting yourself
        (0: Not at all, 1: Several days, 2: More than half the days, 3: Nearly every day)
    
    Returns:
    --------
    int
        Total PHQ-9 score (0-27)
    """
    try:
        # Calculate total PHQ-9 score (sum of all responses)
        total_score = sum([
            interest,
            feeling_down,
            sleep,
            tired,
            appetite,
            feeling_bad,
            concentration,
            movement,
            self_harm
        ])
        
        return total_score
    except Exception as e:
        return {'error': str(e)}

@mcp.tool()
def stop_bang_score(
    snoring: bool,
    tired: bool,
    observed_apnea: bool,
    pressure: bool,
    bmi_over_35: bool,
    age_over_50: bool,
    neck_over_40cm: bool,
    male: bool
) -> int:
    """
    STOP-BANG Score for Obstructive Sleep Apnea
    Screens for obstructive sleep apnea.
    
    Parameters:
    -----------
    snoring : bool
        Do you snore loudly? (Louder than talking or loud enough to be heard through closed doors)
    tired : bool
        Do you often feel tired, fatigued, or sleepy during the daytime?
    observed_apnea : bool
        Has anyone observed you stop breathing during sleep?
    pressure : bool
        Do you have (or are you being treated for) high blood pressure?
    bmi_over_35 : bool
        Is BMI more than 35 kg/m²?
    age_over_50 : bool
        Is age over 50 years?
    neck_over_40cm : bool
        Is neck circumference greater than 40 cm?
    male : bool
        Is patient male?
    
    Returns:
    --------
    int
        Total STOP-BANG score (0-8)
    """
    try:
        # Calculate total STOP-BANG score
        # Add 1 point for each "Yes" (True) response
        total_score = sum([
            snoring,
            tired,
            observed_apnea,
            pressure,
            bmi_over_35,
            age_over_50,
            neck_over_40cm,
            male
        ])
        
        return total_score
    except Exception as e:
        return {'error': str(e)}


@mcp.tool()
def steroid_conversion(
    from_steroid: str,
    from_dose_mg: float,
    to_steroid: str
) -> float:
    """
    Converts corticosteroid dosages using standard equivalencies.

    Parameters:
    -----------
    from_steroid : str
        Name of the original steroid (e.g., 'prednisone', 'dexamethasone').
    from_dose_mg : float
        Dose of the original steroid in mg.
    to_steroid : str
        Name of the steroid to convert to.

    Returns:
    --------
    float
        Equivalent dose in mg of the target steroid.
    """
    try:
        # Equivalent dose per steroid (mg)
        steroid_equivalents = {
            "betamethasone": 0.75,
            "cortisone": 25,
            "dexamethasone": 0.75,
            "hydrocortisone": 20,
            "methylprednisolone": 4,
            "prednisolone": 5,
            "prednisone": 5,
            "triamcinolone": 4
        }

        # Normalize names
        from_steroid = from_steroid.lower()
        to_steroid = to_steroid.lower()

        # Ensure valid steroids
        if from_steroid not in steroid_equivalents or to_steroid not in steroid_equivalents:
            raise ValueError("Invalid steroid name provided.")

        # Convert to hydrocortisone-equivalent dose first
        hydrocortisone_equivalent = from_dose_mg * (steroid_equivalents["hydrocortisone"] / steroid_equivalents[from_steroid])

        # Then convert to target steroid
        converted_dose = hydrocortisone_equivalent * (steroid_equivalents[to_steroid] / steroid_equivalents["hydrocortisone"])
        
        return round(converted_dose, 2)
    except Exception as e:
        return {
            "error": str(e)
        }
@mcp.tool()
def calculate_mme(
    opioid: str,
    dose_per_administration: float,
    doses_per_day: int
) -> float:
    """
    Calculates total daily Morphine Milligram Equivalents (MME).

    Parameters:
    -----------
    opioid : str
        Name of the opioid (e.g., 'oxycodone', 'fentanyl_patch').
    dose_per_administration : float
        Amount of opioid per dose (mg for most, mcg/hr for fentanyl patch).
    doses_per_day : int
        Number of times the dose is taken per day.

    Returns:
    --------
    float
        Total MME/day.
    """
    try:
        # MME conversion factors
        mme_factors = {
            "codeine": 0.15,
            "fentanyl_buccal": 0.13,
            "fentanyl_patch": 2.4,
            "hydrocodone": 1.0,
            "hydromorphone": 5.0,
            "methadone": 4.7,  # Simplified; usually weight/dose dependent
            "morphine": 1.0,
            "oxycodone": 1.5,
            "oxymorphone": 3.0,
            "tapentadol": 0.4,
            "tramadol": 0.2,
            # "buprenorphine": 10.0  # Excluded from calculation per guidelines
        }

        # Normalize input
        opioid_key = opioid.lower()

        if opioid_key not in mme_factors:
            raise ValueError("Unsupported or excluded opioid type.")

        # MME/day = dose x frequency x conversion factor
        mme_per_day = dose_per_administration * doses_per_day * mme_factors[opioid_key]
        return round(mme_per_day, 2)
    except Exception as e:
        return {
            "error": str(e)
        }
    
@mcp.tool()
def maintenance_fluids(weight_kg: float) -> float:
    """
    Calculates maintenance IV fluid rate (mL/hr) using the 4-2-1 Rule.

    Parameters:
    -----------
    weight_kg : float
        Patient's weight in kilograms.

    Returns:
    --------
    float
        Maintenance fluid rate in mL/hr.
    """
    try:
        if weight_kg <= 10:
            rate = 4 * weight_kg
        elif weight_kg <= 20:
            rate = 40 + 2 * (weight_kg - 10)
        else:
            rate = 60 + 1 * (weight_kg - 20)

        return round(rate, 2)
    except Exception as e:
        return {
            "error": str(e)
        }
    
@mcp.tool()
def corrected_sodium_katz(
    measured_sodium: float,
    serum_glucose: float
) -> float:
    """
    Calculates corrected sodium level in the setting of hyperglycemia
    using Katz correction formulas.

    Parameters:
    -----------
    measured_sodium : float
        Measured serum sodium in mEq/L.
    serum_glucose : float
        Serum glucose in mg/dL.

    Returns:
    --------
    float
        Corrected sodium level in mEq/L.
    """
    try:
        if serum_glucose < 100:
            # No correction needed for glucose ≤ 100 mg/dL
            return measured_sodium

        # Apply corrections
        katz_corrected = measured_sodium + 0.016 * (serum_glucose - 100)
        hillier_corrected = measured_sodium + 0.024 * (serum_glucose - 100)

        return katz_corrected
    except Exception as e:
        return {
            "error": str(e)
        }
    
@mcp.tool()
def corrected_sodium_hillier(
    measured_sodium: float,
    serum_glucose: float
) -> float:
    """
    Calculates corrected sodium level in the setting of hyperglycemia
    using Katz correction formulas.

    Parameters:
    -----------
    measured_sodium : float
        Measured serum sodium in mEq/L.
    serum_glucose : float
        Serum glucose in mg/dL.

    Returns:
    --------
    float
        Corrected sodium level in mEq/L.
    """
    try:
        if serum_glucose < 100:
            # No correction needed for glucose ≤ 100 mg/dL
            return measured_sodium

        # Apply corrections
        katz_corrected = measured_sodium + 0.016 * (serum_glucose - 100)
        hillier_corrected = measured_sodium + 0.024 * (serum_glucose - 100)

        return hillier_corrected
    except Exception as e:
        return {
            "error": str(e)
        }

@mcp.tool()
def has_bled_score(
    hypertension: bool,
    abnormal_renal_function: bool,
    abnormal_liver_function: bool,
    stroke_history: bool,
    bleeding_history: bool,
    labile_inr: bool,
    elderly: bool,
    drugs: bool,
    alcohol: bool
) -> int:
    """
    HAS-BLED Score for Major Bleeding Risk
    Estimates risk of major bleeding for patients on anticoagulation to assess risk-benefit in atrial fibrillation care.
    
    Parameters:
    -----------
    hypertension : bool
        Hypertension (uncontrolled, >160 mmHg systolic)
    abnormal_renal_function : bool
        Renal disease (dialysis, transplant, Cr >2.26 mg/dL or 200 µmol/L)
    abnormal_liver_function : bool
        Liver disease (cirrhosis or bilirubin >2x normal with AST/ALT/AP >3x normal)
    stroke_history : bool
        Stroke history
    bleeding_history : bool
        Prior major bleeding or predisposition to bleeding
    labile_inr : bool
        Labile INR (unstable/high INRs, time in therapeutic range <60%)
    elderly : bool
        Elderly (age >65)
    drugs : bool
        Medication usage predisposing to bleeding (aspirin, clopidogrel, NSAIDs)
    alcohol : bool
        Alcohol usage (≥8 drinks/week)
    
    Returns:
    --------
    int
        Total HAS-BLED score (0-9)
    """
    try:
        # Calculate total HAS-BLED score
        # Add 1 point for each "Yes" (True) response
        total_score = sum([
            hypertension,
            abnormal_renal_function,
            abnormal_liver_function,
            stroke_history,
            bleeding_history,
            labile_inr,
            elderly,
            drugs,
            alcohol
        ])
        
        return total_score
    except Exception as e:
        return {'error': str(e)}

@mcp.tool()
def centor_score_modified(
    age: int,
    tonsillar_exudate: bool,
    swollen_lymph_nodes: bool,
    fever: bool,
    cough_absent: bool
) -> int:
    """
    Centor Score (Modified/McIsaac) for Strep Pharyngitis
    Estimates probability that pharyngitis is streptococcal, and suggests management course.
    
    Parameters:
    -----------
    age : int
        Age of patient (-1: ≥45 years, 0: 15-44 years, 1: 3-14 years)
    tonsillar_exudate : bool
        Presence of exudate or swelling on tonsils
    swollen_lymph_nodes : bool
        Tender/swollen anterior cervical lymph nodes
    fever : bool
        Temperature >38°C (100.4°F)
    cough_absent : bool
        Absence of cough
    
    Returns:
    --------
    int
        Total Modified Centor/McIsaac score (-1 to 5)
    """
    try:
        # Calculate total Modified Centor/McIsaac score
        if age<14:
            age_group = 1
        elif age<=44:
            age_group = 0
        else:
            age_group = -1
        total_score = age_group  # -1, 0, or 1 point based on age group
        
        # Add points for other criteria if present
        if tonsillar_exudate:
            total_score += 1
        if swollen_lymph_nodes:
            total_score += 1
        if fever:
            total_score += 1
        if cough_absent:
            total_score += 1
        
        return total_score
    except Exception as e:
        return {'error': str(e)}

@mcp.tool()
def glasgow_coma_scale(
    eye_response: int = 4,     # 1–4
    verbal_response: int = 5,  # 1–5
    motor_response: int = 6    # 1–6
) -> int:
    """
    Glasgow Coma Scale (GCS)
    Coma severity scoring based on Eye, Verbal, and Motor responses.

    SCORING:
    --------
    Eye Opening (E):
        4 = Spontaneous
        3 = To verbal command
        2 = To pain
        1 = No eye opening
        NT = Not testable (not scored)
    
    Verbal Response (V):
        5 = Oriented
        4 = Confused conversation
        3 = Inappropriate words
        2 = Incomprehensible sounds
        1 = No verbal response
        NT = Not testable (e.g., intubated; not scored)
    
    Motor Response (M):
        6 = Obeys commands
        5 = Localizes to pain
        4 = Withdraws from pain
        3 = Flexion to pain (decorticate)
        2 = Extension to pain (decerebrate)
        1 = No motor response
        NT = Not testable (e.g., paralyzed; not scored)

    Parameters:
    -----------
    eye_response: int
        Eye response score (1 to 4)
    verbal_response: int
        Verbal response score (1 to 5)
    motor_response: int
        Motor response score (1 to 6)

    Returns:
    --------
    int
        Total GCS score (range: 3–15)
    """
    try:
        total_score = eye_response + verbal_response + motor_response
        return total_score
    except Exception as e:
        return {
            "error": str(e)
        } 

@mcp.tool()
def caprini_score(
    age: int,
    sex: str,  # 'male' or 'female'
    surgery_type: str,  # 'none', 'minor', 'major', 'arthroplasty'
    recent_major_surgery: bool,
    chf: bool,
    sepsis: bool,
    pneumonia: bool,
    immobilizing_cast: bool,
    fracture: bool,
    stroke: bool,
    multiple_trauma: bool,
    spinal_cord_injury: bool,
    varicose_veins: bool,
    swollen_legs: bool,
    central_venous_access: bool,
    history_dvt_pe: bool,
    family_history_thrombosis: bool,
    factor_v_leiden: bool,
    prothrombin_20210a: bool,
    homocysteine: bool,
    lupus_anticoagulant: bool,
    anticardiolipin_antibody: bool,
    hit: bool,  # Heparin-induced thrombocytopenia
    other_thrombophilia: bool,
    mobility_status: str,  # 'normal', 'bedrest', 'bedrest_72hr'
    ibd: bool,
    bmi_over_25: bool,
    acute_mi: bool,
    copd: bool,
    malignancy: bool,
    other_risk_factors: bool
) -> int:
    """
    Caprini Score for Venous Thromboembolism (VTE)
    Risk stratification based on surgery, history, and clinical conditions.
    
    age: int
        Age of patient in years
    sex: str
        'male' or 'female'
    surgery_type: str
        'none', 'minor', 'major', 'arthroplasty'
    recent_major_surgery: bool
        True if patient had major surgery in the last 30 days
    chf: bool
        True if patient has congestive heart failure
    sepsis: bool
        True if patient has sepsis
    pneumonia: bool
        True if patient has pneumonia
    immobilizing_cast: bool
        True if patient has an immobilizing cast
    fracture: bool
        True if patient has a fracture
    stroke: bool
        True if patient has a history of stroke
    multiple_trauma: bool
        True if patient has multiple trauma
    spinal_cord_injury: bool
        True if patient has spinal cord injury
    varicose_veins: bool
        True if patient has varicose veins
    swollen_legs: bool
        True if patient has swollen legs
    central_venous_access: bool
        True if patient has central venous access
    history_dvt_pe: bool
        True if patient has a history of DVT or PE
    family_history_thrombosis: bool
        True if patient has a family history of thrombosis
    factor_v_leiden: bool
        True if patient has Factor V Leiden mutation
    prothrombin_20210a: bool
        True if patient has Prothrombin 20210A mutation
    homocysteine: bool
        True if patient has elevated homocysteine levels
    lupus_anticoagulant: bool
        True if patient has lupus anticoagulant
    anticardiolipin_antibody: bool
        True if patient has anticardiolipin antibody
    hit: bool   
        True if patient has heparin-induced thrombocytopenia
    other_thrombophilia: bool   
        True if patient has other thrombophilia
    mobility_status: str
        one of 'normal', 'bedrest', 'bedrest_72hr'
    ibd: bool
        True if patient has inflammatory bowel disease
    bmi_over_25: bool
        True if patient has a BMI over 25
    acute_mi: bool
        True if patient has a history of acute myocardial infarction
    copd: bool
        True if patient has chronic obstructive pulmonary disease
    malignancy: bool
        True if patient has malignancy
    other_risk_factors: bool
        True if patient has other risk factors for VTE
    Returns:
    --------
    score: int
        Dictionary containing total Caprini score or error message.
    """
    try:
        score = 0

        # Age points
        if age <= 40:
            score += 0
        elif 41 <= age <= 60:
            score += 1
        elif 61 <= age <= 74:
            score += 2
        else:  # age >= 75
            score += 3

        # Surgery type
        if surgery_type == "minor":
            score += 1
        elif surgery_type == "major":
            score += 2
        elif surgery_type == "arthroplasty":
            score += 5

        # Recent event
        score += int(recent_major_surgery) * 1
        score += int(chf) * 1
        score += int(sepsis) * 1
        score += int(pneumonia) * 1
        score += int(immobilizing_cast) * 2
        score += int(fracture) * 5
        score += int(stroke) * 5
        score += int(multiple_trauma) * 5
        score += int(spinal_cord_injury) * 5

        # Venous/thrombophilia history
        score += int(varicose_veins) * 1
        score += int(swollen_legs) * 1
        score += int(central_venous_access) * 2
        score += int(history_dvt_pe) * 3
        score += int(family_history_thrombosis) * 3
        score += int(factor_v_leiden) * 3
        score += int(prothrombin_20210a) * 3
        score += int(homocysteine) * 3
        score += int(lupus_anticoagulant) * 3
        score += int(anticardiolipin_antibody) * 3
        score += int(hit) * 3
        score += int(other_thrombophilia) * 3

        # Mobility
        if mobility_status == "bedrest":
            score += 1
        elif mobility_status == "bedrest_72hr":
            score += 2

        # Other history
        score += int(ibd) * 1
        score += int(bmi_over_25) * 1
        score += int(acute_mi) * 1
        score += int(copd) * 1
        score += int(malignancy) * 2
        score += int(other_risk_factors) * 1

        return score
    
    except Exception as e:
        return {"error": str(e)}

@mcp.tool()
def ldl_calculated(
    total_cholesterol: float,
    hdl: float,
    triglycerides: float
) -> float:
    """
    Calculates LDL cholesterol using the Friedewald equation:
    LDL (mg/dL) = Total Cholesterol - HDL - (Triglycerides / 5)

    Parameters:
    -----------
    total_cholesterol: float
        Total cholesterol level in mg/dL.
    hdl: float
        HDL cholesterol level in mg/dL.
    triglycerides: float
        Triglycerides level in mg/dL.

    Returns:
    --------
    float
        LDL cholesterol level in mg/dL
    """
    try:
        ldl = total_cholesterol - hdl - (triglycerides / 5)
        return ldl
    except Exception as e:
        return {"error": str(e)}


@mcp.tool()
def sofa_score(
    pao2_fio2: float,
    mechanically_ventilated: bool,
    platelets: int,
    gcs: int,
    bilirubin: float,
    map_mmHg: float,
    dopamine: float,
    dobutamine: bool,
    epinephrine: float,
    norepinephrine: float,
    creatinine: float,
    urine_output_ml_per_day: int
) -> int:
    """
    Sequential Organ Failure Assessment (SOFA) Score
    Predicts ICU mortality based on the degree of organ dysfunction.

    Parameters:
    -----------
    pao2_fio2: float
        Arterial oxygen partial pressure / fraction of inspired oxygen ratio.
    mechanically_ventilated: bool
        Whether the patient is currently mechanically ventilated.
    platelets: int
        Platelet count in ×10³/µL.
    gcs: int
        Glasgow Coma Scale score (3–15).
    bilirubin: float
        Serum bilirubin in mg/dL.
    map_mmHg: float
        Mean arterial pressure in mmHg.
    dopamine: float
        Dopamine dosage in mcg/kg/min.
    dobutamine: bool
        True if dobutamine is being administered.
    epinephrine: float
        Epinephrine dosage in mcg/kg/min.
    norepinephrine: float
        Norepinephrine dosage in mcg/kg/min.
    creatinine: float
        Serum creatinine in mg/dL.
    urine_output_ml_per_day: int
        Total urine output over 24 hours in mL.

    Returns:
    --------
    int
        Total SOFA score (0–24)
    """

    try:
        score = 0

        # Respiratory
        if pao2_fio2 >= 400:
            score += 0
        elif pao2_fio2 >= 300:
            score += 1
        elif pao2_fio2 >= 200:
            score += 2
        elif pao2_fio2 < 100 and mechanically_ventilated:
            score += 4
        elif pao2_fio2 < 200 and mechanically_ventilated:
            score += 3
        else:
            score += 2

        # Coagulation
        if platelets >= 150:
            score += 0
        elif platelets >= 100:
            score += 1
        elif platelets >= 50:
            score += 2
        elif platelets >= 20:
            score += 3
        else:
            score += 4

        # CNS
        if gcs == 15:
            score += 0
        elif gcs >= 13:
            score += 1
        elif gcs >= 10:
            score += 2
        elif gcs >= 6:
            score += 3
        else:
            score += 4

        # Liver
        if bilirubin < 1.2:
            score += 0
        elif bilirubin < 2.0:
            score += 1
        elif bilirubin < 6.0:
            score += 2
        elif bilirubin < 12.0:
            score += 3
        else:
            score += 4

        # Cardiovascular
        if map_mmHg >= 70 and dopamine == 0 and epinephrine == 0 and norepinephrine == 0 and not dobutamine:
            score += 0
        elif map_mmHg < 70:
            score += 1
        elif dopamine <= 5 or dobutamine:
            score += 2
        elif dopamine > 5 or epinephrine <= 0.1 or norepinephrine <= 0.1:
            score += 3
        elif dopamine > 15 or epinephrine > 0.1 or norepinephrine > 0.1:
            score += 4

        # Renal
        if creatinine < 1.2 and urine_output_ml_per_day >= 500:
            score += 0
        elif creatinine < 2.0:
            score += 1
        elif creatinine < 3.5:
            score += 2
        elif creatinine < 5.0 or urine_output_ml_per_day < 500:
            score += 3
        else:
            score += 4

        return score
    except Exception as e:
        return {"error": str(e)}

@mcp.tool()
def perc_rule(
    age_over_50: bool,
    heart_rate_100_or_more: bool,
    oxygen_sat_below_95: bool,
    unilateral_leg_swelling: bool,
    hemoptysis: bool,
    recent_trauma_or_surgery: bool,
    prior_pe_or_dvt: bool,
    hormone_use: bool
) -> int:
    """
    PERC Rule for Pulmonary Embolism
    Rules out PE in low-risk patients if **none** of the criteria are present.
    
    If the pre-test probability is ≤15% (clinically low risk), and all 8 criteria below are **absent** (i.e., all False), PE can be ruled out without further testing.
    If **any** criterion is present (True), PE cannot be ruled out by PERC alone.

    CRITERIA (any present = +1):
    ----------------------------
    • Age ≥ 50 years
    • Heart rate ≥ 100 bpm
    • Oxygen saturation < 95% on room air
    • Unilateral leg swelling
    • Hemoptysis
    • Recent trauma or surgery
    • Prior PE or DVT
    • Hormone use (oral contraceptives, HRT, estrogen in any patient)

    Parameters:
    -----------
    age_over_50: bool
        True if patient is 50 years or older.
    heart_rate_100_or_more: bool
        True if heart rate is ≥100 bpm.
    oxygen_sat_below_95: bool
        True if O₂ saturation is less than 95% on room air.
    unilateral_leg_swelling: bool
        True if leg swelling is present in only one leg.
    hemoptysis: bool
        True if patient is coughing up blood.
    recent_trauma_or_surgery: bool
        True if patient had trauma or surgery recently.
    prior_pe_or_dvt: bool
        True if patient has a history of PE or DVT.
    hormone_use: bool
        True if patient uses hormones (OCPs, HRT, or estrogen).

    Returns:
    --------
    int
        Number of positive PERC criteria (0–8)
    """

    try:
        return sum([
            age_over_50,
            heart_rate_100_or_more,
            oxygen_sat_below_95,
            unilateral_leg_swelling,
            hemoptysis,
            recent_trauma_or_surgery,
            prior_pe_or_dvt,
            hormone_use
        ])
    except Exception as e:
        return {"error": str(e)}

@mcp.tool()
def gad7_score(
    q1: int,
    q2: int,
    q3: int,
    q4: int,
    q5: int,
    q6: int,
    q7: int
) -> int:
    """
    GAD-7 (Generalized Anxiety Disorder-7)
    Measures severity of anxiety symptoms over the past two weeks.

    SCORING PER QUESTION:
    ---------------------
    • 0 = Not at all
    • 1 = Several days
    • 2 = More than half the days
    • 3 = Nearly every day

    QUESTIONS:
    ----------
    1. Feeling nervous, anxious, or on edge
    2. Not being able to stop or control worrying
    3. Worrying too much about different things
    4. Trouble relaxing
    5. Being so restless that it's hard to sit still
    6. Becoming easily annoyed or irritable
    7. Feeling afraid as if something awful might happen

    Parameters:
    -----------
    q1 to q7: int
        Response scores for each of the 7 GAD-7 questions (range: 0–3)

    Returns:
    --------
    int
        Total GAD-7 score (range: 0–21)
    """
    try:
        return q1 + q2 + q3 + q4 + q5 + q6 + q7
    except Exception as e:
        return {"error": str(e)}

@mcp.tool()
def curb65_score(
    confusion: bool,
    bun_over_19: bool,
    respiratory_rate_30_or_more: bool,
    low_blood_pressure: bool,
    age_65_or_more: bool
) -> int:
    """
    CURB-65 Score for Pneumonia Severity
    Assesses mortality risk in community-acquired pneumonia to guide inpatient vs. outpatient treatment decisions.

    SCORING (1 point each):
    -----------------------
    • Confusion (new onset disorientation)
    • BUN > 19 mg/dL (or urea > 7 mmol/L)
    • Respiratory rate ≥ 30 breaths/min
    • Systolic BP < 90 mmHg or Diastolic BP ≤ 60 mmHg
    • Age ≥ 65 years

    Parameters:
    -----------
    confusion: bool
        True if new mental confusion is present.
    bun_over_19: bool
        True if BUN > 19 mg/dL (or urea > 7 mmol/L).
    respiratory_rate_30_or_more: bool
        True if respiratory rate is 30 or higher.
    low_blood_pressure: bool
        True if SBP < 90 mmHg or DBP ≤ 60 mmHg.
    age_65_or_more: bool
        True if age is 65 years or older.

    Returns:
    --------
    int
        Total CURB-65 score (range: 0–5)
    """
    try:
        return sum([
            confusion,
            bun_over_19,
            respiratory_rate_30_or_more,
            low_blood_pressure,
            age_65_or_more
        ])
    except Exception as e:
        return {"error": str(e)}


@mcp.tool()
def meld_3(
    age: int,
    female: bool,
    bilirubin: float,
    inr: float,
    creatinine: float,
    albumin: float,
    sodium: float,
    dialysis: bool
) -> int:
    """
    Calculates MELD 3.0 Score for liver disease transplant planning.

    Parameters:
    -----------
    age : int
        Patient age in years.
    female : bool
        True if patient is female.
    bilirubin : float
        Serum bilirubin in mg/dL.
    inr : float
        INR (International Normalized Ratio).
    creatinine : float
        Serum creatinine in mg/dL.
    albumin : float
        Serum albumin in g/dL.
    sodium : float
        Serum sodium in mEq/L.
    dialysis : bool
        True if patient had ≥2 dialysis sessions or 24h CVVHD in last 7 days.

    Returns:
    --------
    int
        MELD 3.0 score, rounded to the nearest whole number.
    """
    try:
        # Apply rules for minimum/maximum values
        bilirubin = max(bilirubin, 1.0)
        inr = max(inr, 1.0)
        sodium = min(max(sodium, 125), 137)
        albumin = min(max(albumin, 1.5), 3.5)

        if dialysis or creatinine > 3.0:
            creatinine = 3.0
        else:
            creatinine = max(creatinine, 1.0)

        # MELD 3.0 for age >= 18
        if age >= 18:
            female_coef = 1.33 if female else 0
            meld = (
                female_coef +
                4.56 * math.log(bilirubin) +
                0.82 * (137 - sodium) -
                0.24 * (137 - sodium) * math.log(bilirubin) +
                9.09 * math.log(inr) +
                11.14 * math.log(creatinine) +
                1.85 * (3.5 - albumin) -
                1.83 * (3.5 - albumin) * math.log(creatinine) +
                6
            )
        else:  # 12 ≤ age < 18
            meld = (
                4.56 * math.log(bilirubin) +
                0.82 * (137 - sodium) -
                0.24 * (137 - sodium) * math.log(bilirubin) +
                9.09 * math.log(inr) +
                11.14 * math.log(creatinine) +
                1.85 * (3.5 - albumin) -
                1.83 * (3.5 - albumin) -
                1.83 * (3.5 - albumin) * math.log(creatinine) +
                7.33
            )

        return round(meld)
    except Exception as e:
        return {
            "error": str(e)
        }
    
@mcp.tool()
def framingham_risk_score(
    age: int,
    total_cholesterol: float,
    hdl_cholesterol: float,
    systolic_bp: float,
    treated_for_bp: bool,
    smoker: bool,
    gender: str
) -> float:
    """
    Calculates the Framingham Risk Score for 10-year risk of heart attack (CHD)
    based on the Framingham Heart Study equation (men and women).

    Parameters:
    -----------
    age : int
        Age of the patient (30-79 years).
    total_cholesterol : float
        Total cholesterol in mg/dL.
    hdl_cholesterol : float
        HDL cholesterol in mg/dL.
    systolic_bp : float
        Systolic blood pressure in mmHg.
    treated_for_bp : bool
        Whether the patient is treated for high blood pressure (1 if yes, 0 if no).
    smoker : bool
        Whether the patient is a smoker (1 if yes, 0 if no).
    gender : str
        Gender of the patient ("male" or "female").

    Returns:
    --------
    float
        10-year risk of heart attack as a percentage.
    """
    try:
        # Coefficients for men and women
        coefficients = {
            "male": {
                "ln_age": 52.00961,
                "ln_total_chol": 20.014077,
                "ln_hdl_chol": -0.905964,
                "ln_systolic_bp": 1.305784,
                "treated_for_bp": 0.241549,
                "smoker": 12.096316,
                "ln_age_ln_total_chol": -4.605038,
                "ln_age_smoker": -2.84367,
                "ln_age_ln_age": -2.93323,
                "intercept": -172.300168
            },
            "female": {
                "ln_age": 31.764001,
                "ln_total_chol": 22.465206,
                "ln_hdl_chol": -1.187731,
                "ln_systolic_bp": 2.552905,
                "treated_for_bp": 0.420251,
                "smoker": 13.07543,
                "ln_age_ln_total_chol": -5.060998,
                "ln_age_smoker": -2.996945,
                "intercept": -146.5933061
            }
        }
        treated_for_bp = int(treated_for_bp)
        smoker = int(smoker)

        
        # Validate gender input
        if gender.lower() not in coefficients:
            raise ValueError("Invalid gender. Please enter 'male' or 'female'.")
        
        # Select appropriate coefficients based on gender
        coeff = coefficients[gender.lower()]
        
        # Transform variables using logarithms
        ln_age = math.log(age)
        ln_total_chol = math.log(total_cholesterol)
        ln_hdl_chol = math.log(hdl_cholesterol)
        ln_systolic_bp = math.log(systolic_bp)
        
        # Adjust for smoking and age >70 (men) or >78 (women)
        if age > 70 and gender == "male":
            ln_age_smoker = math.log(70) * smoker
        elif age > 78 and gender == "female":
            ln_age_smoker = math.log(78) * smoker
        else:
            ln_age_smoker = ln_age * smoker

        # Compute the linear predictor (L)
        L = (coeff["ln_age"] * ln_age +
            coeff["ln_total_chol"] * ln_total_chol +
            coeff["ln_hdl_chol"] * ln_hdl_chol +
            coeff["ln_systolic_bp"] * ln_systolic_bp +
            coeff["treated_for_bp"] * treated_for_bp +
            coeff["smoker"] * smoker +
            coeff["ln_age_ln_total_chol"] * ln_age * ln_total_chol +
            coeff["ln_age_smoker"] * ln_age_smoker +
            coeff["ln_age_ln_age"] * ln_age ** 2 +
            coeff["intercept"])

        # Calculate probability of a heart attack using the equation
        if gender == "male":
            P = 1 - math.pow(0.9402,math.exp(L))
        else:
            P = 1 - math.pow(0.98767,math.exp(L))

        # Return the risk as a percentage
        risk_percentage = P * 100
        return round(risk_percentage, 2)
    except Exception as e:
        return {
            "error": str(e)
        }
@mcp.tool()
def homa_ir(fasting_insulin: float, fasting_glucose: float) -> float:
    """
    Calculates the HOMA-IR score for insulin resistance.

    Formula:
    Score = (Fasting insulin (uIU/mL) * Fasting glucose (mg/dL)) / 405

    Parameters:
    -----------
    fasting_insulin : float
        Fasting insulin level in micro-units per milliliter (uIU/mL).
    fasting_glucose : float
        Fasting glucose level in milligrams per deciliter (mg/dL).A

    Returns:
    --------
    float
        HOMA-IR score.
    """
    try:
        if fasting_insulin <= 0 or fasting_glucose <= 0:
            raise ValueError("Fasting insulin and fasting glucose must be greater than 0.")
        
        score = (fasting_insulin * fasting_glucose) / 405
        return round(score, 2)
    except Exception as e:
        return {
            "error": str(e)
        }

@mcp.tool()
def fib4_index(age: int, ast: float, alt: float, platelets: float) -> float:
    """
    Fibrosis-4 (FIB-4) Index for Liver Fibrosis
    Noninvasive estimate of liver scarring in HCV and HBV patients, to assess need for biopsy.
    
    Parameters:
    -----------
    age : int
        Age in years
    ast : float
        Aspartate aminotransferase (AST) level in U/L
    alt : float
        Alanine aminotransferase (ALT) level in U/L
    platelets : float
        Platelet count in 10^9/L (or 1000/μL)
    
    Returns:
    --------
    float
        FIB-4 score
    """
    try:
        fib4_score = (age * ast) / (platelets * math.sqrt(alt))
        return fib4_score
    except Exception as e:
        return {'error': str(e)}

@mcp.tool()
def ariscat_score(
    age: int,
    spo2: float,
    recent_respiratory_infection: bool,
    preop_anemia: bool,
    surgical_site: str,        # "peripheral", "upper_abdominal", or "intrathoracic"
    surgery_duration_hrs: float,
    emergency_surgery: bool
) -> int:
    """
    ARISCAT Score for Postoperative Pulmonary Complications
    Predicts risk of respiratory complications (e.g., failure, infection) after surgery.

    Parameters:
    -----------
    age: int
        Patient age in years.
    spo2: float
        Preoperative oxygen saturation percentage on room air.
    recent_respiratory_infection: bool
        True if URI, bronchitis, or pneumonia occurred in the past month with fever and antibiotics.
    preop_anemia: bool
        True if hemoglobin ≤10 g/dL.
    surgical_site: str
        One of "peripheral", "upper_abdominal", or "intrathoracic".
    surgery_duration_hrs: float
        Estimated or actual surgery time in hours.
    emergency_surgery: bool
        True if the procedure is non-elective.

    Returns:
    --------
    int
        Total ARISCAT score (range: 0–123)
    """
    try:
        score = 0

        # Age
        if age > 80:
            score += 16
        elif age >= 51:
            score += 3

        # SpO2
        if spo2 <= 90:
            score += 24
        elif spo2 <= 95:
            score += 8

        # Recent infection
        if recent_respiratory_infection:
            score += 17

        # Preoperative anemia
        if preop_anemia:
            score += 11

        # Surgical site
        if surgical_site == "upper_abdominal":
            score += 15
        elif surgical_site == "intrathoracic":
            score += 24

        # Duration
        if surgery_duration_hrs > 3:
            score += 23
        elif surgery_duration_hrs >= 2:
            score += 16

        # Emergency surgery
        if emergency_surgery:
            score += 8

        return score
    except Exception as e:
        return {"error": str(e)}

@mcp.tool()
def sepsis_criteria(
    temp_abnormal: bool,
    heart_rate_gt_90: bool,
    rr_gt_20_or_paco2_lt_32: bool,
    wbc_abnormal: bool,
    suspected_infection: bool,
    organ_dysfunction: bool,
    fluid_resistant_hypotension: bool,
    multi_organ_failure: bool
) -> str:
    """
    SIRS, Sepsis, and Septic Shock Criteria
    Categorizes patient condition based on systemic inflammatory response and organ function.

    Criteria Overview:
    ------------------
    • SIRS (Systemic Inflammatory Response Syndrome):
        At least 2 of the following:
        - Temp >38°C or <36°C
        - HR >90 bpm
        - RR >20 or PaCO₂ <32 mm Hg
        - WBC >12,000 or <4,000 or >10% bands

    • Sepsis:
        SIRS + suspected or confirmed infection

    • Severe Sepsis:
        Sepsis + evidence of organ dysfunction or hypotension or hypoperfusion

    • Septic Shock:
        Severe sepsis + persistent hypotension despite fluid resuscitation

    • MODS (Multiple Organ Dysfunction Syndrome):
        Severe sepsis + failure of ≥2 organs

    Parameters:
    -----------
    temp_abnormal: bool
        True if temperature >38°C or <36°C
    heart_rate_gt_90: bool
        True if heart rate is over 90 bpm
    rr_gt_20_or_paco2_lt_32: bool
        True if RR >20 or PaCO₂ <32 mm Hg
    wbc_abnormal: bool
        True if WBC >12,000 or <4,000 or bands >10%
    suspected_infection: bool
        True if a source of infection is suspected or confirmed
    organ_dysfunction: bool
        True if signs of lactic acidosis or SBP <90 or SBP drop ≥40 mm Hg
    fluid_resistant_hypotension: bool
        True if hypotension persists despite adequate fluid resuscitation
    multi_organ_failure: bool
        True if there is evidence of ≥2 organs failing

    Returns:
    --------
    str
        One of: "No SIRS", "SIRS", "Sepsis", "Severe Sepsis", "Septic Shock", or "MODS"
    """
    sirs_count = sum([
        temp_abnormal,
        heart_rate_gt_90,
        rr_gt_20_or_paco2_lt_32,
        wbc_abnormal
    ])

    if sirs_count < 2:
        return "No SIRS"

    if multi_organ_failure:
        return "MODS"
    if fluid_resistant_hypotension:
        return "Septic Shock"
    if organ_dysfunction:
        return "Severe Sepsis"
    if suspected_infection:
        return "Sepsis"

    return "SIRS"

@mcp.tool()
def fractional_excretion_of_sodium(
    serum_creatinine: float,
    urine_sodium: float,
    serum_sodium: float,
    urine_creatinine: float
) -> float:
    """
    Fractional Excretion of Sodium (FENa)
    Determines whether acute kidney injury is due to prerenal or intrinsic renal pathology.

    Formula:
    --------
    FENa (%) = 100 × (SCr × UNa) / (SNa × UCr)

    Interpretation:
    ---------------
    • FENa <1%  → Suggests prerenal cause (e.g., hypovolemia)
    • FENa >2%  → Suggests intrinsic renal damage (e.g., acute tubular necrosis)

    Parameters:
    -----------
    serum_creatinine: float
        Serum creatinine (SCr), mg/dL
    urine_sodium: float
        Urine sodium (UNa), mEq/L
    serum_sodium: float
        Serum sodium (SNa), mEq/L
    urine_creatinine: float
        Urine creatinine (UCr), mg/dL

    Returns:
    --------
    float
        Fractional Excretion of Sodium as a percentage (%)
    """
    try:
        fena = 100 * (serum_creatinine * urine_sodium) / (serum_sodium * urine_creatinine)
        return fena
    except Exception as e:
        return {
            "error": str(e)
        }

@mcp.tool()
def free_water_deficit(
    weight_kg: float,
    current_sodium: float,
    is_male: bool,
    is_elderly: bool
) -> float:
    """
    Free Water Deficit in Hypernatremia
    Calculates free water deficit based on body weight and serum sodium concentration.

    Formula:
    --------
    Free water deficit (L) = TBW_fraction × Weight_kg × ([Na_measured / Na_ideal] - 1)

    • Na_ideal is assumed to be 140 mEq/L.
    • TBW_fraction varies by sex and age:
        - Adult male: 0.6
        - Adult female: 0.5
        - Elderly male: 0.5
        - Elderly female: 0.45
        - (Child: 0.6 — not handled in this function)

    Parameters:
    -----------
    weight_kg: float
        Patient’s weight in kilograms.
    current_sodium: float
        Patient’s current serum sodium in mEq/L.
    is_male: bool
        True if the patient is biologically male, False if female.
    is_elderly: bool
        True if the patient is elderly (e.g., age ≥65), False otherwise.

    Returns:
    --------
    float
        Free water deficit in liters.
    """
    try:
        # Determine total body water fraction
        if is_male and is_elderly:
            tbw = 0.5
        elif is_male:
            tbw = 0.6
        elif is_elderly:
            tbw = 0.45
        else:
            tbw = 0.5

        ideal_sodium = 140.0
        deficit = tbw * weight_kg * ((current_sodium / ideal_sodium) - 1)
        return deficit
    except Exception as e:
        return {
            "error": str(e)
        }

@mcp.tool()
def gupta_perioperative_mica(
    age: int,
    functional_status: str,
    asa_class: int,
    creatinine_status: str,
    procedure_type: str
) -> float:
    """
    Gupta Perioperative Risk for Myocardial Infarction or Cardiac Arrest (MICA)
    Calculates the cardiac risk percentage based on clinical variables and procedure type.

    Formula:
    --------
    Risk (%) = e^x / (1 + e^x)
    Where:
        x = −5.25 + age×0.02 + other variable values (based on inputs)

    Parameters:
    -----------
    age: int
        Patient's age in years.
    functional_status: str
        One of: "independent", "partially_dependent", "totally_dependent".
    asa_class: int
        ASA physical status class (1 to 5).
    creatinine_status: str
        One of: "normal", "elevated", "unknown".
    procedure_type: str
        One of the predefined surgical procedure categories from the Gupta MICA model.

    Returns:
    --------
    float
        Predicted cardiac risk as a percentage.
    """

    try:
        # Age coefficient
        x = -5.25 + (age * 0.02)

        # Functional status
        x += {
            "independent": 0,
            "partially_dependent": 0.65,
            "totally_dependent": 1.03
        }.get(functional_status.lower(), 0)

        # ASA class
        x += {
            1: -5.17,
            2: -3.29,
            3: -1.92,
            4: -0.95,
            5: 0
        }.get(asa_class, 0)

        # Creatinine
        x += {
            "normal": 0,
            "elevated": 0.61,
            "unknown": -0.10
        }.get(creatinine_status.lower(), 0)

        # Procedure type coefficients
        procedure_map = {
            "anorectal": -0.16,
            "aortic": 1.60,
            "bariatric": -0.25,
            "brain": 1.40,
            "breast": -1.61,
            "cardiac": 1.01,
            "ent": 0.71,
            "foregut": 1.39,
            "gallbladder": 0.59,
            "hernia": 0,
            "intestinal": 1.14,
            "neck": 0.18,
            "obstetric": 0.76,
            "orthopedic": 0.80,
            "other abdominal": 1.13,
            "peripheral vascular": 0.86,
            "skin": 0.54,
            "spine": 0.21,
            "thoracic": 0.40,
            "vein": -1.09,
            "urology": -0.26
        }

        # Normalize and match procedure type
        key = procedure_type.lower().strip()
        x += procedure_map.get(key, 0)

        # Logistic transformation
        import math
        risk = math.exp(x) / (1 + math.exp(x))
        return risk * 100

    except Exception as e:
        return {
            "error": str(e)
        }

@mcp.tool()
def duke_activity_status_index(
    self_care: bool,  # Able to take care of self
    walk_indoors: bool,  # Able to walk indoors
    walk_1_2_blocks: bool,  # Able to walk 1–2 blocks on level ground
    climb_stairs: bool,  # Able to climb a flight of stairs or walk up a hill
    run_short_distance: bool,  # Able to run a short distance
    light_work: bool,  # Able to do light work around the house
    moderate_work: bool,  # Able to do moderate work around the house
    heavy_work: bool,  # Able to do heavy work around the house
    yardwork: bool,  # Able to do yardwork
    sexual_relations: bool,  # Able to have sexual relations
    moderate_recreational: bool,  # Able to participate in moderate recreational activities
    strenuous_sports: bool  # Able to participate in strenuous sports
) -> float:
    """
    Duke Activity Status Index (DASI)
    Estimates functional capacity based on self-reported physical activity.

    Parameters:
    -----------
    self_care: bool
        True if the patient is able to take care of themselves (e.g., eating, dressing, bathing).
    walk_indoors: bool
        True if the patient can walk indoors.
    walk_1_2_blocks: bool
        True if the patient can walk 1–2 blocks on level ground.
    climb_stairs: bool
        True if the patient can climb a flight of stairs or walk up a hill.
    run_short_distance: bool
        True if the patient can run a short distance.
    light_work: bool
        True if the patient can do light work around the house (e.g., dusting, washing dishes).
    moderate_work: bool
        True if the patient can do moderate work around the house (e.g., vacuuming, sweeping floors).
    heavy_work: bool
        True if the patient can do heavy work around the house (e.g., scrubbing floors, lifting heavy items).
    yardwork: bool
        True if the patient can do yardwork (e.g., raking leaves, weeding, pushing a mower).
    sexual_relations: bool
        True if the patient can have sexual relations.
    moderate_recreational: bool
        True if the patient can participate in moderate recreational activities (e.g., golf, bowling).
    strenuous_sports: bool
        True if the patient can participate in strenuous sports (e.g., swimming, singles tennis).

    Returns:
    --------
    float
        The total Duke Activity Status Index (DASI) score.
    """
    
    try:
        score = 0
        if self_care:
            score += 2.75
        if walk_indoors:
            score += 1.75
        if walk_1_2_blocks:
            score += 2.75
        if climb_stairs:
            score += 5.5
        if run_short_distance:
            score += 8.0
        if light_work:
            score += 2.7
        if moderate_work:
            score += 3.5
        if heavy_work:
            score += 8.0
        if yardwork:
            score += 4.5
        if sexual_relations:
            score += 5.25
        if moderate_recreational:
            score += 6.0
        if strenuous_sports:
            score += 7.5
        
        return score
    
    except Exception as e:
        return {
            "error": str(e)
        }

@mcp.tool()
def ciwa_ar_score(
    nausea_vomiting: int,  # Nausea and vomiting severity (0-7)
    tremor: int,  # Tremor severity (0-7)
    paroxysmal_sweats: int,  # Sweating severity (0-7)
    anxiety: int,  # Anxiety severity (0-7)
    agitation: int,  # Agitation severity (0-7)
    tactile_disturbances: int,  # Tactile disturbances severity (0-7)
    auditory_disturbances: int,  # Auditory disturbances severity (0-7)
    visual_disturbances: int,  # Visual disturbances severity (0-7)
    headache_fullness: int,  # Headache/fullness in head severity (0-7)
    orientation: int  # Orientation/clouding of sensorium (0-4)
) -> int:
    """
    CIWA-Ar (Clinical Institute Withdrawal Assessment for Alcohol)
    Objectifies the severity of alcohol withdrawal based on symptoms.

    SCORING:
    --------
    Each symptom is scored on a scale of 0 to 7, except for orientation, which is scored from 0 to 4.
    
    Symptoms and their associated scoring:
    - Nausea/vomiting: 0 (No nausea) to 7 (Constant nausea, frequent dry heaves and vomiting)
    - Tremor: 0 (No tremor) to 7 (Severe tremor, even with arms not extended)
    - Paroxysmal sweats: 0 (No sweat visible) to 7 (Drenching sweats)
    - Anxiety: 0 (No anxiety) to 7 (Severe panic states or severe delirium)
    - Agitation: 0 (Normal activity) to 7 (Constantly thrashes or paces)
    - Tactile disturbances: 0 (None) to 7 (Continuous hallucinations)
    - Auditory disturbances: 0 (Not present) to 7 (Continuous hallucinations)
    - Visual disturbances: 0 (Not present) to 7 (Continuous hallucinations)
    - Headache/fullness in head: 0 (Not present) to 7 (Extremely severe)
    - Orientation/clouding of sensorium: 0 (Oriented) to 4 (Disoriented to place or person)
    
    Parameters:
    -----------
    nausea_vomiting: int
        Severity of nausea and vomiting (0-7).
    tremor: int
        Severity of tremor (0-7).
    paroxysmal_sweats: int
        Severity of paroxysmal sweats (0-7).
    anxiety: int
        Severity of anxiety (0-7).
    agitation: int
        Severity of agitation (0-7).
    tactile_disturbances: int
        Severity of tactile disturbances (0-7).
    auditory_disturbances: int
        Severity of auditory disturbances (0-7).
    visual_disturbances: int
        Severity of visual disturbances (0-7).
    headache_fullness: int
        Severity of headache or fullness in head (0-7).
    orientation: int
        Orientation or clouding of sensorium (0-4).

    Returns:
    --------
    int
        Total CIWA-Ar score (range: 0-67).
    """
    try:
        total_score = (
            nausea_vomiting + tremor + paroxysmal_sweats + anxiety + agitation +
            tactile_disturbances + auditory_disturbances + visual_disturbances +
            headache_fullness + orientation
        )
        
        return total_score
    
    except Exception as e:
        return {
            "error": str(e)
        }

@mcp.tool()
def psi_port_score(
    age: int,  # Age in years
    sex: str,  # 'Female' or 'Male'
    nursing_home_resident: bool,  # Is the patient a nursing home resident?
    neoplastic_disease: bool,  # History of neoplastic disease?
    liver_disease: bool,  # History of liver disease?
    chf_history: bool,  # History of congestive heart failure?
    cerebrovascular_disease: bool,  # History of cerebrovascular disease?
    renal_disease: bool,  # History of renal disease?
    altered_mental_status: bool,  # Altered mental status?
    resp_rate_30: bool,  # Respiratory rate ≥30 breaths/min
    sbp_90: bool,  # Systolic blood pressure <90 mmHg
    temp_35_39_9: bool,  # Temperature <35°C (95°F) or >39.9°C (103.8°F)
    pulse_125: bool,  # Pulse ≥125 beats/min
    ph_735: bool,  # pH <7.35
    bun_30: bool,  # BUN ≥30 mg/dL or ≥11 mmol/L
    sodium_130: bool,  # Sodium <130 mmol/L
    glucose_250: bool,  # Glucose ≥250 mg/dL or ≥14 mmol/L
    hematocrit_30: bool,  # Hematocrit <30%
    pao2_60: bool,  # Partial pressure of oxygen <60 mmHg or <8 kPa
    pleural_effusion: bool  # Pleural effusion on x-ray
) -> int:
    """
    PSI/PORT Score for Pneumonia Severity (Pneumonia Severity Index)
    
    Estimates mortality risk for adult patients with community-acquired pneumonia (CAP).

    SCORING:
    --------
    Age, sex, and various comorbidities are assigned specific scores. The final score is 
    the sum of individual scores based on clinical variables such as:
    - Age
    - Sex
    - Comorbidities (e.g., neoplastic disease, liver disease)
    - Clinical signs (e.g., respiratory rate, systolic blood pressure)
    - Laboratory findings (e.g., glucose, sodium, hematocrit)

    Parameters:
    -----------
    age: int
        Age in years.
    sex: str
        'Female' or 'Male'.
    nursing_home_resident: bool
        Whether the patient is a nursing home resident.
    neoplastic_disease: bool
        History of neoplastic disease (cancer).
    liver_disease: bool
        History of liver disease.
    chf_history: bool
        History of congestive heart failure.
    cerebrovascular_disease: bool
        History of cerebrovascular disease.
    renal_disease: bool
        History of renal disease.
    altered_mental_status: bool
        Whether the patient has altered mental status.
    resp_rate_30: bool
        Respiratory rate ≥30 breaths/min.
    sbp_90: bool
        Systolic blood pressure <90 mmHg.
    temp_35_39_9: bool
        Temperature <35°C (95°F) or >39.9°C (103.8°F).
    pulse_125: bool
        Pulse ≥125 beats/min.
    ph_735: bool
        pH <7.35.
    bun_30: bool
        BUN ≥30 mg/dL or ≥11 mmol/L.
    sodium_130: bool
        Sodium <130 mmol/L.
    glucose_250: bool
        Glucose ≥250 mg/dL or ≥14 mmol/L.
    hematocrit_30: bool
        Hematocrit <30%.
    pao2_60: bool
        Partial pressure of oxygen <60 mmHg or <8 kPa.
    pleural_effusion: bool
        Whether there is a pleural effusion on x-ray.

    Returns:
    --------
    int
        Total PSI/PORT Score for the patient (higher scores indicate higher risk).
    """
    try:
        # Initialize total score
        total_score = 0
        
        # Age: 
        total_score += age

        # Sex: Female gets +10, Male gets +0
        if sex == "Female":
            total_score += 10

        # Nursing home resident: Yes +10, No +0
        if nursing_home_resident:
            total_score += 10

        # Comorbidities: Adding scores if true
        if neoplastic_disease:
            total_score += 30
        if liver_disease:
            total_score += 20
        if chf_history:
            total_score += 10
        if cerebrovascular_disease:
            total_score += 10
        if renal_disease:
            total_score += 10
        if altered_mental_status:
            total_score += 20

        # Vital signs and lab values
        if resp_rate_30:
            total_score += 20
        if sbp_90:
            total_score += 20
        if temp_35_39_9:
            total_score += 15
        if pulse_125:
            total_score += 10
        if ph_735:
            total_score += 30
        if bun_30:
            total_score += 20
        if sodium_130:
            total_score += 20
        if glucose_250:
            total_score += 10
        if hematocrit_30:
            total_score += 10
        if pao2_60:
            total_score += 10
        if pleural_effusion:
            total_score += 10
        
        return total_score
    
    except Exception as e:
        return {
            "error": str(e)
        }

@mcp.tool()
def serum_anion_gap(
    sodium: float,  # Sodium in mEq/L
    chloride: float,  # Chloride in mEq/L
    bicarbonate: float,  # Bicarbonate in mEq/L
    albumin: float  # Albumin in g/dL
):
    """
    Calculate the Serum Anion Gap and related values.

    FORMULAS:
    -----------
    1. Anion Gap = Na - (Cl + HCO3-)
    2. Delta Gap = (Anion Gap - Normal Anion Gap)
    3. Albumin-Corrected Anion Gap = Anion Gap + [ 2.5 * (4 - Albumin) ]
    4. Albumin-Corrected Delta Gap = Albumin-Corrected Anion Gap - Normal Anion Gap
    5. Delta Ratio = Delta Gap / (24 - Bicarbonate)
    6. Albumin-Corrected Delta Ratio = Albumin-Corrected Delta Gap / (24 - Bicarbonate)

    Parameters:
    -----------
    sodium: float
        Sodium in mEq/L.
    chloride: float
        Chloride in mEq/L.
    bicarbonate: float
        Bicarbonate in mEq/L.
    albumin: float
        Albumin in g/dL.

    Returns:
    --------
    dict:
        A dictionary with the calculated values of Anion Gap, Delta Gap, Albumin-Corrected Anion Gap,
        Albumin-Corrected Delta Gap, Delta Ratio, and Albumin-Corrected Delta Ratio.
    """
    try:
        # Normal Anion Gap range (usually between 10 and 12)
        normal_anion_gap = 10  # Using 10 as the standard for "normal"
        
        # Calculate Anion Gap
        anion_gap = sodium - (chloride + bicarbonate)
        
        # Calculate Delta Gap
        delta_gap = anion_gap - normal_anion_gap
        
        # Calculate Albumin Corrected Anion Gap
        albumin_corrected_anion_gap = anion_gap + (2.5 * (4 - albumin))
        
        # Calculate Albumin Corrected Delta Gap
        albumin_corrected_delta_gap = albumin_corrected_anion_gap - normal_anion_gap
        
        # Calculate Delta Ratio
        delta_ratio = delta_gap / (24 - bicarbonate)
        
        # Calculate Albumin Corrected Delta Ratio
        albumin_corrected_delta_ratio = albumin_corrected_delta_gap / (24 - bicarbonate)
        
        # Return results as a dictionary
        return {
            'Anion Gap': anion_gap,
            'Delta Gap': delta_gap,
            'Albumin Corrected Anion Gap': albumin_corrected_anion_gap,
            'Albumin Corrected Delta Gap': albumin_corrected_delta_gap,
            'Delta Ratio': delta_ratio,
            'Albumin Corrected Delta Ratio': albumin_corrected_delta_ratio
        }
    
    except Exception as e:
        return {'error': str(e)}

@mcp.tool()
def serum_osmolarity(
    sodium: float,  # Sodium in mEq/L
    bun: float,     # BUN in mg/dL
    glucose: float, # Glucose in mg/dL
    ethanol: float  # Ethanol in mg/dL
):
    """
    Calculate the Serum Osmolarity using the formula:
    
    Serum Osmolarity (US units) = (2 × Na) + (BUN / 2.8) + (Glucose / 18) + (Ethanol / 4.6)
    
    Parameters:
    -----------
    sodium: float
        Sodium concentration in mEq/L.
    bun: float
        Blood Urea Nitrogen (BUN) concentration in mg/dL.
    glucose: float
        Glucose concentration in mg/dL.
    ethanol: float
        Ethanol concentration in mg/dL.
    
    Returns:
    --------
    float:
        Calculated serum osmolarity.
    """
    try:
        # Calculate serum osmolarity
        osmolarity = (2 * sodium) + (bun / 2.8) + (glucose / 18) + (ethanol / 4.6)
        return osmolarity
    except Exception as e:
        return {'error': str(e)}

mcp.tool()
def padua_vte_prediction_score(
    active_cancer: bool,            # Active cancer (Yes = True, No = False)
    previous_vte: bool,             # Previous VTE (Yes = True, No = False)
    reduced_mobility: bool,         # Reduced mobility (Yes = True, No = False)
    thrombophilic_condition: bool,  # Known thrombophilic condition (Yes = True, No = False)
    recent_trauma_surgery: bool,    # Recent trauma or surgery (Yes = True, No = False)
    elderly_age: bool,              # Elderly age (≥70 years) (Yes = True, No = False)
    heart_respiratory_failure: bool,# Heart or respiratory failure (Yes = True, No = False)
    acute_mi_stroke: bool,          # Acute MI or ischemic stroke (Yes = True, No = False)
    acute_infection_rheumatologic: bool, # Acute infection or rheumatologic disorder (Yes = True, No = False)
    obesity: bool,                  # Obesity (BMI ≥30) (Yes = True, No = False)
    hormonal_treatment: bool        # Ongoing hormonal treatment (Yes = True, No = False)
):
    """
    Calculate the Padua Prediction Score for the risk of venous thromboembolism (VTE) 
    based on various clinical factors.

    Parameters:
    -----------
    active_cancer: bool
        Whether the patient has active cancer (Yes = True, No = False).
    previous_vte: bool
        Whether the patient has a history of previous VTE (Yes = True, No = False).
    reduced_mobility: bool
        Whether the patient has reduced mobility (Yes = True, No = False).
    thrombophilic_condition: bool
        Whether the patient has a known thrombophilic condition (Yes = True, No = False).
    recent_trauma_surgery: bool
        Whether the patient has had recent trauma or surgery (Yes = True, No = False).
    elderly_age: bool
        Whether the patient is aged ≥70 years (Yes = True, No = False).
    heart_respiratory_failure: bool
        Whether the patient has heart or respiratory failure (Yes = True, No = False).
    acute_mi_stroke: bool
        Whether the patient has acute MI or ischemic stroke (Yes = True, No = False).
    acute_infection_rheumatologic: bool
        Whether the patient has an acute infection or rheumatologic disorder (Yes = True, No = False).
    obesity: bool
        Whether the patient is obese (BMI ≥30) (Yes = True, No = False).
    hormonal_treatment: bool
        Whether the patient is undergoing hormonal treatment (Yes = True, No = False).

    Returns:
    --------
    int:
        The calculated Padua Prediction Score for the risk of VTE.
    """
    try:
        score = 0

        # Assign points based on the conditions
        if active_cancer:
            score += 3
        if previous_vte:
            score += 3
        if reduced_mobility:
            score += 3
        if thrombophilic_condition:
            score += 3
        if recent_trauma_surgery:
            score += 2
        if elderly_age:
            score += 1
        if heart_respiratory_failure:
            score += 1
        if acute_mi_stroke:
            score += 1
        if acute_infection_rheumatologic:
            score += 1
        if obesity:
            score += 1
        if hormonal_treatment:
            score += 1

        return score
    except Exception as e:
        return {'error': str(e)}


@mcp.tool()
def ventilator_tidal_volume(height_cm: float, male: bool) -> dict:
    """
    Low Tidal Volume Ventilation Calculator based on Ideal Body Weight (IBW).
    Calculates IBW from height using the Devine formula, then provides
    tidal volume range for lung-protective ventilation (6-8 mL/kg IBW).

    Parameters:
    -----------
    height_cm : float
        Patient height in centimeters
    male : bool
        True if patient is male, False if female

    Returns:
    --------
    dict
        ibw_kg: Ideal body weight in kg
        tv_6: Tidal volume at 6 mL/kg IBW (mL)
        tv_8: Tidal volume at 8 mL/kg IBW (mL)

    References:
    -----------
    ARDSNet. N Engl J Med. 2000;342(18):1301-1308.
    Devine BJ. Gentamicin therapy. Drug Intell Clin Pharm. 1974;8:650-655.
    """
    try:
        height_inches = height_cm / 2.54
        if male:
            ibw = 50 + 0.91 * (height_cm - 152.4)
        else:
            ibw = 45.5 + 0.91 * (height_cm - 152.4)

        if ibw <= 0:
            return {'error': 'Height too low to calculate IBW'}

        tv_6 = round(ibw * 6, 1)
        tv_8 = round(ibw * 8, 1)

        return {
            'ibw_kg': round(ibw, 1),
            'tv_6_mL': tv_6,
            'tv_8_mL': tv_8,
            'recommendation': f'Tidal volume range: {tv_6:.0f} - {tv_8:.0f} mL (6-8 mL/kg IBW)'
        }
    except Exception as e:
        return {'error': str(e)}


@mcp.tool()
def wells_dvt_criteria(
    active_cancer: bool = False,
    bedridden_or_major_surgery: bool = False,
    calf_swelling_gt_3cm: bool = False,
    collateral_superficial_veins: bool = False,
    entire_leg_swollen: bool = False,
    localized_tenderness: bool = False,
    pitting_edema: bool = False,
    paralysis_paresis_immobilization: bool = False,
    previously_documented_dvt: bool = False,
    alternative_diagnosis_likely: bool = False
) -> dict:
    """
    Wells' Criteria for Deep Vein Thrombosis (DVT).
    Estimates probability of DVT based on clinical criteria.

    Parameters:
    -----------
    active_cancer : bool
        Active cancer (treatment/palliation within 6 months)
    bedridden_or_major_surgery : bool
        Bedridden >3 days or major surgery within 12 weeks
    calf_swelling_gt_3cm : bool
        Calf swelling >3 cm compared to other leg
    collateral_superficial_veins : bool
        Collateral (non-varicose) superficial veins present
    entire_leg_swollen : bool
        Entire leg swollen
    localized_tenderness : bool
        Localized tenderness along deep venous system
    pitting_edema : bool
        Pitting edema confined to symptomatic leg
    paralysis_paresis_immobilization : bool
        Paralysis, paresis, or recent plaster immobilization
    previously_documented_dvt : bool
        Previously documented DVT
    alternative_diagnosis_likely : bool
        Alternative diagnosis at least as likely as DVT

    Returns:
    --------
    dict
        score, risk_level, prevalence
    """
    try:
        score = 0
        if active_cancer: score += 1
        if bedridden_or_major_surgery: score += 1
        if calf_swelling_gt_3cm: score += 1
        if collateral_superficial_veins: score += 1
        if entire_leg_swollen: score += 1
        if localized_tenderness: score += 1
        if pitting_edema: score += 1
        if paralysis_paresis_immobilization: score += 1
        if previously_documented_dvt: score += 1
        if alternative_diagnosis_likely: score -= 2

        if score <= 0:
            risk = "Low"
            prevalence = "~5%"
        elif score <= 2:
            risk = "Moderate"
            prevalence = "~17%"
        else:
            risk = "High"
            prevalence = "17-53%"

        return {'score': score, 'risk_level': risk, 'prevalence': prevalence}
    except Exception as e:
        return {'error': str(e)}


@mcp.tool()
def pecarn_pediatric_head_injury(
    age_years: int,
    gcs: int = 15,
    altered_mental_status: bool = False,
    palpable_skull_fracture: bool = False,
    basilar_skull_fracture_signs: bool = False,
    scalp_hematoma_occipital_parietal_temporal: bool = False,
    loc_ge_5_seconds: bool = False,
    not_acting_normally: bool = False,
    history_of_loc: bool = False,
    history_of_vomiting: bool = False,
    severe_headache: bool = False,
    severe_mechanism: bool = False
) -> dict:
    """
    PECARN Pediatric Head Injury/Trauma Algorithm.
    Identifies children at very low risk of clinically-important traumatic brain injuries (ciTBI).

    Parameters:
    -----------
    age_years : int
        Patient age in years
    gcs : int
        Glasgow Coma Scale score (default 15)
    altered_mental_status : bool
        Altered mental status (agitation, somnolence, repetitive questioning, slow response)
    palpable_skull_fracture : bool
        Palpable skull fracture (age <2 only)
    basilar_skull_fracture_signs : bool
        Signs of basilar skull fracture (age >=2 only)
    scalp_hematoma_occipital_parietal_temporal : bool
        Occipital, parietal, or temporal scalp hematoma (age <2 only)
    loc_ge_5_seconds : bool
        Loss of consciousness >= 5 seconds (age <2 only)
    not_acting_normally : bool
        Not acting normally per parent (age <2 only)
    history_of_loc : bool
        History of loss of consciousness (age >=2 only)
    history_of_vomiting : bool
        History of vomiting (age >=2 only)
    severe_headache : bool
        Severe headache (age >=2 only)
    severe_mechanism : bool
        Severe mechanism of injury

    Returns:
    --------
    dict
        risk_category, ct_recommendation, citbi_risk
    """
    try:
        if age_years < 2:
            if gcs <= 14 or palpable_skull_fracture or altered_mental_status:
                return {
                    'risk_category': 'High',
                    'ct_recommendation': 'CT recommended',
                    'ciTBI_risk': '~4.4%'
                }
            elif (scalp_hematoma_occipital_parietal_temporal or loc_ge_5_seconds or
                  not_acting_normally or severe_mechanism):
                return {
                    'risk_category': 'Intermediate',
                    'ct_recommendation': 'Observation vs CT (based on clinical factors, worsening, age <3 months, physician experience)',
                    'ciTBI_risk': '~0.9%'
                }
            else:
                return {
                    'risk_category': 'Low',
                    'ct_recommendation': 'CT not recommended',
                    'ciTBI_risk': '<0.02%'
                }
        else:
            if gcs <= 14 or basilar_skull_fracture_signs or altered_mental_status:
                return {
                    'risk_category': 'High',
                    'ct_recommendation': 'CT recommended',
                    'ciTBI_risk': '~4.3%'
                }
            elif (history_of_loc or history_of_vomiting or severe_headache or severe_mechanism):
                return {
                    'risk_category': 'Intermediate',
                    'ct_recommendation': 'Observation vs CT (based on clinical factors, worsening, physician experience)',
                    'ciTBI_risk': '~0.9%'
                }
            else:
                return {
                    'risk_category': 'Low',
                    'ct_recommendation': 'CT not recommended',
                    'ciTBI_risk': '<0.05%'
                }
    except Exception as e:
        return {'error': str(e)}


@mcp.tool()
def news2_score(
    respiratory_rate: int,
    spo2: int,
    supplemental_o2: bool,
    temperature: float,
    systolic_bp: int,
    heart_rate: int,
    consciousness: str = "alert",
    spo2_scale2: bool = False
) -> dict:
    """
    National Early Warning Score 2 (NEWS2).
    Detects clinical deterioration in acutely ill patients.

    Parameters:
    -----------
    respiratory_rate : int
        Respiratory rate (breaths/min)
    spo2 : int
        Oxygen saturation (%)
    supplemental_o2 : bool
        Whether patient is on supplemental oxygen
    temperature : float
        Temperature in Celsius
    systolic_bp : int
        Systolic blood pressure (mmHg)
    heart_rate : int
        Heart rate (bpm)
    consciousness : str
        One of: "alert", "confusion", "voice", "pain", "unresponsive"
    spo2_scale2 : bool
        Use SpO2 Scale 2 for confirmed hypercapnic respiratory failure (e.g. COPD)

    Returns:
    --------
    dict
        total_score, subscores, clinical_response, any_extreme (single param >=3)
    """
    try:
        scores = {}

        # Respiratory rate
        if respiratory_rate <= 8: scores['respiratory_rate'] = 3
        elif respiratory_rate <= 11: scores['respiratory_rate'] = 1
        elif respiratory_rate <= 20: scores['respiratory_rate'] = 0
        elif respiratory_rate <= 24: scores['respiratory_rate'] = 2
        else: scores['respiratory_rate'] = 3

        # SpO2
        if spo2_scale2:
            if spo2 <= 83: scores['spo2'] = 3
            elif spo2 <= 85: scores['spo2'] = 2
            elif spo2 <= 87: scores['spo2'] = 1
            elif spo2 <= 92:
                scores['spo2'] = 0
            elif spo2 >= 93 and not supplemental_o2:
                scores['spo2'] = 0
            elif spo2 <= 94 and supplemental_o2: scores['spo2'] = 2
            elif spo2 <= 96 and supplemental_o2: scores['spo2'] = 2
            else: scores['spo2'] = 3  # >=97 on O2
        else:
            if spo2 <= 91: scores['spo2'] = 3
            elif spo2 <= 93: scores['spo2'] = 2
            elif spo2 <= 95: scores['spo2'] = 1
            else: scores['spo2'] = 0

        # Supplemental oxygen
        scores['supplemental_o2'] = 2 if supplemental_o2 else 0

        # Temperature
        if temperature <= 35.0: scores['temperature'] = 3
        elif temperature <= 36.0: scores['temperature'] = 1
        elif temperature <= 38.0: scores['temperature'] = 0
        elif temperature <= 39.0: scores['temperature'] = 1
        else: scores['temperature'] = 2

        # Systolic BP
        if systolic_bp <= 90: scores['systolic_bp'] = 3
        elif systolic_bp <= 100: scores['systolic_bp'] = 2
        elif systolic_bp <= 110: scores['systolic_bp'] = 1
        elif systolic_bp <= 219: scores['systolic_bp'] = 0
        else: scores['systolic_bp'] = 3

        # Heart rate
        if heart_rate <= 40: scores['heart_rate'] = 3
        elif heart_rate <= 50: scores['heart_rate'] = 1
        elif heart_rate <= 90: scores['heart_rate'] = 0
        elif heart_rate <= 110: scores['heart_rate'] = 1
        elif heart_rate <= 130: scores['heart_rate'] = 2
        else: scores['heart_rate'] = 3

        # Consciousness
        consciousness = consciousness.lower()
        if consciousness == "alert":
            scores['consciousness'] = 0
        else:
            scores['consciousness'] = 3

        total = sum(scores.values())
        any_extreme = any(v >= 3 for v in scores.values())

        if total >= 7:
            response = "High - Emergency response, critical care team"
        elif total >= 5:
            response = "Medium - Urgent response, clinician review within 30 min"
        elif any_extreme:
            response = "Low-Medium - Urgent review (single parameter score >= 3)"
        elif total >= 1:
            response = "Low - Assess by competent registered nurse"
        else:
            response = "Routine monitoring"

        return {
            'total_score': total,
            'subscores': scores,
            'clinical_response': response,
            'any_extreme': any_extreme
        }
    except Exception as e:
        return {'error': str(e)}


@mcp.tool()
def grace_acs_score(
    age: int,
    heart_rate: int,
    systolic_bp: int,
    creatinine: float,
    killip_class: int = 1,
    cardiac_arrest: bool = False,
    st_deviation: bool = False,
    elevated_cardiac_enzymes: bool = False
) -> dict:
    """
    GRACE ACS Risk and Mortality Calculator.
    Estimates in-hospital mortality in acute coronary syndrome patients.

    Parameters:
    -----------
    age : int
        Patient age in years
    heart_rate : int
        Heart rate (bpm)
    systolic_bp : int
        Systolic blood pressure (mmHg)
    creatinine : float
        Serum creatinine (mg/dL)
    killip_class : int
        Killip class (1-4): 1=No CHF, 2=Rales/JVD, 3=Pulmonary edema, 4=Cardiogenic shock
    cardiac_arrest : bool
        Cardiac arrest at admission
    st_deviation : bool
        ST-segment deviation on ECG
    elevated_cardiac_enzymes : bool
        Elevated/abnormal cardiac enzymes

    Returns:
    --------
    dict
        score, risk_level, in_hospital_mortality
    """
    try:
        score = 0

        # Age
        if age < 30: score += 0
        elif age < 40: score += 8
        elif age < 50: score += 25
        elif age < 60: score += 41
        elif age < 70: score += 58
        elif age < 80: score += 75
        elif age < 90: score += 91
        else: score += 100

        # Heart rate
        if heart_rate < 50: score += 0
        elif heart_rate < 70: score += 3
        elif heart_rate < 90: score += 9
        elif heart_rate < 110: score += 15
        elif heart_rate < 150: score += 24
        elif heart_rate < 200: score += 38
        else: score += 46

        # Systolic BP (inverse)
        if systolic_bp < 80: score += 58
        elif systolic_bp < 100: score += 53
        elif systolic_bp < 120: score += 43
        elif systolic_bp < 140: score += 34
        elif systolic_bp < 160: score += 24
        elif systolic_bp < 200: score += 10
        else: score += 0

        # Creatinine
        if creatinine < 0.4: score += 1
        elif creatinine < 0.8: score += 4
        elif creatinine < 1.2: score += 7
        elif creatinine < 1.6: score += 10
        elif creatinine < 2.0: score += 13
        elif creatinine < 4.0: score += 21
        else: score += 28

        # Killip class
        killip_points = {1: 0, 2: 20, 3: 39, 4: 59}
        score += killip_points.get(killip_class, 0)

        # Binary variables
        if cardiac_arrest: score += 39
        if st_deviation: score += 28
        if elevated_cardiac_enzymes: score += 14

        if score <= 108:
            risk = "Low"
            mortality = "<1%"
        elif score <= 140:
            risk = "Intermediate"
            mortality = "1-3%"
        else:
            risk = "High"
            mortality = ">3%"

        return {'score': score, 'risk_level': risk, 'in_hospital_mortality': mortality}
    except Exception as e:
        return {'error': str(e)}


@mcp.tool()
def ascvd_10yr_risk(
    age: int,
    male: bool,
    african_american: bool,
    total_cholesterol: float,
    hdl_c: float,
    systolic_bp: int,
    bp_treated: bool,
    diabetes: bool,
    current_smoker: bool
) -> dict:
    """
    ASCVD 2013 Pooled Cohort Equations (AHA/ACC).
    Estimates 10-year risk of atherosclerotic cardiovascular disease.
    Applicable for ages 40-79.

    Parameters:
    -----------
    age : int
        Patient age (40-79)
    male : bool
        True if male
    african_american : bool
        True if African American, False if White/other
    total_cholesterol : float
        Total cholesterol (mg/dL)
    hdl_c : float
        HDL cholesterol (mg/dL)
    systolic_bp : int
        Systolic blood pressure (mmHg)
    bp_treated : bool
        Currently on blood pressure treatment
    diabetes : bool
        Has diabetes
    current_smoker : bool
        Current smoker

    Returns:
    --------
    dict
        risk_percent, risk_category
    """
    try:
        ln_age = math.log(age)
        ln_tc = math.log(total_cholesterol)
        ln_hdl = math.log(hdl_c)
        ln_sbp = math.log(systolic_bp)
        smoker = 1 if current_smoker else 0
        dm = 1 if diabetes else 0

        if male and not african_american:
            # White men
            individual_sum = (
                12.344 * ln_age +
                11.853 * ln_tc +
                -2.664 * ln_age * ln_tc +
                -7.990 * ln_hdl +
                1.769 * ln_age * ln_hdl +
                (1.797 if bp_treated else 1.764) * ln_sbp +
                7.837 * smoker +
                -1.795 * ln_age * smoker +
                0.658 * dm
            )
            mean_coeff = 61.1816
            s0 = 0.91436
        elif male and african_american:
            # AA men
            individual_sum = (
                2.469 * ln_age +
                0.302 * ln_tc +
                -0.307 * ln_hdl +
                (1.916 if bp_treated else 1.809) * ln_sbp +
                0.549 * smoker +
                0.645 * dm
            )
            mean_coeff = 19.5425
            s0 = 0.89536
        elif not male and not african_american:
            # White women
            individual_sum = (
                -29.799 * ln_age +
                4.884 * ln_age ** 2 +
                13.540 * ln_tc +
                -3.114 * ln_age * ln_tc +
                -13.578 * ln_hdl +
                3.149 * ln_age * ln_hdl +
                (2.019 if bp_treated else 1.957) * ln_sbp +
                7.574 * smoker +
                -1.665 * ln_age * smoker +
                0.661 * dm
            )
            mean_coeff = -29.1817
            s0 = 0.96652
        else:
            # AA women
            individual_sum = (
                17.1141 * ln_age +
                0.9396 * ln_tc +
                -18.9196 * ln_hdl +
                4.4748 * ln_age * ln_hdl +
                (29.2907 + -6.4321 * ln_age if bp_treated else 27.8197 + -6.0873 * ln_age) * ln_sbp +
                0.6908 * smoker +
                0.8738 * dm
            )
            mean_coeff = 86.6081
            s0 = 0.95334

        risk = 1 - s0 ** math.exp(individual_sum - mean_coeff)
        risk_pct = round(risk * 100, 1)

        if risk_pct < 5:
            category = "Low"
        elif risk_pct < 7.5:
            category = "Borderline"
        elif risk_pct < 20:
            category = "Intermediate"
        else:
            category = "High"

        return {'risk_percent': risk_pct, 'risk_category': category}
    except Exception as e:
        return {'error': str(e)}


@mcp.tool()
def apache2_score(
    temperature: float,
    map_mmhg: float,
    heart_rate: int,
    respiratory_rate: int,
    fio2: float,
    pao2: float = 0,
    aa_gradient_val: float = 0,
    arterial_ph: float = 7.4,
    sodium: float = 140,
    potassium: float = 4.0,
    creatinine: float = 1.0,
    acute_renal_failure: bool = False,
    hematocrit: float = 40,
    wbc: float = 10,
    gcs: int = 15,
    age: int = 50,
    chronic_health: str = "none"
) -> dict:
    """
    APACHE II Score for ICU mortality prediction.

    Parameters:
    -----------
    temperature : float
        Rectal temperature (Celsius)
    map_mmhg : float
        Mean arterial pressure (mmHg)
    heart_rate : int
        Heart rate (bpm)
    respiratory_rate : int
        Respiratory rate (breaths/min)
    fio2 : float
        Fraction of inspired oxygen (0.21-1.0)
    pao2 : float
        PaO2 in mmHg (used if FiO2 <0.5)
    aa_gradient_val : float
        A-a gradient in mmHg (used if FiO2 >=0.5)
    arterial_ph : float
        Arterial pH
    sodium : float
        Serum sodium (mEq/L)
    potassium : float
        Serum potassium (mEq/L)
    creatinine : float
        Serum creatinine (mg/dL)
    acute_renal_failure : bool
        Acute renal failure (doubles creatinine points)
    hematocrit : float
        Hematocrit (%)
    wbc : float
        White blood cell count (x10^3/uL)
    gcs : int
        Glasgow Coma Scale (3-15)
    age : int
        Age in years
    chronic_health : str
        "none", "elective_postop", or "emergency_or_nonop"

    Returns:
    --------
    dict
        total_score, physiology_score, age_points, chronic_points
    """
    try:
        physiology = 0

        # Temperature
        t = temperature
        if t >= 41: physiology += 4
        elif t >= 39: physiology += 3
        elif t >= 38.5: physiology += 1
        elif t >= 36: physiology += 0
        elif t >= 34: physiology += 1
        elif t >= 32: physiology += 2
        elif t >= 30: physiology += 3
        else: physiology += 4

        # MAP
        m = map_mmhg
        if m >= 160: physiology += 4
        elif m >= 130: physiology += 3
        elif m >= 110: physiology += 2
        elif m >= 70: physiology += 0
        elif m >= 50: physiology += 2
        else: physiology += 4

        # Heart rate
        hr = heart_rate
        if hr >= 180: physiology += 4
        elif hr >= 140: physiology += 3
        elif hr >= 110: physiology += 2
        elif hr >= 70: physiology += 0
        elif hr >= 55: physiology += 2
        elif hr >= 40: physiology += 3
        else: physiology += 4

        # Respiratory rate
        rr = respiratory_rate
        if rr >= 50: physiology += 4
        elif rr >= 35: physiology += 3
        elif rr >= 25: physiology += 1
        elif rr >= 12: physiology += 0
        elif rr >= 10: physiology += 1
        elif rr >= 6: physiology += 2
        else: physiology += 4

        # Oxygenation
        if fio2 >= 0.5:
            aa = aa_gradient_val
            if aa >= 500: physiology += 4
            elif aa >= 350: physiology += 3
            elif aa >= 200: physiology += 2
            else: physiology += 0
        else:
            po2 = pao2
            if po2 > 70: physiology += 0
            elif po2 >= 61: physiology += 1
            elif po2 >= 55: physiology += 3
            else: physiology += 4

        # Arterial pH
        ph = arterial_ph
        if ph >= 7.70: physiology += 4
        elif ph >= 7.60: physiology += 3
        elif ph >= 7.50: physiology += 1
        elif ph >= 7.33: physiology += 0
        elif ph >= 7.25: physiology += 2
        elif ph >= 7.15: physiology += 3
        else: physiology += 4

        # Sodium
        na = sodium
        if na >= 180: physiology += 4
        elif na >= 160: physiology += 3
        elif na >= 155: physiology += 2
        elif na >= 150: physiology += 1
        elif na >= 130: physiology += 0
        elif na >= 120: physiology += 2
        elif na >= 111: physiology += 3
        else: physiology += 4

        # Potassium
        k = potassium
        if k >= 7.0: physiology += 4
        elif k >= 6.0: physiology += 3
        elif k >= 5.5: physiology += 1
        elif k >= 3.5: physiology += 0
        elif k >= 3.0: physiology += 1
        elif k >= 2.5: physiology += 2
        else: physiology += 4

        # Creatinine
        cr = creatinine
        cr_mult = 2 if acute_renal_failure else 1
        if cr >= 3.5: physiology += 4 * cr_mult
        elif cr >= 2.0: physiology += 3 * cr_mult
        elif cr >= 1.5: physiology += 2 * cr_mult
        elif cr >= 0.6: physiology += 0
        else: physiology += 2 * cr_mult

        # Hematocrit
        hct = hematocrit
        if hct >= 60: physiology += 4
        elif hct >= 50: physiology += 2
        elif hct >= 46: physiology += 1
        elif hct >= 30: physiology += 0
        elif hct >= 20: physiology += 2
        else: physiology += 4

        # WBC
        w = wbc
        if w >= 40: physiology += 4
        elif w >= 20: physiology += 2
        elif w >= 15: physiology += 1
        elif w >= 3: physiology += 0
        elif w >= 1: physiology += 2
        else: physiology += 4

        # GCS
        physiology += 15 - gcs

        # Age points
        if age <= 44: age_pts = 0
        elif age <= 54: age_pts = 2
        elif age <= 64: age_pts = 3
        elif age <= 74: age_pts = 5
        else: age_pts = 6

        # Chronic health
        if chronic_health == "emergency_or_nonop":
            chronic_pts = 5
        elif chronic_health == "elective_postop":
            chronic_pts = 2
        else:
            chronic_pts = 0

        total = physiology + age_pts + chronic_pts

        return {
            'total_score': total,
            'physiology_score': physiology,
            'age_points': age_pts,
            'chronic_health_points': chronic_pts
        }
    except Exception as e:
        return {'error': str(e)}


@mcp.tool()
def timi_stemi(
    age: int,
    dm_htn_angina: bool = False,
    systolic_bp_lt_100: bool = False,
    heart_rate_gt_100: bool = False,
    killip_2_to_4: bool = False,
    weight_lt_67kg: bool = False,
    anterior_ste_or_lbbb: bool = False,
    time_to_treatment_gt_4hr: bool = False
) -> dict:
    """
    TIMI Risk Score for STEMI.
    Estimates 30-day mortality in ST-elevation MI patients.

    Parameters:
    -----------
    age : int
        Patient age in years
    dm_htn_angina : bool
        Diabetes, hypertension, or angina
    systolic_bp_lt_100 : bool
        Systolic BP <100 mmHg
    heart_rate_gt_100 : bool
        Heart rate >100 bpm
    killip_2_to_4 : bool
        Killip class II-IV
    weight_lt_67kg : bool
        Weight <67 kg
    anterior_ste_or_lbbb : bool
        Anterior ST elevation or LBBB
    time_to_treatment_gt_4hr : bool
        Time to treatment >4 hours

    Returns:
    --------
    dict
        score, estimated_mortality
    """
    try:
        score = 0
        if age >= 75: score += 3
        elif age >= 65: score += 2
        if dm_htn_angina: score += 1
        if systolic_bp_lt_100: score += 3
        if heart_rate_gt_100: score += 2
        if killip_2_to_4: score += 2
        if weight_lt_67kg: score += 1
        if anterior_ste_or_lbbb: score += 1
        if time_to_treatment_gt_4hr: score += 1

        mortality_map = {
            0: "0.8%", 1: "1.6%", 2: "2.2%", 3: "4.4%", 4: "7.3%",
            5: "12.4%", 6: "16.1%", 7: "23.4%", 8: "26.8%"
        }
        mortality = mortality_map.get(score, "35.9%")

        return {'score': score, 'estimated_30day_mortality': mortality}
    except Exception as e:
        return {'error': str(e)}


@mcp.tool()
def timi_nstemi(
    age_ge_65: bool = False,
    ge_3_cad_risk_factors: bool = False,
    known_cad: bool = False,
    asa_use_past_7days: bool = False,
    severe_angina: bool = False,
    st_deviation: bool = False,
    positive_cardiac_marker: bool = False
) -> dict:
    """
    TIMI Risk Score for UA/NSTEMI.
    Estimates 14-day risk of death, MI, or urgent revascularization.

    Parameters:
    -----------
    age_ge_65 : bool
        Age >= 65
    ge_3_cad_risk_factors : bool
        >= 3 CAD risk factors (HTN, hyperlipidemia, DM, family hx, current smoker)
    known_cad : bool
        Known CAD (stenosis >= 50%)
    asa_use_past_7days : bool
        ASA use in past 7 days
    severe_angina : bool
        Severe angina (>= 2 episodes in 24 hrs)
    st_deviation : bool
        ST deviation >= 0.5mm on ECG
    positive_cardiac_marker : bool
        Positive cardiac marker (troponin/CK-MB)

    Returns:
    --------
    dict
        score, estimated_14day_event_rate
    """
    try:
        score = sum([
            age_ge_65, ge_3_cad_risk_factors, known_cad,
            asa_use_past_7days, severe_angina, st_deviation,
            positive_cardiac_marker
        ])

        if score <= 1: event_rate = "4.7%"
        elif score == 2: event_rate = "8.3%"
        elif score == 3: event_rate = "13.2%"
        elif score == 4: event_rate = "19.9%"
        elif score == 5: event_rate = "26.2%"
        else: event_rate = "40.9%"

        return {'score': score, 'estimated_14day_event_rate': event_rate}
    except Exception as e:
        return {'error': str(e)}


@mcp.tool()
def anion_gap_delta_delta(sodium: float, chloride: float, bicarbonate: float) -> dict:
    """
    Anion Gap with Delta-Delta Ratio calculation.
    Evaluates mixed acid-base disorders.

    Parameters:
    -----------
    sodium : float
        Serum sodium (mEq/L)
    chloride : float
        Serum chloride (mEq/L)
    bicarbonate : float
        Serum bicarbonate / HCO3 (mEq/L)

    Returns:
    --------
    dict
        anion_gap, delta_ag, delta_hco3, delta_ratio, interpretation
    """
    try:
        ag = sodium - (chloride + bicarbonate)
        delta_ag = ag - 12
        delta_hco3 = 24 - bicarbonate

        if delta_hco3 == 0:
            return {
                'anion_gap': round(ag, 1),
                'delta_ag': round(delta_ag, 1),
                'delta_hco3': 0,
                'delta_ratio': None,
                'interpretation': 'HCO3 is normal (24), delta-delta ratio not applicable'
            }

        delta_ratio = delta_ag / delta_hco3

        if delta_ratio < 0.4:
            interp = "Hyperchloremic non-anion gap metabolic acidosis (NAGMA)"
        elif delta_ratio < 0.8:
            interp = "Combined high AG + non-AG metabolic acidosis"
        elif delta_ratio <= 2.0:
            interp = "Pure high anion gap metabolic acidosis"
        else:
            interp = "High AG metabolic acidosis + pre-existing metabolic alkalosis"

        return {
            'anion_gap': round(ag, 1),
            'delta_ag': round(delta_ag, 1),
            'delta_hco3': round(delta_hco3, 1),
            'delta_ratio': round(delta_ratio, 2),
            'interpretation': interp
        }
    except Exception as e:
        return {'error': str(e)}


@mcp.tool()
def aa_gradient(paco2: float, pao2: float, age: int, fio2: float = 0.21, patm: float = 760) -> dict:
    """
    Alveolar-Arterial (A-a) Gradient calculator.
    Evaluates oxygenation efficiency.

    Parameters:
    -----------
    paco2 : float
        Arterial CO2 (mmHg, from ABG)
    pao2 : float
        Arterial O2 (mmHg, from ABG)
    age : int
        Patient age in years
    fio2 : float
        Fraction of inspired oxygen (default 0.21 = room air)
    patm : float
        Atmospheric pressure in mmHg (default 760 = sea level)

    Returns:
    --------
    dict
        pao2_alveolar, aa_gradient, expected_gradient, interpretation
    """
    try:
        pao2_alveolar = fio2 * (patm - 47) - (paco2 / 0.8)
        gradient = pao2_alveolar - pao2
        expected = (age / 4) + 4

        if gradient <= expected:
            interp = "Normal A-a gradient for age. If hypoxemic, consider hypoventilation or low FiO2."
        else:
            interp = "Elevated A-a gradient. Consider V/Q mismatch, shunt, or diffusion impairment."

        return {
            'pao2_alveolar': round(pao2_alveolar, 1),
            'aa_gradient': round(gradient, 1),
            'expected_gradient': round(expected, 1),
            'interpretation': interp
        }
    except Exception as e:
        return {'error': str(e)}


@mcp.tool()
def winters_formula(bicarbonate: float, measured_paco2: float = None) -> dict:
    """
    Winter's Formula for expected respiratory compensation in metabolic acidosis.

    Parameters:
    -----------
    bicarbonate : float
        Measured serum bicarbonate / HCO3 (mEq/L)
    measured_paco2 : float, optional
        Measured PaCO2 (mmHg). If provided, interprets compensation adequacy.

    Returns:
    --------
    dict
        expected_paco2_low, expected_paco2_high, interpretation
    """
    try:
        expected = 1.5 * bicarbonate + 8
        low = expected - 2
        high = expected + 2

        result = {
            'expected_paco2_low': round(low, 1),
            'expected_paco2_high': round(high, 1),
            'expected_paco2_mid': round(expected, 1)
        }

        if measured_paco2 is not None:
            if measured_paco2 < low:
                result['interpretation'] = "Concurrent respiratory alkalosis (overcompensation)"
            elif measured_paco2 > high:
                result['interpretation'] = "Concurrent respiratory acidosis (inadequate compensation)"
            else:
                result['interpretation'] = "Appropriate respiratory compensation"

        return result
    except Exception as e:
        return {'error': str(e)}


@mcp.tool()
def infusion_rate(weight_kg: float, dose: float, dose_unit: str, concentration: float, conc_unit: str) -> dict:
    """
    Universal IV drug infusion rate calculator.
    Calculates mL/h from weight, dose, dose unit, and drug concentration.

    Parameters:
    -----------
    weight_kg : float
        Patient body weight in kilograms
    dose : float
        Drug dose value (e.g. 0.01, 5, 100)
    dose_unit : str
        One of: "mcg/kg/min", "mcg/kg/hr", "mg/kg/min", "mg/kg/hr",
                "mcg/min", "mg/min", "mcg/hr", "mg/hr",
                "mg/kg" (bolus), "mcg/kg" (bolus)
    concentration : float
        Drug concentration value
    conc_unit : str
        One of: "mcg/mL", "mg/mL"

    Returns:
    --------
    dict
        ml_per_hr: infusion rate in mL/h (for continuous infusions)
        ml_bolus: bolus volume in mL (for bolus doses)
        dose_description: human-readable dose description
    """
    try:
        # Normalize concentration to mcg/mL
        if conc_unit == "mg/mL":
            conc_mcg_per_ml = concentration * 1000
        elif conc_unit == "mcg/mL":
            conc_mcg_per_ml = concentration
        else:
            return {'error': f'Unknown concentration unit: {conc_unit}'}

        ml_per_hr = None
        ml_bolus = None

        if dose_unit == "mcg/kg/min":
            ml_per_hr = (dose * weight_kg * 60) / conc_mcg_per_ml
        elif dose_unit == "mcg/kg/hr":
            ml_per_hr = (dose * weight_kg) / conc_mcg_per_ml
        elif dose_unit == "mg/kg/min":
            ml_per_hr = (dose * 1000 * weight_kg * 60) / conc_mcg_per_ml
        elif dose_unit == "mg/kg/hr":
            ml_per_hr = (dose * 1000 * weight_kg) / conc_mcg_per_ml
        elif dose_unit == "mcg/min":
            ml_per_hr = (dose * 60) / conc_mcg_per_ml
        elif dose_unit == "mg/min":
            ml_per_hr = (dose * 1000 * 60) / conc_mcg_per_ml
        elif dose_unit == "mcg/hr":
            ml_per_hr = dose / conc_mcg_per_ml
        elif dose_unit == "mg/hr":
            ml_per_hr = (dose * 1000) / conc_mcg_per_ml
        elif dose_unit == "mg/kg":
            ml_bolus = (dose * weight_kg * 1000) / conc_mcg_per_ml
        elif dose_unit == "mcg/kg":
            ml_bolus = (dose * weight_kg) / conc_mcg_per_ml
        else:
            return {'error': f'Unknown dose unit: {dose_unit}'}

        result = {
            'dose_description': f'{dose} {dose_unit} for {weight_kg} kg patient at {concentration} {conc_unit}'
        }
        if ml_per_hr is not None:
            result['ml_per_hr'] = round(ml_per_hr, 2)
        if ml_bolus is not None:
            result['ml_bolus'] = round(ml_bolus, 2)
        return result
    except Exception as e:
        return {'error': str(e)}


def shutdown_server():
    """Function to shutdown the server after a delay"""
    time.sleep(60)  # Wait for 3 minutes (180 seconds)
    import os
    import sys
    # Use os._exit() for a hard exit that doesn't rely on normal cleanup
    os._exit(0)
    # Alternative: sys.exit(0) for a more graceful shutdown


def main():
    # Start the shutdown timer in a separate thread
    shutdown_thread = threading.Thread(target=shutdown_server)
    shutdown_thread.daemon = True  # Set as daemon so it won't prevent the program from exiting
    shutdown_thread.start()
    
    # Run the server
    print("Starting server...")
    mcp.run()  # This will run until the shutdown timer expires


if __name__ == "__main__":
    main()

# def main():
#     mcp.run()

# if __name__ == "__main__":
#     main()
