Skip to main content
Glama

Camera MCP

Lightweight USB camera snapshot service. Captures fresh images from an attached USB camera and serves them via a simple HTTP API.

Core value: Every API call captures a new frame — no stale caches, no pre-recorded footage.

Quick Start

Prerequisites

  • Docker & Docker Compose v2

  • Python 3.12+ with uv (for local development without Docker)

  • USB camera attached to the host

Development

# Clone and enter
cd camera_mcp

# Copy environment file
cp .env.example .env

# Start with Docker
make dev

# Or run locally
uv sync --group dev
uv run uvicorn src.camera_mcp.main:app --host 0.0.0.0 --port 8579 --reload

Open http://localhost:8579/health to verify.

Running Tests

make test          # All tests
make test-unit     # Unit tests only
make test-coverage # With coverage report

All tests run without hardware — cv2.VideoCapture is mocked.

Related MCP server: OpticMCP

API

Endpoint

Method

Description

/capture

GET

Capture a fresh JPEG image from the first camera (index 0)

/capture/{cam_index}

GET

Capture a fresh JPEG image from a specific camera

/camera

GET

Info for all detected cameras

/camera/{cam_index}

GET

Info for a specific camera

/health

GET

Service health and camera status

Capture

# Default — first camera, 1280px max width
curl -H "Authorization: Bearer $CAMERA_AUTH_TOKEN" http://localhost:8579/capture > photo.jpg

# Custom width
curl -H "Authorization: Bearer $CAMERA_AUTH_TOKEN" "http://localhost:8579/capture?max_width=640" > photo.jpg

# Second camera (index 1)
curl -H "Authorization: Bearer $CAMERA_AUTH_TOKEN" http://localhost:8579/capture/1 > photo_cam2.jpg

Returns image/jpeg on success (200), 404 if the camera doesn't exist, or JSON error (503) if camera is unavailable.

Health

curl http://localhost:8579/health
{
  "status": "ok",
  "place": "home",
  "places": ["default", "home"],
  "cameras": [
    { "index": 0, "connected": true, "device": "/dev/video0" },
    { "index": 1, "connected": true, "device": "/dev/video1" }
  ],
  "camera_count": 2,
  "uptime_seconds": 1234.5,
  "last_error": null
}

place is the display name of this deployment's location, places all its aliases (see CAMERA_PLACES). A deployment whose names include default is the one to use when no location is specified.

Environment Variables

Variable

Default

Description

CAMERA_HOST

0.0.0.0

Listen address

CAMERA_PORT

8579

Listen port

CAMERA_MAX_WIDTH

1280

Default max image width (px)

CAMERA_JPEG_QUALITY

85

JPEG quality (1-100)

CAMERA_LOG_LEVEL

INFO

Log level (DEBUG, INFO, WARNING, ERROR)

CAMERA_PLACES

default

Comma-separated location names for this deployment, e.g. default,home

See .env.example for all options.

Architecture

Single-container stateless service:

  • FastAPI for the HTTP layer

  • OpenCV (cv2) for camera capture and image processing

  • No database — each request is independent

  • Supports multiple USB cameras — auto-detected on startup, indexed access via API

  • Auto-reconnects on camera disconnect

Deployment

See DEPLOYMENT.md for production deployment guide.

MCP Server

The project includes an MCP server that exposes camera tools to Claude Code. When the camera API is running, Claude can capture live images and check camera status.

Available Tools

  • capture_image(camera_index, max_width) — Capture a fresh JPEG image from a USB camera. camera_index selects which camera (0-based, defaults to 0).

  • camera_status() — Check camera health and connection status for all detected cameras. Also reports the deployment's location (e.g. Location: home (default)).

Setup

  1. Start the camera API service:

    make dev
    # or
    uv run uvicorn src.camera_mcp.main:app --host 0.0.0.0 --port 8579
  2. Open Claude Code in this project directory — the MCP server is configured via .mcp.json and will be available automatically. If it doesn't exist, create it with cp .mcp.json.example .mcp.json, point command at your .venv/bin/camera-mcp-mcp, and paste your CAMERA_AUTH_TOKEN from .env (the file is gitignored — it holds a secret).

  3. Use natural language to interact with the camera:

    • "can you see?" → calls camera_status

    • "what do you see?" → calls capture_image() (first camera)

    • "take a photo with the second camera" → calls capture_image(camera_index=1)

Multiple Locations

Each deployment serves one physical location and names itself with CAMERA_PLACES (comma-separated, e.g. default,home). The name(s) are reported by /health, printed by camera_status, and advertised in the MCP server's instructions — so an agent with several camera servers registered can tell them apart.

To add a second location:

  1. Clone this repo to the new machine and deploy as usual (Docker or bare metal).

  2. Set its names in .env:

    • CAMERA_PLACES=office — or CAMERA_PLACES=default,home for the instance that should be the fallback.

    • Mark exactly one deployment with default: it is what agents use when you don't name a location.

  3. Connect its MCP server to your agent (another .mcp.json entry, or the streamable-http URL in another machine's config).

Then "take a photo" hits the default location, while "what do the office cameras see?" goes to the one named office.

Standalone

Run the MCP server manually:

uv run camera-mcp-mcp

Tech Stack

Python 3.12, FastAPI, OpenCV, uvicorn, uv (package manager), ruff, mypy, pytest.

Maintenance

ActivityMaintained
ResponsivenessSyncing

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/bkosciow/mcp_camera'

If you have feedback or need assistance with the MCP directory API, please join our Discord server