From bb7be31d17572006006609215ed6e498a53cc80b Mon Sep 17 00:00:00 2001 From: Ben Brandt Date: Thu, 2 Jul 2026 12:23:30 +0200 Subject: [PATCH] feat(unstable-v2): Align v2 Content types with the latest MCP spec --- agent-client-protocol-schema/src/v2/agent.rs | 8 + .../src/v2/content.rs | 159 ++++++++++++++++++ .../src/v2/conversion.rs | 28 ++- docs/protocol/v2/content.mdx | 24 ++- docs/protocol/v2/draft/content.mdx | 24 ++- docs/protocol/v2/draft/schema.mdx | 79 +++++++++ docs/protocol/v2/schema.mdx | 79 +++++++++ schema/v2/schema.json | 91 +++++++++- schema/v2/schema.unstable.json | 91 +++++++++- 9 files changed, 552 insertions(+), 31 deletions(-) diff --git a/agent-client-protocol-schema/src/v2/agent.rs b/agent-client-protocol-schema/src/v2/agent.rs index eabc119d9..e3181db65 100644 --- a/agent-client-protocol-schema/src/v2/agent.rs +++ b/agent-client-protocol-schema/src/v2/agent.rs @@ -2990,6 +2990,7 @@ pub struct McpServerHttp { /// Human-readable name identifying this MCP server. pub name: String, /// URL to the MCP server. + #[schemars(url)] pub url: String, /// HTTP headers to set when making requests to the MCP server. #[serde_as(deserialize_as = "DefaultOnError>")] @@ -6007,6 +6008,13 @@ mod test_serialization { } } + #[test] + fn mcp_server_http_schema_marks_url_as_uri() { + let schema = serde_json::to_value(schemars::schema_for!(McpServerHttp)).unwrap(); + + assert_eq!(schema["properties"]["url"]["format"], "uri"); + } + #[cfg(feature = "unstable_mcp_over_acp")] #[test] fn test_client_mcp_message_method_names() { diff --git a/agent-client-protocol-schema/src/v2/content.rs b/agent-client-protocol-schema/src/v2/content.rs index d3bf2c08f..44477eb56 100644 --- a/agent-client-protocol-schema/src/v2/content.rs +++ b/agent-client-protocol-schema/src/v2/content.rs @@ -212,12 +212,14 @@ impl> From for ContentBlock { #[non_exhaustive] pub struct ImageContent { /// Base64-encoded media payload. + #[schemars(extend("format" = "byte"))] pub data: String, /// MIME type describing the encoded media payload. pub mime_type: String, /// URI associated with this resource or media payload. #[serde_as(deserialize_as = "DefaultOnError")] #[schemars(extend("x-deserialize-default-on-error" = true))] + #[schemars(url)] #[serde(default)] pub uri: Option, /// Optional annotations that help clients decide how to display or route this content. @@ -284,6 +286,7 @@ impl ImageContent { #[non_exhaustive] pub struct AudioContent { /// Base64-encoded media payload. + #[schemars(extend("format" = "byte"))] pub data: String, /// MIME type describing the encoded media payload. pub mime_type: String, @@ -411,6 +414,7 @@ pub struct TextResourceContents { /// Text payload carried by this content block. pub text: String, /// URI associated with this resource or media payload. + #[schemars(url)] pub uri: String, /// MIME type describing the encoded media payload. #[serde_as(deserialize_as = "DefaultOnError")] @@ -468,8 +472,10 @@ impl TextResourceContents { #[non_exhaustive] pub struct BlobResourceContents { /// Base64-encoded bytes for a binary resource payload. + #[schemars(extend("format" = "byte"))] pub blob: String, /// URI associated with this resource or media payload. + #[schemars(url)] pub uri: String, /// MIME type describing the encoded media payload. #[serde_as(deserialize_as = "DefaultOnError")] @@ -529,6 +535,7 @@ pub struct ResourceLink { /// Human-readable name shown for this protocol object. pub name: String, /// URI associated with this resource or media payload. + #[schemars(url)] pub uri: String, /// Optional display title for end-user UI. #[serde_as(deserialize_as = "DefaultOnError")] @@ -540,6 +547,11 @@ pub struct ResourceLink { #[schemars(extend("x-deserialize-default-on-error" = true))] #[serde(default)] pub description: Option, + /// Optional set of sized icons that the client can display in a user interface. + #[serde_as(deserialize_as = "DefaultOnError>>")] + #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))] + #[serde(default)] + pub icons: Option>, /// MIME type describing the encoded media payload. #[serde_as(deserialize_as = "DefaultOnError")] #[schemars(extend("x-deserialize-default-on-error" = true))] @@ -574,6 +586,7 @@ impl ResourceLink { Self { annotations: None, description: None, + icons: None, mime_type: None, name: name.into(), size: None, @@ -597,6 +610,13 @@ impl ResourceLink { self } + /// Sets or clears the optional `icons` field. + #[must_use] + pub fn icons(mut self, icons: impl IntoOption>) -> Self { + self.icons = icons.into_option(); + self + } + /// Sets or clears the optional `mimeType` field. #[must_use] pub fn mime_type(mut self, mime_type: impl IntoOption) -> Self { @@ -630,6 +650,85 @@ impl ResourceLink { } } +/// An optionally-sized icon that can be displayed in a user interface. +#[serde_as] +#[skip_serializing_none] +#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, JsonSchema)] +#[serde(rename_all = "camelCase")] +#[non_exhaustive] +pub struct Icon { + /// A standard URI pointing to an icon resource. + #[schemars(url)] + pub src: String, + /// Optional MIME type override if the source MIME type is missing or generic. + #[serde_as(deserialize_as = "DefaultOnError")] + #[schemars(extend("x-deserialize-default-on-error" = true))] + #[serde(default)] + pub mime_type: Option, + /// Optional sizes at which the icon can be used. + #[serde_as(deserialize_as = "DefaultOnError>>")] + #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))] + #[serde(default)] + pub sizes: Option>, + /// Optional theme this icon is designed for. + #[serde_as(deserialize_as = "DefaultOnError")] + #[schemars(extend("x-deserialize-default-on-error" = true))] + #[serde(default)] + pub theme: Option, +} + +impl Icon { + /// Builds [`Icon`] with the required source URI; optional display hints start unset. + #[must_use] + pub fn new(src: impl Into) -> Self { + Self { + src: src.into(), + mime_type: None, + sizes: None, + theme: None, + } + } + + /// Sets or clears the optional `mimeType` field. + #[must_use] + pub fn mime_type(mut self, mime_type: impl IntoOption) -> Self { + self.mime_type = mime_type.into_option(); + self + } + + /// Sets or clears the optional `sizes` field. + #[must_use] + pub fn sizes(mut self, sizes: impl IntoOption>) -> Self { + self.sizes = sizes.into_option(); + self + } + + /// Sets or clears the optional `theme` field. + #[must_use] + pub fn theme(mut self, theme: impl IntoOption) -> Self { + self.theme = theme.into_option(); + self + } +} + +/// Theme an icon is designed for. +#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, JsonSchema)] +#[serde(rename_all = "camelCase")] +#[non_exhaustive] +pub enum IconTheme { + /// Icon designed for light backgrounds. + Light, + /// Icon designed for dark backgrounds. + Dark, + /// Custom or future icon theme. + /// + /// Values beginning with `_` are reserved for implementation-specific + /// extensions. Unknown values that do not begin with `_` are reserved for + /// future ACP variants. + #[serde(untagged)] + Other(String), +} + /// Optional annotations for the client. The client can use annotations to inform how objects are used or displayed #[serde_as] #[skip_serializing_none] @@ -650,6 +749,7 @@ pub struct Annotations { /// Relative importance of this content when clients choose what to surface. #[serde_as(deserialize_as = "DefaultOnError")] #[schemars(extend("x-deserialize-default-on-error" = true))] + #[schemars(range(min = 0, max = 1))] #[serde(default)] pub priority: Option, /// The _meta property is reserved by ACP to allow clients and agents to attach additional @@ -774,6 +874,13 @@ mod tests { assert_eq!(serde_json::to_value(&role).unwrap(), "critic"); } + #[test] + fn icon_theme_preserves_unknown_variant() { + let theme: IconTheme = serde_json::from_str("\"contrast\"").unwrap(); + assert_eq!(theme, IconTheme::Other("contrast".to_string())); + assert_eq!(serde_json::to_value(&theme).unwrap(), "contrast"); + } + #[test] fn content_block_preserves_unknown_variant() { let block: ContentBlock = serde_json::from_value(serde_json::json!({ @@ -851,4 +958,56 @@ mod tests { assert!(!json.as_object().unwrap().contains_key("annotations")); assert!(!json.as_object().unwrap().contains_key("meta")); } + + #[test] + fn resource_link_icons_roundtrip() { + let icon = Icon::new("https://example.com/icon.png") + .mime_type("image/png") + .sizes(vec!["48x48".to_string(), "any".to_string()]) + .theme(IconTheme::Dark); + let link = ResourceLink::new("Example", "file:///example.txt").icons(vec![icon]); + + let json = serde_json::to_value(&link).unwrap(); + assert_eq!(json["icons"][0]["src"], "https://example.com/icon.png"); + assert_eq!(json["icons"][0]["mimeType"], "image/png"); + assert_eq!(json["icons"][0]["sizes"][0], "48x48"); + assert_eq!(json["icons"][0]["theme"], "dark"); + + let parsed: ResourceLink = serde_json::from_value(json).unwrap(); + assert_eq!(link, parsed); + } + + #[test] + fn annotations_priority_schema_matches_mcp_bounds() { + let schema = schemars::schema_for!(Annotations); + let json = serde_json::to_value(schema).unwrap(); + + assert_eq!(json["properties"]["priority"]["minimum"], 0); + assert_eq!(json["properties"]["priority"]["maximum"], 1); + } + + #[test] + fn content_schema_matches_mcp_string_formats() { + let image = serde_json::to_value(schemars::schema_for!(ImageContent)).unwrap(); + assert_eq!(image["properties"]["data"]["format"], "byte"); + assert_eq!(image["properties"]["uri"]["format"], "uri"); + + let audio = serde_json::to_value(schemars::schema_for!(AudioContent)).unwrap(); + assert_eq!(audio["properties"]["data"]["format"], "byte"); + + let text_resource = + serde_json::to_value(schemars::schema_for!(TextResourceContents)).unwrap(); + assert_eq!(text_resource["properties"]["uri"]["format"], "uri"); + + let blob_resource = + serde_json::to_value(schemars::schema_for!(BlobResourceContents)).unwrap(); + assert_eq!(blob_resource["properties"]["blob"]["format"], "byte"); + assert_eq!(blob_resource["properties"]["uri"]["format"], "uri"); + + let resource_link = serde_json::to_value(schemars::schema_for!(ResourceLink)).unwrap(); + assert_eq!(resource_link["properties"]["uri"]["format"], "uri"); + + let icon = serde_json::to_value(schemars::schema_for!(Icon)).unwrap(); + assert_eq!(icon["properties"]["src"]["format"], "uri"); + } } diff --git a/agent-client-protocol-schema/src/v2/conversion.rs b/agent-client-protocol-schema/src/v2/conversion.rs index 60bd11255..595f0bf29 100644 --- a/agent-client-protocol-schema/src/v2/conversion.rs +++ b/agent-client-protocol-schema/src/v2/conversion.rs @@ -8912,6 +8912,7 @@ impl IntoV1 for super::ResourceLink { let Self { annotations, description, + icons, mime_type, name, size, @@ -8919,6 +8920,13 @@ impl IntoV1 for super::ResourceLink { uri, meta, } = self; + + if matches!(icons.as_ref(), Some(icons) if !icons.is_empty()) { + return Err(ProtocolConversionError::new( + "v2 ResourceLink.icons cannot be represented in v1", + )); + } + Ok(crate::v1::ResourceLink { annotations: into_v1_default_on_error(annotations), description: description.into_v1()?, @@ -8949,6 +8957,7 @@ impl IntoV2 for crate::v1::ResourceLink { Ok(super::ResourceLink { annotations: into_v2_default_on_error(annotations), description: description.into_v2()?, + icons: None, mime_type: mime_type.into_v2()?, name: name.into_v2()?, size: size.into_v2()?, @@ -9208,16 +9217,16 @@ mod tests { #[test] fn round_trips_initialize_request() { - let mut client_capabilities = v1::ClientCapabilities::new(); + let client_capabilities = v1::ClientCapabilities::new(); #[cfg(feature = "unstable_boolean_config")] - { - client_capabilities = client_capabilities.session( + let client_capabilities = { + client_capabilities.session( v1::ClientSessionCapabilities::new().config_options( v1::SessionConfigOptionsCapabilities::new() .boolean(v1::BooleanConfigOptionCapabilities::new()), ), - ); - } + ) + }; let request = v1::InitializeRequest::new(ProtocolVersion::V1) .client_capabilities(client_capabilities) @@ -10450,6 +10459,15 @@ mod tests { ); } + #[test] + fn v2_resource_link_icons_do_not_convert_to_v1() { + assert_v2_to_v1_error( + v2::ResourceLink::new("file.txt", "file:///file.txt") + .icons(vec![v2::Icon::new("https://example.com/icon.png")]), + "v2 ResourceLink.icons cannot be represented in v1", + ); + } + #[test] fn unknown_v2_raw_fallbacks_do_not_convert_to_v1() { assert_v2_to_v1_error( diff --git a/docs/protocol/v2/content.mdx b/docs/protocol/v2/content.mdx index e60521b92..ac0494b67 100644 --- a/docs/protocol/v2/content.mdx +++ b/docs/protocol/v2/content.mdx @@ -13,7 +13,7 @@ Content blocks appear in: ## Content Types -The Agent Client Protocol uses the same `ContentBlock` structure as the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/specification/2025-06-18/schema#contentblock). +The Agent Client Protocol uses the same `ContentBlock` structure as the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/specification/2026-07-28/schema#contentblock). This design choice enables Agents to seamlessly forward content from MCP tool outputs without transformation. @@ -38,7 +38,7 @@ All Agents **MUST** support text content blocks when included in prompts. Optional metadata about how the content should be used or displayed. [Learn - more](https://modelcontextprotocol.io/specification/2025-06-18/server/resources#annotations). + more](https://modelcontextprotocol.io/specification/2026-07-28/schema#annotations). ### Image Content @@ -71,7 +71,7 @@ prompts. Optional metadata about how the content should be used or displayed. [Learn - more](https://modelcontextprotocol.io/specification/2025-06-18/server/resources#annotations). + more](https://modelcontextprotocol.io/specification/2026-07-28/schema#annotations). ### Audio Content @@ -100,7 +100,7 @@ prompts. Optional metadata about how the content should be used or displayed. [Learn - more](https://modelcontextprotocol.io/specification/2025-06-18/server/resources#annotations). + more](https://modelcontextprotocol.io/specification/2026-07-28/schema#annotations). ### Embedded Resource @@ -162,7 +162,7 @@ prompts. Optional metadata about how the content should be used or displayed. [Learn - more](https://modelcontextprotocol.io/specification/2025-06-18/server/resources#annotations). + more](https://modelcontextprotocol.io/specification/2026-07-28/schema#annotations). ### Resource Link @@ -175,6 +175,13 @@ References to resources that the Agent can access. "uri": "file:///home/user/document.pdf", "name": "document.pdf", "mimeType": "application/pdf", + "icons": [ + { + "src": "https://example.com/icons/pdf.png", + "mimeType": "image/png", + "sizes": ["48x48"] + } + ], "size": 1024000 } ``` @@ -199,11 +206,16 @@ References to resources that the Agent can access. Optional description of the resource contents + + Optional icons Clients can display for this resource. Each icon requires a + `src` URI and may include `mimeType`, `sizes`, and `theme`. + + Optional size of the resource in bytes Optional metadata about how the content should be used or displayed. [Learn - more](https://modelcontextprotocol.io/specification/2025-06-18/server/resources#annotations). + more](https://modelcontextprotocol.io/specification/2026-07-28/schema#annotations). diff --git a/docs/protocol/v2/draft/content.mdx b/docs/protocol/v2/draft/content.mdx index 1567f376f..bbe678b1a 100644 --- a/docs/protocol/v2/draft/content.mdx +++ b/docs/protocol/v2/draft/content.mdx @@ -13,7 +13,7 @@ Content blocks appear in: ## Content Types -The Agent Client Protocol uses the same `ContentBlock` structure as the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/specification/2025-06-18/schema#contentblock). +The Agent Client Protocol uses the same `ContentBlock` structure as the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/specification/2026-07-28/schema#contentblock). This design choice enables Agents to seamlessly forward content from MCP tool outputs without transformation. @@ -38,7 +38,7 @@ All Agents **MUST** support text content blocks when included in prompts. Optional metadata about how the content should be used or displayed. [Learn - more](https://modelcontextprotocol.io/specification/2025-06-18/server/resources#annotations). + more](https://modelcontextprotocol.io/specification/2026-07-28/schema#annotations). ### Image Content @@ -71,7 +71,7 @@ in prompts. Optional metadata about how the content should be used or displayed. [Learn - more](https://modelcontextprotocol.io/specification/2025-06-18/server/resources#annotations). + more](https://modelcontextprotocol.io/specification/2026-07-28/schema#annotations). ### Audio Content @@ -100,7 +100,7 @@ in prompts. Optional metadata about how the content should be used or displayed. [Learn - more](https://modelcontextprotocol.io/specification/2025-06-18/server/resources#annotations). + more](https://modelcontextprotocol.io/specification/2026-07-28/schema#annotations). ### Embedded Resource @@ -162,7 +162,7 @@ in prompts. Optional metadata about how the content should be used or displayed. [Learn - more](https://modelcontextprotocol.io/specification/2025-06-18/server/resources#annotations). + more](https://modelcontextprotocol.io/specification/2026-07-28/schema#annotations). ### Resource Link @@ -175,6 +175,13 @@ References to resources that the Agent can access. "uri": "file:///home/user/document.pdf", "name": "document.pdf", "mimeType": "application/pdf", + "icons": [ + { + "src": "https://example.com/icons/pdf.png", + "mimeType": "image/png", + "sizes": ["48x48"] + } + ], "size": 1024000 } ``` @@ -199,11 +206,16 @@ References to resources that the Agent can access. Optional description of the resource contents + + Optional icons Clients can display for this resource. Each icon requires a + `src` URI and may include `mimeType`, `sizes`, and `theme`. + + Optional size of the resource in bytes Optional metadata about how the content should be used or displayed. [Learn - more](https://modelcontextprotocol.io/specification/2025-06-18/server/resources#annotations). + more](https://modelcontextprotocol.io/specification/2026-07-28/schema#annotations). diff --git a/docs/protocol/v2/draft/schema.mdx b/docs/protocol/v2/draft/schema.mdx index fcc3add74..de587c0a7 100644 --- a/docs/protocol/v2/draft/schema.mdx +++ b/docs/protocol/v2/draft/schema.mdx @@ -2332,6 +2332,12 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/d Relative importance of this content when clients choose what to surface. + + | Constraint | Value | + | ---------- | ----- | + | Minimum | `0` | + | Maximum | `1` | + ## AudioContent @@ -3126,6 +3132,9 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/d Optional human-readable details shown with this protocol object. +Icon[] | null} > + Optional set of sized icons that the client can display in a user interface. + MIME type describing the encoded media payload. @@ -4146,6 +4155,73 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/d The value to set for the HTTP header. +## Icon + +An optionally-sized icon that can be displayed in a user interface. + +**Type:** Object + +**Properties:** + + + Optional MIME type override if the source MIME type is missing or generic. + + + + <> + "string" + [] + + + | null + + } +> + Optional sizes at which the icon can be used. + + + A standard URI pointing to an icon resource. + + + + IconTheme + + | null + + } +> + Optional theme this icon is designed for. + + +## IconTheme + +Theme an icon is designed for. + +**Type:** Union + + + Icon designed for light backgrounds. + + + + Icon designed for dark backgrounds. + + + +Custom or future icon theme. + +Values beginning with `_` are reserved for implementation-specific +extensions. Unknown values that do not begin with `_` are reserved for +future ACP variants. + + + ## IdleStateUpdate The agent is not currently processing work in the session. @@ -6691,6 +6767,9 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/d Optional human-readable details shown with this protocol object. +Icon[] | null} > + Optional set of sized icons that the client can display in a user interface. + MIME type describing the encoded media payload. diff --git a/docs/protocol/v2/schema.mdx b/docs/protocol/v2/schema.mdx index ea75ff15f..3416fdd28 100644 --- a/docs/protocol/v2/schema.mdx +++ b/docs/protocol/v2/schema.mdx @@ -1063,6 +1063,12 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/e Relative importance of this content when clients choose what to surface. + + | Constraint | Value | + | ---------- | ----- | + | Minimum | `0` | + | Maximum | `1` | + ## AudioContent @@ -1531,6 +1537,9 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/e Optional human-readable details shown with this protocol object. +Icon[] | null} > + Optional set of sized icons that the client can display in a user interface. + MIME type describing the encoded media payload. @@ -1916,6 +1925,73 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/e The value to set for the HTTP header. +## Icon + +An optionally-sized icon that can be displayed in a user interface. + +**Type:** Object + +**Properties:** + + + Optional MIME type override if the source MIME type is missing or generic. + + + + <> + "string" + [] + + + | null + + } +> + Optional sizes at which the icon can be used. + + + A standard URI pointing to an icon resource. + + + + IconTheme + + | null + + } +> + Optional theme this icon is designed for. + + +## IconTheme + +Theme an icon is designed for. + +**Type:** Union + + + Icon designed for light backgrounds. + + + + Icon designed for dark backgrounds. + + + +Custom or future icon theme. + +Values beginning with `_` are reserved for implementation-specific +extensions. Unknown values that do not begin with `_` are reserved for +future ACP variants. + + + ## IdleStateUpdate The agent is not currently processing work in the session. @@ -2769,6 +2845,9 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/e Optional human-readable details shown with this protocol object. +Icon[] | null} > + Optional set of sized icons that the client can display in a user interface. + MIME type describing the encoded media payload. diff --git a/schema/v2/schema.json b/schema/v2/schema.json index e7186c4ba..8c1d43a84 100644 --- a/schema/v2/schema.json +++ b/schema/v2/schema.json @@ -1001,6 +1001,8 @@ "description": "Relative importance of this content when clients choose what to surface.", "type": ["number", "null"], "format": "double", + "minimum": 0, + "maximum": 1, "x-deserialize-default-on-error": true }, "_meta": { @@ -1066,7 +1068,8 @@ "properties": { "data": { "description": "Base64-encoded media payload.", - "type": "string" + "type": "string", + "format": "byte" }, "mimeType": { "description": "MIME type describing the encoded media payload.", @@ -1075,6 +1078,7 @@ "uri": { "description": "URI associated with this resource or media payload.", "type": ["string", "null"], + "format": "uri", "x-deserialize-default-on-error": true }, "annotations": { @@ -1104,7 +1108,8 @@ "properties": { "data": { "description": "Base64-encoded media payload.", - "type": "string" + "type": "string", + "format": "byte" }, "mimeType": { "description": "MIME type describing the encoded media payload.", @@ -1131,6 +1136,64 @@ }, "required": ["data", "mimeType"] }, + "Icon": { + "description": "An optionally-sized icon that can be displayed in a user interface.", + "type": "object", + "properties": { + "src": { + "description": "A standard URI pointing to an icon resource.", + "type": "string", + "format": "uri" + }, + "mimeType": { + "description": "Optional MIME type override if the source MIME type is missing or generic.", + "type": ["string", "null"], + "x-deserialize-default-on-error": true + }, + "sizes": { + "description": "Optional sizes at which the icon can be used.", + "type": ["array", "null"], + "items": { + "type": "string" + }, + "x-deserialize-default-on-error": true, + "x-deserialize-skip-invalid-items": true + }, + "theme": { + "description": "Optional theme this icon is designed for.", + "anyOf": [ + { + "$ref": "#/$defs/IconTheme" + }, + { + "type": "null" + } + ], + "x-deserialize-default-on-error": true + } + }, + "required": ["src"] + }, + "IconTheme": { + "description": "Theme an icon is designed for.", + "anyOf": [ + { + "description": "Icon designed for light backgrounds.", + "type": "string", + "const": "light" + }, + { + "description": "Icon designed for dark backgrounds.", + "type": "string", + "const": "dark" + }, + { + "title": "other", + "description": "Custom or future icon theme.\n\nValues beginning with `_` are reserved for implementation-specific\nextensions. Unknown values that do not begin with `_` are reserved for\nfuture ACP variants.", + "type": "string" + } + ] + }, "ResourceLink": { "description": "A resource that the server is capable of reading, included in a prompt or tool call result.", "type": "object", @@ -1141,7 +1204,8 @@ }, "uri": { "description": "URI associated with this resource or media payload.", - "type": "string" + "type": "string", + "format": "uri" }, "title": { "description": "Optional display title for end-user UI.", @@ -1153,6 +1217,15 @@ "type": ["string", "null"], "x-deserialize-default-on-error": true }, + "icons": { + "description": "Optional set of sized icons that the client can display in a user interface.", + "type": ["array", "null"], + "items": { + "$ref": "#/$defs/Icon" + }, + "x-deserialize-default-on-error": true, + "x-deserialize-skip-invalid-items": true + }, "mimeType": { "description": "MIME type describing the encoded media payload.", "type": ["string", "null"], @@ -1218,7 +1291,8 @@ }, "uri": { "description": "URI associated with this resource or media payload.", - "type": "string" + "type": "string", + "format": "uri" }, "mimeType": { "description": "MIME type describing the encoded media payload.", @@ -1240,11 +1314,13 @@ "properties": { "blob": { "description": "Base64-encoded bytes for a binary resource payload.", - "type": "string" + "type": "string", + "format": "byte" }, "uri": { "description": "URI associated with this resource or media payload.", - "type": "string" + "type": "string", + "format": "uri" }, "mimeType": { "description": "MIME type describing the encoded media payload.", @@ -4354,7 +4430,8 @@ }, "url": { "description": "URL to the MCP server.", - "type": "string" + "type": "string", + "format": "uri" }, "headers": { "description": "HTTP headers to set when making requests to the MCP server.", diff --git a/schema/v2/schema.unstable.json b/schema/v2/schema.unstable.json index 00cc31ccf..fb58c052e 100644 --- a/schema/v2/schema.unstable.json +++ b/schema/v2/schema.unstable.json @@ -1145,6 +1145,8 @@ "description": "Relative importance of this content when clients choose what to surface.", "type": ["number", "null"], "format": "double", + "minimum": 0, + "maximum": 1, "x-deserialize-default-on-error": true }, "_meta": { @@ -1210,7 +1212,8 @@ "properties": { "data": { "description": "Base64-encoded media payload.", - "type": "string" + "type": "string", + "format": "byte" }, "mimeType": { "description": "MIME type describing the encoded media payload.", @@ -1219,6 +1222,7 @@ "uri": { "description": "URI associated with this resource or media payload.", "type": ["string", "null"], + "format": "uri", "x-deserialize-default-on-error": true }, "annotations": { @@ -1248,7 +1252,8 @@ "properties": { "data": { "description": "Base64-encoded media payload.", - "type": "string" + "type": "string", + "format": "byte" }, "mimeType": { "description": "MIME type describing the encoded media payload.", @@ -1275,6 +1280,64 @@ }, "required": ["data", "mimeType"] }, + "Icon": { + "description": "An optionally-sized icon that can be displayed in a user interface.", + "type": "object", + "properties": { + "src": { + "description": "A standard URI pointing to an icon resource.", + "type": "string", + "format": "uri" + }, + "mimeType": { + "description": "Optional MIME type override if the source MIME type is missing or generic.", + "type": ["string", "null"], + "x-deserialize-default-on-error": true + }, + "sizes": { + "description": "Optional sizes at which the icon can be used.", + "type": ["array", "null"], + "items": { + "type": "string" + }, + "x-deserialize-default-on-error": true, + "x-deserialize-skip-invalid-items": true + }, + "theme": { + "description": "Optional theme this icon is designed for.", + "anyOf": [ + { + "$ref": "#/$defs/IconTheme" + }, + { + "type": "null" + } + ], + "x-deserialize-default-on-error": true + } + }, + "required": ["src"] + }, + "IconTheme": { + "description": "Theme an icon is designed for.", + "anyOf": [ + { + "description": "Icon designed for light backgrounds.", + "type": "string", + "const": "light" + }, + { + "description": "Icon designed for dark backgrounds.", + "type": "string", + "const": "dark" + }, + { + "title": "other", + "description": "Custom or future icon theme.\n\nValues beginning with `_` are reserved for implementation-specific\nextensions. Unknown values that do not begin with `_` are reserved for\nfuture ACP variants.", + "type": "string" + } + ] + }, "ResourceLink": { "description": "A resource that the server is capable of reading, included in a prompt or tool call result.", "type": "object", @@ -1285,7 +1348,8 @@ }, "uri": { "description": "URI associated with this resource or media payload.", - "type": "string" + "type": "string", + "format": "uri" }, "title": { "description": "Optional display title for end-user UI.", @@ -1297,6 +1361,15 @@ "type": ["string", "null"], "x-deserialize-default-on-error": true }, + "icons": { + "description": "Optional set of sized icons that the client can display in a user interface.", + "type": ["array", "null"], + "items": { + "$ref": "#/$defs/Icon" + }, + "x-deserialize-default-on-error": true, + "x-deserialize-skip-invalid-items": true + }, "mimeType": { "description": "MIME type describing the encoded media payload.", "type": ["string", "null"], @@ -1362,7 +1435,8 @@ }, "uri": { "description": "URI associated with this resource or media payload.", - "type": "string" + "type": "string", + "format": "uri" }, "mimeType": { "description": "MIME type describing the encoded media payload.", @@ -1384,11 +1458,13 @@ "properties": { "blob": { "description": "Base64-encoded bytes for a binary resource payload.", - "type": "string" + "type": "string", + "format": "byte" }, "uri": { "description": "URI associated with this resource or media payload.", - "type": "string" + "type": "string", + "format": "uri" }, "mimeType": { "description": "MIME type describing the encoded media payload.", @@ -7547,7 +7623,8 @@ }, "url": { "description": "URL to the MCP server.", - "type": "string" + "type": "string", + "format": "uri" }, "headers": { "description": "HTTP headers to set when making requests to the MCP server.",