Validate the src and sizes of an icon against the specification - #563
Merged
Merged
Conversation
## Motivation and Context
`MCP::Icon` validated `theme` but accepted anything for `src` and `sizes`: `src:` defaulted to `nil`,
so `MCP::Icon.new.to_h` was `{}`, an icon with no source, and a `sizes` given as a String reached `to_h` unchanged
and serialized as a JSON string where the specification's `Icon` type requires an array of strings.
Nothing on the server side reported either; the server answered every request with 200 and the failure surfaced
in a client, with no reference to the field responsible. The TypeScript SDK types `sizes` as `string[]`
and `src` as required, and the Python SDK's model refuses such an icon at construction, so this SDK was
the one that let it through.
`src` is now a required keyword and must be a non-empty String, `sizes` must be `nil` or an Array of Strings,
and `mime_type` must be `nil` or a String, each refused with `ArgumentError` at construction the way `theme` already was.
The checks stop at the schema's types, as the reference SDKs do: the scheme of a URL and the `WxH` form of a size stay
the caller's to get right. A message names the class of the rejected value, never the value,
since `src` may carry a `data:` URI of any length. Coercing a String into a one-element Array was considered and rejected:
it would hide the caller's mistake that the class exists to surface. The `theme` check let `false` through its truthiness test
and serialized it; it now refuses everything but `nil`, `"light"`, and `"dark"`.
Fixes modelcontextprotocol#562.
## How Has This Been Tested?
New tests in `test/mcp/icon_test.rb`. Against the previous library, an icon without `src` and an icon whose `sizes` is
a String are both constructed and serialized.
## Breaking Changes
`MCP::Icon.new` now raises `ArgumentError` where earlier releases produced an icon the specification's schema rejects:
`src:` is required and must be a non-empty String, so a call without it, or with `nil`, an empty String, or a non-String,
fails; `sizes:` must be `nil` or an Array of Strings, so a String, or an Array holding `nil` or a non-String, fails;
`mime_type:` must be `nil` or a String; `theme:` must be `nil`, `"light"`, or `"dark"`, so `false` fails where it used
to be serialized. Leaving the optional keywords out, or passing `nil` for them, is unchanged.
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.
Motivation and Context
MCP::Iconvalidatedthemebut accepted anything forsrcandsizes:src:defaulted tonil, soMCP::Icon.new.to_hwas{}, an icon with no source, and asizesgiven as a String reachedto_hunchanged and serialized as a JSON string where the specification'sIcontype requires an array of strings. Nothing on the server side reported either; the server answered every request with 200 and the failure surfaced in a client, with no reference to the field responsible. The TypeScript SDK typessizesasstring[]andsrcas required, and the Python SDK's model refuses such an icon at construction, so this SDK was the one that let it through.srcis now a required keyword and must be a non-empty String,sizesmust benilor an Array of Strings, andmime_typemust benilor a String, each refused withArgumentErrorat construction the waythemealready was. The checks stop at the schema's types, as the reference SDKs do: the scheme of a URL and theWxHform of a size stay the caller's to get right. A message names the class of the rejected value, never the value, sincesrcmay carry adata:URI of any length. Coercing a String into a one-element Array was considered and rejected: it would hide the caller's mistake that the class exists to surface. Thethemecheck letfalsethrough its truthiness test and serialized it; it now refuses everything butnil,"light", and"dark".Fixes #562.
How Has This Been Tested?
New tests in
test/mcp/icon_test.rb. Against the previous library, an icon withoutsrcand an icon whosesizesis a String are both constructed and serialized.Breaking Changes
MCP::Icon.newnow raisesArgumentErrorwhere earlier releases produced an icon the specification's schema rejects:src:is required and must be a non-empty String, so a call without it, or withnil, an empty String, or a non-String, fails;sizes:must benilor an Array of Strings, so a String, or an Array holdingnilor a non-String, fails;mime_type:must benilor a String;theme:must benil,"light", or"dark", sofalsefails where it used to be serialized. Leaving the optional keywords out, or passingnilfor them, is unchanged.Types of changes
Checklist