diff --git a/mcp-annotations/src/main/java/org/springaicommunity/mcp/adapter/PromptAdapter.java b/mcp-annotations/src/main/java/org/springaicommunity/mcp/adapter/PromptAdapter.java index f5a5ba9..5d0c428 100644 --- a/mcp-annotations/src/main/java/org/springaicommunity/mcp/adapter/PromptAdapter.java +++ b/mcp-annotations/src/main/java/org/springaicommunity/mcp/adapter/PromptAdapter.java @@ -29,7 +29,7 @@ private PromptAdapter() { * @return The corresponding McpSchema.Prompt object */ public static McpSchema.Prompt asPrompt(McpPrompt mcpPrompt) { - return new McpSchema.Prompt(mcpPrompt.name(), mcpPrompt.description(), List.of()); + return new McpSchema.Prompt(mcpPrompt.name(), mcpPrompt.title(), mcpPrompt.description(), List.of()); } /** @@ -41,7 +41,7 @@ public static McpSchema.Prompt asPrompt(McpPrompt mcpPrompt) { */ public static McpSchema.Prompt asPrompt(McpPrompt mcpPrompt, Method method) { List arguments = extractPromptArguments(method); - return new McpSchema.Prompt(getName(mcpPrompt, method), mcpPrompt.description(), arguments); + return new McpSchema.Prompt(getName(mcpPrompt, method), mcpPrompt.title(), mcpPrompt.description(), arguments); } private static String getName(McpPrompt promptAnnotation, Method method) { diff --git a/mcp-annotations/src/main/java/org/springaicommunity/mcp/annotation/McpPrompt.java b/mcp-annotations/src/main/java/org/springaicommunity/mcp/annotation/McpPrompt.java index 764488e..5002e7f 100644 --- a/mcp-annotations/src/main/java/org/springaicommunity/mcp/annotation/McpPrompt.java +++ b/mcp-annotations/src/main/java/org/springaicommunity/mcp/annotation/McpPrompt.java @@ -21,15 +21,17 @@ public @interface McpPrompt { /** - * A human-readable name for this resource. This can be used by clients to populate UI - * elements. + * Unique identifier for the prompt */ String name() default ""; /** - * A description of what this resource represents. This can be used by clients to - * improve the LLM's understanding of available resources. It can be thought of like a - * "hint" to the model. + * Optional human-readable name of the prompt for display purposes. + */ + String title() default ""; + + /** + * Optional human-readable description. */ String description() default ""; diff --git a/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/tool/AsyncMcpToolMethodCallbackTests.java b/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/tool/AsyncMcpToolMethodCallbackTests.java index c439df3..2355a81 100644 --- a/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/tool/AsyncMcpToolMethodCallbackTests.java +++ b/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/tool/AsyncMcpToolMethodCallbackTests.java @@ -6,6 +6,7 @@ import java.lang.reflect.Method; import java.util.List; +import java.util.Locale; import java.util.Map; import io.modelcontextprotocol.server.McpAsyncServerExchange; @@ -120,7 +121,8 @@ public Mono enumMonoTool(TestEnum enumValue) { @McpTool(name = "primitive-types-mono-tool", description = "Mono tool with primitive types") public Mono primitiveTypesMonoTool(boolean flag, byte b, short s, int i, long l, float f, double d) { - return Mono.just(String.format("Primitives: %b, %d, %d, %d, %d, %.1f, %.1f", flag, b, s, i, l, f, d)); + return Mono + .just(String.format(Locale.US, "Primitives: %b, %d, %d, %d, %d, %.1f, %.1f", flag, b, s, i, l, f, d)); } @McpTool(name = "return-object-mono-tool", description = "Mono tool that returns a complex object") diff --git a/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/tool/AsyncStatelessMcpToolMethodCallbackTests.java b/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/tool/AsyncStatelessMcpToolMethodCallbackTests.java index 5d5e42d..38bd5cf 100644 --- a/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/tool/AsyncStatelessMcpToolMethodCallbackTests.java +++ b/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/tool/AsyncStatelessMcpToolMethodCallbackTests.java @@ -6,6 +6,7 @@ import java.lang.reflect.Method; import java.util.List; +import java.util.Locale; import java.util.Map; import io.modelcontextprotocol.common.McpTransportContext; @@ -120,7 +121,8 @@ public Mono enumMonoTool(TestEnum enumValue) { @McpTool(name = "primitive-types-mono-tool", description = "Mono tool with primitive types") public Mono primitiveTypesMonoTool(boolean flag, byte b, short s, int i, long l, float f, double d) { - return Mono.just(String.format("Primitives: %b, %d, %d, %d, %d, %.1f, %.1f", flag, b, s, i, l, f, d)); + return Mono + .just(String.format(Locale.US, "Primitives: %b, %d, %d, %d, %d, %.1f, %.1f", flag, b, s, i, l, f, d)); } @McpTool(name = "return-object-mono-tool", description = "Mono tool that returns a complex object") diff --git a/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/tool/SyncMcpToolMethodCallbackTests.java b/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/tool/SyncMcpToolMethodCallbackTests.java index 9c00379..b2c5c6a 100644 --- a/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/tool/SyncMcpToolMethodCallbackTests.java +++ b/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/tool/SyncMcpToolMethodCallbackTests.java @@ -6,6 +6,7 @@ import java.lang.reflect.Method; import java.util.List; +import java.util.Locale; import java.util.Map; import io.modelcontextprotocol.server.McpSyncServerExchange; @@ -98,7 +99,7 @@ public String enumTool(TestEnum enumValue) { @McpTool(name = "primitive-types-tool", description = "Tool with primitive types") public String primitiveTypesTool(boolean flag, byte b, short s, int i, long l, float f, double d) { - return String.format("Primitives: %b, %d, %d, %d, %d, %.1f, %.1f", flag, b, s, i, l, f, d); + return String.format(Locale.US, "Primitives: %b, %d, %d, %d, %d, %.1f, %.1f", flag, b, s, i, l, f, d); } @McpTool(name = "return-object-tool", description = "Tool that returns a complex object") diff --git a/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/tool/SyncStatelessMcpToolMethodCallbackTests.java b/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/tool/SyncStatelessMcpToolMethodCallbackTests.java index 5528b8a..77fcf6f 100644 --- a/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/tool/SyncStatelessMcpToolMethodCallbackTests.java +++ b/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/tool/SyncStatelessMcpToolMethodCallbackTests.java @@ -6,6 +6,7 @@ import java.lang.reflect.Method; import java.util.List; +import java.util.Locale; import java.util.Map; import io.modelcontextprotocol.common.McpTransportContext; @@ -99,7 +100,7 @@ public String enumTool(TestEnum enumValue) { @McpTool(name = "primitive-types-tool", description = "Tool with primitive types") public String primitiveTypesTool(boolean flag, byte b, short s, int i, long l, float f, double d) { - return String.format("Primitives: %b, %d, %d, %d, %d, %.1f, %.1f", flag, b, s, i, l, f, d); + return String.format(Locale.US, "Primitives: %b, %d, %d, %d, %d, %.1f, %.1f", flag, b, s, i, l, f, d); } @McpTool(name = "return-object-tool", description = "Tool that returns a complex object") diff --git a/mcp-annotations/src/test/java/org/springaicommunity/mcp/provider/prompt/SyncMcpPromptProviderTests.java b/mcp-annotations/src/test/java/org/springaicommunity/mcp/provider/prompt/SyncMcpPromptProviderTests.java index f0cde3e..a5c321a 100644 --- a/mcp-annotations/src/test/java/org/springaicommunity/mcp/provider/prompt/SyncMcpPromptProviderTests.java +++ b/mcp-annotations/src/test/java/org/springaicommunity/mcp/provider/prompt/SyncMcpPromptProviderTests.java @@ -112,6 +112,29 @@ public GetPromptResult methodWithDifferentName() { assertThat(promptSpecs.get(0).prompt().description()).isEqualTo("Custom named prompt"); } + @Test + void testGetPromptSpecificationsWithTitle() { + class PromptWithTitle { + + @McpPrompt(name = "prompt-name", title = "Custom Title for UI", description = "Custom Titled prompt") + public GetPromptResult methodWithDifferentName() { + return new GetPromptResult("Custom prompt result", + List.of(new PromptMessage(Role.ASSISTANT, new TextContent("Custom prompt content")))); + } + + } + + PromptWithTitle promptObject = new PromptWithTitle(); + SyncMcpPromptProvider provider = new SyncMcpPromptProvider(List.of(promptObject)); + + List promptSpecs = provider.getPromptSpecifications(); + + assertThat(promptSpecs).hasSize(1); + assertThat(promptSpecs.get(0).prompt().name()).isEqualTo("prompt-name"); + assertThat(promptSpecs.get(0).prompt().title()).isEqualTo("Custom Title for UI"); + assertThat(promptSpecs.get(0).prompt().description()).isEqualTo("Custom Titled prompt"); + } + @Test void testGetPromptSpecificationsWithDefaultPromptName() { class DefaultNamePrompt {