关于 stylespeak
stylespeak 是面向 AI 编码 Agent 的 CSS 分析 MCP 服务和命令行工具,可解析层叠规则、追踪属性来源并预览改动影响。它支持 CSS、SCSS、CSS Modules 及 styled-components 和 Emotion 等 CSS-in-JS;也可查询运行中 Chromium 的实际计算样式。
主要功能
- 01解析选择器实际应用的样式
- 02追踪属性设置与层叠胜出规则
- 03预览样式改动影响范围
- 04生成项目 CSS 结构摘要
- 05查询 Chromium 计算样式
- 06解析 CSS-in-JS 与自定义属性
适用场景
- 01修改样式前确认当前生效规则
- 02评估 CSS 属性变更影响
- 03为 Agent 加载项目样式概览
- 04在运行中的浏览器核对计算样式
MCP 相关
作为 MCP 服务,向客户端提供样式解析、属性追踪、影响预览、项目清单和浏览器实时查询工具,帮助 Agent 在修改前了解 CSS 行为。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
5收录的工具列表 · 更新于 3 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| files | array | 否 | 要分析的 CSS/SCSS 文件的绝对路径。 |
| selector | string | 是 | 要解析的 CSS 选择器,例如 ".btn.primary"、"#header a:hover" |
| projectRoot | string | 否 | 可选:项目根目录路径。将递归发现所有 CSS/SCSS 文件。 |
| componentFiles | array | 否 | 可选:JSX/TSX 文件的绝对路径。提供后,将构建 AST 组件图;在确认祖先关系的情况下,将选择器置信度从 possible 提升为 likely。 |
详细介绍
StyleSpeak - MCP and CLI
stylesafe 的配套 MCP 服务和 CLI,可让 AI Agent 清晰理解 CSS——解析层叠关系、追踪属性、预测变更影响,并在 Agent 修改任何样式之前解释哪些规则生效以及原因。
问题
AI 编码 Agent 编写 CSS 时看不到其效果。它们修改一条规则,以为修改生效了,便继续处理,却不知道其他位置已有优先级更高的规则将其覆盖、另一个文件中的组合器规则正悄然生效,或者 CSS 变量解析出的值与预期完全不同。stylespeak 为 Agent 提供结构化的知识层,让它们在进行修改之前先行查询。
功能
resolve_styles — 回答“这个选择器实际应用了哪些 CSS?”
给定一个选择器和一组文件,返回该选择器将获得的每个 CSS 属性、每个属性由哪条规则胜出,以及哪些规则被覆盖;由于没有实际 DOM,还会提供置信度等级。CSS 自定义属性(var())会被解析为实际值,包括链式变量、回退值和媒体上下文覆盖。
trace_property — 回答“这个属性在哪些地方被设置,由哪条规则胜出?”
给定一个属性名称和一组文件,返回设置该属性的所有规则,将目标选择器存在重叠的竞争规则分组,并展示每组完整的层叠链——其中也包含解析后的变量值。
impact_preview — 回答“如果我修改这里,其他地方会有什么影响?”
给定一个选择器、属性和可选的新值,可在修改之前预测变更的全部影响范围——展示哪些选择器的值会发生变化、哪些受优先级更高的规则保护、哪些层叠关系尚不确定,以及哪些下游规则会受到 CSS 变量链或属性继承的影响。无需浏览器。
style_manifest — 回答“如何快速了解整个项目的 CSS?”
构建项目全部 CSS 知识的精简结构化摘要,包括选择器、属性、变量、竞争组和风险热点。Agent 可在会话开始时加载一次并保留在上下文中,而不是反复查询各个文件。
live_resolve — 回答“浏览器实际为这个选择器计算出了什么样式?”
通过 CDP 查询正在运行的 Chromium 浏览器,并返回精确的计算样式和匹配规则。没有启发式推断,也没有置信度等级——结果由浏览器直接解析。需要 Chrome 以 --remote-debugging-port=9222 运行。
支持的不只是普通 CSS。 上述四种静态工具可分析 .css、.scss、CSS Modules,以及自 v1.3 起支持的 styled-components 和 Emotion 源文件(.js / .jsx / .ts / .tsx),全部使用同一套层叠引擎。
快速开始
作为 CLI 工具
npm install -g @patrizzos/stylespeak
stylespeak resolve ".btn.primary" src/styles/main.css
stylespeak trace "color" --projectRoot src/styles
stylespeak impact ".btn" "background-color" src/styles/main.css --newValue "#ff0000"
stylespeak manifest --projectRoot src/styles
# styled-components / Emotion — components are addressed by variable name (const Button = styled.button`` -> .Button)
stylespeak resolve ".Button" src/components/Button.jsx
stylespeak manifest --projectRoot src
作为 MCP 服务
添加到 MCP 客户端配置中(Cursor:.cursor/mcp.json,VS Code:.vscode/mcp.json):
{
"mcpServers": {
"stylespeak": {
"command": "node",
"args": ["/absolute/path/to/stylespeak/src/server.js"]
}
}
}
连接后,Agent 可以调用:
resolve_styles({ selector, files, projectRoot, componentFiles? })trace_property({ property, files, projectRoot })impact_preview({ selector, property, newValue?, files, projectRoot })style_manifest({ files?, projectRoot?, maxSelectors? })live_resolve({ selector, port?, tabUrl? })
输出示例
impact_preview
stylespeak impact ".btn" "background-color" src/styles/buttons.css --newValue "#ff0000"
{
"change": {
"selector": ".btn",
"property": "background-color",
"currentValue": "var(--color-primary)",
"newValue": "#ff0000"
},
"blastRadius": {
"total": 3,
"valueChanges": 1,
"shielded": 1,
"risks": 0,
"variableDownstream": 0,
"inheritanceDownstream": 1
},
"riskLevel": "low",
"safeToChange": true,
"impacts": [
{
"type": "value-change",
"affectedSelector": ".btn",
"currentValue": "var(--color-primary)",
"newValue": "#ff0000",
"confidence": "certain"
},
{
"type": "shielded",
"affectedSelector": ".btn.primary",
"shieldingValue": "darkblue",
"confidence": "certain",
"reason": ".btn.primary has higher specificity — elements with both classes won't be affected"
}
],
"summary": "1 selector will see a different value, 1 selector is shielded by higher specificity.",
"agentNote": "Change appears safe to make. Shielded selectors are safe — higher-specificity rules protect those elements."
}
resolve_styles
stylespeak resolve ".btn" src/styles/buttons.css
{
"properties": {
"background-color": {
"winner": {
"value": "var(--color-primary)",
"resolvedValue": "#2563eb",
"variableChain": ["--color-primary → #2563eb"],
"selector": ".btn",
"specificity": "(0,0,1,0)"
},
"confidence": "certain"
}
},
"variables": { "--color-primary": { "value": "#2563eb", "selector": ":root" } }
}
置信度等级
| 等级 | 含义 |
|---|---|
certain | 选择器完全匹配——规则确定生效 |
likely | 规则标记是所查询选择器标记的子集——多数情况下会生效 |
possible | 组合器规则——取决于 DOM 祖先关系,未经渲染无法确定 |
exact | 仅由 live_resolve 返回——由浏览器解析,不使用启发式推断 |
CSS 自定义属性解析
从 v0.2 起,stylespeak 会在所有输出中完整解析 CSS 自定义属性(var()):
value— 按原样书写的原始值(var(--color-primary))resolvedValue— 实际解析出的值(#2563eb)variableChain— 完整的解析路径,包括链式变量conditionalValues— 变量解析结果不同时的媒体上下文覆盖值
支持:简单变量、回退值、嵌套回退值、链式变量、作用域变量、媒体上下文变量,以及循环引用保护。
CSS-in-JS 支持(styled-components 和 Emotion)
从 v1.3 起,stylespeak 会从导入了 styled-components、@emotion/styled、@emotion/react 或 @emotion/css 的 .js、.jsx、.ts、.tsx、.mjs 和 .cjs 文件中静态提取样式,并使用与普通 CSS 相同的级联引擎进行处理。resolve_styles、trace_property、impact_preview 和 style_manifest 均可用于这些文件,也可以将 CSS-in-JS 与常规 CSS 一起分析。
将 JS/TS 文件传入 files,或将 projectRoot 指向某个目录——会自动发现导入了这些库之一的文件,并忽略所有其他 JS/TS 文件。
组件寻址
生成的类名会在运行时进行哈希处理,因此每个 styled 组件都通过其变量名作为类选择器进行寻址:
const Button = styled.button`...`; // -> .Button
export default styled.section`...`; // -> .Card (named after the file, e.g. Card.jsx)
规则会标记为 cssInJs、library 和 component,并视为局部作用域(类似 CSS Modules):不同文件中名为 Wrapper 的两个组件彼此独立,不会被报告为冲突,也不会被计入“在 N 个位置声明”的风险。查询此类名称时会标记为存在歧义,因为结果会混合两个文件中的内容。
提取内容
| 语法 | 处理方式 |
|---|---|
| 标记模板 | styled.div`…`、styled(Comp)`…`、styled.div.attrs(…)`…`、styled.div<Props>`…`(TypeScript 泛型)、css`…` |
| 对象语法 | styled.div({ … })、styled(Comp)({ … })、css({ … })、styled.div(props => ({ … })) |
| 全局样式 | createGlobalStyle / injectGlobal — 使用实际选择器,而非局部作用域 |
| 嵌套 | &、&&(提高优先级)、&:hover、裸 :hover、嵌套选择器、@media / @supports / @container |
| 组件选择器 | ${Icon} { … } 会转换为 .Icon,例如 .Button .Icon |
| 常量 | 同一文件中的 const 字符串、数字和对象路径:${SPACING}、${colors.primary}、@media ${bp.md} |
css 辅助函数 | 同一文件中的 const mixin = css`…` 会在插值处内联(${mixin}、...mixin),也可通过其自身名称进行查询(标记为 css-helper)——这很有用,因为 Emotion 的 css={mixin} 属性会使辅助函数成为这些样式的唯一可见记录 |
| 对象表示法 | camelCase 会转换为 kebab-case,供应商前缀(WebkitX → -webkit-x、msX → -ms-x),无单位数值会加上 px(opacity、z-index、line-height 等无单位属性除外) |
标记但绝不猜测的内容
依赖属性或主题的值无法静态确定。stylespeak 会保留原始表达式、标记该值,并告知 Agent:
"color": {
"winner": {
"value": "${props => props.color}",
"selector": ".Button",
"cssInJs": true,
"library": "styled-components",
"component": "Button",
"dynamic": true
},
"confidence": "certain",
"dynamic": true
}
- 声明、获胜规则和属性上的
dynamic: true表示该值依赖运行时属性/主题——获胜规则可能因属性而异。 - 条件代码块和 mixin 调用(
${p => p.active && css…})无法求值。它们会被丢弃,并计入dynamicInterpolations;agentNote会警告运行时可能还会应用其他样式。 - 无法关联到选择器的样式块会列在
style_manifest输出中的cssInJs.skipped,而不会被静默忽略。 styled(Base)会记录extends;agentNote会告知 Agent 也解析基础组件。
局限性
这是静态分析,因此存在以下限制:
styled(Base)不会将基础组件的样式合并到子组件中——请单独解析基础选择器。- 不会解析从其他文件导入的常量和主题对象(仅支持同一文件)。也不会解析
ThemeProvider主题。 - JSX 元素上的 Emotion
css属性,以及未赋给具名变量的样式块都是匿名的——没有可定位的选择器,因此会报告为已跳过。 - 不会对
keyframes建模,也不考虑.attrs({ className })。 - 跨文件注入顺序根据提供文件的顺序进行近似推断。
- 如需获取运行中应用的真实结果,请针对实际元素使用
live_resolve。
与 stylesafe 的配合方式
stylesafe 会在 CSS 问题上线前发现它们,包括冲突、无效规则和 Tailwind 冲突。
stylespeak 会解释 CSS,包括解析层叠、追踪属性、预测影响和解析变量,让 Agent 在采取行动前理解样式。
将 stylesafe 用作编辑后的检查工具,将 stylespeak 用作编辑前的咨询工具。二者结合,为 AI 编码 Agent 提供完整的样式反馈闭环。
实时浏览器检查
live_resolve 需要启用远程调试的 Chromium 浏览器:
# Windows
chrome.exe --remote-debugging-port=9222
# macOS
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222
# Linux
google-chrome --remote-debugging-port=9222
**安全提示:**切勿在暴露于不可信网络的机器上或生产环境中运行
--remote-debugging-port。此标志会开放一个本地 API,机器上的任何进程都可以连接。
文件格式支持
| 格式 | 支持级别 |
|---|---|
.css | 完全支持 |
.scss | 完全支持——嵌套、& 引用、透传 @media |
.module.css / .module.scss | 完全支持——检测并标记局部作用域类 |
| vanilla-extract / Linaria / StyleX | 通过编译后的 CSS 输出支持 |
| styled-components / Emotion | 支持(v1.3)——从 .js / .jsx / .ts / .tsx / .mjs / .cjs 中静态提取;依赖属性/主题的值会标记为 dynamic,不会猜测 |
| CSS-in-JS 对象语法 | 支持(v1.3)——styled.div({…})、css({…})、函数返回的对象 |
Emotion css 属性(内联 JSX) | 无法提取——匿名内容会报告为已跳过 |
架构
src/
cssParser.js — CSS tokenizer with SCSS nesting support
specificity.js — standard (id, class, type) specificity calculator
cssomBuilder.js — in-memory cascade model builder (CSS, SCSS, CSS Modules, CSS-in-JS)
selectorMatcher.js — heuristic selector matching with confidence levels
variableResolver.js — CSS custom property resolution
cssModulesAnalyzer.js — CSS Modules local scope detection
scssNestingExpander.js — SCSS nesting pre-processor
cssInJsExtractor.js — styled-components / Emotion static extractor (template + object syntax)
astComponentGraph.js — AST component graph for graph-aware matching
resolveStyles.js — resolve_styles tool
traceProperty.js — trace_property tool
impactPreview.js — impact_preview tool
styleManifest.js — style_manifest project-wide knowledge builder
cdpBridge.js — Chrome DevTools Protocol WebSocket client
liveResolve.js — live_resolve tool
server.js — MCP server (stdio JSON-RPC) + CLI entry point
零外部依赖。需要 Node.js 21+。
路线图
- v0.2 ✅ — CSS 自定义属性解析
- v0.3 ✅ — SCSS 嵌套、CSS Modules 作用域感知、AST 组件图
- v1.0 ✅ — Chrome DevTools Protocol 实时解析
- v1.1 ✅ — impact_preview:在进行更改前预测影响范围
- v1.2 ✅ — style_manifest:为 Agent 上下文提供压缩的项目级 CSS 知识
- v1.3 ✅ — CSS-in-JS:静态提取 styled-components 和 Emotion(模板与对象语法)
后续(尚未排期)
CSS-in-JS 支持中已知的缺口(顺序不分先后):将 styled(Base) 样式合并到子组件中、解析从其他文件导入的常量和主题对象,以及对 keyframes 和 Emotion css 属性建模。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。