feat(mcp): suspend the agent job on a UiPath MCP task#905
Closed
edis-uipath wants to merge 1 commit into
Closed
Conversation
When an MCP tool advertises task support (execution.taskSupport optional/required) and the call starts a UiPath Orchestrator job, the agent now suspends until the child job completes — instead of blocking on tasks/result — reusing the exact process_tool suspend/resume path. - McpClient.call_tool_as_task: sends a task-augmented tools/call (params.task) and parses the CreateTaskResult (the Python SDK has no client task helper, so it sends the raw request). - mcp_tool: task-augmentable tools (per AgentMcpTool.execution.taskSupport, also mapped from dynamic-discovery Tool.execution) invoke @durable_interrupt -> read the result's _meta (uipath.com/source=orchestrator, jobKey, folderKey) -> interrupt(WaitJobRaw(...)). The runtime persists a JOB_RAW resume trigger, Orchestrator suspends the parent, and on completion resumes with the child job's output. Non-task tools are unchanged. Depends on: - uipath-python: AgentMcpTool.execution.taskSupport (UiPath/uipath-python#1716) — needed for the cached discovery path; CI is red until that publishes and the lock picks it up. - AgentHubService task result _meta marker + a `ttl` on the task (so the result parses here). Tests: detection (optional/required vs forbidden/none), execution mapping from a server Tool, call_tool_as_task request shape, and the suspend path (asserts WaitJobRaw carries job/folder keys and resume returns the job output). Full mcp suite green (67). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR adds MCP “task” execution support for UiPath-backed MCP tools so that when a task starts a UiPath Orchestrator job, the agent suspends and resumes via the existing durable interrupt path (instead of blocking on task polling), aligning MCP tool execution with the process_tool job model.
Changes:
- Map MCP server
Tool.execution.taskSupportintoAgentMcpTool.executionand detect task-augmentable tools (optional/required). - Add
McpClient.call_tool_as_task()to send task-augmentedtools/callrequests and receive aCreateTaskResulthandle. - Implement suspend/resume behavior for UiPath-marked tasks by interrupting with
WaitJobRawand returning parsed job output; add tests covering detection, request shape, and suspend path.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
src/uipath_langchain/agent/tools/mcp/mcp_tool.py |
Adds taskSupport mapping/detection and the suspend-on-UiPath-task execution path using WaitJobRaw + durable interrupt. |
src/uipath_langchain/agent/tools/mcp/mcp_client.py |
Adds a raw task-augmented tools/call helper (call_tool_as_task) using send_request. |
tests/agent/tools/test_mcp/test_mcp_task_suspend.py |
New tests validating task detection, request augmentation, and suspend/resume behavior. |
Comment on lines
+257
to
+277
| meta = create_result.meta or {} | ||
| if meta.get(_UIPATH_SOURCE_META_KEY) != _UIPATH_ORCHESTRATOR_SOURCE: | ||
| raise AgentRuntimeError( | ||
| code=AgentRuntimeErrorCode.UNEXPECTED_ERROR, | ||
| title=f"Tool '{mcp_tool.name}' did not start a UiPath job", | ||
| detail=( | ||
| "The MCP server returned a task that is not a UiPath Orchestrator job " | ||
| "(missing the uipath.com/source marker), which is not supported." | ||
| ), | ||
| ) | ||
|
|
||
| return WaitJobRaw( | ||
| # The resume trigger keys off the job's GUID key (item_key = job.key) and re-fetches the | ||
| # job on resume; the numeric id is required by the model but unused here, hence the 0. | ||
| job=Job( | ||
| id=0, | ||
| key=meta.get(_UIPATH_JOB_KEY_META_KEY), | ||
| folder_key=meta.get(_UIPATH_FOLDER_KEY_META_KEY), | ||
| ), | ||
| process_folder_key=meta.get(_UIPATH_FOLDER_KEY_META_KEY), | ||
| ) |
Comment on lines
7
to
11
| from uipath.agent.models.agent import ( | ||
| AgentMcpResourceConfig, | ||
| AgentMcpTool, | ||
| AgentMcpToolExecution, | ||
| CachedToolsConfig, |
Comment on lines
+23
to
+28
| def _mcp_tool(task_support: str | None) -> AgentMcpTool: | ||
| data: dict = { | ||
| "name": "invoke-process", | ||
| "description": "Run a process", | ||
| "inputSchema": {"type": "object", "properties": {}}, | ||
| } |
Contributor
Author
|
we will wait to see where tasks land before doing this |
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.
Suspend the agent job on a UiPath MCP task
Stacked on #904 (mcp 1.27.2). When an MCP tool advertises task support and the call starts a UiPath Orchestrator job, the agent now suspends until the child job completes — instead of blocking on
tasks/result— reusing the exact suspend/resume pathprocess_toolalready uses.Flow
AgentMcpTool.execution.taskSupport=optional/required) is invoked.McpClient.call_tool_as_tasksends a task-augmentedtools/call(params.task) and parses theCreateTaskResult(the Python SDK has no client task helper, so it sends the raw request viasend_request)._metamarks it as a UiPath job (uipath.com/source=orchestrator,jobKey,folderKey).@durable_interrupt→interrupt(WaitJobRaw(job=Job(key=jobKey, folder_key=folderKey), process_folder_key=folderKey)). The runtime persists aJOB_RAWresume trigger, Orchestrator suspends the parent job, and on child completion resumes with the job's output.Non-task tools are unchanged (synchronous
call_tool, 404-retry).Where task support comes from
AgentMcpTool.execution.taskSupport(feat(agent): add execution.taskSupport to AgentMcpTool uipath-python#1716).Tool.executioninto the same field.AgentMcpTool.execution.taskSupport. CI here is red until that publishes and the lock picks it up (the import resolves then). Bump theuipathfloor to that release before merge._metamarker and must emit attlon the task object (the official PythonTask.ttlis required, so theCreateTaskResultwon't parse without it).Testing
optional/required⇒ task;forbidden/absent ⇒ not), execution mapping from a serverTool,call_tool_as_taskrequest shape, and the suspend path (assertsWaitJobRawcarries the job/folder keys from_metaand resume returns the job output).test_mcpsuite green (67); ruff + mypy clean. (Run locally against an editable uipath-python #1716.)🤖 Generated with Claude Code