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.
- 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
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 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": []
}
}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 two images using hash-based methods.
Parameters:
url_a(string, required): URL of the first imageurl_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": []
}
}# Using uv (recommended)
uv sync
# Or using pip
pip install -e .# Run with uv
uv run python src/main.py
# Or directly with Python
python src/main.pyThe server will start on port 8080 by default.
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=30All 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 formatUPSTREAM_ERROR- HTTP error fetching the imageRATE_LIMITED- Rate limited by image hostTIMEOUT- Request timed outPARSE_ERROR- Failed to parse image dataINTERNAL_ERROR- Unexpected server error
- 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
# Run all tests
uv run pytest
# Run with verbose output
uv run pytest -v
# Run specific test file
uv run pytest tests/test_tools.pyimage-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
MIT