Skip to main content
Glama
README.md
# MCP Image Analyzer

> 给任意 LLM 装上「眼睛」——通过 MCP 协议调用 OpenAI 兼容的多模态模型分析图片,让 DeepSeek、Claude(非 vision 版)、本地大模型等不具备视觉能力的模型也能"看图"。

[![Node](https://img.shields.io/badge/node-%3E%3D18-green)](https://nodejs.org)
[![MCP](https://img.shields.io/badge/MCP-Protocol-blue)](https://modelcontextprotocol.io)
[![License](https://img.shields.io/badge/license-MIT-blue)](./LICENSE)

## 为什么需要它?

很多强大的文本模型并不支持视觉输入(如 DeepSeek-R1、Claude 非 vision 版、各类本地模型)。本服务作为**中间层**:接收图片 → 调用 OpenAI 兼容的多模态接口(如 `qwen-vl-max`、`gpt-4o`、`glm-4v`)→ 把分析结果回传给主模型,主模型即可基于"看到了什么"继续推理。

```
你的 LLM ──MCP──→ analyze_image ──→ OpenAI 兼容多模态 API
   ↑                                    (qwen-vl / gpt-4o / glm-4v)
   └────────── 分析结果(文字)←─────────────────┘
```

支持的图片来源:**本地路径 · Base64 · 公网 URL**,三种任选其一。

## 核心特性

| | 能力 |
|---|------|
| 🔒 **安全** | magic bytes 校验真实图片类型——拒绝读取 `/etc/passwd`、SSH 私钥等任意文件,防止通过 `image_path` 外泄敏感数据 |
| ⚡ **性能** | `sharp` 大图自动降采样;显式 60s 超时;SDK 内置 429/5xx 自动重试;异步读盘不阻塞 |
| 🎯 **简洁输出** | 内置 system prompt + `max_tokens` 控制,防止多模态模型输出冗长"小作文" |
| 🔀 **模型分级** | 调用时可用 `model` 参数临时换模型——快速 OCR 用 `qwen-vl-plus`(约 9× 快),复杂分析用 `qwen-vl-max` |
| 🛡️ **健壮** | 配置缺失即退出(不当"僵尸"进程);图片大小上限;结构化错误(附 HTTP 状态码) |
| 🌐 **多服务商** | 兼容阿里百炼 / OpenAI / 智谱等任意 OpenAI 兼容端点;`OPENAI_API_VERSION` 适配智谱 `/v4` 路径 |

## 快速开始

### 1. 克隆与安装

```bash
git clone https://github.com/yunper-wang/mcp-image-analyzer.git
cd mcp-image-analyzer
npm install
```

`npm install` 会装好 `@modelcontextprotocol/sdk`、`openai`、`sharp`(原生模块,按本机架构编译)。

### 2. 配置环境变量

最小配置三项必填,其余可选:

```bash
# 必填(在 MCP 客户端的 server env 中注入)
OPENAI_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode   # 不带 /v1,程序自动拼版本段
OPENAI_API_KEY=sk-你的密钥
OPENAI_MODEL=qwen-vl-max

# 可选
OPENAI_API_VERSION=v1          # OpenAI/阿里百炼用 v1;智谱用 v4
IMAGE_ANALYZER_MAX_TOKENS=1024  # 输出 token 上限
IMAGE_ANALYZER_TIMEOUT_MS=60000 # 单次请求超时(ms)
IMAGE_ANALYZER_MAX_IMAGE_MB=20  # 图片大小上限
IMAGE_ANALYZER_COMPRESS_THRESHOLD=1500000  # 解码后超此字节才压缩
IMAGE_ANALYZER_COMPRESS_MAX_EDGE=2048      # 压缩时长边上限
IMAGE_ANALYZER_SEND_DETAIL=0   # 仅 OpenAI 官方端点才开 detail 字段
```

> 💡 `OPENAI_BASE_URL` 不要带 `/v1` 后缀——程序会自动拼上 `/<OPENAI_API_VERSION>`,带 `/v1` 会拼成 `/v1/v1` 导致 404。即便误带,程序也会自动剥离兜底。

### 3. 接入 MCP 客户端

**Claude Desktop**(`~/Library/Application Support/Claude/claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "image-analyzer": {
      "command": "node",
      "args": ["/你的路径/mcp-image-analyzer/index.js"],
      "env": {
        "OPENAI_BASE_URL": "https://dashscope.aliyuncs.com/compatible-mode",
        "OPENAI_API_KEY": "sk-你的密钥",
        "OPENAI_MODEL": "qwen-vl-max"
      }
    }
  }
}
```

**Cursor / 其他 MCP 客户端**:参照上例,把 `args` 指向解压后的 `index.js` 绝对路径,`env` 注入同样的三项变量即可。详细多平台步骤见 [INSTALL.md](./docs/INSTALL.md)。

配置后重启客户端,`analyze_image` 工具即出现在工具列表中。

## 支持的模型服务商

任意 OpenAI 兼容的多模态端点都可用,常见配置:

| 服务商 | `OPENAI_BASE_URL` | `OPENAI_MODEL` 示例 | `OPENAI_API_VERSION` |
|--------|-------------------|---------------------|----------------------|
| 阿里百炼 DashScope | `https://dashscope.aliyuncs.com/compatible-mode` | `qwen-vl-max` / `qwen-vl-plus` | `v1`(默认) |
| OpenAI 官方 | `https://api.openai.com/v1`(可省略) | `gpt-4o` / `gpt-4o-mini` | `v1` |
| 智谱 BigModel | `https://open.bigmodel.cn/api/paas` | `glm-4v` | `v4` |

## 工具参数

`analyze_image` 工具的入参:

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `image_path` | string | 三选一 | 本地图片绝对路径(仅 PNG/JPEG/GIF/WebP/BMP) |
| `image_base64` | string | 三选一 | 图片 Base64(不含 `data:` 前缀) |
| `image_url` | string | 三选一 | 图片公网 URL |
| `prompt` | string | 可选 | 分析指令,如"提取图中文字""描述这张图表"。留空则默认描述 |
| `detail` | enum | 可选 | `auto` / `low` / `high`,默认 `auto`。**仅 OpenAI 官方端点生效**,兼容端点建议不开 `SEND_DETAIL` |
| `model` | string | 可选 | 覆盖默认模型。如快速 OCR 传 `qwen-vl-plus`、复杂分析传 `qwen-vl-max` |

**示例调用**(LLM 自动发起,也可在 MCP 客户端手动测试):

```json
{
  "image_path": "/abs/path/screenshot.png",
  "prompt": "提取图中所有可见文字"
}
```

```json
{
  "image_url": "https://example.com/chart.png",
  "prompt": "这张折线图说明什么趋势?列出坐标轴和关键数值",
  "model": "qwen-vl-plus"
}
```

## 安全设计

这是本服务相对"裸调 API"的关键加固:

- **magic bytes 校验**:读取本地文件后,先按文件头字节判定是否为真实图片(PNG `89 50 4E 47`、JPEG `FF D8 FF` 等),**不是图片直接拒绝**。这意味着攻击者无法通过 `image_path` 让模型读取并外泄 `/etc/passwd`、SSH 私钥、`.env` 等任意文件——即便这些文件能被 base64 编码。
- **大小上限**:默认 20MB,超限拒绝,防止超大文件拖垮模型上下文或产生高额费用。
- **配置缺失即退出**:三项必填变量缺任一,进程立即 `exit(1)` 并提示缺哪项,避免启动成静默失败的"僵尸"服务。
- **不含敏感信息**:密钥仅从环境变量读取,源码中无任何硬编码凭据。

## 技术栈

- **[@modelcontextprotocol/sdk](https://www.npmjs.com/package/@modelcontextprotocol/sdk)** — MCP 协议实现(stdio 传输)
- **[openai](https://www.npmjs.com/package/openai)** — OpenAI 兼容客户端(超时 + 自动重试)
- **[sharp](https://www.npmjs.com/package/sharp)** — 大图降采样(按需压缩,失败优雅降级)
- 纯 ESM,Node ≥ 18,零构建

## 项目结构

```
mcp-image-analyzer/
├── index.js              # MCP Server 主程序
├── package.json
├── package-lock.json
├── .env.example          # 配置模板(无真实密钥)
├── docs/
│   └── INSTALL.md        # 详细安装与多平台配置
├── SKILL.md              # 客户端无关使用说明
├── LICENSE
└── README.md
```

## License

[MIT](./LICENSE)

TDQS

A4.2/5.0

Scored across 1 tool

Disambiguation5/5

Only one tool exists, so there is no possibility of confusing it with others. The tool's purpose is clearly defined and distinct by default.

Naming Consistency5/5

The single tool name follows a consistent verb_noun pattern (analyze_image), which is clear and indicative of its function.

Tool Count4/5

A single tool is below the typical 3-15 range, but it is reasonable for a narrowly-focused image analysis server. It does not feel excessive or overly sparse given the server's specific purpose.

Completeness5/5

The tool covers all necessary input types (local, base64, URL) and a wide range of analysis capabilities (text, objects, scenes, charts), leaving no obvious gaps for the stated purpose of image analysis.

Maintenance

ActivitySlowing
ResponsivenessNo issues