Skip to main content
Glama

Medical Calculator MCP Service

psi_calculator.py17.1 kB
""" PSI (Pneumonia Severity Index) Calculator """ from typing import Dict, Any from medcalc import ( BaseCalculator, CalculatorInfo, Parameter, ParameterType, ValidationResult, CalculationResult, register_calculator ) from medcalc.utils import round_number @register_calculator("psi") class PSICalculator(BaseCalculator): """PSI肺炎严重程度指数计算器实现""" def get_info(self) -> CalculatorInfo: return CalculatorInfo( id=29, name="Pneumonia Severity Index (PSI)", category="pulmonology", description="Pneumonia severity assessment for community-acquired pneumonia risk stratification", parameters=[ Parameter( name="age", type=ParameterType.NUMERIC, required=True, min_value=0, max_value=120, description="Patient age in years" ), Parameter( name="sex", type=ParameterType.CHOICE, required=True, choices=["Male", "Female"], description="Patient sex" ), Parameter( name="nursing_home_resident", type=ParameterType.BOOLEAN, required=False, default=False, description="Nursing home resident" ), Parameter( name="neoplastic_disease", type=ParameterType.BOOLEAN, required=False, default=False, description="History of neoplastic disease" ), Parameter( name="liver_disease", type=ParameterType.BOOLEAN, required=False, default=False, description="History of liver disease" ), Parameter( name="chf", type=ParameterType.BOOLEAN, required=False, default=False, description="History of congestive heart failure" ), Parameter( name="cerebrovascular_disease", type=ParameterType.BOOLEAN, required=False, default=False, description="History of cerebrovascular disease" ), Parameter( name="renal_disease", type=ParameterType.BOOLEAN, required=False, default=False, description="History of renal disease" ), Parameter( name="altered_mental_status", type=ParameterType.BOOLEAN, required=False, default=False, description="Altered mental status" ), Parameter( name="respiratory_rate", type=ParameterType.NUMERIC, required=True, unit="breaths/min", min_value=5, max_value=80, description="Respiratory rate in breaths per minute" ), Parameter( name="systolic_bp", type=ParameterType.NUMERIC, required=True, unit="mmHg", min_value=30, max_value=300, description="Systolic blood pressure in mmHg" ), Parameter( name="temperature", type=ParameterType.NUMERIC, required=True, unit="°C", min_value=25, max_value=45, description="Body temperature in Celsius" ), Parameter( name="heart_rate", type=ParameterType.NUMERIC, required=True, unit="bpm", min_value=20, max_value=250, description="Heart rate in beats per minute" ), Parameter( name="ph", type=ParameterType.NUMERIC, required=True, min_value=6.5, max_value=8.0, description="Arterial pH" ), Parameter( name="bun", type=ParameterType.NUMERIC, required=True, unit="mg/dL", min_value=1, max_value=200, description="Blood urea nitrogen in mg/dL" ), Parameter( name="sodium", type=ParameterType.NUMERIC, required=True, unit="mmol/L", min_value=100, max_value=200, description="Serum sodium in mmol/L" ), Parameter( name="glucose", type=ParameterType.NUMERIC, required=True, unit="mg/dL", min_value=30, max_value=800, description="Serum glucose in mg/dL" ), Parameter( name="hematocrit", type=ParameterType.NUMERIC, required=True, unit="%", min_value=10, max_value=70, description="Hematocrit percentage" ), Parameter( name="pao2", type=ParameterType.NUMERIC, required=True, unit="mmHg", min_value=20, max_value=500, description="Partial pressure of oxygen in mmHg" ), Parameter( name="pleural_effusion", type=ParameterType.BOOLEAN, required=False, default=False, description="Pleural effusion on chest X-ray" ) ] ) def validate_parameters(self, parameters: Dict[str, Any]) -> ValidationResult: """验证参数""" errors = [] # 获取参数定义 param_defs = {p.name: p for p in self.get_info().parameters} # 检查必需参数 for param_name, param_def in param_defs.items(): if param_def.required and param_name not in parameters: errors.append(f"Missing required parameter: {param_name}") if errors: return ValidationResult(is_valid=False, errors=errors) # 验证数值范围 for param_name, value in parameters.items(): if param_name in param_defs: param_def = param_defs[param_name] if param_def.type == ParameterType.NUMERIC and value is not None: try: numeric_value = float(value) if param_def.min_value is not None and numeric_value < param_def.min_value: errors.append(f"Parameter {param_name}: value {numeric_value} is below minimum {param_def.min_value}") if param_def.max_value is not None and numeric_value > param_def.max_value: errors.append(f"Parameter {param_name}: value {numeric_value} is above maximum {param_def.max_value}") except (ValueError, TypeError): errors.append(f"Parameter {param_name}: invalid numeric value {value}") elif param_def.type == ParameterType.CHOICE and value is not None: if value not in param_def.choices: errors.append(f"Parameter {param_name}: value '{value}' is not in allowed choices {param_def.choices}") return ValidationResult( is_valid=len(errors) == 0, errors=errors ) def calculate(self, parameters: Dict[str, Any]) -> CalculationResult: """计算PSI评分""" # 获取参数值 age = parameters["age"] sex = parameters["sex"] nursing_home_resident = parameters.get("nursing_home_resident", False) neoplastic_disease = parameters.get("neoplastic_disease", False) liver_disease = parameters.get("liver_disease", False) chf = parameters.get("chf", False) cerebrovascular_disease = parameters.get("cerebrovascular_disease", False) renal_disease = parameters.get("renal_disease", False) altered_mental_status = parameters.get("altered_mental_status", False) respiratory_rate = parameters["respiratory_rate"] systolic_bp = parameters["systolic_bp"] temperature = parameters["temperature"] heart_rate = parameters["heart_rate"] ph = parameters["ph"] bun = parameters["bun"] sodium = parameters["sodium"] glucose = parameters["glucose"] hematocrit = parameters["hematocrit"] pao2 = parameters["pao2"] pleural_effusion = parameters.get("pleural_effusion", False) score = 0 explanation_parts = [] # 1. 年龄评分(年龄即分数) score += age explanation_parts.append(f"Age {age} years: +{age} points") # 2. 性别评分 if sex == "Female": score -= 10 explanation_parts.append("Female sex: -10 points") else: explanation_parts.append("Male sex: 0 points") # 3. 护理院居民 if nursing_home_resident: score += 10 explanation_parts.append("Nursing home resident: +10 points") # 4. 肿瘤疾病史 if neoplastic_disease: score += 30 explanation_parts.append("Neoplastic disease: +30 points") # 5. 肝病史 if liver_disease: score += 20 explanation_parts.append("Liver disease: +20 points") # 6. 充血性心力衰竭史 if chf: score += 10 explanation_parts.append("Congestive heart failure: +10 points") # 7. 脑血管疾病史 if cerebrovascular_disease: score += 10 explanation_parts.append("Cerebrovascular disease: +10 points") # 8. 肾病史 if renal_disease: score += 10 explanation_parts.append("Renal disease: +10 points") # 9. 精神状态改变 if altered_mental_status: score += 20 explanation_parts.append("Altered mental status: +20 points") # 10. 呼吸频率 if respiratory_rate >= 30: score += 20 explanation_parts.append(f"Respiratory rate {respiratory_rate} ≥30 breaths/min: +20 points") else: explanation_parts.append(f"Respiratory rate {respiratory_rate} <30 breaths/min: 0 points") # 11. 收缩压 if systolic_bp < 90: score += 20 explanation_parts.append(f"Systolic BP {systolic_bp} <90 mmHg: +20 points") else: explanation_parts.append(f"Systolic BP {systolic_bp} ≥90 mmHg: 0 points") # 12. 体温 if temperature < 35 or temperature > 39.9: score += 15 explanation_parts.append(f"Temperature {temperature}°C (<35°C or >39.9°C): +15 points") else: explanation_parts.append(f"Temperature {temperature}°C (35-39.9°C): 0 points") # 13. 心率 if heart_rate >= 125: score += 10 explanation_parts.append(f"Heart rate {heart_rate} ≥125 bpm: +10 points") else: explanation_parts.append(f"Heart rate {heart_rate} <125 bpm: 0 points") # 14. pH if ph < 7.35: score += 30 explanation_parts.append(f"pH {ph} <7.35: +30 points") else: explanation_parts.append(f"pH {ph} ≥7.35: 0 points") # 15. BUN if bun >= 30: score += 20 explanation_parts.append(f"BUN {bun} ≥30 mg/dL: +20 points") else: explanation_parts.append(f"BUN {bun} <30 mg/dL: 0 points") # 16. 钠 if sodium < 130: score += 20 explanation_parts.append(f"Sodium {sodium} <130 mmol/L: +20 points") else: explanation_parts.append(f"Sodium {sodium} ≥130 mmol/L: 0 points") # 17. 葡萄糖 if glucose >= 250: score += 10 explanation_parts.append(f"Glucose {glucose} ≥250 mg/dL: +10 points") else: explanation_parts.append(f"Glucose {glucose} <250 mg/dL: 0 points") # 18. 血细胞比容 if hematocrit < 30: score += 10 explanation_parts.append(f"Hematocrit {hematocrit}% <30%: +10 points") else: explanation_parts.append(f"Hematocrit {hematocrit}% ≥30%: 0 points") # 19. 氧分压 if pao2 < 60: score += 10 explanation_parts.append(f"PaO2 {pao2} <60 mmHg: +10 points") else: explanation_parts.append(f"PaO2 {pao2} ≥60 mmHg: 0 points") # 20. 胸腔积液 if pleural_effusion: score += 10 explanation_parts.append("Pleural effusion on X-ray: +10 points") # 生成解释 explanation = "PSI (Pneumonia Severity Index) calculation:\n\n" explanation += "\n".join([f"• {part}" for part in explanation_parts]) explanation += f"\n\nTotal PSI Score: {score} points" # 添加风险分层 if score <= 70: risk_class = "Class I" mortality_risk = "<0.1%" recommendation = "Outpatient treatment" elif score <= 85: risk_class = "Class II" mortality_risk = "0.1-0.4%" recommendation = "Outpatient treatment" elif score <= 130: risk_class = "Class III" mortality_risk = "0.4-0.9%" recommendation = "Brief inpatient observation or outpatient treatment" elif score <= 170: risk_class = "Class IV" mortality_risk = "0.9-2.8%" recommendation = "Inpatient treatment" else: risk_class = "Class V" mortality_risk = "2.8-8.2%" recommendation = "Inpatient treatment" explanation += f"\n\nRisk Classification: {risk_class}" explanation += f"\n30-day Mortality Risk: {mortality_risk}" explanation += f"\nRecommendation: {recommendation}" return CalculationResult( value=score, unit="points", explanation=explanation, metadata={ "risk_class": risk_class, "mortality_risk": mortality_risk, "recommendation": recommendation, "age_points": age, "sex_points": -10 if sex == "Female" else 0, "comorbidity_points": ( (10 if nursing_home_resident else 0) + (30 if neoplastic_disease else 0) + (20 if liver_disease else 0) + (10 if chf else 0) + (10 if cerebrovascular_disease else 0) + (10 if renal_disease else 0) ), "physical_exam_points": ( (20 if altered_mental_status else 0) + (20 if respiratory_rate >= 30 else 0) + (20 if systolic_bp < 90 else 0) + (15 if temperature < 35 or temperature > 39.9 else 0) + (10 if heart_rate >= 125 else 0) ), "laboratory_points": ( (30 if ph < 7.35 else 0) + (20 if bun >= 30 else 0) + (20 if sodium < 130 else 0) + (10 if glucose >= 250 else 0) + (10 if hematocrit < 30 else 0) + (10 if pao2 < 60 else 0) + (10 if pleural_effusion else 0) ) } )

MCP directory API

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

curl -X GET 'https://glama.ai/api/mcp/v1/servers/winninghealth/medcalcmcp'

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