Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

[v2] MRTR wipe-cache example reads unvalidated elicitation content and defaults malformed scope to all

已关闭 适合新手
#2,542 3 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 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 内容生成。

描述

spec-2026-07-28 v2
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 模板
  • 阅读贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

modelcontextprotocol/typescript-sdk 的其他 Issue

查看 modelcontextprotocol/typescript-sdk 的全部 Issue

相似的 Issue

更多 TypeScript Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。