# image-mcp: 图片理解 + OCR MCP Server 设计文档

## 概述

基于 Python FastMCP 的 stdio 模式 MCP server，提供两个工具：图片理解/分析（Qwen3.5-27B VL）和 OCR 文字识别（PaddleOCR）。通过 `uvx` 直接运行，用户通过环境变量配置 API 地址。

## 架构

单文件方案（`main.py`），所有逻辑集中在一个文件中。

```
image-mcp/
├── main.py          # FastMCP server + 两个 tool 定义
├── pyproject.toml   # 依赖: fastmcp, openai, httpx
```

- **传输协议**: stdio（默认）
- **运行方式**: `uvx image-mcp`
- **包名**: `image-mcp`（pyproject.toml 中的 `name`）
- **入口点**: `image-mcp = "main:main"`，`main()` 函数调用 `mcp.run()`
- **依赖**: fastmcp, openai, httpx
- **环境变量加载**: 由 MCP client 通过 `--env` 注入，不使用 `.env` 文件

## 环境变量

| 环境变量 | 默认值 | 说明 |
|---------|--------|------|
| `LLM_BASE_URL` | 无，必填 | Qwen VL API 地址（OpenAI 兼容） |
| `LLM_API_KEY` | `"no-key"` | API Key |
| `LLM_MODEL` | `"Qwen3.5-27B"` | 模型名称 |
| `OCR_API_URL` | `http://192.168.25.212:8080/layout-parsing` | PaddleOCR API 地址 |

## Tool 1: `analyze_image`

图片理解与分析工具，通过 Qwen3.5-27B VL 模型对图片进行分析。

### 参数

| 参数 | 类型 | 必需 | 说明 |
|------|------|------|------|
| `prompt` | string | 是 | 对图片的提问或分析要求 |
| `image_url` | string | 是 | 图片来源，支持三种格式（HTTP URL / Base64 Data URI / 本地文件路径） |

### image_url 处理逻辑

| 输入格式 | 判断条件 | 处理方式 |
|---------|---------|---------|
| HTTP URL | 以 `http://` 或 `https://` 开头 | 直接以 URL 形式传给 OpenAI Vision API（无需下载） |
| Base64 Data URI | 以 `data:image/` 开头 | 直接传给 OpenAI Vision API |
| 本地文件路径 | 其他情况 | 读取文件，转为 base64 data URI 后传给 API；文件不存在返回错误 |

支持格式：JPEG、PNG、GIF、WebP（最大 20MB）。

### 调用流程

1. 解析 `image_url`，按类型处理（HTTP URL 和 data URI 直接透传，本地路径转 base64）
2. 通过 OpenAI SDK 构造 vision 请求（包含 prompt + 图片）
3. 发送到 Qwen3.5-27B VL API（超时 60 秒）
4. 返回模型的文本回复（纯文本 MCP content）

## Tool 2: `ocr`

图片/PDF 文字识别工具，通过 PaddleOCR 版面解析 API 将文件转为结构化 Markdown。

### 参数

| 参数 | 类型 | 必需 | 说明 |
|------|------|------|------|
| `file_path` | string | 是 | 文件来源，支持三种格式（HTTP URL / Base64 Data URI / 本地文件路径） |

支持格式：PNG、JPG、BMP、TIFF、WebP、PDF（最大 50MB）。

### 处理逻辑

统一将文件内容转为 base64 后发送给 PaddleOCR API：

| 输入格式 | 判断条件 | 处理方式 |
|---------|---------|---------|
| HTTP URL | 以 `http://` 或 `https://` 开头 | httpx 下载文件，转 base64 |
| Base64 Data URI | 以 `data:` 开头 | 直接提取 base64 数据 |
| 本地文件路径 | 其他情况 | 读取文件，转 base64；文件不存在返回错误 |

### PaddleOCR API 调用规范

- **地址**: `POST {OCR_API_URL}`（默认 `http://192.168.25.212:8080/layout-parsing`）
- **Content-Type**: `application/json`
- **请求体**: `{"image": "<base64编码>", "file_type": "<扩展名>"}`（具体字段以 PaddleOCR 文档为准）
- **超时**: 300 秒（PDF 多页处理可能耗时较长）
- **响应**: 返回结构化 Markdown 文本（纯文本 MCP content）

### 调用流程

1. 解析输入，统一获取文件 base64 内容
2. POST 到 PaddleOCR `/layout-parsing` 接口
3. 返回结构化 Markdown 文本

## 打包与分发

### pyproject.toml 关键配置

```toml
[project]
name = "image-mcp"
dependencies = ["fastmcp", "openai", "httpx"]

[project.scripts]
image-mcp = "main:main"
```

### 用户安装方式

```bash
claude mcp add -s user image-mcp \
  --env LLM_BASE_URL=http://your-vl-server/v1 \
  --env LLM_API_KEY=your-key \
  --env LLM_MODEL=Qwen3.5-27B \
  --env OCR_API_URL=http://your-ocr-server:8080/layout-parsing \
  -- uvx image-mcp
```

## 错误处理

- **图片/文件下载失败**: 返回明确错误，包含 HTTP 状态码和 URL
- **本地文件不存在**: 提示"文件不存在，如果 MCP server 与文件不在同一台机器，请使用 HTTP URL 或 base64 data URI"
- **文件过大**: analyze_image 超过 20MB、ocr 超过 50MB 时拒绝处理
- **不支持的文件格式**: 返回支持的格式列表
- **无效的 base64 数据**: 提示 data URI 格式错误
- **LLM API 调用失败/超时**: 返回 API 错误信息（60 秒超时）
- **OCR API 不可达/超时**: 提示检查 OCR_API_URL 配置（300 秒超时）
- **OCR API 返回错误**: 透传错误信息
- **LLM_BASE_URL 未配置**: 启动时即报错，提示必须设置该环境变量
