Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,15 @@
import java.util.regex.Pattern;

import org.reactivestreams.Publisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

public class McpProviderUtils {

private static final Logger logger = LoggerFactory.getLogger(McpProviderUtils.class);

private static final Pattern URI_VARIABLE_PATTERN = Pattern.compile("\\{([^/]+?)\\}");

public static boolean isUriTemplate(String uri) {
Expand All @@ -40,4 +44,28 @@ public static boolean isUriTemplate(String uri) {
.isAssignableFrom(method.getReturnType()) && !Flux.class.isAssignableFrom(method.getReturnType())
&& !Publisher.class.isAssignableFrom(method.getReturnType());

public static Predicate<Method> filterNonReactiveReturnTypeMethod() {
return method -> {
if (isReactiveReturnType.test(method)) {
return true;
}
logger.info(
"Sync providers doesn't support reactive return types. Skipping method {} with reactive return type {}",
method, method.getReturnType());
return false;
};
}

public static Predicate<Method> filterReactiveReturnTypeMethod() {
return method -> {
if (isNotReactiveReturnType.test(method)) {
return true;
}
logger.info(
"Sync providers doesn't support reactive return types. Skipping method {} with reactive return type {}",
method, method.getReturnType());
return false;
};
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@
import java.util.function.Function;
import java.util.stream.Stream;

import org.springaicommunity.mcp.annotation.McpPromptListChanged;
import org.springaicommunity.mcp.method.changed.prompt.AsyncPromptListChangedSpecification;
import org.springaicommunity.mcp.method.changed.prompt.AsyncMcpPromptListChangedMethodCallback;

import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.util.Assert;
import org.springaicommunity.mcp.annotation.McpPromptListChanged;
import org.springaicommunity.mcp.method.changed.prompt.AsyncMcpPromptListChangedMethodCallback;
import org.springaicommunity.mcp.method.changed.prompt.AsyncPromptListChangedSpecification;
import org.springaicommunity.mcp.provider.McpProviderUtils;
import reactor.core.publisher.Mono;

/**
Expand Down Expand Up @@ -82,8 +82,7 @@ public List<AsyncPromptListChangedSpecification> getPromptListChangedSpecificati
.stream()
.map(consumerObject -> Stream.of(doGetClassMethods(consumerObject))
.filter(method -> method.isAnnotationPresent(McpPromptListChanged.class))
.filter(method -> method.getReturnType() == void.class
|| Mono.class.isAssignableFrom(method.getReturnType()))
.filter(McpProviderUtils.filterNonReactiveReturnTypeMethod())
.sorted((m1, m2) -> m1.getName().compareTo(m2.getName()))
.map(mcpPromptListChangedConsumerMethod -> {
var promptListChangedAnnotation = mcpPromptListChangedConsumerMethod
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,12 @@
import java.util.function.Consumer;
import java.util.stream.Stream;

import org.springaicommunity.mcp.annotation.McpPromptListChanged;
import org.springaicommunity.mcp.method.changed.prompt.SyncPromptListChangedSpecification;
import org.springaicommunity.mcp.method.changed.prompt.SyncMcpPromptListChangedMethodCallback;

import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.util.Assert;
import reactor.core.publisher.Mono;
import org.springaicommunity.mcp.annotation.McpPromptListChanged;
import org.springaicommunity.mcp.method.changed.prompt.SyncMcpPromptListChangedMethodCallback;
import org.springaicommunity.mcp.method.changed.prompt.SyncPromptListChangedSpecification;
import org.springaicommunity.mcp.provider.McpProviderUtils;

/**
* Provider for synchronous prompt list changed consumer callbacks.
Expand Down Expand Up @@ -81,7 +80,7 @@ public List<SyncPromptListChangedSpecification> getPromptListChangedSpecificatio
.stream()
.map(consumerObject -> Stream.of(doGetClassMethods(consumerObject))
.filter(method -> method.isAnnotationPresent(McpPromptListChanged.class))
.filter(method -> !Mono.class.isAssignableFrom(method.getReturnType()))
.filter(McpProviderUtils.filterReactiveReturnTypeMethod())
.sorted((m1, m2) -> m1.getName().compareTo(m2.getName()))
.map(mcpPromptListChangedConsumerMethod -> {
var promptListChangedAnnotation = mcpPromptListChangedConsumerMethod
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@
import java.util.function.Function;
import java.util.stream.Stream;

import org.springaicommunity.mcp.annotation.McpResourceListChanged;
import org.springaicommunity.mcp.method.changed.resource.AsyncResourceListChangedSpecification;
import org.springaicommunity.mcp.method.changed.resource.AsyncMcpResourceListChangedMethodCallback;

import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.util.Assert;
import org.springaicommunity.mcp.annotation.McpResourceListChanged;
import org.springaicommunity.mcp.method.changed.resource.AsyncMcpResourceListChangedMethodCallback;
import org.springaicommunity.mcp.method.changed.resource.AsyncResourceListChangedSpecification;
import org.springaicommunity.mcp.provider.McpProviderUtils;
import reactor.core.publisher.Mono;

/**
Expand Down Expand Up @@ -82,8 +82,7 @@ public List<AsyncResourceListChangedSpecification> getResourceListChangedSpecifi
.stream()
.map(consumerObject -> Stream.of(doGetClassMethods(consumerObject))
.filter(method -> method.isAnnotationPresent(McpResourceListChanged.class))
.filter(method -> method.getReturnType() == void.class
|| Mono.class.isAssignableFrom(method.getReturnType()))
.filter(McpProviderUtils.filterNonReactiveReturnTypeMethod())
.sorted((m1, m2) -> m1.getName().compareTo(m2.getName()))
.map(mcpResourceListChangedConsumerMethod -> {
var resourceListChangedAnnotation = mcpResourceListChangedConsumerMethod
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,12 @@
import java.util.function.Consumer;
import java.util.stream.Stream;

import org.springaicommunity.mcp.annotation.McpResourceListChanged;
import org.springaicommunity.mcp.method.changed.resource.SyncResourceListChangedSpecification;
import org.springaicommunity.mcp.method.changed.resource.SyncMcpResourceListChangedMethodCallback;

import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.util.Assert;
import reactor.core.publisher.Mono;
import org.springaicommunity.mcp.annotation.McpResourceListChanged;
import org.springaicommunity.mcp.method.changed.resource.SyncMcpResourceListChangedMethodCallback;
import org.springaicommunity.mcp.method.changed.resource.SyncResourceListChangedSpecification;
import org.springaicommunity.mcp.provider.McpProviderUtils;

/**
* Provider for synchronous resource list changed consumer callbacks.
Expand Down Expand Up @@ -81,7 +80,7 @@ public List<SyncResourceListChangedSpecification> getResourceListChangedSpecific
.stream()
.map(consumerObject -> Stream.of(doGetClassMethods(consumerObject))
.filter(method -> method.isAnnotationPresent(McpResourceListChanged.class))
.filter(method -> !Mono.class.isAssignableFrom(method.getReturnType()))
.filter(McpProviderUtils.filterReactiveReturnTypeMethod())
.sorted((m1, m2) -> m1.getName().compareTo(m2.getName()))
.map(mcpResourceListChangedConsumerMethod -> {
var resourceListChangedAnnotation = mcpResourceListChangedConsumerMethod
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@
import java.util.function.Function;
import java.util.stream.Stream;

import org.springaicommunity.mcp.annotation.McpToolListChanged;
import org.springaicommunity.mcp.method.changed.tool.AsyncToolListChangedSpecification;
import org.springaicommunity.mcp.method.changed.tool.AsyncMcpToolListChangedMethodCallback;

import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.util.Assert;
import org.springaicommunity.mcp.annotation.McpToolListChanged;
import org.springaicommunity.mcp.method.changed.tool.AsyncMcpToolListChangedMethodCallback;
import org.springaicommunity.mcp.method.changed.tool.AsyncToolListChangedSpecification;
import org.springaicommunity.mcp.provider.McpProviderUtils;
import reactor.core.publisher.Mono;

/**
Expand Down Expand Up @@ -81,8 +81,7 @@ public List<AsyncToolListChangedSpecification> getToolListChangedSpecifications(
List<AsyncToolListChangedSpecification> toolListChangedConsumers = this.toolListChangedConsumerObjects.stream()
.map(consumerObject -> Stream.of(doGetClassMethods(consumerObject))
.filter(method -> method.isAnnotationPresent(McpToolListChanged.class))
.filter(method -> method.getReturnType() == void.class
|| Mono.class.isAssignableFrom(method.getReturnType()))
.filter(McpProviderUtils.filterNonReactiveReturnTypeMethod())
.sorted((m1, m2) -> m1.getName().compareTo(m2.getName()))
.map(mcpToolListChangedConsumerMethod -> {
var toolListChangedAnnotation = mcpToolListChangedConsumerMethod
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,12 @@
import java.util.function.Consumer;
import java.util.stream.Stream;

import org.springaicommunity.mcp.annotation.McpToolListChanged;
import org.springaicommunity.mcp.method.changed.tool.SyncToolListChangedSpecification;
import org.springaicommunity.mcp.method.changed.tool.SyncMcpToolListChangedMethodCallback;

import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.util.Assert;
import reactor.core.publisher.Mono;
import org.springaicommunity.mcp.annotation.McpToolListChanged;
import org.springaicommunity.mcp.method.changed.tool.SyncMcpToolListChangedMethodCallback;
import org.springaicommunity.mcp.method.changed.tool.SyncToolListChangedSpecification;
import org.springaicommunity.mcp.provider.McpProviderUtils;

/**
* Provider for synchronous tool list changed consumer callbacks.
Expand Down Expand Up @@ -80,7 +79,7 @@ public List<SyncToolListChangedSpecification> getToolListChangedSpecifications()
List<SyncToolListChangedSpecification> toolListChangedConsumers = this.toolListChangedConsumerObjects.stream()
.map(consumerObject -> Stream.of(doGetClassMethods(consumerObject))
.filter(method -> method.isAnnotationPresent(McpToolListChanged.class))
.filter(method -> !Mono.class.isAssignableFrom(method.getReturnType()))
.filter(McpProviderUtils.filterReactiveReturnTypeMethod())
.sorted((m1, m2) -> m1.getName().compareTo(m2.getName()))
.map(mcpToolListChangedConsumerMethod -> {
var toolListChangedAnnotation = mcpToolListChangedConsumerMethod
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,12 @@
import io.modelcontextprotocol.server.McpAsyncServerExchange;
import io.modelcontextprotocol.server.McpServerFeatures.AsyncCompletionSpecification;
import io.modelcontextprotocol.util.Assert;
import org.reactivestreams.Publisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springaicommunity.mcp.adapter.CompleteAdapter;
import org.springaicommunity.mcp.annotation.McpComplete;
import org.springaicommunity.mcp.method.complete.AsyncMcpCompleteMethodCallback;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springaicommunity.mcp.provider.McpProviderUtils;

/**
* Provider for asynchronous MCP complete methods.
Expand Down Expand Up @@ -66,9 +64,7 @@ public List<AsyncCompletionSpecification> getCompleteSpecifications() {
List<AsyncCompletionSpecification> asyncCompleteSpecification = this.completeObjects.stream()
.map(completeObject -> Stream.of(doGetClassMethods(completeObject))
.filter(method -> method.isAnnotationPresent(McpComplete.class))
.filter(method -> Mono.class.isAssignableFrom(method.getReturnType())
|| Flux.class.isAssignableFrom(method.getReturnType())
|| Publisher.class.isAssignableFrom(method.getReturnType()))
.filter(McpProviderUtils.filterNonReactiveReturnTypeMethod())
.sorted((m1, m2) -> m1.getName().compareTo(m2.getName()))
.map(mcpCompleteMethod -> {
var completeAnnotation = mcpCompleteMethod.getAnnotation(McpComplete.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,12 @@
import io.modelcontextprotocol.spec.McpSchema.CompleteRequest;
import io.modelcontextprotocol.spec.McpSchema.CompleteResult;
import io.modelcontextprotocol.util.Assert;
import org.reactivestreams.Publisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springaicommunity.mcp.adapter.CompleteAdapter;
import org.springaicommunity.mcp.annotation.McpComplete;
import org.springaicommunity.mcp.method.complete.AsyncStatelessMcpCompleteMethodCallback;
import reactor.core.publisher.Flux;
import org.springaicommunity.mcp.provider.McpProviderUtils;
import reactor.core.publisher.Mono;

/**
Expand Down Expand Up @@ -69,9 +68,7 @@ public List<AsyncCompletionSpecification> getCompleteSpecifications() {
List<AsyncCompletionSpecification> completeSpecs = this.completeObjects.stream()
.map(completeObject -> Stream.of(doGetClassMethods(completeObject))
.filter(method -> method.isAnnotationPresent(McpComplete.class))
.filter(method -> Mono.class.isAssignableFrom(method.getReturnType())
|| Flux.class.isAssignableFrom(method.getReturnType())
|| Publisher.class.isAssignableFrom(method.getReturnType()))
.filter(McpProviderUtils.filterNonReactiveReturnTypeMethod())
.sorted((m1, m2) -> m1.getName().compareTo(m2.getName()))
.map(mcpCompleteMethod -> {
var completeAnnotation = mcpCompleteMethod.getAnnotation(McpComplete.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import org.springaicommunity.mcp.adapter.CompleteAdapter;
import org.springaicommunity.mcp.annotation.McpComplete;
import org.springaicommunity.mcp.method.complete.SyncMcpCompleteMethodCallback;
import reactor.core.publisher.Mono;
import org.springaicommunity.mcp.provider.McpProviderUtils;

/**
*/
Expand All @@ -43,7 +43,7 @@ public List<SyncCompletionSpecification> getCompleteSpecifications() {
List<SyncCompletionSpecification> syncCompleteSpecification = this.completeObjects.stream()
.map(completeObject -> Stream.of(doGetClassMethods(completeObject))
.filter(method -> method.isAnnotationPresent(McpComplete.class))
.filter(method -> !Mono.class.isAssignableFrom(method.getReturnType()))
.filter(McpProviderUtils.filterReactiveReturnTypeMethod())
.sorted((m1, m2) -> m1.getName().compareTo(m2.getName()))
.map(mcpCompleteMethod -> {
var completeAnnotation = mcpCompleteMethod.getAnnotation(McpComplete.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
import org.springaicommunity.mcp.adapter.CompleteAdapter;
import org.springaicommunity.mcp.annotation.McpComplete;
import org.springaicommunity.mcp.method.complete.SyncStatelessMcpCompleteMethodCallback;
import reactor.core.publisher.Mono;
import org.springaicommunity.mcp.provider.McpProviderUtils;

/**
* Provider for synchronous stateless MCP complete methods.
Expand Down Expand Up @@ -67,7 +67,7 @@ public List<SyncCompletionSpecification> getCompleteSpecifications() {
List<SyncCompletionSpecification> completeSpecs = this.completeObjects.stream()
.map(completeObject -> Stream.of(doGetClassMethods(completeObject))
.filter(method -> method.isAnnotationPresent(McpComplete.class))
.filter(method -> !Mono.class.isAssignableFrom(method.getReturnType()))
.filter(McpProviderUtils.filterReactiveReturnTypeMethod())
.sorted((m1, m2) -> m1.getName().compareTo(m2.getName()))
.map(mcpCompleteMethod -> {
var completeAnnotation = mcpCompleteMethod.getAnnotation(McpComplete.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
import org.springaicommunity.mcp.annotation.McpElicitation;
import org.springaicommunity.mcp.method.elicitation.AsyncElicitationSpecification;
import org.springaicommunity.mcp.method.elicitation.AsyncMcpElicitationMethodCallback;

import org.springaicommunity.mcp.provider.McpProviderUtils;
import io.modelcontextprotocol.spec.McpSchema.ElicitRequest;
import io.modelcontextprotocol.spec.McpSchema.ElicitResult;
import io.modelcontextprotocol.util.Assert;
Expand Down Expand Up @@ -89,8 +89,7 @@ public List<AsyncElicitationSpecification> getElicitationSpecifications() {
.filter(method -> method.isAnnotationPresent(McpElicitation.class))
.filter(method -> method.getParameterCount() == 1
&& ElicitRequest.class.isAssignableFrom(method.getParameterTypes()[0]))
.filter(method -> Mono.class.isAssignableFrom(method.getReturnType())
|| ElicitResult.class.isAssignableFrom(method.getReturnType()))
.filter(McpProviderUtils.filterNonReactiveReturnTypeMethod())
.sorted((m1, m2) -> m1.getName().compareTo(m2.getName()))
.map(mcpElicitationMethod -> {
var elicitationAnnotation = mcpElicitationMethod.getAnnotation(McpElicitation.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,15 @@
import java.util.function.Function;
import java.util.stream.Stream;

import io.modelcontextprotocol.spec.McpSchema.ElicitRequest;
import io.modelcontextprotocol.spec.McpSchema.ElicitResult;
import io.modelcontextprotocol.util.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springaicommunity.mcp.annotation.McpElicitation;
import org.springaicommunity.mcp.method.elicitation.SyncElicitationSpecification;
import org.springaicommunity.mcp.method.elicitation.SyncMcpElicitationMethodCallback;

import io.modelcontextprotocol.spec.McpSchema.ElicitRequest;
import io.modelcontextprotocol.spec.McpSchema.ElicitResult;
import io.modelcontextprotocol.util.Assert;
import reactor.core.publisher.Mono;
import org.springaicommunity.mcp.provider.McpProviderUtils;

/**
* Provider for synchronous elicitation callbacks.
Expand Down Expand Up @@ -87,7 +86,7 @@ public List<SyncElicitationSpecification> getElicitationSpecifications() {
List<SyncElicitationSpecification> elicitationHandlers = this.elicitationObjects.stream()
.map(elicitationObject -> Stream.of(doGetClassMethods(elicitationObject))
.filter(method -> method.isAnnotationPresent(McpElicitation.class))
.filter(method -> !Mono.class.isAssignableFrom(method.getReturnType()))
.filter(McpProviderUtils.filterReactiveReturnTypeMethod())
.filter(method -> ElicitResult.class.isAssignableFrom(method.getReturnType()))
.filter(method -> method.getParameterCount() == 1
&& ElicitRequest.class.isAssignableFrom(method.getParameterTypes()[0]))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import org.springaicommunity.mcp.annotation.McpLogging;
import org.springaicommunity.mcp.method.logging.AsyncLoggingSpecification;
import org.springaicommunity.mcp.method.logging.AsyncMcpLoggingMethodCallback;

import org.springaicommunity.mcp.provider.McpProviderUtils;
import io.modelcontextprotocol.spec.McpSchema.LoggingMessageNotification;
import io.modelcontextprotocol.util.Assert;
import reactor.core.publisher.Mono;
Expand Down Expand Up @@ -80,6 +80,7 @@ public List<AsyncLoggingSpecification> getLoggingSpecifications() {
List<AsyncLoggingSpecification> loggingConsumers = this.loggingConsumerObjects.stream()
.map(consumerObject -> Stream.of(this.doGetClassMethods(consumerObject))
.filter(method -> method.isAnnotationPresent(McpLogging.class))
.filter(McpProviderUtils.filterNonReactiveReturnTypeMethod())
.sorted((m1, m2) -> m1.getName().compareTo(m2.getName()))
.map(mcpLoggingConsumerMethod -> {
var loggingConsumerAnnotation = mcpLoggingConsumerMethod.getAnnotation(McpLogging.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,12 @@
import java.util.function.Consumer;
import java.util.stream.Stream;

import io.modelcontextprotocol.spec.McpSchema.LoggingMessageNotification;
import io.modelcontextprotocol.util.Assert;
import org.springaicommunity.mcp.annotation.McpLogging;
import org.springaicommunity.mcp.method.logging.SyncLoggingSpecification;
import org.springaicommunity.mcp.method.logging.SyncMcpLoggingMethodCallback;

import io.modelcontextprotocol.spec.McpSchema.LoggingMessageNotification;
import io.modelcontextprotocol.util.Assert;
import reactor.core.publisher.Mono;
import org.springaicommunity.mcp.provider.McpProviderUtils;

/**
* Provider for synchronous logging consumer callbacks.
Expand Down Expand Up @@ -82,7 +81,7 @@ public List<SyncLoggingSpecification> getLoggingSpecifications() {
List<SyncLoggingSpecification> loggingConsumers = this.loggingConsumerObjects.stream()
.map(consumerObject -> Stream.of(doGetClassMethods(consumerObject))
.filter(method -> method.isAnnotationPresent(McpLogging.class))
.filter(method -> !Mono.class.isAssignableFrom(method.getReturnType()))
.filter(McpProviderUtils.filterReactiveReturnTypeMethod())
.sorted((m1, m2) -> m1.getName().compareTo(m2.getName()))
.map(mcpLoggingConsumerMethod -> {
var loggingConsumerAnnotation = mcpLoggingConsumerMethod.getAnnotation(McpLogging.class);
Expand Down
Loading