test(ai): over-the-wire MCP integration tests + close CI gap (AI-053)#351
Merged
Conversation
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>
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 free
to 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.
AI-053 — over-the-wire MCP integration tests (Phase 8 final)
The AI-047..050 unit tests drive
McpToolCatalogwith fakeHttpMessageHandlers — 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 (McpClient→HttpClientTransport, streamable HTTP) against the realBuildHttpMapMcp("/mcp")host on a loopback port, with a recording stub backend standing in for the API. Locks in what we manually verified live athttps://textstack.app/mcp.15 tests (all genuinely over-the-wire, confirmed by QA — not hollow)
initialize(serverInfotextstack),tools/list(exactly 7).IsError+ zero upstream hits (stub records requests, test assertsTotalRequests==0); invalid args → no call; unreachable upstream → cleanIsError, not a protocol fault.McpClient(oneinitialize): list → get_chapter → save_highlight → ask, same bearer throughout.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) → zeroITool, 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 teststep (onlySearch.Tests+IntegrationTestsran).ci.ymlbackend job now runs bothtests/TextStack.Ai.Mcp.Tests(--no-build, in the sln) andtests/TextStack.UnitTests.QA hardening
Strengthened the
save_highlightPOST-body assertions (chapterId/selectedText/noteText + synthesized-anchor chapterId). Fixed a prod cosmetic:HttpContextTokenProviderno 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→ cleanPhase 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 (
/mcplanding) are packaging/polish.🤖 Generated with Claude Code