MCP Apps: isError form deferral suppresses PR forms in Codex desktop
Les mainteneurs répondent en général sous 2 jours
Personne n'a encore pris cette issue.
Évaluation
- Difficulté
- 5/5
- Temps estimé
- Plus d'une semaine
- Accessibilité débutants
- 25/100
- Type d'issue
- Bug
- Clarté
- Clairement spécifiée
- Activité
- Active
- Stack technique
- github, go
- Domaine
- ai-infra-agents, backend-api-design
Piste de recherche
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.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Description
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.
- Langage dominant
- Go
- Étoiles
- 34.2k
- Forks
- 5.3k
- Merge moyen
- 5 j 18 h
- PR mergées (30 j)
- 13
Préparer son environnement
- Fournit un Dockerfile ou un fichier Docker Compose
- Propose un modèle de pull request
- Lire le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Autres issues de github/github-mcp-server
-
update_issue_labels is annotated destructiveHint: false but replaces (removes) existing labelsOuverte
Difficulté 2/5 1-3 heures Accessibilité débutants 69/100
github/github-mcp-server#3760 ·
Les mainteneurs répondent en général sous 2 jours
-
docs(install-claude): "environment variable" examples put the PAT in argv and the saved configOuverte
Difficulté 2/5 1-3 heures Accessibilité débutants 82/100
github/github-mcp-server#3758 ·
Les mainteneurs répondent en général sous 2 jours
-
Difficulté 2/5 1-3 heures Accessibilité débutants 69/100
github/github-mcp-server#3729 ·
Les mainteneurs répondent en général sous 2 jours
-
Difficulté 2/5 1-3 heures Accessibilité débutants 65/100
github/github-mcp-server#3722 ·
Les mainteneurs répondent en général sous 2 jours
-
Insiders Feedback: PR created UI doesn't link to the PRPeut-être pris @genius-0963 l’a pris il y a 5 jours. Ouvertebug insiders user-experience
Difficulté 2/5 1-3 heures Accessibilité débutants 65/100
github/github-mcp-server#3658 ·
Les mainteneurs répondent en général sous 2 jours
Toutes les issues de github/github-mcp-server
Issues similaires
-
Difficulté 2/5 1-3 heures Accessibilité débutants 82/100
prime-radiant-inc/evener#5901 ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 69/100
-
kind/bug
Difficulté 2/5 1-3 heures Accessibilité débutants 78/100
kyma-project/serverless#2769 ·
Les mainteneurs répondent en général sous 1 jour
-
Update the mise toolsOuverteready-for-agent
Difficulté 2/5 1-3 heures Accessibilité débutants 78/100
hexlet-basics/hexlet-basics#962 ·
Les mainteneurs répondent en général sous 1 jour
-
imapproxy closeForMaintenance grace timer calls clientConn.Close() before closeMaintenanceTransportPeut-être pris @dejanstrbac l’a pris aujourd’hui. Ouverte
Difficulté 2/5 1-3 heures Accessibilité débutants 83/100
Les mainteneurs répondent en général sous 1 jour