DEV Community

Beck_Moulton
Beck_Moulton

Posted on

From Static PDFs to Living Data: Connecting Local EMRs to Claude using Model Context Protocol (MCP)

In the rapidly evolving world of AI Agents and LLM automation, the biggest bottleneck isn't the model's intelligence—it's the context. How do we give an AI safe, structured access to sensitive local data like Electronic Medical Records (EMR) without uploading everything to the cloud?

Today, we are diving into the Model Context Protocol (MCP), a game-changing standard introduced by Anthropic. We’ll build a medical assistant that can browse local patient histories, parse PDFs, and provide structured clinical insights directly within Claude Desktop. By leveraging the MCP SDK and Python, we are moving past simple RAG into true tool-use orchestration.


The Architecture: How MCP Bridges the Gap

The Model Context Protocol acts as a universal translator between an AI model (the client) and your local data sources (the server). Instead of the AI "guessing," it calls specific tools to fetch exactly what it needs.

graph TD
    A[Claude Desktop Client] -- MCP Protocol --> B[Local MCP Server]
    B -- Query --> C[(SQLite Index)]
    B -- Read --> D[Local PDF Repository]
    C -- Metadata --> B
    D -- Content Extraction --> B
    B -- Structured Context --> A
    A -- Reasoning --> E[Medical Advice / Summary]
Enter fullscreen mode Exit fullscreen mode

Prerequisites

To follow this tutorial, you'll need:

  • Claude Desktop installed.
  • Python 3.10+ (we'll use the mcp Python SDK).
  • A directory of sample PDF medical records.
  • SQLite (built-in with Python) for indexing file metadata.

Step 1: Setting Up the MCP Server

First, let's initialize our environment. The MCP SDK allows us to define "tools" that Claude can invoke.

pip install mcp langchain-community pypdf pysqlite3
Enter fullscreen mode Exit fullscreen mode

Now, let's create our server file, medical_mcp_server.py. We want Claude to be able to list patients and read specific clinical notes.

from mcp.server.fastmcp import FastMCP
import sqlite3
import os
from pypdf import PdfReader

# Initialize FastMCP Server
mcp = FastMCP("MedicalRecordExplorer")

DB_PATH = "patients.db"

@mcp.tool()
def search_patients(query: str) -> str:
    """Search for patients in the local SQLite database by name or ID."""
    conn = sqlite3.connect(DB_PATH)
    cursor = conn.cursor()
    cursor.execute("SELECT id, name, dob FROM patients WHERE name LIKE ?", (f"%{query}%",))
    results = cursor.fetchall()
    conn.close()
    return f"Found patients: {results}"

@mcp.tool()
def read_patient_record(file_path: str) -> str:
    """Read and extract text from a local PDF medical record."""
    if not os.path.exists(file_path):
        return "Error: File not found."

    reader = PdfReader(file_path)
    text = ""
    for page in reader.pages:
        text += page.extract_text()

    return f"Content of {file_path}:\n\n{text[:2000]}..." # Returning first 2k chars for context

if __name__ == "__main__":
    mcp.run()
Enter fullscreen mode Exit fullscreen mode

Step 2: Creating the Local Index

For the Agent to know which files exist, we need a lightweight index. This keeps our Model Context Protocol server fast.

# simple_init_db.py
import sqlite3

def setup_db():
    conn = sqlite3.connect("patients.db")
    curr = conn.cursor()
    curr.execute("CREATE TABLE IF NOT EXISTS patients (id INT, name TEXT, dob TEXT)")
    curr.execute("INSERT INTO patients VALUES (1, 'John Doe', '1985-05-12')")
    curr.execute("INSERT INTO patients VALUES (2, 'Jane Smith', '1992-08-24')")
    conn.commit()
    conn.close()

setup_db()
Enter fullscreen mode Exit fullscreen mode

Step 3: Connecting to Claude Desktop

To make Claude aware of our new medical powers, we need to edit the claude_desktop_config.json file.

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json

Add your server configuration:

{
  "mcpServers": {
    "medical-assistant": {
      "command": "python",
      "args": ["/absolute/path/to/medical_mcp_server.py"]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Restart Claude Desktop, and you’ll see a 🔌 icon indicating the MCP Server is active!


The "Official" Way: Advanced Patterns

While this local setup is great for a POC, production-grade medical agents require robust HIPAA-compliant auditing, advanced vector search for RAG, and multi-agent orchestration.

For a deeper look into production-ready AI architectures and how to scale these protocols in a healthcare environment, I highly recommend checking out the technical deep dives at WellAlly Blog. They cover advanced topics like:

  • Securing LLM tool-calling in regulated industries.
  • Optimized PDF parsing for complex clinical tables.
  • Building autonomous agents with LangGraph and MCP.

Step 4: Testing the Agent

Now, open Claude and try a natural language prompt:

"Hey Claude, search for a patient named John Doe and summarize his latest clinical note from the local PDF folder."

What happens behind the scenes?

  1. Claude recognizes the intent to "search."
  2. Claude calls the search_patients tool via MCP.
  3. Claude receives the ID and file path.
  4. Claude calls read_patient_record to pull the text.
  5. Claude summarizes the findings for you locally.

This approach ensures your data stays on your machine, only providing the LLM with the specific text needed for the current turn of the conversation.


Conclusion: The Future is Modular

The Model Context Protocol is more than just a plugin system; it's a fundamental shift in how we build Medical AI Agents. By decoupling the data source from the reasoning engine, we gain privacy, flexibility, and speed.

Are you building with MCP? What local data sources are you connecting first? Let me know in the comments below! 👇

Happy coding!

Top comments (0)