Summary
Permission asks raised by MCP tools invoked from inside Code Mode (execute) never render in the TUI. The execute call blocks indefinitely on the invisible ask, and the next user message (or Esc) aborts it with {"type":"aborted","message":"Tool execution interrupted"}. This silently deadlocks agent↔user workflows. Direct (non-Code-Mode) tool calls show their permission dialogs normally.
Environment
- opencode version: 2.0.16
- OS: Linux 7.2.6-1-omarchy-rc3 (x64, Arch-based Omarchy)
- Terminal: ghostty (TERM=xterm-ghostty, COLORTERM=truecolor)
- Shell: /bin/bash
- Install/channel: latest (v2.0.16, background service via
opencode serve --service)
- Active plugins: superpowers (git+https://github.com/obra/superpowers.git)
- MCP: two local stdio servers (a custom FastMCP Python server, desktop-commander)
Reproduction
- Configure an MCP tool to require an ask, e.g. in
opencode.json:
{ "permissions": [ { "action": "hyprland_*", "resource": "*", "effect": "ask" } ] }
- In a session, call that tool from Code Mode:
await tools.hyprland.clipboard_copy({ text: "hello" })
- No permission dialog appears anywhere in the TUI.
- The
execute call hangs indefinitely (observed 5–44 minutes).
- Type any new message (or press Esc) → the tool result becomes:
{"error":{"type":"aborted","message":"Tool execution interrupted"}}
Expected Behavior
The permission ask renders in the TUI like asks for direct tool calls, so the user can approve/deny and the Code Mode call proceeds.
Actual Behavior
- No ask is ever displayed; the model believes the tool call is running while the user sees nothing. Both sides wait on each other.
- A pending ask eventually exceeds the MCP request timeout in some cases: on v1.18.32→v2 era data we also captured
MCP error -32001: Request timed out (~60 s) for an unanswered ask.
- Additional quirks observed in the same timeline (may be the same root cause):
- Editing
opencode.json permissions mid-session fires config.updated (seen in the log), but the running session still hangs the newly-allowed tool — permission rules are only effective for sessions started after the change.
- An "Allow always" answer is stored project-scoped (row in the
permission table with the project id). A long-running session that belongs to the legacy global project never receives that grant, so its Code Mode calls keep asking (and hanging) forever.
Additional Context
Evidence that the hang is the invisible ask (not the MCP server):
- A config-
allowed tool called via Code Mode returns in 31 ms (tools.hyprland.list_windows()), so Code Mode → MCP plumbing and permission allow-rules work.
- A hung call completed at 18:28:53 — the exact timestamp an
hyprland_clipboard_copy allow row was written to the permission table — i.e. it had been blocked on the ask for 278 s and was released by the grant.
- Reproduced twice in one session after a config change was confirmed applied (
config.updated in the server log 4 s before the second hang).
- The server log shows
message=asking entries for direct tool-call asks (which users answer normally), but no asking entries for the Code Mode hangs.
Full investigation report with timeline available on request.
Summary
Permission asks raised by MCP tools invoked from inside Code Mode (
execute) never render in the TUI. Theexecutecall blocks indefinitely on the invisible ask, and the next user message (or Esc) aborts it with{"type":"aborted","message":"Tool execution interrupted"}. This silently deadlocks agent↔user workflows. Direct (non-Code-Mode) tool calls show their permission dialogs normally.Environment
opencode serve --service)Reproduction
opencode.json:{ "permissions": [ { "action": "hyprland_*", "resource": "*", "effect": "ask" } ] }await tools.hyprland.clipboard_copy({ text: "hello" })executecall hangs indefinitely (observed 5–44 minutes).{"error":{"type":"aborted","message":"Tool execution interrupted"}}Expected Behavior
The permission ask renders in the TUI like asks for direct tool calls, so the user can approve/deny and the Code Mode call proceeds.
Actual Behavior
MCP error -32001: Request timed out(~60 s) for an unanswered ask.opencode.jsonpermissions mid-session firesconfig.updated(seen in the log), but the running session still hangs the newly-allowed tool — permission rules are only effective for sessions started after the change.permissiontable with the project id). A long-running session that belongs to the legacyglobalproject never receives that grant, so its Code Mode calls keep asking (and hanging) forever.Additional Context
Evidence that the hang is the invisible ask (not the MCP server):
allowed tool called via Code Mode returns in 31 ms (tools.hyprland.list_windows()), so Code Mode → MCP plumbing and permission allow-rules work.hyprland_clipboard_copyallow row was written to thepermissiontable — i.e. it had been blocked on the ask for 278 s and was released by the grant.config.updatedin the server log 4 s before the second hang).message=askingentries for direct tool-call asks (which users answer normally), but no asking entries for the Code Mode hangs.Full investigation report with timeline available on request.