Skip to main content
Glama
claudiomedina17

CardioTriage MCP Server

analyze_missing_critical_data

Identify missing or pending critical cardiovascular triage data in a synthetic case to ensure completeness before risk disposition.

Instructions

Flag missing or pending critical cardiovascular triage data for a synthetic case. Use before risk disposition. NOT for clinical use.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
case_idYes

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
case_idYes
missingYes
disclaimerNoNOT for clinical use. Synthetic demo data only. Clinician validation required.

Implementation Reference

  • The core handler function that implements the 'analyze_missing_critical_data' tool logic. It checks for missing/pending troponin, vital signs (blood pressure, heart rate, oxygen saturation), ECG interpretation, STEMI-related contraindications/red flags, heart failure markers (BNP, echo), and Chagas serology based on case data from a synthetic case.
    def analyze_missing_critical_data(case_id: str) -> MissingCriticalDataOutput:
        case = get_synthetic_case(case_id)
        missing: list[MissingCriticalDataItem] = []
    
        lab_keys = {key.lower(): value for key, value in case.labs.items()}
        troponin = lab_keys.get("troponin")
        if troponin is None:
            missing.append(
                MissingCriticalDataItem(
                    field="troponin",
                    status="missing",
                    why_critical="Troponin is needed to support ACS rule-in/rule-out and serial trend assessment.",
                    suggested_action="Obtain baseline and repeat troponin per local ED protocol.",
                )
            )
        elif "pending" in troponin.lower():
            missing.append(
                MissingCriticalDataItem(
                    field="troponin",
                    status="pending",
                    why_critical="A pending troponin does not yet complete ACS risk stratification.",
                    suggested_action="Track result availability and repeat if symptoms or timing require serial testing.",
                )
            )
    
        vital_keys = {key.lower() for key in case.vitals}
        required_vitals = {
            "blood pressure": "Hemodynamic status changes immediate triage priority.",
            "heart rate": "Tachycardia or bradycardia can signal instability or arrhythmia.",
            "oxygen saturation": "Hypoxemia changes escalation and differential diagnosis.",
        }
        for field, why in required_vitals.items():
            if field not in vital_keys:
                missing.append(
                    MissingCriticalDataItem(
                        field=field,
                        status="missing",
                        why_critical=why,
                        suggested_action=f"Document {field} before risk disposition.",
                    )
                )
    
        if not case.ecg:
            missing.append(
                MissingCriticalDataItem(
                    field="ECG interpretation",
                    status="missing",
                    why_critical="ECG interpretation is central to STEMI/NSTEMI and arrhythmia triage.",
                    suggested_action="Document clinician-reviewed ECG interpretation.",
                )
            )
    
        text = f"{case.presenting_problem} {case.ecg}".lower()
        if "st-elevation" in text or "stemi" in text:
            missing.append(
                MissingCriticalDataItem(
                    field="reperfusion/antithrombotic contraindications",
                    status="missing",
                    why_critical="High-risk ACS pathways require contraindication review before therapy decisions.",
                    suggested_action="Document bleeding risk, allergy history, anticoagulant use, and reperfusion contraindications.",
                )
            )
            missing.append(
                MissingCriticalDataItem(
                    field="red flags review",
                    status="incomplete",
                    why_critical="Ongoing pain, syncope, shock, or malignant arrhythmia would change escalation urgency.",
                    suggested_action="Document structured red flags review and escalation status.",
                )
            )
    
        if "heart failure" in text or "dyspnea" in text or "cardiomyopathy" in text:
            missing.extend(
                [
                    MissingCriticalDataItem(
                        field="BNP/NT-proBNP",
                        status="missing",
                        why_critical="Natriuretic peptide data helps support or refute acute heart failure.",
                        suggested_action="Order BNP or NT-proBNP if available.",
                    ),
                    MissingCriticalDataItem(
                        field="echocardiography",
                        status="missing",
                        why_critical="Echo helps characterize ventricular function, valvular disease, and cardiomyopathy pattern.",
                        suggested_action="Request focused or formal echocardiography based on local availability.",
                    ),
                ]
            )
    
        if "chagas" in text:
            missing.extend(
                [
                    MissingCriticalDataItem(
                        field="Chagas serology",
                        status="missing",
                        why_critical="Synthetic Latam endemic-origin context raises Chagas cardiomyopathy as a differential.",
                        suggested_action="Document epidemiologic risk and order confirmatory serology if clinically appropriate.",
                    ),
                ]
            )
    
        return MissingCriticalDataOutput(case_id=case.case_id, missing=missing)
  • server/main.py:160-163 (registration)
    The tool is registered with FastMCP via server.tool()(analyze_missing_critical_data) inside the register_tools function. Also listed in REGISTERED_TOOL_NAMES on line 27.
    def register_tools(server: FastMCP) -> None:
        server.tool()(list_synthetic_cases)
        server.tool()(get_fhir_case_bundle)
        server.tool()(analyze_missing_critical_data)
  • Pydantic models MissingCriticalDataItem (field, status, why_critical, suggested_action) and MissingCriticalDataOutput (case_id, missing list, disclaimer) define the input/output schema for the tool.
    class MissingCriticalDataItem(BaseModel):
        field: str
        status: Literal["missing", "pending", "incomplete"]
        why_critical: str
        suggested_action: str
    
    
    class MissingCriticalDataOutput(BaseModel):
        case_id: str
        missing: list[MissingCriticalDataItem]
        disclaimer: str = DISCLAIMER
  • The MCP-facing wrapper function in server/main.py that delegates to the actual implementation in server/tools/analyze_missing.py. Provides the tool's description for the MCP registry.
    def analyze_missing_critical_data(case_id: str) -> MissingCriticalDataOutput:
        """Flag missing or pending critical cardiovascular triage data for a synthetic case. Use before risk disposition. NOT for clinical use."""
    
        return analyze_missing_tool(case_id)
  • The handoff note tool directly imports and calls analyze_missing_critical_data on line 10, integrating missing data findings into the generated SBAR note.
    from backend.fhir_bundle import get_synthetic_case
    from server.models import HandoffNote, HandoffNoteOutput, Language
    from server.tools.analyze_missing import analyze_missing_critical_data
    from server.tools.summarize_risk import summarize_cardiovascular_risk_signals
    
    
    def generate_structured_handoff_note(case_id: str, language: Language = "en") -> HandoffNoteOutput:
        case = get_synthetic_case(case_id)
        risk = summarize_cardiovascular_risk_signals(case.case_id)
        missing = analyze_missing_critical_data(case.case_id)
        recommendations = _recommendations(case.case_id)
    
        note = HandoffNote(
            situation=f"Synthetic {case.case_id}: {case.presenting_problem}.",
            background=(
                f"{case.age}-year-old {case.sex}; vitals: {_format_dict(case.vitals)}; "
                f"labs: {_format_dict(case.labs) if case.labs else 'none documented'}; ECG: {case.ecg}."
            ),
            assessment=_assessment(case.case_id, risk),
            recommendation=recommendations,
            safety=_safety(language),
        )
        text = _render_sbar(note, missing_fields=[item.field for item in missing.missing], language=language)
        return HandoffNoteOutput(case_id=case.case_id, language=language, note=note, text=text)
