Skip to content

feat(mcp): MCP server bridge over ITool + stdio host - #268

Merged
IanFrelinger merged 1 commit into
masterfrom
feat/mcp-server-bridge
Aug 13, 2026
Merged

feat(mcp): MCP server bridge over ITool + stdio host#268
IanFrelinger merged 1 commit into
masterfrom
feat/mcp-server-bridge

Conversation

@IanFrelinger

Copy link
Copy Markdown
Owner

Summary

PR-1 of the MCP/A2A integration series (stacked on #263retarget to master after #263 merges). Nexo becomes an MCP server: DI-registered ITools are exposed to AI clients (Claude, IDEs, agents) over the official ModelContextProtocol 2.2.0 SDK (spec 2026-07-28), with a standalone stdio host for local clients. Design per docs/architecture/ProtocolIntegration-MCP-A2A.md (added here).

Changes

  • src/Nexo.Mcp.Server — the bridge:
    • Catalog = DI-registered ITools ∩ explicit ExposedToolIds allowlist (deny-by-default; empty exposes nothing). Hand-authored ToolSchema.InputJsonSchema passes through verbatim via dynamic list/call handlers — no reflection-derived schemas.
    • Central NexoMcpToolBridge: sanitized-name catalog (repo.fs.readrepo_fs_read, collisions refuse to boot), operator argument overrides (pin repo.fs.*root against remote re-rooting), policy gate re-applying IPolicy approval against canonical ids (MCP traffic bypasses AgentHost, the only existing enforcement point), concurrency ceiling, audit logging.
    • Fail-closed: Enabled=false default, ValidateOnStart, enable refused under NEXO_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 + .AspNetCore 2.2.0 pins (kernel-spine exclusion comment).
  • LICENSING.md Tier-1 OPEN rows; Nexo.sln entries; docs page + DocsIndex.md / docs/architecture/README.md rows.

Kernel spine untouched: no changes under Nexo.Core.*/Nexo.Infrastructure/Nexo.Hosting — hosts compose via AddNexoMcpServer() (gRPC server-host precedent, keeps the SDK out of the AddNexo pack graph).

Testing

  • dotnet test src/Nexo.Mcp.Server.Tests — 39/39 passing locally (net8 testhost via DOTNET_ROLL_FORWARD=Major)
  • Nexo.Mcp.Server + Nexo.Mcp.Server.Host build clean with warnings-as-errors
  • Full protocol round-trip tests (SDK client ↔ this server) arrive with the MCP client PR; HTTP ProdStyle endpoint tests land with the Nexo.API wiring PR per the layer-boundary split

Testing strategy (blast radius)

New Tier-2 adapter projects only; no kernel-gate paths touched.

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

Checklist

  • Documentation updated (docs/architecture/ProtocolIntegration-MCP-A2A.md + index rows)
  • No TODO or NotImplementedException left unresolved
  • Breaking changes are documented (none — additive)

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

  • Not a versioned release — skip

🤖 Generated with Claude Code

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>
@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.

@IanFrelinger
IanFrelinger merged commit 235ae6a into masterAug 13, 2026
14 checks passed
@IanFrelinger
IanFrelinger deleted the feat/mcp-server-bridge branch August 13, 2026 20:08
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