Disclosure: this issue was written by an AI agent (Claude) while documenting the
human-in-the-loop flow over MCP, and reviewed by a human before filing.
Summary
tasks/update answers a paused task by looking up params.InputResponses under a key
derived from the task. On a key miss it returns {"resultType": "complete"} having done
nothing. The client sees success, the answer is discarded, and the task stays
input_required with no indication anything went wrong.
The code
// go/core/internal/mcp/tasks.go:171-175
key := inputRequestKey(task)
inputResponse := params.InputResponses[key]
if inputResponse == nil {
return &completeTaskResult{ResultType: "complete"}, nil // <-- silent no-op
}
Note the contrast two lines further down: a value of the wrong type under the right key
is a proper error.
response, ok := inputResponse.(*mcp.ElicitResult)
if !ok || response == nil {
return nil, invalidParams(fmt.Errorf("input response %q must be an elicitation result", key))
}
So a malformed answer is reported and a misaddressed answer is not.
The expected key is not guessable from the elicitation alone in every case:
// go/core/internal/mcp/tasks.go:337-342
func inputRequestKey(task *a2atype.Task) string {
if task.Status.Message != nil && task.Status.Message.ID != "" {
return task.Status.Message.ID
}
return string(task.ID)
}
Reproduction
- Drive an agent to pause with
ask_user (a prompt instructing the agent to use its
ask_user tool reliably produces one; it is registered unconditionally at
go/adk/pkg/agent/agent.go:205).
tasks/get the paused task and read inputRequests, a map keyed by request ID.
- Call
tasks/update with inputResponses keyed by something else, for example
not-a-real-key, carrying a valid ElicitResult.
Observed: the reply is {"resultType": "complete"}, and a follow-up tasks/get shows the
task still input_required. No error is returned and nothing indicates the answer was
dropped. Verified on a kind cluster against controller v0.10.0-rc1-112-g30a8ffe4.
Expected
An inputResponses map that contains no entry for the task's current input request is
rejected with invalidParams, naming the expected key, in the same way a wrong-typed value
already is. A success envelope should not be returned for a write that did not happen.
Note
resultType is about the envelope rather than the run, so a client cannot use it to detect
this either: a task paused on a question reports "resultType": "complete" alongside
"status": "input_required". The only reliable signal is status, which makes the silent
success especially easy to mistake for a completed answer.
Summary
tasks/updateanswers a paused task by looking upparams.InputResponsesunder a keyderived from the task. On a key miss it returns
{"resultType": "complete"}having donenothing. The client sees success, the answer is discarded, and the task stays
input_requiredwith no indication anything went wrong.The code
Note the contrast two lines further down: a value of the wrong type under the right key
is a proper error.
So a malformed answer is reported and a misaddressed answer is not.
The expected key is not guessable from the elicitation alone in every case:
Reproduction
ask_user(a prompt instructing the agent to use itsask_usertool reliably produces one; it is registered unconditionally atgo/adk/pkg/agent/agent.go:205).tasks/getthe paused task and readinputRequests, a map keyed by request ID.tasks/updatewithinputResponseskeyed by something else, for examplenot-a-real-key, carrying a valid ElicitResult.Observed: the reply is
{"resultType": "complete"}, and a follow-uptasks/getshows thetask still
input_required. No error is returned and nothing indicates the answer wasdropped. Verified on a kind cluster against controller
v0.10.0-rc1-112-g30a8ffe4.Expected
An
inputResponsesmap that contains no entry for the task's current input request isrejected with
invalidParams, naming the expected key, in the same way a wrong-typed valuealready is. A success envelope should not be returned for a write that did not happen.
Note
resultTypeis about the envelope rather than the run, so a client cannot use it to detectthis either: a task paused on a question reports
"resultType": "complete"alongside"status": "input_required". The only reliable signal isstatus, which makes the silentsuccess especially easy to mistake for a completed answer.