甘南藏族自治州网站建设_网站建设公司_页面加载速度_seo优化
2025/12/17 13:05:38 网站建设 项目流程

当我们把各种内部系统、数据源、工具接入大语言模型时,往往会遇到一个尴尬的问题:每个团队、每套系统都有自己的一套“接入规范”。有的用 HTTP API,有的用消息队列,有的直接连数据库,最后一圈串下来,既难以统一治理,又很难在不同应用之间复用。这时,你可能会问:有没有一种通用的协议,既能让 AI 模型方便地调用外部工具、访问数据,又能让后端服务方用标准方式暴露能力?

Model Context Protocol(MCP)就是为此而生的标准之一,而本文要介绍的 Java SDK,则为 Java 开发者提供了一条直接接入 MCP 生态的通路。通过它,你可以用统一的模型,在 Java 应用里暴露工具、资源、提示模版,也可以轻松作为客户端去调用这些能力。本文将从整体架构讲起,一步步带你用一个可运行的示例,搭建起自己的 MCP 服务端与客户端。

1. 概览

随着近年来 AI 的快速发展,越来越多的工具和系统开始与 AI 模型集成。但随之而来的一个挑战是:每种集成都可能采用完全不同的标准和方式,将外部工具、资源和系统接入到 AI 模型中。

Model Context Protocol(MCP)是一个开源标准,它定义了 AI 应用(如大语言模型、图像生成模型等)与工具、数据源以及其他资源之间的集成方式。借助 MCP,AI 应用可以按外部系统约定的方式访问数据、调用工具并执行工作流。

MCP 的 Java SDK 为开发者提供了一组库,支持多种协议和通信机制,用于把 Java 应用与 AI 应用连接起来。

在本教程中,我们将一起了解这个 SDK,并通过一个简单示例来体验 MCP 的使用方式。

2. 架构

MCP 架构的核心组件主要包括:

  • MCP Host:负责管理多个 MCP Client
  • MCP Client:从 MCP Server 获取上下文,供 MCP Host 使用
  • MCP Server:向 MCP Client 提供上下文信息和可调用能力

MCP 将通信划分为两个概念层次:数据层(Data Layer),用于定义客户端与服务端的通信协议和生命周期管理;以及 传输层(Transport Layer),用于定义客户端和服务端之间的具体传输通道和机制

Java 版的 MCP SDK 将这些概念映射为如下几个层次:

  • Client/Server 层:通过 McpClient / McpServer 实现并管理客户端/服务端的具体操作
  • Session 层:通过 McpSession 管理通信模式和会话状态
  • Transport 层:通过 McpTransport 处理消息的序列化与反序列化

客户端会调用 MCP 服务端暴露的一到多个工具(tool),而底层的通信则由传输层负责。

在 MCP 中,Primitive(原语) 是最基础的构建单元,用来定义可用的上下文信息类型以及可执行的操作范围。服务端和客户端都提供了一些原语。

服务端侧的原语包括工具(tools)、资源(resources)和提示模版(prompts)。工具是 AI 应用可以调用的可执行函数,例如查询数据库、文件操作等。资源是提供给客户端的上下文数据源,例如数据库结构、文件内容等。提示模版是可复用的模版,用于与语言模型进行交互

客户端侧的原语则帮助 McpServer 的实现者构建更丰富的交互能力,包括采样(sampling)、信息补充(elicitation)和日志(logging)。采样允许服务端在不集成模型 SDK 的情况下,向客户端请求语言模型补全结果。 信息补充让服务端能够向用户请求额外信息或确认操作。 日志则允许服务端向客户端发送日志消息,用于调试和监控。

3. 环境准备

要使用 MCP Java SDK,我们需要在项目中加入 mcp 依赖:

<dependency><groupId>io.modelcontextprotocol.sdk</groupId><artifactId>mcp</artifactId><version>0.15.0</version>
</dependency>

3.1 定义一个 MCP 工具

我们先通过 LoggingTool 这个类,定义一个非常简单的 MCP 工具,用来打印收到的提示词(prompt),该方法返回一个 SyncToolSpecification

