Skip to content

Commit 6212c19

Browse files
committed
refactor(server): Replace factory classes with concrete server implementations and streamline server component registration
1 parent f41212f commit 6212c19

23 files changed

+246
-166
lines changed

src/main/java/com/github/codeboyzhou/mcp/declarative/McpServers.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77
import com.github.codeboyzhou.mcp.declarative.di.GuiceDependencyInjector;
88
import com.github.codeboyzhou.mcp.declarative.di.GuiceInjectorModule;
99
import com.github.codeboyzhou.mcp.declarative.server.McpServerInfo;
10-
import com.github.codeboyzhou.mcp.declarative.server.factory.McpSseServerFactory;
10+
import com.github.codeboyzhou.mcp.declarative.server.factory.McpSseServer;
1111
import com.github.codeboyzhou.mcp.declarative.server.factory.McpSseServerInfo;
12-
import com.github.codeboyzhou.mcp.declarative.server.factory.McpStdioServerFactory;
13-
import com.github.codeboyzhou.mcp.declarative.server.factory.McpStreamableServerFactory;
12+
import com.github.codeboyzhou.mcp.declarative.server.factory.McpStdioServer;
13+
import com.github.codeboyzhou.mcp.declarative.server.factory.McpStreamableServer;
1414
import com.github.codeboyzhou.mcp.declarative.server.factory.McpStreamableServerInfo;
15-
import com.github.codeboyzhou.mcp.declarative.server.factory.configurable.ConfigurableMcpServerFactories;
15+
import com.github.codeboyzhou.mcp.declarative.server.factory.configurable.ConfigurableMcpServerFactory;
1616
import com.google.inject.Guice;
1717
import io.modelcontextprotocol.util.Assert;
1818
import org.slf4j.Logger;
@@ -39,15 +39,15 @@ public static McpServers run(Class<?> applicationMainClass, String[] args) {
3939
}
4040

4141
public void startStdioServer(McpServerInfo serverInfo) {
42-
injector.getInstance(McpStdioServerFactory.class).startServer(serverInfo);
42+
injector.getInstance(McpStdioServer.class).start(serverInfo);
4343
}
4444

4545
public void startSseServer(McpSseServerInfo serverInfo) {
46-
injector.getInstance(McpSseServerFactory.class).startServer(serverInfo);
46+
injector.getInstance(McpSseServer.class).start(serverInfo);
4747
}
4848

4949
public void startStreamableServer(McpStreamableServerInfo serverInfo) {
50-
injector.getInstance(McpStreamableServerFactory.class).startServer(serverInfo);
50+
injector.getInstance(McpStreamableServer.class).start(serverInfo);
5151
}
5252

