Skip to content

Commit c1bfe12

Browse files
committed
feat(server): Add support for MCP server configuration
1 parent ce85a7a commit c1bfe12

File tree

6 files changed

+183
-0
lines changed

6 files changed

+183
-0
lines changed

pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
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>
@@ -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: 64 additions & 0 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;
@@ -15,11 +19,16 @@
1519
import io.modelcontextprotocol.server.transport.StdioServerTransportProvider;
1620
import io.modelcontextprotocol.spec.McpServerTransportProvider;
1721
import org.reflections.Reflections;
22+
import org.slf4j.Logger;
23+
import org.slf4j.LoggerFactory;
1824

25+
import java.io.IOException;
1926
import java.time.Duration;
2027

2128
public class McpServers {
2229

30+
private static final Logger logger = LoggerFactory.getLogger(McpServers.class);
31+
2332
private static final McpServers INSTANCE = new McpServers();
2433

2534
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
@@ -73,4 +82,59 @@ public void startSyncSseServer(McpSseServerInfo serverInfo) {
7382
startSyncSseServer(serverInfo, new DefaultMcpSyncHttpServerStatusListener());
7483
}
7584

85+
public void startServer(String configFileName) {
86+
McpServerConfiguration configuration = loadConfiguration(configFileName);
87+
if (configuration.enabled()) {
88+
startServerWith(configuration);
89+
} else {
90+
logger.info("MCP server is disabled.");
91+
}
92+
}
93+
94+
public void startServer() {
95+
// Load configuration from default file
96+
startServer(null);
97+
}
98+
99+
private McpServerConfiguration loadConfiguration(String configFileName) {
100+
YamlConfigurationLoader configurationLoader = new YamlConfigurationLoader();
101+
McpServerConfiguration configuration;
102+
try {
103+
if (configFileName == null || configFileName.isBlank()) {
104+
configuration = configurationLoader.loadConfiguration();
105+
} else {
106+
configuration = configurationLoader.load(configFileName);
107+
}
108+
} catch (IOException e) {
109+
throw new McpServerException("Error loading configuration file", e);
110+
}
111+
return configuration;
112+
}
113+
114+
private void startServerWith(McpServerConfiguration configuration) {
115+
if (ServerType.SYNC.name().equalsIgnoreCase(configuration.type())) {
116+
if (configuration.stdio()) {
117+
McpServerInfo serverInfo = McpServerInfo.builder()
118+
.name(configuration.name())
119+
.version(configuration.version())
120+
.instructions(configuration.instructions())
121+
.requestTimeout(Duration.ofSeconds(configuration.requestTimeout()))
122+
.build();
123+
startSyncStdioServer(serverInfo);
124+
} else {
125+
McpSseServerInfo serverInfo = McpSseServerInfo.builder()
126+
.name(configuration.name())
127+
.version(configuration.version())
128+
.instructions(configuration.instructions())
129+
.requestTimeout(Duration.ofSeconds(configuration.requestTimeout()))
130+
.baseUrl(configuration.baseUrl())
131+
.messageEndpoint(configuration.sseMessageEndpoint())
132+
.sseEndpoint(configuration.sseEndpoint())
133+
.port(configuration.ssePort())
134+
.build();
135+
startSyncSseServer(serverInfo);
136+
}
137+
}
138+
}
139+
76140
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.github.codeboyzhou.mcp.declarative.configuration;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
5+
import java.util.Map;
6+
7+
public record McpServerConfiguration(
8+
@JsonProperty("enabled") boolean enabled,
9+
@JsonProperty("stdio") boolean stdio,
10+
@JsonProperty("name") String name,
11+
@JsonProperty("version") String version,
12+
@JsonProperty("instructions") String instructions,
13+
@JsonProperty("request-timeout") long requestTimeout,
14+
@JsonProperty("type") String type,
15+
@JsonProperty("resource-change-notification") boolean resourceChangeNotification,
16+
@JsonProperty("prompt-change-notification") boolean promptChangeNotification,
17+
@JsonProperty("tool-change-notification") boolean toolChangeNotification,
18+
@JsonProperty("tool-response-mime-type") Map<String, String> toolResponseMimeType,
19+
@JsonProperty("sse-message-endpoint") String sseMessageEndpoint,
20+
@JsonProperty("sse-endpoint") String sseEndpoint,
21+
@JsonProperty("base-url") String baseUrl,
22+
@JsonProperty("sse-port") int ssePort
23+
) {
24+
25+
public static McpServerConfiguration defaultConfiguration() {
26+
return new McpServerConfiguration(
27+
true,
28+
false,
29+
"mcp-server",
30+
"1.0.0",
31+
"mcp-server",
32+
10000,
33+
"SYNC",
34+
true,
35+
true,
36+
true,
37+
Map.of(),
38+
"/mcp/message",
39+
"/sse",
40+
"",
41+
8080
42+
);
43+
}
44+
45+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.github.codeboyzhou.mcp.declarative.configuration;
2+
3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
5+
import org.slf4j.Logger;
6+
import org.slf4j.LoggerFactory;
7+
8+
import java.io.BufferedReader;
9+
import java.io.IOException;
10+
import java.io.InputStream;
11+
import java.io.InputStreamReader;
12+
import java.nio.file.NoSuchFileException;
13+
import java.util.Objects;
14+
15+
import static java.util.stream.Collectors.joining;
16+
17+
public class YamlConfigurationLoader {
18+
19+
private static final Logger logger = LoggerFactory.getLogger(YamlConfigurationLoader.class);
20+
21+
private final ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
22+
23+
public McpServerConfiguration loadConfiguration() {
24+
try {
25+
McpServerConfiguration configuration = load("mcp-server.yml");
26+
if (configuration == null) {
27+
configuration = load("mcp-server.yaml");
28+
}
29+
return Objects.requireNonNullElseGet(configuration, McpServerConfiguration::defaultConfiguration);
30+
} catch (IOException e) {
31+
logger.error("Error loading configuration file, will use default configuration", e);
32+
return McpServerConfiguration.defaultConfiguration();
33+
}
34+
}
35+
36+
public McpServerConfiguration load(String configFileName) throws IOException {
37+
ClassLoader classLoader = YamlConfigurationLoader.class.getClassLoader();
38+
try (InputStream inputStream = classLoader.getResourceAsStream(configFileName)) {
39+
if (inputStream == null) {
40+
throw new NoSuchFileException(configFileName);
41+
}
42+
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
43+
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
44+
final String content = bufferedReader.lines().collect(joining(System.lineSeparator()));
45+
return mapper.readValue(content, McpServerConfiguration.class);
46+
}
47+
}
48+
49+
}
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.enums;
2+
3+
public enum ServerType {
4+
SYNC,
5+
ASYNC
6+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.github.codeboyzhou.mcp.declarative.exception;
2+
3+
public class McpServerException extends RuntimeException {
4+
5+
public McpServerException(String message) {
6+
super(message);
7+
}
8+
9+
public McpServerException(String message, Throwable cause) {
10+
super(message, cause);
11+
}
12+
13+
}

0 commit comments

Comments
 (0)