Skip to content

fix(cli): forward user input to MCP prompts with no declared arguments - #6571

Merged
yiliang114 merged 3 commits into
QwenLM:mainfrom
yiliang114:fix/mcp-prompt-no-arguments-forward
Jul 9, 2026
Merged

fix(cli): forward user input to MCP prompts with no declared arguments#6571
yiliang114 merged 3 commits into
QwenLM:mainfrom
yiliang114:fix/mcp-prompt-no-arguments-forward

Conversation

@yiliang114

Copy link
Copy Markdown
Collaborator

What this PR does

When an MCP server prompt declares no arguments field, the slash-command handler silently discarded everything the user typed after the prompt name. The parseArgs() method parsed the input into named and positional parts, then hit an early return {} that threw all of it away before it ever reached prompt.invoke().

This PR changes that early return so that, when the prompt declares no arguments (either undefined or an empty array), the parsed input is still forwarded to the MCP server:

  • Named arguments (--key="value") are passed through as-is.
  • Positional/free-form text is forwarded under the input key (e.g. { input: "abc" }).

This matches Claude Code's behavior of forwarding user text unconditionally regardless of whether the prompt declares arguments.

Why it's needed

Silent data loss is the core problem. A user typing /my_prompt some important context reasonably expects that text to reach the MCP server, but it was silently dropped with no error and no feedback. The MCP server received an empty {} arguments object, making the prompt appear broken for no discernible reason.

Fixes #6563.

Reviewer Test Plan

How to verify

  1. Unit tests cover the new behavior — run cd packages/cli && npx vitest run src/services/McpPromptLoader.test.ts and confirm all 33 tests pass.
  2. To verify end-to-end, configure an MCP server whose prompt declares no arguments field, then run /prompt_name some text. Before this fix the server receives arguments: {}; after the fix it receives arguments: { input: "some text" }.

Evidence (Before & After)

N/A — no user-visible TUI change; behavior is in MCP argument forwarding.

Tested on

OS Status
🍏 macOS
🪟 Windows N/A
🐧 Linux N/A

Environment (optional)

N/A — only unit tests.

Risk & Scope

  • Main risk or tradeoff: MCP servers that explicitly declare zero arguments and do not expect an input key will receive one. The MCP spec allows servers to ignore unknown arguments, so this should be safe. A server that strictly validates argument keys could surface a new error, but that error would be more informative than the previous silent drop.
  • Not validated / out of scope: No-argument prompts that receive only named arguments (e.g. --key="value") — the named args are forwarded as-is, which is the expected behavior but not the primary scenario reported in the issue.
  • Breaking changes / migration notes: None.

Linked Issues

Fixes #6563

中文说明

本 PR 做了什么

当 MCP server 的 prompt 未声明 arguments 字段时,斜杠命令处理器会静默丢弃用户在 prompt 名称后输入的所有内容。parseArgs() 方法将输入解析为命名参数和位置参数后,遇到一个提前的 return {},将所有内容丢弃,从未传递到 prompt.invoke()

本 PR 修改了这个提前返回逻辑,使得当 prompt 未声明参数(undefined 或空数组)时,解析后的输入仍然会转发给 MCP server:

  • 命名参数(--key="value")原样传递。
  • 位置参数/自由文本通过 input 键转发(例如 { input: "abc" })。

这与 Claude Code 无条件转发用户文本的行为一致。

为什么需要

静默数据丢失是核心问题。用户输入 /my_prompt some important context 时,合理预期是文本会到达 MCP server,但它被静默丢弃,没有错误也没有反馈。MCP server 收到空的 {} 参数对象,使 prompt 看起来莫名其妙地坏了。

修复 #6563

审阅者测试计划

如何验证

  1. 单元测试覆盖了新行为 — 运行 cd packages/cli && npx vitest run src/services/McpPromptLoader.test.ts,确认全部 33 个测试通过。
  2. 端到端验证:配置一个 prompt 未声明 arguments 字段的 MCP server,运行 /prompt_name some text。修复前 server 收到 arguments: {};修复后收到 arguments: { input: "some text" }

