feat(McpSchema): CallToolResult and CallToolRequest usability improvements (#87)

- Add constructor to CallToolResult with one String entry
- Add a new constructor to CallToolRequest that accepts JSON string arguments
- Implement a builder pattern for CallToolResult with methods for adding content items
- Add test coverage for new functionality

Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
Co-authored-by: Christian Tzolov <christian.tzolov@broadcom.com>
This commit is contained in:
Dennis Kawurek 2025-03-30 20:49:04 +02:00 • committed by Christian Tzolov
commit 8d5872fd66

View file

@ -18,6 +18,7 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.modelcontextprotocol.util.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -741,6 +742,19 @@ public final class McpSchema {
public record CallToolRequest(// @formatter:off
@JsonProperty("name") String name,
@JsonProperty("arguments") Map<String, Object> arguments) implements Request {
public CallToolRequest(String name, String jsonArguments) {
this(name, parseJsonArguments(jsonArguments));
}
private static Map<String, Object> parseJsonArguments(String jsonArguments) {
try {
return OBJECT_MAPPER.readValue(jsonArguments, MAP_TYPE_REF);
}
catch (IOException e) {
throw new IllegalArgumentException("Invalid arguments: " + jsonArguments, e);
}
}
}// @formatter:off
/**
@ -756,6 +770,103 @@ public final class McpSchema {
public record CallToolResult( // @formatter:off
@JsonProperty("content") List<Content> content,
@JsonProperty("isError") Boolean isError) {
/**
* Creates a new instance of {@link CallToolResult} with a string containing the
* tool result.
*
* @param content The content of the tool result. This will be mapped to a one-sized list
* with a {@link TextContent} element.
* @param isError If true, indicates that the tool execution failed and the content contains error information.
* If false or absent, indicates successful execution.
*/
public CallToolResult(String content, Boolean isError) {
this(List.of(new TextContent(content)), isError);
}
/**
* Creates a builder for {@link CallToolResult}.
* @return a new builder instance
*/
public static Builder builder() {
return new Builder();
}
/**
* Builder for {@link CallToolResult}.
*/
public static class Builder {
private List<Content> content = new ArrayList<>();
private Boolean isError;
/**
* Sets the content list for the tool result.
* @param content the content list
* @return this builder
*/
public Builder content(List<Content> content) {
Assert.notNull(content, "content must not be null");
this.content = content;
return this;
}
/**
* Sets the text content for the tool result.
* @param textContent the text content
* @return this builder
*/
public Builder textContent(List<String> textContent) {
Assert.notNull(textContent, "textContent must not be null");
textContent.stream()
.map(TextContent::new)
.forEach(this.content::add);
return this;
}
/**
* Adds a content item to the tool result.
* @param contentItem the content item to add
* @return this builder
*/
public Builder addContent(Content contentItem) {
Assert.notNull(contentItem, "contentItem must not be null");
if (this.content == null) {
this.content = new ArrayList<>();
}
this.content.add(contentItem);
return this;
}
/**
* Adds a text content item to the tool result.
* @param text the text content
* @return this builder
*/
public Builder addTextContent(String text) {
Assert.notNull(text, "text must not be null");
return addContent(new TextContent(text));
}
/**
* Sets whether the tool execution resulted in an error.
* @param isError true if the tool execution failed, false otherwise
* @return this builder
*/
public Builder isError(Boolean isError) {
Assert.notNull(isError, "isError must not be null");
this.isError = isError;
return this;
}
/**
* Builds a new {@link CallToolResult} instance.
* @return a new CallToolResult instance
*/
public CallToolResult build() {
return new CallToolResult(content, isError);
}
}
} // @formatter:on
// ---------------------------