主题
Java SDK
Model Context Protocol (MCP) 的 Java SDK 提供了构建 MCP 服务器和客户端的完整工具集,支持 Java 8+ 和现代 Java 特性。
安装
Maven
xml
<dependency>
<groupId>io.modelcontextprotocol</groupId>
<artifactId>mcp-java-sdk</artifactId>
<version>1.0.0</version>
</dependency>
Gradle
gradle
implementation 'io.modelcontextprotocol:mcp-java-sdk:1.0.0'
快速开始
创建 MCP 服务器
java
import io.mcp.server.McpServer;
import io.mcp.server.ServerOptions;
import io.mcp.server.tool.Tool;
import io.mcp.server.tool.ToolCall;
import io.mcp.server.tool.ToolSchema;
import io.mcp.common.JsonSchema;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
public class MyMcpServer {
public static void main(String[] args) {
// 创建服务器
McpServer server = McpServer.builder()
.name("my-java-server")
.version("1.0.0")
.description("Java MCP 服务器示例")
.build();
// 注册工具
server.registerTool(new EchoTool());
// 启动服务器
server.start();
}
}
class EchoTool implements Tool {
@Override
public String getName() {
return "echo";
}
@Override
public String getDescription() {
return "回显输入的消息";
}
@Override
public JsonSchema getInputSchema() {
return JsonSchema.builder()
.type("object")
.property("message", JsonSchema.builder()
.type("string")
.description("要回显的消息")
.build())
.required("message")
.build();
}
@Override
public CompletableFuture<Object> call(ToolCall call) {
Map<String, Object> args = call.getArguments();
String message = (String) args.get("message");
Map<String, String> result = Map.of("echo", message);
return CompletableFuture.completedFuture(result);
}
}
创建 MCP 客户端
java
import io.mcp.client.McpClient;
import io.mcp.client.ClientOptions;
import io.mcp.transport.StdioTransport;
import io.mcp.transport.WebSocketTransport;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
public class MyMcpClient {
public static void main(String[] args) throws Exception {
// 创建传输层
StdioTransport transport = new StdioTransport();
// 创建客户端
McpClient client = McpClient.builder()
.transport(transport)
.connectTimeout(Duration.ofSeconds(10))
.requestTimeout(Duration.ofSeconds(30))
.build();
// 连接到服务器
client.connect().get();
try {
// 列出可用工具
var tools = client.listTools().get();
System.out.println("可用工具: " + tools);
// 调用工具
Map<String, Object> args = Map.of("message", "Hello from Java!");
var result = client.callTool("echo", args).get();
System.out.println("工具调用结果: " + result);
} finally {
client.close();
}
}
}
核心功能
服务器功能
工具注册
java
// 简单工具
server.registerTool(new SimpleCalculatorTool());
// 异步工具
server.registerTool(new AsyncDatabaseTool());
// 带验证的工具
server.registerTool(new ValidatedFileTool());
资源管理
java
import io.mcp.server.resource.Resource;
import io.mcp.server.resource.ResourceProvider;
class FileResourceProvider implements ResourceProvider {
@Override
public CompletableFuture<Resource> getResource(String uri) {
return CompletableFuture.supplyAsync(() -> {
// 读取文件内容
String content = Files.readString(Paths.get(uri));
return Resource.builder()
.uri(uri)
.mimeType("text/plain")
.content(content)
.build();
});
}
@Override
public CompletableFuture<List<String>> listResources() {
return CompletableFuture.supplyAsync(() -> {
// 返回可用资源列表
return List.of("file:///path/to/file1.txt", "file:///path/to/file2.txt");
});
}
}
// 注册资源提供者
server.registerResourceProvider(new FileResourceProvider());
提示模板
java
import io.mcp.server.prompt.Prompt;
import io.mcp.server.prompt.PromptProvider;
class CodeReviewPromptProvider implements PromptProvider {
@Override
public CompletableFuture<Prompt> getPrompt(String name, Map<String, Object> arguments) {
if ("code-review".equals(name)) {
String code = (String) arguments.get("code");
String language = (String) arguments.get("language");
String promptText = String.format(
"请审查以下 %s 代码并提供改进建议:\n\n```%s\n%s\n```",
language, language, code
);
return CompletableFuture.completedFuture(
Prompt.builder()
.name(name)
.description("代码审查提示")
.content(promptText)
.build()
);
}
return CompletableFuture.failedFuture(
new IllegalArgumentException("未知提示: " + name)
);
}
@Override
public CompletableFuture<List<String>> listPrompts() {
return CompletableFuture.completedFuture(List.of("code-review"));
}
}
// 注册提示提供者
server.registerPromptProvider(new CodeReviewPromptProvider());
客户端功能
连接管理
java
// 自动重连客户端
McpClient client = McpClient.builder()
.transport(transport)
.autoReconnect(true)
.maxReconnectAttempts(5)
.reconnectDelay(Duration.ofSeconds(2))
.build();
// 连接状态监听
client.addConnectionListener(new ConnectionListener() {
@Override
public void onConnected() {
System.out.println("已连接到服务器");
}
@Override
public void onDisconnected() {
System.out.println("与服务器断开连接");
}
@Override
public void onError(Throwable error) {
System.err.println("连接错误: " + error.getMessage());
}
});
批量操作
java
// 批量调用工具
List<CompletableFuture<Object>> futures = List.of(
client.callTool("tool1", args1),
client.callTool("tool2", args2),
client.callTool("tool3", args3)
);
CompletableFuture<List<Object>> allResults = CompletableFuture.allOf(
futures.toArray(new CompletableFuture[0])
).thenApply(v -> futures.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList())
);
List<Object> results = allResults.get();
传输协议
Stdio 传输
java
StdioTransport transport = StdioTransport.builder()
.command("python", "server.py")
.workingDirectory("/path/to/server")
.environment(Map.of("ENV_VAR", "value"))
.build();
WebSocket 传输
java
WebSocketTransport transport = WebSocketTransport.builder()
.uri("ws://localhost:8080/mcp")
.headers(Map.of("Authorization", "Bearer token"))
.connectTimeout(Duration.ofSeconds(10))
.build();
HTTP SSE 传输
java
SseTransport transport = SseTransport.builder()
.uri("http://localhost:8080/mcp")
.headers(Map.of("Authorization", "Bearer token"))
.readTimeout(Duration.ofSeconds(30))
.build();
高级特性
中间件支持
java
// 日志中间件
server.addMiddleware(new LoggingMiddleware());
// 认证中间件
server.addMiddleware(new AuthenticationMiddleware());
// 限流中间件
server.addMiddleware(new RateLimitingMiddleware());
class LoggingMiddleware implements Middleware {
@Override
public CompletableFuture<Object> handle(Request request, MiddlewareChain chain) {
System.out.println("处理请求: " + request.getMethod());
long startTime = System.currentTimeMillis();
return chain.next(request).whenComplete((result, error) -> {
long duration = System.currentTimeMillis() - startTime;
System.out.println("请求完成,耗时: " + duration + "ms");
});
}
}
事件系统
java
// 服务器事件
server.addEventListener(ServerEvent.TOOL_CALLED, event -> {
ToolCallEvent toolEvent = (ToolCallEvent) event;
System.out.println("工具被调用: " + toolEvent.getToolName());
});
server.addEventListener(ServerEvent.ERROR, event -> {
ErrorEvent errorEvent = (ErrorEvent) event;
System.err.println("服务器错误: " + errorEvent.getError().getMessage());
});
// 客户端事件
client.addEventListener(ClientEvent.TOOL_RESULT, event -> {
ToolResultEvent resultEvent = (ToolResultEvent) event;
System.out.println("工具结果: " + resultEvent.getResult());
});
配置管理
java
// 从配置文件加载
McpConfig config = McpConfig.fromFile("mcp-config.yaml");
McpServer server = McpServer.builder()
.config(config)
.build();
// 程序化配置
McpConfig config = McpConfig.builder()
.server(ServerConfig.builder()
.name("my-server")
.version("1.0.0")
.maxConnections(100)
.requestTimeout(Duration.ofSeconds(30))
.build())
.logging(LoggingConfig.builder()
.level(LogLevel.INFO)
.file("/var/log/mcp-server.log")
.build())
.build();
测试
单元测试
java
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeEach;
import static org.junit.jupiter.api.Assertions.*;
class EchoToolTest {
private EchoTool tool;
@BeforeEach
void setUp() {
tool = new EchoTool();
}
@Test
void testEcho() throws Exception {
ToolCall call = ToolCall.builder()
.name("echo")
.arguments(Map.of("message", "test"))
.build();
Object result = tool.call(call).get();
assertEquals(Map.of("echo", "test"), result);
}
@Test
void testEchoWithMissingArgument() {
ToolCall call = ToolCall.builder()
.name("echo")
.arguments(Map.of())
.build();
assertThrows(IllegalArgumentException.class, () -> {
tool.call(call).get();
});
}
}
集成测试
java
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
class McpIntegrationTest {
private McpServer server;
private McpClient client;
@BeforeEach
void setUp() throws Exception {
// 启动测试服务器
server = McpServer.builder()
.name("test-server")
.build();
server.registerTool(new EchoTool());
server.start();
// 创建客户端
StdioTransport transport = new StdioTransport();
client = McpClient.builder()
.transport(transport)
.build();
client.connect().get();
}
@AfterEach
void tearDown() throws Exception {
if (client != null) {
client.close();
}
if (server != null) {
server.stop();
}
}
@Test
void testToolCall() throws Exception {
Map<String, Object> args = Map.of("message", "test");
Object result = client.callTool("echo", args).get();
assertEquals(Map.of("echo", "test"), result);
}
}
部署
Spring Boot 集成
java
@SpringBootApplication
public class McpServerApplication {
@Bean
public McpServer mcpServer() {
McpServer server = McpServer.builder()
.name("spring-mcp-server")
.version("1.0.0")
.build();
// 注册 Spring Bean 作为工具
server.registerTool(applicationContext.getBean(DatabaseTool.class));
server.registerTool(applicationContext.getBean(EmailTool.class));
return server;
}
@EventListener
public void onApplicationReady(ApplicationReadyEvent event) {
mcpServer().start();
}
public static void main(String[] args) {
SpringApplication.run(McpServerApplication.class, args);
}
}
Docker 部署
dockerfile
FROM openjdk:17-jre-slim
WORKDIR /app
COPY target/mcp-server.jar app.jar
EXPOSE 8080
CMD ["java", "-jar", "app.jar"]
Kubernetes 部署
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: mcp-server
spec:
replicas: 3
selector:
matchLabels:
app: mcp-server
template:
metadata:
labels:
app: mcp-server
spec:
containers:
- name: mcp-server
image: my-registry/mcp-server:1.0.0
ports:
- containerPort: 8080
env:
- name: MCP_SERVER_NAME
value: "kubernetes-mcp-server"
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
name: mcp-server-service
spec:
selector:
app: mcp-server
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: LoadBalancer