Add structured output to the Go weather server and client#166
Draft
olaservo wants to merge 1 commit into
Draft
Conversation
Both tools declare an OutputSchema and return StructuredContent alongside the text. get_alerts returns []Alert, so it answers with a top-level JSON array rather than an array nested in an object, which protocol revision 2026-07-28 is the first to allow. "No alerts" is simply []. get_forecast returns an object, for contrast. The declared schema narrows the inferred ["null","array"] root to "array": jsonschema-go infers the nullable form because a nil slice is valid Go, but the handler always builds a slice. Error paths return an error: a tool declaring an OutputSchema MUST return conforming structured content, so a path with no data has to fail. The client compiles every declared OutputSchema at connect time and validates results against it, using jsonschema-go - already an SDK dependency, so no new one. Each channel goes to its stated reader: Content is forwarded to the model, StructuredContent is used as data, reporting how many items came back. The client no longer treats a missing .env as fatal and checks for ANTHROPIC_API_KEY after connecting rather than before, matching the Python and TypeScript clients, so the connection can be exercised without credentials. Requires go-sdk v1.7.0-pre.3: non-object output schema support (SEP-2106) landed after v1.6.1 and is in no stable release. Model identifier moves to claude-sonnet-5; the second call in the tool loop used a hardcoded ModelClaude3_7SonnetLatest while the first used the package variable, so both now use the same one. Note that the SDK sends an array-rooted schema as written on every connection rather than projecting it down, so an older client rejects the tool list. Co-Authored-By: Claude Opus 5 <[email protected]>
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.
Brings the Go examples onto protocol revision
2026-07-28and gives both tools a declaredOutputSchemawith matchingStructuredContent.get_alertsreturns[]Alert, so it answers with a top-level JSON array:[ { "event": "Flood Warning", "area": "La Salle County", ... }, { "event": "Heat Advisory", "area": "Wheeler County", ... } ]Through
2025-11-25anOutputSchemahad to be object-rooted, so a tool returning a list had to invent a key to hang it off.get_forecastreturns an object, for contrast.The declared schema narrows the inferred
["null","array"]root to"array":jsonschema-goinfers the nullable form because a nil slice is valid Go, but the handler always builds a slice.Other changes
Error paths return an error. A tool declaring an
OutputSchemaMUST return conforming structured content, so a path with no data has to fail rather than answer with a bare text result.The client validates. It compiles every declared
OutputSchemaat connect time and checks results against it — the spec's client-side SHOULD.jsonschema-gois already an SDK dependency, so this adds none.Each channel goes to its stated reader.
Contentis forwarded to the model;StructuredContentis used as data, reporting how many items came back.A missing
.envis no longer fatal, andANTHROPIC_API_KEYis checked after connecting rather than before, matching the Python and TypeScript clients. That is what lets the connection be exercised without credentials.Model identifier moves to
claude-sonnet-5. The second call in the tool loop used a hardcodedModelClaude3_7SonnetLatestwhile the first used the package variable; both now use the same one.Requires
go-sdk v1.7.0-pre.3— non-object output schema support (SEP-2106) landed afterv1.6.1and is in no stable release.One caveat
The SDK sends an array-rooted schema as written on every connection rather than projecting it down the way the TypeScript SDK does, so a
2025-11-25client rejects the tool list:Use an object root if you need to serve both eras. The README says so.
Verification
Captured off the raw wire — a real
get_alerts("TX")call against live NWS data, no SDK on the client side:Two blocks because the SDK appends the serialised JSON as a backwards-compatibility fallback alongside the tool's own text.
Related
One of a set bringing the examples onto
2026-07-28, one PR per language so the four can be compared: #164 (Python), #165 (TypeScript), #166 (Go), #167 (Rust). #163 is the shared prerequisite. CI here is green, but only becausemain's smoke test does not cover the Go examples at all — nothing in this diff is exercised by it. That coverage lands once #163 is in, since it depends on helpers introduced there. Until then this PR is verified by the raw-wire capture above, not by CI.The Ruby examples are deliberately not in the set: the
mcpgem caps at protocol2025-11-25.🤖 Generated with Claude Code