llm-vision
llm-vision
Give vision to vision-less LLMs — a local MCP server powered by Alibaba DashScope.
English | 简体中文
Vision-less models (e.g. DeepSeek) can't see images — but they don't have to. llm-vision is a local MCP server that acts as their eyes: hand it a local image path, and it returns a text description generated by Alibaba Cloud's vision models (qwen3-vl-plus / qwen3.5-ocr).
✨ Features
Two tools, one pipeline —
describe_imagefor general image understanding,extract_textfor OCR & document parsing (ID cards, invoices, receipts)Bring your own model — model IDs configurable via environment variables, no code changes
Zero-cost test suite — 68 tests, most run offline against mocked HTTP
Portable setup — ship
.mcp.jsonwith your repo; works anywhere afteruv syncModel-consumable errors — every tool returns a readable error string, never an exception
🚀 Quick Start
Prerequisites
1. Install
git clone https://github.com/1710782766/llm_vision.git && cd llm-vision
uv sync
export DASHSCOPE_API_KEY=sk-xxx # or add to your shell profile2. Register with Claude Code
The repo ships with a portable .mcp.json — just open Claude Code in the project directory and ask:
"Use
describe_imageto look atpath/to/your/image.jpgand tell me what's in it."
Approve the server connection once, and every future session has vision.
Prefer the CLI? Register manually:
claude mcp add llm-vision --env DASHSCOPE_API_KEY=sk-xxx -- uv run python main.pyUse it in every project — register globally (user scope) so any project directory has vision:
claude mcp add -s user llm-vision --env DASHSCOPE_API_KEY=sk-xxx -- uv run python /absolute/path/to/llm_vision/main.py⚠️ With global registration, relative image paths resolve against the MCP process's working directory (your current project), not this repo — pass absolute paths to the model.
The project-local .mcp.json (portable, cwd: ".") and global -s user registration serve different setups: the former keeps the server bound to this repo, the latter makes it available everywhere.
🛠 Tools
Tool | Arguments | Description |
|
| View an image; |
|
| OCR & text localization — documents, ID cards, invoices; ask for structured output (e.g. "extract the name and ID number as JSON") |
Supported formats: jpg · jpeg · png · webp · gif · bmp · heic/heif (HEIC/HEIF via macOS sips) — single file < 10 MB.
⚙️ Configuration
Variable | Required | Default | Description |
| ✅ | — | DashScope API key ( |
| — |
| Vision model used by |
| — |
| OCR model used by |
| — |
| Per-attempt timeout (seconds) |
| — |
| Retries for transient errors (timeouts, network, HTTP 5xx); |
| — | (built-in) | Override the default prompt for |
| — | (built-in) | Override the default OCR prompt |
| — |
| Result cache on/off ( |
| — |
| Cache location (or |
| — |
| Max image edge (px) before auto-scaling; |
| — |
| Auto-preprocess oversize images on/off |
🛡️ Reliability & Cost
Designed to "just work" in real use — including screenshot-heavy workflows:
Auto-compression — images over 1568px (the DashScope recommended edge) are scaled down via the macOS built-in
sips(zero runtime dependencies); oversized files are re-encoded (JPEG q85, transparent PNGs preserved). Only oversize images are touched; normal images pass through untouched. Fixes the classic "big screenshot times out" failure. Non-macOS platforms skip preprocessing and rely on timeout + retry instead.Retries — transient errors (timeout, network, HTTP 5xx) retry up to
LLM_VISION_MAX_RETRIEStimes with exponential backoff and a shrinking per-attempt budget (total ≤ 2× timeout). Errors are tagged(已重试 N 次)so you know the failure survived retries.Result cache — identical image + model + prompt + preprocess settings hits a content-addressed cache (keyed by file SHA-256) at
~/.cache/llm-vision/responses.json; re-viewing the same screenshot costs nothing. Only the model's text answer is stored — never image bytes. The file being replaced (new hash) invalidates the entry automatically. Disable withLLM_VISION_CACHE=0.⚠️ Note: OCR results (e.g. ID-card numbers extracted via
extract_text) are stored in plain text in that cache file for up to 30 days (file permission0600). For sensitive documents, setLLM_VISION_CACHE=0.Animated GIFs over 1.5 MB are converted to their first frame.
🧠 Model Selection
qwen3-vl-plus(default vision) — benchmarked as the only hallucination-free option in our model evaluation;qwen3.7-plusis a promising upgrade candidateqwen3.5-ocr(default OCR) — cheap, and notably strong at document & card-key-value extraction⚠️ The
qwen3-vl-plus-latestalias has been retired (returns404) — use stable model IDs
🏗 Architecture
main.py (MCP server)
├── describe_image(path, prompt?, perspective="normal") → LLM_VISION_MODEL
├── extract_text(path, prompt?) → LLM_VISION_OCR_MODEL
└── _analyze_image pipeline
→ image_loader path/extension/10MB validation, base64 + MIME
→ dashscope_client httpx → DashScope OpenAI-compatible endpointTools always return a string: the model's answer on success, a readable Chinese error message on failure — never an exception to the client.
🔒 Security & Privacy
DASHSCOPE_API_KEYlives only in your environment — never in.mcp.jsonor in gitWhen a tool is invoked, the image is sent as base64 to Alibaba DashScope — only hand the model images you're comfortable leaving your machine
🧪 Development
uv run pytest tests/ -q # full suite (22 tests, mostly offline)
uv run python scripts/smoke_test.py [image_path ...] # real-API smoke test (billed, ~¥0.01/call); pass paths or provide your own under images/
uv run python scripts/compare_models.py qwen3-vl-plus qwen3.7-plus # model bake-off (billed)Developer notes for Claude Code: see CLAUDE.md.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/1710782766/llm_vision'
If you have feedback or need assistance with the MCP directory API, please join our Discord server