Skip to content

[Bug] Copilot: an approved connector action executes, but its result never reaches the assistant or the card #504

Description

@bemany

Summary

When Quinn (Copilot) proposes a connector tool call and a teammate approves it, the call executes, but its result goes nowhere: it is not added to the assistant's thread, and it is not rendered on the card either. The assistant then believes the action is still awaiting approval.

The data is fetched from the remote MCP server and effectively discarded — nobody, neither the model nor the human, ever sees it.

Environment

  • Self-hosted, single workspace, v0.13.2-1017-g9d222efbf
  • AI: OpenAI directly (OPENAI_BASE_URL=https://api.openai.com/v1), AI_CHAT_MODEL=gpt-4.1-mini
  • Connector: a remote MCP server (Plane's hosted MCP), auth mode bearer
  • Tool policies: group defaults read: always, write: approval

Steps to reproduce

  1. Add an MCP connector whose tools are classified as write (no readOnlyHint), so they fall under write: approval.
  2. Open a conversation, switch the right-hand panel to Copilot.
  3. Ask something that requires the connector, e.g. "What is the title and status of work item ABC-107?"
  4. Quinn answers that the request has been submitted and needs approval, and renders the proposed-action card with the tool name and arguments. This part works correctly.
  5. Click Approve.
  6. The card changes to "Approved and executed". The connector row's last_call_at is updated, so the call really did run.
  7. Ask a follow-up in the same Copilot chat: "Now tell me the title and status from the result, without a new lookup."

Expected

Quinn answers using the result of the approved call.

Actual

Quinn answers (translated): "The retrieval of the data for work item ABC-107 has not been approved yet, so I do not have the title and status."

At that point the action had been approved and executed twice. The card never shows the payload either — only a short status line.

Where this seems to come from

I did not chase this all the way, so take the pointers as observations rather than a diagnosis:

  • copilot-panel.tsxrunTurn notes that "History rides the AG-UI thread natively (useChat re-sends its accumulated messages)". The executed action's result is not part of those messages, so the next turn cannot see it.
  • copilot-proposed-action-card.tsx renders formatProposedActionResult(data.result) — explicitly documented as "a short, human line out of a tool's JSON result, if it offered one", falling back to "Approved and executed". A connector result ({ ok, data, note }) offers no such line, so the payload is never displayed.

So the result appears to be persisted on the proposed action server-side, but there is no path from there back into either the thread or the UI.

Impact

Any connector tool behind approval is effectively write-only: it can perform an action, but it cannot answer a question.

This is worse than it sounds for read-shaped tools. Many MCP servers bundle read and write into one tool — Plane's workitem handles list, retrieve, create and update in a single tool and therefore reports no readOnlyHint, so it lands in the write group and requires approval. Every lookup then goes through this path and every lookup loses its answer.

Side observation

retrieve without a field filter returns the full record (description HTML included) and hits CONNECTOR_RESPONSE_CHAR_LIMIT; the card shows "Result was truncated." Asking the assistant to limit the fields works around it. Mentioning it only because it is easy to mistake for the same bug — it is not.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions