[BUG] Cannot Exit Plan Mode in TypeScript SDK

Resolved 💬 3 comments Opened Jul 23, 2025 by omidmogasemi Closed Aug 19, 2025

Environment

  • Platform (select one):
  • [x] Anthropic API
  • [ ] AWS Bedrock
  • [ ] Google Vertex AI
  • [ ] Other: <!-- specify -->
  • Claude CLI version: 1.0.59
  • Operating System: macOS 15.5
  • Terminal: iTerm2

Bug Description

When attempting to get plan mode to work with the TypeScript SDK, we ran into the following error.

  1. We set permissionMode to plan.
  2. We then pass a custom MCP server to mcpServers along with a specific tool name to permissionPromptToolName to handle permissions. This tool is a custom built HTTP server to communicate via our app's frontend for users to accept/deny tools.
  3. This tool works for all tools _except_ allowing the exit_plan_mode tool. Denying exit_plan_mode works perfectly fine, but allowing it immediately kicks Claude Code off to implement the plan without changing the permissionsMode away from plan mode, which gets it stuck in an infinite loop of requesting exit_plan_mode.

Steps to Reproduce

  1. Use the TypeScript SDK in plan mode
  2. Setup a local MCP server for handling tool permissions
  3. Approve a tool call to exit_plan_mode from Claude Code

Expected Behavior

Claude Code should either:

  1. Not fake a message on the user's behalf, and return control to the user after the user approves exit_plan_mode.
  2. More reasonably, change the permissionsMode to something other than plan (ideally this would be customizable via an option in the SDK).

Actual Behavior

  1. Claude fakes a message on the user's behalf approving the exit_plan_mode tool to the AI, but doesn't actually change the permissionsMode so Claude Code gets stuck in an endless loop.

Additional Context

See the relevant logs from our process running Claude Code and the MCP server. Notice how there is a user message that our application never sent. The Claude Code SDK clearly creates this message on our behalf (which is fine), but it doesn't change the permissionsMode.

[2025-07-23T21:16:22.762Z] MCPServer: Sending manual approval response: {
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "{\"behavior\":\"allow\",\"updatedInput\":{\"plan\":\"...\"}}"
      }
    ]
  }
}
[2025-07-23T21:16:22.762Z] MCPServer: Response text content: {"behavior":"allow","updatedInput":{"plan":"..."}}
[2025-07-23T21:16:22.765Z] Received message 7: user [object Object]
[2025-07-23T21:16:22.765Z] Message 7 details: {
  "type": "user",
  "message": {
    "role": "user",
    "content": [
      {
        "type": "tool_result",
        "content": "User has approved your plan. You can now start coding. Start with updating your todo list if applicable",
        "tool_use_id": ...
      }
    ]
  },
  "parent_tool_use_id": null,
  "session_id": ...
}

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