diff --git a/mcp-server-chat2mysql/chat2mysql-commons/pom.xml b/mcp-server-chat2mysql/chat2mysql-commons/pom.xml
index 8c1b2a4..4d27368 100644
--- a/mcp-server-chat2mysql/chat2mysql-commons/pom.xml
+++ b/mcp-server-chat2mysql/chat2mysql-commons/pom.xml
@@ -13,12 +13,4 @@
chat2mysql-commons
jar
-
- 17
- ${java.version}
- ${java.version}
- UTF-8
- UTF-8
-
-
diff --git a/mcp-server-chat2mysql/chat2mysql-declarative-sdk-example/pom.xml b/mcp-server-chat2mysql/chat2mysql-declarative-sdk-example/pom.xml
index 3f75cf9..27b3d5d 100644
--- a/mcp-server-chat2mysql/chat2mysql-declarative-sdk-example/pom.xml
+++ b/mcp-server-chat2mysql/chat2mysql-declarative-sdk-example/pom.xml
@@ -13,19 +13,31 @@
chat2mysql-declarative-sdk-example
jar
-
- 17
- ${java.version}
- ${java.version}
- UTF-8
- UTF-8
-
-
com.github.codeboyzhou
chat2mysql-commons
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
+
+ org.mockito
+ mockito-inline
+ test
+
+
+ org.mockito
+ mockito-junit-jupiter
+ test
+
+
+ org.slf4j
+ slf4j-simple
+ test
+
diff --git a/mcp-server-chat2mysql/chat2mysql-declarative-sdk-example/src/test/java/com/github/mcp/server/chat2mysql/McpStdioServerTest.java b/mcp-server-chat2mysql/chat2mysql-declarative-sdk-example/src/test/java/com/github/mcp/server/chat2mysql/McpStdioServerTest.java
new file mode 100644
index 0000000..73557e6
--- /dev/null
+++ b/mcp-server-chat2mysql/chat2mysql-declarative-sdk-example/src/test/java/com/github/mcp/server/chat2mysql/McpStdioServerTest.java
@@ -0,0 +1,27 @@
+package com.github.mcp.server.chat2mysql;
+
+import com.github.codeboyzhou.mcp.declarative.annotation.McpComponentScan;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class McpStdioServerTest {
+
+ @Test
+ void classIsAnnotatedWithMcpComponentScan() {
+ Class cls = McpStdioServer.class;
+ assertTrue(cls.isAnnotationPresent(McpComponentScan.class),
+ "McpStdioServer should be annotated with @McpComponentScan");
+
+ McpComponentScan ann = cls.getAnnotation(McpComponentScan.class);
+ assertEquals(McpStdioServer.class, ann.basePackageClass(),
+ "@McpComponentScan.basePackageClass should point to McpStdioServer.class");
+ }
+
+ @Test
+ void mainHandlesNoArgsWithoutException() {
+ // ensure main method does not throw when called with empty args
+ assertDoesNotThrow(() -> McpStdioServer.main(new String[0]),
+ "Calling main with no arguments should not throw an exception");
+ }
+}
diff --git a/mcp-server-chat2mysql/chat2mysql-declarative-sdk-example/src/test/java/com/github/mcp/server/chat2mysql/MyMcpPromptsTest.java b/mcp-server-chat2mysql/chat2mysql-declarative-sdk-example/src/test/java/com/github/mcp/server/chat2mysql/MyMcpPromptsTest.java
new file mode 100644
index 0000000..a4825e5
--- /dev/null
+++ b/mcp-server-chat2mysql/chat2mysql-declarative-sdk-example/src/test/java/com/github/mcp/server/chat2mysql/MyMcpPromptsTest.java
@@ -0,0 +1,50 @@
+package com.github.mcp.server.chat2mysql;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import com.github.mcp.server.chat2mysql.util.SqlHelper;
+import java.util.Set;
+
+class MyMcpPromptsTest {
+
+ @Test
+ void generateSqlOptimizationTips_includesSqlAndPromptHeader() {
+ String sql = "SELECT * FROM users WHERE id = 1;";
+ try (MockedStatic helper = Mockito.mockStatic(SqlHelper.class)) {
+ helper.when(() -> SqlHelper.parseTableNames(sql))
+ .thenReturn(Set.of("users"));
+ helper.when(() -> SqlHelper.showCreateTable("users"))
+ .thenReturn("CREATE TABLE users (id INT PRIMARY KEY);");
+ helper.when(() -> SqlHelper.explainSql(sql))
+ .thenReturn("id | select_type | table | type | possible_keys | key | rows | Extra\n1 | SIMPLE | users | ALL | NULL | NULL | 1 | ");
+
+ String prompt = MyMcpPrompts.generateSqlOptimizationTips(sql);
+
+ // verify the prompt is not null or empty
+ assertNotNull(prompt, "Prompt should not be null");
+ assertFalse(prompt.isBlank(), "Prompt should not be blank");
+
+ // verify it includes the SQL statement
+ assertTrue(prompt.contains("The SQL statement is: " + sql),
+ "Prompt should include the SQL statement");
+
+ // verify it includes the explain plan section label and content
+ assertTrue(prompt.contains("The EXPLAIN plan for the SQL statement is:"),
+ "Prompt should include the EXPLAIN plan section");
+ assertTrue(prompt.contains("id | select_type"),
+ "Prompt should include the mocked EXPLAIN plan content");
+
+ // verify it includes the mocked table schema
+ assertTrue(prompt.contains("The table schema for users is: CREATE TABLE users"),
+ "Prompt should include the mocked table schema content");
+
+ // verify it ends with the language-specific message ending
+ String ending = com.github.mcp.server.chat2mysql.enums.PromptMessageEnding.ofCurrentUserLanguage();
+ assertTrue(prompt.endsWith(ending),
+ "Prompt should end with the language-specific message ending");
+ }
+ }
+}
diff --git a/mcp-server-chat2mysql/chat2mysql-native-sdk-example/pom.xml b/mcp-server-chat2mysql/chat2mysql-native-sdk-example/pom.xml
index ac87b88..85e634a 100644
--- a/mcp-server-chat2mysql/chat2mysql-native-sdk-example/pom.xml
+++ b/mcp-server-chat2mysql/chat2mysql-native-sdk-example/pom.xml
@@ -13,19 +13,31 @@
chat2mysql-native-sdk-example
jar
-
- 17
- ${java.version}
- ${java.version}
- UTF-8
- UTF-8
-
-
com.github.codeboyzhou
chat2mysql-commons
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
+
+ org.mockito
+ mockito-inline
+ test
+
+
+ org.mockito
+ mockito-junit-jupiter
+ test
+
+
+ org.slf4j
+ slf4j-simple
+ test
+
diff --git a/mcp-server-chat2mysql/chat2mysql-native-sdk-example/src/test/java/com/github/mcp/server/chat2mysql/McpPromptsTest.java b/mcp-server-chat2mysql/chat2mysql-native-sdk-example/src/test/java/com/github/mcp/server/chat2mysql/McpPromptsTest.java
new file mode 100644
index 0000000..10d1244
--- /dev/null
+++ b/mcp-server-chat2mysql/chat2mysql-native-sdk-example/src/test/java/com/github/mcp/server/chat2mysql/McpPromptsTest.java
@@ -0,0 +1,61 @@
+package com.github.mcp.server.chat2mysql;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import io.modelcontextprotocol.server.McpSyncServer;
+import io.modelcontextprotocol.server.McpServerFeatures.SyncPromptSpecification;
+import io.modelcontextprotocol.spec.McpSchema;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+
+import java.util.List;
+
+class McpPromptsTest {
+
+ static {
+ // Enable Byte Buddy experimental support for Java 21
+ System.setProperty("net.bytebuddy.experimental", "true");
+ }
+
+ private static SyncPromptSpecification spec;
+
+ @BeforeAll
+ static void setup() {
+ // obtain the prompt specification
+ spec = McpPrompts.generateSqlOptimizationTips();
+ }
+
+ @Test
+ void specHasCorrectNameAndDescription() {
+ McpSchema.Prompt prompt = spec.prompt();
+ assertEquals("generate_sql_optimization_tips", prompt.name(),
+ "Prompt name should match");
+ assertEquals("Generate SQL optimization tips.", prompt.description(),
+ "Prompt description should match");
+ }
+
+ @Test
+ void specHasSqlArgument() {
+ List args = spec.prompt().arguments();
+ assertEquals(1, args.size(), "There should be exactly one argument");
+ McpSchema.PromptArgument arg = args.get(0);
+ assertEquals("sql", arg.name(), "Argument name should be 'sql'");
+ assertTrue(arg.required(), "SQL argument should be required");
+ }
+
+ @Test
+ void addAllToRegistersPromptOnServer() {
+ McpSyncServer server = mock(McpSyncServer.class);
+ McpPrompts.addAllTo(server);
+ // verify that addPrompt was called with the correct prompt specification properties
+ ArgumentCaptor captor = ArgumentCaptor.forClass(SyncPromptSpecification.class);
+ verify(server).addPrompt(captor.capture());
+ SyncPromptSpecification actual = captor.getValue();
+ assertEquals(spec.prompt().name(), actual.prompt().name(), "Prompt name should match");
+ assertEquals(spec.prompt().description(), actual.prompt().description(), "Prompt description should match");
+ assertEquals(spec.prompt().arguments().size(),
+ actual.prompt().arguments().size(), "Argument count should match");
+ }
+}
diff --git a/mcp-server-chat2mysql/chat2mysql-native-sdk-example/src/test/java/com/github/mcp/server/chat2mysql/McpStdioServerTest.java b/mcp-server-chat2mysql/chat2mysql-native-sdk-example/src/test/java/com/github/mcp/server/chat2mysql/McpStdioServerTest.java
new file mode 100644
index 0000000..8524a5d
--- /dev/null
+++ b/mcp-server-chat2mysql/chat2mysql-native-sdk-example/src/test/java/com/github/mcp/server/chat2mysql/McpStdioServerTest.java
@@ -0,0 +1,52 @@
+
+package com.github.mcp.server.chat2mysql;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+import org.mockito.MockedStatic;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Field;
+
+import io.modelcontextprotocol.server.McpSyncServer;
+
+class McpStdioServerTest {
+
+ private McpStdioServer stdioServer;
+
+ @BeforeEach
+ void setUp() {
+ stdioServer = new McpStdioServer();
+ }
+
+ @Test
+ void initializeShouldSetServerField() throws Exception {
+ // call private initialize()
+ Method init = McpStdioServer.class.getDeclaredMethod("initialize");
+ init.setAccessible(true);
+ init.invoke(stdioServer);
+
+ // reflectively get 'server' field
+ Field field = McpStdioServer.class.getDeclaredField("server");
+ field.setAccessible(true);
+ Object serverInstance = field.get(stdioServer);
+
+ assertNotNull(serverInstance, "server field should be initialized");
+ assertTrue(serverInstance instanceof McpSyncServer,
+ "server field should be an instance of McpSyncServer");
+ }
+
+ @Test
+ void mainShouldCallPromptsAddAllTo() {
+ // mock McpPrompts static
+ try (MockedStatic prompts = mockStatic(McpPrompts.class)) {
+ // ensure no exception
+ assertDoesNotThrow(() -> McpStdioServer.main(new String[0]));
+
+ // verify addAllTo was called with any McpSyncServer
+ prompts.verify(() -> McpPrompts.addAllTo(any(McpSyncServer.class)), times(1));
+ }
+ }
+}
diff --git a/mcp-server-chat2mysql/pom.xml b/mcp-server-chat2mysql/pom.xml
index 4c32882..c5b57f2 100644
--- a/mcp-server-chat2mysql/pom.xml
+++ b/mcp-server-chat2mysql/pom.xml
@@ -20,13 +20,6 @@
- 17
- ${java.version}
- ${java.version}
- UTF-8
- UTF-8
-
- 3.6.0
9.2.0
diff --git a/mcp-server-filesystem/filesystem-commons/pom.xml b/mcp-server-filesystem/filesystem-commons/pom.xml
index b0effa4..c58ff20 100644
--- a/mcp-server-filesystem/filesystem-commons/pom.xml
+++ b/mcp-server-filesystem/filesystem-commons/pom.xml
@@ -12,13 +12,4 @@
filesystem-commons
jar
-
-
- 17
- ${java.version}
- ${java.version}
- UTF-8
- UTF-8
-
-
diff --git a/mcp-server-filesystem/filesystem-declarative-sdk-example/pom.xml b/mcp-server-filesystem/filesystem-declarative-sdk-example/pom.xml
index f897224..dff8a7a 100644
--- a/mcp-server-filesystem/filesystem-declarative-sdk-example/pom.xml
+++ b/mcp-server-filesystem/filesystem-declarative-sdk-example/pom.xml
@@ -13,19 +13,31 @@
filesystem-declarative-sdk-example
jar
-
- 17
- ${java.version}
- ${java.version}
- UTF-8
- UTF-8
-
-
com.github.codeboyzhou
filesystem-commons
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
+
+ org.mockito
+ mockito-inline
+ test
+
+
+ org.mockito
+ mockito-junit-jupiter
+ test
+
+
+ org.slf4j
+ slf4j-simple
+ test
+
diff --git a/mcp-server-filesystem/filesystem-declarative-sdk-example/src/main/java/com/github/mcp/examples/server/filesystem/McpStdioServer.java b/mcp-server-filesystem/filesystem-declarative-sdk-example/src/main/java/com/github/mcp/examples/server/filesystem/McpStdioServer.java
index c2e9a2a..0369a1f 100644
--- a/mcp-server-filesystem/filesystem-declarative-sdk-example/src/main/java/com/github/mcp/examples/server/filesystem/McpStdioServer.java
+++ b/mcp-server-filesystem/filesystem-declarative-sdk-example/src/main/java/com/github/mcp/examples/server/filesystem/McpStdioServer.java
@@ -15,7 +15,7 @@ public class McpStdioServer {
public static void main(String[] args) {
McpServerInfo serverInfo = McpServerInfo.builder().name(SERVER_NAME).version(SERVER_VERSION).build();
- McpServers.run(McpSseServer.class, args).startSyncStdioServer(serverInfo);
+ McpServers.run(McpStdioServer.class, args).startSyncStdioServer(serverInfo);
}
}
diff --git a/mcp-server-filesystem/filesystem-declarative-sdk-example/src/test/java/com/github/mcp/examples/server/filesystem/McpSseServerTest.java b/mcp-server-filesystem/filesystem-declarative-sdk-example/src/test/java/com/github/mcp/examples/server/filesystem/McpSseServerTest.java
new file mode 100644
index 0000000..560bf46
--- /dev/null
+++ b/mcp-server-filesystem/filesystem-declarative-sdk-example/src/test/java/com/github/mcp/examples/server/filesystem/McpSseServerTest.java
@@ -0,0 +1,27 @@
+package com.github.mcp.examples.server.filesystem;
+
+import com.github.codeboyzhou.mcp.declarative.McpServers;
+import com.github.codeboyzhou.mcp.declarative.server.McpSseServerInfo;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+class McpSseServerTest {
+
+ static {
+ // Enable Byte Buddy experimental support for Java 21
+ System.setProperty("net.bytebuddy.experimental", "true");
+ }
+
+ @Test
+ void mainInvokesServerRun() {
+ try (MockedStatic ms = mockStatic(McpServers.class)) {
+ com.github.codeboyzhou.mcp.declarative.McpServers fake = mock(com.github.codeboyzhou.mcp.declarative.McpServers.class);
+ ms.when(() -> McpServers.run(McpSseServer.class, new String[0])).thenReturn(fake);
+ assertDoesNotThrow(() -> McpSseServer.main(new String[0]));
+ verify(fake).startSyncSseServer(any(McpSseServerInfo.class));
+ }
+ }
+}
diff --git a/mcp-server-filesystem/filesystem-declarative-sdk-example/src/test/java/com/github/mcp/examples/server/filesystem/McpStdioServerTest.java b/mcp-server-filesystem/filesystem-declarative-sdk-example/src/test/java/com/github/mcp/examples/server/filesystem/McpStdioServerTest.java
new file mode 100644
index 0000000..e5aa8a3
--- /dev/null
+++ b/mcp-server-filesystem/filesystem-declarative-sdk-example/src/test/java/com/github/mcp/examples/server/filesystem/McpStdioServerTest.java
@@ -0,0 +1,27 @@
+package com.github.mcp.examples.server.filesystem;
+
+import com.github.codeboyzhou.mcp.declarative.McpServers;
+import com.github.codeboyzhou.mcp.declarative.server.McpServerInfo;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+class McpStdioServerTest {
+
+ static {
+ // Enable Byte Buddy experimental support for Java 21
+ System.setProperty("net.bytebuddy.experimental", "true");
+ }
+
+ @Test
+ void mainInvokesStdioServerRun() {
+ try (MockedStatic ms = mockStatic(McpServers.class)) {
+ com.github.codeboyzhou.mcp.declarative.McpServers fake = mock(com.github.codeboyzhou.mcp.declarative.McpServers.class);
+ ms.when(() -> McpServers.run(McpStdioServer.class, new String[0])).thenReturn(fake);
+ assertDoesNotThrow(() -> McpStdioServer.main(new String[0]));
+ verify(fake).startSyncStdioServer(any(McpServerInfo.class));
+ }
+ }
+}
diff --git a/mcp-server-filesystem/filesystem-declarative-sdk-example/src/test/java/com/github/mcp/examples/server/filesystem/MyMcpPromptsTest.java b/mcp-server-filesystem/filesystem-declarative-sdk-example/src/test/java/com/github/mcp/examples/server/filesystem/MyMcpPromptsTest.java
new file mode 100644
index 0000000..ede8f9f
--- /dev/null
+++ b/mcp-server-filesystem/filesystem-declarative-sdk-example/src/test/java/com/github/mcp/examples/server/filesystem/MyMcpPromptsTest.java
@@ -0,0 +1,41 @@
+package com.github.mcp.examples.server.filesystem;
+
+import com.github.codeboyzhou.mcp.declarative.annotation.McpPrompt;
+import com.github.codeboyzhou.mcp.declarative.annotation.McpPrompts;
+import org.junit.jupiter.api.Test;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class MyMcpPromptsTest {
+
+ @Test
+ void classIsAnnotatedWithMcpPrompts() {
+ assertTrue(MyMcpPrompts.class.isAnnotationPresent(McpPrompts.class),
+ "MyMcpPrompts should be annotated with @McpPrompts");
+ }
+
+ @Test
+ void readFileMethodAnnotation() throws NoSuchMethodException {
+ Method m = MyMcpPrompts.class.getMethod("readFile", String.class);
+ McpPrompt ann = m.getAnnotation(McpPrompt.class);
+ assertNotNull(ann, "readFile should have @McpPrompt");
+ assertEquals("read_file", ann.name());
+ assertEquals("Read complete contents of a file.", ann.description());
+ // check parameter annotation
+ Parameter p = m.getParameters()[0];
+ assertTrue(p.isAnnotationPresent(com.github.codeboyzhou.mcp.declarative.annotation.McpPromptParam.class));
+ }
+
+ @Test
+ void listFilesMethodAnnotation() throws NoSuchMethodException {
+ Method m = MyMcpPrompts.class.getMethod("listFiles", String.class, String.class, boolean.class);
+ McpPrompt ann = m.getAnnotation(McpPrompt.class);
+ assertNotNull(ann, "listFiles should have @McpPrompt");
+ assertEquals("list_files", ann.name());
+ assertEquals("List files of a directory.", ann.description());
+ assertEquals(3, m.getParameters().length);
+ }
+}
diff --git a/mcp-server-filesystem/filesystem-declarative-sdk-example/src/test/java/com/github/mcp/examples/server/filesystem/MyMcpResourcesTest.java b/mcp-server-filesystem/filesystem-declarative-sdk-example/src/test/java/com/github/mcp/examples/server/filesystem/MyMcpResourcesTest.java
new file mode 100644
index 0000000..6672563
--- /dev/null
+++ b/mcp-server-filesystem/filesystem-declarative-sdk-example/src/test/java/com/github/mcp/examples/server/filesystem/MyMcpResourcesTest.java
@@ -0,0 +1,28 @@
+package com.github.mcp.examples.server.filesystem;
+
+import com.github.codeboyzhou.mcp.declarative.annotation.McpResource;
+import com.github.codeboyzhou.mcp.declarative.annotation.McpResources;
+import org.junit.jupiter.api.Test;
+
+import java.lang.reflect.Method;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class MyMcpResourcesTest {
+
+ @Test
+ void classIsAnnotatedWithMcpResources() {
+ assertTrue(MyMcpResources.class.isAnnotationPresent(McpResources.class),
+ "MyMcpResources should be annotated with @McpResources");
+ }
+
+ @Test
+ void filesystemMethodHasMcpResourceAnnotation() throws NoSuchMethodException {
+ Method m = MyMcpResources.class.getMethod("filesystem");
+ assertTrue(m.isAnnotationPresent(McpResource.class), "filesystem() should have @McpResource");
+ McpResource ann = m.getAnnotation(McpResource.class);
+ assertEquals("file://system", ann.uri(), "URI should match");
+ assertEquals("filesystem", ann.name(), "name should match");
+ assertEquals("File system operations interface", ann.description(), "description should match");
+ }
+}
diff --git a/mcp-server-filesystem/filesystem-declarative-sdk-example/src/test/java/com/github/mcp/examples/server/filesystem/MyMcpToolsTest.java b/mcp-server-filesystem/filesystem-declarative-sdk-example/src/test/java/com/github/mcp/examples/server/filesystem/MyMcpToolsTest.java
new file mode 100644
index 0000000..2442210
--- /dev/null
+++ b/mcp-server-filesystem/filesystem-declarative-sdk-example/src/test/java/com/github/mcp/examples/server/filesystem/MyMcpToolsTest.java
@@ -0,0 +1,38 @@
+package com.github.mcp.examples.server.filesystem;
+
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class MyMcpToolsTest {
+
+ @Test
+ void readFileNonexistent() throws IOException {
+ MyMcpTools tools = new MyMcpTools();
+ String path = "nonexistent.txt";
+ String result = tools.readFile(path);
+ assertTrue(result.contains("does not exist"), "Should report missing file");
+ }
+
+ @Test
+ void listFilesNonexistent() throws IOException {
+ MyMcpTools tools = new MyMcpTools();
+ String path = "no_such_dir";
+ String result = tools.listFiles(path, "", false);
+ assertTrue(result.contains("does not exist"), "Should report missing directory");
+ }
+
+ @Test
+ void readFileAndListOnTemp() throws IOException {
+ Path tempFile = Files.createTempFile("test", ".txt");
+ Files.writeString(tempFile, "hello");
+ MyMcpTools tools = new MyMcpTools();
+ String content = tools.readFile(tempFile.toString());
+ assertEquals("hello", content);
+ Files.delete(tempFile);
+ }
+}
diff --git a/mcp-server-filesystem/filesystem-native-sdk-example/pom.xml b/mcp-server-filesystem/filesystem-native-sdk-example/pom.xml
index 598b953..8830e5b 100644
--- a/mcp-server-filesystem/filesystem-native-sdk-example/pom.xml
+++ b/mcp-server-filesystem/filesystem-native-sdk-example/pom.xml
@@ -13,19 +13,31 @@
filesystem-native-sdk-example
jar
-
- 17
- ${java.version}
- ${java.version}
- UTF-8
- UTF-8
-
-
com.github.codeboyzhou
filesystem-commons
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
+
+ org.mockito
+ mockito-inline
+ test
+
+
+ org.mockito
+ mockito-junit-jupiter
+ test
+
+
+ org.slf4j
+ slf4j-simple
+ test
+
diff --git a/mcp-server-filesystem/filesystem-native-sdk-example/src/test/java/com/github/mcp/examples/server/filesystem/McpPromptsTest.java b/mcp-server-filesystem/filesystem-native-sdk-example/src/test/java/com/github/mcp/examples/server/filesystem/McpPromptsTest.java
new file mode 100644
index 0000000..4cff67a
--- /dev/null
+++ b/mcp-server-filesystem/filesystem-native-sdk-example/src/test/java/com/github/mcp/examples/server/filesystem/McpPromptsTest.java
@@ -0,0 +1,55 @@
+package com.github.mcp.examples.server.filesystem;
+
+import io.modelcontextprotocol.server.McpSyncServer;
+import io.modelcontextprotocol.server.McpServerFeatures.SyncPromptSpecification;
+import io.modelcontextprotocol.spec.McpSchema;
+import org.junit.jupiter.api.Test;
+import io.modelcontextprotocol.server.McpServer;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+import reactor.core.publisher.Mono;
+import io.modelcontextprotocol.spec.McpServerTransportProvider;
+
+class McpPromptsTest {
+
+ @Test
+ void readFileMethodAndSpec() {
+ SyncPromptSpecification spec = com.github.mcp.examples.server.filesystem.McpPrompts.readFile();
+ McpSchema.Prompt p = spec.prompt();
+ assertEquals("read_file", p.name());
+ assertEquals("Read complete contents of a file.", p.description());
+ assertEquals(1, p.arguments().size());
+ // skip reflection entirely
+ }
+
+ @Test
+ void listFilesMethodAndSpec() {
+ SyncPromptSpecification spec = com.github.mcp.examples.server.filesystem.McpPrompts.listFiles();
+ McpSchema.Prompt p = spec.prompt();
+ assertEquals("list_files", p.name());
+ assertEquals("List files of a directory.", p.description());
+ assertEquals(3, p.arguments().size());
+ }
+
+ @Test
+ void addAllToRegistersPromptsNotifies() {
+ // Create a mock transport provider
+ McpServerTransportProvider mockProvider = mock(McpServerTransportProvider.class);
+ // Stub notifyClients to return empty Mono
+ when(mockProvider.notifyClients(eq(McpSchema.METHOD_NOTIFICATION_PROMPTS_LIST_CHANGED), isNull()))
+ .thenReturn(Mono.empty());
+ // Build async server with prompts capability
+ var async = McpServer.async(mockProvider)
+ .capabilities(McpSchema.ServerCapabilities.builder().prompts(true).build())
+ .build();
+ McpSyncServer server = new McpSyncServer(async);
+
+ // Invoke prompt registration
+ com.github.mcp.examples.server.filesystem.McpPrompts.addAllTo(server);
+
+ // Verify that notifyClients was called twice for prompts-list-changed
+ verify(mockProvider, times(2))
+ .notifyClients(eq(McpSchema.METHOD_NOTIFICATION_PROMPTS_LIST_CHANGED), isNull());
+ }
+}
diff --git a/mcp-server-filesystem/filesystem-native-sdk-example/src/test/java/com/github/mcp/examples/server/filesystem/McpResourcesTest.java b/mcp-server-filesystem/filesystem-native-sdk-example/src/test/java/com/github/mcp/examples/server/filesystem/McpResourcesTest.java
new file mode 100644
index 0000000..cb79af1
--- /dev/null
+++ b/mcp-server-filesystem/filesystem-native-sdk-example/src/test/java/com/github/mcp/examples/server/filesystem/McpResourcesTest.java
@@ -0,0 +1,47 @@
+package com.github.mcp.examples.server.filesystem;
+
+import io.modelcontextprotocol.server.McpSyncServer;
+import io.modelcontextprotocol.server.McpServer;
+import io.modelcontextprotocol.server.McpServerFeatures.SyncResourceSpecification;
+import io.modelcontextprotocol.spec.McpSchema;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+import reactor.core.publisher.Mono;
+import io.modelcontextprotocol.spec.McpServerTransportProvider;
+
+@com.github.codeboyzhou.mcp.declarative.annotation.McpResources
+class McpResourcesTest {
+
+ @Test
+ void filesystemSpecHasCorrectResource() {
+ // call the method and inspect the spec
+ SyncResourceSpecification spec = com.github.mcp.examples.server.filesystem.McpResources.filesystem();
+ McpSchema.Resource resource = spec.resource();
+ assertEquals("file://system", resource.uri());
+ assertEquals("filesystem", resource.name());
+ assertEquals("File system operations interface", resource.description());
+ }
+
+ @Test
+ void addAllToRegistersResourceNotifies() {
+ // Create a mock transport provider
+ McpServerTransportProvider mockProvider = mock(McpServerTransportProvider.class);
+ // Stub notifyClients to return empty Mono
+ when(mockProvider.notifyClients(eq(McpSchema.METHOD_NOTIFICATION_RESOURCES_LIST_CHANGED), isNull()))
+ .thenReturn(Mono.empty());
+ // Build async server with resources capability
+ var async = McpServer.async(mockProvider)
+ .capabilities(McpSchema.ServerCapabilities.builder().resources(true, true).build())
+ .build();
+ McpSyncServer server = new McpSyncServer(async);
+
+ // Invoke resource registration
+ McpResources.addAllTo(server);
+
+ // Verify that notifyClients was called once for resources-list-changed
+ verify(mockProvider, times(1))
+ .notifyClients(eq(McpSchema.METHOD_NOTIFICATION_RESOURCES_LIST_CHANGED), isNull());
+ }
+}
diff --git a/mcp-server-filesystem/filesystem-native-sdk-example/src/test/java/com/github/mcp/examples/server/filesystem/McpSseServerTest.java b/mcp-server-filesystem/filesystem-native-sdk-example/src/test/java/com/github/mcp/examples/server/filesystem/McpSseServerTest.java
new file mode 100644
index 0000000..07f3c0d
--- /dev/null
+++ b/mcp-server-filesystem/filesystem-native-sdk-example/src/test/java/com/github/mcp/examples/server/filesystem/McpSseServerTest.java
@@ -0,0 +1,60 @@
+package com.github.mcp.examples.server.filesystem;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.BeforeEach;
+
+import java.lang.reflect.Field;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class McpSseServerTest {
+
+ private McpSseServer serverInstance;
+
+ @BeforeEach
+ void setup() {
+ serverInstance = new McpSseServer();
+ }
+
+ @Test
+ void initializeShouldSetServerField() throws Exception {
+ // call private initialize()
+ var initMethod = McpSseServer.class.getDeclaredMethod("initialize");
+ initMethod.setAccessible(true);
+ initMethod.invoke(serverInstance);
+
+ // verify the 'server' field is non-null
+ Field serverField = McpSseServer.class.getDeclaredField("server");
+ serverField.setAccessible(true);
+ Object srv = serverField.get(serverInstance);
+ assertNotNull(srv, "McpSyncServer should be initialized");
+ }
+
+ @Test
+ void mainShouldNotThrow() {
+ ExecutorService exec = Executors.newSingleThreadExecutor(r -> {
+ Thread t = new Thread(r);
+ t.setDaemon(true);
+ return t;
+ });
+ Future> future = exec.submit(() -> McpSseServer.main(new String[0]));
+ try {
+ future.get(2, TimeUnit.SECONDS);
+ } catch (TimeoutException e) {
+ // main() did not complete in time; cancel the task
+ future.cancel(true);
+ } catch (Exception e) {
+ fail("main() threw an exception: " + e.getMessage());
+ } finally {
+ exec.shutdownNow();
+ }
+ // If we reach here, main() started and was interrupted as expected
+ assertTrue(true);
+ }
+}
diff --git a/mcp-server-filesystem/filesystem-native-sdk-example/src/test/java/com/github/mcp/examples/server/filesystem/McpStdioServerTest.java b/mcp-server-filesystem/filesystem-native-sdk-example/src/test/java/com/github/mcp/examples/server/filesystem/McpStdioServerTest.java
new file mode 100644
index 0000000..5af81c6
--- /dev/null
+++ b/mcp-server-filesystem/filesystem-native-sdk-example/src/test/java/com/github/mcp/examples/server/filesystem/McpStdioServerTest.java
@@ -0,0 +1,40 @@
+
+package com.github.mcp.examples.server.filesystem;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class McpStdioServerTest {
+
+ private McpStdioServer serverInstance;
+
+ @BeforeEach
+ void setup() {
+ serverInstance = new McpStdioServer();
+ }
+
+ @Test
+ void initializeShouldSetServerField() throws Exception {
+ // call private initialize()
+ Method init = McpStdioServer.class.getDeclaredMethod("initialize");
+ init.setAccessible(true);
+ init.invoke(serverInstance);
+
+ // verify the 'server' field is non-null
+ Field field = McpStdioServer.class.getDeclaredField("server");
+ field.setAccessible(true);
+ Object srv = field.get(serverInstance);
+ assertNotNull(srv, "server field should be initialized");
+ }
+
+ @Test
+ void mainShouldInvokeInitializeAndNotThrow() {
+ assertDoesNotThrow(() -> McpStdioServer.main(new String[0]),
+ "main() should complete without throwing");
+ }
+}
diff --git a/mcp-server-filesystem/filesystem-native-sdk-example/src/test/java/com/github/mcp/examples/server/filesystem/McpToolsTest.java b/mcp-server-filesystem/filesystem-native-sdk-example/src/test/java/com/github/mcp/examples/server/filesystem/McpToolsTest.java
new file mode 100644
index 0000000..68ef504
--- /dev/null
+++ b/mcp-server-filesystem/filesystem-native-sdk-example/src/test/java/com/github/mcp/examples/server/filesystem/McpToolsTest.java
@@ -0,0 +1,59 @@
+package com.github.mcp.examples.server.filesystem;
+
+import io.modelcontextprotocol.server.McpSyncServer;
+import io.modelcontextprotocol.server.McpServerFeatures.SyncToolSpecification;
+import io.modelcontextprotocol.spec.McpSchema;
+import org.junit.jupiter.api.Test;
+import io.modelcontextprotocol.server.McpServer;
+import static org.mockito.Mockito.*;
+import io.modelcontextprotocol.spec.McpServerTransportProvider;
+import reactor.core.publisher.Mono;
+
+import java.io.IOException;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class McpToolsTest {
+
+ @Test
+ void readFileSpecHasCorrectTool() throws IOException {
+ SyncToolSpecification spec = McpTools.readFile();
+ McpSchema.Tool tool = spec.tool();
+ assertEquals("read_file", tool.name());
+ assertEquals("Read complete contents of a file.", tool.description());
+ assertNotNull(tool.inputSchema(), "Tool JSON schema should be present");
+ }
+
+ @Test
+ void listFilesSpecHasCorrectTool() throws IOException {
+ SyncToolSpecification spec = McpTools.listFiles();
+ McpSchema.Tool tool = spec.tool();
+ assertEquals("list_files", tool.name());
+ assertEquals("List files of a directory.", tool.description());
+ assertNotNull(tool.inputSchema(), "Tool JSON schema should be present");
+ }
+
+
+ @Test
+ void addAllToRegistersToolsNotifies() {
+ // Create a mock transport provider
+ McpServerTransportProvider mockProvider = mock(McpServerTransportProvider.class);
+ // Stub the notification call to return a real (empty) Mono
+ when(mockProvider.notifyClients(eq(McpSchema.METHOD_NOTIFICATION_TOOLS_LIST_CHANGED), isNull()))
+ .thenReturn(Mono.empty());
+
+ // Build async server with mock transport
+ var async = McpServer.async(mockProvider)
+ .capabilities(McpSchema.ServerCapabilities.builder()
+ .tools(true)
+ .build())
+ .build();
+ McpSyncServer server = new McpSyncServer(async);
+
+ // Invoke tool registration
+ McpTools.addAllTo(server);
+
+ // Verify that notifyClients was called twice
+ verify(mockProvider, times(2)).notifyClients(eq(McpSchema.METHOD_NOTIFICATION_TOOLS_LIST_CHANGED), isNull());
+ }
+}
diff --git a/mcp-server-filesystem/pom.xml b/mcp-server-filesystem/pom.xml
index 078db3a..49dd37c 100644
--- a/mcp-server-filesystem/pom.xml
+++ b/mcp-server-filesystem/pom.xml
@@ -19,16 +19,6 @@
filesystem-native-sdk-example
-
- 17
- ${java.version}
- ${java.version}
- UTF-8
- UTF-8
-
- 3.6.0
-
-
@@ -45,7 +35,6 @@
org.apache.maven.plugins
maven-shade-plugin
- ${maven-shade-plugin.version}
diff --git a/pom.xml b/pom.xml
index 92e8e3f..ceb7d6d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,20 +21,78 @@
UTF-8
UTF-8
+ 3.4.0
4.0.0
+ 3.6.0
+ 4.11.0
+ 5.11.4
+ 2.0.16
0.3.0
+
+
+
+ org.junit.jupiter
+ junit-jupiter
+ ${junit.jupiter.version}
+ test
+
+
+ org.mockito
+ mockito-inline
+ ${mockito.version}
+ test
+
+
+ org.mockito
+ mockito-junit-jupiter
+ ${mockito.version}
+ test
+
+
+ org.slf4j
+ slf4j-simple
+ ${slf4j.simple.version}
+ test
+
+
+
+
io.github.codeboyzhou
mcp-declarative-java-sdk
- 0.3.0-SNAPSHOT
+ ${mcp-declarative-java-sdk.version}
+
+
+
+ com.github.ekryd.sortpom
+ sortpom-maven-plugin
+ ${sortpom-maven-plugin.version}
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ ${maven-shade-plugin.version}
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ ${maven-surefire-plugin.version}
+
+ false
+ -Dnet.bytebuddy.experimental=true
+
+
+
+
+
com.github.ekryd.sortpom