证据(前后对比)

N/A — 无用户可见的 TUI 变化;行为在 MCP 参数转发层面。

测试环境

OS 状态
🍏 macOS
🪟 Windows N/A
🐧 Linux N/A

环境(可选)

N/A — 仅单元测试。

风险与范围

  • 主要风险/权衡:显式声明零个参数且不期望 input 键的 MCP server 会收到一个。MCP 规范允许 server 忽略未知参数,因此应该安全。严格验证参数键的 server 可能会出现新错误,但该错误比之前的静默丢弃更有信息量。
  • 未验证/超出范围:仅收到命名参数(例如 --key="value")的无参数 prompt — 命名参数原样转发,这是预期行为但不是 issue 中报告的主要场景。
  • 破坏性变更/迁移说明:无。

关联 Issue

Fixes #6563

When a prompt declares no arguments, parseArgs() silently discarded
all user input. Forward named args as-is and positional input under
the "input" key, matching Claude Code's behavior.

Fixes QwenLM#6563
@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Thanks for the PR!

Template looks good ✓

Problem: observed bug with clear reproduction in #6563. When an MCP prompt declares no arguments, user input after the prompt name is silently discarded by parseArgs() before reaching prompt.invoke(). Root cause confirmed at line 276 of McpPromptLoader.ts — the early return promptInputs (which is {}) happens after positional args have already been parsed but before they're forwarded.

Direction: aligned. Silent data loss is a real user problem, and forwarding user text unconditionally matches Claude Code's behavior. No sensitive areas touched (MCP argument parsing only).

Size: 5 production lines + 48 test lines in packages/cli/src/services/. Not applicable for core-module size thresholds.

Approach: scope feels right — minimal, focused change that does exactly what's needed. The fix correctly handles all the relevant cases (undefined args, empty args array, named-only, positional-only, mixed). One minor note: the added promptArgs.length === 0 guard is a nice defensive touch even though the original issue focused on the undefined case.

Moving on to code review and testing. 🔍

中文说明

感谢贡献!

模板完整 ✓

问题:已观测到的 bug,#6563 提供了清晰的复现。当 MCP prompt 未声明 arguments 时,用户输入在 parseArgs() 中被静默丢弃,从未到达 prompt.invoke()。根因在 McpPromptLoader.ts 第 276 行已确认——return promptInputs(此时为 {})发生在位置参数已解析但尚未转发时。

方向:对齐。静默数据丢失是真实的用户问题,无条件转发用户文本与 Claude Code 行为一致。未触及敏感区域(仅 MCP 参数解析)。

规模:5 行生产代码 + 48 行测试代码,位于 packages/cli/src/services/。不触发核心模块规模阈值。

方案:范围合理——最小化、聚焦的改动,精确解决问题。修复正确处理了所有相关场景(undefined args、空 args 数组、仅命名参数、仅位置参数、混合参数)。新增的 promptArgs.length === 0 守卫是不错的防御性补充。

进入代码审查和测试 🔍

Qwen Code · qwen3.7-max

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Code Review

The fix is clean and minimal — exactly 5 production lines in McpPromptLoader.ts. The change modifies the early-return guard in parseArgs() to forward named args (via Object.assign) and positional text (via the input key) instead of silently returning {}. The added promptArgs.length === 0 check is a sensible defensive addition beyond the original undefined case.

No correctness bugs, no regressions, no over-abstraction. The test coverage is thorough — 6 new tests covering undefined/empty args, positional-only, named-only, mixed, and the loadCommands integration path. All follow the project's existing test patterns.

