Skip to content

fix: hide Claude permission modes from MCP callers#64

Draft
Disaster-Terminator wants to merge 1 commit into
mainfrom
fix-mcp-to-restrict-permission-modes
Draft

fix: hide Claude permission modes from MCP callers#64
Disaster-Terminator wants to merge 1 commit into
mainfrom
fix-mcp-to-restrict-permission-modes

Conversation

@Disaster-Terminator

@Disaster-Terminator Disaster-Terminator commented Jul 11, 2026

Copy link
Copy Markdown
Owner

Motivation

  • The MCP tool surface exposed a caller-controlled permissionMode that could be forwarded to the Claude CLI, creating a confused-deputy permission bypass risk.
  • The change prevents untrusted MCP clients (or prompt-influenced inputs) from requesting permissive Claude permission modes.

Description

  • Remove permissionMode from the claude_run and claude_continue MCP input schemas so the tool surface no longer advertises caller-controlled permission modes (src/mcp.ts).
  • Add stripCallerPermissionMode to sanitize MCP tool arguments by dropping any caller-supplied permissionMode before forwarding to the backend (src/mcp.ts).
  • Update MCP tests to assert the schemas no longer expose permissionMode and to verify injected permissionMode values are not forwarded to retinue.run/retinue.continueJob (tests/mcp-tools.test.ts).

Testing

  • Typecheck: ran pnpm exec tsc -p tsconfig.json --noEmit which completed successfully.
  • Unit/integration tests: ran pnpm exec vitest run --maxWorkers=1 tests/mcp-tools.test.ts tests/core/claudeArgs.test.ts and the test suite passed (Test Files 2 passed, Tests 61 passed).

Codex Task

Summary by Sourcery

通过从 MCP 工具接口中移除由调用方配置的 permissionMode,并对转发的参数进行清理,强化 Claude 的 MCP 集成,以避免绕过权限模式的情况。

Bug Fixes:

  • 通过在转发到后端之前剥离任何由调用方提供的 permissionMode,防止 MCP 调用方控制 Claude 的权限模式。

Enhancements:

  • claude_runclaude_continue MCP 工具 schema 中停止暴露 permissionMode,以降低“受骗代理人”(confused-deputy)风险。
  • 将 MCP 客户端与 retinue 的连接逻辑泛化,使其与 RetinueApi 接口而非 ClaudeRetinue 协同工作。

Tests:

  • 更新 MCP 工具测试,以验证 permissionMode 被从工具 schema 中省略,并且不会被转发到 retinue.runretinue.continueJob
Original summary in English

Summary by Sourcery

Harden the MCP integration with Claude by removing caller-configurable permissionMode from the MCP tool surface and sanitizing forwarded arguments to avoid permission-mode bypasses.

Bug Fixes:

  • Prevent MCP callers from controlling Claude permission modes by stripping any caller-supplied permissionMode before forwarding to the backend.

Enhancements:

  • Stop advertising permissionMode in claude_run and claude_continue MCP tool schemas to reduce confused-deputy risk.
  • Generalize MCP client-retinue wiring to work with the RetinueApi interface instead of ClaudeRetinue.

Tests:

  • Update MCP tool tests to verify permissionMode is omitted from tool schemas and not forwarded to retinue.run or retinue.continueJob.

@sourcery-ai

sourcery-ai Bot commented Jul 11, 2026

Copy link
Copy Markdown

Reviewer's Guide

本次 PR 移除了通过 MCP 层面控制 Claude permissionMode 的能力,并确保在转发到后端之前剥离任何调用方提供的 permissionMode,同时更新测试以验证新的行为和工具 schema。

在调用 Claude 后端前剥离调用方 permissionMode 的序列图

sequenceDiagram
  actor McpClient
  participant McpServer
  participant stripCallerPermissionMode
  participant RetinueApi

  McpClient->>McpServer: claude_run(args_with_permissionMode)
  McpServer->>stripCallerPermissionMode: stripCallerPermissionMode(args_with_permissionMode)
  stripCallerPermissionMode-->>McpServer: safeArgs_without_permissionMode
  McpServer->>RetinueApi: run(safeArgs_without_permissionMode)

  alt claude_continue
    McpClient->>McpServer: claude_continue(args_with_permissionMode)
    McpServer->>stripCallerPermissionMode: stripCallerPermissionMode(args_with_permissionMode)
    stripCallerPermissionMode-->>McpServer: safeArgs_without_permissionMode
    McpServer->>RetinueApi: continueJob(safeArgs_without_permissionMode)
  end
Loading

File-Level Changes

Change Details Files
在调用后端 retinue API 之前,在 MCP 服务器中隐藏并清理 Claude 的 permission mode。
  • 引入 stripCallerPermissionMode 辅助函数,在将工具参数转发到后端之前,删除任何由调用方提供的 permissionMode。
  • 更新 claude_run MCP 工具的 schema,使其不再暴露 permissionMode 字段,并在调用 retinue.run 之前使用 stripCallerPermissionMode。
  • 更新 claude_continue MCP 工具的 schema,使其不再暴露 permissionMode 字段,并在调用 retinue.continueJob 之前使用 stripCallerPermissionMode。
