Opticmcp — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Opticmcp (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
A Model Context Protocol (MCP) server that provides camera/vision tools for AI assistants. Connect to cameras and capture images for use with LLMs.
OpticMCP aims to be a universal camera interface for AI assistants, supporting any camera type:
pip install optic-mcpOr with uv:
uv pip install optic-mcp# Clone the repository
git clone https://github.com/Timorleiderman/OpticMCP.git
cd OpticMCP
# Install dependencies with uv
uv syncIf installed from PyPI:
optic-mcpOr with uvx (no installation required):
uvx optic-mcpuv run optic-mcpAdd to your Claude Desktop configuration file:
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json Windows: %APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"optic-mcp": {
"command": "uvx",
"args": ["optic-mcp"]
}
}
}Add to your opencode.json (in .opencode/ in your project directory or ~/.opencode/ globally):
{
"mcp": {
"optic-mcp": {
"type": "local",
"command": ["uvx", "optic-mcp"]
}
}
}Using uvx (recommended - no installation required):
{
"mcpServers": {
"optic-mcp": {
"command": "uvx",
"args": ["optic-mcp"]
}
}
}Using pip installation:
{
"mcpServers": {
"optic-mcp": {
"command": "optic-mcp"
}
}
}From source:
{
"mcpServers": {
"optic-mcp": {
"command": "uv",
"args": ["run", "--directory", "/path/to/OpticMCP", "optic-mcp"]
}
}
}Scans for available USB cameras (indices 0-9) and returns their status.
[
{
"index": 0,
"status": "available",
"backend": "AVFOUNDATION",
"description": "Camera 0 (AVFOUNDATION)"
}
]Captures a frame and saves it to disk.
Parameters:
file_path (str) - Path where the image will be savedcamera_index (int, default: 0) - Camera index to capture fromReturns: Success message with file path
Stream cameras to a local HTTP server for real-time viewing in any browser.
#### start_stream
Start streaming a camera to a localhost HTTP server. The stream uses MJPEG format which is widely supported.
Parameters:
camera_index (int, default: 0) - Camera index to streamport (int, default: 8080) - Port to serve the stream onReturns: Dictionary with stream URLs and status
{
"status": "started",
"camera_index": 0,
"port": 8080,
"url": "http://localhost:8080",
"stream_url": "http://localhost:8080/stream"
}Usage:
http://localhost:8080 in a browser to view the stream with a simple UIhttp://localhost:8080/stream for the raw MJPEG stream (can be embedded in other applications)#### stop_stream
Stop streaming a camera.
Parameters:
camera_index (int, default: 0) - Camera index to stop streamingReturns: Dictionary with status
#### list_streams
List all active camera streams.
Returns: List of active stream information including URLs and ports
#### start_dashboard
Start a dynamic multi-camera dashboard server. The dashboard automatically detects all active camera streams and displays them in a responsive grid layout.
Parameters:
port (int, default: 9000) - Port to serve the dashboard onReturns: Dictionary with dashboard URL and status
{
"status": "started",
"port": 9000,
"url": "http://localhost:9000"
}Usage:
start_streamstart_dashboardhttp://localhost:9000 in a browser#### stop_dashboard
Stop the dashboard server.
Returns: Dictionary with status
Note: RTSP functionality has not been tested with real RTSP hardware/streams. It is implemented but may require adjustments for specific camera vendors.
#### rtsp_save_image
Captures a frame from an RTSP stream and saves it to disk.
Parameters:
rtsp_url (str) - RTSP stream URL (e.g., rtsp://ip:554/stream)file_path (str) - Path where the image will be savedtimeout_seconds (int, default: 10) - Connection timeoutReturns: Success message with file path
#### rtsp_check_stream
Validates an RTSP stream and returns stream information.
Parameters:
rtsp_url (str) - RTSP stream URL to validatetimeout_seconds (int, default: 10) - Connection timeoutReturns: Dictionary with stream status and properties (width, height, fps, codec)
#### hls_save_image
Captures a frame from an HLS stream and saves it to disk.
Parameters:
hls_url (str) - HLS stream URL (typically ending in .m3u8)file_path (str) - Path where the image will be savedtimeout_seconds (int, default: 30) - Connection timeoutReturns: Success message with file path
#### hls_check_stream
Validates an HLS stream and returns stream information.
Parameters:
hls_url (str) - HLS stream URL to validatetimeout_seconds (int, default: 30) - Connection timeoutReturns: Dictionary with stream status and properties (width, height, fps, codec)
#### mjpeg_save_image
Captures a frame from an MJPEG stream (common in IP cameras, ESP32-CAM, Arduino cameras).
Parameters:
mjpeg_url (str) - MJPEG stream URL (e.g., http://camera/video.mjpg)file_path (str) - Path where the image will be savedtimeout_seconds (int, default: 10) - Connection timeoutReturns: Dictionary with status, file_path, and size_bytes
#### mjpeg_check_stream
Validates an MJPEG stream URL.
Parameters:
mjpeg_url (str) - MJPEG stream URL to validatetimeout_seconds (int, default: 10) - Connection timeoutReturns: Dictionary with status, url, and content_type
#### screen_list_monitors
Lists all available monitors/displays.
Returns: List of monitors with id, dimensions, and position
#### screen_save_image
Captures a full screenshot of a monitor.
Parameters:
file_path (str) - Path where the image will be savedmonitor (int, default: 0) - Monitor index (0 = all monitors combined)Returns: Dictionary with status, file_path, and dimensions
#### screen_save_region
Captures a specific region of the screen.
Parameters:
file_path (str) - Path where the image will be savedx (int) - X coordinate of top-left cornery (int) - Y coordinate of top-left cornerwidth (int) - Width in pixelsheight (int) - Height in pixelsReturns: Dictionary with status, file_path, and region details
#### http_save_image
Downloads an image from a URL and saves it to disk.
Parameters:
url (str) - Image URL (http:// or https://)file_path (str) - Path where the image will be savedtimeout_seconds (int, default: 30) - Connection timeoutReturns: Dictionary with status, file_path, size_bytes, and content_type
#### http_check_image
Validates an image URL using a HEAD request.
Parameters:
url (str) - Image URL to validatetimeout_seconds (int, default: 10) - Connection timeoutReturns: Dictionary with status, content_type, and size_bytes
Note: These tools require thelibzbarsystem library. Install with:brew install zbar(macOS) orapt install libzbar0(Linux)
#### decode_qr
Decodes QR codes from an image file.
Parameters:
file_path (str) - Path to the image fileReturns: Dictionary with found, count, and codes list
#### decode_barcode
Decodes barcodes (EAN, UPC, Code128, etc.) from an image file.
Parameters:
file_path (str) - Path to the image fileReturns: Dictionary with found, count, and codes list
#### decode_all
Decodes all QR codes and barcodes from an image file.
Parameters:
file_path (str) - Path to the image fileReturns: Dictionary with found, count, and codes list
#### decode_and_annotate
Decodes codes and saves an annotated image with bounding boxes.
Parameters:
file_path (str) - Path to the input imageoutput_path (str) - Path for the annotated output imageReturns: Dictionary with found, count, output_path, and codes list
#### image_get_metadata
Extracts metadata from an image file including dimensions, format, and EXIF data.
Parameters:
file_path (str) - Path to the image fileReturns: Dictionary with width, height, format, mode, file_size_bytes, and exif dict
{
"width": 1920,
"height": 1080,
"format": "JPEG",
"mode": "RGB",
"file_size_bytes": 245678,
"exif": {"Make": "Canon", "Model": "EOS R5", ...}
}#### image_get_stats
Calculates basic image statistics including brightness, contrast, and sharpness.
Parameters:
file_path (str) - Path to the image fileReturns: Dictionary with brightness (0-1), contrast (0-1), sharpness, and is_grayscale
{
"brightness": 0.65,
"contrast": 0.42,
"sharpness": 2.35,
"is_grayscale": false
}#### image_get_histogram
Calculates color histogram for each channel (R, G, B) with optional visualization.
Parameters:
file_path (str) - Path to the image fileoutput_path (str, optional) - Path to save histogram visualizationReturns: Dictionary with channels (r, g, b arrays of 256 values) and output_path if provided
#### image_get_dominant_colors
Extracts dominant colors using K-means clustering.
Parameters:
file_path (str) - Path to the image filenum_colors (int, default: 5) - Number of colors to extract (1-20)Returns: List of colors with RGB values, hex codes, and percentages
{
"colors": [
{"rgb": [64, 128, 192], "hex": "#4080C0", "percentage": 35.2},
{"rgb": [255, 255, 255], "hex": "#FFFFFF", "percentage": 28.1}
]
}#### image_compare_ssim
Compares two images using Structural Similarity Index (SSIM).
Parameters:
file_path_1 (str) - Path to first imagefile_path_2 (str) - Path to second imagethreshold (float, default: 0.95) - Similarity thresholdReturns: Dictionary with ssim_score (-1 to 1), is_similar, and threshold
{
"ssim_score": 0.9823,
"is_similar": true,
"threshold": 0.95
}#### image_compare_mse
Compares two images using Mean Squared Error.
Parameters:
file_path_1 (str) - Path to first imagefile_path_2 (str) - Path to second imageReturns: Dictionary with mse, is_identical, and normalized_mse (0-1)
#### image_compare_hash
Compares two images using perceptual hashing.
Parameters:
file_path_1 (str) - Path to first imagefile_path_2 (str) - Path to second imagehash_type (str, default: "phash") - Hash type: "phash", "dhash", or "ahash"Returns: Dictionary with hash_1, hash_2, distance, is_similar, and hash_type
{
"hash_1": "8f0f0f0f0f0f0f0f",
"hash_2": "8f0f0f0f0f0f0f0f",
"distance": 0,
"is_similar": true,
"hash_type": "phash"
}#### image_get_hash
Generates a perceptual hash for a single image.
Parameters:
file_path (str) - Path to the image filehash_type (str, default: "phash") - Hash type: "phash", "dhash", or "ahash"Returns: Dictionary with hash (hex string) and hash_type
#### image_diff
Creates a visual diff highlighting differences between two images.
Parameters:
file_path_1 (str) - Path to reference imagefile_path_2 (str) - Path to comparison imageoutput_path (str) - Path to save diff visualizationthreshold (int, default: 30) - Pixel difference threshold (0-255)Returns: Dictionary with status, output_path, diff_percentage, and diff_pixels
{
"status": "success",
"output_path": "/path/to/diff.png",
"diff_percentage": 12.5,
"diff_pixels": 25600
}#### image_compare_histograms
Compares two images by their color histograms.
Parameters:
file_path_1 (str) - Path to first imagefile_path_2 (str) - Path to second imagemethod (str, default: "correlation") - Method: "correlation", "chi_square", "intersection", "bhattacharyya"Returns: Dictionary with score, method, and is_similar
#### detect_faces
Detects faces in an image using Haar cascades or DNN.
Parameters:
file_path (str) - Path to the image filemethod (str, default: "haar") - Detection method: "haar" (fast) or "dnn" (accurate)Returns: Dictionary with found, count, and faces list containing x, y, width, height, and confidence (DNN only)
{
"found": true,
"count": 2,
"faces": [
{"x": 120, "y": 80, "width": 150, "height": 150},
{"x": 400, "y": 100, "width": 140, "height": 140, "confidence": 0.95}
]
}#### detect_faces_save
Detects faces and saves an annotated image with bounding boxes.
Parameters:
file_path (str) - Path to the input imageoutput_path (str) - Path to save annotated imagemethod (str, default: "haar") - Detection method: "haar" or "dnn"Returns: Dictionary with found, count, output_path, and faces list
#### detect_motion
Compares two frames to detect motion between them.
Parameters:
file_path_1 (str) - Path to the first (earlier) imagefile_path_2 (str) - Path to the second (later) imagethreshold (float, default: 25.0) - Pixel difference threshold (0-255)Returns: Dictionary with motion_detected, motion_percentage, motion_regions list, and changed_pixels
{
"motion_detected": true,
"motion_percentage": 15.3,
"motion_regions": [
{"x": 200, "y": 150, "width": 80, "height": 120}
],
"changed_pixels": 31250
}#### detect_edges
Detects edges in an image using various methods.
Parameters:
file_path (str) - Path to the input imageoutput_path (str) - Path to save edge detection outputmethod (str, default: "canny") - Method: "canny", "sobel", or "laplacian"Returns: Dictionary with status, output_path, and method
{
"status": "success",
"output_path": "/path/to/edges.png",
"method": "canny"
}#### detect_objects
Detects common objects using MobileNet SSD.
Parameters:
file_path (str) - Path to the image fileconfidence_threshold (float, default: 0.5) - Minimum confidence (0-1)Returns: Dictionary with found, count, and objects list
Note: Requires pre-trained MobileNet SSD model files. Returns empty result if models are not available.
{
"found": true,
"count": 3,
"objects": [
{"class": "person", "confidence": 0.92, "x": 50, "y": 100, "width": 200, "height": 400},
{"class": "car", "confidence": 0.87, "x": 300, "y": 250, "width": 180, "height": 120}
]
}OpenCV prints debug messages to stderr which corrupts MCP's stdio communication. This server suppresses stderr at the file descriptor level before importing cv2 to prevent this issue.
Contributions are welcome! See CONTRIBUTING.md for guidelines.
MIT
<a href="https://glama.ai/mcp/servers/@Timorleiderman/OpticMCP"> <img width="380" height="200" src="https://glama.ai/mcp/servers/@Timorleiderman/OpticMCP/badge" /> </a>
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.