Before (without fix — 5 tests fail, bug confirmed)

 ❯ src/services/McpPromptLoader.test.ts (33 tests | 5 failed) 24ms
   × McpPromptLoader > parseArgs > should forward positional input as "input" when promptArgs is undefined 9ms
     → expected {} to deeply equal { input: 'hello world' }
   × McpPromptLoader > parseArgs > should forward positional input as "input" when promptArgs is empty 1ms
     → expected {} to deeply equal { input: 'hello world' }
   × McpPromptLoader > parseArgs > should forward named args when promptArgs is undefined 1ms
     → expected {} to deeply equal { key: 'value' }
   × McpPromptLoader > parseArgs > should forward both named and positional args when promptArgs is undefined 1ms
     → expected {} to deeply equal { key: 'value', input: 'some text' }
   × McpPromptLoader > loadCommands > should forward user input when prompt has no declared arguments 2ms
     → expected "spy" to be called with arguments: [ { input: 'some user input' } ]

   Test Files  1 failed (1)
        Tests  5 failed | 28 passed (33)

After (with fix — all 33 tests pass)

 ✓ src/services/McpPromptLoader.test.ts (33 tests) 11ms

 Test Files  1 passed (1)
      Tests  33 passed (33)

Note: Real-scenario tmux testing with a live MCP server is not possible here — reproducing the bug requires a configured MCP server whose prompt declares no arguments. The unit tests directly exercise the buggy code path and conclusively demonstrate both the bug (before: expected {} to deeply equal { input: 'hello world' }) and the fix (after: all 33 pass).

中文说明

代码审查

修复干净且最小化——McpPromptLoader.ts 中仅 5 行生产代码。修改了 parseArgs() 中的提前返回守卫,将命名参数(通过 Object.assign)和位置文本(通过 input 键)转发,而非静默返回 {}。新增的 promptArgs.length === 0 检查是对原始 undefined 场景的合理防御性补充。

无正确性 bug、无回归、无过度抽象。测试覆盖全面——6 个新测试覆盖 undefined/空 args、仅位置参数、仅命名参数、混合参数和 loadCommands 集成路径。均遵循项目现有测试模式。

修复前(无修复——5 个测试失败,bug 确认)

新测试显示 parseArgs 返回 {} 而非转发用户输入,直接证实了静默数据丢失的 bug。

修复后(全部 33 个测试通过)

所有测试通过,修复有效。

注: 此处无法进行实时 MCP server 的 tmux 测试——复现 bug 需要配置一个 prompt 未声明 arguments 的 MCP server。单元测试直接覆盖了 bug 代码路径,明确证实了 bug(修复前:expected {} to deeply equal { input: 'hello world' })和修复效果(修复后:33 个全部通过)。

Qwen Code · qwen3.7-max

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

This is a clean, well-scoped fix for a confirmed bug. The silent data loss in parseArgs() when MCP prompts declare no arguments is unambiguous — the before-test shows expected {} to deeply equal { input: 'hello world' } in 5 separate test cases, and the fix resolves all of them with just 5 production lines.

The approach matches what I'd independently propose: forward named args via Object.assign and positional text under the input key. The promptArgs.length === 0 defensive guard is a nice addition. Test coverage is thorough across all edge cases.

Approving. ✅

中文说明

这是一个干净、范围明确的已确认 bug 修复。当 MCP prompt 未声明 arguments 时,parseArgs() 中的静默数据丢失是明确的——修复前的测试在 5 个独立测试用例中显示 expected {} to deeply equal { input: 'hello world' },修复仅用 5 行生产代码就解决了全部问题。

方案与我独立提出的方案一致:通过 Object.assign 转发命名参数,通过 input 键转发位置文本。promptArgs.length === 0 防御性守卫是不错的补充。测试覆盖了所有边界场景。

批准。✅

Qwen Code · qwen3.7-max

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, looks ready to ship. ✅

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed — no blockers. Suggestion-level recommendations are in the Suggestion summary comment below.

@qwen-code-ci-bot

qwen-code-ci-bot commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

No new Suggestion-level findings this round — all prior suggestions have been addressed or superseded.

— qwen3.7-max via Qwen Code /review

@yiliang114

yiliang114 commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator Author

Additional tmux verification for PR #6571

Ponytail review: Lean already. Ship. I did not find a correctness or over-engineering issue in the PR diff, so no source changes were needed locally.

I ran a targeted tmux E2E check with a real stdio MCP server exposing a prompt that declares no arguments field, plus a fake OpenAI-compatible server so the CLI flow completes without external model traffic. I refreshed the comparison screenshots so both runs show the exact same slash command before the observed MCP arguments.

