mcpField
C
color-engine-mcp

color-engine-mcp

本地服务
github.com/aimsise开发工具120 周前更新

关于 color-engine-mcp

color-engine-mcp 为设计与开发工作流提供纯内存 CSS 颜色工具,包括解析、转换、对比度计算、色域映射和色阶生成。它支持 WCAG 2.1,并可选计算 APCA 对比度。

主要功能

  1. 01解析并转换 CSS 颜色格式
  2. 02计算 WCAG 2.1 与可选 APCA 对比度
  3. 03将宽色域颜色映射到 sRGB
  4. 04生成色阶并输出设计令牌
  5. 05求解满足对比度目标的前景色

适用场景

  1. 01检查文字与背景的可访问性对比度
  2. 02将 P3 或 OKLCH 颜色映射到 sRGB
  3. 03为基础色生成设计系统色阶
  4. 04查找满足 WCAG 目标的文字颜色

MCP 相关

作为标准 stdio MCP 服务,它向 MCP 客户端提供六种颜色工具。所有操作仅在内存中运行,不进行网络 I/O 或文件系统写入。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"aimsise-color-engine": {
"command": "npx",
"args": [
"-y",
"color-engine-mcp"
]
}
}
}
启动命令npx -y color-engine-mcp

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npmcolor-engine-mcp1.0.1

工具

6

收录的工具列表 · 更新于 2 周前

参数类型必填说明
inputstring是CSS 颜色字符串,例如 "tomato"、"#ff6347"、"oklch(0.6 0.18 27)"(最多 256 个字符)

详细介绍

color-engine MCP Server

npm version CI License: MIT

一个 Model Context Protocol(MCP)服务,提供 6 种 CSS 颜色工具:解析、转换、色域映射、WCAG 对比度(可选 APCA)、色调/阴影渐变生成(可选设计令牌输出),以及对比度目标求解。所有工具都纯粹在内存中运行,不进行网络 I/O,也不写入文件系统。

工具用途
parse_color将任意 CSS 颜色字符串解析为十六进制、RGB、OKLCH 和色域信息
convert_color将颜色转换为规范的 hex / rgb / hsl / oklch 字符串
contrastWCAG 2.1 对比度及等级标记,可选提供 APCA Lc
gamut_map通过感知式 OKLCH 色度降低,将宽色域颜色映射到 sRGB
generate_ramp生成由浅色到深色的渐变,提供每个色块的对比度信息和设计令牌输出
solve_for_contrast查找满足相对于背景的 WCAG 对比度目标的前景色

本 README 中显示的所有 JSON 输出,均为通过 MCP Inspector CLI(npx @modelcontextprotocol/inspector --cli)从构建后的服务中捕获的真实响应。

安装

需要 Node.js >= 20。npm 包提供了 color-engine-mcp 可执行文件,因此无需克隆或构建,客户端可通过 npx 启动它。这是一个标准的 stdio MCP 服务,仅使用 tools 原语,因此任何兼容 MCP 的客户端都可以用相同方式注册:将启动命令指定给客户端,然后由客户端自行启动并管理进程。

对于 Claude Code,只需运行一条命令即可注册服务:

claude mcp add color-engine -- npx -y color-engine-mcp

(默认作用范围是本地项目;添加 --scope user 可将其注册到你的所有项目,添加 --scope project 则会写入共享的 .mcp.json。)

大多数其他使用 JSON 配置的客户端都可以直接使用以下配置格式:

{
  "mcpServers": {
    "color-engine": {
      "command": "npx",
      "args": ["-y", "color-engine-mcp"]
    }
  }
}

以下是一些常见客户端中配置文件的位置:

客户端配置文件
Claude Code项目根目录中的 .mcp.json
Claude Desktopclaude_desktop_config.json(例如 macOS 上的 ~/Library/Application Support/Claude/)
Cursor.cursor/mcp.json(每个项目单独配置)或 ~/.cursor/mcp.json(全局配置)
VS Code.vscode/mcp.json — VS Code 使用 servers 而不是 mcpServers 作为顶层键
Windsurf~/.codeium/windsurf/mcp_config.json