public class LoggingTool {public static McpServerFeatures.SyncToolSpecification logPromptTool() {McpSchema.JsonSchema inputSchema = new McpSchema.JsonSchema("object",Map.of("prompt", String.class), List.of("prompt"), false, null, null);return new McpServerFeatures.SyncToolSpecification(new McpSchema.Tool("logPrompt", "Log Prompt","Logs a provided prompt", inputSchema, null, null, null),(exchange, args) -> {String prompt = (String) args.get("prompt");return McpSchema.CallToolResult.builder().content(List.of(new McpSchema.TextContent("Input Prompt: " + prompt))).isError(false).build();});}
}

这里我们首先定义了输入的 JSON Schema,用来为用户输入建立一个清晰的契约。接着,使用该输入 Schema 来实例化一个 Tool,在处理逻辑中提取出 prompt 参数,并最终返回包含该 promptTextContent 结果。

4. MCP 客户端与服务端搭建

接下来,我们需要一个 MCP 服务端来暴露自定义工具,以及一个或多个 MCP 客户端,用于连接该服务端并调用其中的工具。

4.1 MCP 服务端实现

McpServer 具有一组能力(capabilities),用来告知客户端当前服务器支持哪些类别的协议操作,例如日志记录、提示词补全、资源访问等。此外,工具(tools)则提供给客户端可调用的具体函数。

先来看一个 McpServer 的实现:

public class McpServerApp {public static McpSyncServer createServer() {JacksonMcpJsonMapper jsonMapper = new JacksonMcpJsonMapper(new ObjectMapper());StdioServerTransportProvider transportProvider = new StdioServerTransportProvider(jsonMapper);return McpServer.sync(transportProvider).serverInfo("baeldung-demo-server", "0.0.1").capabilities(McpSchema.ServerCapabilities.builder().tools(true).logging().build()).tools(LoggingTool.logPromptTool()).build();}public static void main(String[] args) {createServer();}
}

上面代码定义了一个同步的 McpServer,通过标准输入/输出流并使用 JSON 消息格式进行通信。随后我们声明了服务器的能力:开启工具以及日志功能(基于 SLF4J 日志框架),最后把自定义的 logPromptTool 注册到服务器上。

4.3 MCP 客户端实现

下面再定义一个简单的 McpClient,用于连接到服务端:

public class McpClientApp {public static McpSyncClient getClient() {ServerParameters params = ServerParameters.builder("npx").args("-y", "@modelcontextprotocol/server-everything").build();JacksonMcpJsonMapper jsonMapper = new JacksonMcpJsonMapper(new ObjectMapper());McpClientTransport transport = new StdioClientTransport(params, jsonMapper);return io.modelcontextprotocol.client.McpClient.sync(transport).build();}public static void main(String[] args) {McpSyncClient client = getClient();client.initialize();}
}

这里我们使用 MCP 提供的示例服务端,并通过 ServerParameters 进行配置。客户端同样通过标准输入/输出流以及 JSON 消息格式与服务端进行同步通信。

5. 测试

到目前为止,我们已经具备了测试 MCP 交互和核心概念所需的全部组件。

5.1 测试 MCP 工具与客户端实现

我们先从测试 LoggingTool 开始,验证其输出是否正确:

@Test
void whenLogPromptToolCalled_thenReturnsResult() {McpSchema.CallToolRequest request = new McpSchema.CallToolRequest("",Map.of("prompt", "Unit test message"));McpServerFeatures.SyncToolSpecification toolSpec = LoggingTool.logPromptTool();McpSchema.CallToolResult result = toolSpec.callHandler().apply(null, request);assertNotNull(result);assertFalse(result.isError());assertEquals("Input Prompt: Unit test message",((McpSchema.TextContent) (result.content().getFirst())).text());
}

在这个测试中,我们创建了一个带有 promptCallToolRequest,并将其传递给 LoggingToolSyncToolSpecification。随后,我们断言返回结果非空、无错误,并且返回的文本内容与预期相同。

接下来,我们再通过 MCP 提供的示例服务端来测试 McpClient

@Test
void whenCalledViaClient_thenReturnsLoggedResult() {McpSchema.CallToolRequest request = new McpSchema.CallToolRequest("echo", Map.of("message", "Client-server test message"));McpSchema.CallToolResult result = client.callTool(request);assertNotNull(result);assertNull(result.isError());assertEquals("Echo: Client-server test message",((McpSchema.TextContent) (result.content().getFirst())).text());
}