Check SHA / worktree Slash command Observed MCP getPrompt arguments Result
Base reproduction befa937375f6ff1aca5bb2b43a9f7e52c9f806fd /pr6571_prompt hello from tmux {} PASS: reproduces the old dropped-input behavior
PR head verification 5cdec9f7a52f320a4f59164ec3564fe7a40f1d9a /pr6571_prompt hello from tmux {"input":"hello from tmux"} PASS: forwards the positional user input
Targeted unit test 5cdec9f7a52f320a4f59164ec3564fe7a40f1d9a n/a McpPromptLoader.test.ts PASS: 33/33 tests

Commands run inside tmux:

PR6571_REPO_ROOT=.worktrees/pr6571-before PR6571_EXPECT_FIXED=0 npx tsx .qwen/scripts/pr6571-mcp-prompt-cli-check.ts
PR6571_REPO_ROOT=.worktrees/pr6571-after PR6571_EXPECT_FIXED=1 npx tsx .qwen/scripts/pr6571-mcp-prompt-cli-check.ts
cd .worktrees/pr6571-after/packages/cli && npx vitest run src/services/McpPromptLoader.test.ts

Screenshots:

Base reproduction PR head verification
Base run showing the same slash command and dropped input PR head run showing the same slash command and forwarded input

Interactive tmux demo on PR head: qwen was started in tmux, I entered /pr6571_prompt hello from tmux, the MCP prompt returned the received arguments into the model context, and the right pane tails the MCP server's getPrompt argument log.

Interactive qwen tmux run showing MCP arguments

Targeted unit test passing

Note: this was a targeted PR verification pass; I did not run the full repository build/typecheck.

- Use positionalArgs.join(' ') instead of positionalArgsString to
  properly strip quotes from positional input, consistent with the
  existing single-arg path.
- Guard against overwriting a user-provided --input named arg with
  positional text.
- Add comment explaining the input key convention.

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed — no blockers. Suggestion-level recommendations are in the Suggestion summary comment below.

The help text previously said the prompt 'has no arguments', which is
now misleading — user input is forwarded as-is. Updated to explain
that free-form text is accepted and how it maps to the input key.

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found. LGTM! ✅

— qwen3.7-max via Qwen Code /review

@yiliang114
yiliang114 enabled auto-merge July 9, 2026 11:43

@chiga0 chiga0 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Overview (AI Generated)

PR: #6571 — fix(cli): forward user input to MCP prompts with no declared arguments
Type: Bug Fix
Change size: +74/-2 across 2 files
HEAD: 04fe0f6b

Findings Summary

  • Critical/Major/Minor: 0
  • Nit: 0

Cross-Validation

Finding Other Reviewer My Assessment
LGTM qwen-code-ci-bot Confirmed
No issues found qwen3.7-max Confirmed

Review

Clean, focused bug fix. The original code had if (!promptArgs) { return {}; } which discarded all parsed user input when the MCP prompt declared no arguments. The fix correctly:

  1. Catches both undefined and empty array cases (!promptArgs || promptArgs.length === 0)
  2. Uses positionalArgs.join(' ') (not the raw string) to properly strip quotes, consistent with the existing single-arg path
  3. Guards --input named arg precedence via Object.hasOwn(argValues, 'input') — user-provided --input wins over positional text
  4. Updates help text from "has no arguments" to accurately describe the forwarding behavior

Test coverage is thorough: 9 new tests covering undefined/empty promptArgs, named-only, positional-only, mixed, quote stripping, --input precedence, empty input, and end-to-end loadCommands flow.

Final Verdict

LGTM. Correct fix for silent data loss with good test coverage.


This review was generated by QoderWork AI

@yiliang114
yiliang114 added this pull request to the merge queue Jul 9, 2026
Merged via the queue into QwenLM:main with commit bb96ac4 Jul 9, 2026
33 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MCP prompt 未声明 arguments 时用户输入被静默丢弃

3 participants