关于 Cache Kit
Cache Kit 是面向 MCP SEP-2549 缓存提示的 TypeScript 库,供 MCP 服务开发者及客户端、代理和网关使用。它同时提供提示设置与缓存实现,并按授权上下文隔离 private 结果,避免跨用户泄漏。
主要功能
- 01设置并校验 ttlMs 与 cacheScope
- 02按请求和授权范围缓存结果
- 03隔离 private 缓存条目
- 04提供缓存安全判定与原因
- 05容错处理无效提示和请求键
适用场景
- 01为服务端响应添加缓存提示
- 02在代理中安全缓存 MCP 结果
- 03避免不同用户或租户共享私有结果
- 04测试缓存过期行为
MCP 相关
该库实现 MCP SEP-2549 的 ttlMs 和 cacheScope 缓存语义。它为 MCP 服务端提供提示设置工具,并为客户端或代理提供遵循授权范围的结果缓存。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
属于 StudioMeyer MCP Stack — 在马略卡岛打造 🌴 · 如果你在使用,请 ⭐
mcp-cache-kit
针对新的 MCP 缓存语义提供正确且可防止数据泄漏的缓存(SEP-2549)。
MCP 规范 2026-07-28 候选发布版新增了 SEP-2549:tools/list、resources/read(以及其他列表结果)现在包含 ttlMs 和 cacheScope,让客户端、网关和代理可以缓存它们,设计参考了 HTTP Cache-Control。这项功能刚刚推出,几乎没有专用工具。通用缓存会以“某种方式”存储结果,并忽略 cacheScope,这会带来实实在在的安全隐患:标记为 cacheScope: "private" 的结果被缓存后跨用户提供,就会造成跨用户数据泄漏。
mcp-cache-kit 正是为此提供的小巧、可靠的层:
- 服务端 — 正确设置这些字段(
withCacheHints)。 - 客户端 / 代理端 — 提供遵循
ttlMs且绝不会跨授权上下文提供private结果的缓存(McpResultCache)。 - 安全检查 — 判断给定范围内的任何结果是否可以缓存,并说明明确理由(
cacheSafety/assertCacheSafe)。
零运行时依赖。TypeScript 严格模式,支持 ESM + CJS,Node 20+。@modelcontextprotocol/sdk 是一个可选的对等依赖 — 这些辅助工具也适用于普通结果对象,因此无需 SDK 也能使用。
⚠️ 2026-07-28 规范仍处于候选发布阶段。 字段名称和语义在正式发布前仍可能发生变化。此库采用保守方式对其建模,并有意容忍缺失或格式错误的字段(无法证明安全的内容一律视为不可缓存)。
SEP-2549 实际规定了什么
已根据规范源文件(schema/draft/schema.ts 和 docs/.../utilities/caching.mdx)核实:
可缓存结果会扩展为包含两个顶层字段的 CacheableResult 结构:
| 字段 | 类型 | 含义 |
|---|---|---|
ttlMs | number (@minimum 0) | 新鲜度窗口,类似于 Cache-Control: max-age。0 = 立即过期。缺失或为负值 → 视为 0。 |
cacheScope | "public" | "private" | 类似于 Cache-Control: public 与 private。见下文。 |
"public"—— 响应不包含特定于用户的数据。任何客户端或中间件都可以缓存该响应,并在不同授权上下文之间提供该响应。"private"—— 响应可以缓存并重复使用,但仅限于相同的授权上下文。缓存不得在不同授权上下文之间共享(不同的访问令牌/用户/会话需要不同的缓存条目)。
适用于 tools/list、resources/list、resources/templates/list、prompts/list 和 resources/read。
规范还警告:来自经过身份验证端点的
"public"结果仍可在调用方之间共享,而且不得仅依赖cacheScope来防止未授权访问。此库会为你强制执行作用域边界,但你仍需确保作用域标记准确,并在源站进行身份验证。见 SECURITY.md。
跨用户泄漏陷阱
tools/list / resources/read
user A ───────────────────────────────► proxy (caches by request only)
│ stores result, ignores cacheScope
user B ───────── same request ──────────► proxy
│ returns A's cached result ← LEAK
如果缓存的结果是 cacheScope: "private"(A 的收件箱、A 的租户配置等),用户 B 就收到了其他用户的数据。mcp-cache-kit 会根据请求和调用方的作用域身份为每个条目建立键,因此 B 在结构上无法访问 A 的 private 条目。
安装
npm install mcp-cache-kit
# optional, only if you use the SDK result types directly:
npm install @modelcontextprotocol/sdk
服务端——设置提示
将这些字段附加到结果中。withCacheHints 会验证这些字段(拒绝负数/非有限的 ttlMs,以及任何不是 public/private 的 cacheScope),并返回一个新对象。
import { withCacheHints, CacheScope } from "mcp-cache-kit";
// tools/list rarely contains user data → public, cache for 5 minutes
server.setRequestHandler(ListToolsRequestSchema, async () =>
withCacheHints({ tools }, { ttlMs: 5 * 60_000, cacheScope: CacheScope.Public }),
);
// a per-user resource → private, cache for 1 minute
server.setRequestHandler(ReadResourceRequestSchema, async (req) => {
const contents = await loadForUser(req.params.uri);
return withCacheHints({ contents }, { ttlMs: 60_000, cacheScope: CacheScope.Private });
});
此外还提供简写:publicHints(ttlMs) 和 privateHints(ttlMs)。
客户端/代理端——安全地遵循提示
McpResultCache 会根据 (request, scope) 缓存结果。传入一个 scopeId,用于标识调用方的授权上下文(访问令牌哈希、用户 ID、租户 ID 或会话 ID)。
import { McpResultCache } from "mcp-cache-kit";
const cache = new McpResultCache({ maxEntries: 5_000 });
async function handleReadResource(req, ctx) {
const scopeId = ctx.tokenHash; // identifies the authorization context
// try the cache first
const hit = cache.get(req, { scopeId });
if (hit.hit) return hit.value;
// miss → fetch from the upstream MCP server, then offer it to the cache.
// set() stores it ONLY if the result is cache-safe for this scope.
const result = await upstream.request(req);
cache.set(req, result, { scopeId });
return result;
}
或者使用单行写法:
const result = await cache.getOrLoad(req, () => upstream.request(req), { scopeId });
缓存提供的保证:
- 遵循 TTL —— 条目会在
received + ttlMs时过期,并在访问时移除(或通过prune()移除)。 private永不泄漏 —— 为作用域 A 存储的private条目只会返回给作用域 A。不同的scopeId或未提供scopeId都会导致缓存未命中。- 共享
public条目 —— 条目存储在一个共享键下,并返回给任何人。 - 故障安全 —— 对无法证明安全的任何内容,
set()都会静默拒绝(并计为rejected):提示缺失/不完整、cacheScope无效、ttlMs无效、private未提供scopeId,以及ttlMs: 0(默认情况下)。 - 热路径上绝不抛出异常 —— 无法转换为稳定键的请求(循环
params、BigInt、method/params上具有恶意行为的 getter)会以故障安全方式处理:get返回未命中/set拒绝,并给出原因"unkeyable-request";绝不会抛出可能导致代理崩溃的异常。
防护——cacheSafety/assertCacheSafe
如果你希望自行决定是否安全,可在网关中使用这些方法:
import { cacheSafety, assertCacheSafe } from "mcp-cache-kit";
const decision = cacheSafety(result, { scopeId });
if (decision.cacheable) {
// decision.scopeKey is where to store it; decision.hints.ttlMs is the TTL
myStore.put(decision.scopeKey, result, decision.hints.ttlMs);
} else {
// decision.reason: "missing-fields" | "invalid-ttl" | "invalid-scope"
// | "zero-ttl" | "private-without-scope" | "not-an-object"
log.debug(`not caching: ${decision.message}`);
}
// or throw if "must be cacheable here" is an invariant:
const { hints, scopeKey } = assertCacheSafe(result, { scopeId }); // throws CacheUnsafeError otherwise
低级辅助工具
均为单独导出并经过测试:
parseCacheHints(result)→{ ok: true, hints } | { ok: false, reason, message }— 绝不抛出异常。validateCacheHints({ ttlMs, cacheScope })→ 规范化后的提示信息(输入不合法时抛出TypeError)。isCacheScope(x)、isValidTtlMs(x)— 类型保护函数。deriveScopeKey(cacheScope, scopeId?)— 作用域键规则(private且没有scopeId时返回undefined)。deriveRequestKey({ method, params })/stableStringify(x)— 确定性请求键(参数键顺序无关;循环结构会以"[Circular]"标记表示,绝不会导致堆栈溢出)。- 常量:
CacheScope、CACHE_SCOPE_VALUES、PUBLIC_SCOPE_KEY。
故障保护理念
跨用户缓存错误内容,比缓存未命中更糟。因此,默认决策始终是**“不缓存”**,除非结果明确证明缓存安全:两个字段都存在、都有效,而且对于 private,还必须提供 scopeId 以绑定作用域。SEP-2549 仍处于 RC 阶段,因此采取严格策略也能保护你免受上游服务发出不完整或标注错误的提示信息的影响。
测试说明
McpResultCache 支持注入 clock(() => number),因此你无需依赖真实时间,就能确定性地测试 TTL 行为;它也支持由 vitest 假定时器驱动默认的 Date.now。测试套件涵盖了这两种方式,也包括最重要的跨用户泄漏测试。
StudioMeyer MCP 工具包的一部分
一组专注且达到生产级标准的工具,用于构建和运维 MCP 服务,可按需组合使用:
- mcp-armor — 运行时防御 sidecar:扫描工具调用、验证签名清单、拦截已知存在漏洞的 CVE
- mcp-gauntlet — 部署前使用
mcp-fuzz(感知 schema 的模糊测试工具)和mcp-storm(负载测试工具) - mcp-otel — W3C Trace Context → OpenTelemetry 桥接器
- mcp-cache-kit (本项目) — 防泄漏的 SEP-2549 缓存(
ttlMs+cacheScope) - skilldoctor — Agent 技能文件的 linter 和安全扫描工具
许可证
MIT © StudioMeyer 2026
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。