Add structured output to the Rust weather server and client#167
Draft
olaservo wants to merge 1 commit into
Draft
Add structured output to the Rust weather server and client#167olaservo wants to merge 1 commit into
olaservo wants to merge 1 commit into
Conversation
Both tools declare an output_schema and return structured_content alongside the text. get_alerts declares Vec<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. Error paths return a tool-level error: a tool declaring an output_schema 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. rmcp does not do this; its docs point at the jsonschema crate, which is the one new dependency here. Each channel goes to its stated reader: content is forwarded to the model, structured_content is used as data, reporting how many items came back. A missing .env is no longer fatal, and the API key is checked after connecting rather than before. This supersedes modelcontextprotocol#143, which bumped rmcp 0.3 -> 1.4 and failed CI because the 0.3 #[tool] macro API does not survive the jump. The rewrite was required either way, so the bump is folded in and taken to 3.0.0-beta.2, the first version with the 2026-07-28 model. list_tools is hand-written. #[tool_handler] generates one hardcoding ttl_ms: None, cache_scope: None, but both are required on a paginated result at 2026-07-28 (SEP-2549) and a strict client rejects the response outright. get_info does not pin ProtocolVersion::V_2026_07_28 either: rmcp's server never implements server/discover, so pinning would overstate support. Model identifier moves to claude-sonnet-5, replacing claude-sonnet-4-20250514, which is past end of life. Note that rmcp 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 <noreply@anthropic.com>
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 Rust examples onto protocol revision
2026-07-28and gives both tools a declaredoutput_schemawith matchingstructured_content.get_alertsdeclaresVec<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-25anoutput_schemahad 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.This supersedes #143
That PR bumped
rmcp0.3→1.4and failed CI because the0.3#[tool]macro API does not survive the jump. The rewrite was required either way, so the bump is folded in and taken to3.0.0-beta.2, the first version with the2026-07-28model.Two rmcp details worth knowing
list_toolsis hand-written.#[tool_handler]generates one hardcodingttl_ms: None, cache_scope: None, but both are required on a paginated result at2026-07-28(SEP-2549), and a strict client rejects the response outright. The macro skips generation when the impl defines the method.get_infodoes not pinProtocolVersion::V_2026_07_28. rmcp's server never implementsserver/discover— the string appears only in its client — so pinning would overstate support.Other changes
Error paths return a tool-level error. A tool declaring an
output_schemaMUST 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. rmcp does not do this; its docs point at thejsonschemacrate, which is the one new dependency here.Each channel goes to its stated reader.
contentis forwarded to the model;structured_contentis used as data, reporting how many items came back.A missing
.envis no longer fatal, and the API key is checked after connecting rather than before, matching the Python and TypeScript clients.Model identifier moves to
claude-sonnet-5, replacingclaude-sonnet-4-20250514, which is past end of life.One caveat
rmcp 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: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 — the smoke test onmainuses an MCP SDK v1 helper that negotiates2025-11-25and rejects this server's array-rooted schema (Invalid input: expected "object"), so CI here stays red until that merges. The other four tests pass. Smoke-test coverage for the Rust client follows once #163 is in, since it depends on helpers introduced there.The Ruby examples are deliberately not in the set: the
mcpgem caps at protocol2025-11-25.🤖 Generated with Claude Code