fix(workspace-runtime): route delegate_task through platform A2A proxy - #2418
Merged
HongmingWang-Rabbit merged 1 commit intoMay 1, 2026
Merged
Conversation
tool_delegate_task was POSTing directly to peer["url"], which is the Docker-internal hostname (e.g. http://ws-X-Y:8000) for in- container peers. External callers — the standalone molecule-mcp wrapper running on an operator's laptop — get [Errno 8] nodename nor servname every single delegation, breaking the universal-MCP path's last "ride the same code as in-container" claim. The platform's /workspaces/:peer-id/a2a proxy endpoint already handles internal forwarding for in-container peers AND is the only path external runtimes can use. Unify on it: in-container callers pay one extra HTTP hop on the same Docker bridge (microseconds); external callers get a working delegation path for the first time. discover_peer is still called for access-control + online-status detection — only the routing target changes. Verified live on 2026-04-30 against workspace 8dad3e29 (external mac runtime) → 97ac32e9 (Claude Code Agent in-container): direct POST returned ConnectError, proxy POST returned "acknowledged from claude code agent" as requested. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
HongmingWang-Rabbit
requested a review
from hongmingwang-moleculeai
as a code owner
May 1, 2026 00:14
HongmingWang-Rabbit
enabled auto-merge
May 1, 2026 00:14
6 tasks
HongmingWang-Rabbit
pushed a commit
that referenced
this pull request
May 1, 2026
…s UUID Two cleanups stacked on PR #2418: 1. Refactor `send_a2a_message(target_url, msg)` → `send_a2a_message(peer_id, msg)`. After #2418 every caller passes `${PLATFORM_URL}/workspaces/{peer_id}/a2a` — the function's parameter pretended to accept arbitrary URLs but in practice only one shape is meaningful. Owning URL construction inside the function makes the contract honest and centralises the peer-id validation introduced below. 2. Add `_validate_peer_id` UUID-shape check at the trust boundary. `discover_peer` and `send_a2a_message` are the entry points where agent-controlled strings flow into URL paths; rejecting non-UUID input at this layer eliminates the URL-interpolation class of bug (`workspace_id="../admin"` etc.) regardless of how the rest of the codebase interpolates ids elsewhere. Auth was already gating malicious access — this is consistency + clear failure over silent platform 4xx. In-container tests cover positive UUIDs, malformed input (``"ws-abc"``, ``"../admin"``, empty), and the contract that ``tool_delegate_task`` hands the peer_id to ``send_a2a_message`` without building URLs itself. Live-verified: external delegation 8dad3e29 → 97ac32e9 returned "refactor verified" from Claude Code Agent through the refactored code; ``_validate_peer_id`` rejects ``"ws-abc"`` and ``"../admin"`` and accepts canonical UUIDs. Stacked on PR #2418 (proxy-routing fix). Will rebase onto staging once #2418 merges. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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
tool_delegate_taskwas POSTing directly topeer[\"url\"], which for in-container peers is a Docker-internal hostname (http://ws-X-Y:8000). External callers — the standalonemolecule-mcpwrapper — fail every delegation with[Errno 8] nodename nor servname providedbecause that hostname only resolves inside the platform's container DNS.The platform's
/workspaces/:peer-id/a2aproxy endpoint already handles internal forwarding for in-container peers AND is the only path external runtimes can use. This PR unifies on it.Diff is 4 lines of substance
discover_peeris still called for access-control + online-status — only the routing target changes.Live verification
Against staging tenant
hongmingwang.moleculesai.app:http://ws-97ac32e9-b7a:8000${PLATFORM_URL}/workspaces/97ac32e9.../a2aIn-container delegation continues to work — the proxy forwards over the same Docker bridge that direct routing already used; the cost is one HTTP hop on a private network (microseconds).
Test plan
pytest tests/test_a2a_tools_impl.py— replacedtest_peer_has_no_url_returns_error(obsolete) withtest_offline_peer_returns_error+ newtest_routes_through_platform_proxy_not_peer_urlthat asserts the URL shapeWhy this matters
This closes the last gap in the universal-MCP claim. With #2412 (token-on-restart), #2413 (standalone register+heartbeat), #2415 (inbox polling), and now this fix, an external operator can run `molecule-mcp` on a laptop and get full bidirectional A2A — including delegating to in-container peers — with no tunnel + no Python-SDK dependency.
🤖 Generated with Claude Code