MCP 示例服务端暴露了一个名为 echo 的工具,它会把输入消息原样返回,这与我们之前实现的 LoggingTool 的行为类似。

5.2 测试本地服务端

最后,我们来测试自己编写的本地服务端。为此需要定义一个单独的 McpClient,并使用指向本地 JAR 的不同服务端参数:

public class McpClientApp2 {private static final Logger log = LoggerFactory.getLogger(McpClientApp2.class);public static void main(String[] args) {String jarPath = new java.io.File("java-mcp/target/java-mcp-1.0.0-SNAPSHOT.jar").getAbsolutePath();ServerParameters params = ServerParameters.builder("java").args("-jar", jarPath).build();JacksonMcpJsonMapper jsonMapper = new JacksonMcpJsonMapper(new ObjectMapper());McpClientTransport transport = new StdioClientTransport(params, jsonMapper);McpSyncClient client = McpClient.sync(transport).build();client.initialize();ListToolsResult tools = client.listTools();McpClientApp2.log.info("Tools exposed by the server:");tools.tools().forEach(tool -> System.out.println(" - " + tool.name()));McpClientApp2.log.info("\nCalling 'logPrompt' tool...");CallToolResult result = client.callTool(new CallToolRequest("logPrompt", Map.of("prompt", "Hello from MCP client!")));McpClientApp2.log.info("Result: " + result.content());client.closeGracefully();}
}

运行该客户端后,我们可以通过日志来验证它是否成功连接到了本地 JAR 中定义的服务端:

14:04:27.879 [boundedElastic-1] INFO  i.m.c.transport.StdioClientTransport - MCP server starting.
14:04:27.920 [boundedElastic-1] INFO  i.m.c.transport.StdioClientTransport - MCP server started
14:04:28.517 [pool-4-thread-1] INFO  i.m.c.transport.StdioClientTransport - STDERR Message received: 14:04:28.504 [pool-1-thread-1] INFO  i.m.server.McpAsyncServer - Client initialize request - Protocol: 2024-11-05, Capabilities: ClientCapabilities[experimental=null, roots=null, sampling=null, elicitation=null], Info: Implementation[name=Java SDK MCP Client, title=null, version=0.15.0]
14:04:28.575 [pool-1-thread-1] INFO  i.m.client.LifecycleInitializer - Server response with Protocol: 2024-11-05, Capabilities: ServerCapabilities[completions=null, experimental=null, logging=LoggingCapabilities[], prompts=null, resources=null, tools=ToolCapabilities[listChanged=true]], Info: Implementation[name=baeldung-demo-server, title=null, version=0.0.1] and Instructions null
14:04:28.626 [main] INFO  mcp.McpClientApp2 - Tools exposed by the server:
14:04:28.626 [main] INFO  mcp.McpClientApp2 - 
Calling 'logPrompt' tool...- logPrompt
14:04:28.671 [main] INFO  mcp.McpClientApp2 - Result: [TextContent[annotations=null, text=Input Prompt: Hello from MCP client!, meta=null]]
14:04:28.784 [ForkJoinPool.commonPool-worker-1] WARN  i.m.c.transport.StdioClientTransport - Process terminated with code 143Process finished with exit code 0

从日志可以看到,首先 McpServer 启动成功,随后客户端完成初始化并与服务端建立连接。接着客户端请求列出服务端暴露的工具,最后在调用 logPrompt 工具之后,我们也看到了来自服务端的返回结果。

6. 总结

在本文中,我们首先回顾了 MCP 及其 Java SDK 的整体架构,重点介绍了 McpServerMcpClientMcpHost 之间的关系,以及由 McpTransport 负责的传输层细节。

接着,我们了解了 MCP 中的各种原语(primitives),以及在服务端和客户端侧分别可用的类型和能力。

最后,我们实现了一个简单的 MCP 工具,并通过 MCP 示例服务端和本地自建服务端,验证了 McpClient 的连接与调用流程。借助 MCP 标准和 Java SDK,你可以更方便地把现有系统能力以统一的方式暴露给 AI 应用,也能在不同项目之间复用这套集成模式。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询