Skip to main content
Glama
DeepSeek Vision MCP
by groxaxo

DeepSeek Vision MCP

CI Python License: MIT

A secure, lightweight MCP v2 server that gives any MCP-compatible agent DeepSeek V4 Flash Vision: image analysis, faithful descriptions, OCR, comparisons, UI/object localization, and reusable Files API uploads.

The server exposes the exact model deepseek-v4-flash-vision-exp without embedding provider-specific image payloads in every agent integration.

Tools

Tool

Purpose

vision_analyze

General one/multi-image analysis with a custom prompt

vision_describe

Faithful scene/UI description

vision_ocr

Screenshot/document OCR

vision_compare

Compare two or more images

vision_locate

Best-effort UI/object localization to normalized coordinates

vision_upload

Upload a local image to DeepSeek Files API

vision_files_list

List reusable uploaded images

vision_files_delete

Delete an uploaded image

Accepted image references:

  • local server-side path

  • public http:// or https:// URL

  • data:image/...;base64,...

  • DeepSeek file-api-... file ID

Related MCP server: vision-mcp

Why this server is thin

The MCP server does not run a local vision model. It only validates/normalizes image inputs and delegates inference to DeepSeek. That makes CPU/RAM usage tiny and lets any MCP-capable agent gain vision without embedding DeepSeek-specific payload shapes in the agent itself.

Install with uv

git clone https://github.com/groxaxo/deepseek-vision-mcp.git
cd deepseek-vision-mcp

uv sync --locked

cp .env.example .env
# Set DEEPSEEK_API_KEY and allowed roots in .env

For a local MCP host, stdio is the preferred transport:

DEEPSEEK_API_KEY="..." \
DEEPSEEK_VISION_ALLOWED_ROOTS="/home/you/Pictures:/tmp/vision" \
uv run deepseek-vision-mcp

For development with MCP Inspector:

DEEPSEEK_API_KEY="..." uv run mcp dev src/deepseek_vision_mcp/server.py

MCP host configuration

Typical stdio configuration:

{
  "mcpServers": {
    "deepseek-vision": {
      "command": "uv",
      "args": [
        "--directory",
        "/absolute/path/to/deepseek-vision-mcp",
        "run",
        "deepseek-vision-mcp"
      ],
      "env": {
        "DEEPSEEK_API_KEY": "YOUR_KEY",
        "DEEPSEEK_VISION_ALLOWED_ROOTS": "/home/you/Pictures:/tmp/vision"
      }
    }
  }
}

Do not commit the API key. If the host can inherit environment variables, prefer injecting DEEPSEEK_API_KEY from your secret manager or shell.

Safe shared launcher

run-mcp.py is useful when several local agents share one installation. It:

  • reads only approved DeepSeek variables from the process or an env file;

  • filters unrelated inherited secrets before launching the MCP;

  • forces stdio transport;

  • restricts local images to explicit roots.

By default it reads ~/.hermes/.env and allows the usual image-working directories under the current home directory plus /tmp. Override those choices without editing the script:

export DEEPSEEK_VISION_ENV_FILE="$HOME/.config/deepseek-vision.env"
export DEEPSEEK_VISION_ALLOWED_ROOTS="$HOME/Pictures:/tmp/vision"
./run-mcp.py

Hermes configuration:

mcp_servers:
  deepseek-vision:
    command: "/absolute/path/to/deepseek-vision-mcp/run-mcp.py"
    args: []
    enabled: true

OpenCode configuration:

{
  "mcp": {
    "deepseek-vision": {
      "type": "local",
      "command": ["/absolute/path/to/deepseek-vision-mcp/run-mcp.py"],
      "enabled": true
    }
  }
}

OMP and other standard MCP hosts can use the mcpServers example above with run-mcp.py as the command.

Streamable HTTP

export DEEPSEEK_API_KEY="..."
export MCP_TRANSPORT=streamable-http
export MCP_HOST=127.0.0.1
export MCP_PORT=8000

uv run deepseek-vision-mcp

The MCP endpoint is:

http://127.0.0.1:8000/mcp

Use TLS and authentication in front of the server before exposing it outside a trusted machine/network.

Example tool calls

Analyze a screenshot

{
  "images": ["/home/you/Pictures/screen.png"],
  "prompt": "What application is open, what is the current state, and what should I click next?",
  "detail": "original"
}

Fast coarse screen read

{
  "images": ["/home/you/Pictures/screen.png"],
  "prompt": "Is a modal dialog visible? Answer briefly.",
  "detail": "low"
}

OCR

{
  "image": "/home/you/Pictures/error.png",
  "detail": "original"
}

Best-effort UI grounding

{
  "image": "/home/you/Pictures/screen.png",
  "target": "the blue Save button"
}

vision_locate returns coordinates normalized to 0..1000. It is intentionally described as best-effort: a generative VLM is not a deterministic detector. Validate its target before high-impact clicks.

