-
Notifications
You must be signed in to change notification settings - Fork 876
feat: Add SEP-973 icons and metadata support #912
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 3 commits
d22688b
26c9409
70f36ac
bcab3c0
3e835a6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,18 +10,20 @@ | |
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
| import com.fasterxml.jackson.annotation.JsonCreator; | ||
| import com.fasterxml.jackson.annotation.JsonIgnore; | ||
| import com.fasterxml.jackson.annotation.JsonIgnoreProperties; | ||
| import com.fasterxml.jackson.annotation.JsonInclude; | ||
| import com.fasterxml.jackson.annotation.JsonProperty; | ||
| import com.fasterxml.jackson.annotation.JsonSubTypes; | ||
| import com.fasterxml.jackson.annotation.JsonTypeInfo; | ||
|
|
||
| import io.modelcontextprotocol.json.McpJsonMapper; | ||
| import io.modelcontextprotocol.json.TypeRef; | ||
| import io.modelcontextprotocol.util.Assert; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
| /** | ||
| * Based on the <a href="http://www.jsonrpc.org/specification">JSON-RPC 2.0 | ||
|
|
@@ -661,16 +663,63 @@ public ServerCapabilities build() { | |
| * past specs or fallback (if title isn't present). | ||
| * @param title Intended for UI and end-user contexts | ||
| * @param version The version of the implementation. | ||
| * @param description An optional human-readable description of this implementation. | ||
| * @param icons An optional list of icons for this implementation. | ||
| * @param websiteUrl An optional URL of the website for this implementation. | ||
| */ | ||
| @JsonInclude(JsonInclude.Include.NON_ABSENT) | ||
| @JsonIgnoreProperties(ignoreUnknown = true) | ||
| public record Implementation( // @formatter:off | ||
| @JsonProperty("name") String name, | ||
| @JsonProperty("title") String title, | ||
| @JsonProperty("version") String version) implements Identifier { // @formatter:on | ||
| @JsonProperty("version") String version, | ||
| @JsonProperty("description") String description, | ||
| @JsonProperty("icons") List<Icon> icons, | ||
| @JsonProperty("websiteUrl") String websiteUrl) implements Identifier { // @formatter:on | ||
|
|
||
| public Implementation(String name, String version) { | ||
| this(name, null, version); | ||
| this(name, null, version, null, null, null); | ||
| } | ||
|
|
||
| public Implementation(String name, String title, String version) { | ||
| this(name, title, version, null, null, null); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Represents an icon that can be displayed in a user interface. | ||
| * | ||
| * @param src A URI pointing to an icon resource or a base64-encoded data URI. | ||
| * @param mimeType Optional MIME type override if the server's MIME type is missing or | ||
| * generic. | ||
| * @param sizes Optional array of strings specifying sizes at which the icon can be | ||
| * used. Each string should be in WxH format (e.g., "48x48", "96x96") or "any" for | ||
| * scalable formats like SVG. | ||
| * @param theme Optional specifier for the theme this icon is designed for. "light" | ||
| * indicates the icon is designed for a light background, "dark" indicates the icon is | ||
| * designed for a dark background. If not provided, the client should assume the icon | ||
| * can be used with any theme. | ||
| * @see <a href= | ||
| * "https://github.com/modelcontextprotocol/modelcontextprotocol/issues/973">SEP-973</a> | ||
| */ | ||
| @JsonInclude(JsonInclude.Include.NON_ABSENT) | ||
| @JsonIgnoreProperties(ignoreUnknown = true) | ||
| public record Icon( // @formatter:off | ||
| @JsonProperty("src") String src, | ||
| @JsonProperty("mimeType") String mimeType, | ||
| @JsonProperty("sizes") List<String> sizes, | ||
| @JsonProperty("theme") String theme) { // @formatter:on | ||
|
Comment on lines
+1112
to
+1115
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need a builder that accepts
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. Added |
||
|
|
||
| public Icon { | ||
| Assert.hasText(src, "Icon src must not be empty"); | ||
| } | ||
|
|
||
| public Icon(String src, String mimeType) { | ||
| this(src, mimeType, null, null); | ||
| } | ||
|
|
||
| public Icon(String src, String mimeType, List<String> sizes) { | ||
| this(src, mimeType, sizes, null); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please remove these constructors and use the builder pattern as documented in the
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed. The only constructors on Icon now are the canonical 4-arg constructor and the |
||
| } | ||
| } | ||
|
|
||
|
|
@@ -792,6 +841,7 @@ public record Resource( // @formatter:off | |
| @JsonProperty("mimeType") String mimeType, | ||
| @JsonProperty("size") Long size, | ||
| @JsonProperty("annotations") Annotations annotations, | ||
| @JsonProperty("icons") List<Icon> icons, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a backwards incompatible change. Please check the process described in
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed. Added deprecated backward-compatible overload constructors for Resource, ResourceTemplate, Prompt, and Tool that delegate to the new canonical constructor with |
||
| @JsonProperty("_meta") Map<String, Object> meta) implements ResourceContent { // @formatter:on | ||
|
|
||
| public static Builder builder() { | ||
|
|
@@ -814,6 +864,8 @@ public static class Builder { | |
|
|
||
| private Annotations annotations; | ||
|
|
||
| private List<Icon> icons; | ||
|
|
||
| private Map<String, Object> meta; | ||
|
|
||
| public Builder uri(String uri) { | ||
|
|
@@ -851,6 +903,11 @@ public Builder annotations(Annotations annotations) { | |
| return this; | ||
| } | ||
|
|
||
| public Builder icons(List<Icon> icons) { | ||
| this.icons = icons; | ||
| return this; | ||
| } | ||
|
|
||
| public Builder meta(Map<String, Object> meta) { | ||
| this.meta = meta; | ||
| return this; | ||
|
|
@@ -860,7 +917,7 @@ public Resource build() { | |
| Assert.hasText(uri, "uri must not be empty"); | ||
| Assert.hasText(name, "name must not be empty"); | ||
|
|
||
| return new Resource(uri, name, title, description, mimeType, size, annotations, meta); | ||
| return new Resource(uri, name, title, description, mimeType, size, annotations, icons, meta); | ||
| } | ||
|
|
||
| } | ||
|
|
@@ -893,18 +950,24 @@ public record ResourceTemplate( // @formatter:off | |
| @JsonProperty("description") String description, | ||
| @JsonProperty("mimeType") String mimeType, | ||
| @JsonProperty("annotations") Annotations annotations, | ||
| @JsonProperty("icons") List<Icon> icons, | ||
| @JsonProperty("_meta") Map<String, Object> meta) implements Annotated, Identifier, Meta { // @formatter:on | ||
|
|
||
| public ResourceTemplate(String uriTemplate, String name, String title, String description, String mimeType, | ||
| Annotations annotations) { | ||
| this(uriTemplate, name, title, description, mimeType, annotations, null); | ||
| this(uriTemplate, name, title, description, mimeType, annotations, null, null); | ||
| } | ||
|
|
||
| public ResourceTemplate(String uriTemplate, String name, String description, String mimeType, | ||
| Annotations annotations) { | ||
| this(uriTemplate, name, null, description, mimeType, annotations); | ||
| } | ||
|
|
||
| public ResourceTemplate(String uriTemplate, String name, String title, String description, String mimeType, | ||
| Annotations annotations, Map<String, Object> meta) { | ||
| this(uriTemplate, name, title, description, mimeType, annotations, null, meta); | ||
| } | ||
|
|
||
| public static Builder builder() { | ||
| return new Builder(); | ||
| } | ||
|
|
@@ -923,6 +986,8 @@ public static class Builder { | |
|
|
||
| private Annotations annotations; | ||
|
|
||
| private List<Icon> icons; | ||
|
|
||
| private Map<String, Object> meta; | ||
|
|
||
| public Builder uriTemplate(String uri) { | ||
|
|
@@ -955,6 +1020,11 @@ public Builder annotations(Annotations annotations) { | |
| return this; | ||
| } | ||
|
|
||
| public Builder icons(List<Icon> icons) { | ||
| this.icons = icons; | ||
| return this; | ||
| } | ||
|
|
||
| public Builder meta(Map<String, Object> meta) { | ||
| this.meta = meta; | ||
| return this; | ||
|
|
@@ -964,7 +1034,7 @@ public ResourceTemplate build() { | |
| Assert.hasText(uriTemplate, "uri must not be empty"); | ||
| Assert.hasText(name, "name must not be empty"); | ||
|
|
||
| return new ResourceTemplate(uriTemplate, name, title, description, mimeType, annotations, meta); | ||
| return new ResourceTemplate(uriTemplate, name, title, description, mimeType, annotations, icons, meta); | ||
| } | ||
|
|
||
| } | ||
|
|
@@ -1168,14 +1238,20 @@ public record Prompt( // @formatter:off | |
| @JsonProperty("title") String title, | ||
| @JsonProperty("description") String description, | ||
| @JsonProperty("arguments") List<PromptArgument> arguments, | ||
| @JsonProperty("icons") List<Icon> icons, | ||
| @JsonProperty("_meta") Map<String, Object> meta) implements Identifier { // @formatter:on | ||
|
|
||
| public Prompt(String name, String description, List<PromptArgument> arguments) { | ||
| this(name, null, description, arguments, null); | ||
| this(name, null, description, arguments, null, null); | ||
| } | ||
|
|
||
| public Prompt(String name, String title, String description, List<PromptArgument> arguments) { | ||
| this(name, title, description, arguments, null); | ||
| this(name, title, description, arguments, null, null); | ||
| } | ||
|
|
||
| public Prompt(String name, String title, String description, List<PromptArgument> arguments, | ||
| Map<String, Object> meta) { | ||
| this(name, title, description, arguments, null, meta); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -1367,6 +1443,7 @@ public record Tool( // @formatter:off | |
| @JsonProperty("inputSchema") Map<String, Object> inputSchema, | ||
| @JsonProperty("outputSchema") Map<String, Object> outputSchema, | ||
| @JsonProperty("annotations") ToolAnnotations annotations, | ||
| @JsonProperty("icons") List<Icon> icons, | ||
| @JsonProperty("_meta") Map<String, Object> meta) { // @formatter:on | ||
|
|
||
| public static Builder builder() { | ||
|
|
@@ -1387,6 +1464,8 @@ public static class Builder { | |
|
|
||
| private ToolAnnotations annotations; | ||
|
|
||
| private List<Icon> icons; | ||
|
|
||
| private Map<String, Object> meta; | ||
|
|
||
| public Builder name(String name) { | ||
|
|
@@ -1450,14 +1529,19 @@ public Builder annotations(ToolAnnotations annotations) { | |
| return this; | ||
| } | ||
|
|
||
| public Builder icons(List<Icon> icons) { | ||
| this.icons = icons; | ||
| return this; | ||
| } | ||
|
|
||
| public Builder meta(Map<String, Object> meta) { | ||
| this.meta = meta; | ||
| return this; | ||
| } | ||
|
|
||
| public Tool build() { | ||
| Assert.hasText(name, "name must not be empty"); | ||
| return new Tool(name, title, description, inputSchema, outputSchema, annotations, meta); | ||
| return new Tool(name, title, description, inputSchema, outputSchema, annotations, icons, meta); | ||
| } | ||
|
|
||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
3 new optional fields indicate we need to add a builder with a static method that creates the builder instance with the required fields (name version) and all the others are optionally configured.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Added
Implementation.builder(String name, String version)with optional.title(),.description(),.icons(),.websiteUrl()setters. The existing 2-arg and 3-arg constructors are preserved as@Deprecatedoverloads for backward compatibility.