Skip to content

Commit 6c330db

Browse files
LucaButBoringtzolov
authored andcommitted
feat: add size field and builder pattern to Resource record (#331)
The size field helps hosts display file sizes and estimate context window usage. - Add size parameter to Resource record for tracking raw content size in bytes - Implement Builder pattern for Resource construction with validation - Add deprecated constructor for backwards compatibility - Add tests for builder pattern and field validation Resolves #330 Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
1 parent 0fe76ba commit 6c330db

File tree

3 files changed

+130
-7
lines changed

3 files changed

+130
-7
lines changed

mcp/src/main/java/io/modelcontextprotocol/spec/McpSchema.java

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
* Context Protocol Schema</a>.
3030
*
3131
* @author Christian Tzolov
32+
* @author Luca Chang
3233
*/
3334
public final class McpSchema {
3435

@@ -482,6 +483,9 @@ public record Annotations( // @formatter:off
482483
* by clients to improve the LLM's understanding of available resources. It can be
483484
* thought of like a "hint" to the model.
484485
* @param mimeType The MIME type of this resource, if known.
486+
* @param size The size of the raw resource content, in bytes (i.e., before base64
487+
* encoding or any tokenization), if known. This can be used by Hosts to display file
488+
* sizes and estimate context window usage.
485489
* @param annotations Optional annotations for the client. The client can use
486490
* annotations to inform how objects are used or displayed.
487491
*/
@@ -492,7 +496,67 @@ public record Resource( // @formatter:off
492496
@JsonProperty("name") String name,
493497
@JsonProperty("description") String description,
494498
@JsonProperty("mimeType") String mimeType,
499+
@JsonProperty("size") Long size,
495500
@JsonProperty("annotations") Annotations annotations) implements Annotated {
501+
502+
/**
503+
* @deprecated Only exists for backwards-compatibility purposes. Use
504+
* {@link Resource#builder()} instead.
505+
*/
506+
@Deprecated
507+
public Resource(String uri, String name, String description, String mimeType, Annotations annotations) {
508+
this(uri, name, description, mimeType, null, annotations);
509+
}
510+
511+
public static Builder builder() {
512+
return new Builder();
513+
}
514+
515+
public static class Builder {
516+
private String uri;
517+
private String name;
518+
private String description;
519+
private String mimeType;
520+
private Long size;
521+
private Annotations annotations;
522+
523+
public Builder uri(String uri) {
524+
this.uri = uri;
525+
return this;
526+
}
527+
528+
public Builder name(String name) {
529+
this.name = name;
530+
return this;
531+
}
532+
533+
public Builder description(String description) {
534+
this.description = description;
535+
return this;
536+
}
537+
538+
public Builder mimeType(String mimeType) {
539+
this.mimeType = mimeType;
540+
return this;
541+
}
542+
543+
public Builder size(Long size) {
544+
this.size = size;
545+
return this;
546+
}
547+
548+
public Builder annotations(Annotations annotations) {
549+
this.annotations = annotations;
550+
return this;
551+
}
552+
553+
public Resource build() {
554+
Assert.hasText(uri, "uri must not be empty");
555+
Assert.hasText(name, "name must not be empty");
556+
557+
return new Resource(uri, name, description, mimeType, size, annotations);
558+
}
559+
}
496560
} // @formatter:on
497561

498562
/**
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package io.modelcontextprotocol.spec;
2+
3+
public class ArgumentException {
4+
5+
}

mcp/src/test/java/io/modelcontextprotocol/spec/McpSchemaTests.java

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,24 @@
33
*/
44
package io.modelcontextprotocol.spec;
55

6+
import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson;
7+
import static net.javacrumbs.jsonunit.assertj.JsonAssertions.json;
8+
import static org.assertj.core.api.Assertions.assertThat;
9+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
10+
611
import java.util.Arrays;
712
import java.util.Collections;
813
import java.util.HashMap;
914
import java.util.List;
1015
import java.util.Map;
1116

12-
import com.fasterxml.jackson.core.type.TypeReference;
17+
import org.junit.jupiter.api.Test;
18+
1319
import com.fasterxml.jackson.databind.ObjectMapper;
1420
import com.fasterxml.jackson.databind.exc.InvalidTypeIdException;
21+
1522
import io.modelcontextprotocol.spec.McpSchema.TextResourceContents;
1623
import net.javacrumbs.jsonunit.core.Option;
17-
import org.junit.jupiter.api.Test;
18-
19-
import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson;
20-
import static net.javacrumbs.jsonunit.assertj.JsonAssertions.json;
21-
import static org.assertj.core.api.Assertions.assertThat;
22-
import static org.assertj.core.api.Assertions.assertThatThrownBy;
2324

2425
/**
2526
* @author Christian Tzolov
@@ -295,6 +296,59 @@ void testResource() throws Exception {
295296
{"uri":"resource://test","name":"Test Resource","description":"A test resource","mimeType":"text/plain","annotations":{"audience":["user","assistant"],"priority":0.8}}"""));
296297
}
297298

299+
@Test
300+
void testResourceBuilder() throws Exception {
301+
McpSchema.Annotations annotations = new McpSchema.Annotations(
302+
Arrays.asList(McpSchema.Role.USER, McpSchema.Role.ASSISTANT), 0.8);
303+
304+
McpSchema.Resource resource = McpSchema.Resource.builder()
305+
.uri("resource://test")
306+
.name("Test Resource")
307+
.description("A test resource")
308+
.mimeType("text/plain")
309+
.size(256L)
310+
.annotations(annotations)
311+
.build();
312+
313+
String value = mapper.writeValueAsString(resource);
314+
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
315+
.when(Option.IGNORING_EXTRA_ARRAY_ITEMS)
316+
.isObject()
317+
.isEqualTo(
318+
json("""
319+
{"uri":"resource://test","name":"Test Resource","description":"A test resource","mimeType":"text/plain","size":256,"annotations":{"audience":["user","assistant"],"priority":0.8}}"""));
320+
}
321+
322+
@Test
323+
void testResourceBuilderUriRequired() {
324+
McpSchema.Annotations annotations = new McpSchema.Annotations(
325+
Arrays.asList(McpSchema.Role.USER, McpSchema.Role.ASSISTANT), 0.8);
326+
327+
McpSchema.Resource.Builder resourceBuilder = McpSchema.Resource.builder()
328+
.name("Test Resource")
329+
.description("A test resource")
330+
.mimeType("text/plain")
331+
.size(256L)
332+
.annotations(annotations);
333+
334+
assertThatThrownBy(resourceBuilder::build).isInstanceOf(java.lang.IllegalArgumentException.class);
335+
}
336+
337+
@Test
338+
void testResourceBuilderNameRequired() {
339+
McpSchema.Annotations annotations = new McpSchema.Annotations(
340+
Arrays.asList(McpSchema.Role.USER, McpSchema.Role.ASSISTANT), 0.8);
341+
342+
McpSchema.Resource.Builder resourceBuilder = McpSchema.Resource.builder()
343+
.uri("resource://test")
344+
.description("A test resource")
345+
.mimeType("text/plain")
346+
.size(256L)
347+
.annotations(annotations);
348+
349+
assertThatThrownBy(resourceBuilder::build).isInstanceOf(java.lang.IllegalArgumentException.class);
350+
}
351+
298352
@Test
299353
void testResourceTemplate() throws Exception {
300354
McpSchema.Annotations annotations = new McpSchema.Annotations(Arrays.asList(McpSchema.Role.USER), 0.5);

0 commit comments

Comments
 (0)