模型上下文协议(MCP)Java SDK v0.8.0规范
引言
模型上下文协议(MCP)是用于AI模型和外部工具或资源之间通信的标准化协议。Java SDK提供了此协议的强大实现,使Java应用程序能够创建向AI模型公开工具和资源的MCP服务器,以及可以与这些服务器通信的MCP客户端。
本文档是MCP Java SDK版本0.8.0的综合规范,旨在用于MCP客户端和服务器的AI辅助代码生成。
建筑
MCP Java SDK遵循模块化架构,具有明确的关注点分离:
graph TD
Client[Client] --> Transport[Transport Layer]
Server[Server] --> Transport
Transport --> Protocol[Protocol Layer]
Protocol --> JSON[JSON Schema]
Client --> Resources[Resources]
Client --> Tools[Tools]
Server --> Resources
Server --> Tools
Server --> ErrorHandling[Error Handling]
Client --> ErrorHandling核心组件
- 客户端 -与MCP服务器连接以访问资源和工具
- 服务器 -向MCP客户端公开资源和工具
- 传输层 -处理客户端和服务器之间的通信
- 协议层 -实施MCP协议规范
- 资源 -服务器暴露的静态或动态数据
- 工具 -服务器公开的可执行函数
封装结构
SDK分为以下关键包:
io.modelcontextprotocol.client-客户端实现(McpClient)io.modelcontextprotocol.server-服务器实现(McpServer、McpSyncServer、McpAsyncServer)io.modelcontextprotocol.client.transport-客户端传输实现io.modelcontextprotocol.server.transport-服务器传输实现和提供商io.modelcontextprotocol.spec-核心协议规范和模式类io.modelcontextprotocol.transport-传输层接口和实现io.modelcontextprotocol.types-MCP协议的类型定义io.modelcontextprotocol.errors-错误处理类和实用程序
安装
Maven依赖关系
将MCP BOM(物料清单)添加到您的项目中,以确保所有组件的兼容版本:
io.modelcontextprotocol.sdk
mcp-bom
0.8.0
pom
import
然后添加您需要的特定依赖关系:
io.modelcontextprotocol.sdk
mcp
io.modelcontextprotocol.sdk
mcp-test
jakarta.servlet
jakarta.servlet-api
5.0.0
provided
客户端实施
带工具的同步客户端
import io.modelcontextprotocol.client.McpClient;
import io.modelcontextprotocol.client.McpSyncClient;
import io.modelcontextprotocol.client.transport.ServerParameters;
import io.modelcontextprotocol.client.transport.StdioClientTransport;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpError;
import java.util.HashMap;
import java.util.Map;
public class SyncClientStdioToolsExample {
public static void main(String[] args) throws Exception {
// Create client info
McpSchema.Implementation clientInfo = new McpSchema.Implementation("example-client", "1.0.0");
// Create server parameters
ServerParameters serverParams = ServerParameters.builder("example-server-command")
.build();
// Create transport with server parameters
StdioClientTransport transport = new StdioClientTransport(serverParams);
// Create the client using the builder pattern
McpSyncClient client = McpClient.sync(transport)
.clientInfo(clientInfo)
.build();
try {
// Read a resource
McpSchema.ReadResourceRequest request = new McpSchema.ReadResourceRequest("example://resource");
McpSchema.ReadResourceResult result = client.readResource(request);
// Access the resource contents
if (result.contents() != null && !result.contents().isEmpty()) {
McpSchema.ResourceContents contents = result.contents().get(0);
if (contents instanceof McpSchema.TextResourceContents textContents) {
System.out.println("Resource content: " + textContents.text());
}
}
// Call a tool with a Map of arguments
Map toolArgs = new HashMap<>();
toolArgs.put("param1", "value1");
toolArgs.put("param2", 42);
McpSchema.CallToolRequest toolRequest = new McpSchema.CallToolRequest("example-tool", toolArgs);
McpSchema.CallToolResult toolResponse = client.callTool(toolRequest);
// Access the tool response content
if (toolResponse.content() != null && !toolResponse.content().isEmpty()) {
McpSchema.Content content = toolResponse.content().get(0);
if (content instanceof McpSchema.TextContent textContent) {
System.out.println("Tool response: " + textContent.text());
}
}
} finally {
// Close the client
client.close();
}
}
}带提示的同步客户端
import io.modelcontextprotocol.client.McpClient;
import io.modelcontextprotocol.client.McpSyncClient;
import io.modelcontextprotocol.client.transport.ServerParameters;
import io.modelcontextprotocol.client.transport.StdioClientTransport;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpSchema.GetPromptRequest;
import io.modelcontextprotocol.spec.McpSchema.GetPromptResult;
import io.modelcontextprotocol.spec.McpSchema.ListPromptsResult;
import io.modelcontextprotocol.spec.McpSchema.Prompt;
import io.modelcontextprotocol.spec.McpSchema.PromptMessage;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class SyncClientStdioPromptsExample {
public static void main(String[] args) throws Exception {
// Create client info
McpSchema.Implementation clientInfo = new McpSchema.Implementation("example-client", "1.0.0");
// Create server parameters
ServerParameters serverParams = ServerParameters.builder("example-server-command")
.build();
// Create transport with server parameters
StdioClientTransport transport = new StdioClientTransport(serverParams);
// Create the client using the builder pattern
McpSyncClient client = McpClient.sync(transport)
.clientInfo(clientInfo)
.build();
try {
// List available prompts
ListPromptsResult promptsResult = client.listPrompts();
if (promptsResult.prompts() != null && !promptsResult.prompts().isEmpty()) {
System.out.println("Available prompts:");
for (Prompt prompt : promptsResult.prompts()) {
System.out.println("- " + prompt.name() + ": " + prompt.description());
}
// Get a specific prompt
String promptName = promptsResult.prompts().get(0).name();
// Create arguments for the prompt if needed
Map promptArgs = new HashMap<>();
promptArgs.put("language", "Java");
promptArgs.put("code", "public class Example { public static void main(String[] args) { } }");
GetPromptRequest promptRequest = new GetPromptRequest(promptName, promptArgs);
GetPromptResult promptResult = client.getPrompt(promptRequest);
// Process the prompt result
if (promptResult.messages() != null && !promptResult.messages().isEmpty()) {
System.out.println("Prompt messages:");
for (PromptMessage message : promptResult.messages()) {
System.out.println("Role: " + message.role());
System.out.println("Content: " + message.content());
}
}
} else {
System.out.println("No prompts available from the server.");
}
} finally {
// Close the client
client.close();
}
}
}带工具的异步客户端
import io.modelcontextprotocol.client.McpClient;
import io.modelcontextprotocol.client.McpAsyncClient;
import io.modelcontextprotocol.client.transport.ServerParameters;
import io.modelcontextprotocol.client.transport.StdioClientTransport;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpError;
import reactor.core.publisher.Mono;
import java.util.HashMap;
import java.util.Map;
public class AsyncClientStdioToolsExample {
public static void main(String[] args) throws Exception {
// Create client info
McpSchema.Implementation clientInfo = new McpSchema.Implementation("example-client", "1.0.0");
// Create server parameters
ServerParameters serverParams = ServerParameters.builder("example-server-command")
.build();
// Create transport with server parameters
StdioClientTransport transport = new StdioClientTransport(serverParams);
// Create the client using the builder pattern
McpAsyncClient client = McpClient.async(transport)
.clientInfo(clientInfo)
.build();
try {
// Initialize the client (connects to the server)
client.initialize().block(); // Block until initialization completes
// Read a resource
McpSchema.ReadResourceRequest request = new McpSchema.ReadResourceRequest("example://resource");
McpSchema.ReadResourceResult result = client.readResource(request).block();
// Access the resource contents
if (result.contents() != null && !result.contents().isEmpty()) {
McpSchema.ResourceContents contents = result.contents().get(0);
if (contents instanceof McpSchema.TextResourceContents textContents) {
System.out.println("Resource content: " + textContents.text());
}
}
// Call a tool with a Map of arguments
Map toolArgs = new HashMap<>();
toolArgs.put("param1", "value1");
toolArgs.put("param2", 42);
McpSchema.CallToolRequest toolRequest = new McpSchema.CallToolRequest("example-tool", toolArgs);
McpSchema.CallToolResult toolResponse = client.callTool(toolRequest).block();
// Access the tool response content
if (toolResponse.content() != null && !toolResponse.content().isEmpty()) {
McpSchema.Content content = toolResponse.content().get(0);
if (content instanceof McpSchema.TextContent textContent) {
System.out.println("Tool response: " + textContent.text());
}
}
} catch (Exception e) {
if (e.getCause() instanceof McpError) {
McpError mcpError = (McpError) e.getCause();
System.err.println("MCP Error: " + mcpError.getMessage());
} else {
System.err.println("Error: " + e.getMessage());
}
} finally {
// Close the client
client.close();
}
}
}带提示的异步客户端
import io.modelcontextprotocol.client.McpClient;
import io.modelcontextprotocol.client.McpAsyncClient;
import io.modelcontextprotocol.client.transport.ServerParameters;
import io.modelcontextprotocol.client.transport.StdioClientTransport;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpSchema.GetPromptRequest;
import io.modelcontextprotocol.spec.McpSchema.GetPromptResult;
import io.modelcontextprotocol.spec.McpSchema.ListPromptsResult;
import io.modelcontextprotocol.spec.McpSchema.Prompt;
import io.modelcontextprotocol.spec.McpSchema.PromptMessage;
import io.modelcontextprotocol.spec.McpError;
import java.util.HashMap;
import java.util.Map;
public class AsyncClientStdioPromptsExample {
public static void main(String[] args) throws Exception {
// Create client info
McpSchema.Implementation clientInfo = new McpSchema.Implementation("example-client", "1.0.0");
// Create server parameters
ServerParameters serverParams = ServerParameters.builder("example-server-command")
.build();
// Create transport with server parameters
StdioClientTransport transport = new StdioClientTransport(serverParams);
// Create the client using the builder pattern
McpAsyncClient client = McpClient.async(transport)
.clientInfo(clientInfo)
.build();
try {
// Initialize the client (connects to the server)
client.initialize().block(); // Block until initialization completes
// List available prompts
ListPromptsResult promptsResult = client.listPrompts().block();
if (promptsResult.prompts() != null && !promptsResult.prompts().isEmpty()) {
System.out.println("Available prompts:");
for (Prompt prompt : promptsResult.prompts()) {
System.out.println("- " + prompt.name() + ": " + prompt.description());
}
// Get a specific prompt
String promptName = promptsResult.prompts().get(0).name();
// Create arguments for the prompt if needed
Map promptArgs = new HashMap<>();
promptArgs.put("language", "Java");
promptArgs.put("code", "public class Example { public static void main(String[] args) { } }");
GetPromptRequest promptRequest = new GetPromptRequest(promptName, promptArgs);
GetPromptResult promptResult = client.getPrompt(promptRequest).block();
// Process the prompt result
if (promptResult.messages() != null && !promptResult.messages().isEmpty()) {
System.out.println("Prompt messages:");
for (PromptMessage message : promptResult.messages()) {
System.out.println("Role: " + message.role());
System.out.println("Content: " + message.content());
}
}
} else {
System.out.println("No prompts available from the server.");
}
} catch (Exception e) {
if (e.getCause() instanceof McpError) {
McpError mcpError = (McpError) e.getCause();
System.err.println("MCP Error: " + mcpError.getMessage());
} else {
System.err.println("Error: " + e.getMessage());
}
} finally {
// Close the client
client.close();
}
}
}服务器实现
带工具的同步服务器
import io.modelcontextprotocol.server.McpServer;
import io.modelcontextprotocol.server.McpSyncServer;
import io.modelcontextprotocol.server.transport.StdioServerTransportProvider;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpError;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class SyncServerStdioToolsExample {
public static void main(String[] args) throws Exception {
// Create server info
McpSchema.Implementation serverInfo = new McpSchema.Implementation("example-server", "1.0.0");
// Create transport provider
StdioServerTransportProvider transportProvider = new StdioServerTransportProvider();
// Create server using the builder pattern
McpSyncServer server = McpServer.sync(transportProvider)
.serverInfo(serverInfo)
.tool(
new McpSchema.Tool(
"example-tool",
"An example tool",
createToolSchema()
),
(exchange, toolArgs) -> {
String param1 = (String) toolArgs.get("param1");
Number param2 = (Number) toolArgs.get("param2");
List content = new ArrayList<>();
content.add(new McpSchema.TextContent(
null,
null,
"Tool executed with param1=" + param1 + ", param2=" + param2
));
return new McpSchema.CallToolResult(content, false);
}
)
.build();
System.err.println("Server started");
}
/**
* Creates the JSON schema for the example tool.
*/
private static McpSchema.JsonSchema createToolSchema() {
// Create input schema for the tool
Map properties = new HashMap<>();
Map param1 = new HashMap<>();
param1.put("type", "string");
param1.put("description", "A string parameter");
Map param2 = new HashMap<>();
param2.put("type", "number");
param2.put("description", "A numeric parameter");
properties.put("param1", param1);
properties.put("param2", param2);
List required = List.of("param1");
return new McpSchema.JsonSchema("object", properties, required, null);
}
}带提示的同步服务器
import io.modelcontextprotocol.server.McpServer;
import io.modelcontextprotocol.server.McpSyncServer;
import io.modelcontextprotocol.server.transport.StdioServerTransportProvider;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpSchema.Prompt;
import io.modelcontextprotocol.spec.McpSchema.PromptArgument;
import io.modelcontextprotocol.spec.McpSchema.PromptMessage;
import io.modelcontextprotocol.spec.McpSchema.GetPromptRequest;
import io.modelcontextprotocol.spec.McpSchema.GetPromptResult;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class SyncServerStdioPromptsExample {
public static void main(String[] args) throws Exception {
// Create server info
McpSchema.Implementation serverInfo = new McpSchema.Implementation("prompts-example-server", "1.0.0");
// Create transport provider
StdioServerTransportProvider transportProvider = new StdioServerTransportProvider();
// Create a code analysis prompt
List
codeAnalysisArgs = new ArrayList<>();
codeAnalysisArgs.add(new PromptArgument(
"language",
"The programming language of the code",
true
));
codeAnalysisArgs.add(new PromptArgument(
"code",
"The code to analyze",
true
));
Prompt codeAnalysisPrompt = new Prompt(
"code-analysis",
"Analyzes code for potential issues and improvements",
codeAnalysisArgs
);
// Create server using the builder pattern
McpSyncServer server = McpServer.sync(transportProvider)
.serverInfo(serverInfo)
.prompt(
codeAnalysisPrompt,
(exchange, request) -> {
// Extract arguments from the request
String language = (String) request.arguments().get("language");
String code = (String) request.arguments().get("code");
// Create prompt messages
List
messages = new ArrayList<>();
// System message
messages.add(new PromptMessage(
"system",
"You are a code analysis assistant that helps identify issues and suggest improvements."
));
// User message with the code
messages.add(new PromptMessage(
"user",
"Please analyze this " + language + " code:\n\n```" + language + "\n" + code + "\n```"
));
// Assistant message with the analysis
messages.add(new PromptMessage(
"assistant",
"Here's my analysis of your " + language + " code:\n\n" +
"1. The code is very minimal and doesn't do anything yet.\n" +
"2. Consider adding some functionality to the main method.\n" +
"3. Add comments to explain the purpose of the class."
));
// Return the prompt result
return new GetPromptResult(
"Code analysis for " + language,
messages
);
}
)
.build();
System.err.println("Prompts server started");
}
}带工具的异步服务器
import io.modelcontextprotocol.server.McpServer;
import io.modelcontextprotocol.server.McpAsyncServer;
import io.modelcontextprotocol.server.transport.StdioServerTransportProvider;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpError;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import reactor.core.publisher.Mono;
public class AsyncServerStdioToolsExample {
public static void main(String[] args) {
try {
// Create server info
McpSchema.Implementation serverInfo = new McpSchema.Implementation("example-server", "1.0.0");
// Create transport provider
StdioServerTransportProvider transportProvider = new StdioServerTransportProvider();
// Create server using the builder pattern
McpAsyncServer server = McpServer.async(transportProvider)
.serverInfo(serverInfo)
.tool(
new McpSchema.Tool(
"example-tool",
"An example tool",
createToolSchema()
),
(exchange, toolArgs) -> {
String param1 = (String) toolArgs.get("param1");
Number param2 = (Number) toolArgs.get("param2");
List content = new ArrayList<>();
content.add(new McpSchema.TextContent(
null,
null,
"Tool executed with param1=" + param1 + ", param2=" + param2
));
return Mono.just(new McpSchema.CallToolResult(content, false));
}
)
.build();
System.err.println("Server started");
} catch (Exception e) {
System.err.println("Failed to start server: " + e.getMessage());
}
}
/**
* Creates the JSON schema for the example tool.
*/
private static McpSchema.JsonSchema createToolSchema() {
// Create input schema for the tool
Map properties = new HashMap<>();
Map param1 = new HashMap<>();
param1.put("type", "string");
param1.put("description", "A string parameter");
Map param2 = new HashMap<>();
param2.put("type", "number");
param2.put("description", "A numeric parameter");
properties.put("param1", param1);
properties.put("param2", param2);
List required = List.of("param1");
return new McpSchema.JsonSchema("object", properties, required, null);
}
}具有资源的异步服务器
import io.modelcontextprotocol.server.McpServer;
import io.modelcontextprotocol.server.McpAsyncServer;
import io.modelcontextprotocol.server.transport.StdioServerTransportProvider;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpError;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import reactor.core.publisher.Mono;
public class AsyncServerStdioResourcesExample {
// Pattern for matching resource URIs
private static final Pattern RESOURCE_PATTERN = Pattern.compile("data://users/(.+)");
public static void main(String[] args) {
try {
// Create server info
McpSchema.Implementation serverInfo = new McpSchema.Implementation("async-resources-example", "1.0.0");
// Create transport provider
StdioServerTransportProvider transportProvider = new StdioServerTransportProvider();
// Create server using the builder pattern
McpAsyncServer server = McpServer.async(transportProvider)
.serverInfo(serverInfo)
.resourceTemplate(
new McpSchema.ResourceTemplate(
"data://users/{userId}",
"User Data",
"Data for a specific user",
"application/json",
null
),
(exchange, request) -> {
String uri = request.uri();
// Parse the URI to extract parameters
Matcher matcher = RESOURCE_PATTERN.matcher(uri);
if (matcher.matches()) {
String userId = matcher.group(1);
// Simulate an asynchronous database lookup
return Mono.fromCallable(() -> {
// In a real implementation, this would be a database query
// For this example, we'll just generate some data
String userData = String.format(
"{\"id\":\"%s\",\"name\":\"User %s\",\"email\":\"user%s@example.com\",\"created\":\"2025-03-24\"}",
userId, userId, userId
);
List contents = new ArrayList<>();
contents.add(new McpSchema.TextResourceContents(
uri,
"application/json",
userData
));
return new McpSchema.ReadResourceResult(contents);
});
}
return Mono.error(new McpError(
new McpSchema.JSONRPCResponse.JSONRPCError(
McpSchema.ErrorCodes.RESOURCE_NOT_FOUND,
"Resource not found: " + uri,
null
)
));
}
)
.build();
System.err.println("Async resources server started");
} catch (Exception e) {
System.err.println("Failed to start server: " + e.getMessage());
}
}
}带提示的异步服务器
import io.modelcontextprotocol.server.McpServer;
import io.modelcontextprotocol.server.McpAsyncServer;
import io.modelcontextprotocol.server.transport.StdioServerTransportProvider;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpSchema.Prompt;
import io.modelcontextprotocol.spec.McpSchema.PromptArgument;
import io.modelcontextprotocol.spec.McpSchema.PromptMessage;
import io.modelcontextprotocol.spec.McpSchema.GetPromptRequest;
import io.modelcontextprotocol.spec.McpSchema.GetPromptResult;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import reactor.core.publisher.Mono;
public class AsyncServerStdioPromptsExample {
public static void main(String[] args) {
try {
// Create server info
McpSchema.Implementation serverInfo = new McpSchema.Implementation("async-prompts-example", "1.0.0");
// Create transport provider
StdioServerTransportProvider transportProvider = new StdioServerTransportProvider();
// Create a code analysis prompt
List
codeAnalysisArgs = new ArrayList<>();
codeAnalysisArgs.add(new PromptArgument(
"language",
"The programming language of the code",
true
));
codeAnalysisArgs.add(new PromptArgument(
"code",
"The code to analyze",
true
));
Prompt codeAnalysisPrompt = new Prompt(
"code-analysis",
"Analyzes code for potential issues and improvements",
codeAnalysisArgs
);
// Create server using the builder pattern
McpAsyncServer server = McpServer.async(transportProvider)
.serverInfo(serverInfo)
.prompt(
codeAnalysisPrompt,
(exchange, request) -> {
// Extract arguments from the request
String language = (String) request.arguments().get("language");
String code = (String) request.arguments().get("code");
// Simulate an asynchronous operation (e.g., calling an external API)
return Mono.fromCallable(() -> {
// Create prompt messages
List
messages = new ArrayList<>();
// System message
messages.add(new PromptMessage(
"system",
"You are a code analysis assistant that helps identify issues and suggest improvements."
));
// User message with the code
messages.add(new PromptMessage(
"user",
"Please analyze this " + language + " code:\n\n```" + language + "\n" + code + "\n```"
));
// Assistant message with the analysis
messages.add(new PromptMessage(
"assistant",
"Here's my analysis of your " + language + " code:\n\n" +
"1. The code is very minimal and doesn't do anything yet.\n" +
"2. Consider adding some functionality to the main method.\n" +
"3. Add comments to explain the purpose of the class."
));
// Return the prompt result
return new GetPromptResult(
"Code analysis for " + language,
messages
);
});
}
)
.build();
System.err.println("Async prompts server started");
} catch (Exception e) {
System.err.println("Failed to start server: " + e.getMessage());
}
}
}运输配置
MCP Java SDK支持多种传输机制,用于客户端和服务器之间的通信。
标准运输
通过标准输入/输出流进行通信,这对于子流程通信非常有用。
// Server-side
import io.modelcontextprotocol.server.transport.StdioServerTransportProvider;
StdioServerTransportProvider transportProvider = new StdioServerTransportProvider();
McpSyncServer server = new McpSyncServer(transportProvider, features);
// Client-side
import io.modelcontextprotocol.client.transport.ServerParameters;
import io.modelcontextprotocol.client.transport.StdioClientTransport;
ServerParameters serverParams = new ServerParameters.Builder().build();
StdioClientTransport transport = new StdioClientTransport(serverParams);
client.connect(transport);海关运输
您可以通过实现适当的传输提供程序接口来实现自定义传输。
import io.modelcontextprotocol.transport.Transport;
import io.modelcontextprotocol.transport.ReceiveHandler;
import io.modelcontextprotocol.server.transport.McpServerTransportProvider;
import io.modelcontextprotocol.client.transport.McpClientTransport;
// Server-side custom transport provider
public class CustomServerTransportProvider implements McpServerTransportProvider {
@Override
public Transport createTransport() {
// Implement transport creation logic
return new CustomServerTransport();
}
}
// Client-side custom transport
public class CustomClientTransport implements Transport {
@Override
public void send(String message) {
// Implement sending logic
}
@Override
public void setReceiveHandler(ReceiveHandler handler) {
// Implement receiving logic
}
@Override
public void close() {
// Implement closing logic
}
}资源实施
MCP中的资源表示客户端可以访问的数据。它们可以是静态的(预定义的)或动态的(按需生成的)。
静态资源
import io.modelcontextprotocol.server.McpServerFeatures;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpError;
import java.util.ArrayList;
import java.util.List;
// Define static resources in server features
features.resourceHandler = (exchange, request) -> {
if (request instanceof McpSchema.ListResourcesRequest) {
List resources = new ArrayList<>();
resources.add(new McpSchema.Resource("data://example/static"));
return new McpSchema.ListResourcesResult(resources, null);
} else if (request instanceof McpSchema.ReadResourceRequest) {
McpSchema.ReadResourceRequest readRequest = (McpSchema.ReadResourceRequest) request;
String uri = readRequest.uri();
if ("data://example/static".equals(uri)) {
List contents = new ArrayList<>();
contents.add(new McpSchema.TextResourceContents(
uri,
"application/json",
"{\"name\":\"Example\",\"value\":42}"
));
return new McpSchema.ReadResourceResult(contents);
}
throw new McpError(McpSchema.ErrorCodes.RESOURCE_NOT_FOUND, "Resource not found: " + uri);
}
return null;
};动态资源(资源模板)
import io.modelcontextprotocol.server.McpServerFeatures;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpError;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
// Define resource templates in server features
features.resourceHandler = (exchange, request) -> {
if (request instanceof McpSchema.ListResourceTemplatesRequest) {
List templates = new ArrayList<>();
// Define a resource template
templates.add(new McpSchema.ResourceTemplate(
"data://users/{userId}",
"User Data",
"application/json",
"Data for a specific user",
null
));
return new McpSchema.ListResourceTemplatesResult(templates, null);
} else if (request instanceof McpSchema.ReadResourceRequest) {
McpSchema.ReadResourceRequest readRequest = (McpSchema.ReadResourceRequest) request;
String uri = readRequest.uri();
// Parse the URI to extract parameters
Pattern pattern = Pattern.compile("data://users/(.+)");
Matcher matcher = pattern.matcher(uri);
if (matcher.matches()) {
String userId = matcher.group(1);
// Generate dynamic content based on the userId
String userData = String.format("{\"id\":\"%s\",\"name\":\"User %s\",\"email\":\"user%s@example.com\"}",
userId, userId, userId);
List contents = new ArrayList<>();
contents.add(new McpSchema.TextResourceContents(
uri,
"application/json",
userData
));
return new McpSchema.ReadResourceResult(contents);
}
throw new McpError(McpSchema.ErrorCodes.RESOURCE_NOT_FOUND, "Resource not found: " + uri);
}
return null;
};工具实施
MCP中的工具表示可由客户端调用的可执行函数。
import io.modelcontextprotocol.server.McpServerFeatures;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpError;
import io.modelcontextprotocol.types.CallToolRequestSchema;
import io.modelcontextprotocol.types.ErrorCode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
// Define tools in server features
features.toolHandler = (exchange, request) -> {
if (request instanceof McpSchema.ListToolsRequest) {
List tools = new ArrayList<>();
// Define a calculator tool
Map properties = new HashMap<>();
Map operation = new HashMap<>();
operation.put("type", "string");
operation.put("description", "Operation to perform (add, subtract, multiply, divide)");
operation.put("enum", List.of("add", "subtract", "multiply", "divide"));
Map a = new HashMap<>();
a.put("type", "number");
a.put("description", "First operand");
Map b = new HashMap<>();
b.put("type", "number");
b.put("description", "Second operand");
properties.put("operation", operation);
properties.put("a", a);
properties.put("b", b);
Map inputSchema = new HashMap<>();
inputSchema.put("type", "object");
inputSchema.put("properties", properties);
inputSchema.put("required", List.of("operation", "a", "b"));
tools.add(new McpSchema.Tool(
"calculator",
"Performs basic arithmetic operations",
new McpSchema.JsonSchema(inputSchema),
null
));
return new McpSchema.ListToolsResult(tools, null);
} else if (request instanceof McpSchema.CallToolRequest) {
McpSchema.CallToolRequest callRequest = (McpSchema.CallToolRequest) request;
String name = callRequest.name();
if ("calculator".equals(name)) {
Map arguments = callRequest.arguments();
String operation = (String) arguments.get("operation");
Number a = (Number) arguments.get("a");
Number b = (Number) arguments.get("b");
double result;
switch (operation) {
case "add":
result = a.doubleValue() + b.doubleValue();
break;
case "subtract":
result = a.doubleValue() - b.doubleValue();
break;
case "multiply":
result = a.doubleValue() * b.doubleValue();
break;
case "divide":
if (b.doubleValue() == 0) {
throw new McpError(ErrorCode.INVALID_PARAMS, "Division by zero");
}
result = a.doubleValue() / b.doubleValue();
break;
default:
throw new McpError(ErrorCode.INVALID_PARAMS, "Unknown operation: " + operation);
}
List content = new ArrayList<>();
content.add(new McpSchema.TextContent(String.valueOf(result)));
return new McpSchema.CallToolResult(content, false);
}
throw new McpError(ErrorCode.METHOD_NOT_FOUND, "Tool not found: " + name);
}
return null;
};错误处理
MCP Java SDK提供了一种使用 McpError 类。
错误代码
SDK在 McpSchema.ErrorCodes 类别:
PARSE_ERROR-收到无效的JSONINVALID_REQUEST-请求无效METHOD_NOT_FOUND-请求的方法不存在INVALID_PARAMS-方法参数无效INTERNAL_ERROR-内部服务器错误RESOURCE_NOT_FOUND-请求的资源不存在
抛出错误
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpError;
import io.modelcontextprotocol.types.ErrorCode;
// In a request handler
if (someCondition) {
throw new McpError(ErrorCode.INVALID_PARAMS, "Parameter 'x' must be positive");
}处理错误
// Synchronous error handling
try {
client.callTool(toolRequest);
} catch (McpError e) {
System.err.println("MCP Error: " + e.getMessage());
}
// Asynchronous error handling
client.callTool(toolRequest)
.thenAccept(response -> {
// Handle success
})
.exceptionally(e -> {
if (e.getCause() instanceof McpError) {
McpError mcpError = (McpError) e.getCause();
System.err.println("MCP Error: " + mcpError.getCode() + ": " + mcpError.getMessage());
} else {
System.err.println("Error: " + e.getMessage());
}
return null;
});服务器端错误处理
// Set a request handler for specific requests
server.setRequestHandler(CallToolRequestSchema, (request) -> {
// Handle the request
return new McpSchema.CallToolResult(content, false);
});
// Set an error handler for specific error types
server.setErrorHandler(error -> {
// Handle the error
System.err.println("Server error: " + error.getMessage());
});
// Set a global error handler in server features
features.errorHandler = error -> {
System.err.println("Server error: " + error.getMessage());
// Log the error, send metrics, etc.
};最佳实践
将军
- 使用物料清单 -始终使用MCP BOM以确保所有组件的兼容版本。
- 关闭连接 -当不再需要客户端和服务器时,始终关闭它们。
- 处理错误 -对所有MCP操作实施适当的错误处理。
- 验证输入 -在处理之前验证所有输入。
- 使用适当的交通工具 -为您的用例选择合适的传输机制。
客户端
- 重复使用客户端 -创建单个客户端实例并将其重用于多个操作。
- 处理断开连接 -实现网络传输的重新连接逻辑。
- 验证响应 -在使用之前,请验证服务器的所有响应。
服务器端
- 文档资源和工具 -为所有资源和工具提供清晰的描述。
- 实施适当的错误处理 -返回相应的错误代码和消息。
- 验证请求参数 -在处理之前验证所有请求参数。
- 使用资源模板 -使用动态资源的资源模板。
参考文献
类引用
客户端类
McpClient-创建MCP客户端的工厂McpSyncClient-同步MCP客户端实现McpAsyncClient-异步MCP客户端实现McpSchema.Implementation-用于连接初始化的客户端信息
服务器类
McpServer-用于创建MCP服务器的工厂McpSyncServer-同步MCP服务器实现McpAsyncServer-异步MCP服务器实现McpSchema.Implementation-用于连接初始化的服务器信息
运输类别
StdioClientTransport-通过标准I/O进行客户端传输StdioServerTransport-通过标准I/O进行服务器传输Transport-所有传输的基础接口ReceiveHandler-用于接收消息的处理程序
内容类
McpSchema.ResourceContents-资源内容界面McpSchema.TextResourceContents-基于文本的资源内容McpSchema.Content-工具内容界面McpSchema.TextContent-基于文本的工具内容McpSchema.CallToolResult-工具执行的响应
错误处理
McpError-MCP协议错误的错误类别McpSchema.ErrorCodes-错误代码常量ErrorCode-类型包中的错误代码常量
