Skip to content

fix: retrieve MCP servers and A2A agents from the resource folder [PRODEV-1374] - #1051

Closed
PopescuTudor wants to merge 1 commit into
mainfrom
fix/mcp-a2a-resource-folder
Closed

fix: retrieve MCP servers and A2A agents from the resource folder [PRODEV-1374]#1051
PopescuTudor wants to merge 1 commit into
mainfrom
fix/mcp-a2a-resource-folder

Conversation

@PopescuTudor

@PopescuTudor PopescuTudor commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator

Problem

McpClient._initialize_client retrieves the MCP server with the folder the job executes in (get_execution_folder_path()UIPATH_FOLDER_PATH, falling back to the ambient UIPATH_FOLDER_KEY inside the SDK), ignoring the folderPath recorded on the resource config. A2aClient.get() does the same for remote A2A agents.

AgentHub's server lookup (GET api/servers/{identifier}, and the A2A equivalent) is folder-scoped, so a server living in a different folder than the job 404s:

  • Agent Builder debug runs execute in the personal workspace, so every debug run against a tenant-folder server fails — cached discovery dies on the first tool call with 404 Not Found on GET …/agenthub_/api/servers/{name}, dynamic discovery (Flow inline agents) dies at startup in list_tools.
  • Published agents whose job runs in a different folder than the server hit the same 404.
  • The failing call happens before any type-specific logic, so all MCP server types are affected (Remote, Coded, Command, UiPath), and Remote A2A tools identically.

Binding overwrites cannot compensate today: the Studio binding-overwrites response carries process/index/memorySpace entries but no mcpServer/remoteA2aAgent ones (the bindings generator emits those bindings without a folderPath value), so the @resource_override decorators on retrieve_async never match — those are the No resource overwrite matched for mcpServer key='mcpServer.<Name>' on retrieve_async lines in the failing runs' logs.

Tracked as PRODEV-1374 (dogfooding, Remote MCP; independently reported for coded MCP servers on staging).

Fix

Resolve the retrieve folder from the resource first:

  1. config.folder_path — where the registration actually lives. An MCP server / remote A2A agent is an external reference with its own folder, unlike a process deployed alongside the agent, so the recorded folder is authoritative;
  2. mapped through the new resolve_resource_folder_path() (_utils/_environment.py): the packager's solution_folder sentinel and empty values become None, so solution-local resources keep falling back to
  3. the execution folder (UIPATH_FOLDER_PATH) — and from there the SDK's ambient folder key, as before.

The sentinel guard is the lesson from #1038 / #1047: solution_folder must never be sent as a real folder path. Binding overwrites, when present, still win — the @resource_override decorators replace both name and folder args after this resolution.

A2aClient gains an optional resource_folder_path parameter (default None preserves the previous behavior for direct constructions); create_a2a_tools_and_clients passes resource.folder_path.

Testing

  • New tests (written first, watched fail with folder_path='/Exec/JobFolder' instead of the resource folder):
    • TestMcpClient::test_retrieve_uses_resource_folder_not_execution_folder, plus sentinel-fallback and sentinel-with-no-env pins (…falls_back_to_execution_folder_for_sentinel, …passes_none_when_sentinel_and_no_execution_folder)
    • test_client_retrieves_agent_from_resource_folder and test_client_falls_back_to_execution_folder_for_sentinel_resource for A2A, going through create_a2a_tools_and_clients so the resource→client wiring is covered
  • Removed test_retrieve_async_uses_name_and_execution_folder_path, which pinned the buggy resolution (and used identical env/resource values, so it could not tell the two sources apart).
  • Full suite green except 3 pre-existing test_uipath_cli_tool.py schema-example failures that fail identically on clean main in this environment (local CLI version, unrelated).
  • ruff check / ruff format --check / httpx client linter clean. Module docs (mcp/claude.md, test_mcp/claude.md) updated. Version bumped 0.16.10 → 0.16.11.

Follow-ups (separate, noted on PRODEV-1374)

  • Agents repo: BindingsGenerator should emit folderPath in mcpServer/remoteA2aAgent bindings so Solutions deployments can remap folders and binding overwrites start covering MCP/A2A.
  • Per fix: process tool folder fallback when UIPATH_FOLDER_PATH is unset #1038's notes, context_tool.py / escalation_recipient.py / escalation_tool.py still do env-only resolution; out of scope here.

🤖 Generated with Claude Code

An agent's MCP/A2A tool retrieved its server with the job's execution
folder (UIPATH_FOLDER_PATH, falling back to the ambient
UIPATH_FOLDER_KEY in the SDK), ignoring the folderPath recorded on the
resource config. AgentHub's server lookup is folder-scoped, so any
server living in a different folder than the job 404'd on the first
tool call (cached discovery) or at startup (dynamic discovery) — every
Agent Builder debug run against a tenant-folder server, since debug
runs execute in the personal workspace (PRODEV-1374).

Resolve the retrieve folder from the resource's folderPath first,
mapping the packager's solution_folder sentinel (and empty values) to
None so solution-local resources keep falling back to the execution
folder. Binding overwrites still win: the @resource_override decorators
replace both name and folder when one matches. Version 0.16.10 -> 0.16.11.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 26, 2026 14:34

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@PopescuTudor PopescuTudor self-assigned this Aug 26, 2026
@sonarqubecloud

Copy link
Copy Markdown

@radugheo radugheo closed this Aug 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants