MCP从0到1 -- 生产级MCP服务器搭建
原创
黄鹂儿
黄鹂儿
一路狂飚的蜗牛
2026年7月13日 21:26
北京
在小说阅读器读本章
去阅读
从Hello World到Kubernetes部署,一步步构建可落地的MCP服务
一、什么是MCP?
MCP(Model Context Protocol,模型上下文协议)是由Anthropic提出的一种开放协议,旨在让大语言模型(LLM)能够以标准化的方式连接外部工具和数据源。
简单来说,MCP就是AI应用的\"USB-C接口\"——统一标准,即插即用。过去,每个AI应用如果要调用外部工具,都需要单独开发集成代码;有了MCP后,只需按协议实现一个Server,所有兼容MCP的客户端都能直接使用。
核心角色
| 角色 | 说明 | 类比 |
|---|---|---|
| MCP Host | 运行LLM的应用(如Claude Desktop、CodeBuddy/TRAE IDE) | 电脑主机 |
| MCP Client | Host内部的协议解析器,与Server建立1:1连接 | USB控制器 |
| MCP Server | 暴露工具/资源的后端服务 | USB设备 |
| Tools | Server提供的可调用函数 | 设备功能 |
| Resources | Server暴露的只读数据 | 设备存储 |
| Prompts | Server预定义的提示模板 | 设备预设 |
三种传输方式一览
| 方式 | 适用场景 | 复杂度 |
|---|---|---|
| Stdio(标准输入输出) | 本地开发、IDE集成 | ⭐ |
| SSE(Server-Sent Events) | 远程服务、需长连接推送 | ⭐⭐ |
| Streamable HTTP(推荐) | 生产部署、负载均衡 | ⭐⭐ |
接下来,我们将从最简单的Hello World开始,一步步深入这三种传输方式,最终构建一个可在Kubernetes上弹性伸缩的生产级MCP Server。
二、5分钟入门:Hello World
先从最简单的Stdio模式开始。只需十几行代码,就能写一个可用的MCP Server。
项目文件结构
▲ 项目文件结构一览
Server端代码
hello\_mcp\_server.py
from mcp.server.fastmcp import FastMCP
mcp = FastMCP(\"hello-mcp-server\")
@mcp.tool()
def hello(name: str) -> str:
\"\"\"向指定的人或内容打招呼\"\"\"
return f\"Hello, {name}!\"
if \\_name\\ == \"\\main\\_\":
mcp.run()
▲ 仅11行代码即可实现一个MCP Server
Client端代码
import asyncio
from mcp import stdio\_client, StdioServerParameters, ClientSession
async def main():
server\_params = StdioServerParameters(
command=\"python3\", args=[\"hello\_mcp\_server.py\"])
async with stdio\_client(server\_params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
result = await session.call\_tool(\"hello\", {\"name\": \"woniu\"})
print(result.content[0].text) # 输出: Hello, woniu!
asyncio.run(main())
💡 Stdio模式通过标准输入输出来通信,Client启动Server子进程,通过管道读写JSON-RPC消息。这是最简单的方式,适合本地测试和IDE集成。
三、三种传输方式深度对比
理解了Hello World之后,我们来深入理解三种传输方式的差异。这是选择生产部署方案的关键知识。
3.1 Stdio模式
通过标准输入输出(stdin/stdout)通信。Client启动Server子进程,JSON-RPC消息在管道中传递。
✅ 优点:零网络配置,安全简单 ❌ 缺点:无法远程访问,不支持负载均衡
适用场景:IDE本地集成、开发调试。
3.2 SSE模式
通过HTTP SSE(Server-Sent Events)建立长连接,支持服务端主动推送。
mcp.settings.host = \"0.0.0.0\"
mcp.settings.port = 8080
... 工具定义 ...
mcp.run(transport=\"sse\")
✅ 优点:支持远程访问和服务端推送 ❌ 缺点:需要会话亲和性(Sticky Session),扩展复杂
3.3 Streamable HTTP模式(生产推荐)
通过HTTP POST发送请求,响应可以是JSON或SSE流。支持无状态部署,是生产环境的首选方案。
mcp.settings.host = \"0.0.0.0\"
mcp.settings.port = 8081
mcp.settings.stateless\_http = True # 关键:无状态模式
... 工具定义 ...
mcp.run(transport=\"streamable-http\")
✅ 优点:无状态设计原生支持负载均衡和水平扩展 ❌ 缺点:不支持服务端主动推送
三种方式总结
| 特性 | Stdio | SSE | Streamable HTTP |
|---|---|---|---|
| 通信方式 | 进程stdin/stdout | HTTP SSE流 | HTTP POST + SSE |
| 适用场景 | 本地开发 | 远程+推送 | 生产部署 |
| 会话管理 | 进程生命周期 | 需会话亲和性 | 无状态 |
| 负载均衡 | 不支持 | 复杂 | 原生支持 |
| 推荐环境 | IDE调试 | 实时推送 | 企业生产 |
⚠️ 生产环境首选Streamable HTTP + stateless\_http=True,这是本文后续所有部署方案的基础。
四、调试方法:不用每次启动LLM
开发过程中如果每次都要通过LLM来测试MCP工具,效率太低。下面介绍三种高效的调试方法。
4.1 MCP Inspector(官方工具,最推荐)
一行命令启动,浏览器可视化调试:
npx @modelcontextprotocol/inspector
▲ MCP Inspector连接成功,可查看工具列表
▲ 在Inspector中调用hello工具,查看输入和输出
Inspector能做什么:列出所有工具 → 手动输入参数 → 查看JSON-RPC原始消息 → 验证元数据。
4.2 curl命令行调试
初始化连接
curl -X POST http://localhost:8081/mcp \
-H \"Content-Type: application/json\" \
-d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",...}'
调用工具
curl -X POST http://localhost:8081/mcp \
-H \"Content-Type: application/json\" \
-d '{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"callTool\",
\"params\":{\"name\":\"hello\",\"arguments\":{\"name\":\"woniu\"}}}'
4.3 日志调试
在工具函数中添加日志,记录每次调用的参数、结果和耗时:
import logging, time, uuid
logger = logging.getLogger(\\_name\\_)
@mcp.tool()
def hello(name: str) -> str:
request\_id = str(uuid.uuid4())[:8]
start = time.time()
result = f\"Hello, {name}!\"
duration = (time.time() - start) \* 1000
logger.info(f\"[{request\_id}] hello({name}) -> {duration}ms\")
return result
五、企业级MCP Server开发
Hello World只是开始。生产环境的MCP Server需要考虑更多:无状态设计、健康检查、结构化日志、容器化支持等。
5.1 增强版Server核心代码
import logging, os, json, socket, time, uuid
from datetime import datetime
from mcp.server.fastmcp import FastMCP
from starlette.requests import Request
from starlette.responses import JSONResponse
mcp = FastMCP(\"enterprise-mcp-server\")
mcp.settings.host = \"0.0.0.0\"
mcp.settings.port = int(os.environ.get(\"PORT\", 8000))
mcp.settings.stateless\_http = True# 无状态,负载均衡基础
K8S/Docker 健康检查端点
@mcp.custom\_route(\"/health\", methods=[\"GET\"])
async def health\_check(request: Request) -> JSONResponse:
return JSONResponse({\"status\":\"healthy\"})
工具:获取服务器信息(验证负载均衡用)
@mcp.tool()
def get\_server\_info() -> str:
return json.dumps({
\"hostname\": socket.gethostname(),
\"pid\": os.getpid(),
\"port\": mcp.settings.port,
\"timestamp\": datetime.now().isoformat()
})
@mcp.tool()
def hello(name: str) -> str:
return f\"Hello, {name}!\"
@mcp.tool()
def add(a: int, b: int) -> int:
return a + b
if \\_name\\ == \"\\main\\_\":
mcp.run(transport=\"streamable-http\")
5.2 关键设计要点
| 特性 | 作用 |
|---|---|
| stateless\_http=True | 无状态模式,每个请求独立,是负载均衡的基础 |
| 环境变量PORT | 方便容器化和多实例部署 |
| /health自定义路由 | Docker/K8S健康检查所需,是生产部署必备 |
| UUID请求追踪 | 记录每次调用的request\_id,便于排查问题 |
| 结构化日志 | 记录工具名、参数、结果、耗时 |
5.3 配置到IDE
完成Server开发后,将其配置到CodeBuddy/TRAE IDE,让AI助手直接调用你的工具。
▲ IDE中配置MCP Server的JSON
▲ AI助手调用MCP工具的实际效果
六、Docker化与Nginx负载均衡
容器化是生产部署的第一步。我们将用Docker Compose编排3个MCP Server实例 + 1个Nginx负载均衡器。
6.1 Dockerfile
FROM python:3.12-slim-bookworm
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY mcp\_server\_pro.py .
EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=3s \
CMD python -c \"import httpx; \
r = httpx.get('http://localhost:8000/health'); \
exit(0 if r.status\_code == 200 else 1)\"
CMD [\"python\", \"mcp\_server\_pro.py\"]
6.2 docker-compose.yml
services:
mcp-server-1:
build: .
ports: [\"8001:8000\"]
networks: [mcp-network]
healthcheck:
test: [\"CMD\", \"python\", \"-c\",
\"import httpx; ...exit(0 if ok else 1)\"]
mcp-server-2:# 同上,端口 8002
mcp-server-3:# 同上,端口 8003
nginx:
image: nginx:1.25-alpine
ports: [\"80:80\"]
volumes: [./nginx.conf:/etc/nginx/nginx.conf]
depends\_on: [mcp-server-1, mcp-server-2, mcp-server-3]
6.3 nginx.conf
upstream mcp\_servers {
server mcp-server-1:8000;
server mcp-server-2:8000;
server mcp-server-3:8000;
}
server {
listen 80;
location /mcp {
proxy\_pass http://mcp\_servers/mcp;
proxy\_buffering off; # SSE需要关闭缓冲
proxy\_read\_timeout 300s;
}
location /health {
proxy\_pass http://mcp\_servers/health;
}
}
6.4 架构图
6.5 启动与验证
▲ docker-compose build 构建镜像过程
▲ 4个容器全部 healthy:3个MCP Server + 1个Nginx
启动
cd project\_dir && docker-compose up -d
验证状态(所有容器必须 healthy)
docker-compose ps
验证负载均衡(多次调用,hostname应不同)
for i in 1 2 3 4 5 6; do
curl -s -X POST http://localhost:8088/mcp \
-H \"Content-Type: application/json\" \
-d '{\"jsonrpc\":\"2.0\",\"id\":1,
\"method\":\"callTool\",\"params\":
{\"name\":\"get\_server\_info\",\"arguments\":{}}}'
done
💡 验证负载均衡的关键:多次调用get\_server\_info,观察返回的hostname是否在3个容器之间轮换。
七、Kubernetes生产部署
Docker Compose适合单机部署,但要实现自动扩缩容、滚动更新和自愈能力,就得用Kubernetes。我们使用Colima + K3S搭建本地K8S集群。
7.1 环境搭建
启动Colima并启用Kubernetes
colima start --kubernetes
验证集群
kubectl cluster-info
kubectl get nodes
构建镜像(Colima Docker环境)
docker build -t mcp-server:latest .
7.2 Deployment(含健康检查)
apiVersion: apps/v1
kind: Deployment
metadata:
name: mcp-server
spec:
replicas: 3
template:
spec:
containers:
- name: mcp-server
image: mcp-server:latest
ports:
- containerPort: 8000
livenessProbe: # 存活探针
tcpSocket:
port: 8000
initialDelaySeconds: 10
readinessProbe: # 就绪探针
httpGet:
path: /health
port: 8000
initialDelaySeconds: 5
💡 存活探针用tcpSocket检测进程是否存活,就绪探针用HTTP /health检测服务是否就绪。只有就绪的Pod才会接收流量。
7.3 Service(对外暴露)
apiVersion: v1
kind: Service
metadata:
name: mcp-server-service
spec:
type: NodePort
selector:
app: mcp-server
ports:
- port: 8000
targetPort: 8000
nodePort: 30080 # 对外暴露端口
使用NodePort类型,通过30080端口对外暴露,kube-proxy内置iptables轮询负载均衡。
7.4 HPA(自动扩缩容)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: mcp-server-hpa
spec:
scaleTargetRef:
name: mcp-server
minReplicas: 2
maxReplicas: 10
metrics:
- resource:
name: cpu
target:
averageUtilization: 60 # CPU>60%触发扩容
- resource:
name: memory
target:
averageUtilization: 75 # 内存>75%触发扩容
HPA根据CPU和内存使用率自动扩缩容,最小2个Pod,最多10个Pod,保证服务在高负载下依然稳定。
7.5 部署与验证
▲ kubectl get svc,hpa —— Service + HPA 全部就绪
▲ 通过NodePort 30080访问/health端点,返回healthy
部署
kubectl apply -f k8s/deployment.yaml
kubectl apply -f k8s/service.yaml
kubectl apply -f k8s/hpa.yaml
查看状态
kubectl get pods -w # 等待Running
kubectl get svc,hpa # 确认Service和HPA
验证负载均衡(9次请求应分发到3个Pod)
使用 python 脚本,每次新建httpx.AsyncClient
观察hostname在mcp-server-xxx之间轮换
7.6 K8S整体架构
▲ K8S部署架构全景
7.7 踩坑记录
| 问题 | 原因 | 解决方案 |
|---|---|---|
| kubectl logs 报EOF | Colima K3S的kubelet API不稳定 | 改用colima ssh -- sudo crictl logs查看 |
| 健康检查404 | Streamable HTTP模式未内置/health | 通过@mcp.custom\_route添加自定义路由 |
| 所有请求落同一Pod | kube-proxy同连接亲和性 | 每次新建HTTP客户端建立新TCP连接 |
| HPA显示unknown | 未安装metrics-server | kubectl apply -f metrics-server组件 |
八、进阶扩展
LangGraph智能体客户端(可选)
将MCP工具集成到LangGraph工作流中,实现复杂的多步推理和工具调用链。
class MCPExecutor:
async def call\_tool(self, tool\_name, arguments):
result = await self.session.call\_tool(
tool\_name, arguments)
return result.content[0].text
支持并发调用多个MCP工具
async def concurrent\_mcp\_calls(executor, tasks):
results = await asyncio.gather(\*[
executor.call\_tool(t) for t in tasks
])
九、总结与学习路径
本文从MCP的基本概念出发,一步步构建了一个可用于生产环境的MCP Server。下面是完整的学习路径,建议按顺序学习:
| 阶段 | 内容 | 难度 |
|---|---|---|
| Level 1 入门 | 理解MCP概念 → 写Stdio模式Hello World → 配置到IDE | ⭐ |
| Level 2 掌握 | 理解三种传输方式区别 → 用Inspector调试 → curl验证 | ⭐⭐ |
| Level 3 进阶 | stateless\_http设计 → 日志追踪 → 健康检查端点 | ⭐⭐⭐ |
| Level 4 容器化 | Dockerfile → docker-compose多实例 → Nginx负载均衡 | ⭐⭐⭐ |
| Level 5 K8S | Colima+K3S → Deployment+Service → HPA自动扩缩容 | ⭐⭐⭐⭐ |
| Level 6 高级 | LangGraph智能体 → CI/CD集成 | ⭐⭐⭐⭐⭐ |
核心要点回顾
| 序号 | 要点 |
|---|---|
| 1 | 从简单开始:先在IDE中配置Stdio模式的Hello World,理解MCP工作原理 |
| 2 | 生产首选Streamable HTTP + stateless\_http=True,原生支持负载均衡 |
| 3 | 健康检查不能省:/@mcp.custom\_route(\"/health\")是生产部署的基础 |
| 4 | 用MCP Inspector调试:npx @modelcontextprotocol/inspector,可视化工具调用 |
| 5 | 日志是排查关键:记录request\_id、参数、结果、耗时 |
| 6 | Docker Compose适合单机多实例部署,K8S适合生产级弹性伸缩 |
| 7 | K8S HPA需要metrics-server,否则无法获取CPU/内存指标 |
如果本文对你有帮助,欢迎点赞、在看、转发,让更多人看到。
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论