Skip to content

Commit 8291207

Browse files
committed
feat(mcp): expand @McpResource annotation and enhance APT generation
This commit significantly expands the `@McpResource` annotation to fully support the Model Context Protocol (MCP) Resource specification, and updates the annotation processor to map these new fields into the SDK constructors. Details: * Renamed the default `value` attribute to `uri` for better clarity. * Added support for `title`, `description`, `mimeType`, and `size` metadata. * Introduced a nested `@McpAnnotations` interface to support advanced resource metadata, including `audience` roles, `priority`, and `lastModified` dates. * Updated the `McpRoute` APT generator to extract the new attributes and map them correctly into `McpSchema.Resource` and `McpSchema.ResourceTemplate`. * Implemented string-based parsing for nested annotations in `McpRoute` to safely generate the `ResourceAnnotations` object for Java and Kotlin, bypassing the need for heavy `ElementVisitor` boilerplate.
1 parent 8cd4c0a commit 8291207

File tree

17 files changed

+628
-565
lines changed

17 files changed

+628
-565
lines changed

jooby/src/main/java/io/jooby/MediaType.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,21 @@ static boolean matches(@NonNull String expected, @NonNull String contentType) {
443443
return index > 0 ? byFileExtension(filename.substring(index + 1)) : octetStream;
444444
}
445445

446+
/**
447+
* Mediatype by file extension.
448+
*
449+
* @param ext File extension.
450+
* @return Mediatype.
451+
*/
452+
public static @NonNull MediaType byFileExtension(
453+
@NonNull String ext, @NonNull String defaultType) {
454+
var result = byFileExtension(ext);
455+
if (result.equals(octetStream) || result.equals(all)) {
456+
return MediaType.valueOf(defaultType);
457+
}
458+
return result;
459+
}
460+
446461
/**
447462
* Mediatype by file extension.
448463
*

jooby/src/main/java/io/jooby/annotation/McpResource.java

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
*
2525
* @return The resource URI.
2626
*/
27-
String value();
27+
String uri();
2828

2929
/**
3030
* The name of the resource.
@@ -33,6 +33,9 @@
3333
*/
3434
String name() default "";
3535

36+
/** Optional human-readable name of the prompt for display purposes. */
37+
String title() default "";
38+
3639
/**
3740
* A description of the resource.
3841
*
@@ -41,8 +44,45 @@
4144
String description() default "";
4245

4346
/**
44-
* The MIME type of the resource (e.g., "text/plain", "application/json"). * @return The MIME
45-
* type.
47+
* The MIME type of the resource (e.g., "text/plain", "application/json").
48+
*
49+
* @return The MIME type.
4650
*/
4751
String mimeType() default "";
52+
53+
/** Optional size in bytes. */
54+
int size() default -1;
55+
56+
/** Optional MCP metadata annotations for this resource. */
57+
McpAnnotations[]
58+
annotations() default {}; // Using an array is the safest way to provide an "empty" default in
59+
60+
// Java annotations
61+
62+
enum Role {
63+
USER,
64+
ASSISTANT
65+
}
66+
67+
@Retention(RetentionPolicy.RUNTIME)
68+
@Target(ElementType.ANNOTATION_TYPE)
69+
@interface McpAnnotations {
70+
71+
/**
72+
* Describes who the intended customer of this object or data is. It can include multiple
73+
* entries to indicate content useful for multiple audiences (e.g., [“user”, “assistant”]).
74+
*/
75+
Role[] audience();
76+
77+
/** The date and time (in ISO 8601 format) when the resource was last modified. */
78+
String lastModified() default "";
79+
80+
/**
81+
* Describes how important this data is for operating the server.
82+
*
83+
* <p>A value of 1 means “most important,” and indicates that the data is effectively required,
84+
* while 0 means “least important,” and indicates that the data is entirely optional.
85+
*/
86+
double priority();
87+
}
4888
}

modules/jooby-apt/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@
1818

1919
<dependencies>
2020

21+
<dependency>
22+
<groupId>io.jooby</groupId>
23+
<artifactId>jooby-javadoc</artifactId>
24+
<version>${jooby.version}</version>
25+
</dependency>
26+
2127
<dependency>
2228
<groupId>io.jooby</groupId>
2329
<artifactId>jooby</artifactId>

modules/jooby-apt/src/main/java/io/jooby/apt/JoobyProcessor.java

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import static io.jooby.apt.JoobyProcessor.Options.*;
99
import static java.nio.charset.StandardCharsets.UTF_8;
1010
import static java.util.Optional.ofNullable;
11-
import static javax.tools.StandardLocation.SOURCE_OUTPUT;
11+
import static javax.tools.StandardLocation.*;
1212

1313
import java.io.*;
1414
import java.net.URI;
@@ -21,9 +21,7 @@
2121
import javax.annotation.processing.*;
2222
import javax.lang.model.SourceVersion;
2323
import javax.lang.model.element.*;
24-
import javax.tools.Diagnostic;
25-
import javax.tools.JavaFileObject;
26-
import javax.tools.SimpleJavaFileObject;
24+
import javax.tools.*;
2725

2826
import io.jooby.internal.apt.*;
2927

@@ -138,10 +136,6 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
138136
for (var controller : controllers) {
139137
if (controller.getModifiers().contains(Modifier.ABSTRACT)) continue;
140138

141-
// These factory methods will scan the class methods and return a populated router
142-
// if it finds relevant annotations (@GET for Rest, @McpTool for MCP, etc.)
143-
// We will implement these factories inside the respective Router classes.
144-
145139
var restRouter = RestRouter.parse(context, controller);
146140
if (!restRouter.isEmpty()) {
147141
activeRouters.add(restRouter);

modules/jooby-apt/src/main/java/io/jooby/internal/apt/JsonRpcRoute.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515

1616
import javax.lang.model.element.ExecutableElement;
1717

18-
public class JsonRpcRoute extends WebRoute {
18+
public class JsonRpcRoute extends WebRoute<JsonRpcRouter> {
1919

20-
public JsonRpcRoute(WebRouter<?> router, ExecutableElement method) {
20+
public JsonRpcRoute(JsonRpcRouter router, ExecutableElement method) {
2121
super(router, method);
2222
}
2323

0 commit comments

Comments
 (0)