Repository navigation
Conversation
marekdano
requested review from
Lang-Akshay,
brian-hussey,
ja8zyjits and
msureshkumar88
as code owners
October 29, 2026 11:59
Lang-Akshay
requested changes
Oct 29, 2026
Lang-Akshay
left a comment
Collaborator
There was a problem hiding this comment.
Blocking Changes
| # | Area | File | Line | Blocking reason | Required change |
|---|---|---|---|---|---|
| 1 | Security (subagent SECURITY_VERDICT=BLOCK) / Issue |
mcpgateway/services/a2a_service.py |
3615-3617 | {"messageId": ..., "role": "user", **message, "taskId": task_id} lets the client override the gateway-generated messageId and role. The contextId guard (if task.get("contextId") and not follow_up.get("contextId")) only fills a missing value. A client-supplied contextId is forwarded and stored in the task_continued event. taskId mismatch returns 400, but contextId mismatch passes silently. The PR claims the message is bound to the stored task and context. |
Set contextId from the stored task after the spread, or reject a mismatching value with 400 as for taskId. Set role and messageId after the spread, or reject client values. Add a regression test for each override. |
marekdano
added a commit
that referenced
this pull request
Oct 29, 2026
Address review feedback on #7374 (issue #6703). Stop a client from overriding fields the gateway owns when it continues a task. The spread of the client message could replace messageId and role, and a client contextId was forwarded and logged. - Set taskId and contextId from the stored task. Reject a client value that differs, including a contextId on a task that has none. - Always send role as the user role. Accept the user and ROLE_USER spellings. Reject any other role. - Always generate messageId in the gateway. - Add a regression test for each override and for each accepted case. Signed-off-by: Marek Dano <mk.dano@gmail.com>
marekdano
added a commit
that referenced
this pull request
Oct 30, 2026
Address review feedback on #7374 (issue #6703). Stop a client from overriding fields the gateway owns when it continues a task. The spread of the client message could replace messageId and role, and a client contextId was forwarded and logged. - Set taskId and contextId from the stored task. Reject a client value that differs, including a contextId on a task that has none. - Always send role as the user role. Accept the user and ROLE_USER spellings. Reject any other role. - Always generate messageId in the gateway. - Add a regression test for each override and for each accepted case. Signed-off-by: Marek Dano <mk.dano@gmail.com>
marekdano
force-pushed
the
6703-a2a-continue-task
branch
from
October 30, 2026 12:12
d3c8630 to
f08c76f
Compare
marekdano
added a commit
that referenced
this pull request
Oct 30, 2026
Address review feedback on #7374 (issue #6703). Stop a client from overriding fields the gateway owns when it continues a task. The spread of the client message could replace messageId and role, and a client contextId was forwarded and logged. - Set taskId and contextId from the stored task. Reject a client value that differs, including a contextId on a task that has none. - Always send role as the user role. Accept the user and ROLE_USER spellings. Reject any other role. - Always generate messageId in the gateway. - Add a regression test for each override and for each accepted case. Signed-off-by: Marek Dano <mk.dano@gmail.com>
marekdano
force-pushed
the
6703-a2a-continue-task
branch
from
October 30, 2026 15:13
727a397 to
f07080f
Compare
marekdano
added a commit
that referenced
this pull request
Nov 3, 2026
Address review feedback on #7374 (issue #6703). Stop a client from overriding fields the gateway owns when it continues a task. The spread of the client message could replace messageId and role, and a client contextId was forwarded and logged. - Set taskId and contextId from the stored task. Reject a client value that differs, including a contextId on a task that has none. - Always send role as the user role. Accept the user and ROLE_USER spellings. Reject any other role. - Always generate messageId in the gateway. - Add a regression test for each override and for each accepted case. Signed-off-by: Marek Dano <mk.dano@gmail.com>
marekdano
force-pushed
the
6703-a2a-continue-task
branch
from
November 3, 2026 14:32
f07080f to
27991cd
Compare
marekdano
added a commit
that referenced
this pull request
Nov 9, 2026
Address review feedback on #7374 (issue #6703). Stop a client from overriding fields the gateway owns when it continues a task. The spread of the client message could replace messageId and role, and a client contextId was forwarded and logged. - Set taskId and contextId from the stored task. Reject a client value that differs, including a contextId on a task that has none. - Always send role as the user role. Accept the user and ROLE_USER spellings. Reject any other role. - Always generate messageId in the gateway. - Add a regression test for each override and for each accepted case. Signed-off-by: Marek Dano <mk.dano@gmail.com>
marekdano
force-pushed
the
6703-a2a-continue-task
branch
from
November 9, 2026 10:46
27991cd to
9586778
Compare
A caller could not answer an agent that paused in an input-required
or auth-required state. The invoke routes had no task identifier.
Add POST /v1/a2a/{agent_id}/tasks/{task_id}/messages. The body holds
either an A2A message object or a text string. The gateway adds taskId
and the stored contextId, converts the message for 0.3 and 1.0 agents,
and sends it through invoke_agent. The task row takes its state from
the agent response. A task_continued event records the previous and
new state.
An unknown or invisible task returns 404. A task in a terminal state
returns 409. A message that names a different taskId returns 400. The
route requires a2a.invoke, and TokenScopingMiddleware maps the path.
Fix cancel_task and upsert_task to treat the 1.0 terminal states
(TASK_STATE_COMPLETED, TASK_STATE_FAILED, TASK_STATE_CANCELED) as
terminal. Before, cancelling a finished 1.0 task overwrote its state.
Signed-off-by: Marek Dano <mk.dano@gmail.com>
Address review feedback on #7374 (issue #6703). Stop a client from overriding fields the gateway owns when it continues a task. The spread of the client message could replace messageId and role, and a client contextId was forwarded and logged. - Set taskId and contextId from the stored task. Reject a client value that differs, including a contextId on a task that has none. - Always send role as the user role. Accept the user and ROLE_USER spellings. Reject any other role. - Always generate messageId in the gateway. - Add a regression test for each override and for each accepted case. Signed-off-by: Marek Dano <mk.dano@gmail.com>
Signed-off-by: Marek Dano <mk.dano@gmail.com>
marekdano
force-pushed
the
6703-a2a-continue-task
branch
from
November 11, 2026 09:40
9586778 to
af46258
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A caller can now answer an agent that paused in an
input-requiredorauth-requiredstate. Before, the invoke routes had no task identifier, so interaction stopped at a single-shot request and response.Closes #6703
Part of #5936
Depends on #7372, which adds the routes that read task state. Merge #7372 first. This branch does not include that change. After #7372 merges, rebase onto
main.Changes
New route:
POST /v1/a2a/{agent_id}/tasks/{task_id}/messages, with permissiona2a.invoke.message(an A2A message object) ortext(one text part). The request needs exactly one of them.message.partsmust not be empty.A2AAgentService.continue_task()finds the task with the same visibility scoping asget_task. It addstaskIdand the storedcontextIdto the message, and defaultsmessageIdandrole.invoke_agent. A2A 0.3 and 1.0 both carrytaskIdandcontextIdon the message, and the existing normalization converts the rest. A 1.0 agent getsSendMessagewithROLE_USER. A 0.3 agent getsmessage/sendwithkindmarkers.invoke_agent.task_continuedevent ina2a_task_eventsrecords the previous and new state, with a per-task sequence number. A failed event write is logged and does not fail the request, because the agent already received the message.TokenScopingMiddlewaremaps the new path toa2a.invoke.message.taskIdnames a different taskRelated fix
cancel_taskandupsert_taskonly recognized the 0.3 terminal states. Cancelling a finished 1.0 task, stored asTASK_STATE_COMPLETED, overwrote its state. Both now use the newis_terminal_task_state()helper, which also drives the 409 check.Limits
Checklist
make pre-commit ruff interrogate pylint verifypass