5353
public void startServer(String configFileName) {
@@ -63,7 +63,7 @@ public void startServer() {
6363

6464
private void doStartServer(McpServerConfiguration configuration) {
6565
if (configuration.enabled()) {
66-
ConfigurableMcpServerFactories.getFactory(configuration).startServer();
66+
ConfigurableMcpServerFactory.getServer(configuration).startServer();
6767
} else {
6868
log.warn("MCP server is disabled, please check your configuration file.");
6969
}

src/main/java/com/github/codeboyzhou/mcp/declarative/di/GuiceInjectorModule.java

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@
1010
import com.github.codeboyzhou.mcp.declarative.annotation.McpResource;
1111
import com.github.codeboyzhou.mcp.declarative.annotation.McpServerApplication;
1212
import com.github.codeboyzhou.mcp.declarative.annotation.McpTool;
13-
import com.github.codeboyzhou.mcp.declarative.server.component.McpServerPromptFactory;
14-
import com.github.codeboyzhou.mcp.declarative.server.component.McpServerResourceFactory;
15-
import com.github.codeboyzhou.mcp.declarative.server.component.McpServerToolFactory;
13+
import com.github.codeboyzhou.mcp.declarative.server.component.McpServerPrompt;
14+
import com.github.codeboyzhou.mcp.declarative.server.component.McpServerResource;
15+
import com.github.codeboyzhou.mcp.declarative.server.component.McpServerTool;
1616
import com.github.codeboyzhou.mcp.declarative.server.converter.McpPromptParameterConverter;
1717
import com.github.codeboyzhou.mcp.declarative.server.converter.McpToolParameterConverter;
18-
import com.github.codeboyzhou.mcp.declarative.server.factory.McpSseServerFactory;
19-
import com.github.codeboyzhou.mcp.declarative.server.factory.McpStdioServerFactory;
20-
import com.github.codeboyzhou.mcp.declarative.server.factory.McpStreamableServerFactory;
18+
import com.github.codeboyzhou.mcp.declarative.server.factory.McpSseServer;
19+
import com.github.codeboyzhou.mcp.declarative.server.factory.McpStdioServer;
20+
import com.github.codeboyzhou.mcp.declarative.server.factory.McpStreamableServer;
2121
import com.google.inject.AbstractModule;
2222
import com.google.inject.Provides;
2323
import com.google.inject.Singleton;
@@ -45,18 +45,18 @@ protected void configure() {
4545
bindClassesOfMethodsAnnotatedWith(McpTool.class);
4646

4747
// Bind all implementations of McpServerComponentFactory
48-
bind(McpServerResourceFactory.class).in(SINGLETON);
49-
bind(McpServerPromptFactory.class).in(SINGLETON);
50-
bind(McpServerToolFactory.class).in(SINGLETON);
48+
bind(McpServerResource.class).in(SINGLETON);
49+
bind(McpServerPrompt.class).in(SINGLETON);
50+
bind(McpServerTool.class).in(SINGLETON);
5151

5252
// Bind all implementations of ParameterConverter
5353
bind(McpPromptParameterConverter.class).in(SINGLETON);
5454
bind(McpToolParameterConverter.class).in(SINGLETON);
5555

5656
// Bind all implementations of McpServerFactory
57-
bind(McpStdioServerFactory.class).in(SINGLETON);
58-
bind(McpSseServerFactory.class).in(SINGLETON);
59-
bind(McpStreamableServerFactory.class).in(SINGLETON);
57+
bind(McpStdioServer.class).in(SINGLETON);
58+
bind(McpSseServer.class).in(SINGLETON);
59+
bind(McpStreamableServer.class).in(SINGLETON);
6060

6161
// Bind for boolean variable: i18nEnabled
6262
final boolean i18nEnabled = mainClass.isAnnotationPresent(McpI18nEnabled.class);

src/main/java/com/github/codeboyzhou/mcp/declarative/reflect/MethodMetadata.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package com.github.codeboyzhou.mcp.declarative.reflect;
22

3+
import com.github.codeboyzhou.mcp.declarative.annotation.McpPrompt;
4+
import com.github.codeboyzhou.mcp.declarative.annotation.McpResource;
5+
import com.github.codeboyzhou.mcp.declarative.annotation.McpTool;
36
import com.github.codeboyzhou.mcp.declarative.common.Immutable;
47
import java.lang.reflect.Method;
58
import java.lang.reflect.Parameter;
@@ -9,14 +12,29 @@ public final class MethodMetadata {
912

1013
private final Immutable<Method> method;
1114

15+
private final String methodName;
16+
17+
private final Class<?> declaringClass;
18+
1219
private final Parameter[] parameters;
1320

1421
private final String methodSignature;
1522

23+
private final McpResource mcpResourceAnnotation;
24+
25+
private final McpPrompt mcpPromptAnnotation;
26+
27+
private final McpTool mcpToolAnnotation;
28+
1629
public MethodMetadata(Method method) {
1730
this.method = Immutable.of(method);
31+
this.methodName = method.getName();
32+
this.declaringClass = method.getDeclaringClass();
1833
this.parameters = method.getParameters();
1934
this.methodSignature = method.toGenericString();
35+
this.mcpResourceAnnotation = method.getAnnotation(McpResource.class);
36+
this.mcpPromptAnnotation = method.getAnnotation(McpPrompt.class);
37+
this.mcpToolAnnotation = method.getAnnotation(McpTool.class);
2038
}
2139

2240
public static MethodMetadata of(Method method) {
@@ -27,6 +45,14 @@ public Method getMethod() {
2745
return method.get();
2846
}
2947

48+
public String getMethodName() {
49+
return methodName;
50+
}
51+
52+
public Class<?> getDeclaringClass() {
53+
return declaringClass;
54+
}
55+
3056
public Parameter[] getParameters() {
3157
return parameters.clone();
3258
}
@@ -35,6 +61,18 @@ public String getMethodSignature() {
3561
return methodSignature;
3662
}
3763

64+
public McpResource getMcpResourceAnnotation() {
65+
return mcpResourceAnnotation;
66+
}
67+
68+
public McpPrompt getMcpPromptAnnotation() {
69+
return mcpPromptAnnotation;
70+
}
71+
72+
public McpTool getMcpToolAnnotation() {
73+
return mcpToolAnnotation;
74+
}
75+
3876
@Override
3977
public boolean equals(Object obj) {
4078
if (this == obj) {
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
import org.slf4j.Logger;
1111
import org.slf4j.LoggerFactory;
1212

13-
public abstract class AbstractMcpServerComponentFactory<T> implements McpServerComponentFactory<T> {
13+
public abstract class AbstractMcpServerComponent<T, U, R>
14+
implements McpServerComponent<T>, McpServerComponentHandler<U, R> {
1415

15-
private static final Logger log =
16-
LoggerFactory.getLogger(AbstractMcpServerComponentFactory.class);
16+
private static final Logger log = LoggerFactory.getLogger(AbstractMcpServerComponent.class);
1717

1818
private static final String RESOURCE_BUNDLE_BASE_NAME = "i18n/mcp_server_component_descriptions";
1919

@@ -25,7 +25,7 @@ public abstract class AbstractMcpServerComponentFactory<T> implements McpServerC
2525

2626
private final boolean i18nEnabled;
2727

28-
protected AbstractMcpServerComponentFactory() {
28+
protected AbstractMcpServerComponent() {
2929
this.bundle = loadResourceBundle();
3030
this.injector = DependencyInjectorProvider.INSTANCE.getInjector();
3131
this.i18nEnabled = injector.getVariable(Boolean.class, INJECTED_VARIABLE_NAME_I18N_ENABLED);
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22

33
import java.lang.reflect.Method;
44

5-
public interface McpServerComponentFactory<T> {
6-
T create(Class<?> clazz, Method method);
5+
public interface McpServerComponent<T> {
6+
T create(Method method);
77
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.github.codeboyzhou.mcp.declarative.server.component;
2+
3+
import io.modelcontextprotocol.server.McpSyncServerExchange;
4+
import java.util.function.BiFunction;
5+
6+
public interface McpServerComponentHandler<U, R> extends BiFunction<McpSyncServerExchange, U, R> {}

src/main/java/com/github/codeboyzhou/mcp/declarative/server/component/McpServerComponentRegister.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,21 +32,20 @@ public static McpServerComponentRegister of(McpSyncServer server) {
3232
}
3333

3434
public void registerComponents() {
35-
register(McpResource.class, McpServerResourceFactory.class, McpSyncServer::addResource);
36-
register(McpPrompt.class, McpServerPromptFactory.class, McpSyncServer::addPrompt);
37-
register(McpTool.class, McpServerToolFactory.class, McpSyncServer::addTool);
35+
register(McpResource.class, McpServerResource.class, McpSyncServer::addResource);
36+
register(McpPrompt.class, McpServerPrompt.class, McpSyncServer::addPrompt);
37+
register(McpTool.class, McpServerTool.class, McpSyncServer::addTool);
3838
}
3939

4040
private <T> void register(
4141
Class<? extends Annotation> annotationClass,
42-
Class<? extends McpServerComponentFactory<T>> factoryClass,
42+
Class<? extends McpServerComponent<T>> componentClass,
4343
BiConsumer<McpSyncServer, T> serverAddComponent) {
4444

4545
Set<Method> methods = reflections.getMethodsAnnotatedWith(annotationClass);
46-
McpServerComponentFactory<T> factory = injector.getInstance(factoryClass);
46+
McpServerComponent<T> component = injector.getInstance(componentClass);
4747
for (Method method : methods) {
48-
T component = factory.create(method.getDeclaringClass(), method);
49-
serverAddComponent.accept(server.get(), component);
48+
serverAddComponent.accept(server.get(), component.create(method));
5049
}
5150
}
5251
}
Lines changed: 46 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.github.codeboyzhou.mcp.declarative.util.ObjectMappers;
99
import com.github.codeboyzhou.mcp.declarative.util.Strings;
1010
import io.modelcontextprotocol.server.McpServerFeatures;
11+
import io.modelcontextprotocol.server.McpSyncServerExchange;
1112
import io.modelcontextprotocol.spec.McpSchema;
1213
import java.lang.reflect.Method;
1314
import java.lang.reflect.Parameter;
@@ -17,54 +18,67 @@
1718
import org.slf4j.Logger;
1819
import org.slf4j.LoggerFactory;
1920

20-
public class McpServerPromptFactory
21-
extends AbstractMcpServerComponentFactory<McpServerFeatures.SyncPromptSpecification> {
21+
public class McpServerPrompt
22+
extends AbstractMcpServerComponent<
23+
McpServerFeatures.SyncPromptSpecification,
24+
McpSchema.GetPromptRequest,
25+
McpSchema.GetPromptResult> {
2226

23-
private static final Logger log = LoggerFactory.getLogger(McpServerPromptFactory.class);
27+
private static final Logger log = LoggerFactory.getLogger(McpServerPrompt.class);
28+
29+
private final McpPromptParameterConverter converter;
30+
31+
private MethodMetadata methodCache;
32+
33+
private Object instance;
34+
35+
private String description;
36+
37+
public McpServerPrompt() {
38+
this.converter = injector.getInstance(McpPromptParameterConverter.class);
39+
}
2440

2541
@Override
26-
public McpServerFeatures.SyncPromptSpecification create(Class<?> clazz, Method method) {
42+
public McpServerFeatures.SyncPromptSpecification create(Method method) {
2743
// Use reflection cache for performance optimization
28-
MethodMetadata metadata = ReflectionCache.INSTANCE.getMethodMetadata(method);
44+
methodCache = ReflectionCache.INSTANCE.getMethodMetadata(method);
45+
instance = injector.getInstance(methodCache.getDeclaringClass());
2946

30-
McpPrompt promptMethod = method.getAnnotation(McpPrompt.class);
31-
final String name = Strings.defaultIfBlank(promptMethod.name(), method.getName());
47+
McpPrompt promptMethod = methodCache.getMcpPromptAnnotation();
48+
final String name = Strings.defaultIfBlank(promptMethod.name(), methodCache.getMethodName());
3249
final String title = resolveComponentAttributeValue(promptMethod.title());
33-
final String description = resolveComponentAttributeValue(promptMethod.description());
50+
description = resolveComponentAttributeValue(promptMethod.description());
3451

35-
List<McpSchema.PromptArgument> promptArguments = createPromptArguments(metadata);
52+
List<McpSchema.PromptArgument> promptArguments = createPromptArguments();
3653
McpSchema.Prompt prompt = new McpSchema.Prompt(name, title, description, promptArguments);
3754

3855
log.debug(
3956
"Registering prompt: {} (Cached: {})",
4057
ObjectMappers.toJson(prompt),
4158
ReflectionCache.INSTANCE.isCached(method));
4259

43-
Object instance = injector.getInstance(clazz);
44-
McpPromptParameterConverter converter = injector.getInstance(McpPromptParameterConverter.class);
45-
46-
return new McpServerFeatures.SyncPromptSpecification(
47-
prompt,
48-
(exchange, request) -> {
49-
Object result;
50-
try {
51-
Map<String, Object> arguments = request.arguments();
52-
List<Object> convertedParams = converter.convertAllParameters(metadata, arguments);
53-
// Use cached method for invocation
54-
result = metadata.getMethod().invoke(instance, convertedParams.toArray());
55-
} catch (Exception e) {
56-
log.error("Error invoking prompt method {}", metadata.getMethodSignature(), e);
57-
result = e + ": " + e.getMessage();
58-
}
59-
McpSchema.Content content = new McpSchema.TextContent(result.toString());
60-
McpSchema.PromptMessage message =
61-
new McpSchema.PromptMessage(McpSchema.Role.USER, content);
62-
return new McpSchema.GetPromptResult(description, List.of(message));
63-
});
60+
return new McpServerFeatures.SyncPromptSpecification(prompt, this);
61+
}
62+
63+
@Override
64+
public McpSchema.GetPromptResult apply(McpSyncServerExchange ex, McpSchema.GetPromptRequest req) {
65+
Object result;
66+
try {
67+
Map<String, Object> arguments = req.arguments();
68+
List<Object> convertedParams = converter.convertAllParameters(methodCache, arguments);
69+
// Use cached method for invocation
70+
result = methodCache.getMethod().invoke(instance, convertedParams.toArray());
71+
} catch (Exception e) {
72+
log.error("Error invoking prompt method: {}", methodCache.getMethodSignature(), e);
73+
result = e + ": " + e.getMessage();
74+
}
75+
McpSchema.Content content = new McpSchema.TextContent(result.toString());
76+
McpSchema.PromptMessage message = new McpSchema.PromptMessage(McpSchema.Role.USER, content);
77+
return new McpSchema.GetPromptResult(description, List.of(message));
6478
}
6579

66-
private List<McpSchema.PromptArgument> createPromptArguments(MethodMetadata metadata) {
67-
Parameter[] methodParams = metadata.getParameters();
80+
private List<McpSchema.PromptArgument> createPromptArguments() {
81+
Parameter[] methodParams = methodCache.getParameters();
6882
List<McpSchema.PromptArgument> promptArguments = new ArrayList<>(methodParams.length);
6983

7084
for (Parameter param : methodParams) {

0 commit comments

Comments
 (0)