Skip to main content
Glama

image-viewer-mcp

一个用 Node.js 编写的 MCP 服务器。它接收图片的本地路径或 URL,把图片交给视觉语言模型(VLM)识别内容,返回三段结构化的描述,让只看得见文字的 LLM 也能完整理解图片。

背景

纯文本的 LLM 看不到图片。如果需要让它在对话中理解一张截图、一张图表或一张照片,常见的做法是借助外部视觉模型代为描述。本项目以 MCP 工具的形式提供这种能力,任何支持 MCP 的客户端(如 Claude Code、Claude Desktop)都可以直接调用。

Related MCP server: vision-mcp

功能

  • 输入:本机图片的绝对路径、http(s) 图片 URL,或 data: 内联图片 URL

  • 可选输入:图片背景信息(context),帮助模型更精准地识别

  • 输出:三个字段,按工具调用的结构化结果返回

字段

含义

brief

简要描述图片

description

详细描述图片

summary

总结图片的意图、潜在含义、代表意义

  • 返回格式可切换:text(可读文本)、json(JSON 字符串)、raw(VLM 原始输出),默认取配置 output.format,调用时可用 format 参数覆盖

  • 识别缓存:按图片内容 hash 复用识别结果,同图同配置直接返回缓存,节省 API 调用;默认启用,调用时可用 use_cache 参数控制

  • 支持格式:PNG / JPG / JPEG / GIF / WEBP / AVIF / SVG,单张不超过 20MB

    • SVG 在服务端用 @resvg/resvg-js 自动转成 PNG 后再送模型,调用方无感(本地 SVG 文件或 SVG URL 均可);尺寸过小(<14px)的 SVG 会自动放大到模型可读

    • AVIF 在服务端用 sharp 自动转码为 PNG 再送模型,不依赖模型侧对 AVIF 的支持

    • 过小的位图(如 icon)按整数倍自动放大到模型可读尺寸,避免被模型拒绝

  • 后端默认使用 OpenAI 的 gpt-4o 视觉模型,可通过配置更换模型或改用任何兼容 OpenAI 协议的服务

工作原理

flowchart LR
    A[客户端调用 analyze_image] --> B{图片来源}
    B -->|本地路径| C[读取文件,按扩展名识别 MIME]
    B -->|http URL| D[下载图片,按响应头识别 MIME]
    B -->|data URL| E[解析内联 base64]
    C --> F[base64 编码]
    D --> F
    E --> F
    F --> G[组装多模态消息]
    G --> H[调用 VLM 接口]
    H --> I[解析三段 XML 标签]
    I --> J[返回 brief / description / summary]

安装

要求 Node.js 18 或更高版本。

npm install

配置

配置有两种方式:config.yaml 配置文件和环境变量。环境变量的优先级高于配置文件,便于在 MCP 客户端(如 Claude Code)中直接注入 Key。

优先级从高到低:环境变量 > config.yaml > 内置默认值。

配置文件

复制 config.example.yamlconfig.yaml,按需修改。config.yaml 已被 .gitignore 忽略,不会入库,可安全存放 API Key。

查找位置:默认在 src/index.js 所在目录的上一级(即项目根目录)查找 config.yaml,与启动服务器时的工作目录无关。也可以把配置文件放到任意位置,用 --config <路径> 参数或 CONFIG_PATH 环境变量指定;这两种方式给出的相对路径按当前工作目录解析。

api_key 外所有字段均可选,未写的字段使用内置默认值。完整字段如下:

字段

默认值

说明

api_key

无(必填)

OpenAI API Key

base_url

官方地址

自定义 API 地址,兼容 OpenAI 协议的中转服务也可用

extra_headers

附加 HTTP 请求头,部分中转服务需要自定义鉴权头

model

gpt-4o

视觉模型名

max_tokens

2048

单次回答的最大 token 数

temperature

0.2

采样温度,越低越稳定,识别类任务建议 0 ~ 0.5

top_p

不发送

核采样概率,不写则按模型默认

timeout_seconds

120

单次请求超时(秒)

max_retries

2

网络异常时自动重试次数

max_image_size_mb

20

图片大小上限(MB)

download_timeout_seconds

30

网络图片下载超时(秒)

svg.render_size

512

SVG 未声明尺寸时的兜底渲染像素;密集元素建议调大

svg.min_pixel

14

渲染尺寸下限:SVG 低于则放大到 render_size;位图低于则整数倍放大

svg.auto_size

true

自动推断合适渲染尺寸(按最小字号 + 元素密度),声明尺寸也参与评估

svg.min_text_px

14

自动推断时最小文字渲染高度目标(像素)

svg.density_px

20

自动推断时每个元素的平均占地(像素),越大越清晰

svg.max_render_size

4096

自动推断的尺寸上限

prompts

见下方

提示词配置,全部可自定义

output.format

text

返回格式:text 可读文本、json JSON 字符串、raw VLM 原始输出,调用时可覆盖

cache.enabled

true

是否默认启用识别缓存,调用时可覆盖

cache.dir

.cache

缓存目录,相对项目根目录

cache.key_components

三个均开

缓存键组成,image / config / context 各可独立开关

