Skip to content

Commit 92e0e95

Browse files
committed
chore(release): v0.4.0 released
# Conflicts: # src/main/java/com/github/codeboyzhou/mcp/declarative/server/McpSyncServerToolRegister.java # src/main/java/com/github/codeboyzhou/mcp/declarative/util/ReflectionHelper.java
2 parents ea483cc + 5091d00 commit 92e0e95

31 files changed

+558
-74
lines changed

README.md

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,15 @@ Declarative [MCP Java SDK](https://github.com/modelcontextprotocol/java-sdk) Dev
1414
- No need to write more SDK low-level codes.
1515
- Get rid of complex and lengthy JSON schema definitions.
1616
- Just focus on your core logic (resources/prompts/tools).
17+
- Configuration file compatible with the Spring AI framework.
1718

1819
## Showcase
1920

2021
Just put this one line code in your `main` method:
2122

2223
```java
24+
import com.github.codeboyzhou.mcp.declarative.McpServers;
25+
2326
// You can use this annotation to specify the base package
2427
// to scan for MCP resources, prompts, tools, but it's optional.
2528
// If not specified, it will scan the package where the main method is located.
@@ -35,11 +38,34 @@ public class MyMcpServer {
3538
McpServers.run(MyMcpServer.class, args).startSyncSseServer(
3639
McpSseServerInfo.builder().name("mcp-server").version("1.0.0").port(8080).build()
3740
);
41+
// or start with yaml configuration file (compatible with the Spring AI framework)
42+
McpServers.run(MyMcpServer.class, args).startServer();
43+
// or start with a specific configuration file (compatible with the Spring AI framework)
44+
McpServers.run(MyMcpServer.class, args).startServer("my-mcp-server.yml");
3845
}
3946

4047
}
4148
```
4249

50+
This is a yaml configuration file example (named `mcp-server.yml` by default, or also `mcp-server.yaml`) only if you are using `startServer()` method:
51+
52+
```yaml
53+
enabled: true
54+
stdio: false
55+
name: mcp-server
56+
version: 1.0.0
57+
instructions: mcp-server
58+
request-timeout: 30000
59+
type: SYNC
60+
resource-change-notification: true
61+
prompt-change-notification: true
62+
tool-change-notification: true
63+
sse-message-endpoint: /mcp/message
64+
sse-endpoint: /sse
65+
base-url: http://localhost:8080
66+
sse-port: 8080
67+
```
68+
4369
No need to care about the low-level details of native MCP Java SDK and how to create the MCP resources, prompts, and tools. Just annotate them like this:
4470
4571
```java
@@ -103,11 +129,11 @@ Now it's all set, run your MCP server, choose one MCP client you like and start
103129
Add the following Maven dependency to your project:
104130

105131
```xml
106-
<!-- Internally relies on native MCP Java SDK 0.9.0 -->
132+
<!-- Internally relies on native MCP Java SDK 0.10.0 -->
107133
<dependency>
108134
<groupId>io.github.codeboyzhou</groupId>
109135
<artifactId>mcp-declarative-java-sdk</artifactId>
110-
<version>0.3.0</version>
136+
<version>0.4.0</version>
111137
</dependency>
112138
```
113139

pom.xml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>io.github.codeboyzhou</groupId>
88
<artifactId>mcp-declarative-java-sdk</artifactId>
9-
<version>0.3.0</version>
9+
<version>0.4.0</version>
1010

1111
<name>MCP Declarative Java SDK</name>
1212
<description>Annotation-driven MCP (Model Context Protocol) Development with Java - No Spring Framework Required</description>
@@ -51,10 +51,11 @@
5151
<maven-surefire-plugin.version>3.2.3</maven-surefire-plugin.version>
5252
<sortpom-maven-plugin.version>4.0.0</sortpom-maven-plugin.version>
5353
<!--==================== dependency versions ======================-->
54+
<jackson-dataformat-yaml.version>2.18.3</jackson-dataformat-yaml.version>
5455
<jetty.version>12.0.18</jetty.version>
5556
<junit5.version>5.10.2</junit5.version>
5657
<logback.version>1.5.18</logback.version>
57-
<mcp-sdk.version>0.9.0</mcp-sdk.version>
58+
<mcp-sdk.version>0.10.0</mcp-sdk.version>
5859
<reflections.version>0.10.2</reflections.version>
5960
</properties>
6061

@@ -78,6 +79,11 @@
7879
<version>${logback.version}</version>
7980
<scope>test</scope>
8081
</dependency>
82+
<dependency>
83+
<groupId>com.fasterxml.jackson.dataformat</groupId>
84+
<artifactId>jackson-dataformat-yaml</artifactId>
85+
<version>${jackson-dataformat-yaml.version}</version>
86+
</dependency>
8187
<dependency>
8288
<groupId>io.modelcontextprotocol.sdk</groupId>
8389
<artifactId>mcp</artifactId>

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

Lines changed: 67 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
import com.fasterxml.jackson.databind.ObjectMapper;
44
import com.github.codeboyzhou.mcp.declarative.annotation.McpComponentScan;
5+
import com.github.codeboyzhou.mcp.declarative.configuration.McpServerConfiguration;
6+
import com.github.codeboyzhou.mcp.declarative.configuration.YamlConfigurationLoader;
7+
import com.github.codeboyzhou.mcp.declarative.enums.ServerType;
8+
import com.github.codeboyzhou.mcp.declarative.exception.McpServerException;
59
import com.github.codeboyzhou.mcp.declarative.listener.DefaultMcpSyncHttpServerStatusListener;
610
import com.github.codeboyzhou.mcp.declarative.listener.McpHttpServerStatusListener;
711
import com.github.codeboyzhou.mcp.declarative.server.McpHttpServer;
@@ -14,18 +18,22 @@
1418
import io.modelcontextprotocol.server.transport.HttpServletSseServerTransportProvider;
1519
import io.modelcontextprotocol.server.transport.StdioServerTransportProvider;
1620
import io.modelcontextprotocol.spec.McpServerTransportProvider;
21+
import io.modelcontextprotocol.util.Assert;
1722
import org.reflections.Reflections;
23+
import org.slf4j.Logger;
24+
import org.slf4j.LoggerFactory;
25+
26+
import java.io.IOException;
27+
import java.time.Duration;
1828

1929
public class McpServers {
2030

31+
private static final Logger logger = LoggerFactory.getLogger(McpServers.class);
32+
2133
private static final McpServers INSTANCE = new McpServers();
2234

2335
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
2436

25-
private static final String DEFAULT_MESSAGE_ENDPOINT = "/message";
26-
27-
private static final int DEFAULT_HTTP_SERVER_PORT = 8080;
28-
2937
private static Reflections reflections;
3038

3139
public static McpServers run(Class<?> applicationMainClass, String[] args) {
@@ -46,18 +54,20 @@ private static String determineBasePackage(McpComponentScan scan, Class<?> appli
4654
return applicationMainClass.getPackageName();
4755
}
4856

57+
@Deprecated(since = "0.4.0")
4958
public void startSyncStdioServer(String name, String version, String instructions) {
59+
McpServerInfo serverInfo = McpServerInfo.builder().name(name).version(version)
60+
.instructions(instructions).requestTimeout(Duration.ofSeconds(10)).build();
61+
startSyncStdioServer(serverInfo);
62+
}
63+
64+
public void startSyncStdioServer(McpServerInfo serverInfo) {
5065
McpServerFactory<McpSyncServer> factory = new McpSyncServerFactory();
51-
McpServerInfo serverInfo = McpServerInfo.builder().name(name).version(version).instructions(instructions).build();
5266
McpServerTransportProvider transportProvider = new StdioServerTransportProvider();
5367
McpSyncServer server = factory.create(serverInfo, transportProvider);
5468
McpServerComponentRegisters.registerAllTo(server, reflections);
5569
}
5670

57-
public void startSyncStdioServer(McpServerInfo serverInfo) {
58-
startSyncStdioServer(serverInfo.name(), serverInfo.version(), serverInfo.instructions());
59-
}
60-
6171
public void startSyncSseServer(McpSseServerInfo serverInfo, McpHttpServerStatusListener<McpSyncServer> listener) {
6272
McpServerFactory<McpSyncServer> factory = new McpSyncServerFactory();
6373
HttpServletSseServerTransportProvider transportProvider = new HttpServletSseServerTransportProvider(
@@ -73,4 +83,52 @@ public void startSyncSseServer(McpSseServerInfo serverInfo) {
7383
startSyncSseServer(serverInfo, new DefaultMcpSyncHttpServerStatusListener());
7484
}
7585

86+
public void startServer(String configFileName) {
87+
Assert.notNull(configFileName, "configFileName must not be null");
88+
YamlConfigurationLoader configurationLoader = new YamlConfigurationLoader();
89+
McpServerConfiguration configuration;
90+
try {
91+
configuration = configurationLoader.load(configFileName);
92+
if (configuration.enabled()) {
93+
startServerWith(configuration);
94+
} else {
95+
logger.info("MCP server is disabled.");
96+
}
97+
} catch (IOException e) {
98+
throw new McpServerException("Error loading configuration file: " + e.getMessage(), e);
99+
}
100+
}
101+
102+
public void startServer() {
103+
YamlConfigurationLoader configurationLoader = new YamlConfigurationLoader();
104+
McpServerConfiguration configuration = configurationLoader.loadConfiguration();
105+
startServerWith(configuration);
106+
}
107+
108+
private void startServerWith(McpServerConfiguration configuration) {
109+
if (ServerType.SYNC.name().equalsIgnoreCase(configuration.type())) {
110+
if (configuration.stdio()) {
111+
McpServerInfo serverInfo = McpServerInfo.builder()
112+
.name(configuration.name())
113+
.version(configuration.version())
114+
.instructions(configuration.instructions())
115+
.requestTimeout(Duration.ofSeconds(configuration.requestTimeout()))
116+
.build();
117+
startSyncStdioServer(serverInfo);
118+
} else {
119+
McpSseServerInfo serverInfo = McpSseServerInfo.builder()
120+
.name(configuration.name())
121+
.version(configuration.version())
122+
.instructions(configuration.instructions())
123+
.requestTimeout(Duration.ofSeconds(configuration.requestTimeout()))
124+
.baseUrl(configuration.baseUrl())
125+
.messageEndpoint(configuration.sseMessageEndpoint())
126+
.sseEndpoint(configuration.sseEndpoint())
127+
.port(configuration.ssePort())
128+
.build();
129+
startSyncSseServer(serverInfo);
130+
}
131+
}
132+
}
133+
76134
}
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.github.codeboyzhou.mcp.declarative.annotation;
22

3+
import com.github.codeboyzhou.mcp.declarative.util.StringHelper;
4+
35
import java.lang.annotation.ElementType;
46
import java.lang.annotation.Retention;
57
import java.lang.annotation.RetentionPolicy;
@@ -8,7 +10,7 @@
810
@Target(ElementType.TYPE)
911
@Retention(RetentionPolicy.RUNTIME)
1012
public @interface McpComponentScan {
11-
String basePackage() default "";
13+
String basePackage() default StringHelper.EMPTY;
1214

1315
Class<?> basePackageClass() default Object.class;
1416
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.github.codeboyzhou.mcp.declarative.annotation;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.RetentionPolicy;
6+
import java.lang.annotation.Target;
7+
8+
@Target(ElementType.TYPE)
9+
@Retention(RetentionPolicy.RUNTIME)
10+
public @interface McpJsonSchemaDefinition {
11+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.github.codeboyzhou.mcp.declarative.annotation;
2+
3+
import com.github.codeboyzhou.mcp.declarative.util.StringHelper;
4+
5+
import java.lang.annotation.ElementType;
6+
import java.lang.annotation.Retention;
7+
import java.lang.annotation.RetentionPolicy;
8+
import java.lang.annotation.Target;
9+
10+
@Target(ElementType.FIELD)
11+
@Retention(RetentionPolicy.RUNTIME)
12+
public @interface McpJsonSchemaDefinitionProperty {
13+
String name() default StringHelper.EMPTY;
14+
15+
String description();
16+
17+
boolean required() default false;
18+
}

src/main/java/com/github/codeboyzhou/mcp/declarative/annotation/McpPrompt.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.github.codeboyzhou.mcp.declarative.annotation;
22

3+
import com.github.codeboyzhou.mcp.declarative.util.StringHelper;
4+
35
import java.lang.annotation.ElementType;
46
import java.lang.annotation.Retention;
57
import java.lang.annotation.RetentionPolicy;
@@ -9,7 +11,7 @@
911
@Retention(RetentionPolicy.RUNTIME)
1012
public @interface McpPrompt {
1113

12-
String name() default "";
14+
String name() default StringHelper.EMPTY;
1315

1416
String description();
1517
}

src/main/java/com/github/codeboyzhou/mcp/declarative/annotation/McpResource.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.github.codeboyzhou.mcp.declarative.annotation;
22

3+
import com.github.codeboyzhou.mcp.declarative.util.StringHelper;
34
import io.modelcontextprotocol.spec.McpSchema;
45

56
import java.lang.annotation.ElementType;
@@ -12,7 +13,7 @@
1213
public @interface McpResource {
1314
String uri();
1415

15-
String name() default "";
16+
String name() default StringHelper.EMPTY;
1617

1718
String description();
1819

src/main/java/com/github/codeboyzhou/mcp/declarative/annotation/McpTool.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.github.codeboyzhou.mcp.declarative.annotation;
22

3+
import com.github.codeboyzhou.mcp.declarative.util.StringHelper;
4+
35
import java.lang.annotation.ElementType;
46
import java.lang.annotation.Retention;
57
import java.lang.annotation.RetentionPolicy;
@@ -9,7 +11,7 @@
911
@Retention(RetentionPolicy.RUNTIME)
1012
public @interface McpTool {
1113

12-
String name() default "";
14+
String name() default StringHelper.EMPTY;
1315

1416
String description();
1517
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.github.codeboyzhou.mcp.declarative.configuration;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import com.github.codeboyzhou.mcp.declarative.util.StringHelper;
5+
6+
public record McpServerConfiguration(
7+
@JsonProperty("enabled") boolean enabled,
8+
@JsonProperty("stdio") boolean stdio,
9+
@JsonProperty("name") String name,
10+
@JsonProperty("version") String version,
11+
@JsonProperty("instructions") String instructions,
12+
@JsonProperty("request-timeout") long requestTimeout,
13+
@JsonProperty("type") String type,
14+
@JsonProperty("resource-change-notification") boolean resourceChangeNotification,
15+
@JsonProperty("prompt-change-notification") boolean promptChangeNotification,
16+
@JsonProperty("tool-change-notification") boolean toolChangeNotification,
17+
@JsonProperty("sse-message-endpoint") String sseMessageEndpoint,
18+
@JsonProperty("sse-endpoint") String sseEndpoint,
19+
@JsonProperty("base-url") String baseUrl,
20+
@JsonProperty("sse-port") int ssePort
21+
) {
22+
23+
public static McpServerConfiguration defaultConfiguration() {
24+
return new McpServerConfiguration(
25+
true,
26+
false,
27+
"mcp-server",
28+
"1.0.0",
29+
"mcp-server",
30+
10000,
31+
"SYNC",
32+
true,
33+
true,
34+
true,
35+
"/mcp/message",
36+
"/sse",
37+
StringHelper.EMPTY,
38+
8080
39+
);
40+
}
41+
42+
}

0 commit comments

Comments
 (0)