Add structured output to the TypeScript weather server and client and update to v2#165
Draft
olaservo wants to merge 1 commit into
Draft
Conversation
Both tools declare an outputSchema and return structuredContent alongside the
text.
get-alerts declares z.array(...), 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.
This costs older clients nothing. The server declares the array schema once
and never branches on protocol version: serveStdio serves both eras from one
factory, and the SDK projects the schema down to
{"type":"object","properties":{"result":...}} for a 2025-11-25 client, wrapping
the structured content to match. Verified against both eras.
Error paths throw: a tool declaring an outputSchema MUST return conforming
structured content, so a path with no data has to fail.
The client passes versionNegotiation {mode:"auto"}; the SDK default is
"legacy". The SDK validates every result against the declared schema, so the
client-side SHOULD needs no code. Each channel goes to its stated reader:
content is forwarded to the model, structuredContent is used as data,
reporting how many items came back.
Moves to the 2.0 beta packages, where the 2026-07-28 support lives:
@modelcontextprotocol/sdk is replaced by @modelcontextprotocol/server and
@modelcontextprotocol/client. Model identifier moves to claude-sonnet-5.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This was referenced Jul 26, 2026
There was a problem hiding this comment.
Pull request overview
Updates the TypeScript weather server/client examples to MCP SDK v2 (split client/server packages) and adds declared tool outputSchema with matching structuredContent, including an array-rooted schema for get-alerts to align with protocol revision 2026-07-28.
Changes:
- Migrate server to
@modelcontextprotocol/serverand useserveStdio(buildServer)with per-tooloutputSchema+structuredContentforget-alerts(array) andget-forecast(object). - Migrate client to
@modelcontextprotocol/client, enable automatic protocol version negotiation, and surface basic structured-output handling. - Update READMEs and dependency manifests/lockfiles for the new package split and Zod v4 usage.
Reviewed changes
Copilot reviewed 6 out of 8 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| weather-server-typescript/src/index.ts | Switches to v2 server APIs, adds output schemas + structured results, and refactors server startup via serveStdio. |
| weather-server-typescript/README.md | Documents structured output behavior and backward-compat projection. |
| weather-server-typescript/package.json | Replaces @modelcontextprotocol/sdk with @modelcontextprotocol/server and adds zod. |
| weather-server-typescript/package-lock.json | Locks updated dependency graph for server v2 + Zod v4. |
| mcp-client-typescript/index.ts | Switches to v2 client APIs, enables versionNegotiation: auto, and distinguishes content vs structuredContent. |
| mcp-client-typescript/README.md | Documents structured output handling and version negotiation. |
| mcp-client-typescript/package.json | Replaces @modelcontextprotocol/sdk with @modelcontextprotocol/client. |
| mcp-client-typescript/package-lock.json | Locks updated dependency graph for client v2. |
Files not reviewed (2)
- mcp-client-typescript/package-lock.json: Generated file
- weather-server-typescript/package-lock.json: Generated file
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+1
to
+3
| import { McpServer } from "@modelcontextprotocol/server"; | ||
| import { serveStdio } from "@modelcontextprotocol/server/stdio"; | ||
| import * as z from "zod/v4"; |
|
|
||
| The SDK validates every result against the tool's declared `outputSchema`, so the spec's client-side SHOULD needs no code here. | ||
|
|
||
| The two channels go to different readers: `content` is forwarded to the model, while `structuredContent` is used as data — the client counts the items it returns. See [Structured Content](https://modelcontextprotocol.io/specification/draft/server/tools#structured-content). |
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 TypeScript examples onto MCP SDK 2.0 and protocol revision
2026-07-28, and gives both tools a declaredoutputSchemawith matchingstructuredContent.get-alertsanswers 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.This costs older clients nothing
The server declares the array schema once and never branches on protocol version.
serveStdioserves both eras from one factory, and the SDK projects the schema for whichever era connects.A
2026-07-28client sees the schema as written. A2025-11-25client sees{"type":"object","properties":{"result":{...}}}and getsstructuredContentas{"result":[...]}. Verified against both.Other changes
Error paths throw. 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 negotiates.
versionNegotiation: { mode: 'auto' }probesserver/discoverand falls back to the2025-11-25handshake; the SDK's default is'legacy'.Each channel goes to its stated reader.
contentis forwarded to the model;structuredContentis used as data, reporting how many items came back. The SDK validates it against the declared schema, so the client-side SHOULD needs no code.Package split.
@modelcontextprotocol/sdkbecomes@modelcontextprotocol/serverand@modelcontextprotocol/client, which is where the2026-07-28support lives. Model identifier moves toclaude-sonnet-5.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. CI here is green, which is itself worth noting:main's smoke test uses an MCP SDK v1 helper that negotiates2025-11-25, and it accepts this server because the SDK projects the array-rooted schema down to the object form that revision expects. The behaviour described above, confirmed by a real v1 client. Extending that test to assert on structured output comes with #163.The Ruby examples are deliberately not in the set: the
mcpgem caps at protocol2025-11-25.🤖 Generated with Claude Code