mcpField
J
java-mcp-server-generator

java-mcp-server-generator

github.com/github开发40.5k8.8k 次安装今天更新
代码仓库

关于 java-mcp-server-generator

指导使用官方 MCP Java SDK 2.x 创建 Java MCP 服务的技能,涵盖项目初始化、实现、子进程测试、构建和客户端配置,并说明 SDK 特有的注意事项。

主要功能

  1. 01Maven 项目脚手架
  2. 02基于 Java SDK 2.x 实现服务
  3. 03工具模式与结果验证
  4. 04通过 stdio 进行子进程测试
  5. 05构建与客户端配置指导
  6. 06SDK 迁移和传输方式注意事项

适用场景

  1. 01按需求生成 Java MCP 服务工具
  2. 02使用 SDK 客户端测试 stdio 协议行为
  3. 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();
    }
}

然后根据用户的请求修改模板:

  1. 将 divideTool() 替换为用户要求的工具。每个工具编写一个方法。
  2. 为每个工具提供 JSON Schema inputSchema 和 description。描述应说明模型何时使用该工具。
  3. 如果客户端需要获取机器可读数据,则在工具中添加 .outputSchema(Map)。使用 CallToolResult.builder().structuredContent(map) 返回数据。还要将相同数据作为文本内容添加,以兼容较旧的客户端。
  4. 使用 .annotations(ToolAnnotations.builder().readOnlyHint(true).build()) 标记只读工具。对于破坏性工具,使用 destructiveHint(true)。
  5. 仅在用户要求时添加资源、资源模板和提示词。还要在 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:构建项目,直到测试通过
  1. 运行 mvn verify。此命令会编译代码、运行测试,并生成 target/mcp-server-demo-0.1.0.jar。
  2. 如果测试失败,请查看错误并修复服务或测试。
  3. 再次运行 mvn verify。
  4. 只有构建成功后才能继续。
步骤 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 或服务配置中获取路径。

评论

支持 Markdown