Skip to content

feat(mcp): client tool adapters over external MCP servers - #265

Merged
IanFrelinger merged 1 commit into
masterfrom
feat/mcp-client-tools
Aug 13, 2026
Merged

feat(mcp): client tool adapters over external MCP servers#265
IanFrelinger merged 1 commit into
masterfrom
feat/mcp-client-tools

Conversation

@IanFrelinger

Copy link
Copy Markdown
Owner

Summary

PR-2 of the MCP/A2A series (stacked on #264#263; retarget to master as parents merge). Nexo becomes an MCP client: external streamable-HTTP MCP servers contribute their tools to Nexo agent toolboxes as namespaced ITool proxies, with pinned definitions and fail-closed drift handling. Design: docs/architecture/ProtocolIntegration-MCP-A2A.md (Phase 2 section added).

Changes

  • src/Nexo.Mcp.ClientMcpClientConnectionManager (hosted service + IToolSource):
    • Connect + pin at startup: each configured server is dialed once; tool name/description/raw schema are captured verbatim and become the contract for the process lifetime (optional per-server AllowedTools narrowing).
    • Namespaced idsmcp:{server}:{tool} — a remote server can never shadow repo.fs.write (CapabilityRegistry registration is last-wins by id).
    • Drift faults, never follows: periodic re-list compares against pins; changed/vanished definitions withdraw the tool until restart. Unreachable servers contribute zero tools without failing host boot.
    • Remote isError/transport failures → McpToolFailure error payloads (repo tool convention, model-visible); API keys are env-var-named with presence verified at startup; stdio child processes deliberately out of v1 (command-allowlist design needed first).
  • Nexo.Abstractions.IToolSource — one SDK-free interface for post-startup-discovered tools; RepoFsToolboxFactory gains an extraTools fold-in and SelfExtendRunnerAdapter snapshots DI-registered sources each cycle (optional ctor param, no existing call sites broken).
  • src/Nexo.Mcp.Client.Tests — 29 tests, headlined by full protocol round trips: a real McpClient against the real PR-1 server bridge over in-memory pipes (sanitized-name listing, call with structured content, unknown-tool protocol error, manager pin→proxy→invoke end-to-end). Plus 4 fold-in tests in Nexo.Tests.BackgroundAgents.
  • Directory.Packages.props: Microsoft.Extensions.Options.ConfigurationExtensions 10.0.11 pin.
  • LICENSING.md OPEN rows, Nexo.sln entries, docs Phase-2 section.

Testing

  • dotnet test src/Nexo.Mcp.Client.Tests — 29/29 locally (roll-forward runtime)
  • dotnet test src/Nexo.Tests.BackgroundAgents --filter RepoFsToolboxFactoryExtraToolsTests — 4/4 on net8.0 + net9.0
  • All touched projects build clean with warnings-as-errors

Testing strategy (blast radius)

Tier-2 adapter + one additive optional-param seam in BackgroundAgents.HostRunners (outside kernel-gate paths); Nexo.Abstractions gains one interface (no behavior).

  • make kernel-coverage-gate — n/a (no src/Nexo.Core.*/Infrastructure changes)
  • make kernel-gate — n/a
  • make test-prod-style — n/a

Checklist

  • Documentation updated
  • No TODO or NotImplementedException left unresolved
  • Breaking changes are documented (none — additive; existing RepoFsToolboxFactory call sites unchanged)

Release (only when this PR ships a versioned NuGet/GHCR release)

  • Not a versioned release — skip

🤖 Generated with Claude Code

@cursor

cursorBot commented Aug 13, 2026

Copy link
Copy Markdown
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.

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>
@IanFrelinger
IanFrelingerforce-pushed the feat/mcp-server-bridge branch from 6e8afe9 to 9e941bbCompareAugust 13, 2026 18:17
Base automatically changed from feat/mcp-server-bridge to masterAugust 13, 2026 20:08
@IanFrelinger
IanFrelinger changed the base branch from feat/mcp-server-bridge to masterAugust 13, 2026 20:08
@IanFrelinger
IanFrelinger merged commit d749db1 into masterAug 13, 2026
10 of 11 checks passed
@IanFrelinger
IanFrelinger deleted the feat/mcp-client-tools branch August 13, 2026 20:10
Sign up for freeto 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.

2 participants

@IanFrelinger@PlzTouchGrass