提示词配置

prompts 段控制发给 VLM 的全部提示词。三段输出的标签(tag)、标题(heading)、可读名称(label)均可自定义;用户提示词由配置自动生成,修改 tag 后提示词与解析器自动同步,不需要改两处。

prompts:
  system: |                      # 系统提示:约束角色、输出语言与回答纪律
    你是一个专业的图片内容识别助手。只依据图片和给定的背景信息进行描述,
    不虚构图片中不存在的细节。必须使用中文回答。
  instruction: |                 # 指令:紧跟图片发送,说明任务目标
    详细描述图片内容,目标是让仅能看到文字的LLM能够完全理解图片内容。
    回答格式:
  context_label: "图片背景信息(仅作参考):"   # 附加 context 参数时的引导语
  require_all_sections: true     # true 时任何一段缺失都按格式违规;false 时缺失段落留空
  sections:                      # 三段输出配置;key 固定,可只写想改的段,其余继承默认值
    - key: brief                 # 与工具输出字段对应
      tag: image_brief           # 模型回答中的包裹标签,解析器按此提取
      heading: 简要描述图片       # 提示词中该段的占位说明
      label: 简要                # 可读文本中该段的名称
    - key: description
      tag: image_description
      heading: 详细描述图片
      label: 详细
    - key: summary
      tag: image_summary
      heading: 总结图片意图/潜在含义/代表意义等
      label: 总结

环境变量

环境变量

说明

OPENAI_API_KEY

OpenAI API Key,设置后覆盖配置文件中的 api_key

OPENAI_BASE_URL

自定义 API 地址,覆盖配置文件中的 base_url

VLM_MODEL

视觉模型名,覆盖配置文件中的 model

VLM_MAX_TOKENS

单次回答的最大 token 数,覆盖配置文件中的 max_tokens

缺少 API Key 时服务器会拒绝启动并给出明确提示。

在 Claude Code 中使用

~/.claude.json 或项目的 .mcp.json 中添加以下配置:

{
  "mcpServers": {
    "image-viewer": {
      "command": "node",
      "args": ["/绝对路径/image-viewer-mcp/src/index.js"],
      "env": {
        "OPENAI_API_KEY": "sk-你的key"
      }
    }
  }
}

配置完成后,直接让 Claude 描述一张图片即可,例如:

帮我看看 /home/user/screenshots/bug.png 里有什么,这是报错截图

手动测试

# 运行单元测试(提示词生成、解析、配置校验)
npm test

# 列出工具
node test/client.js --list

# 识别本地图片(可附加背景信息)
node test/client.js /path/to/image.png "这是监控截图"

# 识别网络图片
node test/client.js "https://example.com/image.jpg"

# 指定返回格式
node test/client.js /path/to/image.png --format json

# 强制重新识别(不使用缓存)
node test/client.js /path/to/image.png --no-cache

# 使用 config.yaml 配置后直接运行服务器(stdio 模式)
npm start

# 指定其他位置的配置文件
node src/index.js --config /path/to/config.yaml

输出示例

analyze_image 调用成功时返回:

{
  "content": [
    { "type": "text", "text": "【简要】...\n\n【详细】...\n\n【总结】..." }
  ],
  "structuredContent": {
    "brief": "简要描述",
    "description": "详细描述",
    "summary": "总结"
  },
  "_meta": { "cache": "hit" }
}
  • content 通道按 format 显示:text(默认)为可读文本,json 为 JSON 字符串,raw 为 VLM 原始输出

  • structuredContent 始终是结构化的三段字段,供程序化消费

  • _meta.cache 表示本次结果来源:hit 命中缓存、miss 新识别并写入缓存、disabled 未启用缓存

失败时(文件不存在、格式不支持、网络错误、API 报错等)返回 isError: true 和中文错误说明,调用方 LLM 可以直接看到原因。

缓存机制

缓存键由三部分构成,各部分在 cache.key_components 中独立开关。参与计算的组件任一变化都会得到不同的缓存,避免返回过期结果:

  • image:图片内容 hash(同一张图无论来自路径还是 URL 都相同)

  • config:模型与提示词配置 hash(改配置后缓存自动失效)

  • context:背景信息 hash(不同背景要求不同的识别结果)

例如背景信息可能频繁变化、又希望同一张图复用缓存时,可以关闭 context 组件:

cache:
  key_components:
    context: false

关闭后,同一张图无论背景怎么变都命中同一缓存。至少需要启用一个组件,全部关闭会在启动时报错。

缓存默认写入项目根目录的 .cache/(已被 .gitignore 忽略),每张图一条 JSON 文件。每条缓存保存完整的模型与提示词参数(model / max_tokens / temperature / top_p / prompts 等)以及命中所用的键组成,便于排查缓存为何命中或失效。缓存读失败或写失败都不影响主流程。

限制

  • 图片最大 20MB,与 OpenAI 视觉接口的上限一致

  • 模型的识别质量取决于所配置的 VLM,更换更强或更弱的模型会影响输出精度

  • 图片数据以 base64 内联形式发送给配置的模型服务商,请勿在需要保密的场景上传敏感图片

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers