MCP Apps: isError form deferral suppresses PR forms in Codex desktop
Los mantenedores suelen responder en 2 días
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 5/5
- Tiempo estimado
- Más de una semana
- Aptitud para principiantes
- 25/100
- Tipo de issue
- Error
- Claridad
- Bien especificado
- Estado de actividad
- Activo
- Stack tecnológico
- github, go
Línea de trabajo
Start by reading pkg/utils/result.go, especially NewToolResultAwaitingFormSubmission, and trace how form deferral sets IsError and structured status. Then follow the form result handler and host rendering lifecycle for pending, submitted, cancelled, and failed states; done means a deferred form renders and completes correctly without treating genuine tool failures as pending. The issue calls for testing submission, cancellation, failures, and final result delivery.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Describe the bug
On Codex desktop, GitHub MCP form deferral returns isError: true while instructing the assistant to wait for a form submission. The host classifies the call as failed and excludes the corresponding MCP App from rendering. The user therefore has no form to submit, the requested GitHub mutation never executes, and the assistant may end its turn waiting for an interaction that is unavailable.
This is a concrete mismatch between the server's pending-form signaling and the host's error-rendering policy. Related reports describe invisible or collapsing forms in Claude: #2823 and #3415. #3455 discusses retaining an opt-out. This report adds a Codex reproduction and a replay of the installed client's rendering gate; I have not established that the Claude reports have the same cause.
Affected version
- Server: hosted remote GitHub MCP at
https://api.githubcopilot.com/mcp/, not a local Docker deployment. - Version reported by MCP initialization during the controlled reproduction:
github-mcp-server/remote-a5f0ed2ba9b09e7e6bd87d7e8adb559158f83ff5. - Client: Codex desktop on macOS, version
26.1027.61615, build24141, production channel. - The app's updater reported
up_to_date; no desktop upgrade was applied during diagnosis. - Observed on November 3, 2026. Both PR creation and PR update encountered form deferral.
- The controlled MCP client advertised the
io.modelcontextprotocol/uiextension with MIME typetext/html;profile=mcp-app.
Steps to reproduce the behavior
- Connect the hosted GitHub MCP server to the affected Codex desktop version with MCP Apps support enabled and without the
mcp_apps_disable_form_deferralfeature flag. - Use an existing test PR that the authenticated account can edit. Read its current title.
- Call
update_pull_requestwith onlyowner,repo,pullNumber, and that same title. Using the unchanged title avoids an intentional content change. Example tool arguments:
{
"owner": "YOUR_OWNER",
"repo": "YOUR_TEST_REPO",
"pullNumber": 123,
"title": "THE_CURRENT_PR_TITLE"
}
- Observe a result with
isError: truewhose text asserts that a form has been shown and directs the assistant to wait silently for submission. - In the client, the call is marked failed and no usable form remains available to submit. The PR update has not executed.
The problem also occurred with create_pull_request. Reproducing with an existing PR is preferable to repeatedly attempting creation.
Expected vs actual behavior
Expected: Deferring to a form leaves a visible, usable form, accurately reports that the GitHub mutation is still pending, and eventually delivers submission success, failure, or cancellation to the assistant.
Actual: The pending-form response is treated as a failed tool result, which prevents form rendering. The response text asserts UI visibility without confirmation from the host. The assistant can then wait or stop while the user has nothing to submit.
Logs
Sanitized excerpt from an actual completed create-PR event; identifiers, arguments, and message text are omitted:
{
"type": "McpToolCall",
"server": "github",
"tool": "create_pull_request",
"mcpAppResourceUri": "ui://github-mcp-server/pr-write",
"status": "failed",
"result": {
"isError": true
}
}
The original result also contained a text block telling the assistant that a form was already displayed and to wait for submission. The corresponding resource-read RPC returned no protocol error, but that alone does not prove successful UI rendering.
Root-cause evidence
NewToolResultAwaitingFormSubmission deliberately sets IsError: true to stop the agent continuing. Its comment assumes the host will still render UI from the tool's metadata regardless of the result. The helper also supplies an awaiting_user_submission structured status in this source revision.
That assumption does not hold in the installed Codex build. Inspection of the installed JavaScript bundle found this chain:
- The tool-event projection passes the recorded
failedstatus into result normalization. - Normalization produces a result with
type: "error". - The MCP App eligibility/renderability logic explicitly excludes error results.
- The resource renderer returns its fallback branch when
shouldRenderMcpAppis false, even if valid HTML is available.
A local replay used the actual captured event and the unchanged normalization, error-detection, renderability, and resource-selection functions extracted from that installed bundle:
| Replay input | Normalized result | Form renderable | Resource selection |
|---|---|---|---|
Original recorded failed status |
error |
false |
fallback |
Only the recorded status changed to completed |
success |
true |
html |
This isolates a sufficient rendering blocker. The control changes the projected call status, not the live server response; it is not an end-to-end test of changing isError upstream. Unrelated eligibility predicates were allowed, text normalization was an identity operation for the captured text-only fixture, and the resource selector received synthetic valid HTML. No app binaries were modified. No live DOM instrumentation was performed, and additional UI problems are not ruled out.
The linked source revision is not claimed to be identical to the deployed remote build; the captured response independently establishes the problematic isError: true behavior.
Suggested fix
Please separate a successful handoff to a pending form from an actual tool error. One candidate is a non-error result carrying an explicit pending status and a clear indication that the GitHub mutation has not executed:
{
"isError": false,
"structuredContent": {
"status": "awaiting_user_submission",
"operationExecuted": false
}
}
The status already present in the helper is a useful starting point. Agents must not interpret a non-error handoff as a completed PR mutation. The client, form, and agent lifecycle should agree on pending, submitted, cancelled, and failed states. Also consider changing the response wording to describe a requested form handoff rather than asserting that the form is already visible.
This is a proposed direction, not a verified one-line fix: please test the form's own result handler, host rendering, submission, cancellation, genuine tool failures, and delivery of the final result. Simply allowing all failed-tool UIs or automatically executing an unsubmitted mutation would not address the underlying contract cleanly.
Verified workaround
The following request header avoids form deferral:
X-MCP-Features: mcp_apps_disable_form_deferral
Against the same remote server and the same unchanged-title PR update, the baseline request deferred with isError: true; the flagged request executed successfully. After restarting Codex to reload the header, an actual in-chat GitHub MCP PR update also succeeded without waiting for a form. This restores writes but does not repair form rendering.
- Lenguaje dominante
- Go
- Estrellas
- 34.2k
- Forks
- 5.3k
- Merge medio
- 5 d 18 h
- PR fusionados (30 d)
- 13
Preparar el entorno
- Incluye un Dockerfile o un archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de github/github-mcp-server
-
update_issue_labels is annotated destructiveHint: false but replaces (removes) existing labelsAbierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 69/100
github/github-mcp-server#3760 ·
Los mantenedores suelen responder en 2 días
-
docs(install-claude): "environment variable" examples put the PAT in argv and the saved configAbierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
github/github-mcp-server#3758 ·
Los mantenedores suelen responder en 2 días
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 69/100
github/github-mcp-server#3729 ·
Los mantenedores suelen responder en 2 días
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
github/github-mcp-server#3722 ·
Los mantenedores suelen responder en 2 días
-
Insiders Feedback: PR created UI doesn't link to the PRPosiblemente ocupada @genius-0963 la tomó hace 5 días. Abiertobug insiders user-experience
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
github/github-mcp-server#3658 ·
Los mantenedores suelen responder en 2 días
Todos los issues de github/github-mcp-server
Issues similares
-
Update the mise toolsAbiertoready-for-agent
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
hexlet-basics/hexlet-basics#962 ·
Los mantenedores suelen responder en 1 día
-
imapproxy closeForMaintenance grace timer calls clientConn.Close() before closeMaintenanceTransportPosiblemente ocupada @dejanstrbac la tomó hoy. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 83/100
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
-
Renovate health check failedAbiertorenovate-health
Dificultad 2/5 1-3 horas Aptitud para principiantes 62/100
Netcracker/qubership-network-latency-exporter#267 ·
Los mantenedores suelen responder en 1 día
-
Network capture does not workPosiblemente ocupada @KSpaceer la tomó hoy. Abiertokind/bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
aquasecurity/tracee#5395 ·