在做 CodeStyle(码蜂)项目的过程中,我深度研究了 MCP(Model Context Protocol)协议及其在 Spring AI 中的实现。MCP 正在快速成为 AI 工具生态的标准化协议,但国内相关的深入文章还不多。本文从协议原理、Spring AI 实现、到 CodeStyle 的实际架构,系统性地记录这一路的学习和实践经验。
一、MCP 协议深度解析
1.1 为什么需要 MCP?
在 MCP 出现之前,AI 模型与外部工具的集成处于”百花齐放、各自为战”的状态。OpenAI 有 Function Calling、Anthropic 有 Tool Use、Google 有 Function Declaration——每种模型都有自己的一套工具调用协议。开发者如果要支持多种模型,需要写多套适配代码。更麻烦的是,工具提供方(如数据库、API 服务)也要为每种模型适配一套接口。
MCP 解决的就是这个问题:定义一套通用的、模型无关的、开放的工具交互标准。类似于 USB 协议之于外设,MCP 让任何 AI 模型都能”即插即用”地使用任何 MCP 兼容的工具,把生态接入的 N×M 问题降维成了 N+M。
1.2 协议架构与三大原语
MCP 采用经典的 Client-Server 架构,基于 JSON-RPC 2.0 通信:
MCP Client (AI IDE / Host) <-- JSON-RPC 2.0 --> MCP Server (Tool Provider)
例如:Cursor、Claude Desktop 例如:数据库工具、文件系统、
Cherry Studio、Windsurf API 网关、代码模板库
MCP 协议定义了三个核心原语(Primitives),每个都是一个独立的 JSON-RPC 方法族:
| 原语 | 方向 | 典型方法 | 用途 |
|---|---|---|---|
| Tools | Client→Server | tools/list, tools/call | AI调用外部工具执行操作(查数据库、调API、生成代码) |
| Resources | Client→Server | resources/list, resources/read | AI读取外部数据源(文件内容、配置、文档) |
| Prompts | Server→Client | prompts/list, prompts/get | 服务端提供预置提示词模板,指导AI如何使用工具 |
1.3 传输层:stdio vs HTTP
MCP 支持两种传输方式:
- stdio(标准输入输出):MCP Server 作为子进程启动,通过 stdin/stdout 与 Client 通信。优势是零网络配置、天然隔离,适合本地工具。IDE(Cursor、Windsurf)普遍采用此方式。
- HTTP + SSE:MCP Server 作为 HTTP 服务运行,Client 通过网络连接。适合远程工具或需要水平扩展的场景。CodeStyle 的远程检索模式使用此方式。
一个典型的 tools/list JSON-RPC 交互:
// Request (Client -> Server)
{
"jsonrpc": "2.0", "id": 1,
"method": "tools/list", "params": {}
}
// Response (Server -> Client)
{
"jsonrpc": "2.0", "id": 1,
"result": {
"tools": [{
"name": "codestyleSearch",
"description": "搜索代码模板库,匹配最佳实践",
"inputSchema": {
"type": "object",
"properties": {
"keyword": { "type": "string", "description": "搜索关键词" },
"language": { "type": "string", "description": "编程语言" }
}
}
}]
}
}
二、Spring AI 的 MCP 实现
Spring AI 从 2.0 版本开始深度集成 MCP,提供开箱即用的 McpServer 和 McpClient。
2.1 @Tool 注解驱动的工具暴露
Spring AI MCP Server 的核心设计是注解驱动。开发者只需在方法上添加 @Tool 注解,框架会自动完成:扫描注解 → 提取方法签名和参数类型 → 生成 JSON Schema → 注册为 MCP Tool → 暴露给 MCP Client。
@Component
public class CodestyleTools {
@Tool(description = "搜索代码模板库,匹配最佳实践的代码模板")
public List<TemplateResult> codestyleSearch(
@ToolParam(description = "搜索关键词,如CRUD、分页查询") String keyword,
@ToolParam(description = "编程语言:Java, TypeScript, Python等") String language
) {
return searchService.search(keyword, language);
}
@Tool(description = "根据模板路径获取完整模板内容")
public String getTemplateByPath(
@ToolParam(description = "模板路径,如 continew/CRUD/1.0.0/backend/Controller.ftl")
String path
) {
return templateService.loadTemplate(path);
}
@Tool(description = "分析项目代码结构")
public ProjectAnalysis analyzeProject(
@ToolParam(description = "项目根目录路径") String projectPath
) {
return analyzer.analyze(projectPath);
}
}
MCP Server 启动后,Client 自动通过 tools/list 发现这些工具。当用户在 Cursor 中输入”帮我写用户管理CRUD”时,AI 自动调用 codestyleSearch 获取模板,再根据模板生成代码。整个过程用户无感,但生成的代码风格完全符合团队规范。
2.2 Tool Group:按需暴露,节省 Token
每个 MCP 工具的 Schema(名称、描述、参数类型)都会占用 AI 的上下文窗口 token。如果暴露6个工具,每个有3-5个参数,工具描述就可能占2000+ tokens。通过 codestyle.tool-group 配置实现按需暴露:
-Dcodestyle.tool-group=all(默认):暴露全部工具(5-6个),功能最全-Dcodestyle.tool-group=analyze:仅暴露代码分析工具(2个),节省约60%的token-Dcodestyle.tool-group=template:仅暴露模板相关工具(3个)
这是 MCP 实践中容易被忽略但非常重要的优化——不是工具越多越好,而是越精准越好。
三、CodeStyle 系统架构设计
CodeStyle 的完整系统架构分为四层:
层一:AI IDE 层
Cursor / Windsurf / Trae / Claude Desktop
通过 MCP 协议或 Claude Skill 连接
------------------------------------------------------
层二:MCP Server 层
mcp-codestyle-server (Spring AI MCP)
+-- Lucene 中文分词全文检索
+-- 双模式检索(本地Lucene / 远程HTTP API)
+-- SHA256 增量同步
+-- Maven 风格多版本目录
------------------------------------------------------
层三:CodeStyle 管理后台
codestyle-admin (Spring Boot + Vue 3)
+-- 检索插件 (Elasticsearch RAG)
+-- Wiki 插件 (Markdown 知识库)
+-- 代码生成器 (FreeMarker 模板引擎)
+-- 多租户管理 + 任务调度 (XXL-Job)
------------------------------------------------------
层四:数据存储层
MySQL (业务数据) / Redis (热缓存)
Elasticsearch (全文检索)
codestyle-repository (Git 模板仓库)
3.1 两阶段渐进式 RAG 检索
这是 CodeStyle 最核心的设计——两阶段渐进式召回策略:
阶段一:轻量预览。用户搜索时,系统不立即加载所有匹配模板的完整内容。而是只查询 meta.json 索引文件(轻量级元数据汇总),返回每个模板的 description、分类、标签等摘要信息。一次搜索匹配15个模板,仅消耗几百个 token。
阶段二:按需加载。用户/AI 从预览列表中选择感兴趣的模板后,通过 getTemplateByPath 加载完整内容。如果本地缓存不存在(首次使用),从远程仓库同步下载。
这个设计的收益非常显著:减少约80%的无效上下文消耗。假设搜索”CRUD模板”匹配15个结果,每个完整模板约2000 tokens,一次性加载就是30000 tokens——加上对话历史和系统提示词,很容易超出模型上下文窗口。两阶段策略只需约500 tokens完成匹配和筛选,再加载1-2个完整模板(约4000 tokens)。
3.2 双模式检索:Lucene 本地 vs ES 远程
CodeStyle MCP Server 支持两种检索模式,通过配置切换:
| 维度 | 本地 Lucene 模式 | 远程 Open API 模式 |
|---|---|---|
| 适用场景 | 个人开发者、离线环境 | 团队/企业、多用户共享 |
| 分词器 | SmartChineseAnalyzer | Elasticsearch ik_max_word |
| 部署依赖 | 零依赖,jar 内置索引 | 需部署管理后台 |
| 数据实时性 | 定时SHA256增量同步 | 实时查询后端 ES |
| 认证方式 | 无需认证 | AccessKey + SecretKey HMAC签名 |
| 启动时间 | 冷启动3-5秒(建索引) | 即时(无本地索引) |
本地 Lucene 模式使用 SmartChineseAnalyzer(中文智能分词器)。搜索”分页查询接口”的分词结果是 [“分页”, “查询”, “接口”],而非逐字拆分。索引存储在 mcp-cache/ 目录,首次启动从远程拉取模板建索引,之后仅做 SHA256 增量更新。
3.3 SHA256 增量同步与多版本共存
模板仓库持续迭代,MCP Server 需保持本地缓存同步。增量更新流程:下载最新 meta.json 索引(仅几KB)→ 遍历每条模板条目,用本地文件 SHA256 比对 → 仅下载哈希不一致的文件。借鉴 Git 的 diff 思想,但更轻量——不需要完整版本控制,只需知道”是否需要更新”。
借鉴 Maven 仓库的 groupId/artifactId/version/ 目录结构,CodeStyle 支持多版本模板共存。不同项目可引用不同版本的模板,升级不会影响仍在开发中的旧项目。
四、完整代码生成流程
以一个实际场景为例,开发者在 Cursor 中写 Spring Boot 项目,需要添加分页用户管理 CRUD:
- 对话触发:在 Cursor 中输入”帮我写 User 的分页查询接口,参考团队规范”
- 工具发现:Cursor 从 tools/list 发现
codestyleSearch工具,其描述匹配用户意图 - 渐进式检索:MCP Server 执行 Lucene 搜索,返回8个匹配模板的 description(轻量预览,约500 tokens)
- AI 筛选:AI 判断”Spring Boot 分页 Controller”模板最匹配,调用
getTemplateByPath获取 FreeMarker 模板 - 变量填充:AI 根据用户指定的类名 User、包名 com.example.user、表名 t_user 填充模板,生成完整 Controller/Service/Mapper
- 风格一致:生成的代码完全符合团队规范——统一命名约定、异常处理模式、分页封装方式
五、关键设计决策
5.1 为什么用 Lucene 而不是嵌入式 ES?
MCP Server 的设计目标是”3分钟接入”,要求零配置即插即用。Elasticsearch 即使是嵌入式部署也需要堆内存配置和端口管理。Lucene 是纯 Java 库,可直接打进 jar,启动时在本地建索引,完全离线可用。
5.2 启动时快速失败(Fail-Fast)
在远程检索模式下,如果 AccessKey 错误或后端不可达,与其在用户触发搜索时才报错,不如在启动时就验证。CodeStyle 在 ApplicationRunner 中实现:测试远程 API 连通性、验证签名合法性、检查缓存目录可写性。任何失败都会在启动日志中明确提示并阻止启动。
5.3 上下文窗口管理——最大的教训
最初设计是搜索后直接返回所有匹配模板的完整内容,但实际发现这会迅速耗尽 AI 的上下文窗口。一个 CRUD 模板约500行代码(约2000 tokens),搜索返回10个就是20000 tokens,加上当前代码、对话历史、系统提示词,很容易超出限制导致 AI”遗忘”前面内容。
改为两阶段渐进式检索后,上下文消耗降低了约80%。这也是为什么”渐进式”是整个 RAG 架构的核心设计理念——不是返回越多越好,而是返回越精准越好。
六、总结与展望
MCP 协议为 AI 工具生态带来了真正的统一接口。对工具提供方(如 CodeStyle),只需实现一次 MCP Server,就能被所有主流 AI IDE 使用。Spring AI 的注解驱动实现让 Java 开发者几乎零学习成本。
CodeStyle 在此基础上构建了完整的代码知识库体系——从模板制作、存储、检索到 IDE 内代码生成,形成闭环。目前项目已在 GitHub 开源,核心代码约 15000 行 Java + 5000 行 Vue,两个版本迭代下来,架构已经相对稳定。未来会跟进 MCP 协议的 Streaming 响应和更细粒度的权限控制。