src/mcp.ts
调整 MCP 测试,以验证 permissionMode 不再被暴露且不会被转发,并通过 RetinueApi 将测试与 ClaudeRetinue 的具体实现解耦。
  • 用新的测试替换之前针对不支持的 permission mode 的无效参数测试,现在的测试会验证调用方提供的 permissionMode 在调用 retinue.run/continueJob 前被剥离,并捕获被转发的选项。
  • 扩展工具 schema 断言,要求 claude_continue 的字段存在,并确保在 claude_run 和 claude_continue 工具中没有 permissionMode 字段。
  • 将 connectMcpClientWithRetinue 修改为依赖 RetinueApi 接口而不是具体的 ClaudeRetinue 实现,从而可以注入一个简单的测试替身。
tests/mcp-tools.test.ts

Tips and commands

Interacting with Sourcery

  • 触发新的代码审查: 在 pull request 中评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审查评论。
  • 从审查评论生成 GitHub issue: 通过回复某条审查评论,请 Sourcery 根据该评论创建 issue。你也可以在审查评论中回复 @sourcery-ai issue 来创建对应的 issue。
  • 生成 pull request 标题: 在 pull request 标题中的任意位置写上 @sourcery-ai,即可在任意时间生成标题。你也可以在 pull request 中评论 @sourcery-ai title,随时(重新)生成标题。
  • 生成 pull request 摘要: 在 pull request 的正文任意位置写上 @sourcery-ai summary,即可在你希望的位置生成 PR 摘要。你也可以在 pull request 中评论 @sourcery-ai summary,在任意时间(重新)生成摘要。
  • 生成 Reviewer's Guide: 在 pull request 中评论 @sourcery-ai guide,即可在任意时间(重新)生成审查指南。
  • 解决所有 Sourcery 评论: 在 pull request 中评论 @sourcery-ai resolve,可一次性标记解决所有 Sourcery 评论。如果你已经处理完所有评论且不希望再看到它们,这会很有用。
  • 忽略所有 Sourcery 审查: 在 pull request 中评论 @sourcery-ai dismiss,即可忽略所有现有的 Sourcery 审查。如果你希望以一次全新的审查重新开始,这尤其有用——别忘了再评论 @sourcery-ai review 来触发新的审查!

Customizing Your Experience

访问你的 dashboard 以:

  • 启用或禁用审查功能,例如 Sourcery 自动生成的 pull request 摘要、审查指南等。
  • 更改审查语言。
  • 添加、删除或编辑自定义审查说明。
  • 调整其他审查设置。

Getting Help

Original review guide in English

Reviewer's Guide

This PR removes MCP-surface control of Claude permissionMode and ensures any caller-supplied permission modes are stripped before forwarding to the backend, updating tests to verify the new behavior and tool schemas.

Sequence diagram for stripping caller permissionMode before Claude backend calls

sequenceDiagram
  actor McpClient
  participant McpServer
  participant stripCallerPermissionMode
  participant RetinueApi

  McpClient->>McpServer: claude_run(args_with_permissionMode)
  McpServer->>stripCallerPermissionMode: stripCallerPermissionMode(args_with_permissionMode)
  stripCallerPermissionMode-->>McpServer: safeArgs_without_permissionMode
  McpServer->>RetinueApi: run(safeArgs_without_permissionMode)

  alt claude_continue
    McpClient->>McpServer: claude_continue(args_with_permissionMode)
    McpServer->>stripCallerPermissionMode: stripCallerPermissionMode(args_with_permissionMode)
    stripCallerPermissionMode-->>McpServer: safeArgs_without_permissionMode
    McpServer->>RetinueApi: continueJob(safeArgs_without_permissionMode)
  end
Loading

File-Level Changes

Change Details Files
Hide and sanitize Claude permission modes in MCP server before calling backend retinue APIs.
  • Introduce stripCallerPermissionMode helper that drops any caller-supplied permissionMode from tool args before forwarding to the backend.
  • Update claude_run MCP tool schema to no longer expose a permissionMode field and use stripCallerPermissionMode before calling retinue.run.
  • Update claude_continue MCP tool schema to no longer expose a permissionMode field and use stripCallerPermissionMode before calling retinue.continueJob.
src/mcp.ts
Adjust MCP tests to validate permissionMode is no longer surfaced and is not forwarded, and decouple tests from ClaudeRetinue implementation via RetinueApi.
  • Replace the previous invalid-parameter test for unsupported permission modes with a test that verifies caller-supplied permissionMode is stripped before calling retinue.run/continueJob, capturing the forwarded options.
  • Extend tool schema assertions to require claude_continue fields and ensure permissionMode is absent from claude_run and claude_continue tools.
  • Change connectMcpClientWithRetinue to depend on the RetinueApi interface instead of a concrete ClaudeRetinue implementation, allowing injection of a simple test double.
tests/mcp-tools.test.ts

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant