Built for the Wisconsin Reading Center
GitHub

Data Quality Agent

Automated retinal image quality assessment for the Wisconsin Reading Center. MCP server with classical computer vision and deep learning checks.

MCP Protocol Streamable HTTP 8 Quality Tools

What is this?

A Model Context Protocol (MCP) server that accepts retinal fundus image URLs and evaluates them for diagnostic quality. It runs 7 classical computer vision checks plus an optional deep learning model (EyeQ/MCF-Net) and returns an ACCEPT, REVIEW, or REJECT verdict.

Connect this server to OpenCode, Claude Desktop, or any MCP-compatible assistant to quality-gate images before human grading.

MCP Endpoint

POST /mcp

Streamable HTTP transport. JSON-RPC 2.0 with headers Content-Type: application/json and Accept: application/json, text/event-stream

Tools

tool_check_image_quality

Full Quality Report — Primary Tool

Runs ALL checks and returns a combined verdict with individual results. Use this for a single comprehensive assessment.

Input Parameters
{
  "image_url": {
    "type": "string",
    "format": "uri",
    "required": true,
    "description": "Publicly accessible URL of the image to check"
  }
}
Output Schema — QualityReport
{
  "verdict": "accept" | "review" | "reject",
  "checks": [
    {
      "name": "string",        // e.g. "sharpness", "resolution"
      "passed": true | false,
      "detail": "string"       // human-readable explanation
    }
  ],
  "fundus_assessment": {       // null if EyeQ unavailable
    "grade": "good" | "usable" | "reject",
    "confidence": 0.95,
    "probabilities": {
      "good": 0.95, "usable": 0.04, "reject": 0.01
    }
  },
  "image_url": "string"
}

tool_check_sharpness

Blur Detection

Laplacian variance analysis. Score >150 = sharp, <80 = blurry.

Input Parameters
{
  "image_url": {
    "type": "string", "format": "uri",
    "required": true,
    "description": "Public image URL"
  }
}
Output — SharpnessResult
{
  "score": 155.3,       // Laplacian variance
  "is_sharp": true,     // pass/fail
  "detail": "string"
}

tool_check_resolution

Dimension Validation

Checks width/height against minimums (default 1024×1024).

Input Parameters
{
  "image_url": {
    "type": "string", "format": "uri",
    "required": true,
    "description": "Public image URL"
  }
}
Output — ResolutionResult
{
  "width": 2048,
  "height": 2048,
  "meets_minimum": true,
  "megapixels": 4.19
}

tool_check_format

Format & Corruption

Validates file type via magic bytes. Detects truncated or corrupted files.

Input Parameters
{
  "image_url": {
    "type": "string", "format": "uri",
    "required": true,
    "description": "Public image URL"
  }
}
Output — FormatResult
{
  "format": "JPEG",
  "valid": true,
  "corrupted": false,
  "detail": "string"
}

tool_check_illumination

Exposure & Vignetting

Brightness uniformity, over/underexposure, and dark-corner detection.

Input Parameters
{
  "image_url": {
    "type": "string", "format": "uri",
    "required": true,
    "description": "Public image URL"
  }
}
Output — IlluminationResult
{
  "mean_brightness": 128.5,
  "std_brightness": 42.3,
  "uniform": true,
  "vignetting_detected": false,
  "detail": "string"
}

tool_check_color

Color Balance

RGB validation and channel imbalance detection (tint, wash-out).

Input Parameters
{
  "image_url": {
    "type": "string", "format": "uri",
    "required": true,
    "description": "Public image URL"
  }
}
Output — ColorResult
{
  "mode": "RGB",
  "channels": 3,
  "balanced": true,
  "channel_means": [130.2, 125.8, 122.1],
  "detail": "string"
}

tool_validate_metadata

EXIF Extraction

Extracts camera model, capture date, dimensions, and other metadata.

Input Parameters
{
  "image_url": {
    "type": "string", "format": "uri",
    "required": true,
    "description": "Public image URL"
  }
}
Output — MetadataResult
{
  "has_exif": true,
  "fields": {
    "Make": "Canon",
    "Model": "EOS R5",
    "DateTime": "2026:03:15 14:30:00"
  }
}

tool_assess_fundus_quality

Deep Learning — EyeQ / MCF-Net

DenseNet121-based multi-color-space fusion model trained on fundus images. Processes in RGB, HSV, and LAB and returns Good / Usable / Reject with confidence scores.

Input Parameters
{
  "image_url": {
    "type": "string", "format": "uri",
    "required": true,
    "description": "Public URL of a fundus/retinal image"
  }
}
Output — FundusAssessment
{
  "grade": "good" | "usable" | "reject",
  "confidence": 0.95,
  "probabilities": {
    "good": 0.95,
    "usable": 0.04,
    "reject": 0.01
  }
}

All tools accept a single parameter: image_url (string) — a publicly accessible image URL.

Connect Your Agent

OpenCode

{
  "mcp": {
    "data-quality": {
      "type": "remote",
      "url": "https://YOUR_DEPLOYMENT_URL/mcp",
      "enabled": true
    }
  }
}

Claude Desktop

{
  "mcpServers": {
    "data-quality": {
      "url": "https://YOUR_DEPLOYMENT_URL/mcp"
    }
  }
}

Test with curl

1. Initialize session

curl -X POST /mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{
    "protocolVersion":"2025-03-26","capabilities":{},
    "clientInfo":{"name":"test","version":"0.1"}}}' \
  -i

Copy the Mcp-Session-Id header from the response.

2. List tools

curl -X POST /mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "Mcp-Session-Id: YOUR_SESSION_ID" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}'

3. Run full quality check

curl -X POST /mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "Mcp-Session-Id: YOUR_SESSION_ID" \
  -d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{
    "name":"tool_check_image_quality",
    "arguments":{"image_url":"https://picsum.photos/2048/2048.jpg"}}}'

Configuration

All thresholds are configurable via environment variables:

VariableDefaultDescription
QUALITY_SHARPNESS_PASS150Sharpness score to pass
QUALITY_SHARPNESS_REVIEW80Sharpness score for review
QUALITY_MIN_WIDTH1024Minimum image width (px)
QUALITY_MIN_HEIGHT1024Minimum image height (px)
QUALITY_BRIGHTNESS_MIN_PASS60Min brightness to pass
QUALITY_BRIGHTNESS_MAX_PASS200Max brightness to pass
QUALITY_COLOR_BALANCE_PASS30Max channel diff to pass
QUALITY_ALLOWED_FORMATSJPEG,PNG,TIFF,BMPAccepted file formats
QUALITY_EYEQ_ENABLEDtrueEnable EyeQ deep learning

Tech Stack

Python · Pydantic · FastMCP · OpenCV · Pillow · PyTorch + EyeQ/MCF-Net · Vercel