关于 java-mcp-server-generator
指导使用官方 MCP Java SDK 2.x 创建 Java MCP 服务的技能,涵盖项目初始化、实现、子进程测试、构建和客户端配置,并说明 SDK 特有的注意事项。
主要功能
- 01Maven 项目脚手架
- 02基于 Java SDK 2.x 实现服务
- 03工具模式与结果验证
- 04通过 stdio 进行子进程测试
- 05构建与客户端配置指导
- 06SDK 迁移和传输方式注意事项
适用场景
- 01按需求生成 Java MCP 服务工具
- 02使用 SDK 客户端测试 stdio 协议行为
- 03配置 VS Code 或 Claude Desktop 启动服务
MCP 相关
使用官方 Java SDK 2.x 创建 MCP 服务,并默认采用 stdio 传输。还提供 VS Code、Claude Desktop 和 Streamable HTTP 的客户端配置指导。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ github/ awesome-copilot --skill java-mcp-server-generator安装后在 Claude Code 中输入/java-mcp-server-generator确认已加载。
附带文件references/gradle.mdreferences/streamable-http.md
详细介绍
Java MCP 服务生成器
使用官方 MCP Java SDK 2.x 在 Java 中创建 Model Context Protocol(MCP)服务。SDK 2.0.x 支持 MCP 规范修订版 2025-11-25 及更早的修订版。SDK 3.x 将新增对修订版 2026-07-28 的支持。
工作流
复制此检查清单并跟踪进度:
- 步骤 1:创建项目。
- 步骤 2:编写服务。
- 步骤 3:编写测试。
- 步骤 4:构建项目,直到测试通过。
- 步骤 5:配置客户端。
步骤 1:创建项目
默认使用 Maven。如果项目使用 Gradle,或者用户要求使用 Gradle,请阅读 references/gradle.md。在步骤 1、步骤 4 和步骤 5 中使用该配置。
创建以下目录结构:
project-name/
├── pom.xml
└── src/
├── main/java/com/example/McpServerApp.java
└── test/java/com/example/McpServerAppTest.java
编写 pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>mcp-server-demo</artifactId>
<version>0.1.0</version>
<properties>
<maven.compiler.release>17</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp-bom</artifactId>
<version>2.0.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>6.1.3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.17</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.example.McpServerApp</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
mcp工件包含mcp-core和 Jackson 3 JSON 映射器mcp-json-jackson3。slf4j-simple会将 SDK 日志写入 stderr。- shade 插件会将所有依赖项打包成一个可执行 JAR。
步骤 2:编写服务
从此模板开始:
package com.example;
import java.util.List;
import java.util.Map;
import io.modelcontextprotocol.json.McpJsonDefaults;
import io.modelcontextprotocol.server.McpServer;
import io.modelcontextprotocol.server.McpServerFeatures.SyncToolSpecification;
import io.modelcontextprotocol.server.transport.StdioServerTransportProvider;
import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
import io.modelcontextprotocol.spec.McpSchema.ServerCapabilities;
import io.modelcontextprotocol.spec.McpSchema.Tool;
public final class McpServerApp {
static SyncToolSpecification divideTool() {
Tool tool = Tool.builder("divide", Map.of(
"type", "object",
"properties", Map.of(
"a", Map.of("type", "number", "description", "Dividend"),
"b", Map.of("type", "number", "description", "Divisor")),
"required", List.of("a", "b")))
.description("Divide a by b.")
.build();
return SyncToolSpecification.builder()
.tool(tool)
.callHandler((exchange, request) -> {
double a = ((Number) request.arguments().get("a")).doubleValue();
double b = ((Number) request.arguments().get("b")).doubleValue();
if (b == 0) {
return CallToolResult.builder().addTextContent("b must not be zero.").isError(true).build();
}
return CallToolResult.builder().addTextContent(String.valueOf(a / b)).build();
})
.build();
}
public static void main(String[] args) {
McpServer.sync(new StdioServerTransportProvider(McpJsonDefaults.getMapper()))
.serverInfo("demo", "0.1.0")
.capabilities(ServerCapabilities.builder().tools(false).build())
.tools(divideTool())
.build();
}
}
然后根据用户的请求修改模板:
- 将
divideTool()替换为用户要求的工具。每个工具编写一个方法。 - 为每个工具提供 JSON Schema
inputSchema和description。描述应说明模型何时使用该工具。 - 如果客户端需要获取机器可读数据,则在工具中添加
.outputSchema(Map)。使用CallToolResult.builder().structuredContent(map)返回数据。还要将相同数据作为文本内容添加,以兼容较旧的客户端。 - 使用
.annotations(ToolAnnotations.builder().readOnlyHint(true).build())标记只读工具。对于破坏性工具,使用destructiveHint(true)。 - 仅在用户要求时添加资源、资源模板和提示词。还要在
ServerCapabilities中启用它们。
默认使用 stdio。只有当用户要求远程服务、HTTP 服务或 Spring Boot 时,才阅读 references/streamable-http.md。
步骤 3:编写测试
测试会将服务作为子进程启动,并使用 SDK 客户端连接到服务。为每个工具和每种错误结果编写测试:
package com.example;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.nio.file.Path;
import java.util.Map;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
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.json.McpJsonDefaults;
import io.modelcontextprotocol.spec.McpSchema.CallToolRequest;
import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
import io.modelcontextprotocol.spec.McpSchema.TextContent;
class McpServerAppTest {
private static McpSyncClient client;
@BeforeAll
static void startServer() {
String java = Path.of(System.getProperty("java.home"), "bin", "java").toString();
ServerParameters server = ServerParameters.builder(java)
.args("-cp", System.getProperty("java.class.path"), McpServerApp.class.getName())
.build();
client = McpClient.sync(new StdioClientTransport(server, McpJsonDefaults.getMapper())).build();
client.initialize();
}
@AfterAll
static void stopServer() {
client.close();
}
@Test
void divide() {
CallToolResult result = client.callTool(
CallToolRequest.builder("divide").arguments(Map.of("a", 6, "b", 3)).build());
assertEquals("2.0", ((TextContent) result.content().get(0)).text());
}
@Test
void divideByZero() {
CallToolResult result = client.callTool(
CallToolRequest.builder("divide").arguments(Map.of("a", 1, "b", 0)).build());
assertTrue(result.isError());
assertTrue(((TextContent) result.content().get(0)).text().contains("must not be zero"));
}
}
- 测试使用运行 Maven 的 JDK 中的
java命令。不要使用PATH中的java命令。 - 测试使用真实的 stdio 传输和真实的 JSON-RPC 消息。
步骤 4:构建项目,直到测试通过
- 运行
mvn verify。此命令会编译代码、运行测试,并生成target/mcp-server-demo-0.1.0.jar。 - 如果测试失败,请查看错误并修复服务或测试。
- 再次运行
mvn verify。 - 只有构建成功后才能继续。
步骤 5:配置客户端
对于 VS Code,编写 .vscode/mcp.json:
{
"servers": {
"demo": {
"type": "stdio",
"command": "java",
"args": ["-jar", "/absolute/path/to/project/target/mcp-server-demo-0.1.0.jar"]
}
}
}
对于 Claude Desktop,将相同的 command 和 args 放入 claude_desktop_config.json 中的 mcpServers 键下。
对于 HTTP 服务,请使用 references/streamable-http.md 中的客户端配置。
告知用户以下事实:
java -jar target/mcp-server-demo-0.1.0.jar会启动 stdio 服务。服务会等待通过 stdin 连接的主机。SDK 日志会写入 stderr。- 要手动测试服务,请使用相同的命令启动 MCP Inspector。Inspector 使用 Node.js。
注意事项
SDK 2.x 更改了 SDK 0.x 和 1.x 中的许多用法。不要照搬早期版本的示例。请阅读迁移指南,了解完整列表。
- 使用先接收必需字段的构建器:
Tool.builder(name, inputSchema)、Resource.builder(uri, name)、Prompt.builder(name)、TextContent.builder(text)和ReadResourceResult.builder(contents)。不带参数的构建器已弃用。 - 必需字段不能为
null。null值会导致IllegalArgumentException。 - 工具名称必须为 1 到 128 个字符,且只能包含字母、数字、
_、-和.。如果名称不正确,服务构建器会抛出IllegalArgumentException。运行时的addTool()不会检查名称。 inputSchema和outputSchema是Map<String, Object>值。JsonSchema记录已弃用。- 调用
build()或addTool()时,服务会根据 JSON Schema 2020-12 检查每个架构。架构不正确会导致IllegalArgumentException。 - SDK 会根据
inputSchema验证工具参数,也会根据outputSchema验证structuredContent。如果验证失败,客户端会收到isError设为true的工具结果。因此,处理程序收到的参数都是有效的。 - 如果工具有
outputSchema,则应在每个成功结果中返回structuredContent。如果不返回,SDK 会返回isError设为true的工具结果。 - 对于模型必须读取的错误,请返回
isError(true)的CallToolResult。 - 工具调用失败时,不要抛出异常或
McpError。客户端会收到 JSON-RPC 错误,而非工具结果。许多宿主不会将此错误显示给模型。 - 在 stdio 服务中,stdout 是协议通道。不要调用
System.out.println()。 - 使用 SLF4J 将日志写入 stderr。Logback 的默认控制台 appender 会写入 stdout。如果使用 Logback,请将其目标设为
System.err。 - Spring 传输已迁移至 Spring AI 2.0 及更高版本(group
org.springframework.ai)。不要使用io.modelcontextprotocol.sdk:mcp-spring-*工件。 - 不要使用已弃用的 SSE 传输。远程服务请使用 Streamable HTTP。
- 2026-07-28 版修订弃用了以下功能(SEP-2577)。不要在新服务中添加这些功能:
- Sampling(
exchange.createMessage()):直接调用 LLM 提供方 API。 - Protocol logging(
exchange.loggingNotification()):使用 SLF4J。 - Roots(
exchange.listRoots()):从工具参数、资源 URI 或服务配置中获取路径。
- Sampling(