[v2] MRTR wipe-cache example reads unvalidated elicitation content and defaults malformed scope to all
维护者通常 1 天内回复
还没有人认领这个 Issue。
评估
- 难度
- 2/5
- 预计耗时
- 1-3 小时
- 新手友好度
- 78/100
- Issue 类型
- 文档
- 描述清晰度
- 描述清楚
- 活跃度
- 活跃
- 技术栈
- typescript
调研方向
打开 docs/servers/input-required.md,找到“Carry state across rounds with requestState”清除缓存示例。阅读页面前面支持 schema 的 acceptedContent() 用法,然后更新确认和范围处理,以便在运行时验证客户端内容。完成标准是:范围无效或缺失的请求会重新要求输入,而不是默认使用“all”。
由索引模型根据 Issue 内容生成。
描述
What happened?
The v2 input_required documentation correctly states that
ctx.mcpReq.inputResponses is client-provided and untrusted, and recommends
using the schema-aware overload of acceptedContent().
However, the sequential wipe-cache example uses the unchecked generic
overload for both confirmation and scope:
const confirmed = acceptedContent<{ confirm: boolean }>(
ctx.mcpReq.inputResponses,
'confirm'
);
It later treats that response as proof that the operator confirmed:
if (confirmed?.confirm !== true) {
return inputRequired({
inputRequests: {
confirm: inputRequired.elicit({
message: 'Really wipe the cache?',
requestedSchema: {
type: 'object',
properties: {
confirm: {
type: 'boolean'
}
},
required: ['confirm']
}
})
}
});
}
return inputRequired({
inputRequests: {
scope: inputRequired.elicit({
message: 'Which scope?',
requestedSchema: {
type: 'object',
properties: {
scope: {
type: 'string'
}
},
required: ['scope']
}
})
},
requestState: await stateCodec.mint({
step: 'confirmed'
})
});
The generic type parameter only affects TypeScript typing. It does not perform
runtime validation of the client-provided value.
For example, a malformed accepted response could contain:
{
"action": "accept",
"content": {
"confirm": "false"
}
}
The string "false" is truthy in JavaScript. Because the example only checks:
confirmed?.confirm !== true
this particular value does not equal the boolean true, so the current
!== true check fails closed.
However, the example still demonstrates reading untrusted client content using
a compile-time generic instead of the runtime-validating overload. A copied or
slightly modified version using a normal truthiness check such as:
if (!confirmed?.confirm) {
// request confirmation
}
would treat "false" as confirmation.
The same example later reads the requested scope with the unchecked overload:
const scope = acceptedContent<{ scope: string }>(
ctx.mcpReq.inputResponses,
'scope'
);
return {
content: [{
type: 'text',
text: `Wiped ${scope?.scope ?? 'all'}`
}]
};
If the scope response is missing, malformed, or of an unexpected type, the
example falls back to "all". That feels unsafe for a destructive example and
conflicts with the page's earlier guidance to validate inputResponses using
the schema-aware overload.
This is primarily a documentation and defensive API-usage issue, not a claim
that a malicious MCP client gains a capability it did not already possess.
What did you expect?
I expected the destructive wipe-cache example to follow the page's own
guidance and validate all client-provided elicitation content at runtime.
For example:
const confirmationSchema = z.object({
confirm: z.boolean()
});
const scopeSchema = z.object({
scope: z.string()
});
const confirmed = acceptedContent(
ctx.mcpReq.inputResponses,
'confirm',
confirmationSchema
);
if (confirmed?.confirm !== true) {
return inputRequired({
inputRequests: {
confirm: inputRequired.elicit({
message: 'Really wipe the cache?',
requestedSchema: confirmationSchema
})
}
});
}
const scope = acceptedContent(
ctx.mcpReq.inputResponses,
'scope',
scopeSchema
);
if (scope === undefined) {
return inputRequired({
inputRequests: {
scope: inputRequired.elicit({
message: 'Which scope?',
requestedSchema: scopeSchema
})
}
});
}
return {
content: [{
type: 'text',
text: `Wiped ${scope.scope}`
}]
};
The example should also fail closed when scope content is missing or invalid,
rather than defaulting to "all".
Code to reproduce
Documentation page:
`docs/servers/input-required.md`
Relevant section:
`Carry state across rounds with requestState`
Relevant example:
const confirmed = acceptedContent<{ confirm: boolean }>(
ctx.mcpReq.inputResponses,
'confirm'
);
const scope = acceptedContent<{ scope: string }>(
ctx.mcpReq.inputResponses,
'scope'
);
return {
content: [{
type: 'text',
text: `Wiped ${scope?.scope ?? 'all'}`
}]
};
Minimal demonstration that the generic type does not validate at runtime:
const clientContent: unknown = {
confirm: 'false'
};
const confirmed =
clientContent as {
confirm: boolean;
};
console.log(typeof confirmed.confirm);
// "string"
console.log(Boolean(confirmed.confirm));
// true
The cast changes the TypeScript type but does not transform or validate the
runtime value.
SDK version
main at commit 1e1392e3f91583884fe82a0b4b91335875c3fba6
Area
Documentation
- 主要语言
- TypeScript
- 星标
- 13.5k
- 派生
- 2.3k
- 平均合并
- 2 天 7 小时
- 30 天内合并 PR
- 53
环境准备
- 没有 Dockerfile 或 Docker Compose 文件
- 没有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
modelcontextprotocol/typescript-sdk 的其他 Issue
-
v2
难度 2/5 1-3 小时 新手友好度 72/100
modelcontextprotocol/typescript-sdk#2966 · 1 条评论 ·
维护者通常 1 天内回复
-
v1 v2
难度 2/5 1-3 小时 新手友好度 72/100
modelcontextprotocol/typescript-sdk#2946 · 3 条评论 ·
维护者通常 1 天内回复
-
[v2] URI template reserved expansions encode existing %HH sequences again可能已有人在做 @takagibit18 于 6 天前认领。 未关闭v1 v2
难度 2/5 1-3 小时 新手友好度 84/100
modelcontextprotocol/typescript-sdk#2920 · 1 条评论 ·
维护者通常 1 天内回复
-
[v2] URI template strict expansions leave !'()* unencoded可能已有人在做 @takagibit18 于 6 天前认领。 未关闭v1 v2
难度 2/5 1-3 小时 新手友好度 84/100
modelcontextprotocol/typescript-sdk#2919 · 1 条评论 ·
维护者通常 1 天内回复
-
Malformed params on spec request methods return -32603 Internal error instead of -32602 Invalid params可能已有人在做 @Gauravtiwari31 于 6 天前认领。 未关闭v1 v2
难度 2/5 1-3 小时 新手友好度 78/100
modelcontextprotocol/typescript-sdk#2916 · 3 条评论 ·
维护者通常 1 天内回复
查看 modelcontextprotocol/typescript-sdk 的全部 Issue
相似的 Issue
-
难度 1/5 1 小时以内 新手友好度 85/100
lukilabs/beautiful-mermaid#160 ·
-
难度 2/5 1-3 小时 新手友好度 66/100
rescript-lang/rescript-lang.org#1420 ·
维护者通常 2 天内回复
-
bug
难度 2/5 1-3 小时 新手友好度 82/100
chthollyphile/folia-major#520 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 72/100
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 82/100
databuddy-analytics/Databuddy#1106 ·
维护者通常 1 天内回复