ModelContextProtocol (MCP) Java SDK v0.8.0 Specification
Okay, here's a breakdown of instructions for an AI on how to create a Java-based MCP (Minecraft Coder Pack) server and client. This is a complex task, so the instructions are broken down into manageable steps. The AI will need to understand Java, networking concepts (sockets, TCP), and the basics of Minecraft's internal structure (though we'll abstract away the really complex parts). **High-Level Goal:** The AI should create a simple Java application consisting of two parts: 1. **MCP Server:** A server application that listens for connections from MCP clients. It will receive commands from the client, process them (in a very basic way), and send responses back. For simplicity, the server will primarily focus on handling commands related to Minecraft block and item IDs. 2. **MCP Client:** A client application that connects to the MCP server, sends commands (e.g., "get block ID for dirt", "get item name for 260"), and displays the server's responses. **Phase 1: Project Setup and Basic Networking (Foundation)** 1. **Project Creation:** * Create a new Java project in a suitable IDE (IntelliJ IDEA, Eclipse, etc.). * Create two main packages: `server` and `client`. * Within each package, create a main class: `server.MCPServer` and `client.MCPClient`. 2. **Basic Server Socket Setup (server.MCPServer):** * **Import necessary classes:** `java.net.ServerSocket`, `java.net.Socket`, `java.io.BufferedReader`, `java.io.PrintWriter`, `java.io.InputStreamReader`. * **Create a `ServerSocket`:** The server should listen on a specific port (e.g., 12345). Handle `IOException` appropriately (try-catch). * **Accept Connections:** Use `serverSocket.accept()` to listen for incoming client connections. This will return a `Socket` object representing the connection to the client. * **Input/Output Streams:** For each connected client: * Create a `BufferedReader` to read data from the client (using `InputStreamReader` wrapped around the `Socket`'s input stream). * Create a `PrintWriter` to send data back to the client (using the `Socket`'s output stream). Set `autoFlush` to `true` for immediate sending. * **Basic Echo:** For now, the server should simply read a line of text from the client and send it back (echo). This verifies basic connectivity. * **Multi-threading (Important):** The server needs to handle multiple clients concurrently. Create a new `Thread` for each client connection. The `Runnable` for the thread should contain the input/output stream handling and the echo logic. This prevents one client from blocking the entire server. * **Error Handling:** Implement `try-catch` blocks to handle potential `IOExceptions` during socket operations. Log errors to the console. * **Resource Cleanup:** Ensure that sockets, input streams, and output streams are closed properly in a `finally` block to prevent resource leaks. 3. **Basic Client Socket Setup (client.MCPClient):** * **Import necessary classes:** `java.net.Socket`, `java.io.BufferedReader`, `java.io.PrintWriter`, `java.io.InputStreamReader`. * **Create a `Socket`:** Connect to the server's IP address and port (e.g., "localhost", 12345). Handle `IOException`. * **Input/Output Streams:** Similar to the server, create a `BufferedReader` and `PrintWriter` for communication. * **Send a Message:** Send a simple message to the server (e.g., "Hello from the client!"). * **Receive Response:** Read the server's response and print it to the console. * **Resource Cleanup:** Close the socket, input stream, and output stream in a `finally` block. 4. **Testing:** * Run the server. * Run the client. * Verify that the client connects to the server, sends a message, and receives the echoed response. **Phase 2: Command Handling and Data (Core Functionality)** 1. **Command Protocol:** * Define a simple command protocol. Commands will be strings. Examples: * `GET_BLOCK_ID <block_name>` (e.g., `GET_BLOCK_ID dirt`) * `GET_ITEM_NAME <item_id>` (e.g., `GET_ITEM_NAME 260`) * `LIST_BLOCKS` (Lists all known blocks) * `LIST_ITEMS` (Lists all known items) * `EXIT` (Client disconnects) 2. **Server-Side Command Parsing (server.MCPServer):** * In the server's client-handling thread, read the command from the client. * Use `String.split()` or regular expressions to parse the command and its arguments. * Implement a `switch` statement or `if-else` chain to handle different commands. 3. **Data Storage (Server-Side):** * Create a simple data structure to store block and item information. A `HashMap` is suitable: * `HashMap<String, Integer> blockNameToId`: Maps block names (String) to IDs (Integer). * `HashMap<Integer, String> itemIdToName`: Maps item IDs (Integer) to names (String). * **Populate with Sample Data:** Add a few entries to the `HashMap`s for testing. Example: * `blockNameToId.put("dirt", 3);` * `blockNameToId.put("stone", 1);` * `itemIdToName.put(260, "apple");` * `itemIdToName.put(276, "diamond_sword");` 4. **Command Implementation (Server-Side):** * **`GET_BLOCK_ID <block_name>`:** * Look up the block name in `blockNameToId`. * If found, send the ID back to the client. * If not found, send an error message (e.g., "Block not found"). * **`GET_ITEM_NAME <item_id>`:** * Parse the item ID as an integer. * Look up the ID in `itemIdToName`. * If found, send the name back to the client. * If not found, send an error message (e.g., "Item not found"). * **`LIST_BLOCKS`:** * Iterate through the `blockNameToId` map and send each block name and ID to the client, separated by a delimiter (e.g., "dirt:3\nstone:1\n"). * **`LIST_ITEMS`:** * Iterate through the `itemIdToName` map and send each item ID and name to the client, separated by a delimiter (e.g., "260:apple\n276:diamond_sword\n"). * **`EXIT`:** * Close the client socket and terminate the client-handling thread. Send a confirmation message to the client before closing. 5. **Client-Side Command Input and Output (client.MCPClient):** * Prompt the user to enter a command. * Send the command to the server. * Read the server's response and display it to the user. * Implement a loop that continues until the user enters the `EXIT` command. 6. **Testing:** * Run the server. * Run the client. * Test each command to ensure it works correctly. Test error cases (e.g., requesting a non-existent block). **Phase 3: Refinement and Error Handling (Polishing)** 1. **Error Handling:** * **Server-Side:** Add more robust error handling to the server. Catch potential `NumberFormatExceptions` when parsing item IDs. Log errors to a file or the console. Send informative error messages to the client. * **Client-Side:** Handle potential `IOExceptions` when reading from or writing to the socket. Display user-friendly error messages. 2. **Input Validation:** * **Server-Side:** Validate the input from the client to prevent potential security vulnerabilities (e.g., prevent command injection). Sanitize input before using it in lookups. * **Client-Side:** Provide basic input validation to the user (e.g., ensure that the item ID is a number). 3. **Code Style and Readability:** * Use meaningful variable names. * Add comments to explain the code. * Format the code consistently. * Break down long methods into smaller, more manageable methods. 4. **Configuration:** * Allow the server port to be configured via a command-line argument or a configuration file. * Allow the client to specify the server IP address and port via command-line arguments. 5. **Logging:** * Implement basic logging to record server activity and errors. Use a logging framework like `java.util.logging` or Log4j. **Example Code Snippets (Illustrative - Not Complete):** **Server (Simplified):** ```java // Inside the client-handling thread's Runnable String command = reader.readLine(); if (command != null) { String[] parts = command.split(" "); String action = parts[0]; switch (action) { case "GET_BLOCK_ID": if (parts.length > 1) { String blockName = parts[1]; Integer blockId = blockNameToId.get(blockName); if (blockId != null) { writer.println("Block ID: " + blockId); } else { writer.println("Block not found."); } } else { writer.println("Invalid command format."); } break; case "EXIT": writer.println("Goodbye!"); socket.close(); return; // Exit the thread's run() method default: writer.println("Unknown command."); } } ``` **Client (Simplified):** ```java Scanner scanner = new Scanner(System.in); String command; while (true) { System.out.print("Enter command: "); command = scanner.nextLine(); writer.println(command); writer.flush(); // Ensure the command is sent immediately String response = reader.readLine(); System.out.println("Server response: " + response); if (command.equals("EXIT")) { break; } } ``` **Important Considerations for the AI:** * **Security:** This is a simplified example. In a real-world application, security would be a major concern. The AI should be aware of potential vulnerabilities (e.g., command injection, denial-of-service attacks) and take steps to mitigate them. However, for this exercise, focus on the core functionality first. * **Scalability:** This example is not designed for high scalability. For a large number of clients, more advanced techniques (e.g., asynchronous I/O, thread pools) would be necessary. * **Minecraft Data:** The AI will need access to a data source for Minecraft block and item IDs. This could be a simple text file, a JSON file, or a database. For this exercise, a hardcoded `HashMap` is sufficient for testing. The AI should be able to load data from a file if instructed. * **Error Handling:** Robust error handling is crucial. The AI should anticipate potential errors and handle them gracefully. * **Modularity:** The AI should strive to create modular code that is easy to understand and maintain. **AI Task Breakdown:** The AI should perform the following tasks: 1. **Code Generation:** Generate the Java code for the server and client applications, following the instructions above. 2. **Data Population:** Populate the `HashMap`s with sample Minecraft block and item data. 3. **Testing:** Provide instructions on how to test the application. 4. **Documentation:** Generate basic documentation for the code. This is a substantial project. Start with Phase 1 and get the basic networking working before moving on to Phase 2 and Phase 3. Good luck!
jayessdeesea
README
ModelContextProtocol (MCP) Java SDK v0.8.0 规范
简介
模型上下文协议 (MCP) 是一种用于 AI 模型与外部工具或资源之间通信的标准化协议。Java SDK 提供了此协议的强大实现,使 Java 应用程序能够创建 MCP 服务器,向 AI 模型公开工具和资源,以及创建可以与这些服务器通信的 MCP 客户端。
本文档是 MCP Java SDK 0.8.0 版本的完整规范,旨在用于 AI 辅助生成 MCP 客户端和服务器的代码。
架构
MCP Java SDK 遵循模块化架构,具有清晰的关注点分离:
graph TD
Client[客户端] --> Transport[传输层]
Server[服务器] --> Transport
Transport --> Protocol[协议层]
Protocol --> JSON[JSON 模式]
Client --> Resources[资源]
Client --> Tools[工具]
Server --> Resources
Server --> Tools
Server --> ErrorHandling[错误处理]
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(物料清单)添加到您的项目中,以确保所有组件的兼容版本:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp-bom</artifactId>
<version>0.8.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
然后添加您需要的特定依赖项:
<dependencies>
<!-- MCP 核心依赖项 -->
<dependency>
<groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp</artifactId>
</dependency>
<!-- 测试实用程序 -->
<dependency>
<groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp-test</artifactId>
</dependency>
<!-- Jakarta Servlet API (HTTP/SSE 传输需要) -->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>5.0.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
客户端实现
带有工具的同步客户端
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 {
// 创建客户端信息
McpSchema.Implementation clientInfo = new McpSchema.Implementation("example-client", "1.0.0");
// 创建服务器参数
ServerParameters serverParams = ServerParameters.builder("example-server-command")
.build();
// 使用服务器参数创建传输
StdioClientTransport transport = new StdioClientTransport(serverParams);
// 使用构建器模式创建客户端
McpSyncClient client = McpClient.sync(transport)
.clientInfo(clientInfo)
.build();
try {
// 读取资源
McpSchema.ReadResourceRequest request = new McpSchema.ReadResourceRequest("example://resource");
McpSchema.ReadResourceResult result = client.readResource(request);
// 访问资源内容
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());
}
}
// 使用参数 Map 调用工具
Map<String, Object> 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);
// 访问工具响应内容
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 {
// 关闭客户端
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 {
// 创建客户端信息
McpSchema.Implementation clientInfo = new McpSchema.Implementation("example-client", "1.0.0");
// 创建服务器参数
ServerParameters serverParams = ServerParameters.builder("example-server-command")
.build();
// 使用服务器参数创建传输
StdioClientTransport transport = new StdioClientTransport(serverParams);
// 使用构建器模式创建客户端
McpSyncClient client = McpClient.sync(transport)
.clientInfo(clientInfo)
.build();
try {
// 列出可用的提示
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());
}
// 获取特定的提示
String promptName = promptsResult.prompts().get(0).name();
// 如果需要,为提示创建参数
Map<String, Object> 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);
// 处理提示结果
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 {
// 关闭客户端
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 {
// 创建客户端信息
McpSchema.Implementation clientInfo = new McpSchema.Implementation("example-client", "1.0.0");
// 创建服务器参数
ServerParameters serverParams = ServerParameters.builder("example-server-command")
.build();
// 使用服务器参数创建传输
StdioClientTransport transport = new StdioClientTransport(serverParams);
// 使用构建器模式创建客户端
McpAsyncClient client = McpClient.async(transport)
.clientInfo(clientInfo)
.build();
try {
// 初始化客户端(连接到服务器)
client.initialize().block(); // 阻塞直到初始化完成
// 读取资源
McpSchema.ReadResourceRequest request = new McpSchema.ReadResourceRequest("example://resource");
McpSchema.ReadResourceResult result = client.readResource(request).block();
// 访问资源内容
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());
}
}
// 使用参数 Map 调用工具
Map<String, Object> 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();
// 访问工具响应内容
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 {
// 关闭客户端
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 {
// 创建客户端信息
McpSchema.Implementation clientInfo = new McpSchema.Implementation("example-client", "1.0.0");
// 创建服务器参数
ServerParameters serverParams = ServerParameters.builder("example-server-command")
.build();
// 使用服务器参数创建传输
StdioClientTransport transport = new StdioClientTransport(serverParams);
// 使用构建器模式创建客户端
McpAsyncClient client = McpClient.async(transport)
.clientInfo(clientInfo)
.build();
try {
// 初始化客户端(连接到服务器)
client.initialize().block(); // 阻塞直到初始化完成
// 列出可用的提示
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());
}
// 获取特定的提示
String promptName = promptsResult.prompts().get(0).name();
// 如果需要,为提示创建参数
Map<String, Object> 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();
// 处理提示结果
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 {
// 关闭客户端
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 {
// 创建服务器信息
McpSchema.Implementation serverInfo = new McpSchema.Implementation("example-server", "1.0.0");
// 创建传输提供程序
StdioServerTransportProvider transportProvider = new StdioServerTransportProvider();
// 使用构建器模式创建服务器
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<McpSchema.Content> 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");
}
/**
* 为示例工具创建 JSON 模式。
*/
private static McpSchema.JsonSchema createToolSchema() {
// 创建工具的输入模式
Map<String, Object> properties = new HashMap<>();
Map<String, Object> param1 = new HashMap<>();
param1.put("type", "string");
param1.put("description", "A string parameter");
Map<String, Object> param2 = new HashMap<>();
param2.put("type", "number");
param2.put("description", "A numeric parameter");
properties.put("param1", param1);
properties.put("param2", param2);
List<String> 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 {
// 创建服务器信息
McpSchema.Implementation serverInfo = new McpSchema.Implementation("prompts-example-server", "1.0.0");
// 创建传输提供程序
StdioServerTransportProvider transportProvider = new StdioServerTransportProvider();
// 创建代码分析提示
List<PromptArgument> 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
);
// 使用构建器模式创建服务器
McpSyncServer server = McpServer.sync(transportProvider)
.serverInfo(serverInfo)
.prompt(
codeAnalysisPrompt,
(exchange, request) -> {
// 从请求中提取参数
String language = (String) request.arguments().get("language");
String code = (String) request.arguments().get("code");
// 创建提示消息
List<PromptMessage> messages = new ArrayList<>();
// 系统消息
messages.add(new PromptMessage(
"system",
"You are a code analysis assistant that helps identify issues and suggest improvements."
));
// 带有代码的用户消息
messages.add(new PromptMessage(
"user",
"Please analyze this " + language + " code:\n\n```" + language + "\n" + code + "\n```"
));
// 带有分析的助手消息
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 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 {
// 创建服务器信息
McpSchema.Implementation serverInfo = new McpSchema.Implementation("example-server", "1.0.0");
// 创建传输提供程序
StdioServerTransportProvider transportProvider = new StdioServerTransportProvider();
// 使用构建器模式创建服务器
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<McpSchema.Content> 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());
}
}
/**
* 为示例工具创建 JSON 模式。
*/
private static McpSchema.JsonSchema createToolSchema() {
// 创建工具的输入模式
Map<String, Object> properties = new HashMap<>();
Map<String, Object> param1 = new HashMap<>();
param1.put("type", "string");
param1.put("description", "A string parameter");
Map<String, Object> param2 = new HashMap<>();
param2.put("type", "number");
param2.put("description", "A numeric parameter");
properties.put("param1", param1);
properties.put("param2", param2);
List<String> 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 {
// 创建服务器信息
McpSchema.Implementation serverInfo = new McpSchema.Implementation("async-resources-example", "1.0.0");
// 创建传输提供程序
StdioServerTransportProvider transportProvider = new StdioServerTransportProvider();
// 使用构建器模式创建服务器
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<McpSchema.ResourceContents> 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 {
// 创建服务器信息
McpSchema.Implementation serverInfo = new McpSchema.Implementation("async-prompts-example", "1.0.0");
// 创建传输提供程序
StdioServerTransportProvider transportProvider = new StdioServerTransportProvider();
// 创建代码分析提示
List<PromptArgument> 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
);
// 使用构建器模式创建服务器
McpAsyncServer server = McpServer.async(transportProvider)
.serverInfo(serverInfo)
.prompt(
codeAnalysisPrompt,
(exchange, 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(() -> {
// 创建提示消息
List<PromptMessage> messages = new ArrayList<>();
// 系统消息
messages.add(new PromptMessage(
"system",
"You are a code analysis assistant that helps identify issues and suggest improvements."
));
// 带有代码的用户消息
messages.add(new PromptMessage(
"user",
"Please analyze this " + language + " code:\n\n```" + language + "\n" + code + "\n```"
));
// 带有分析的助手消息
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 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 支持多种传输机制,用于客户端和服务器之间的通信。
StdioTransport
通过标准输入/输出流进行通信,适用于子进程通信。
// 服务器端
import io.modelcontextprotocol.server.transport.StdioServerTransportProvider;
StdioServerTransportProvider transportProvider = new StdioServerTransportProvider();
McpSyncServer server = new McpSyncServer(transportProvider, features);
// 客户端
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;
// 服务器端自定义传输提供程序
public class CustomServerTransportProvider implements McpServerTransportProvider {
@Override
public Transport createTransport() {
// 实现传输创建逻辑
return new CustomServerTransport();
}
}
// 客户端自定义传输
public class CustomClientTransport implements Transport {
@Override
public void send(String message) {
// 实现发送逻辑
}
@Override
public void setReceiveHandler(ReceiveHandler handler) {
// 实现接收逻辑
}
@Override
public void close() {
// 实现关闭逻辑
}
}
资源实现
MCP 中的资源表示客户端可以访问的数据。它们可以是静态的(预定义的)或动态的(按需生成的)。
静态资源
import io.modelcontextprotocol.server.McpServerFeatures;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpError;
import java.util.ArrayList;
import java.util.List;
// 在服务器功能中定义静态资源
features.resourceHandler = (exchange, request) -> {
if (request instanceof McpSchema.ListResourcesRequest) {
List<McpSchema.Resource> 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<McpSchema.ResourceContents> contents = new ArrayList<>();
contents.add(new McpSchema.TextResourceContents(
uri,
"application/json",
"{\"name\":\"Example\",\"value\":4
推荐服务器
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
MCP Package Docs Server
促进大型语言模型高效访问和获取 Go、Python 和 NPM 包的结构化文档,通过多语言支持和性能优化来增强软件开发。
Claude Code MCP
一个实现了 Claude Code 作为模型上下文协议(Model Context Protocol, MCP)服务器的方案,它可以通过标准化的 MCP 接口来使用 Claude 的软件工程能力(代码生成、编辑、审查和文件操作)。
@kazuph/mcp-taskmanager
用于任务管理的模型上下文协议服务器。它允许 Claude Desktop(或任何 MCP 客户端)在基于队列的系统中管理和执行任务。
mermaid-mcp-server
一个模型上下文协议 (MCP) 服务器,用于将 Mermaid 图表转换为 PNG 图像。
Jira-Context-MCP
MCP 服务器向 AI 编码助手(如 Cursor)提供 Jira 工单信息。
Linear MCP Server
一个模型上下文协议(Model Context Protocol)服务器,它与 Linear 的问题跟踪系统集成,允许大型语言模型(LLM)通过自然语言交互来创建、更新、搜索和评论 Linear 问题。
Sequential Thinking MCP Server
这个服务器通过将复杂问题分解为顺序步骤来促进结构化的问题解决,支持修订,并通过完整的 MCP 集成来实现多条解决方案路径。
Curri MCP Server
通过管理文本笔记、提供笔记创建工具以及使用结构化提示生成摘要,从而实现与 Curri API 的交互。