feat: Add customizable URI template manager factory to MCP server
Implement URI template functionality for MCP resources, allowing dynamic
resource URIs with variables in the format {variableName}.
- Enable resource URIs with variable placeholders (e.g., "/api/users/{userId}")
- Automatic extraction of variable values from request URIs
- Validation of template arguments in completions
- Matching of request URIs against templates
- Add new URI template management interfaces and implementations
- Enhanced resource template listing to include templated resources
- Updated resource request handling to support template matching
- Test coverage for URI template functionality
- Adding a configurable uriTemplateManagerFactory field to both AsyncSpecification and SyncSpecification classes
- Adding builder methods to allow setting a custom URI template manager factory
- Modifying constructors to pass the URI template manager factory to the server implementation
- Updating the server implementation to use the provided factory
- Add bulk registration methods for async completions
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
This commit is contained in:
parent
261554bb7f
commit
e610d853f9
1 changed files with 489 additions and 16 deletions
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright 2025-2025 the original author or authors.
|
||||
*/
|
||||
|
||||
package io.modelcontextprotocol;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.modelcontextprotocol.util.DeafaultMcpUriTemplateManagerFactory;
|
||||
import io.modelcontextprotocol.util.McpUriTemplateManager;
|
||||
import io.modelcontextprotocol.util.McpUriTemplateManagerFactory;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Tests for {@link McpUriTemplateManager} and its implementations.
|
||||
*
|
||||
* @author Christian Tzolov
|
||||
*/
|
||||
public class McpUriTemplateManagerTests {
|
||||
|
||||
private McpUriTemplateManagerFactory uriTemplateFactory;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
this.uriTemplateFactory = new DeafaultMcpUriTemplateManagerFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldExtractVariableNamesFromTemplate() {
|
||||
List<String> variables = this.uriTemplateFactory.create("/api/users/{userId}/posts/{postId}")
|
||||
.getVariableNames();
|
||||
assertEquals(2, variables.size());
|
||||
assertEquals("userId", variables.get(0));
|
||||
assertEquals("postId", variables.get(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnEmptyListWhenTemplateHasNoVariables() {
|
||||
List<String> variables = this.uriTemplateFactory.create("/api/users/all").getVariableNames();
|
||||
assertEquals(0, variables.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionWhenExtractingVariablesFromNullTemplate() {
|
||||
assertThrows(IllegalArgumentException.class, () -> this.uriTemplateFactory.create(null).getVariableNames());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionWhenExtractingVariablesFromEmptyTemplate() {
|
||||
assertThrows(IllegalArgumentException.class, () -> this.uriTemplateFactory.create("").getVariableNames());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionWhenTemplateContainsDuplicateVariables() {
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> this.uriTemplateFactory.create("/api/users/{userId}/posts/{userId}").getVariableNames());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldExtractVariableValuesFromRequestUri() {
|
||||
Map<String, String> values = this.uriTemplateFactory.create("/api/users/{userId}/posts/{postId}")
|
||||
.extractVariableValues("/api/users/123/posts/456");
|
||||
assertEquals(2, values.size());
|
||||
assertEquals("123", values.get("userId"));
|
||||
assertEquals("456", values.get("postId"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnEmptyMapWhenTemplateHasNoVariables() {
|
||||
Map<String, String> values = this.uriTemplateFactory.create("/api/users/all")
|
||||
.extractVariableValues("/api/users/all");
|
||||
assertEquals(0, values.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnEmptyMapWhenRequestUriIsNull() {
|
||||
Map<String, String> values = this.uriTemplateFactory.create("/api/users/{userId}/posts/{postId}")
|
||||
.extractVariableValues(null);
|
||||
assertEquals(0, values.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldMatchUriAgainstTemplatePattern() {
|
||||
var uriTemplateManager = this.uriTemplateFactory.create("/api/users/{userId}/posts/{postId}");
|
||||
|
||||
assertTrue(uriTemplateManager.matches("/api/users/123/posts/456"));
|
||||
assertFalse(uriTemplateManager.matches("/api/users/123/comments/456"));
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in a new issue