feat(mcp): MCP server bridge over ITool + stdio host - #268
Merged
Conversation
Nexo as an MCP server, built on the official ModelContextProtocol 2.2.0 SDK (spec 2026-07-28, streamable HTTP + stdio, down-level client negotiation): - src/Nexo.Mcp.Server: catalog of DI-registered ITools filtered by an explicit allowlist (deny-by-default), hand-authored JSON schemas passed through verbatim (dynamic list/call handlers instead of reflection-derived tools), central invocation gate (IPolicy approval against canonical tool ids + audit logging + concurrency ceiling), operator argument overrides to pin caller-influenced args (e.g. repo.fs.* root), fail-fast startup catalog validation, and an IMcpToolContributor port for host-side additions (bricks). - src/Nexo.Mcp.Server.Host: standalone stdio console host (Claude/IDE clients); stderr-only logging (stdout carries the protocol stream); pre-registers only read-only repo tools for allowlisting. - src/Nexo.Mcp.Server.Tests: 39 unit tests (naming, contributor, gate, bridge, DI wiring incl. air-gapped enable refusal). Fail-closed posture throughout: Enabled=false default, empty allowlists expose nothing, ValidateOnStart, and enablement is refused under the AirGapped profile. Kernel spine takes no new dependencies; hosts compose via AddNexoMcpServer() (gRPC server-host precedent). No AllowAnonymous - the endpoint mapper inherits host auth and maps nothing while disabled. Docs: docs/architecture/ProtocolIntegration-MCP-A2A.md (+ index rows); LICENSING.md Tier-1 OPEN rows for all three projects; Nexo.sln entries. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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. |
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-1 of the MCP/A2A integration series (stacked on #263 — retarget to
masterafter #263 merges). Nexo becomes an MCP server: DI-registeredITools are exposed to AI clients (Claude, IDEs, agents) over the officialModelContextProtocol2.2.0 SDK (spec 2026-07-28), with a standalone stdio host for local clients. Design perdocs/architecture/ProtocolIntegration-MCP-A2A.md(added here).Changes
src/Nexo.Mcp.Server— the bridge:ITools ∩ explicitExposedToolIdsallowlist (deny-by-default; empty exposes nothing). Hand-authoredToolSchema.InputJsonSchemapasses through verbatim via dynamic list/call handlers — no reflection-derived schemas.NexoMcpToolBridge: sanitized-name catalog (repo.fs.read→repo_fs_read, collisions refuse to boot), operator argument overrides (pinrepo.fs.*rootagainst remote re-rooting), policy gate re-applyingIPolicyapproval against canonical ids (MCP traffic bypassesAgentHost, the only existing enforcement point), concurrency ceiling, audit logging.Enabled=falsedefault,ValidateOnStart, enable refused underNEXO_DEPLOYMENT_PROFILE=airgapped, startup catalog validation fails boot on missing tools/bad schemas.MapNexoMcpEndpoint()maps nothing while disabled and deliberately does notAllowAnonymous()(divergence from the commercial GameDirector endpoint noted in-code).src/Nexo.Mcp.Server.Host— stdio console host (claude mcp add nexo -- dotnet run --project src/Nexo.Mcp.Server.Host); stderr-only logging; pre-registers read-only repo tools only.src/Nexo.Mcp.Server.Tests— 39 tests (naming, contributor, gate, bridge, DI/options incl. air-gapped refusal).Directory.Packages.props:ModelContextProtocol+.AspNetCore2.2.0 pins (kernel-spine exclusion comment).LICENSING.mdTier-1 OPEN rows;Nexo.slnentries; docs page +DocsIndex.md/docs/architecture/README.mdrows.Kernel spine untouched: no changes under
Nexo.Core.*/Nexo.Infrastructure/Nexo.Hosting— hosts compose viaAddNexoMcpServer()(gRPC server-host precedent, keeps the SDK out of theAddNexopack graph).Testing
dotnet test src/Nexo.Mcp.Server.Tests— 39/39 passing locally (net8 testhost viaDOTNET_ROLL_FORWARD=Major)Nexo.Mcp.Server+Nexo.Mcp.Server.Hostbuild clean with warnings-as-errorsTesting strategy (blast radius)
New Tier-2 adapter projects only; no kernel-gate paths touched.
— n/a (nomake kernel-coverage-gatesrc/Nexo.Core.*/Infrastructurechanges)— n/amake kernel-gate— n/a (no production DI / API / routing changes)make test-prod-styleChecklist
docs/architecture/ProtocolIntegration-MCP-A2A.md+ index rows)TODOorNotImplementedExceptionleft unresolvedRelease (only when this PR ships a versioned NuGet/GHCR release)
🤖 Generated with Claude Code