引言:当 AI 助手遇到"信息孤岛"
使用 Claude Code 一段时间后,你可能遇到过这些场景:
场景 1:你想让 AI 帮忙查一下公司内部文档里关于某个 API 的说明,但它只能说"我无法访问你的内部系统"。
场景 2:你正在修复一个 Bug,想让 AI 看看 Jira 上的问题描述,却不得不手动复制粘贴一大段文字。
场景 3:你希望 AI 能直接查询数据库验证数据,而不是每次都让你手动执行 SQL 再把结果贴回来。
这些问题的本质是:Claude Code 是一个"信息孤岛",它只能访问本地文件系统,无法触及你的知识库、项目管理工具、数据库等外部系统。
MCP(Model Context Protocol) 就是解决这个问题的答案------它是 Anthropic 推出的开放协议,让 AI 能够安全、标准化地连接外部世界。
一、MCP 是什么?
1.1 一句话定义
MCP 是 AI 与外部系统之间的"USB 接口"。
就像 USB 让各种设备(键盘、鼠标、硬盘)能用统一的方式连接电脑,MCP 让各种外部服务(知识库、数据库、API)能用统一的方式连接 AI。
1.2 MCP 的三大能力
MCP 服务器可以向 AI 暴露三种能力:
| 能力类型 | 说明 | 示例 |
|---|---|---|
| Tools(工具) | 让 AI 执行操作 | 搜索知识库、创建 Jira 任务、发送消息 |
| Resources(资源) | 向 AI 暴露数据 | 配置文件内容、数据库 Schema、API 文档 |
| Prompts(提示词) | 预定义的交互模板 | 代码审查模板、报告生成模板 |
实际开发中,Tools 是最常用的能力,本文的案例也主要围绕 Tools 展开。
1.3 MCP vs Plugin:有什么区别?
在第 10 篇我们讲过 Plugin,它和 MCP 有什么不同?
| 维度 | Plugin | MCP |
|---|---|---|
| 运行位置 | Claude Code 进程内 | 独立进程,通过协议通信 |
| 开发语言 | 必须是 TypeScript/JavaScript | 任意语言(Python、Go、Rust...) |
| 隔离性 | 共享 Claude Code 环境 | 完全隔离,更安全 |
| 适用场景 | 轻量级功能增强 | 连接外部系统、复杂集成 |
简单理解:Plugin 像是给 Claude Code "装插件",MCP 像是让 Claude Code "连外设"。
二、MCP 配置与使用
2.1 配置文件位置
Claude Code 的 MCP 配置文件位于:
bash
~/.claude/mcp.json # 全局配置
<项目目录>/.mcp.json # 项目级配置(优先级更高)
2.2 配置文件格式
json
{
"mcpServers": {
"ragflow": {
"command": "python",
"args": [
"/path/to/mcp_server.py",
"--address", "ragflow.example.com",
"--api-key", "your-api-key"
]
},
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/allowed/dir"]
}
}
}
关键字段说明:
command:启动 MCP 服务器的命令args:命令行参数env:环境变量(可选,用于传递敏感信息)
2.3 常用官方 MCP 服务器
Anthropic 和社区提供了一些开箱即用的 MCP 服务器:
| 服务器 | 安装命令 | 用途 |
|---|---|---|
| filesystem | npx @modelcontextprotocol/server-filesystem |
访问指定目录的文件 |
| sqlite | npx @modelcontextprotocol/server-sqlite |
查询 SQLite 数据库 |
| fetch | npx @modelcontextprotocol/server-fetch |
发起 HTTP 请求 |
| github | npx @modelcontextprotocol/server-github |
GitHub 操作 |
| brave-search | npx @modelcontextprotocol/server-brave-search |
网络搜索 |
2.4 验证 MCP 连接
配置完成后,在 Claude Code 中可以通过 /mcp 命令查看已连接的 MCP 服务器及其提供的工具。
三、自定义 MCP 服务器开发
当官方服务器无法满足需求时,就需要自己开发 MCP 服务器。Python 生态推荐使用 FastMCP 框架,它大大简化了开发流程。
3.1 FastMCP 框架
FastMCP 是 MCP 的 Python SDK 封装,提供了类似 Flask/FastAPI 的装饰器语法:
python
from mcp.server.fastmcp import FastMCP
# 创建 MCP 服务器实例
mcp = FastMCP("my_server")
# 定义工具
@mcp.tool(name="hello", description="打招呼")
def hello(name: str) -> str:
return f"Hello, {name}!"
# 启动服务器
if __name__ == "__main__":
mcp.run(transport='stdio')
核心要素:
FastMCP("server_name"):创建服务器实例@mcp.tool():装饰器定义工具,name是工具名,description是 AI 看到的说明mcp.run(transport='stdio'):以 stdio 模式启动(Claude Code 使用此模式通信)
3.2 开发流程
markdown
1. 安装依赖 pip install mcp
2. 创建服务器 使用 FastMCP 定义工具
3. 本地测试 python mcp_server.py --help
4. 配置连接 编辑 ~/.claude/mcp.json
5. 验证集成 在 Claude Code 中测试工具调用
四、案例 1:RAGFlow 知识库集成
这是一个真实的生产案例,将 RAGFlow 知识库接入 Claude Code,让 AI 能够搜索和管理内部文档。
4.1 需求分析
我们希望 Claude Code 能够:
- 搜索知识库中的相关内容
- 上传新文档到知识库
- 列出数据集和文档
4.2 核心实现
服务器初始化与全局配置:
python
from mcp.server.fastmcp import FastMCP
from core.ragflow_api import get_datasets, retrieve_chunks, upload_document
import argparse
mcp = FastMCP("ragflow_mcp")
# 全局配置(通过命令行参数传入)
ADDRESS = None
API_KEY = None
核心工具 1:搜索知识库
python
@mcp.tool(name="search_chunks", description="从数据集中检索相关的文本块")
def search_chunks(question: str, dataset_id: str = None, page_size: int = 5) -> str:
"""
从知识库中搜索与问题相关的内容。
:param question: 要搜索的问题或关键词
:param dataset_id: 数据集ID,不提供则搜索所有数据集
:param page_size: 返回结果数量,默认5条
"""
# 获取要搜索的数据集
if dataset_id:
dataset_ids = [dataset_id]
else:
dataset_ids = get_all_dataset_ids() # 搜索所有数据集
# 调用 RAGFlow API 检索
result = retrieve_chunks(
address=ADDRESS,
api_key=API_KEY,
question=question,
dataset_ids=dataset_ids,
page_size=page_size,
similarity_threshold=0.1
)
# 格式化返回结果
if result and result.get('code') == 0:
chunks = result.get('data', {}).get('chunks', [])
if not chunks:
return f"未找到与 '{question}' 相关的内容"
formatted = []
for i, chunk in enumerate(chunks, 1):
content = chunk.get('content', '')
similarity = chunk.get('similarity', 0)
doc_name = chunk.get('document_keyword', '未知文档')
formatted.append(f"{i}. 【{doc_name}】(相似度: {similarity:.3f})\n{content[:500]}")
return f"找到 {len(chunks)} 个相关结果:\n\n" + "\n\n".join(formatted)
return f"检索失败: {result.get('message', '未知错误')}"
核心工具 2:上传文档
python
@mcp.tool(name="upload_documents", description="上传文档到知识库")
def upload_documents_tool(file_paths: list, dataset_id: str = None) -> str:
"""
上传本地文档到 RAGFlow 知识库。
:param file_paths: 文件路径列表
:param dataset_id: 目标数据集ID
"""
if isinstance(file_paths, str):
file_paths = [file_paths]
results = []
for file_path in file_paths:
if not os.path.exists(file_path):
results.append({"file": file_path, "error": "文件不存在"})
continue
result = upload_document(
address=ADDRESS,
api_key=API_KEY,
dataset_id=dataset_id,
file_path=file_path,
document_name=os.path.basename(file_path)
)
results.append({"file": file_path, "result": result})
return json.dumps(results, ensure_ascii=False, indent=2)
启动入口:
python
def main():
global ADDRESS, API_KEY
parser = argparse.ArgumentParser(description='RAGFlow MCP Server')
parser.add_argument('--address', required=True, help='RAGFlow 服务器地址')
parser.add_argument('--api-key', required=True, help='API 密钥')
args = parser.parse_args()
ADDRESS = args.address
API_KEY = args.api_key
# 验证连接
result = get_datasets(address=ADDRESS, api_key=API_KEY, page=1, page_size=1)
if not result or result.get('code') != 0:
print("❌ RAGFlow 连接失败", file=sys.stderr)
sys.exit(1)
print("✅ RAGFlow 连接成功", file=sys.stderr)
mcp.run(transport='stdio')
if __name__ == "__main__":
main()
4.3 配置与使用
配置 ~/.claude/mcp.json:
json
{
"mcpServers": {
"ragflow": {
"command": "python",
"args": [
"/path/to/mcp_server_stdio.py",
"--address", "ragflow.your-company.com",
"--api-key", "ragflow-xxxxxx"
]
}
}
}
在 Claude Code 中使用:
scss
你:帮我在知识库里搜一下"用户认证流程"相关的文档
Claude Code:[调用 search_chunks 工具]
找到 3 个相关结果:
1. 【认证模块设计文档】(相似度: 0.892)
用户认证采用 JWT + Refresh Token 双令牌机制...
2. 【API 接口规范】(相似度: 0.756)
POST /api/auth/login 用户登录接口...
五、案例 2:Jira 集成
让 Claude Code 能够直接操作 Jira,实现开发与任务管理的无缝衔接。
5.1 工具定义
python
from mcp.server.fastmcp import FastMCP
import requests
mcp = FastMCP("jira_mcp")
JIRA_URL = None
JIRA_TOKEN = None
@mcp.tool(name="get_issue", description="获取 Jira 任务详情")
def get_issue(issue_key: str) -> str:
"""
获取指定 Jira 任务的详细信息。
:param issue_key: 任务编号,如 PROJ-123
"""
response = requests.get(
f"{JIRA_URL}/rest/api/2/issue/{issue_key}",
headers={"Authorization": f"Bearer {JIRA_TOKEN}"},
timeout=10
)
if response.status_code == 200:
data = response.json()
fields = data.get('fields', {})
return f"""
任务: {issue_key}
标题: {fields.get('summary', '')}
状态: {fields.get('status', {}).get('name', '')}
优先级: {fields.get('priority', {}).get('name', '')}
描述: {fields.get('description', '')[:500]}
"""
return f"获取任务失败: {response.status_code}"
@mcp.tool(name="add_comment", description="给 Jira 任务添加评论")
def add_comment(issue_key: str, comment: str) -> str:
"""
给指定任务添加评论。
:param issue_key: 任务编号
:param comment: 评论内容
"""
response = requests.post(
f"{JIRA_URL}/rest/api/2/issue/{issue_key}/comment",
headers={
"Authorization": f"Bearer {JIRA_TOKEN}",
"Content-Type": "application/json"
},
json={"body": comment},
timeout=10
)
if response.status_code == 201:
return f"✅ 评论已添加到 {issue_key}"
return f"❌ 添加评论失败: {response.status_code}"
@mcp.tool(name="update_status", description="更新 Jira 任务状态")
def update_status(issue_key: str, status: str) -> str:
"""
更新任务状态。
:param issue_key: 任务编号
:param status: 目标状态(如 "In Progress", "Done")
"""
# 先获取可用的 transitions
trans_resp = requests.get(
f"{JIRA_URL}/rest/api/2/issue/{issue_key}/transitions",
headers={"Authorization": f"Bearer {JIRA_TOKEN}"}
)
if trans_resp.status_code != 200:
return f"获取状态转换失败"
transitions = trans_resp.json().get('transitions', [])
target = next((t for t in transitions if t['name'].lower() == status.lower()), None)
if not target:
available = [t['name'] for t in transitions]
return f"无效状态。可用状态: {available}"
# 执行状态转换
response = requests.post(
f"{JIRA_URL}/rest/api/2/issue/{issue_key}/transitions",
headers={
"Authorization": f"Bearer {JIRA_TOKEN}",
"Content-Type": "application/json"
},
json={"transition": {"id": target['id']}}
)
if response.status_code == 204:
return f"✅ {issue_key} 状态已更新为 {status}"
return f"❌ 状态更新失败"
5.2 实际使用场景
场景:Bug 修复完成后自动更新 Jira
css
你:我已经修复了 PROJ-456 的 Bug,帮我更新一下 Jira 状态,并添加修复说明
Claude Code:好的,我来更新 Jira。
[调用 add_comment] ✅ 评论已添加到 PROJ-456
[调用 update_status] ✅ PROJ-456 状态已更新为 Done
已完成:
1. 添加了修复说明评论
2. 将任务状态更新为 Done
六、最佳实践
6.1 错误处理
MCP 工具的返回值会直接展示给 AI,因此错误信息要清晰易懂:
python
# ❌ 不好的做法
return str(e)
# ✅ 好的做法
return f"❌ 操作失败: {str(e)}。请检查参数是否正确。"
6.2 安全考虑
- 敏感信息:API Key 等通过命令行参数或环境变量传入,不要硬编码
- 权限控制:MCP 服务器应该只暴露必要的操作,避免过度授权
- 输入校验:对用户输入进行校验,防止注入攻击
python
# 通过环境变量传递敏感信息
{
"mcpServers": {
"myserver": {
"command": "python",
"args": ["server.py"],
"env": {
"API_KEY": "${MYSERVER_API_KEY}"
}
}
}
}
6.3 性能优化
- 连接复用:使用连接池,避免每次请求都建立新连接
- 超时设置:所有外部调用都要设置合理的超时时间
- 结果缓存:对于不常变化的数据,可以在 MCP 服务器端缓存
总结
MCP 是 Claude Code 连接外部世界的桥梁:
- 官方 + 社区服务器:覆盖文件系统、数据库、HTTP 请求等常见场景
- FastMCP 框架:用 Python 快速开发自定义服务器
- 真实案例:RAGFlow 知识库集成让 AI 能搜索内部文档,Jira 集成实现开发流程自动化
通过 MCP,Claude Code 从一个只能操作本地文件的工具,进化为能够连接企业各种系统的"能力枢纽"。
下一篇,我们将把本系列的所有内容整合起来,构建一个开箱即用的完整工作流包,让你能够一键安装、立即使用。
"MCP 让 AI 从信息孤岛变成能力枢纽------连接一切,无所不能。"
MCP资源
🔗 相关文章:
如果这篇文章对你有帮助,欢迎点赞、收藏、分享!有任何问题或建议,欢迎在评论区留言讨论。让我们一起学习,一起成长!
也欢迎访问我的个人主页发现更多宝藏资源