Skip to content

Return get_alerts as {"alerts": [...]} so 2025-11-25 clients can use it - #296

Merged
olaservo merged 1 commit into
mainfrom
fix/272-alerts-object-schema
Nov 14, 2026
Merged

olaservo merged 1 commit into
mainfrom
fix/272-alerts-object-schema

Conversation

@a-akimov

Copy link
Copy Markdown
Contributor

Motivation and Context

Closes #272, and also closes the Python half of #191.

All five servers declared get_alerts' output schema with a top-level array root and sent it on every session. 2025-11-25 and earlier require an object root, and 2025-11-25 is what most clients negotiate today. Python failed tools/list outright (-32603 "Handler returned an invalid result", so no tools at all). Go, Ruby and Rust sent the array, which strict clients reject and Inspector drops. Only TypeScript worked, because its SDK wraps the array as {"result": [...]}.

No SDK release converts the schema for older sessions yet, so until they do, the servers wrap the list themselves:

  • get_alerts now returns {"alerts": [...]} with an object-rooted schema in all five servers, and an empty list when there are no alerts
    • Python: Alerts is a plain BaseModel, no longer a RootModel
    • Go: dropped the hand-written schema override and the SDK infers the schema; jsonschema-go becomes an indirect dependency
    • TypeScript, Ruby, Rust: wrapped the schema and the returned value
  • Tests: each server test now first opens a raw JSON-RPC 2025-11-25 session (initialize, tools/list) without the SDK, which could quietly drop or rewrite a bad tool. It checks that the call succeeds and that every outputSchema has an object root. Then it connects through the SDK as before (it negotiates 2026-07-28 and now logs the version) and checks object roots and object structuredContent there too
  • READMEs: each server README explains what a 2025-11-25 client sees and why the list is wrapped; tests/README.md describes the new check

How Has This Been Tested?

  • Ran the updated server test against all five servers. Each passes on both a 2025-11-25 and a 2026-07-28 session. Go and Ruby ran in golang:1.25 and ruby:3.4 containers
  • Ran the new check against the unfixed Python server from main: it fails with the -32603 error from Stop breaking 2025-11-25 clients with get_alerts' array output schema #272, so it catches the regression
  • ruff, tsc (servers, clients, test helpers), cargo fmt / clippy -D warnings, gofmt / go vet and ruby -wc pass
  • Clients and the mock server are unchanged, so the client and tool-loop tests are not affected

Breaking Changes

N/a

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

Assisted with Claude Code.

Closes #272 with option A. Also closes the Python half of #191.

All five servers declared `get_alerts`' output schema with a top-level array root and sent it on every session. 2025-11-25 and earlier require an object root, and 2025-11-25 is what most clients negotiate today. Python failed `tools/list` outright (`-32603 "Handler returned an invalid result"`, so no tools at all). Go, Ruby and Rust sent the array, which strict clients reject and Inspector drops. Only TypeScript worked, because its SDK wraps the array as `{"result": [...]}`.

No SDK release converts the schema for older sessions yet, so until they do, the servers wrap the list themselves:

- `get_alerts` now returns `{"alerts": [...]}` with an object-rooted schema in all five servers, and an empty list when there are no alerts
  - Python: `Alerts` is a plain `BaseModel`, no longer a `RootModel`
  - Go: dropped the hand-written schema override and the SDK infers the schema; `jsonschema-go` becomes an indirect dependency
  - TypeScript, Ruby, Rust: wrapped the schema and the returned value
- Tests: each server test now first opens a raw JSON-RPC 2025-11-25 session (`initialize`, `tools/list`) without the SDK, which could quietly drop or rewrite a bad tool. It checks that the call succeeds and that every `outputSchema` has an `object` root. Then it connects through the SDK as before (it negotiates 2026-07-28 and now logs the version) and checks object roots and object `structuredContent` there too
- READMEs: each server README explains what a 2025-11-25 client sees and why the list is wrapped; `tests/README.md` describes the new check
Copilot AI balanced review requested due to automatic review settings November 13, 2026 07:54

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues are reported for the alert-response compatibility changes.

No open issues 🎉

What changed in this PR

Updates all five weather-server examples to return {"alerts": [...]} with an object-rooted output schema. This addresses the legacy-client compatibility issue in #272 and the Python tool-listing failure reported in #191.

Changes:

  • Wrap alert results consistently across Python, TypeScript, Go, Rust, and Ruby, preserving empty lists when no alerts exist.
  • Add raw 2025-11-25 session checks alongside SDK-based schema and structured-result checks.
  • Document protocol compatibility and simplify Go schema generation to use SDK inference.
File Description
weather-server-typescript/​src/​index.ts Wraps the alert schema and structured results in an object.
weather-server-typescript/​README.md Explains wrapping and TypeScript SDK compatibility behavior.
weather-server-rust/​src/​main.rs Adds an Alerts wrapper for schema generation and results.
weather-server-rust/​README.md Documents the wrapped result and legacy compatibility.
weather-server-ruby/​weather.rb Wraps the alert schema and structured results.
weather-server-ruby/​README.md Updates output documentation while retaining the separate protocol limitation.
weather-server-python/​weather.py Replaces the root-list model with an object containing alerts.
weather-server-python/​README.md Explains how wrapping avoids legacy tool-listing failures.
weather-server-go/​README.md Documents inferred schemas and non-null empty lists.
weather-server-go/​main.go Returns an Alerts struct and removes the schema override.
weather-server-go/​go.mod Marks jsonschema-go as an indirect dependency.
tests/​README.md Describes legacy-session checks and object-result validation.
tests/​helpers/​mcp-test-client.ts Adds raw legacy-session checks, version logging, and object-root assertions.

Review effort: Balanced

@a-akimov
a-akimov requested review from a team and a balanced review from Copilot November 14, 2026 11:50

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues block the cross-language alerts-response compatibility update.

No open issues 🎉

Review effort: Balanced

@olaservo olaservo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Read through all five servers and the test client. Wrapping the list as {"alerts": [...]} with an object root in every server is the right call while four of the five SDKs send the schema as written to 2025-11-25 clients, and the raw JSON-RPC session in the test is a good regression guard, since it sees exactly what an older client receives. The READMEs explain the reason and point at #272 for when the wrap can go. CI is green. Merging.

Two notes, neither blocking:

  • Ruby: GetAlerts.output_schema now has no explicit type: "object" while GetForecast declares one. The gem fills it in, and the 2025-11-25 check proves that, but declaring it would keep the two tools in the same file alike.
  • The clients print [get_alerts returned N items] only when structured_content is an array, so against the quickstart servers that line no longer appears. The mock server still covers the array path in the client tests, so nothing breaks, but the client READMEs and the build-client tutorial describe that output and may want a word on it.

Generated by Claude Code

@olaservo
olaservo merged commit d084a4b into main Nov 14, 2026
14 checks passed
@olaservo
olaservo deleted the fix/272-alerts-object-schema branch November 14, 2026 17:56
@a-akimov

Copy link
Copy Markdown
Contributor Author

Thank you, @olaservo !

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.

Stop breaking 2025-11-25 clients with get_alerts' array output schema

4 participants