Behavior3/5

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

No annotations provided, so the description must convey behavior. It reveals a flagging operation, but lacks detail on what specific data is considered critical or how missing vs pending is determined. An output schema exists but is not described.

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

Conciseness5/5

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

Two sentences, no excessive words, meaning front-loaded in the first sentence. Perfectly concise for the information conveyed.

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

Completeness4/5

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

Given a simple tool with one parameter and an output schema, the description covers purpose, usage timing, and a safety warning. Could elaborate on what constitutes 'critical cardiovascular triage data' or the output shape, but overall adequate.

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

Parameters2/5

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

Schema coverage is 0%, and the description does not explain the 'case_id' parameter beyond its existence. While the parameter name is self-explanatory, the description misses the chance to add context about its format or source.

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

Purpose5/5

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

Description clearly states the tool flags missing or pending critical cardiovascular triage data for a synthetic case, distinguishing it from siblings like ECG interpretation or risk summarization. Including 'Use before risk disposition' further clarifies its role.

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

Usage Guidelines4/5

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

Explicitly says 'Use before risk disposition' and 'NOT for clinical use', providing clear context. Does not mention alternatives, but the purpose is distinct enough from siblings to be inferred.

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

Install Server

Other Tools

Latest Blog Posts

MCP directory API

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

curl -X GET 'https://glama.ai/api/mcp/v1/servers/claudiomedina17/cardiotriage-mcp'

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