为什么做这篇指南(一句话说明)
MCP(Model Context Protocol)是把 LLM 与外部数据/工具标准化连接起来的开放协议——学会搭建一个本地/自托管的 MCP Server,能让你的应用把模型变成可执行的 agent。(modelcontextprotocol.io, Google Cloud)
目标读者 & 输出形式
- 读者:对 LLM 集成感兴趣的后端/工具工程师,熟悉 JS/TS 或 Python;也适合希望把 AI 能力「写入自己 Infra」的团队。
- 输出:一篇 ~2000–3500 字的深度教程或 8–12 分钟的技术实操视频(含终端/IDE 演示)。
教程结构(可直接用作文章目录或视频分段)
- 概念速览:什么是 MCP,为什么要有 MCP Server(含传输方式:stdio / SSE 等)。(modelcontextprotocol.io, GitHub)
- 环境与前置条件(Node.js、npm、Python 3.11+、pip、Docker 可选)
- 第一个最小可运行 MCP Server(TypeScript 版本:stdio 传输) — 5 分钟上手
- Python 版本实现(asyncio + stdio) — 5 分钟上手
- 常见功能扩展:注册 tools/resources、执行本地命令、安全沙箱、权限控制
- 本地测试与与客户端(Host)对接(模拟请求、日志、错误处理)
- 部署与运维注意(容器化、系统权限、审计日志)
- 常见问题与排错清单
- 参考资源与扩展阅读(MCP 官方、示例仓库、社区集合)(modelcontextprotocol.io, GitHub, mcp-docs.cn)
快速上手:TypeScript 最小实现(stdio transport)
目标:用 Node.js 建一个通过 stdin/stdout 收发 JSON 的最小 MCP Server(便于跟支持 stdio 的 Host 集成或做开发调试)。
// file: mcp-server-ts.ts
// 运行: node --loader ts-node/esm mcp-server-ts.ts (或先 tsc 编译再 node)
import readline from 'readline';
const rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: false });
// 简单的 Message 帧格式示例(实际协议更丰富,这里做最小示范)
type MCPMessage = { id: string; type: string; payload?: any };
function send(msg: MCPMessage) {
const s = JSON.stringify(msg);
process.stdout.write(s + '\n'); // 每条 JSON 一行,便于 Host 解析
}
rl.on('line', (line) => {
if (!line.trim()) return;
try {
const msg: MCPMessage = JSON.parse(line);
console.error('[mcp-server] recv:', msg);
// 简单路由:type === 'invoke' -> 执行工具/返回结果
if (msg.type === 'invoke') {
const tool = msg.payload?.tool;
if (tool === 'echo') {
send({ id: msg.id, type: 'result', payload: { output: msg.payload?.input ?? '' }});
} else {
send({ id: msg.id, type: 'error', payload: { message: 'unknown tool' }});
}
} else if (msg.type === 'ping') {
send({ id: msg.id, type: 'pong' });
} else {
send({ id: msg.id, type: 'error', payload: { message: 'unsupported type' }});
}
} catch (err) {
console.error('[mcp-server] parse error', err);
}
});
console.error('[mcp-server] ready');
说明:这个示例把协议简化为「每行一个 JSON 对象」,用于本地调试和与支持 stdio 的 MCP Host(或模拟客户端)对接。真实实现会遵循 MCP 规范的资源、prompts、tools 等字段与约定。(GitHub)
同步示例:Python 最小实现(asyncio + stdio)
# file: mcp_server_py.py
# 运行: python mcp_server_py.py
import sys
import asyncio
import json
async def read_loop():
loop = asyncio.get_event_loop()
reader = asyncio.StreamReader()
protocol = asyncio.StreamReaderProtocol(reader)
await loop.connect_read_pipe(lambda: protocol, sys.stdin)
while True:
line = await reader.readline()
if not line:
await asyncio.sleep(0.1)
continue
try:
msg = json.loads(line.decode().strip())
sys.stderr.write(f"[mcp-server] recv: {msg}\n")
if msg.get('type') == 'invoke' and msg.get('payload', {}).get('tool') == 'echo':
resp = {'id': msg.get('id'), 'type': 'result', 'payload': {'output': msg['payload'].get('input', '')}}
else:
resp = {'id': msg.get('id'), 'type': 'error', 'payload': {'message': 'unknown'}}
sys.stdout.write(json.dumps(resp) + "\n")
sys.stdout.flush()
except Exception as e:
sys.stderr.write(f"[mcp-server] err: {e}\n")
asyncio.run(read_loop())
说明:Python 版本同样演示读取 stdin、解析 JSON、写回 stdout 的最小 loop,便于直接与 MCP Host(Local client)连接。真实项目通常会把工具执行放进子进程/隔离沙箱并做调用限速与审计。(flowhunt.io)
关键实现建议(安全 & 可用性)
- 输入输出严格校验:不要直接把 LLM 的指令当作 shell 命令执行,必须做白名单 & 参数化。(flowhunt.io)
- 权限与审计:把所有 tool 调用、返回、异常写日志并归档,便于事后审计。
- 隔离执行:本地命令通过容器/短生命周期子进程执行,限制资源和超时。
- 传输选择:stdio 适合本地进程模式;SSE/HTTP 适合远程/持久连接场景,而规范亦支持多种 transport。(GitHub, modelcontextprotocol.io)
测试与集成(快速套路)
- 本地模拟 Host:写一个小脚本模拟 Host 向你的 MCP Server 发起
invoke
消息(JSON 行)。 - 端到端用例:配置一个简单 tool(如 echo / list_files / db_query),跑 10–100 次并记录成功率与延迟。
- 安全测试:尝试注入、超长输入、并发突发,验证限速与超时。
- 与现有 MCP Client 对接:使用社区现成的 MCP 客户端或 Host(参考 Awesome 列表)做互通测试。(GitHub, mcp.so)
参考资源(必看)
- MCP 官方站(Model Context Protocol)—— 协议与规范入门。(modelcontextprotocol.io)
- Anthropic/Cloud 介绍文章(为什么需要 MCP)。(Google Cloud)
- MCP 中文入门与实战指南(社区翻译/示例)。(GitHub, mcp-docs.cn)
- Awesome MCP Servers(社区示例集合)—— 找现成 server/实现参考。(GitHub)
如果你愿意,我可以 立刻帮你把第 3 与第 4 节(TypeScript & Python 的实战部分)扩充为可直接拷贝运行的完整项目仓库结构(包含:package.json、requirements.txt、测试脚本、Dockerfile、以及一个简单的 Host 模拟器)。你想先要 完整代码 + README(可直接上传到 GitHub) 还是先要 视频脚本与分镜?🙂
发表回复