vision-mcp
MCP server that provides visual question answering, image description, object detection, OCR, and image manipulation tools using OpenAI-compatible vision models.
README
Vision MCP Server
基于 VLM(视觉语言模型)的 MCP 服务,提供视觉问答、图像解读、目标检测、OCR 以及完整的图像处理工具链。通过 OpenAI 兼容 API 接入任意 VLM 大模型,以 stdio 方势提供服务。
特性
- 4 个 VLM 工具:视觉问答、视觉解读、目标检测(归一化包围盒)、OCR 文字提取
- 8 个图像处理工具:元信息、缩放、裁剪、旋转、镜像、拼接、画方框、写文字(中文)
- 忠实还原:所有 VLM 调用内置"不脑补"指令 +
temperature: 0 - 自动缩放:VLM 工具内置
max_dimension参数,发送前自动等比缩放,避免超限 - 坐标归一化:检测工具通过系统提示词 + 后处理双重保障,始终返回 0-1 归一化包围盒
- 双输入模式:支持本地文件路径和 URL 两种图片输入方式
- 双输出模式:图像处理工具返回 base64 图片内容,可选
output_path保存到文件
快速开始
环境要求
- Node.js >= 18
- 任意 OpenAI 兼容的 VLM API(如 OpenAI GPT-4o、Qwen-VL、GLM-4V 等)
安装
git clone <repo-url>
cd vision-mcp
npm install
npm run build
配置
通过环境变量配置:
| 环境变量 | 必需 | 说明 | 示例 |
|---|---|---|---|
VLM_BASE_URL |
是 | VLM API 基础地址 | https://api.openai.com/v1 |
VLM_API_KEY |
是 | API 密钥 | sk-xxxx |
VLM_MODEL_ID |
是 | 模型 ID | gpt-4o |
VISION_MCP_FONT_PATH |
否 | 中文字体文件路径(.ttf/.otf) | fonts/SimHei.ttf |
启动
VLM_BASE_URL=https://api.openai.com/v1 \
VLM_API_KEY=sk-xxxx \
VLM_MODEL_ID=gpt-4o \
node dist/index.js
在 MCP 客户端中配置
Claude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"vision": {
"command": "node",
"args": ["/path/to/vision-mcp/dist/index.js"],
"env": {
"VLM_BASE_URL": "https://api.openai.com/v1",
"VLM_API_KEY": "sk-xxxx",
"VLM_MODEL_ID": "gpt-4o",
"VISION_MCP_FONT_PATH": "/path/to/vision-mcp/fonts/SimHei.ttf"
}
}
}
}
Cursor / 其他 MCP 客户端:参照各客户端文档,使用 node dist/index.js 作为启动命令,传入上述环境变量。
使用 MCP Inspector 调试
VLM_BASE_URL=... VLM_API_KEY=... VLM_MODEL_ID=... \
npm run inspector
工具列表
VLM 工具(4 个)
通过 OpenAI 兼容 API 调用 VLM 大模型完成视觉任务。所有 VLM 工具:
- 接受
images(路径或 URL 数组,1-8 张) - 内置
max_dimension(默认 2048)自动缩放 - 使用
temperature: 0+ 忠实性提示词确保不脑补
vision_qa — 视觉问答
对图片提问,返回基于图片内容的文字回答。适用于检查 Web 页面、PPT 页面是否符合要求等场景。
| 参数 | 类型 | 必需 | 默认值 | 说明 |
|---|---|---|---|---|
images |
string[] |
是 | — | 图片路径或 URL 列表 |
question |
string |
是 | — | 要提问的问题 |
max_dimension |
number |
否 | 2048 | 发送前自动缩放最大边长,设 0 禁用 |
vision_describe — 视觉解读
详细、真实地解读图片内容,不推测或脑补。
| 参数 | 类型 | 必需 | 默认值 | 说明 |
|---|---|---|---|---|
images |
string[] |
是 | — | 图片路径或 URL 列表 |
detail_level |
"brief"|"normal"|"detailed" |
否 | "normal" |
描述详细程度 |
max_dimension |
number |
否 | 2048 | 发送前自动缩放最大边长 |
vision_detect — 视觉检测
在图片中检测指定目标,返回 0-1 归一化包围盒。
系统提示词强制要求归一化坐标;后处理函数自动检测像素坐标(值 > 1)并除以图片尺寸归一化,双重保障。
| 参数 | 类型 | 必需 | 默认值 | 说明 |
|---|---|---|---|---|
images |
string[] |
是 | — | 图片路径或 URL 列表 |
target |
string |
是 | — | 要检测的目标描述 |
max_dimension |
number |
否 | 2048 | 发送前自动缩放最大边长 |
返回结构:
{
"detections": [
{
"label": "对象描述",
"bbox": { "x_min": 0.1, "y_min": 0.2, "x_max": 0.3, "y_max": 0.4 },
"confidence": 0.95
}
]
}
vision_ocr — 视觉 OCR
提取图片中所有可见文字。
| 参数 | 类型 | 必需 | 默认值 | 说明 |
|---|---|---|---|---|
images |
string[] |
是 | — | 图片路径或 URL 列表 |
max_dimension |
number |
否 | 2048 | 发送前自动缩放最大边长 |
返回结构:
{
"text_blocks": [
{ "text": "文字内容", "bbox": { "x_min": 0.1, "y_min": 0.2, "x_max": 0.3, "y_max": 0.4 } }
],
"full_text": "所有文字按阅读顺序拼接"
}
图像处理工具(8 个)
基于 sharp 和 @napi-rs/canvas 的程序化图像操作。所有工具:
- 返回 base64 PNG 图片内容(MCP
imagecontent type) - 提供
structuredContent(宽高、格式、大小) - 支持可选
output_path参数保存到文件
image_get_metadata — 获取图片元信息
返回宽度、高度、格式、通道数、色彩空间、DPI、Alpha 通道、EXIF 方向等。
| 参数 | 类型 | 必需 | 说明 |
|---|---|---|---|
image |
string |
是 | 图片路径或 URL |
image_resize — 图片缩放
| 参数 | 类型 | 必需 | 默认值 | 说明 |
|---|---|---|---|---|
image |
string |
是 | — | 图片路径或 URL |
width |
number |
否 | — | 目标宽度(像素) |
height |
number |
否 | — | 目标高度(像素) |
scale |
number |
否 | — | 缩放比例(0.01-10) |
fit |
string |
否 | "inside" |
缩放模式:cover/contain/fill/inside/outside |
output_path |
string |
否 | — | 保存路径 |
width/height和scale三选一。width/height同时指定时按fit模式处理。
image_crop — 图片裁剪
| 参数 | 类型 | 必需 | 默认值 | 说明 |
|---|---|---|---|---|
image |
string |
是 | — | 图片路径或 URL |
left |
number |
是 | — | 裁剪区域左上角 x 坐标 |
top |
number |
是 | — | 裁剪区域左上角 y 坐标 |
width |
number |
是 | — | 裁剪区域宽度 |
height |
number |
是 | — | 裁剪区域高度 |
normalized |
boolean |
否 | false |
坐标是否为 0-1 归一化值 |
output_path |
string |
否 | — | 保存路径 |
image_rotate — 图片旋转
| 参数 | 类型 | 必需 | 说明 |
|---|---|---|---|
image |
string |
是 | 图片路径或 URL |
angle |
number |
是 | 旋转角度(正数为顺时针) |
output_path |
string |
否 | 保存路径 |
image_flip — 图片镜像
| 参数 | 类型 | 必需 | 说明 |
|---|---|---|---|
image |
string |
是 | 图片路径或 URL |
direction |
"horizontal"|"vertical" |
是 | horizontal=左右翻转,vertical=上下翻转 |
output_path |
string |
否 | 保存路径 |
image_concat — 图片拼接
| 参数 | 类型 | 必需 | 默认值 | 说明 |
|---|---|---|---|---|
images |
string[] |
是 | — | 图片路径或 URL 列表 |
layout |
"horizontal"|"vertical"|"grid" |
是 | — | 拼接布局 |
cols |
number |
否 | — | grid 布局的列数 |
gap |
number |
否 | 0 | 图片间距(像素) |
background |
string |
否 | "#FFFFFF" |
背景色 |
output_path |
string |
否 | — | 保存路径 |
image_draw_box — 添加方框标记
| 参数 | 类型 | 必需 | 默认值 | 说明 |
|---|---|---|---|---|
image |
string |
是 | — | 图片路径或 URL |
boxes |
object[] |
是 | — | 方框列表 |
boxes[].x |
number |
是 | — | 方框左上角 x 坐标 |
boxes[].y |
number |
是 | — | 方框左上角 y 坐标 |
boxes[].w |
number |
是 | — | 方框宽度 |
boxes[].h |
number |
是 | — | 方框高度 |
boxes[].color |
string |
否 | "#FF0000" |
方框颜色 |
boxes[].label |
string |
否 | — | 方框标签文字 |
boxes[].line_width |
number |
否 | 自适应 | 线宽(像素) |
normalized |
boolean |
否 | false |
坐标是否为 0-1 归一化值 |
output_path |
string |
否 | — | 保存路径 |
image_draw_text — 添加文字标记
支持中文,中文字体通过 VISION_MCP_FONT_PATH 指定,或自动检测系统 CJK 字体。
| 参数 | 类型 | 必需 | 默认值 | 说明 |
|---|---|---|---|---|
image |
string |
是 | — | 图片路径或 URL |
texts |
object[] |
是 | — | 文字列表 |
texts[].x |
number |
是 | — | 文字左上角 x 坐标 |
texts[].y |
number |
是 | — | 文字左上角 y 坐标 |
texts[].text |
string |
是 | — | 文字内容(支持中文) |
texts[].font_size |
number |
否 | 24 | 字号(像素) |
texts[].color |
string |
否 | "#FF0000" |
文字颜色 |
texts[].background_color |
string |
否 | — | 文字背景色 |
normalized |
boolean |
否 | false |
坐标是否为 0-1 归一化值 |
output_path |
string |
否 | — | 保存路径 |
使用示例
示例 1:检测图片中的目标并标注
Agent: 我要找到这张图片中所有人的位置并标注出来
工具调用流程:
1. vision_detect(images=["photo.jpg"], target="人")
→ { detections: [{ label: "人", bbox: {x_min:0.1, y_min:0.2, x_max:0.3, y_max:0.5}, confidence: 0.9 }] }
2. image_draw_box(
image="photo.jpg",
boxes=[{ x:0.1, y:0.2, w:0.2, h:0.3, color:"#FF0000", label:"人" }],
normalized=true,
output_path="annotated.png"
)
→ 返回标注后的图片
示例 2:提取 PPT 中的文字
Agent: 提取这页 PPT 的所有文字内容
工具调用:
1. vision_ocr(images=["slide.png"])
→ { text_blocks: [...], full_text: "标题\n正文内容..." }
示例 3:检查 Web 页面是否符合设计要求
Agent: 检查这个页面截图的导航栏是否在顶部,按钮颜色是否为蓝色
工具调用:
1. vision_qa(images=["screenshot.png"], question="导航栏是否在页面顶部?按钮颜色是什么?")
→ "导航栏在页面顶部。按钮颜色为蓝色。"
示例 4:拼接多张截图后整体解读
Agent: 把这三张页面截图拼在一起,然后整体描述
工具调用:
1. image_concat(images=["p1.png","p2.png","p3.png"], layout="vertical")
→ 返回拼接后的图片
2. vision_describe(images=[拼接结果], detail_level="detailed")
→ 整体描述
项目结构
vision-mcp/
├── package.json
├── tsconfig.json
├── src/
│ ├── index.ts # 入口:server 初始化 + stdio 传输
│ ├── constants.ts # 环境变量、默认值、忠实性提示词
│ ├── types.ts # 共享类型定义
│ ├── schemas.ts # Zod 输入/输出 schema
│ ├── services/
│ │ ├── image-loader.ts # 路径/URL → buffer + metadata
│ │ ├── vlm-client.ts # OpenAI 兼容 VLM API 客户端
│ │ ├── image-processor.ts # sharp: resize/crop/rotate/flip/concat
│ │ └── image-annotator.ts # @napi-rs/canvas: draw_box/draw_text
│ └── tools/
│ ├── vlm.ts # 4 个 VLM 工具
│ └── image.ts # 8 个图像处理工具
├── eval/
│ ├── setup.mjs # 测试图片生成
│ ├── evaluation.xml # 评估问题
│ ├── test-all.mjs # 完整测试脚本
│ └── images/ # 测试图片
└── dist/ # 编译输出
技术栈
| 组件 | 技术 | 用途 |
|---|---|---|
| MCP SDK | @modelcontextprotocol/server v2 |
MCP 协议实现 |
| Schema 校验 | Zod v4 | 输入/输出验证 |
| 图像变换 | sharp | resize/crop/rotate/flip/concat/metadata |
| 图像标注 | @napi-rs/canvas | draw_box/draw_text(中文支持) |
| VLM 调用 | 原生 fetch | OpenAI 兼容 API,零额外依赖 |
| 传输方式 | stdio | 本地集成,单用户场景 |
设计要点
忠实性保障
- 所有 VLM prompt 内置忠实性指令:"只描述你在图片中能直接看到的内容,不要推测、脑补或添加图片中不存在的信息"
temperature: 0确保确定性输出- 检测工具要求模型在不确定时返回空结果
坐标归一化双重保障
- 系统提示词:
DETECTION_SYSTEM_PROMPT强制要求 0-1 归一化坐标,说明归一化公式 - 后处理:
normalizeBbox自动检测像素坐标(任一值 > 1.0),除以图片尺寸归一化
图像输出
- 始终返回 base64 PNG 图片内容(MCP
imagecontent type),LLM 可直接看到处理结果 - 可选
output_path参数保存到文件,适合大图和后续使用 structuredContent包含结果图片的宽高、格式、大小
中文字体支持
image_draw_text 的字体查找优先级:
VISION_MCP_FONT_PATH指定的字体文件- 系统 CJK 字体(Microsoft YaHei / SimHei / PingFang SC / Noto Sans CJK SC 等)
sans-serif回退(可能无法渲染中文)
开发
# 开发模式(热重载)
npm run dev
# 构建
npm run build
# 运行测试
node eval/test-all.mjs
# 生成测试图片
node eval/setup.mjs
许可证
MIT
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.