其他客户端(Zed、JetBrains、基于 MCP SDK 构建的自定义 Agent 等)仅在文件位置以及偶尔使用的顶层键名称上有所不同,请参阅它们的 MCP 服务注册文档。

已作为 io.github.aimsise/color-engine-mcp 列入官方 MCP Registry。

连接后,可以尝试向你的 Agent 提出以下请求:

  • “从 #3b82f6 生成一个包含 11 个步骤的 Tailwind 渐变”
  • “为背景色 #1e293b 查找对比度为 4.5:1 的无障碍文本颜色”

如需从克隆的仓库运行,请参阅开发。

颜色输入处理

每个工具都会通过同一个解析边界处理颜色字符串,因此以下规则统一适用。

接受的格式。 culori 能解析的任何 CSS 颜色字符串,包括命名颜色、十六进制(#rgb、#rgba、#rrggbb、#rrggbbaa)、rgb()/rgba()、hsl()/hsla() 和 oklch(),以及广色域 / CSS Color 4 格式:

  • color(display-p3 r g b)
  • lab(L a b) / lch(L C h)
  • oklab(L a b)
  • hwb(h w b)
  • color(rec2020 r g b)
  • color(a98-rgb r g b)
  • color(xyz-d65 x y z)

超出 sRGB 的广色域输入可以正常解析,并会报告 inGamut: false:

{ "input": "color(display-p3 1 0 0)" }
{
  "hex": "#ff0000",
  "rgb": { "r": 255, "g": 0, "b": 0 },
  "oklch": { "l": 0.6485740751442981, "c": 0.2994852863383699, "h": 28.958132730803953 },
  "inGamut": false
}

空白字符。 解析前会去除首尾空白字符——" #ff0000 " 会被解析为 #ff0000。

CSS Color 4 通道钳制(仅限旧式色彩空间)。 按照 CSS Color 4 的规定,十六进制 / rgb() / hsl() 输入中超出范围的通道会在解析边界处被钳制:rgb(-50 0 0) 的效果与 rgb(0 0 0) 完全相同,hsl() 的饱和度 / 明度也会钳制(色相会循环)。其他模式(oklch()、lab()、color(display-p3 …) 等)中的输入不会被钳制——其超出色域的值会原样传递,这正是 gamut_map 有用之处。

none 通道。 所有六个工具都会将 CSS Color 4 的 none 通道规范化为 0——oklch(0.5 none 30) 的效果与 oklch(0.5 0 30) 完全相同。

分量大小。 如果可解析的分量数值异常巨大(超过 1e6,例如 oklch(0.5 1e30 30)),则会被拒绝,并返回 COMPONENT_OUT_OF_RANGE——其中两个工具(gamut_map、solve_for_contrast)对此的处理方式有所不同;请参阅错误代码表。实际的超出色域值比这一限制低许多个数量级,因此不会受到影响。

Alpha 策略。 contrast 和 solve_for_contrast 会拒绝半透明颜色——任何显式设置的 alpha < 1,包括 rgba()/hsla() 函数式 alpha 和 4 / 8 位十六进制(#00000080)——并返回 ALPHA_UNSUPPORTED,因为半透明图层的实际颜色取决于未知的背景;请先将颜色与背景合成。其他工具都接受半透明输入,并且仅忽略 alpha 通道(计算时使用不透明颜色;输出不会包含 alpha 分量)。

长度上限。 去除首尾空白字符后,超过 256 个字符的颜色字符串会被拒绝,并返回 INPUT_TOO_LONG。

工具

parse_color

解析任意 CSS 颜色字符串,并返回十六进制、RGB、OKLCH 和色域信息。

输入架构

字段类型必填描述
input字符串是任意 CSS 颜色字符串,例如 "#ff0000"、"red"、"oklch(0.6 0.2 30)"

{ "input": "#ff0000" } 的输出

{
  "hex": "#ff0000",
  "rgb": { "r": 255, "g": 0, "b": 0 },
  "oklch": { "l": 0.6279553639214311, "c": 0.2576833038053608, "h": 29.233880279627854 },
  "inGamut": true
}

rgb 通道是经过 sRGB 钳制的 0–255 整数投影(与 hex 一致)。对于超出色域的输入(例如广色域 oklch(...)),通道会被钳制到 [0, 255],而不会报告原始超范围值——可使用 inGamut 标志判断输入是否超出 sRGB 色域。与之相反,oklch 块是输入的 原始(无损、未舍入) OKLCH,且对于非彩色,oklch.h 为 0。


convert_color

将 CSS 颜色字符串转换为规范的 hex、rgb、hsl 或 oklch 格式字符串。

输入架构

字段类型必填说明
inputstring是任意 CSS 颜色字符串
tostring是目标格式:"hex"、"rgb"、"hsl" 或 "oklch"

{ "input": "#ff0000", "to": "oklch" } 的输出

{ "result": "oklch(0.62796 0.25768 29.23)" }

超出色域输入的原始值与钳制值

对于超出 sRGB 色域的颜色,目标格式会有所不同:

  • to: "oklch" 返回原始、无损的 OKLCH 三元组,因此超出色域的颜色可以忠实地往返转换。例如,{ "input": "oklch(0.7 0.4 30)", "to": "oklch" } → "oklch(0.70000 0.40000 30.00)"。
  • to: "hex"、"rgb" 和 "hsl" 均基于钳制到 sRGB 色域的投影值派生,并返回色域内的近似值。例如,{ "input": "oklch(0.7 0.4 30)", "to": "rgb" } → "rgb(255, 0, 0)"。rgb 通道值为 [0, 255] 范围内的整数。

(L/C 保留 5 位小数,H 保留 2 位小数,可确保在整个 sRGB 立方体范围内精确往返转换为 hex。)


contrast

计算两个完全不透明的 CSS 颜色字符串之间的 WCAG 2.1 对比度,并返回等级标志。还可选择计算 APCA Lc 值(参见 APCA(可选的感知对比度))。

输入架构

字段类型必填说明
astring是第一个 CSS 颜色字符串(在 APCA 中视为文本/前景色),例如 "#000000"
bstring是第二个 CSS 颜色字符串(在 APCA 中视为背景色),例如 "#ffffff"
apcaboolean否为 true 时,额外返回文本 a 在背景 b 上的有符号 APCA-W3 apcaLc

{ "a": "#000000", "b": "#ffffff" } 的输出

{
  "ratio": 21,
  "aaNormal": true,
  "aaLarge": true,
  "aaaNormal": true,
  "aaaLarge": true
}

ratio 是保留 2 位小数的显示值。四个等级布尔值根据未舍入的原始比率计算(因此,原始值接近边界的 4.4999 虽显示为 4.50,仍会得到 aaNormal: false)。

WCAG 2.1 等级阈值:

  • aaNormal / aaLarge 要求比率 ≥ 4.5 / ≥ 3.0
  • aaaNormal / aaaLarge 要求比率 ≥ 7.0 / ≥ 4.5

错误。 无法解析的字符串会产生带参数名称的错误:对于 a,为 PARSE_FAILED: could not parse the foreground color;对于 b,为 PARSE_FAILED: could not parse the background color。半透明输入会产生 ALPHA_UNSUPPORTED(参见 Alpha 策略)。

APCA(可选的感知对比度)

传入 apca: true 可额外获取 apcaLc,即文本 a 在背景 b 上的有符号 APCA-W3(SAPC-4g)亮度对比度 Lc,结果保留 2 位小数(对于 APCA,参数顺序很重要,不同于对称的 WCAG 比率)。符号表示极性:深色文字在浅色背景上为正值,浅色文字在深色背景上为负值;比较时使用 |Lc| 的绝对值。

{ "a": "#1a1a1a", "b": "#ffffff", "apca": true }
{ "ratio": 17.4, "aaNormal": true, "aaLarge": true, "aaaNormal": true, "aaaLarge": true, "apcaLc": 104.27 }

反转颜色对会使符号翻转:{ "a": "#ffffff", "b": "#1a1a1a", "apca": true } → "apcaLc": -106.55(WCAG ratio 仍为 17.4,因为 WCAG 比率具有对称性)。

常见引用的 APCA 指南阈值(按 |Lc|):

|Lc|常见指南用途
45大号/粗体文字的最低值
60其他内容文字的最低值
75正文文字
90正文文字的理想值

免责声明: APCA 是 WCAG 3 的候选方法,尚未成为规范性 WCAG 标准;如需声明符合标准,请使用 WCAG 2.1 等级标志。


gamut_map

通过感知式 OKLCH 色度缩减,将任意 CSS 颜色字符串映射到 sRGB 色域。适用于将广色域颜色(P3、Rec2020、任意 OKLCH)转换为可显示的 sRGB 颜色。

输入架构

字段类型必填描述
inputstring是任意 CSS 颜色字符串,例如 "oklch(0.6 0.4 30)"

输出:对于 { "input": "oklch(0.6 0.4 30)" }

{
  "hex": "#f70000",
  "oklch": { "l": 0.6137129506655941, "c": 0.25183888824211537, "h": 29.233880279628004 },
  "clamped": true
}

当输入超出 sRGB 色域且必须进行映射时,clamped 为 true。返回的 oklch 是映射后色域内结果的原始 OKLCH 值(感知式缩减了色度),而非原始输入的值。

恒等性与幂等性。 对于已位于 sRGB 色域内的输入,将原样返回:clamped 为 false,且 hex 与输入的规范十六进制颜色完全一致(例如 { "input": "#3b82f6" } → { "hex": "#3b82f6", …, "clamped": false })。此工具也具有幂等性:其输出的十六进制颜色始终位于色域内,因此将结果再次输入时会走恒等路径,并返回相同的十六进制颜色。


generate_ramp

根据基础 CSS 颜色生成从浅色到深色的色阶。返回按顺序排列的色板,每个色板都包含十六进制颜色、OKLCH、相对于白色和黑色的 WCAG 对比度,以及色域标志。还可选择将色阶输出为设计令牌(参见设计令牌)。

输入架构

字段类型必填描述
basestring是任意 CSS 颜色字符串,例如 "#3b82f6"
stepsinteger否色板数量(2–512)。默认值:5
lightnessMinnumber否亮度下限(OKLCH L,0–1)。默认值:0.05
lightnessMaxnumber否亮度上限(OKLCH L,0–1)。默认值:0.97
deltaLnumber否以基础颜色的 L 为中心的总亮度跨度——端点为基础 L ± deltaL/2(覆盖固定范围)
tokenFormatstring否"tailwind" 或 "css-variables"——指定后,输出会包含一个 tokens 字符串
tokenNamestring否输出令牌的基础名称(字母/数字/连字符,必须以字母开头,长度为 1–64 个字符)。默认值:"color"

输出:对于 { "base": "#3b82f6", "steps": 5 }(显示 5 个色板中的第一个)

{
  "swatches": [
    {
      "step": 0,
      "hex": "#f5f5f5",
      "oklch": { "l": 0.97, "c": 0, "h": 259.81 },
      "vsWhite": { "ratio": 1.09, "tier": "FAIL" },
      "vsBlack": { "ratio": 19.26, "tier": "AAA" },
      "inGamut": true
    }
  ]
}

色板索引从零开始:色板按亮度从高到低排列(step: 0 最浅,step: steps - 1 最深),OKLCH 亮度严格递减。(上方完整的 5 个色板响应中,位于色域内的基础颜色 #3b82f6 会在 step: 2 原样出现——色阶会将最接近基础颜色亮度的步骤作为锚点。)

每个色板都包含 vsWhite/vsBlack,其结构均为 { ratio, tier },其中 ratio 是相对于白色/黑色的 WCAG 对比度,tier 为 "AAA"(原始比率 ≥ 7.0)、"AA"(≥ 4.5)或 "FAIL"。

显示精度处理。 色板数值会按显示精度取整:对比度 ratio 保留 2 位小数,oklch.l/oklch.c 保留 5 位小数,oklch.h 保留 2 位小数。tier 分类仍基于未取整的原始比率(原始值为 6.9999 时会显示为 7.00,但分类为 "AA")。

阈值附近的等级量化。 每个色板的对比度均根据其 8 位 hex 计算(这是权威的显示颜色),因此在距离等级阈值(3.0/4.5/7.0)约 0.01 的范围内,量化可能导致等级与浮点精度计算的结果不同。如果需要确保留有余量,请将目标比率设为明显高于阈值的值(例如,按 4.6 而非 4.5 求解)。

验证规则

数值约束已在工具架构中声明,因此 SDK 会在处理程序运行前拒绝超出范围的调用——通过 MCP 调用时,这些拒绝会作为 SDK 的验证错误返回,而非下方列出的工具级错误代码(参见架构层与工具层的强制校验):

  • steps 必须是 [2, 512] 范围内的整数 → 否则返回 STEPS_OUT_OF_RANGE。
  • 如果提供 deltaL,则必须是大于 0 的有限数值 → 否则返回 INVALID_DELTA_L。
  • 解析后的明度范围必须满足 lightnessMin < lightnessMax(端点会先被限制在 [0, 1] 范围内)→ 否则返回 INVALID_LIGHTNESS_RANGE。
  • 基础颜色的 OKLCH 色度必须 ≤ 100 → 否则返回 BASE_CHROMA_OUT_OF_RANGE。
  • 如果 base 解析失败,则转发解析错误代码(PARSE_FAILED、INPUT_TOO_LONG、COMPONENT_OUT_OF_RANGE 或 NON_FINITE_COMPONENTS)。

负载大小。 steps: 512 的调用会在工具结果中返回约 200 KB 的 JSON(美化打印后约为 280 KB)。在 LLM 上下文中,建议使用较小的步数(5–11)——只需极少的令牌,就能覆盖几乎所有设计系统的使用场景。

关于 swatch.oklch 与 swatch.hex 的说明

每个色板报告的 oklch 是经过 目标明度/色度限制 的投影(目标明度下将色度降低至 sRGB 色域内),这能保持整个渐变中的明度严格单调。因此,它可能与根据 swatch.hex 计算出的精确 OKLCH 略有不同(ΔL 最大约为 0.013)。这是有意为之的权衡:优先保证明度单调,而非精确还原十六进制颜色;hex 仍是权威的显示颜色。

设计令牌

传入 tokenFormat(以及可选的 tokenName),即可在 swatches 之外额外获得一个 tokens 字符串。

  • 步数恰好为 11 时,令牌键使用 Tailwind 标准刻度 50, 100, 200, …, 900, 950(色板 0——最浅色——对应 50)。
  • 其他任何步数都使用从零开始的 step 索引作为键。

tokenFormat: "tailwind" — 美化打印的 JSON 对象字符串。对于 { "base": "#3b82f6", "steps": 11, "tokenFormat": "tailwind", "tokenName": "blue" },tokens 输出如下:

{
  "blue": {
    "50": "#f5f5f5",
    "100": "#c1d8fe",
    "200": "#8fbaff",
    "300": "#629bfa",
    "400": "#3b82f6",
    "500": "#155ecf",
    "600": "#0043ab",
    "700": "#002b80",
    "800": "#001750",
    "900": "#000721",
    "950": "#000000"
  }
}

tokenFormat: "css-variables" — 一个 :root 块。对于 { "base": "#3b82f6", "steps": 5, "tokenFormat": "css-variables", "tokenName": "brand" },tokens 输出如下:

:root {
  --brand-0: #f5f5f5;
  --brand-1: #78abfe;
  --brand-2: #3b82f6;
  --brand-3: #002068;
  --brand-4: #000000;
}

tokenName 会在架构边界处进行验证(/^[a-z][a-z0-9-]*$/i,1–64 个字符),因此始终可以安全地嵌入 CSS 自定义属性名称或 JSON 键中。


solve_for_contrast

查找满足背景色一个或多个 WCAG 2.1 对比度目标的前景色。通过二分搜索 OKLCH 明度(色相和色度保持不变)。

输入架构

字段类型必填说明
backgroundstring是背景 CSS 颜色字符串
targetnumber二选一单个 WCAG 2.1 对比度目标(例如 4.5、7)
targetsnumber[]二选一多个对比度目标(1–50 项;不接受空数组)
prefer"lighter","darker","either"否搜索方向。默认值:"either"
huenumber否搜索期间保持不变的固定 OKLCH 色相(度)
chromanumber否搜索期间保持不变的固定 OKLCH 色度(≥ 0)

hue/chroma 默认值——传入 chroma 以保持饱和度

省略时,chroma 默认为背景自身的色度,hue 默认为背景的色相(若背景为无彩色,则默认为 0)。有两点值得注意:

  • 仅传入 hue 不会增加饱和度。 对于无彩色背景(白色/灰色/黑色),默认色度为 0,因此无论传入什么色相,结果都是无彩色灰色。对于 #ffffff,当 target: 4.5 时:{ "hue": 260 } → { "met": true, "color": "#767676", "ratio": 4.54 }(与完全不传色相时得到的灰色相同),而 { "hue": 260, "chroma": 0.15 } → { "met": true, "color": "#4075cf", "ratio": 4.5 }(真正的蓝色)。
  • 仅传入 chroma 时,色相固定为背景的色相(若背景为无彩色,则为 0)。如果 sRGB 色域要求降低色度,系统仍可能按明度降低固定的色度。

target 与 targets 的优先级及响应结构

传入单个 target 或 targets(数组)。如果同时传入两者,则以 targets 为准,并忽略单个 target。两种模式会返回不同的响应结构:

  • 单个 target → { met, color, ratio }(另可能包含 nearMiss 标记)。
  • targets 数组 → { results: [ { met, color, ratio, nearMiss? }, ... ] },按请求顺序为每个目标返回一项。

已注册的输出架构是两种结构的全可选超集;每个响应只会填充其中一种结构。

输入 { "background": "#ffffff", "target": 4.5, "prefer": "darker" } 的输出

{ "met": true, "color": "#767676", "ratio": 4.54 }

输入 { "background": "#1e293b", "targets": [4.5, 7] } 的输出

{
  "results": [
    { "met": true, "color": "#8290a6", "ratio": 4.52 },
    { "met": true, "color": "#a6b5cc", "ratio": 7.04 }
  ]
}

当 met 通过接近上限的容差判定时,可能会出现 nearMiss: true(无论是在单个结果中,还是在 results 内的某一项中):在搜索方向上可达到的最佳原始对比度与目标相差不超过 0.03,且低于目标。使用方向性 prefer("lighter"/"darker")时,只搜索对应的一侧,因此另一侧仍可能严格满足目标;使用 "either" 模式时,始终优先选择严格满足目标的一侧,所以只有在两侧都无法严格满足目标时,才会出现 nearMiss。

错误。 无法解析的背景会返回带有 PARSE_FAILED: could not parse the background color 的 isError——单个 target 和 targets 两种路径均如此。半透明背景会产生 ALPHA_UNSUPPORTED(请参阅 Alpha policy)。


错误处理

每个工具都是全定义的:格式错误或超出范围的输入不会导致服务崩溃,也不会泄露堆栈跟踪。发生故障时,工具会返回一个 isError: true 的 MCP 结果,其中包含一个文本内容块,文本遵循统一的 <CODE>: message 格式,<CODE> 是来自封闭集合的 UPPER_SNAKE_CASE 值。消息是静态且安全的字符串,不会包含原始输入、文件路径、堆栈或库内部信息。出错时,工具不会设置 structuredContent。

错误文本示例:

PARSE_FAILED: could not parse the provided color string

任何意外内部故障的兜底错误始终为:

INTERNAL_ERROR: unexpected internal error
架构层与工具层的强制校验

工具的 zod 输入架构中声明的约束,由 MCP SDK 在工具处理程序运行前强制校验——处理程序不会执行,结果也不包含 structuredContent。在 MCP SDK 1.29 中,这种拒绝会以内嵌方式返回为带错误标记的工具结果(isError: true),其文本以 MCP error -32602: Input validation error: … 开头——该文本由 SDK 生成,不受上述统一 CODE: message 格式和不包含内部信息的保证约束(这些保证仅适用于工具层错误);未来的 SDK 版本可能会改为返回真正的 -32602 协议错误,因此不要针对具体的返回方式或措辞进行模式匹配。对应的工具层错误代码会予以保留,作为纵深防御,供直接调用库的调用方使用(即导入处理程序或 src/lib 函数并绕过 SDK 校验的代码)。由架构强制校验的约束:

  • INPUT_TOO_LONG — 每个颜色字符串字段都声明了 .max(256)。
  • STEPS_OUT_OF_RANGE — steps 声明为整数,范围为 2..512。
  • INVALID_DELTA_L — deltaL 声明为有限且 > 0。
  • TOO_MANY_TARGETS — targets 声明了 .max(50)。
  • EMPTY_TARGETS — targets 声明了 .min(1)(空数组会在处理程序运行前被拒绝)。
  • INVALID_TARGET、INVALID_CHROMA 和 INVALID_HUE 所依据的有限性/符号约束同样由架构声明(而且 JSON 本身无法表示非有限数字)。
错误代码
代码含义
INPUT_TOO_LONG颜色字符串超过了 256 个字符的上限(用于防范 DoS,在解析前执行;由 schema 强制执行)。
PARSE_FAILED无法将提供的颜色字符串解析为任何 CSS 颜色。在 contrast 和 solve_for_contrast 中,静态消息会指出失败的参数:could not parse the foreground color / could not parse the background color。
COMPONENT_OUT_OF_RANGE可解析的颜色分量幅度异常(> 1e6),例如 oklch(0.5 1e30 30)——由 parse_color、convert_color、contrast 和 generate_ramp 返回。例外:gamut_map 会以 CHROMA_OUT_OF_RANGE 拒绝相同输入(其色度范围检查会先触发),而 solve_for_contrast 会将其报告为带参数名称的 PARSE_FAILED。
ALPHA_UNSUPPORTEDcontrast / solve_for_contrast 收到了半透明颜色(显式 alpha < 1,包括 4 位/8 位十六进制颜色)。静态消息:contrast requires fully opaque colors (alpha = 1); composite the color over its backdrop first。
NON_FINITE_COMPONENTS颜色解析结果包含非有限的 RGB/OKLCH 分量(例如色度溢出)。
NON_FINITE_LUMINANCE对比度计算产生了非有限的亮度值。
NON_FINITE_OKLCH_COMPONENTS色域映射期间,OKLCH 明度/色度为非有限值。
NULL_OKLCH_CHANNELS色域映射期间,OKLCH 通道解析为 null。
NON_FINITE_OKLCH_HUE色域映射期间,彩色的 OKLCH 色相为非有限值。
CHROMA_OUT_OF_RANGEOKLCH 色度超过了色域映射器支持的最大值(100)。对于 oklch(0.5 1e30 30),gamut_map 会返回此错误——而不是 COMPONENT_OUT_OF_RANGE。
GAMUT_MAP_COLLAPSE色域映射导致通道变为 null/非有限值。
STEPS_OUT_OF_RANGEgenerate_ramp 的 steps 不是 [2, 512] 范围内的整数(由 schema 强制执行)。
INVALID_LIGHTNESS_RANGEgenerate_ramp 解析出的 lightnessMin >= lightnessMax。
INVALID_DELTA_Lgenerate_ramp 的 deltaL 不是大于 0 的有限数值(由 schema 强制执行)。
BASE_CHROMA_OUT_OF_RANGEgenerate_ramp 的基础 OKLCH 色度超过了 100。
MISSING_BACKGROUND调用 solve_for_contrast 时未提供 background。
MISSING_TARGET调用 solve_for_contrast 时既未提供 target,也未提供 targets。
EMPTY_TARGETSsolve_for_contrast 的 targets 是空数组(通过 .min(1) 由 schema 强制执行)。
TOO_MANY_TARGETSsolve_for_contrast 的 targets 超过了 50 项(由 schema 强制执行)。
INVALID_TARGETsolve_for_contrast 的某个 target 不是大于等于 0 的有限数值。
INVALID_CHROMAsolve_for_contrast 的 chroma 不是大于等于 0 的有限数值。
INVALID_HUEsolve_for_contrast 的 hue 不是有限数值。
INVALID_GEOMETRYsolve_for_contrast 解析出的色相/色度为非有限值,或色度为负数。通过 MCP 调用时,显式指定的 hue/chroma 会先经过 schema 验证,因此此错误代码实际上是为直接调用库的情况提供的纵深防御。
INTERNAL_ERROR用于捕获任何意外内部错误。

工具注解和服务元数据

六个工具都注册了 MCP 工具注解,声明它们为只读且无副作用(readOnlyHint: true、idempotentHint: true、destructiveHint: false、openWorldHint: false),并附有便于阅读的 title。服务本身注册了一个 title("Color Engine")和一段 instructions 字符串,其中概述了六个工具、优先采用 OKLCH 的设计、舍入规则,以及供连接的客户端使用的错误格式(特别是引导 Agent 在需要达到某个比率而不只是测量比率时使用 solve_for_contrast)。每个工具结果都包含 structuredContent 及与之等效的纯文本内容块,因此无法处理结构化输出的客户端也不会遗漏任何信息。

准确性与性能

准确性(均已在测试套件中验证——运行 npm test 即可复现):

  • WCAG 比率通过双重基准验证:一套基于原理实现的 WCAG 2.1 亮度算法,以及独立的 colorjs.io 实现;通过跨越各阈值(3.0 / 4.5 / 7.0)的颜色对检查等级分类。
  • 在覆盖 sRGB 色域的数千个确定性网格点和带种子的模糊测试样本中,hex ↔ OKLCH 往返转换的字节结果完全一致。
  • APCA 与独立的 colorjs.io APCA 实现的差异不超过 0.1 Lc,两种极性下均如此。
  • gamut_map 对色域内颜色返回逐位完全相同的结果,且对自身输出具有幂等性。

性能(每次调用的中位数,使用 Node v25.9.0 通过 npm run build && npm run bench 测得——仅供参考,不作保证):

调用中位数(毫秒)
parse_color0.005
convert_color0.002
contrast0.004
gamut_map(输入超出色域)0.015
generate_ramp(steps=5)0.037
solve_for_contrast(单个目标)0.067
generate_ramp(steps=512,最坏情况)3.3
solve_for_contrast(50 个目标,最坏情况)2.7

冷启动(从启动进程到收到 initialize 响应)中位数约为 135 ms。

开发

构建
npm install
npm run build

编译后的服务位于 dist/server.js。

从源代码运行。 若要让 MCP 客户端指向本地克隆,而非 npm 包,请先构建,然后使用:

{
  "mcpServers": {
    "color-engine": {
      "command": "node",
      "args": ["/absolute/path/to/color-engine-mcp/dist/server.js"]
    }
  }
}

将 /absolute/path/to/color-engine-mcp/dist/server.js 替换为克隆中 dist/server.js 的实际路径。

测试
npm test

运行完整测试套件(包括通过 npx @modelcontextprotocol/inspector --cli 运行的 MCP Inspector CLI 集成测试)。pretest 脚本会自动运行 tsc,确保在 Inspector 测试运行前 dist/server.js 是最新的。

基准测试
npm run build
npm run bench

对构建后的 dist/ 处理程序运行 scripts/bench.mjs(每个用例预热 20 次、计时 200 次,并报告中位数)——这是 准确性与性能 中数据的来源。

更新日志

请参阅 CHANGELOG.md 查看发布历史。

许可证

MIT——请参阅 LICENSE。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。