feat(a2a): A2A server core + client transport + scheme-dispatched remotes - #266
Merged
Conversation
Contributor
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
7 tasks
Nexo as an MCP client: external streamable-HTTP MCP servers surface their tools
as namespaced ITool proxies (mcp:{server}:{tool}) that reach agent toolboxes
through a new IToolSource seam.
- src/Nexo.Mcp.Client: McpClientConnectionManager (hosted service) dials
configured servers, pins each tool definition (name/description/raw schema)
for the process lifetime, and faults on drift instead of following remote
redefinitions; unreachable servers degrade to zero tools; remote isError and
transport failures map to error payloads per the repo tool convention;
per-server API keys are env-var named and verified present at startup.
- Nexo.Abstractions.IToolSource: SDK-free seam for post-startup-discovered
tools; RepoFsToolboxFactory gains an extraTools fold-in and
SelfExtendRunnerAdapter snapshots DI-registered sources each cycle.
- src/Nexo.Mcp.Client.Tests: 29 tests, including full protocol round trips -
a real McpClient against the real Nexo.Mcp.Server bridge over in-memory
pipes (list/call/structured-content/protocol-error), plus manager
pin-and-proxy end-to-end.
- Directory.Packages.props: Microsoft.Extensions.Options.ConfigurationExtensions
pin (10.0.11).
Fail-closed: Enabled=false default, ValidateOnStart, AirGapped refusal, empty
allowlists, stdio child processes deliberately excluded from v1.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>…otes
Nexo speaks A2A v1.0 in both directions via the official A2A + A2A.AspNetCore
SDK (1.0.0-preview2; consuming projects IsPackable=false until stable).
Client (src/Nexo.Transport.A2A):
- A2AAgentTransport : IAgentTransport selected by the a2a+ endpoint scheme;
peers are ordinary EndpointDescriptors, so routing/health/barrier metadata
work unchanged and no kernel public API moved.
- Correlation/span/barrier context propagates as protocol metadata on message
and request (gRPC x-nexo-* header equivalent, same audit event); remote task
states map to typed AgentResults; MaxRetries covers transport-level failures
only; per-endpoint API keys are env-var named and verified at startup.
Coexistence (src/Nexo.Runtime + Nexo.Abstractions):
- AgentTransportSchemeRegistration (Abstractions, dep-free) +
SchemeDispatchingAgentTransport (Runtime): AddNexoRuntimeTransport wraps the
remote side only when scheme registrations exist - with none, composition is
byte-for-byte the previous gRPC-only behavior. Phase05 untouched.
Server core (src/Nexo.Transport.A2A.Server):
- Deny-by-default exposure (ExposedAgentIds allowlist + opt-in coordination-
protocol marker); enabled-with-zero-agents refuses to boot.
- NexoA2AAgentHandler mirrors the gRPC facade: fixed agent identity, bounded
execution budget, IAgentTransport.SendAsync - never the reflection-scanning
RunAgentCommand/AgentExecutorAdapter path.
- Spec cards via INexoA2ACardProjector (streaming=false in the synchronous v1);
the colliding A2A.AgentCard type never leaves the adapter; hosts implement
INexoA2AAgentCatalog (adapter cannot reference Core.Domain per layering).
- MapNexoA2AEndpoints: per-agent JSON-RPC + card under /api/a2a/{id}, primary
card at /.well-known/agent-card.json; RPC and card builders returned
separately for differentiated host auth.
Tests: 36 transport + 13 server (incl. full-wire round trip: A2AAgentTransport
-> JSON-RPC over TestServer -> mapped endpoints -> handler -> fake in-process
transport, correlation verified) + 6 scheme-dispatch/composition tests and 3
layering mirrors in Nexo.Tests.Transport; NexoIngressTransports gains mcp/a2a
labels (contracts test updated).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>IanFrelingerforce-pushed
the
feat/mcp-client-tools
branch
from
August 13, 2026 18:17
ad0dda2 to
d749db1CompareIanFrelingerforce-pushed
the
feat/a2a-adapters
branch
from
August 13, 2026 18:17
336a6fa to
076bc62CompareUh oh!
There was an error while loading. Please reload this page.
This was referenced Aug 13, 2026
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 freeto 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
PR-3 of the MCP/A2A series (stacked on #265 → #264 → #263; retarget as parents merge). Nexo speaks A2A v1.0 in both directions via the official
A2A+A2A.AspNetCoreSDK (1.0.0-preview2 — both consuming projectsIsPackable=falsewith a tracking comment until a stable SDK ships, avoiding NU5104). Design: Phase-3 section ofdocs/architecture/ProtocolIntegration-MCP-A2A.md.Changes
src/Nexo.Transport.A2A):A2AAgentTransport : IAgentTransportselected by thea2a+endpoint scheme — peers are ordinaryEndpointDescriptors (a2a+https://peer/api/a2a/agent), so capability routing, health filtering, and barrier levels work unchanged and no kernel public API moved. Correlation/span/barrier context propagates as protocol metadata (message + request) with the same audit event as the gRPC transport'sx-nexo-*headers. Remote task states map to typed results (a2a.task.failed,a2a.timeout, …);MaxRetriescovers transport-level failures only; per-endpoint API keys are env-var-named and presence-verified at startup; card-fetch health probe included.Nexo.Abstractions+Nexo.Runtime): dependency-freeAgentTransportSchemeRegistration+SchemeDispatchingAgentTransport;AddNexoRuntimeTransportwraps the remote side only when registrations exist — with none, composition is byte-for-byte the previous gRPC-only behavior, and kernel Phase05 is untouched. Hosts opt in withAddNexoA2ATransport(configuration)beforeAddNexo().src/Nexo.Transport.A2A.Server): deny-by-default exposure (ExposedAgentIdsallowlist + opt-ina2acoordination-protocol marker; enabled-with-zero-agents refuses to boot);NexoA2AAgentHandlermirrors the gRPC facade (fixed agent identity, bounded execution budget,IAgentTransport.SendAsync— never the reflection-scanningAgentExecutorAdapterpath); spec cards viaINexoA2ACardProjector(streaming=falsein the synchronous v1; the collidingA2A.AgentCardtype never leaves the adapter);MapNexoA2AEndpoints()maps per-agent JSON-RPC + card under/api/a2a/{id}and the primary card at/.well-known/agent-card.json, returning RPC and card builders separately so the host can auth-gate them differently (AllowAnonymousAgentCardopt-out).NexoIngressTransportsgainsmcp/a2alabels (+contracts test);TransportLayeringTestsgains A2A mirrors; LICENSING OPEN rows; sln entries; docs Phase-3 section.Testing
src/Nexo.Transport.A2A.Tests— 36/36 (scheme parsing, invocation mapping matrix incl. barrier metadata, options validation, DI no-op when disabled)src/Nexo.Transport.A2A.Server.Tests— 13/13 (net9.0 + TestHost 9.0VersionOverride, same pattern/reason asNexo.Tests.Infrastructure), including a full-wire round trip:A2AAgentTransport→ JSON-RPC over TestServer → mapped endpoints → handler → fake in-process transport, with correlation propagation assertedsrc/Nexo.Tests.Transport— 81/81 (6 new scheme-dispatch/composition tests + 3 layering mirrors; no regressions)src/Nexo.Tests.Contracts— 13/13 on both TFMsTesting strategy (blast radius)
Tier-2 adapters + one composition change inside
Nexo.Runtime''sAddNexoRuntimeTransport(covered by newNexo.Tests.Transporttests, incl. a no-registrations regression guard). NoNexo.Hosting, no gate-path files.— n/a (no Core.Domain/Core.Application/Infrastructure changes)make kernel-coverage-gate— n/amake kernel-gate— n/a (ProdStyle endpoint coverage lands with the Nexo.API wiring + PR-5 per the layer-boundary split)make test-prod-styleChecklist
TODOorNotImplementedExceptionleft unresolvedRelease (only when this PR ships a versioned NuGet/GHCR release)
🤖 Generated with Claude Code