Skip to content

Commit 8c5bc7f

Browse files
Merge pull request #18937 from brokenhardisk/master
BAEL-9308: Java SDK for MCP
2 parents 931c853 + 0630865 commit 8c5bc7f

File tree

8 files changed

+261
-0
lines changed

8 files changed

+261
-0
lines changed

java-mcp/pom.xml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
<artifactId>java-mcp</artifactId>
7+
<name>java-mcp</name>
8+
9+
<parent>
10+
<groupId>com.baeldung</groupId>
11+
<artifactId>parent-modules</artifactId>
12+
<version>1.0.0-SNAPSHOT</version>
13+
</parent>
14+
15+
16+
<dependencies>
17+
<dependency>
18+
<groupId>io.modelcontextprotocol.sdk</groupId>
19+
<artifactId>mcp</artifactId>
20+
<version>${mcp.version}</version>
21+
</dependency>
22+
</dependencies>
23+
24+
<build>
25+
<plugins>
26+
<plugin>
27+
<groupId>org.apache.maven.plugins</groupId>
28+
<artifactId>maven-shade-plugin</artifactId>
29+
<version>3.5.0</version>
30+
<executions>
31+
<execution>
32+
<phase>package</phase>
33+
<goals>
34+
<goal>shade</goal>
35+
</goals>
36+
<configuration>
37+
<transformers>
38+
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
39+
<mainClass>mcp.McpServerApp</mainClass>
40+
</transformer>
41+
</transformers>
42+
</configuration>
43+
</execution>
44+
</executions>
45+
</plugin>
46+
<plugin>
47+
<groupId>org.apache.maven.plugins</groupId>
48+
<artifactId>maven-compiler-plugin</artifactId>
49+
<configuration>
50+
<source>21</source>
51+
<target>21</target>
52+
</configuration>
53+
</plugin>
54+
</plugins>
55+
</build>
56+
57+
58+
<properties>
59+
<mcp.version>0.15.0</mcp.version>
60+
</properties>
61+
62+
</project>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package mcp;
2+
3+
import java.util.HashMap;
4+
import java.util.List;
5+
import java.util.Map;
6+
7+
import io.modelcontextprotocol.server.McpServerFeatures;
8+
import io.modelcontextprotocol.spec.McpSchema;
9+
10+
public class LoggingTool {
11+
12+
public static McpServerFeatures.SyncToolSpecification logPromptTool() {
13+
McpSchema.JsonSchema inputSchema = new McpSchema.JsonSchema("object", Map.of("prompt", String.class), List.of("prompt"), false, null, null);
14+
15+
return new McpServerFeatures.SyncToolSpecification(
16+
new McpSchema.Tool("logPrompt", "Log Prompt", "Logs a provided prompt", inputSchema, null, null, null), (exchange, args) -> {
17+
String prompt = (String) args.get("prompt");
18+
return McpSchema.CallToolResult.builder()
19+
.content(List.of(new McpSchema.TextContent("Input Prompt: " + prompt)))
20+
.isError(false)
21+
.build();
22+
});
23+
}
24+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package mcp;
2+
3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
5+
import io.modelcontextprotocol.client.McpSyncClient;
6+
import io.modelcontextprotocol.client.transport.ServerParameters;
7+
import io.modelcontextprotocol.client.transport.StdioClientTransport;
8+
import io.modelcontextprotocol.json.jackson.JacksonMcpJsonMapper;
9+
import io.modelcontextprotocol.spec.McpClientTransport;
10+
11+
public class McpClientApp {
12+
13+
public static McpSyncClient getClient() {
14+
ServerParameters params = ServerParameters.builder("npx")
15+
.args("-y", "@modelcontextprotocol/server-everything")
16+
.build();
17+
18+
JacksonMcpJsonMapper jsonMapper = new JacksonMcpJsonMapper(new ObjectMapper());
19+
McpClientTransport transport = new StdioClientTransport(params, jsonMapper);
20+
21+
return io.modelcontextprotocol.client.McpClient.sync(transport)
22+
.build();
23+
24+
}
25+
26+
public static void main(String[] args) {
27+
McpSyncClient client = getClient();
28+
client.initialize();
29+
}
30+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package mcp;
2+
3+
import java.io.IOException;
4+
import java.util.Map;
5+
6+
import org.slf4j.Logger;
7+
import org.slf4j.LoggerFactory;
8+
9+
import com.fasterxml.jackson.databind.ObjectMapper;
10+
11+
import io.modelcontextprotocol.client.McpClient;
12+
import io.modelcontextprotocol.client.McpSyncClient;
13+
import io.modelcontextprotocol.client.transport.ServerParameters;
14+
import io.modelcontextprotocol.client.transport.StdioClientTransport;
15+
import io.modelcontextprotocol.json.jackson.JacksonMcpJsonMapper;
16+
import io.modelcontextprotocol.spec.McpClientTransport;
17+
import io.modelcontextprotocol.spec.McpSchema.CallToolRequest;
18+
import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
19+
import io.modelcontextprotocol.spec.McpSchema.ListToolsResult;
20+
21+
22+
public class McpClientApp2 {
23+
24+
private static final Logger log = LoggerFactory.getLogger(McpClientApp2.class);
25+
26+
public static void main(String[] args) {
27+
String jarPath = new java.io.File("java-mcp/target/java-mcp-1.0.0-SNAPSHOT.jar").getAbsolutePath();
28+
ServerParameters params = ServerParameters.builder("java")
29+
.args("-jar", jarPath)
30+
.build();
31+
32+
JacksonMcpJsonMapper jsonMapper = new JacksonMcpJsonMapper(new ObjectMapper());
33+
McpClientTransport transport = new StdioClientTransport(params, jsonMapper);
34+
35+
McpSyncClient client = McpClient.sync(transport)
36+
.build();
37+
38+
client.initialize();
39+
40+
ListToolsResult tools = client.listTools();
41+
McpClientApp2.log.info("Tools exposed by the server:");
42+
tools.tools()
43+
.forEach(tool -> System.out.println(" - " + tool.name()));
44+
45+
McpClientApp2.log.info("\nCalling 'logPrompt' tool...");
46+
CallToolResult result = client.callTool(new CallToolRequest("logPrompt", Map.of("prompt", "Hello from MCP client!")));
47+
McpClientApp2.log.info("Result: " + result.content());
48+
49+
client.closeGracefully();
50+
}
51+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package mcp;
2+
3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
5+
import io.modelcontextprotocol.json.jackson.JacksonMcpJsonMapper;
6+
import io.modelcontextprotocol.server.McpServer;
7+
import io.modelcontextprotocol.server.McpSyncServer;
8+
import io.modelcontextprotocol.server.transport.StdioServerTransportProvider;
9+
import io.modelcontextprotocol.spec.McpSchema;
10+
11+
public class McpServerApp {
12+
13+
public static McpSyncServer createServer() {
14+
JacksonMcpJsonMapper jsonMapper = new JacksonMcpJsonMapper(new ObjectMapper());
15+
StdioServerTransportProvider transportProvider = new StdioServerTransportProvider(jsonMapper);
16+
17+
return McpServer.sync(transportProvider)
18+
.serverInfo("baeldung-demo-server", "0.0.1")
19+
.capabilities(McpSchema.ServerCapabilities.builder()
20+
.tools(true)
21+
.logging()
22+
.build())
23+
.tools(LoggingTool.logPromptTool())
24+
.build();
25+
}
26+
27+
public static void main(String[] args) {
28+
createServer();
29+
}
30+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<configuration>
2+
<appender name="STDERR" class="ch.qos.logback.core.ConsoleAppender">
3+
<target>System.err</target>
4+
<encoder>
5+
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
6+
</encoder>
7+
</appender>
8+
9+
<root level="info">
10+
<appender-ref ref="STDERR"/>
11+
</root>
12+
</configuration>
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package mcp;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertFalse;
5+
import static org.junit.jupiter.api.Assertions.assertNotNull;
6+
import static org.junit.jupiter.api.Assertions.assertNull;
7+
8+
import java.util.Map;
9+
10+
import org.junit.jupiter.api.BeforeAll;
11+
import org.junit.jupiter.api.Test;
12+
13+
import io.modelcontextprotocol.client.McpSyncClient;
14+
import io.modelcontextprotocol.server.McpServerFeatures;
15+
import io.modelcontextprotocol.spec.McpSchema;
16+
17+
class McpClientAppServerUnitTest {
18+
19+
private static McpSyncClient client;
20+
21+
@BeforeAll
22+
static void init() {
23+
client = McpClientApp.getClient();
24+
client.initialize();
25+
}
26+
27+
@Test
28+
void whenLogPromptToolCalled_thenReturnsResult() {
29+
McpSchema.CallToolRequest request = new McpSchema.CallToolRequest("", Map.of("prompt", "Unit test message"));
30+
31+
McpServerFeatures.SyncToolSpecification toolSpec = LoggingTool.logPromptTool();
32+
McpSchema.CallToolResult result = toolSpec.callHandler()
33+
.apply(null, request);
34+
assertNotNull(result);
35+
assertFalse(result.isError());
36+
assertEquals("Input Prompt: Unit test message", ((McpSchema.TextContent) (result.content()
37+
.getFirst())).text());
38+
}
39+
40+
@Test
41+
void whenCalledViaClient_thenReturnsLoggedResult() {
42+
McpSchema.CallToolRequest request = new McpSchema.CallToolRequest("echo", Map.of("message", "Client-server test message"));
43+
McpSchema.CallToolResult result = client.callTool(request);
44+
45+
assertNotNull(result);
46+
assertNull(result.isError());
47+
assertEquals("Echo: Client-server test message", ((McpSchema.TextContent) (result.content()
48+
.getFirst())).text());
49+
}
50+
}
51+

pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,7 @@
841841
<module>web-modules</module>
842842
<module>webrtc</module>
843843
<module>xml-modules</module>
844+
<module>java-mcp</module>
844845
</modules>
845846

846847
<properties>

0 commit comments

Comments
 (0)