手搓 MCP 到最简 Agent 知识点清单

0 阅读4分钟

一、Python 环境与工具链

  • uv 的定位:pip + venv + pyenv + pipx 的合体,Rust 写的,快 10~100 倍
  • uv python install:安装独立 Python 版本,不污染系统
  • uv python pin:修改 .python-version,钉死项目 Python 版本
  • .python-version 优先级高于 pyproject.toml 的 requires-python
  • uv venv:创建隔离环境 .venv/
  • uv add:装包 + 写 pyproject.toml + 生成 uv.lock
  • uv run:在 .venv 里执行命令,无需手动 activate
  • uv pip show:查看已装包版本
  • pin 的含义:钉死版本,让工具别再自己猜(.python-version 钉 Python,uv.lock 钉依赖,== 钉包版本)

二、MCP 核心概念

  • MCP 是工具层/连接协议:让 LLM 标准化发现和调用外部工具,不参与推理
  • MCP 与 Agent 的关系:先学 MCP(手脚),再学 Agent(大脑)
  • MCP Server 的三层结构:Server 实例 → @mcp.tool() 挂工具 → mcp.run() 启动
  • @mcp.tool() 做的事:读函数名(工具名)、类型注解(参数 schema)、docstring(工具描述),自动生成 JSON Schema
  • 工具函数两条惯例:返回值统一 str;错误不 raise,直接 return 字符串
  • FastMCP 是 v1 的名字,v2 改名为 MCPServer(from mcp.server.mcpserver import MCPServer)
  • 其他装饰器:@mcp.resource()(只读资源)、@mcp.prompt()(提示词模板)

三、Transport 传输方式

  • transport="stdio":用标准输入输出管道通信,不开端口
  • stdio 工作方式:Server 监听 stdin,响应写 stdout;Client 创建子进程接管管道
  • stdio 的优点:简单、零配置、天然隔离;缺点:只能本机
  • 其他传输:sse(HTTP + SSE)、streamable-http(HTTP 流式)
  • stdio 的坑:工具函数里不能往 stdout 打印普通文本,调试用 stderr
  • stdio 必须一条命令启动:Server 是 Inspector 的子进程,父子关系启动时建立,不能分开执行

四、JSON-RPC 协议交互

  • 一次工具调用 = 6 次 JSON-RPC 往返:initialize 请求/响应 → tools/list 请求/响应 → tools/call 请求/响应
  • 消息固定结构:{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{...}}
  • Server 的本质:把 Python 函数"翻译"成 JSON Schema 说明书,等待调用,不会思考
  • 真正决定调用什么的是 Client 一侧

五、Inspector 调试工具

  • Inspector 是官方参考调试工具,扮演"临时替身 Client"
  • 三种形态:Web 界面(默认)、CLI、TUI
  • Inspector 不读 Python 代码,只读协议消息,根据 JSON Schema 自动渲染表单
  • 改代码重启 Server,表单自动更新——协议化的好处
  • Inspector 的启动命令:pnpm dlx @modelcontextprotocol/inspector uv run python server.py
  • 必须用带 ?MCP_INSPECTOR_API_TOKEN=... 的完整 URL 打开浏览器
  • npm 原生绑定 bug(npm/cli#4828):Apple Silicon 上缺 darwin-arm64,用 pnpm 绕过

六、手搓 Client

  • Client 四步:连接 Server → list_tools() → schema 转 Ollama 格式 → 跑 Agent 循环
  • Schema 翻译几乎是透传:MCP 的 inputSchema 就是标准 JSON Schema,Ollama 的 parameters 也接受
  • messages.append(response.message) 不能漏:包含模型"决定调工具"的动作记录
  • role: "tool" 回填格式:{"role": "tool", "tool_name": ..., "content": ...}
  • ollama 是第三方包,需 uv add ollama

七、模型决策 vs 框架执行

  • chat(...) 是模型做决策:读对话历史 + 工具清单 → 判断调不调、调哪个、传什么参数
  • session.call_tool(...) 是框架执行决策:通过 MCP 协议真正调用工具
  • 模型只负责"说",框架负责"做"
  • 模型选工具的依据:几乎完全来自工具的 description 和参数 schema
  • docstring 要写"什么时候用",不只是"函数做什么"
  • 三个常见误解:LLM 不会自动"发现"工具(框架每轮塞清单)、不会执行工具(只输出调用请求)、可能选错(3B 小模型工具多了易混淆)

八、最简 Agent

  • 最简 Agent = 控制台输入 + LLM 决策 + MCP 工具执行 + 结果回填 + 循环
  • Agent 五要素:感知(input())、决策(chat)、行动(call_tool)、反馈(role:tool 回填)、循环(内外两层 while)
  • ReAct 模式:Reasoning + Acting 的最小实现,思考 → 行动 → 观察 → 再思考
  • 最简 Agent 的四个局限:无记忆管理(messages 无限增长)、无错误恢复(异常会崩)、无多步规划(3B 易乱)、工具描述依赖人工

九、HTTP 工具实践(查天气)

  • wttr.in 免费 API,不需要 Key
  • 编码坑:'ascii' codec can't encode characters——中文城市名和 format 参数的特殊字符没完全编码
  • 解决:城市名和 format 参数分开 quote(..., safe="")
  • timeout 必加:防止网络卡住导致 Agent 卡死
  • 错误返回字符串而非抛异常:模型能理解并决定下一步

十、三层分工总结

层角色项目对应
MCP工具层/连接协议(手脚)server.py 的三个工具
LLM决策层(大脑)千问 2.5 3B,经 Ollama 调用
Agent 框架神经,连接两者、跑循环、回填结果client.py 的 while True + call_tool
  • 一句话:MCP 提供手脚,LLM 提供大脑,Agent 框架是神经,三者配合才能完成任务
  • 后续可加:记忆管理、错误恢复、多步规划、多工具协同