Agent技能、MCP服务器与规则文件:如何选择?
编码Agent上下文配置指南。对比规则文件、技能与MCP服务器的加载机制与Token成本。了解为何规则文件应限制在200行以内,以及如何通过延迟加载优化Claude Code的上下文窗口占用,避免不必要的性能损耗。
Agent 技能、MCP 服务器与规则文件的简要对比
Agent 技能、MCP 服务器和规则文件均用于向编码 Agent 提供知识。请根据知识的用途进行选择。MCP (Model Context Protocol) 适用于每次查看时可能发生变化的数据。技能适用于即便在 6 周后依然有效的既定流程。规则文件则适用于在每次会话中必须遵循的少量事实。
选择这些机制需要付出代价,即上下文窗口的消耗。Agent 不需要但被强制读取的指令每消耗一个 token,用于读取代码的 token 就会减少。由于每次请求都会重新发送整个上下文窗口,这些 token 在每一轮对话中都会被重复计算。因此,真正的问题不在于哪种机制“能够”完成任务(通常三者都能),而在于哪种机制在闲置时占用的成本最低。
使用前先了解各自的成本
三者在不同时间加载,而加载时机就是全部差异所在。
规则文件会在启动时完整加载,每个会话都如此,无论是否相关。Claude Code 会在每次对话开始时读取 CLAUDE.md 并完整加载,无论文件有多长;只有超过 4 MiB 的文件会被跳过。文档建议每个文件少于 200 行,因为更长的文件不仅会占用更多上下文,模型也更难稳定遵循。两种影响方向相同,因此 900 行的规则文件甚至不如没有规则文件。
技能分两个阶段加载。启动时,每个 SKILL.md frontmatter 中只有 description 行进入上下文,因此模型知道该技能存在,并大致知道何时适用。调用技能后才会加载正文。因此,400 行的参考文档在真正需要之前几乎不会产生成本。
MCP 服务器过去是成本最高的一项,这也是现在许多比较文章已经过时的原因。当前 Claude Code 默认启用工具搜索。会话开始时只加载工具名称和服务器的 instructions 字段;完整的 JSON(JavaScript 对象表示法)架构会推迟到 Claude 搜索这些工具时再加载。添加服务器不再需要预先占用数千个 token。但它仍然有成本;如果关闭工具搜索,则仍会在启动时承担全部成本。
此图表背后的数据
[
{
"label": "Rules file, 200 lines",
"at_startup": "2,500",
"after_use": "2,500"
},
{
"label": "Skill, 12 KB body",
"at_startup": 40,
"after_use": "3,000"
},
{
"label": "MCP server, tool search on",
"at_startup": 500,
"after_use": "3,200"
},
{
"label": "MCP server, tool search off",
"at_startup": "4,500",
"after_use": "4,500"
}
]这些是估算值,不是从您的机器测得的结果。估算依据是各机制加载的文本大小,按每个 token 约 4 个字符计算:200 行的规则文件约为 10 KB Markdown,技能描述约为 160 个字符,而暴露 12 个工具的服务器包含约 18 KB 的架构和 2 KB 的 instructions 块。Claude Code 默认会将服务器 instructions 字段和每个启动时加载的工具描述截断为 4,096 个字符;通过工具搜索加载的工具描述则截断为 16,384 个字符,因此这一部分存在上限。在 v2.1.296 之前,较短的限制是 2,048 个字符;设置 CLAUDE_CODE_MAX_MCP_DESCRIPTION_LENGTH 后,它会替代这两个限制。下一节将介绍如何读取您自己的实际数字。
将前两行放在一起阅读。规则文件在无人需要它的会话中会占用 2,500 个 token。技能在同一会话中占用 40 个 token;而在十个会话中有一个调用它的情况下,会占用 3,000 个 token。最后两行是同一个服务器的两种情况,分别开启和关闭工具搜索:占用 500 个 token,而不是 4,500 个。旧建议仍在传播 MCP 上下文膨胀问题,原因就在于这个差距。
截至 2026 年 10 月,Claude Code 会在 Claude Opus 4、Sonnet 4、Haiku 4.5 及更高版本模型上使用工具搜索;在 Google Cloud 的 Agent Platform 上,则会在 Opus 4.5、Sonnet 4.5、Haiku 4.5 及更高版本模型上使用工具搜索。在更早的模型上,以及在 Azure 托管的 Microsoft Foundry 部署中,无论您如何设置,每个 MCP 工具都会在启动时加载。对于指向 LLM 网关的 ANTHROPIC_BASE_URL,自 v2.1.304 起默认启用工具搜索;更早版本在这里默认关闭,除非您主动启用。设置 ENABLE_TOOL_SEARCH 可控制此行为:false 会在启动时加载所有架构,true 会使用与未设置时相同的模型和部署回退逻辑推迟加载,auto 只会在这些架构占上下文窗口不超过 10% 时于启动时加载。配置了 "alwaysLoad": true 的服务器无论 ENABLE_TOOL_SEARCH 如何设置,都会在启动时加载其工具。
# Load schemas up front only if they fit in 5% of the window
ENABLE_TOOL_SEARCH=auto:5 claude决定性问题:数据在多次调用之间会发生变化吗?
首先询问这个问题,因为它能直接排除一种选项。如果 Agent 需要读取或写入的内容在下次查看时可能会有所不同,那么你需要一个服务器。例如问题跟踪器、数据库、监控仪表板或你自己的内部 API(应用程序编程接口)。将数据写下来没有帮助,因为一旦有人编辑了记录,你写下的内容就过时了。你自己的代码库也属于此类,因为它的结构会随着每次提交而变动,这就是为什么建议 通过 MCP 向 Agent 提供解析后的代码库映射,而不是用一个会过时的文件来描述布局。
如果该内容在六周后无人维护时依然正确,那么你需要的是一个技能(skill)。例如发布检查清单、迁移流程、错误响应的格式,或者该代码库要求的测试编写方式。技能就是一个 git 中的文件。它没有端口,没有进程,除了内容错误(可以通过代码审查发现)之外,没有其他故障模式。
如果某个事实必须适用于你尚未考虑到的工作,请将其放入规则文件(rules file)中。Run make lint before committing. Never push to main. Handlers live in src/api/handlers/. 每行一条。一旦条目扩展为多个步骤,它就不再是事实,而变成了流程,此时应将其移至技能中。
规则文件足够时
规则文件会从多个位置加载,范围从广到窄依次为:托管策略文件、个人 ~/.claude/CLAUDE.md、项目的 ./CLAUDE.md 或 ./.claude/CLAUDE.md,以及被 git 忽略的 ./CLAUDE.local.md。所有发现的文件都会串联,而不是相互覆盖;距离工作目录越近的文件,读取顺序越靠后。
从 v2.1.277 开始,Claude Code 还会读取 AGENTS.md,但默认只有在工作目录及其上级目录中不存在 CLAUDE.md、.claude/CLAUDE.md 或 CLAUDE.local.md 时才会读取。如果仓库同时包含这两类文件,Claude 只会读取 CLAUDE.md 文件,因此不要维护两份会逐渐不一致的副本。
ln -s AGENTS.md CLAUDE.md符号链接成功时不会输出任何内容。启动会话,运行 /context,确认 Memory files 下出现 CLAUDE.md。如果这里没有列出该文件,说明代理从未读取过它,重新措辞也无法解决问题。如果还需要添加 Claude 专用内容,请改用导入形式,并将这些内容放在导入语句下方。
@AGENTS.md
## Claude Code
Use plan mode for changes under `src/billing/`.这里有一个容易踩到的陷阱。@path 导入不会节省上下文。导入的文件会在启动时展开并加载,同时加载引用它的文件,最多深入四层。将一个 600 行的规则文件拆分为六个导入文件,只会让人更容易管理,token 成本完全不会改变。确定布局前,建议阅读AGENTS.md 背后的约定及其面向人的对应文件。
真正能够降低成本的是带有 paths 字段的 .claude/rules/。包含 paths frontmatter 的规则文件,只有在代理处理与某个模式匹配的文件时才会加载。
---
paths:
- "src/api/**/*.ts"
---
# API rules
- Every endpoint validates its input.
- Use the standard error response shape.不包含 paths 字段的规则会在启动时加载,其优先级与 .claude/CLAUDE.md 相同。因此,实际使用的模式是保留简短的无条件规则,并在只适用于某个目录的内容上添加 paths 列表。
需要技能时
技能是一个包含 SKILL.md 的目录。个人技能位于 ~/.claude/skills/<name>/SKILL.md,适用于计算机上的每个项目。项目技能位于 .claude/skills/<name>/SKILL.md,会随仓库一起维护,也可以像其他文件一样在 pull request 中审查。
mkdir -p ~/.claude/skills/summarize-changes---
name: summarize-changes
description: Summarizes uncommitted changes and flags anything risky. Use when the user asks what changed, wants a commit message, or asks to review their diff.
---
Run `git status` and `git diff` against the merge base.
Group the changes by intent, not by file.
Call out anything touching auth, migrations or deletions.description 是该文件中技能运行前唯一会进入上下文的部分,因此承担两项职责。它说明技能的作用,也说明何时应调用技能。描述如果写成“帮助执行部署”,模型就无法将其与请求匹配,因此技能会悄悄地从不触发,您便会得出技能无法工作的结论。
目录名称会成为命令,因此上面的示例会生成 /summarize-changes。在个人技能或项目技能中,如果 frontmatter 中的 name 与目录名称不同,就会设置 / 菜单显示的命令名,除非已有其他命令使用该名称;目录名称仍然可以调用该技能。
调用技能后,其渲染内容会作为一条消息进入对话,并在本次会话的剩余时间内保留。Claude Code 不会在后续轮次重新读取该文件。应编写长期有效的指令,而不是一次性步骤,并保持正文精简,因为从此以后,每一行都会在每个请求中产生持续的上下文成本。自动压缩后,Claude Code 会重新附加每个技能最近一次调用的内容,并在总计 25,000 个 token 的预算中保留每个技能的前 5,000 个 token。在一次会话中调用多个大型技能时,最早调用的技能会被完全移除,因此长时间对话后,某个技能可能看起来不再生效。再次调用该技能,它就会恢复。以流程较多的技能为例,unlazy 技能及其 Depth Tree 方法 会在上下文中为检查点和计划文件占用实际空间,换取一个不会过早宣布工作完成的代理。当同一流程适用于多个代码库时,应使用 在多个仓库之间共享一个技能,而不是复制文件。
何时需要 MCP 服务器
添加服务器只需一条命令,其运行形式由传输方式决定。
# Remote HTTP server
claude mcp add --transport http notion https://mcp.notion.com/mcp
# Remote HTTP server behind a bearer token
claude mcp add --transport http secure-api https://api.example.com/mcp \
--header "Authorization: Bearer your-token"
# Local stdio server: everything after -- is passed through untouched
claude mcp add --env AIRTABLE_API_KEY=YOUR_KEY --transport stdio airtable \
-- npx -y airtable-mcp-server-- 非常重要。对于 stdio 服务器,它用于区分 Claude Code 自身的选项与启动服务器的命令行参数。如果省略该分隔符,原本发给服务器的 --port 8080 会被解析为 claude mcp add 的选项,导致解析失败。
claude mcp list
claude mcp get notionclaude mcp add 会通过 Added ... 行进行确认,这仅表示配置已写入磁盘。claude mcp list 命令才是判断真实状态的依据,它会在每个服务器旁显示健康状态:✔ Connected、! Needs authentication 或 ✘ Failed to connect。状态显示为失败意味着 Claude Code 无法连接到该服务器,而非 list 命令本身出错。在会话内部,/mcp 可查看每个服务器的相同状态及工具数量。
每次对 MCP 服务器的调用都是独立的,并携带所需的所有信息,这正是 MCP 服务器不记录上一次请求的原因。这是一种设计选择,但也带来了一个必须承担的后果:任何需要保留的状态都必须存储在服务器后端,即数据库或文件中,而这正是你现在需要维护的内容。
MCP 服务器是必须运行的进程
供应商对比中遗漏了这项成本。skill 是一个文件。MCP 服务器是运行在某处的软件;如果运行位置是您的 VPS(虚拟专用服务器),您就需要负责它的可用性。
stdio 服务器属于成本较低的情况。Claude Code 会在会话开始时将其作为子进程启动,并在会话结束时终止。您无需监控它,也无需按其自身的计划打补丁。远程 HTTP 服务器是长期运行的服务,需要长期运行服务所需的一切,首先是专用用户。创建以下单元运行所用的 mcp 用户,并将服务器目录授予该用户:
sudo useradd --system --home-dir /srv/notes-mcp --shell /usr/sbin/nologin mcp
sudo chown -R mcp:mcp /srv/notes-mcp[Unit]
Description=Notes MCP server
After=network-online.target
Wants=network-online.target
[Service]
User=mcp
WorkingDirectory=/srv/notes-mcp
ExecStart=/usr/bin/node /srv/notes-mcp/dist/server.js
Environment=PORT=8931
Restart=on-failure
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
[Install]
WantedBy=multi-user.targetsudo systemctl daemon-reload
sudo systemctl enable --now notes-mcp
systemctl is-active notes-mcp
journalctl -u notes-mcp -n 50 --no-pagersystemctl is-active 应输出 active。如果输出 failed,原因会记录在 journal 中。首次运行时,原因几乎总是缺少环境变量,或端口已被其他进程占用。这里不能省略 Restart=on-failure,因为崩溃的 MCP 服务器不会主动报告自身状态。只有代理告诉您无法读取问题跟踪系统时,您才会发现问题。
将进程绑定到 127.0.0.1,并在其前面配置带 TLS(传输层安全)的反向代理。能够访问数据库、却在未进行身份验证的情况下监听公网端口的 MCP 服务器,本质上就是一个已公开发布的数据库。在 VPS 上运行 MCP 服务器详细介绍了代理、证书和防火墙的正确配置方式。
然后如实计算持续性工作。该服务会按照自己的计划安装安全更新,与连接它的代理无关。其 OAuth 令牌会过期,claude mcp list 也可能在不合适的时间开始输出 ! Needs authentication。其凭据存放在配置文件或 Authorization 标头中,因此需要像其他机密信息一样妥善保护。这本身就是一个完整主题:防止 AI 代理接触机密信息。skill 不需要这些工作。
在构建之前,先将其与替代方案进行比较。如果拟议服务器背后的数据大约每季度才变化一次,那么使用 skill 告诉代理应查看的位置以及字段含义,会比维护一个必须持续运行的服务成本更低。
如何测量您自己的上下文成本
停止估算,在会话中运行 /context。它会输出启动时的详细分解:系统提示、记忆文件、工具和 MCP 服务器,以及每项所占的 token 数。
检查两点。在 Memory files 下,确认列出了您预期的每个规则文件。文件缺失时,agent 无法看到其中内容;因此,当指令未被遵循时,首先应排除这一原因。如果文件已列出,但规则仍被跳过,原因完全在其他地方;在再次改写该行之前,值得先排查agent 明明能看到指令却跳过它的原因。然后查看各服务器的成本。如果某个每月使用两次的服务器在该列表中属于占用量最大的条目之一,请在 /mcp 中将其关闭,并在需要该服务器的会话中重新开启。无论是否关闭,该配置都会保留。
如果您的账户启用了 discovery cache,之前使用过的远程服务器可能显示类似 cached 2h ago · connects on first use · 5 tools 的状态。这表示 Claude Code 从之前的会话读取了工具列表,而不是在启动时连接;首次调用工具时,它才会连接。工具从您的第一条消息开始即可用,因此无需修复。默认情况下,缓存处于关闭状态,除非渐进式发布已为您启用它:将 MCP_DISCOVERY_CACHE=0 设置为让每个服务器都在启动时连接,或将 1 设置为开启缓存。如需了解全貌,请参阅管理 Claude Code 上下文窗口,其中介绍压缩后哪些内容会保留;这些 token 实际会花费您多少钱则会将这些数字换算为金额。
为什么我的 skill 始终不触发?
通常原因是 description。在 skill 运行前,它是上下文中的唯一文本。因此,如果其中没有说明相关场景,就不会匹配。应将触发条件直接写入句子:“当用户询问发生了哪些变化、需要提交消息,或要求审查其 diff 时使用。”含糊的描述会静默失败,因此很难察觉。
第二个原因是 frontmatter 拼写错误。在 Claude Code 中,这同样会静默失败。字段名必须完全匹配,包括连字符;Claude Code 遇到无法识别的字段时会直接忽略,不报告错误。只有在打包 skill,或将其上传到 claude.ai 或 Skills API 时,才会出现明确错误;这些平台接受的字段更少,会直接拒绝其他字段:
Unexpected key(s) in SKILL.md frontmatter: argument-hint. Allowed properties are: allowed-tools, compatibility, description, license, metadata, name第三个原因是位置。项目 skill 会从工作目录中的 .claude/skills/ 以及一直到仓库根目录的所有父目录加载。启动时不会加载你开始位置下方的嵌套目录中的 skill。只有当代理首次读取或编辑该子目录中的文件时,这些 skill 才会出现。因此,在此之前,它们不会出现在自动补全中,也无法按名称调用。
MCP 中与这种静默失败等效的情况,是某个 .mcp.json 条目包含 url,但没有 type。Claude Code 会将任何不含 type 的条目视为 stdio 服务器,因此会跳过该条目并报告:
MCP server "notes" has a "url" but no "type"; add "type": "http" (or "sse" / "ws") to this entry三者协同使用
这些机制并非互斥。高效的配置方案会在各自最适用的场景下使用它们。规则文件(rules file)仅包含少量适用于全局的通用准则。技能(skills)包含具体的操作流程,且仅在适用时加载。MCP 服务器(通常配置一个,偶尔两个)用于连接那些内容不可预知的系统。如果您仍在构建关于前者的认知模型,代理技能的本质 一文详细介绍了其格式。
通过一项测试即可解决关于功能归属的大多数争议:删除该功能,开启一个新会话,并向代理下达任务。如果代理只是执行变慢,说明它属于技能;如果代理表现得自信但结果错误,说明它属于规则文件;如果代理完全无法获取信息,说明您需要一个服务器,且此时还需制定维护该服务器运行的方案。
FAQ
我应该编写 skill,还是部署 MCP 服务器?
根据信息是否会在两次调用之间发生变化来决定。如果 agent 必须读取其他人可以编辑的实时状态,例如 issue tracker、数据库或 dashboard,就需要 MCP 服务器,因为记录一旦变化,您写下的任何内容都会过时。如果您可以只写下一次答案,并且六周后仍然正确,就编写 skill。skill 是 git 中的一个文件,不需要运行进程、不需要暴露端口,也不需要补丁计划;因此,只要可行,它就是成本更低的选项。
MCP 服务器还会填满我的上下文窗口吗?
比过去少得多。当前的 Claude Code 默认启用 tool search,因此会话启动时只加载工具名称和服务器的 instructions 字段;Claude 搜索工具时才会获取完整 schema。自 v2.1.304 起,这也包括通过 ANTHROPIC_BASE_URL 设置的 LLM gateway 后面的会话。以下情况仍会在启动时加载全部内容:使用 ENABLE_TOOL_SEARCH=false 时;服务器设置为 "alwaysLoad": true 时;使用早于 Claude Opus 4 和 Sonnet 4 的模型时;使用 Google Cloud 的 Agent Platform 上早于 4.5 代的模型时;以及部署在 Azure 上的 Microsoft Foundry 时。运行 /context 查看您属于哪种情况,因为较早的对比文章中的数字假设会在启动时加载全部内容。
Claude Code 会读取 AGENTS.md 吗?
会,从 v2.1.277 起支持;但默认情况下,仅当您的工作目录及其上级目录中不存在 CLAUDE.md、.claude/CLAUDE.md 或 CLAUDE.local.md 时才会读取。如果您的代码仓库同时存在这两类文件,Claude 只读取 CLAUDE.md 文件,因此请让其中一个指向另一个,不要保留两份副本。运行 ln -s AGENTS.md CLAUDE.md 创建普通符号链接,或者在 CLAUDE.md 的第一行加入 @AGENTS.md,并在其下方添加 Claude 专用指令。然后启动会话并运行 /context,确认 CLAUDE.md 出现在 Memory files 下。
为什么我的 skill 在会话进行到一半时不再生效?
通常是因为自动压缩。对话被总结后,Claude Code 会重新附加每个 skill 最近一次调用的内容:每个 skill 保留前 5,000 个 token,所有 skill 合计上限为 25,000 个 token。它会从最近调用的 skill 开始填充该上限,因此如果您调用了多个大型 skill,较早的 skill 会被完全丢弃。再次调用该 skill,即可恢复其完整内容。
如何阻止长规则文件在每个会话中加载?
将仅在某些情况下需要的部分移入 .claude/rules/ 文件,并在其 frontmatter 中加入 paths 字段,使每个文件仅在 agent 接触匹配文件时加载。将文件拆分为 @path imports 没有帮助,因为导入的文件会在启动时展开并加载,与引用它们的文件同时完成。任何属于多步骤流程、而非固定事实的内容,都应改为 skill,因为 skill 的正文在调用前不会产生任何成本。