第8篇:《白嫖社区生态:一行配置接入GitHub的MCP Server,AI直接读我的代码仓库》

承上:上一篇我们把自己的工具升级成了MCP协议,三种传输方式都玩了一遍。但你有没有想过------连我们自己都知道把工具做成MCP Server,GitHub、文件系统、数据库这些常用工具,社区是不是早就有人写好了?今天,我们不写一行工具代码,直接接入开源MCP Server,让AI读文件、查数据库、操作GitHub。

1. 核心认知:MCP最大的价值不是"写",是"接"

回顾一下我们上篇做的事情:

arduino 复制代码
自己写WeatherService → 用@Tool暴露 → 启动MCP Server → Client连接

这条路走通了,但换个角度想:

如果你的AI需要读本地文件,你要自己写文件读取逻辑吗?

如果你的AI需要查数据库,你要自己写JDBC查询吗?

如果你的AI需要操作GitHub Issue,你要自己调GitHub API吗?

不用。社区已经有现成的MCP Server了。

这就是MCP协议真正的威力------不是让你多写代码,而是让你少写代码。

2. 社区MCP Server生态一览

在动手之前,先看看社区有哪些"轮子"可以直接用:

MCP Server 功能 官方/社区
@anthropic/mcp-server-filesystem 文件系统读写 官方
@anthropic/mcp-server-github GitHub Issue/PR/仓库操作 官方
@anthropic/mcp-server-postgres PostgreSQL数据库查询 官方
@anthropic/mcp-server-sqlite SQLite数据库查询 官方
@anthropic/mcp-server-puppeteer 浏览器自动化 官方
@anthropic/mcp-server-brave-search Brave搜索引擎 官方
社区还有更多... Slack、Jira、Notion等 社区

这些Server大部分是Node.js/Python写的。你不需要懂这些语言,只需要知道怎么启动它们,然后用Spring AI的MCP Client去连接。

3. 实战一:接入文件系统MCP Server

3.1 场景

让AI能读取你本地的代码、文档、配置文件,然后回答诸如:

  • "我这个项目的pom.xml里用了哪些依赖?"
  • "帮我找一下项目里所有用了@Tool注解的类"
  • "application.yml里配置了多少个MCP连接?"

3.2 安装文件系统MCP Server

bash 复制代码
# 需要Node.js环境
npm install -g @modelcontextprotocol/server-filesystem

3.3 Spring AI Client配置

yaml 复制代码
spring:
  ai:
    mcp:
      client:
        stdio:
          servers-configuration: classpath:mcp-servers-config.json

classpath:mcp-servers-config.json

perl 复制代码
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/yunxi/IdeaProjects/yunxi-spring-ai/chapter-07-mcp-client"]
    }
  }
}

注意 :路径必须是绝对路径。~ 波浪号可能不被识别,建议写完整路径。

3.4 Client代码

kotlin 复制代码
package com.yunxi.ai.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class ChatService {

    private final ChatClient chatClient;

    public ChatService(ChatClient.Builder builder, ToolCallbackProvider tools) {
        this.chatClient = builder
                .defaultToolCallbacks(tools)
                .build();
    }

    public String chat(String message) {
        return chatClient.prompt()
                .system("你是一个专业的助手,可以读取文件系统")
                .user(message)
                .call()
                .content();
    }

}

3.5 测试

