Skip to content

BUZDOLAPCI/image-forensics

Repository files navigation

Image Forensics MCP Server

A lightweight MCP server for image metadata extraction and forensic analysis. Provides tools for extracting EXIF data, calculating cryptographic and perceptual hashes, and comparing images for deduplication.

Features

  • Image Facts - Extract basic image information (format, dimensions, color mode, file size)
  • EXIF Extraction - Parse EXIF metadata including camera info, dates, and GPS coordinates
  • Hash Calculation - Generate SHA-256 and perceptual hashes (pHash) for image fingerprinting
  • Image Comparison - Compare two images using hash-based similarity analysis

Tools

image_facts(url: str)

Get basic image facts from a URL.

Parameters:

  • url (string, required): URL of the image to analyze

Returns:

{
  "ok": true,
  "data": {
    "format": "JPEG",
    "width": 1920,
    "height": 1080,
    "mode": "RGB",
    "file_size_bytes": 245678
  },
  "meta": {
    "source": "https://example.com/image.jpg",
    "retrieved_at": "2024-01-15T12:00:00Z",
    "pagination": {"next_cursor": null},
    "warnings": []
  }
}

extract_exif(url: str)

Extract EXIF metadata from an image.

Parameters:

  • url (string, required): URL of the image to analyze

Returns:

{
  "ok": true,
  "data": {
    "camera_make": "Canon",
    "camera_model": "EOS R5",
    "datetime_original": "2024:01:15 10:30:00",
    "iso": 100,
    "f_number": 2.8,
    "exposure_time": 0.004,
    "focal_length": 50.0,
    "gps": {
      "latitude": 37.7749,
      "longitude": -122.4194,
      "altitude_meters": 10.5
    }
  },
  "meta": {
    "source": "https://example.com/photo.jpg",
    "retrieved_at": "2024-01-15T12:00:00Z",
    "pagination": {"next_cursor": null},
    "warnings": []
  }
}

image_hashes(url: str)

Calculate cryptographic and perceptual hashes for an image.

Parameters:

  • url (string, required): URL of the image to analyze

Returns:

{
  "ok": true,
  "data": {
    "sha256": "a1b2c3d4e5f6...",
    "phash": "d4c3b2a19080..."
  },
  "meta": {
    "source": "https://example.com/image.jpg",
    "retrieved_at": "2024-01-15T12:00:00Z",
    "pagination": {"next_cursor": null},
    "warnings": []
  }
}

compare_images(url_a: str, url_b: str)

Compare two images using hash-based methods.

Parameters:

  • url_a (string, required): URL of the first image
  • url_b (string, required): URL of the second image

Returns:

{
  "ok": true,
  "data": {
    "exact_match": false,
    "perceptual_similarity": 87.5,
    "hamming_distance": 8,
    "sha256_a": "a1b2c3d4...",
    "sha256_b": "e5f6g7h8...",
    "phash_a": "d4c3b2a1...",
    "phash_b": "d4c3b2a9..."
  },
  "meta": {
    "source": "https://example.com/a.jpg vs https://example.com/b.jpg",
    "retrieved_at": "2024-01-15T12:00:00Z",
    "pagination": {"next_cursor": null},
    "warnings": []
  }
}

Installation

# Using uv (recommended)
uv sync

# Or using pip
pip install -e .

Usage

Starting the Server

# Run with uv
uv run python src/main.py

# Or directly with Python
python src/main.py

The server will start on port 8080 by default.

Configuration

Configuration is done via environment variables. Copy .env.example to .env and customize:

# Server port (default: 8080)
PORT=8080

# Maximum image size in bytes (default: 10MB)
MAX_IMAGE_BYTES=10485760

# Request timeout in seconds (default: 30)
REQUEST_TIMEOUT=30

Error Handling

All tools return a standardized error envelope on failure:

{
  "ok": false,
  "error": {
    "code": "INVALID_INPUT",
    "message": "URL must start with http:// or https://",
    "details": {
      "field": "url",
      "value": "invalid-url"
    }
  },
  "meta": {
    "retrieved_at": "2024-01-15T12:00:00Z"
  }
}

Error Codes:

  • INVALID_INPUT - Invalid parameters or unsupported image format
  • UPSTREAM_ERROR - HTTP error fetching the image
  • RATE_LIMITED - Rate limited by image host
  • TIMEOUT - Request timed out
  • PARSE_ERROR - Failed to parse image data
  • INTERNAL_ERROR - Unexpected server error

Limitations

  • Maximum file size: 10MB by default (configurable)
  • Request timeout: 30 seconds by default (configurable)
  • Supported formats: All formats supported by Pillow (JPEG, PNG, GIF, WebP, BMP, TIFF, etc.)
  • EXIF support: Only JPEG and TIFF images typically contain EXIF data
  • No OpenCV: Uses Pillow only for lightweight operation
  • Perceptual hash: Uses pHash algorithm with 64-bit output

Testing

# Run all tests
uv run pytest

# Run with verbose output
uv run pytest -v

# Run specific test file
uv run pytest tests/test_tools.py

Development

Project Structure

image-forensics/
├── src/
│   ├── __init__.py
│   ├── main.py             # Entry point
│   ├── server.py           # MCP server configuration
│   ├── tools/
│   │   ├── __init__.py
│   │   ├── facts.py        # image_facts tool
│   │   ├── exif.py         # extract_exif tool
│   │   ├── hashes.py       # image_hashes tool
│   │   └── compare.py      # compare_images tool
│   └── utils.py            # Shared utilities
├── tests/
│   ├── __init__.py
│   ├── test_tools.py       # Unit tests
│   └── test_server.py      # E2E tests
├── pyproject.toml
├── .env.example
├── .gitignore
├── .python-version
└── README.md

License

MIT

About

MCP server for image metadata and lightweight forensics (Python)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages