Assert on structured output in the smoke tests#163
Draft
olaservo wants to merge 1 commit into
Draft
Conversation
olaservo
marked this pull request as draft
July 26, 2026 02:14
olaservo
force-pushed
the
structured-output-2026-07-28/tests
branch
2 times, most recently
from
July 26, 2026 04:18
00cf861 to
10903f6
Compare
The smoke tests connected to each server, listed its tools and stopped there, so they could not catch a broken structured result. mcp-test-client now calls every tool that declares an outputSchema and checks the answer against it: the result must carry structuredContent, and a tool with an array-rooted schema must return a top-level JSON array rather than an object wrapping one. Tools with no output schema are left alone, so this is not a new requirement on any example. The client negotiates with mode "auto", so it exercises servers of either protocol era. Tool calls reach the live NWS API; an error result is reported as a skip rather than a failure. mock-mcp-server moves to the low-level Server and advertises one array-rooted and one object-rooted tool, with the schemas written out literally. A client that compiles every declared outputSchema at connect time fails against the array-rooted one if it assumes output schemas are always objects. utils.sh no longer swallows build output. A failed build left no binary behind and the test reported a downstream spawn ENOENT instead of the compiler error, which is what makes a broken build hard to diagnose from CI logs; modelcontextprotocol#143 is the current example. check_dependency returns instead of exiting, so a missing toolchain fails its own test and the suite still prints its summary. Binaries resolve through a helper that accounts for the .exe suffix. The test helpers move to the 2.0 MCP SDK packages, where the 2026-07-28 support lives; the examples themselves are untouched. Those require Node 20 or newer, so CI moves off Node 18 to Node 24, the Active LTS - Node 20 reached end of life in April 2026. The Go examples and the Rust client stay uncovered here. Both clients abort when no .env file is present, so that coverage lands with those examples. Co-Authored-By: Claude Opus 5 <[email protected]>
olaservo
force-pushed
the
structured-output-2026-07-28/tests
branch
from
July 26, 2026 04:24
10903f6 to
f350c0f
Compare
This was referenced Jul 26, 2026
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.
What the test client now does
After listing tools it calls every tool that declares an
outputSchemaand checks the answer against it:structuredContent, andProtocol revision
2026-07-28is what makes the array case possible: through2025-11-25anoutputSchemahad to be object-rooted. The client negotiates withmode: "auto"— oneserver/discoverprobe, falling back to theinitializehandshake — so it keeps working against every example as it stands today while also being able to test a server that speaks the new revision.Tool calls reach the live NWS API. An unreachable upstream comes back as an error result, which the test reports as a skip rather than a failure; someone else's outage should not fail the build.
Mock server
mock-mcp-servermoves to the low-levelServerand advertises two tools, one array-rooted and one object-rooted, with the schemas written out literally — what goes on the wire is exactly what is in the file.Build output is no longer swallowed
ensure_builtran every build with>/dev/null 2>&1unconditionally. A compile failure therefore left no binary behind and the test reported a downstreamspawn ... ENOENTinstead of the actual error, which is what makes a broken build hard to diagnose from CI logs alone — #143 is the current example.run_buildnow prints the compiler output when a build fails.Two smaller fixes alongside it:
check_dependencyreturns instead of callingexit 1, so a missing toolchain fails its own test and the suite still finishes and prints its summary..exesuffix, so the suite is runnable on Windows as well as in CI.CI
The test helpers move to the 2.0 MCP SDK packages, which is where the
2026-07-28support lives. The examples themselves are untouched.Those packages require Node 20 or newer, so CI moves off Node 18. It goes to Node 24, the Active LTS, rather than to the floor — Node 20 reached end of life in April 2026.
Still uncovered
The Go examples and the Rust client remain untested here. Each needs a change inside its own directory first — both clients abort when no
.envfile is present, so neither can be driven without credentials — so that coverage belongs with those changes rather than in this PR.Verification
CI on this PR is green. Locally, run against
mainwith these changes applied, all five covered examples pass:The Python server already exercises the new assertion: its tools return
-> str, from which the SDK derives an object-rooted{"result": ...}schema, and the test confirms the structured content matches it. The TypeScript and Rust servers declare no output schemas today, so the assertion correctly no-ops rather than failing them.Related
First of a set bringing the examples onto
2026-07-28. This one is the prerequisite: it is what lets the smoke tests exercise a server that declares a non-object output schema. The rest of the set is #164 (Python), #165 (TypeScript), #166 (Go), #167 (Rust), with #163 as the shared prerequisite. The Ruby examples are deliberately not in the set: themcpgem caps at protocol2025-11-25.🤖 Generated with Claude Code