ini 复制代码
2026-07-25T19:57:28.338+08:00 DEBUG 62860 --- [nio-9999-exec-3] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to com.yunxi.ai.controller.ChatController#chat(String)
2026-07-25T19:57:28.356+08:00 DEBUG 62860 --- [nio-9999-exec-3] o.s.web.client.DefaultRestClient         : Writing [ChatCompletionRequest[messages=[ChatCompletionMessage[rawContent=你是一个专业的助手,可以读取文件系统, role=SYSTEM, name=null, toolCallId=null, toolCalls=null, refusal=null, audioOutput=null, annotations=null, reasoningContent=null], ChatCompletionMessage[rawContent=写一个测试文件hello world, role=USER, name=null, toolCallId=null, toolCalls=null, refusal=null, audioOutput=null, annotations=null, reasoningContent=null]], model=deepseek-v4-pro, store=null, metadata=null, frequencyPenalty=null, logitBias=null, logprobs=null, topLogprobs=null, maxTokens=null, maxCompletionTokens=null, n=null, outputModalities=null, audioParameters=null, presencePenalty=null, responseFormat=null, seed=null, serviceTier=null, stop=null, stream=false, streamOptions=null, temperature=0.7, topP=null, tools=[org.springframework.ai.openai.api.OpenAiApi$FunctionTool@7fd90769, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@26a98958, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@1a88f6c0, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@357a5804, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@22ff38d, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@68a649d9, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@35459cfb, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@5218582f, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@2f566a7a, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@756406c8, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@6cdffedb, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@7c161a4f, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@608fba0d, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@3508a292, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@2632bbce], toolChoice=null, parallelToolCalls=null, user=null, reasoningEffort=null, webSearchOptions=null, verbosity=null, promptCacheKey=null, safetyIdentifier=null, extraBody={}]] as "application/json" with org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
2026-07-25T19:57:30.569+08:00 DEBUG 62860 --- [nio-9999-exec-3] o.s.web.client.DefaultRestClient         : Reading to [org.springframework.ai.openai.api.OpenAiApi$ChatCompletion]
2026-07-25T19:57:30.571+08:00 DEBUG 62860 --- [nio-9999-exec-3] o.s.a.m.tool.DefaultToolCallingManager   : Executing tool call: write_file
2026-07-25T19:57:30.588+08:00 DEBUG 62860 --- [nio-9999-exec-3] o.s.web.client.DefaultRestClient         : Writing [ChatCompletionRequest[messages=[ChatCompletionMessage[rawContent=你是一个专业的助手,可以读取文件系统, role=SYSTEM, name=null, toolCallId=null, toolCalls=null, refusal=null, audioOutput=null, annotations=null, reasoningContent=null], ChatCompletionMessage[rawContent=写一个测试文件hello world, role=USER, name=null, toolCallId=null, toolCalls=null, refusal=null, audioOutput=null, annotations=null, reasoningContent=null], ChatCompletionMessage[rawContent=我来创建一个 `hello_world` 测试文件。, role=ASSISTANT, name=null, toolCallId=null, toolCalls=[ToolCall[index=null, id=call_00_VAuDtPo7fV0dndXT4LsR0717, type=function, function=ChatCompletionFunction[name=write_file, arguments={"path": "hello_world.txt", "content": "Hello World!\n这是一个测试文件。\n"}]]], refusal=null, audioOutput=null, annotations=null, reasoningContent=null], ChatCompletionMessage[rawContent=[{"text":"Successfully wrote to hello_world.txt"}], role=TOOL, name=write_file, toolCallId=call_00_VAuDtPo7fV0dndXT4LsR0717, toolCalls=null, refusal=null, audioOutput=null, annotations=null, reasoningContent=null]], model=deepseek-v4-pro, store=null, metadata=null, frequencyPenalty=null, logitBias=null, logprobs=null, topLogprobs=null, maxTokens=null, maxCompletionTokens=null, n=null, outputModalities=null, audioParameters=null, presencePenalty=null, responseFormat=null, seed=null, serviceTier=null, stop=null, stream=false, streamOptions=null, temperature=0.7, topP=null, tools=[org.springframework.ai.openai.api.OpenAiApi$FunctionTool@6aba0925, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@77f899ad, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@714a9f2, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@34cb8e15, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@e025a88, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@3d049f14, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@1ffdfa7f, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@772e74b3, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@6be4a6c4, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@72017893, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@25f4aae, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@6503dba, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@484c6932, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@31705548, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@490263f2], toolChoice=null, parallelToolCalls=null, user=null, reasoningEffort=null, webSearchOptions=null, verbosity=null, promptCacheKey=null, safetyIdentifier=null, extraBody={}]] as "application/json" with org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
2026-07-25T19:57:32.141+08:00 DEBUG 62860 --- [nio-9999-exec-3] o.s.web.client.DefaultRestClient         : Reading to [org.springframework.ai.openai.api.OpenAiApi$ChatCompletion]
2026-07-25T19:57:32.143+08:00 DEBUG 62860 --- [nio-9999-exec-3] o.s.a.m.tool.DefaultToolCallingManager   : Executing tool call: read_text_file
2026-07-25T19:57:32.169+08:00 DEBUG 62860 --- [nio-9999-exec-3] o.s.web.client.DefaultRestClient         : Writing [ChatCompletionRequest[messages=[ChatCompletionMessage[rawContent=你是一个专业的助手,可以读取文件系统, role=SYSTEM, name=null, toolCallId=null, toolCalls=null, refusal=null, audioOutput=null, annotations=null, reasoningContent=null], ChatCompletionMessage[rawContent=写一个测试文件hello world, role=USER, name=null, toolCallId=null, toolCalls=null, refusal=null, audioOutput=null, annotations=null, reasoningContent=null], ChatCompletionMessage[rawContent=我来创建一个 `hello_world` 测试文件。, role=ASSISTANT, name=null, toolCallId=null, toolCalls=[ToolCall[index=null, id=call_00_VAuDtPo7fV0dndXT4LsR0717, type=function, function=ChatCompletionFunction[name=write_file, arguments={"path": "hello_world.txt", "content": "Hello World!\n这是一个测试文件。\n"}]]], refusal=null, audioOutput=null, annotations=null, reasoningContent=null], ChatCompletionMessage[rawContent=[{"text":"Successfully wrote to hello_world.txt"}], role=TOOL, name=write_file, toolCallId=call_00_VAuDtPo7fV0dndXT4LsR0717, toolCalls=null, refusal=null, audioOutput=null, annotations=null, reasoningContent=null], ChatCompletionMessage[rawContent=文件已成功创建!让我确认一下内容:, role=ASSISTANT, name=null, toolCallId=null, toolCalls=[ToolCall[index=null, id=call_00_WewfrWtoSgjnOiJDT5Op7208, type=function, function=ChatCompletionFunction[name=read_text_file, arguments={"path": "hello_world.txt"}]]], refusal=null, audioOutput=null, annotations=null, reasoningContent=null], ChatCompletionMessage[rawContent=[{"text":"Hello World!\n这是一个测试文件。\n"}], role=TOOL, name=read_text_file, toolCallId=call_00_WewfrWtoSgjnOiJDT5Op7208, toolCalls=null, refusal=null, audioOutput=null, annotations=null, reasoningContent=null]], model=deepseek-v4-pro, store=null, metadata=null, frequencyPenalty=null, logitBias=null, logprobs=null, topLogprobs=null, maxTokens=null, maxCompletionTokens=null, n=null, outputModalities=null, audioParameters=null, presencePenalty=null, responseFormat=null, seed=null, serviceTier=null, stop=null, stream=false, streamOptions=null, temperature=0.7, topP=null, tools=[org.springframework.ai.openai.api.OpenAiApi$FunctionTool@66132625, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@3b5dc607, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@69243810, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@4aa1bd72, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@357c880d, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@60441d5b, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@28684dfb, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@6fe53fa9, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@3e08eeb8, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@7ee692e7, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@140b1f55, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@5255720a, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@2bd12bd6, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@616ae5e1, org.springframework.ai.openai.api.OpenAiApi$FunctionTool@2dd7af2e], toolChoice=null, parallelToolCalls=null, user=null, reasoningEffort=null, webSearchOptions=null, verbosity=null, promptCacheKey=null, safetyIdentifier=null, extraBody={}]] as "application/json" with org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
2026-07-25T19:57:33.410+08:00 DEBUG 62860 --- [nio-9999-exec-3] o.s.web.client.DefaultRestClient         : Reading to [org.springframework.ai.openai.api.OpenAiApi$ChatCompletion]
2026-07-25T19:57:33.415+08:00 DEBUG 62860 --- [nio-9999-exec-3] m.m.a.RequestResponseBodyMethodProcessor : Using 'text/plain', given [*/*] and supported [text/plain, */*, application/json, application/*+json, application/yaml]
2026-07-25T19:57:33.416+08:00 DEBUG 62860 --- [nio-9999-exec-3] m.m.a.RequestResponseBodyMethodProcessor : Writing ["✅ 测试文件 `hello_world.txt` 已创建完成,内容如下:<EOL><EOL>```<EOL>Hello World!<EOL>这是一个测试文件。<EOL>```"]
2026-07-25T19:57:33.419+08:00 DEBUG 62860 --- [nio-9999-exec-3] o.s.web.servlet.DispatcherServlet        : Completed 200 OK 画一下这个交互

你一行文件读取代码都没写。 这就是白嫖的快乐。

4. 实战二:接入Gitee MCP Server

4.1 场景

让AI能操作你的Gitee仓库:

  • "帮我查一下最近一周的Issue"
  • "创建一个PR,标题是'修复订单查询Bug'"
  • "看看最近的commit记录"

4.2 安装Gitee MCP Server

css 复制代码
npm install -g @gitee/mcp-gitee@latest

4.3 创建Gitee Personal Access Token

  1. 打开 gitee.com/profile/per...
  2. 点击 "生成新令牌"
  3. 勾选权限:user_info projects pull_requests issues notes keys hook groups gists enterprises emails
  4. 生成后复制Token(只显示一次)

4.4 Spring AI Client配置

perl 复制代码
{
  "mcpServers": {
    "gitee": {
      "command": "npx",
      "args": [ "-y", "@gitee/mcp-gitee@latest" ],
      "env": {
        "GITEE_API_BASE": "https://gitee.com/api/v5",
        "GITEE_ACCESS_TOKEN": "e474ac8baf0******a5260decebab4"
      }
    }
  }
}

4.5 测试

5. 实战三:同时接入多个MCP Server

把文件系统和Gitee一起接进来:

跨系统协作,只靠一个 McpClient

6. 如何发现更多社区MCP Server?

资源 地址 说明
MCP官方仓库 github.com/modelcontex... 官方维护的Server列表
npm搜索 npm search mcp-server Node.js生态
GitHub搜索 mcp-server topic 社区开源项目
Spring AI文档 docs.spring.io/spring-ai/r... Java生态
MCP广场 www.modelscope.cn/mcp 魔塔社区

7. 避坑指南

坑1:Node.js环境没装

大部分社区MCP Server是Node.js写的,需要先装Node.js

bash 复制代码
node -v   # 确认版本 >= 18
npm -v

坑2:文件系统MCP Server权限太大

mcp-server-filesystem 默认能读传入目录下的所有文件,包括 .env.git/config 等敏感文件。

建议:创建一个专门给AI访问的目录,不要直接给项目根目录。

坑3:STDIO方式的日志看不到

STDIO方式如果Server启动失败,日志不会直接输出到控制台。排查时可以先手动运行命令确认Server能启动。

坑4:版本兼容问题

社区MCP Server更新频繁,和Spring AI的MCP Client可能有兼容问题。优先使用官方维护的 @anthropic/ 开头的Server。

八、本篇小结

这一篇我们没有写一行工具代码,全靠白嫖社区生态:

接入的Server 能力
文件系统 读代码、读配置、读文档
Gitee Issue、PR、Commit操作
(未来更多) 数据库、Slack、Jira...

核心心法

arduino 复制代码
第一阶段:自己写@Tool → 知道原理
第二阶段:升级成MCP Server → 标准化
第三阶段:接入社区MCP Server → 白嫖  ← 你现在在这里

MCP协议真正的价值,不在于你写了多少Server,而在于你能接入多少现成的生态。

MCP协议真正的价值,不在于你写了多少Server,而在于你能接入多少现成的生态。

现在我们的AI工具能力已经拉满了------能调接口、能读文件、能操作GitHub。但每次对话都像在跟一个失忆的人聊天,上一句刚说完我叫张三,下一句它就问"您好,请问怎么称呼?"

下一篇,我们要解决这个问题------给AI装上"海马体",让它记住你们聊过什么。


本文与DeepSeek协作完成

相关推荐
雨辰AI1 小时前
全集实战:企业级大模型服务化部署全栈指南|FastAPI 封装 + Nginx 负载均衡 + 高可用架构 从单机到生产一步到位
人工智能·ai·负载均衡·fastapi·ai编程
chaors5 小时前
DeepResearchSystem 0x01:Agent 基础
langchain·aigc·ai编程
sweet丶5 小时前
移动端轻量级AI Agent自动化UI验证:sim-use
ai编程
东小西6 小时前
第7篇:《工具的USB接口:我把Function Calling升级成了MCP》
openai·ai编程
腻害兔7 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:CRM 客户关系模块深度解析——从线索到回款,一套完整的 B2B 销售闭环是怎么搭的?
java·前端·javascript·vue.js·产品经理·ai编程
大数据点灯人7 小时前
【AI编程】Vibe Coding 模型选型:越贵越好吗?效果/速度/成本平衡指南
编程·ai编程·claude·codex·vibe coding
oort1237 小时前
吃上了自家的细糠,还挺丝滑,用起来手感还行,OortCloud发布新版AI编程平台,下载 OortCodex,Token多,免费薅
大数据·开发语言·人工智能·ai编程
小虎AI生活8 小时前
WorkBuddy 自动化实战,TTS 配音从安装到跑通
ai编程
小虎AI生活10 小时前
workbuddy 短视频获客的终极形态,不是做内容,是建工厂
ai编程