How ClinResolve Turns Conflicting Drug Evidence into Deterministic MCP Decisions

Sharvari Raut
Sharvari Raut
How ClinResolve Turns Conflicting Drug Evidence into Deterministic MCP Decisions
How ClinResolve Turns Conflicting Drug Evidence into Deterministic MCP Decisions

ClinResolve is a clinical decision support prototype that pulls medication evidence from eight separate databases, reconciles the disagreements between them, and produces a prescribing recommendation with a reasoning trail a clinician can actually audit. It's built on the NitroStack SDK as an MCP server, and its most interesting design choice is what it refuses to let a language model do.

What this enables

  • Reconciles medication evidence from eight sources, including RxNorm, OpenFDA, and PubMed, in one call
  • Ranks conflicting sources by clinical authority instead of averaging or guessing between them
  • Runs prescribing logic through a five-stage deterministic pipeline, not a language model
  • Flags hard contraindications, such as NSAIDs for a patient in CKD Stage 4, as automatic overrides
  • Surfaces the decision as a widget with risk level, confidence score, and any missing evidence called out

What ClinResolve is

ClinResolve is a Model Context Protocol server for medication safety review, built with TypeScript on the NitroStack SDK. A prescriber, pharmacist, or clinical reviewer selects a patient, asks about a drug, and the server pulls that drug's profile from eight external and internal sources: RxNorm, OpenFDA, DailyMed, PubMed, ClinicalTrials.gov, and hospital-specific guideline data among them. The intended user is someone who needs a second, evidence-backed opinion before a prescription goes out, not someone who wants a chatbot to summarize a drug label.

Why one clean answer is hard to get

Clinical databases don't agree with each other. RxNorm might list an interaction that DailyMed doesn't flag as prominently, or a hospital's internal guideline might be stricter than what a public FDA source implies. A system that simply hands all of this to a language model and asks it to "decide" inherits two problems at once: it can't explain why it weighted one source over another, and its output isn't reproducible from the same inputs. In a medication-safety context, both failures matter. A recommendation that can't cite its own reasoning is hard to defend in an audit, and one that isn't deterministic can't be trusted to behave the same way twice for the same patient and the same drug.

That's the actual constraint ClinResolve is built around: reconcile disagreement across sources, and keep the safety logic outside the language model entirely.

Why MCP fits here

MCP gives ClinResolve a clean split between the parts of the system that must be deterministic and the parts that are allowed to be conversational. The decision pipeline runs as ordinary application code, exposed as MCP tools with fixed inputs and outputs. The explanation layer, turning a computed decision into a physician's note or a plain-language summary for a patient, runs as MCP prompts, which is where letting a model generate language is actually appropriate. The same tool set works whether the caller is NitroStudio during development or a production MCP client later.

The build

ClinResolve exposes five tools to the calling agent: list-patients and select-patient load patient context, collect-evidence reconciles a drug's profile across the eight sources and surfaces conflicts, generate-decision runs the full pipeline, and get-audit-history retrieves prior decisions from the session.

The decision pipeline itself is split into five sub-engines rather than one large function:

  1. A DrugKnowledgeEngine normalizes the differently-shaped responses from each provider into one structured drug profile.
  2. A ClinicalRuleEngine evaluates contraindications deterministically against that profile.
  3. A RiskScoringEngine scores the result from LOW to CRITICAL using patient context.
  4. An EvidenceConfidenceEngine calculates a confidence score, and lowers it when a provider times out or fails to respond.
  5. A SafetyCheckEngine applies hard overrides for known dangerous combinations, regardless of what the risk score alone would suggest.
Article image

Once a decision exists, ClinResolve doesn't stop at a verdict. Seven MCP prompts, including explain-decision, summarize-evidence, explain-conflict, and role-specific report generators for physicians, pharmacists, and patients, turn the deterministic output into language appropriate for whoever is reading it. The conflict-explanation prompt is worth calling out specifically: it doesn't just report that two sources disagreed, it narrates why the trust engine preferred one over the other.

Where NitroStack fits

The tool and prompt boundary is structured with the NitroStack SDK, which keeps the deterministic engines as ordinary, testable TypeScript modules behind typed MCP tool definitions rather than folding decision logic into prompt text. During development, the project is run and inspected through NitroStudio: a reviewer can select a patient, call collect-evidence for a specific drug, and see the resulting source list and conflict data directly, without going through a chat client. On the output side, NitroStack Widgets render the result as a Decision Card showing risk level, confidence score, and any missing evidence, alongside an Evidence Graph and audit history view. A text response from an LLM would be a poor substitute for showing a clinician a confidence gap at a glance.

Why the pipeline being boring is the point

The unglamorous part of ClinResolve is also the important part: the actual prescribing logic never touches the language model. An LLM can hallucinate a dosage or misremember an interaction; a five-stage pipeline built from ordinary conditional logic either flags a contraindication or it doesn't. The model's job is downstream, narrating a decision that's already been made deterministically. That's a deliberate trade-off. It means ClinResolve can't reason about a scenario the pipeline wasn't built to handle, which is a real limitation compared to a more open-ended LLM-driven system. Even so, it's the correct trade-off for a domain where reproducibility matters more than flexibility.

What the prototype demonstrates

ClinResolve runs against fixture patient data rather than a live hospital feed, so it hasn't been validated in a production clinical setting and shouldn't be read as one. What it does demonstrate is that a multi-source evidence reconciliation problem, the kind that normally lives inside a monolithic clinical application, can be decomposed into MCP tools an agent calls directly, with the safety-critical logic kept outside the model's reasoning path entirely. Running the tools through NitroStudio also shows that the underlying decision engine can be inspected and tested independently of whatever chat interface eventually sits in front of it.

The reusable pattern

The lesson here isn't "MCP works for healthcare." It's narrower and more useful: when a workflow needs both auditable determinism and natural-language explanation, don't ask one model to do both jobs. Keep the decision logic as deterministic application code exposed through typed tools, and reserve the language model for the prompts that turn a finished decision into a note a person can read. That split generalizes past medication review to any domain where a wrong, unexplainable answer is more costly than a slow one.

If you want to see ClinResolve in action, check out the complete video here.

It walks through the MCP server, the evidence reconciliation workflow, how the five-stage pipeline scores and overrides risky prescriptions, and how the Decision Card widget surfaces confidence and missing evidence to a reviewer.

To explore the implementation in more detail, head over to the NitroStack docs for guides on building tools, resources, and prompts, testing MCP servers in NitroStudio, and deploying them through NitroCloud.

Check out the complete code here. You can also read the source and build your own MCP application using the same SDK and workflow at nitrostack.ai.