Security model

Images analyzed by this MCP are sent to DeepSeek's external API. Do not send private or sensitive images without informed user intent.

Local paths are restricted to DEEPSEEK_VISION_ALLOWED_ROOTS. If no roots are configured, the server only allows images under its current working directory.

This matters: an unrestricted vision_analyze("/etc/...") style tool would let an MCP host turn image analysis into arbitrary local-file exfiltration.

The server also rejects obvious localhost/private-IP external URLs.

The shared launcher passes only baseline process variables, XDG_*, and the four approved DeepSeek settings to the child process. It never sources an entire credentials file.

DeepSeek image behavior reflected by this server

  • JPEG, PNG, GIF, WebP

  • local/base64 inline image: max 32 MiB each

  • DeepSeek Files API image: max 64 MiB

  • max 600 images/request

  • external URL length: max 8192 chars

  • max dimension: 8192 px/side, or 4096 px/side for 15+ images

  • detail=low: DeepSeek downsamples to 512x512

  • detail=original / high: preserve original detail

  • images are only sent in the user message

Large/reused images

Upload once:

{
  "local_path": "/home/you/Pictures/large.png",
  "expires_seconds": 86400
}

Then pass the returned file-api-... ID into vision_analyze. Use null for expires_seconds only when you intentionally want permanent DeepSeek storage.

Docker

docker build -t deepseek-vision-mcp .
docker run --rm \
  -p 127.0.0.1:8000:8000 \
  -e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
  deepseek-vision-mcp

For local image paths in Docker, mount only the directories the MCP needs and set DEEPSEEK_VISION_ALLOWED_ROOTS to the container-side path.

Architecture

MCP host / agent
      |
      | MCP tool call
      v
DeepSeek Vision MCP
  - validates source
  - restricts local paths
  - encodes local files
  - shapes DeepSeek payload
      |
      | HTTPS
      v
api.deepseek.com
  deepseek-v4-flash-vision-exp
      |
      v
structured MCP result

Development

uv sync --locked --extra dev
uv run ruff check .
uv run pytest

CI runs the same gates on Python 3.11 and 3.13. Contributions and focused bug reports are welcome.

Available Tools

8 tools
vision_analyzeB

Analyze one or more images with a custom prompt.

Image sources may be:

  • local server-side paths under DEEPSEEK_VISION_ALLOWED_ROOTS

  • public http(s) URLs

  • base64 data:image/... URLs

  • DeepSeek Files API IDs beginning with file-api-

Use detail="low" for cheap/fast coarse inspection, or "original" for screenshots, OCR, charts, and other fine-detail tasks.

Inputs: images (required), prompt (required), detail, json_mode, +1 more.

vision_compareB

Compare 2+ images in the order provided.

Inputs: images (required), detail, question, max_tokens.

vision_describeC

Describe the visible content of an image faithfully and concisely.

Inputs: image (required), detail, max_tokens.

vision_files_deleteC

Delete an uploaded DeepSeek Files API image.

Inputs: file_id (required).

vision_files_listA

List uploaded DeepSeek user_data image files, newest first.

Inputs: limit.

vision_locateA

Best-effort semantic localization of a visible target.

Coordinates are model-estimated and MUST be validated before destructive or high-impact UI actions. This is useful for agent grounding but is not a deterministic object detector.

Inputs: image (required), target (required), detail.

vision_ocrA

Read visible text from a screenshot/document image.

Returns the transcription as model text. Prefer detail="original".

Inputs: image (required), detail, max_tokens.

vision_uploadA

Upload a local image to DeepSeek Files API and return its reusable file_id.

Local paths must be inside DEEPSEEK_VISION_ALLOWED_ROOTS. expires_seconds: 3600..2592000 (1h..30d), or null for permanent storage.

Inputs: local_path (required), expires_seconds.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3.4/5.0

    Scored across 8 tools

    Disambiguation5/5

    Each tool targets a distinct visual task: custom analysis, faithful description, OCR, comparison, semantic localization, upload, listing, and deletion. The overlaps between analyze and describe are minor and clearly differentiated by purpose and usage notes.

    Naming Consistency3/5

    Most tools follow a vision_<verb> pattern (analyze, describe, compare, locate, upload), but vision_files_list and vision_files_delete reverse the noun-verb order, and vision_ocr is an abbreviation noun. The shared prefix provides some consistency, but the mixed conventions prevent a higher score.

    Tool Count5/5

    Eight tools is a well-scoped number for a vision MCP server, covering both image analysis and file lifecycle management without unnecessary bloat. Each tool serves a clear purpose.

    Completeness5/5

    The tool surface covers the major vision tasks (analysis, description, OCR, comparison, localization) and includes full file management via upload, list, and delete. There are no obvious dead ends; images are immutable so update/delete semantics are appropriately handled.

    Maintenance

    ActivityInactive
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers