feat: Add title field support to MCP schema classes (#372)

- Add BaseMetadata interface with name() and title() methods for consistent metadata handling
- The Prompt, PromptArgument, Resource, ResourceTemplate, ResuorceLink, PromptReference, Tool,
  and Implementation classes implement the BaseMetadata interface, adding a new, optional title field
- Update constructors to support backward compatibility while allowing title specification
- Modify ResourceContent interface to extend BaseMetadata
- Update all test cases to accommodate new title parameter

The title field provides human-readable display names optimized for UI contexts,
while name remains for programmatic/logical use. This change maintains backward compatibility.

Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
Co-authored-by: Christian Tzolov <christian.tzolov@broadcom.com>
This commit is contained in:
bzsurbhi 2025-07-03 11:43:28 -07:00 • committed by Christian Tzolov
commit 9977a064d5
11 changed files with 1053 additions and 929 deletions

View file

@ -996,11 +996,11 @@ class WebFluxSseIntegrationTests {
var mcpServer = McpServer.sync(mcpServerTransportProvider) var mcpServer = McpServer.sync(mcpServerTransportProvider)
.capabilities(ServerCapabilities.builder().completions().build()) .capabilities(ServerCapabilities.builder().completions().build())
.prompts(new McpServerFeatures.SyncPromptSpecification( .prompts(new McpServerFeatures.SyncPromptSpecification(
new Prompt("code_review", "this is code review prompt", new Prompt("code_review", "Code review", "this is code review prompt",
List.of(new PromptArgument("language", "string", false))), List.of(new PromptArgument("language", "Language", "string", false))),
(mcpSyncServerExchange, getPromptRequest) -> null)) (mcpSyncServerExchange, getPromptRequest) -> null))
.completions(new McpServerFeatures.SyncCompletionSpecification( .completions(new McpServerFeatures.SyncCompletionSpecification(
new McpSchema.PromptReference("ref/prompt", "code_review"), completionHandler)) new McpSchema.PromptReference("ref/prompt", "code_review", "Code review"), completionHandler))
.build(); .build();
try (var mcpClient = clientBuilder.build()) { try (var mcpClient = clientBuilder.build()) {
@ -1008,7 +1008,8 @@ class WebFluxSseIntegrationTests {
InitializeResult initResult = mcpClient.initialize(); InitializeResult initResult = mcpClient.initialize();
assertThat(initResult).isNotNull(); assertThat(initResult).isNotNull();
CompleteRequest request = new CompleteRequest(new PromptReference("ref/prompt", "code_review"), CompleteRequest request = new CompleteRequest(
new PromptReference("ref/prompt", "code_review", "Code review"),
new CompleteRequest.CompleteArgument("language", "py")); new CompleteRequest.CompleteArgument("language", "py"));
CompleteResult result = mcpClient.completeCompletion(request); CompleteResult result = mcpClient.completeCompletion(request);

View file

@ -420,7 +420,7 @@ public abstract class AbstractMcpAsyncClientTests {
.consumeNextWith(result -> { .consumeNextWith(result -> {
assertThat(result.prompts()).isNotNull(); assertThat(result.prompts()).isNotNull();
// Verify that the returned list is immutable // Verify that the returned list is immutable
assertThatThrownBy(() -> result.prompts().add(new Prompt("test", "test", null))) assertThatThrownBy(() -> result.prompts().add(new Prompt("test", "Test", "test", null)))
.isInstanceOf(UnsupportedOperationException.class); .isInstanceOf(UnsupportedOperationException.class);
}) })
.verifyComplete(); .verifyComplete();
@ -604,7 +604,7 @@ public abstract class AbstractMcpAsyncClientTests {
assertThat(result.resourceTemplates()).isNotNull(); assertThat(result.resourceTemplates()).isNotNull();
// Verify that the returned list is immutable // Verify that the returned list is immutable
assertThatThrownBy(() -> result.resourceTemplates() assertThatThrownBy(() -> result.resourceTemplates()
.add(new McpSchema.ResourceTemplate("test://template", "test", null, null, null))) .add(new McpSchema.ResourceTemplate("test://template", "test", "test", null, null, null)))
.isInstanceOf(UnsupportedOperationException.class); .isInstanceOf(UnsupportedOperationException.class);
}) })
.verifyComplete(); .verifyComplete();

View file

@ -302,7 +302,7 @@ public abstract class AbstractMcpAsyncServerTests {
.serverInfo("test-server", "1.0.0") .serverInfo("test-server", "1.0.0")
.build(); .build();
Prompt prompt = new Prompt(TEST_PROMPT_NAME, "Test Prompt", List.of()); Prompt prompt = new Prompt(TEST_PROMPT_NAME, "Test Prompt", "Test Prompt", List.of());
McpServerFeatures.AsyncPromptSpecification specification = new McpServerFeatures.AsyncPromptSpecification( McpServerFeatures.AsyncPromptSpecification specification = new McpServerFeatures.AsyncPromptSpecification(
prompt, (exchange, req) -> Mono.just(new GetPromptResult("Test prompt description", List prompt, (exchange, req) -> Mono.just(new GetPromptResult("Test prompt description", List
.of(new PromptMessage(McpSchema.Role.ASSISTANT, new McpSchema.TextContent("Test content")))))); .of(new PromptMessage(McpSchema.Role.ASSISTANT, new McpSchema.TextContent("Test content"))))));
@ -330,7 +330,7 @@ public abstract class AbstractMcpAsyncServerTests {
void testRemovePrompt() { void testRemovePrompt() {
String TEST_PROMPT_NAME_TO_REMOVE = "TEST_PROMPT_NAME678"; String TEST_PROMPT_NAME_TO_REMOVE = "TEST_PROMPT_NAME678";
Prompt prompt = new Prompt(TEST_PROMPT_NAME_TO_REMOVE, "Test Prompt", List.of()); Prompt prompt = new Prompt(TEST_PROMPT_NAME_TO_REMOVE, "Test Prompt", "Test Prompt", List.of());
McpServerFeatures.AsyncPromptSpecification specification = new McpServerFeatures.AsyncPromptSpecification( McpServerFeatures.AsyncPromptSpecification specification = new McpServerFeatures.AsyncPromptSpecification(
prompt, (exchange, req) -> Mono.just(new GetPromptResult("Test prompt description", List prompt, (exchange, req) -> Mono.just(new GetPromptResult("Test prompt description", List
.of(new PromptMessage(McpSchema.Role.ASSISTANT, new McpSchema.TextContent("Test content")))))); .of(new PromptMessage(McpSchema.Role.ASSISTANT, new McpSchema.TextContent("Test content"))))));

View file

@ -289,7 +289,7 @@ public abstract class AbstractMcpSyncServerTests {
.serverInfo("test-server", "1.0.0") .serverInfo("test-server", "1.0.0")
.build(); .build();
Prompt prompt = new Prompt(TEST_PROMPT_NAME, "Test Prompt", List.of()); Prompt prompt = new Prompt(TEST_PROMPT_NAME, "Test Prompt", "Test Prompt", List.of());
McpServerFeatures.SyncPromptSpecification specification = new McpServerFeatures.SyncPromptSpecification(prompt, McpServerFeatures.SyncPromptSpecification specification = new McpServerFeatures.SyncPromptSpecification(prompt,
(exchange, req) -> new GetPromptResult("Test prompt description", List (exchange, req) -> new GetPromptResult("Test prompt description", List
.of(new PromptMessage(McpSchema.Role.ASSISTANT, new McpSchema.TextContent("Test content"))))); .of(new PromptMessage(McpSchema.Role.ASSISTANT, new McpSchema.TextContent("Test content")))));
@ -310,7 +310,7 @@ public abstract class AbstractMcpSyncServerTests {
@Test @Test
void testRemovePrompt() { void testRemovePrompt() {
Prompt prompt = new Prompt(TEST_PROMPT_NAME, "Test Prompt", List.of()); Prompt prompt = new Prompt(TEST_PROMPT_NAME, "Test Prompt", "Test Prompt", List.of());
McpServerFeatures.SyncPromptSpecification specification = new McpServerFeatures.SyncPromptSpecification(prompt, McpServerFeatures.SyncPromptSpecification specification = new McpServerFeatures.SyncPromptSpecification(prompt,
(exchange, req) -> new GetPromptResult("Test prompt description", List (exchange, req) -> new GetPromptResult("Test prompt description", List
.of(new PromptMessage(McpSchema.Role.ASSISTANT, new McpSchema.TextContent("Test content"))))); .of(new PromptMessage(McpSchema.Role.ASSISTANT, new McpSchema.TextContent("Test content")))));

View file

@ -462,8 +462,8 @@ public class McpAsyncServer {
.filter(uri -> uri.contains("{")) .filter(uri -> uri.contains("{"))
.map(uri -> { .map(uri -> {
var resource = this.resources.get(uri).resource(); var resource = this.resources.get(uri).resource();
var template = new McpSchema.ResourceTemplate(resource.uri(), resource.name(), resource.description(), var template = new McpSchema.ResourceTemplate(resource.uri(), resource.name(), resource.title(),
resource.mimeType(), resource.annotations()); resource.description(), resource.mimeType(), resource.annotations());
return template; return template;
}) })
.toList(); .toList();
@ -725,7 +725,8 @@ public class McpAsyncServer {
String refType = (String) refMap.get("type"); String refType = (String) refMap.get("type");
McpSchema.CompleteReference ref = switch (refType) { McpSchema.CompleteReference ref = switch (refType) {
case "ref/prompt" -> new McpSchema.PromptReference(refType, (String) refMap.get("name")); case "ref/prompt" -> new McpSchema.PromptReference(refType, (String) refMap.get("name"),
refMap.get("title") != null ? (String) refMap.get("title") : null);
case "ref/resource" -> new McpSchema.ResourceReference(refType, (String) refMap.get("uri")); case "ref/resource" -> new McpSchema.ResourceReference(refType, (String) refMap.get("uri"));
default -> throw new IllegalArgumentException("Invalid ref type: " + refType); default -> throw new IllegalArgumentException("Invalid ref type: " + refType);
}; };

File diff suppressed because it is too large Load diff

View file

@ -421,7 +421,7 @@ public abstract class AbstractMcpAsyncClientTests {
.consumeNextWith(result -> { .consumeNextWith(result -> {
assertThat(result.prompts()).isNotNull(); assertThat(result.prompts()).isNotNull();
// Verify that the returned list is immutable // Verify that the returned list is immutable
assertThatThrownBy(() -> result.prompts().add(new Prompt("test", "test", null))) assertThatThrownBy(() -> result.prompts().add(new Prompt("test", "test", "test", null)))
.isInstanceOf(UnsupportedOperationException.class); .isInstanceOf(UnsupportedOperationException.class);
}) })
.verifyComplete(); .verifyComplete();
@ -605,7 +605,7 @@ public abstract class AbstractMcpAsyncClientTests {
assertThat(result.resourceTemplates()).isNotNull(); assertThat(result.resourceTemplates()).isNotNull();
// Verify that the returned list is immutable // Verify that the returned list is immutable
assertThatThrownBy(() -> result.resourceTemplates() assertThatThrownBy(() -> result.resourceTemplates()
.add(new McpSchema.ResourceTemplate("test://template", "test", null, null, null))) .add(new McpSchema.ResourceTemplate("test://template", "test", "test", null, null, null)))
.isInstanceOf(UnsupportedOperationException.class); .isInstanceOf(UnsupportedOperationException.class);
}) })
.verifyComplete(); .verifyComplete();

View file

@ -251,8 +251,8 @@ class McpAsyncClientResponseHandlerTests {
assertThat(asyncMcpClient.initialize().block()).isNotNull(); assertThat(asyncMcpClient.initialize().block()).isNotNull();
// Create a mock prompts list that the server will return // Create a mock prompts list that the server will return
McpSchema.Prompt mockPrompt = new McpSchema.Prompt("test-prompt", "Test Prompt Description", McpSchema.Prompt mockPrompt = new McpSchema.Prompt("test-prompt", "Test Prompt", "Test Prompt Description",
List.of(new McpSchema.PromptArgument("arg1", "Test argument", true))); List.of(new McpSchema.PromptArgument("arg1", "Test argument", "Test argument", true)));
McpSchema.ListPromptsResult mockPromptsResult = new McpSchema.ListPromptsResult(List.of(mockPrompt), null); McpSchema.ListPromptsResult mockPromptsResult = new McpSchema.ListPromptsResult(List.of(mockPrompt), null);
// Simulate server sending prompts/list_changed notification // Simulate server sending prompts/list_changed notification

View file

@ -301,7 +301,7 @@ public abstract class AbstractMcpAsyncServerTests {
.serverInfo("test-server", "1.0.0") .serverInfo("test-server", "1.0.0")
.build(); .build();
Prompt prompt = new Prompt(TEST_PROMPT_NAME, "Test Prompt", List.of()); Prompt prompt = new Prompt(TEST_PROMPT_NAME, "Test Prompt", "Test Prompt", List.of());
McpServerFeatures.AsyncPromptSpecification specification = new McpServerFeatures.AsyncPromptSpecification( McpServerFeatures.AsyncPromptSpecification specification = new McpServerFeatures.AsyncPromptSpecification(
prompt, (exchange, req) -> Mono.just(new GetPromptResult("Test prompt description", List prompt, (exchange, req) -> Mono.just(new GetPromptResult("Test prompt description", List
.of(new PromptMessage(McpSchema.Role.ASSISTANT, new McpSchema.TextContent("Test content")))))); .of(new PromptMessage(McpSchema.Role.ASSISTANT, new McpSchema.TextContent("Test content"))))));
@ -329,7 +329,7 @@ public abstract class AbstractMcpAsyncServerTests {
void testRemovePrompt() { void testRemovePrompt() {
String TEST_PROMPT_NAME_TO_REMOVE = "TEST_PROMPT_NAME678"; String TEST_PROMPT_NAME_TO_REMOVE = "TEST_PROMPT_NAME678";
Prompt prompt = new Prompt(TEST_PROMPT_NAME_TO_REMOVE, "Test Prompt", List.of()); Prompt prompt = new Prompt(TEST_PROMPT_NAME_TO_REMOVE, "Test Prompt", "Test Prompt", List.of());
McpServerFeatures.AsyncPromptSpecification specification = new McpServerFeatures.AsyncPromptSpecification( McpServerFeatures.AsyncPromptSpecification specification = new McpServerFeatures.AsyncPromptSpecification(
prompt, (exchange, req) -> Mono.just(new GetPromptResult("Test prompt description", List prompt, (exchange, req) -> Mono.just(new GetPromptResult("Test prompt description", List
.of(new PromptMessage(McpSchema.Role.ASSISTANT, new McpSchema.TextContent("Test content")))))); .of(new PromptMessage(McpSchema.Role.ASSISTANT, new McpSchema.TextContent("Test content"))))));

View file

@ -288,7 +288,7 @@ public abstract class AbstractMcpSyncServerTests {
.serverInfo("test-server", "1.0.0") .serverInfo("test-server", "1.0.0")
.build(); .build();
Prompt prompt = new Prompt(TEST_PROMPT_NAME, "Test Prompt", List.of()); Prompt prompt = new Prompt(TEST_PROMPT_NAME, "Test Prompt", "Test Prompt", List.of());
McpServerFeatures.SyncPromptSpecification specification = new McpServerFeatures.SyncPromptSpecification(prompt, McpServerFeatures.SyncPromptSpecification specification = new McpServerFeatures.SyncPromptSpecification(prompt,
(exchange, req) -> new GetPromptResult("Test prompt description", List (exchange, req) -> new GetPromptResult("Test prompt description", List
.of(new PromptMessage(McpSchema.Role.ASSISTANT, new McpSchema.TextContent("Test content"))))); .of(new PromptMessage(McpSchema.Role.ASSISTANT, new McpSchema.TextContent("Test content")))));
@ -309,7 +309,7 @@ public abstract class AbstractMcpSyncServerTests {
@Test @Test
void testRemovePrompt() { void testRemovePrompt() {
Prompt prompt = new Prompt(TEST_PROMPT_NAME, "Test Prompt", List.of()); Prompt prompt = new Prompt(TEST_PROMPT_NAME, "Test Prompt", "Test Prompt", List.of());
McpServerFeatures.SyncPromptSpecification specification = new McpServerFeatures.SyncPromptSpecification(prompt, McpServerFeatures.SyncPromptSpecification specification = new McpServerFeatures.SyncPromptSpecification(prompt,
(exchange, req) -> new GetPromptResult("Test prompt description", List (exchange, req) -> new GetPromptResult("Test prompt description", List
.of(new PromptMessage(McpSchema.Role.ASSISTANT, new McpSchema.TextContent("Test content"))))); .of(new PromptMessage(McpSchema.Role.ASSISTANT, new McpSchema.TextContent("Test content")))));

View file

@ -207,8 +207,8 @@ public class McpSchemaTests {
@Test @Test
void testResourceLink() throws Exception { void testResourceLink() throws Exception {
McpSchema.ResourceLink resourceLink = new McpSchema.ResourceLink("main.rs", "file:///project/src/main.rs", McpSchema.ResourceLink resourceLink = new McpSchema.ResourceLink("main.rs", "Main file",
"Primary application entry point", "text/x-rust", null, null); "file:///project/src/main.rs", "Primary application entry point", "text/x-rust", null, null);
String value = mapper.writeValueAsString(resourceLink); String value = mapper.writeValueAsString(resourceLink);
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER) assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
@ -216,7 +216,7 @@ public class McpSchemaTests {
.isObject() .isObject()
.isEqualTo( .isEqualTo(
json(""" json("""
{"type":"resource_link","name":"main.rs","uri":"file:///project/src/main.rs","description":"Primary application entry point","mimeType":"text/x-rust"}""")); {"type":"resource_link","name":"main.rs","title":"Main file","uri":"file:///project/src/main.rs","description":"Primary application entry point","mimeType":"text/x-rust"}"""));
} }
@Test @Test
@ -419,7 +419,7 @@ public class McpSchemaTests {
McpSchema.Annotations annotations = new McpSchema.Annotations(Arrays.asList(McpSchema.Role.USER), 0.5); McpSchema.Annotations annotations = new McpSchema.Annotations(Arrays.asList(McpSchema.Role.USER), 0.5);
McpSchema.ResourceTemplate template = new McpSchema.ResourceTemplate("resource://{param}/test", "Test Template", McpSchema.ResourceTemplate template = new McpSchema.ResourceTemplate("resource://{param}/test", "Test Template",
"A test resource template", "text/plain", annotations); "Test Template", "A test resource template", "text/plain", annotations);
String value = mapper.writeValueAsString(template); String value = mapper.writeValueAsString(template);
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER) assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
@ -427,7 +427,7 @@ public class McpSchemaTests {
.isObject() .isObject()
.isEqualTo( .isEqualTo(
json(""" json("""
{"uriTemplate":"resource://{param}/test","name":"Test Template","description":"A test resource template","mimeType":"text/plain","annotations":{"audience":["user"],"priority":0.5}}""")); {"uriTemplate":"resource://{param}/test","name":"Test Template","title":"Test Template","description":"A test resource template","mimeType":"text/plain","annotations":{"audience":["user"],"priority":0.5}}"""));
} }
@Test @Test
@ -453,10 +453,10 @@ public class McpSchemaTests {
@Test @Test
void testListResourceTemplatesResult() throws Exception { void testListResourceTemplatesResult() throws Exception {
McpSchema.ResourceTemplate template1 = new McpSchema.ResourceTemplate("resource://{param}/test1", McpSchema.ResourceTemplate template1 = new McpSchema.ResourceTemplate("resource://{param}/test1",
"Test Template 1", "First test template", "text/plain", null); "Test Template 1", "Test Template 1", "First test template", "text/plain", null);
McpSchema.ResourceTemplate template2 = new McpSchema.ResourceTemplate("resource://{param}/test2", McpSchema.ResourceTemplate template2 = new McpSchema.ResourceTemplate("resource://{param}/test2",
"Test Template 2", "Second test template", "application/json", null); "Test Template 2", "Test Template 2", "Second test template", "application/json", null);
McpSchema.ListResourceTemplatesResult result = new McpSchema.ListResourceTemplatesResult( McpSchema.ListResourceTemplatesResult result = new McpSchema.ListResourceTemplatesResult(
Arrays.asList(template1, template2), "next-cursor"); Arrays.asList(template1, template2), "next-cursor");
@ -467,7 +467,7 @@ public class McpSchemaTests {
.isObject() .isObject()
.isEqualTo( .isEqualTo(
json(""" json("""
{"resourceTemplates":[{"uriTemplate":"resource://{param}/test1","name":"Test Template 1","description":"First test template","mimeType":"text/plain"},{"uriTemplate":"resource://{param}/test2","name":"Test Template 2","description":"Second test template","mimeType":"application/json"}],"nextCursor":"next-cursor"}""")); {"resourceTemplates":[{"uriTemplate":"resource://{param}/test1","name":"Test Template 1","title":"Test Template 1","description":"First test template","mimeType":"text/plain"},{"uriTemplate":"resource://{param}/test2","name":"Test Template 2","title":"Test Template 2","description":"Second test template","mimeType":"application/json"}],"nextCursor":"next-cursor"}"""));
} }
@Test @Test
@ -535,11 +535,13 @@ public class McpSchemaTests {
@Test @Test
void testPrompt() throws Exception { void testPrompt() throws Exception {
McpSchema.PromptArgument arg1 = new McpSchema.PromptArgument("arg1", "First argument", true); McpSchema.PromptArgument arg1 = new McpSchema.PromptArgument("arg1", "First argument", "First argument", true);
McpSchema.PromptArgument arg2 = new McpSchema.PromptArgument("arg2", "Second argument", false); McpSchema.PromptArgument arg2 = new McpSchema.PromptArgument("arg2", "Second argument", "Second argument",
false);
McpSchema.Prompt prompt = new McpSchema.Prompt("test-prompt", "A test prompt", Arrays.asList(arg1, arg2)); McpSchema.Prompt prompt = new McpSchema.Prompt("test-prompt", "Test Prompt", "A test prompt",
Arrays.asList(arg1, arg2));
String value = mapper.writeValueAsString(prompt); String value = mapper.writeValueAsString(prompt);
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER) assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
@ -547,7 +549,7 @@ public class McpSchemaTests {
.isObject() .isObject()
.isEqualTo( .isEqualTo(
json(""" json("""
{"name":"test-prompt","description":"A test prompt","arguments":[{"name":"arg1","description":"First argument","required":true},{"name":"arg2","description":"Second argument","required":false}]}""")); {"name":"test-prompt","title":"Test Prompt","description":"A test prompt","arguments":[{"name":"arg1","title":"First argument","description":"First argument","required":true},{"name":"arg2","title":"Second argument","description":"Second argument","required":false}]}"""));
} }
@Test @Test
@ -566,11 +568,13 @@ public class McpSchemaTests {
@Test @Test
void testListPromptsResult() throws Exception { void testListPromptsResult() throws Exception {
McpSchema.PromptArgument arg = new McpSchema.PromptArgument("arg", "An argument", true); McpSchema.PromptArgument arg = new McpSchema.PromptArgument("arg", "Argument", "An argument", true);
McpSchema.Prompt prompt1 = new McpSchema.Prompt("prompt1", "First prompt", Collections.singletonList(arg)); McpSchema.Prompt prompt1 = new McpSchema.Prompt("prompt1", "First prompt", "First prompt",
Collections.singletonList(arg));
McpSchema.Prompt prompt2 = new McpSchema.Prompt("prompt2", "Second prompt", Collections.emptyList()); McpSchema.Prompt prompt2 = new McpSchema.Prompt("prompt2", "Second prompt", "Second prompt",
Collections.emptyList());
McpSchema.ListPromptsResult result = new McpSchema.ListPromptsResult(Arrays.asList(prompt1, prompt2), McpSchema.ListPromptsResult result = new McpSchema.ListPromptsResult(Arrays.asList(prompt1, prompt2),
"next-cursor"); "next-cursor");
@ -581,7 +585,7 @@ public class McpSchemaTests {
.isObject() .isObject()
.isEqualTo( .isEqualTo(
json(""" json("""
{"prompts":[{"name":"prompt1","description":"First prompt","arguments":[{"name":"arg","description":"An argument","required":true}]},{"name":"prompt2","description":"Second prompt","arguments":[]}],"nextCursor":"next-cursor"}""")); {"prompts":[{"name":"prompt1","title":"First prompt","description":"First prompt","arguments":[{"name":"arg","title":"Argument","description":"An argument","required":true}]},{"name":"prompt2","title":"Second prompt","description":"Second prompt","arguments":[]}],"nextCursor":"next-cursor"}"""));
} }
@Test @Test