MCP 协议入门与实践 – 基于 Spring AI 的代码知识库

在做 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 方法族:

原语方向典型方法用途
ToolsClient→Servertools/list, tools/callAI调用外部工具执行操作(查数据库、调API、生成代码)
ResourcesClient→Serverresources/list, resources/readAI读取外部数据源(文件内容、配置、文档)
PromptsServer→Clientprompts/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,提供开箱即用的 McpServerMcpClient

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 模式
适用场景个人开发者、离线环境团队/企业、多用户共享
分词器SmartChineseAnalyzerElasticsearch 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:

  1. 对话触发:在 Cursor 中输入”帮我写 User 的分页查询接口,参考团队规范”
  2. 工具发现:Cursor 从 tools/list 发现 codestyleSearch 工具,其描述匹配用户意图
  3. 渐进式检索:MCP Server 执行 Lucene 搜索,返回8个匹配模板的 description(轻量预览,约500 tokens)
  4. AI 筛选:AI 判断”Spring Boot 分页 Controller”模板最匹配,调用 getTemplateByPath 获取 FreeMarker 模板
  5. 变量填充:AI 根据用户指定的类名 User、包名 com.example.user、表名 t_user 填充模板,生成完整 Controller/Service/Mapper
  6. 风格一致:生成的代码完全符合团队规范——统一命名约定、异常处理模式、分页封装方式

五、关键设计决策

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 响应和更细粒度的权限控制。

项目地址:CodeStyle(码蜂) | MCP Codestyle Server

留下评论

您的邮箱地址不会被公开。 必填项已用 * 标注