Skip to content

test(ai): over-the-wire MCP integration tests + close CI gap (AI-053)#351

Merged
mrviduus merged 1 commit into
mainfrom
ai-053-mcp-integration
Jun 17, 2026
Merged

test(ai): over-the-wire MCP integration tests + close CI gap (AI-053)#351
mrviduus merged 1 commit into
mainfrom
ai-053-mcp-integration

Conversation

@mrviduus

Copy link
Copy Markdown
Owner

AI-053 — over-the-wire MCP integration tests (Phase 8 final)

The AI-047..050 unit tests drive McpToolCatalog with fake HttpMessageHandlers — they never exercise the real MCP wire protocol, BuildHttp, or the SDK framing. This adds a hermetic integration suite that drives the real MCP SDK client (McpClientHttpClientTransport, streamable HTTP) against the real BuildHttp MapMcp("/mcp") host on a loopback port, with a recording stub backend standing in for the API. Locks in what we manually verified live at https://textstack.app/mcp.

15 tests (all genuinely over-the-wire, confirmed by QA — not hollow)

  • 7 per-tool — each asserts the mapped MCP result content AND the exact upstream request the bridge issued (method / path / Bearer / body).
  • ask_book spoiler-gate variant → clean "haven't read far enough" text (not error).
  • Protocolinitialize (serverInfo textstack), tools/list (exactly 7).
  • Negatives — no-bearer → auth-required IsError + zero upstream hits (stub records requests, test asserts TotalRequests==0); invalid args → no call; unreachable upstream → clean IsError, not a protocol fault.
  • One-session e2e (the DoD scenario) — a single McpClient (one initialize): list → get_chapter → save_highlight → ask, same bearer throughout.
  • stdio smoke — spawns the shipped TextStack.Ai.Mcp.dll; skips cleanly if not built.

Hermetic: loopback only, no Docker, no live API, no network. The test project references only the MCP bridge (no Application/Tools) → zero ITool, StudyBuddy set-equality safe by construction.

Closes a real CI gap

The AI-047..050 MCP unit tests were built but never run by an explicit dotnet test step (only Search.Tests + IntegrationTests ran). ci.yml backend job now runs both tests/TextStack.Ai.Mcp.Tests (--no-build, in the sln) and tests/TextStack.UnitTests.

QA hardening

Strengthened the save_highlight POST-body assertions (chapterId/selectedText/noteText + synthesized-anchor chapterId). Fixed a prod cosmetic: HttpContextTokenProvider no longer double-prefixes "authentication required — " (the catalog wrapper already adds it).

Verify

  • dotnet test tests/TextStack.Ai.Mcp.Tests → 15 pass (hermetic)
  • dotnet test tests/TextStack.UnitTests → 629 pass (202 MCP, StudyBuddy set-equality intact)
  • dotnet build / dotnet format --verify-no-changes → clean

Phase 8 (MCP server) complete: 7 tools · stdio + remote HTTP transports · device-flow auth · live at textstack.app/mcp · full test coverage. Remaining: AI-051 (npm wrapper) + AI-052 (/mcp landing) are packaging/polish.

🤖 Generated with Claude Code

New hermetic project tests/TextStack.Ai.Mcp.Tests: the real MCP SDK client
(McpClient → HttpClientTransport, streamable HTTP) drives the real
BuildHttp MapMcp("/mcp") host on a loopback port — exercising the actual
JSON-RPC wire framing + the scoped per-request HttpContextTokenProvider
that the unit tests (fake HttpMessageHandler) skip. A recording StubBackend
stands in for the API so each test asserts both the mapped MCP result AND
the exact upstream request (method/path/Bearer/body) the bridge issued.

15 tests: 7 per-tool + ask_book spoiler-gate + initialize + tools/list(==7)
+ negatives (no-bearer → auth-required IsError + ZERO upstream hits;
invalid args → no call; unreachable upstream → clean IsError not protocol
fault) + the one-session e2e (single client: list → get_chapter →
save_highlight → ask, same bearer) + a stdio subprocess smoke (spawns the
shipped DLL; skips if absent). Hermetic — loopback only, no Docker/API/net.

Closes a real CI gap: the AI-047..050 MCP UNIT tests were built but NEVER
run by an explicit dotnet test step. ci.yml backend job now runs both
tests/TextStack.Ai.Mcp.Tests and tests/TextStack.UnitTests.

QA: hardened the save_highlight body assertions; fixed a prod cosmetic —
HttpContextTokenProvider no longer double-prefixes "authentication
required — " (the catalog wrapper already adds it).

15 integration + 202 MCP unit (629 UnitTests) green; StudyBuddy
set-equality intact (the test assembly references only the MCP bridge, no
ITool). Completes Phase 8.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mrviduus mrviduus merged commit 625d30a into main Jun 17, 2026
5 checks passed
@mrviduus mrviduus deleted the ai-053-mcp-integration branch June 17, 2026 18:56
Sign up for free to 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.

1 participant