资讯动态

MCP 快速入门:从 stdio 命令到 Agent 可调用工具

发布时间:2026/9/23 23:54:07 来源:尧图企业网站定制
简介这是一份面向大模型应用开发者与Agent方向学习者的MCP入门实战资料围绕Model Context Protocol这一由Anthropic提出的智能体工具调用协议展开帮助读者跨越Function calling门槛过高、外部函数重复开发的痛点从零搭建可运行的MCP客户端与服务器。内容覆盖MCP技术体系与Agent开发脉络回顾、uv依赖管理工具使用、极简客户端搭建、接入OpenAI与DeepSeek在线模型及本地ollama、vLLM模型以及天气查询服务器的完整创建与Inspector调试并延伸至客户端与服务器的进阶功能。资源为1个PDF文件压缩包约47.66MB适合按章节顺序阅读并同步动手实践。目前已有1124人学习下载可作为理解MCP通讯机制、掌握客户端与服务器协作流程的参考材料。1. MCP 快速入门从一条 stdio 命令到能被 Agent 调用的工具很多人第一次接触 MCP是在某个 AI 编辑器里看到「添加 MCP Server」的按钮点进去填了个命令然后就没有然后了。真正卡住的地方从来不是概念而是我写的这个 Server怎么让 Agent 稳定地发现、调用、拿到结构化结果MCPModel Context Protocol解决的正是这件事——它把「模型能调用的能力」抽象成一套标准协议Server 暴露 tools、resources、promptsClient也就是 Agent 宿主负责握手、列能力、转发调用。你不需要改模型只需要按协议把工具挂上去。这篇面向想动手的人会用 Python 写函数、装过 uv、知道 Agent 大概是什么。目标是从零跑通一个本地 stdio Server再用一个最小 Client 调通它最后讲清楚参数、传输方式和排错。全程不依赖任何云端账号本地就能复现。2. MCP 协议核心概念与 uv 环境准备2.1 MCP 的三种原语tool、resource、prompt 到底怎么选MCP 把 Server 能提供的东西分成三类选错了后面调用会很别扭。tool有副作用、需要参数、返回执行结果。比如查数据库、发请求、写文件。Agent 会把它当成「函数」来调。resource只读数据用 URI 标识比如file:///logs/app.log。适合把上下文喂给模型而不是让模型去执行。prompt预置的提示模板Server 提供、Client 选用常用于把复杂任务固化成可复用入口。判断标准很简单要执行动作选 tool要读数据选 resource要复用一段提示词选 prompt。新手最容易把所有东西都塞成 tool结果模型面对一堆「读文件」工具反复试错。2.2 用 uv 装 Python 环境避开依赖地狱MCP 官方 Python SDK 迭代快用 uv 管理最省心。uv 是 Rust 写的包与环境管理器装依赖比 pip 快一个量级还能直接锁定 Python 版本。# 安装 uvLinux/macOS curl -LsSf https://astral.sh/uv/install.sh | sh # Ubuntu 上如果 curl 装完找不到命令重开 shell 或 source 一下 source $HOME/.local/bin/env # 初始化项目指定 Python 版本 uv init mcp-demo cd mcp-demo uv python pin 3.11 # 添加 MCP SDK uv add mcp[cli]逻辑说明uv init生成pyproject.tomluv python pin把解释器版本写进.python-version避免团队里有人用 3.8 跑不起来。uv add mcp[cli]会同时装 SDK 和命令行工具mcp后面调试要用。参数说明mcp[cli]里的方括号是 extras 语法只装核心 SDK 不带 CLI 的话mcp dev这类命令会缺失。国内网络慢可以设UV_INDEX_URL指向镜像但别写死在项目文件里用环境变量更干净。提示如果机器完全离线先在能联网的机器上uv pip download或直接拷贝 uv 缓存目录再在目标机uv sync --offline。别用系统 pip 混装版本冲突排查成本很高。2.3 传输方式选型stdio 还是 HTTP传输方式适用场景启动方式注意点stdio本地工具、编辑器集成Client 拉起子进程日志绝不能写 stdoutStreamable HTTP远程共享、多 ClientServer 常驻监听需要处理会话与鉴权SSE旧兼容老 ClientHTTP 长连接新项目不建议再用本地开发一律先上 stdio因为它最简单Client 用命令启动 Server两者通过标准输入输出交换 JSON-RPC 消息。代价是任何print()都会污染协议流导致 Client 解析失败。调试信息一律走stderr或 logging。3. 写一个最小 MCP Server 并本地跑通3.1 用 FastMCP 定义第一个 tool官方 SDK 提供FastMCP装饰器风格几行就能起一个 Server。# server.py from mcp.server.fastmcp import FastMCP mcp FastMCP(demo-server) mcp.tool() def add(a: int, b: int) - int: 两数相加。a 和 b 必须是整数。 return a b mcp.tool() def word_count(text: str) - dict: 统计文本的字符数和词数。 return {chars: len(text), words: len(text.split())} if __name__ __main__: mcp.run(transportstdio)逻辑说明mcp.tool()把普通函数注册成 MCP tool函数签名和类型注解会被自动转成 JSON SchemaAgent 靠这个 Schema 决定怎么传参。docstring 不是装饰它会作为工具描述发给模型——写清楚「参数是什么、返回什么」模型调用准确率会明显提升。参数说明FastMCP(demo-server)里的名字是 Server 标识Client 侧会看到。mcp.run(transportstdio)指定传输方式本地调试就用它。返回类型建议用dict或基础类型别返回自定义对象序列化会出问题。3.2 用 mcp dev 做交互式调试写完别急着接 Agent先用官方调试器验证工具本身没问题。# 启动调试界面 uv run mcp dev server.py它会起一个本地 Inspector你能看到 Server 暴露了哪些 tool、每个 tool 的 Schema、手动填参数调用看返回。这一步能挡掉 80% 的低级错误类型写错、docstring 缺失、返回值不可序列化。注意如果 Inspector 里工具列表是空的先检查函数有没有被mcp.tool()装饰再看有没有在if __name__ __main__之前定义。装饰器必须在模块加载时就执行到。3.3 常见启动报错与定位方法现象大概率原因处理Client 连不上无输出Server 往 stdout 打了日志改用 stderr / logging工具列表为空装饰器没生效或导入失败单独uv run python server.py看报错调用返回 schema 错误类型注解缺失或用了复杂类型补注解返回基础类型进程秒退依赖没装进当前环境uv sync后重试定位核心思路把 Server 当普通进程先跑起来。uv run python server.py能正常阻塞等待输入说明进程没问题问题在协议层如果直接报错就是代码或依赖问题。4. 用 Client 调通 Server从握手到工具调用4.1 最小 Client 的完整调用链Client 的职责是启动 Server 子进程 → 初始化握手 → 列出工具 → 调用工具。下面是一个能直接跑的版本。# client.py import asyncio from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client async def main(): params StdioServerParameters( commanduv, args[run, python, server.py], ) async with stdio_client(params) as (read, write): async with ClientSession(read, write) as session: await session.initialize() # 握手 tools await session.list_tools() # 列能力 print(tools:, [t.name for t in tools.tools]) result await session.call_tool( add, {a: 3, b: 5} ) print(result:, result.content) asyncio.run(main())逻辑说明StdioServerParameters描述怎么拉起 Serverstdio_client建立管道ClientSession封装 JSON-RPC 会话。initialize()是必须的握手步骤跳过它后续调用会失败。list_tools()返回工具元数据call_tool()按名字和参数字典调用。参数说明command和args要能被系统直接执行uv run python server.py是最稳的写法因为它会自动用项目环境。call_tool的第二个参数是 dict键必须和 Schema 里的参数名一致类型也要对传字符串给 int 参数会被拒。4.2 把 Server 接进 Agent 宿主的配置写法大多数支持 MCP 的编辑器或 Agent 框架配置本质就是上面那段StdioServerParameters的 JSON 化。{ mcpServers: { demo: { command: uv, args: [--directory, /abs/path/to/mcp-demo, run, python, server.py] } } }逻辑说明--directory让 uv 切到项目目录再执行避免相对路径找不到pyproject.toml。路径一定用绝对路径Agent 宿主的工作目录和你终端不一样。参数说明不同宿主字段名可能叫mcpServers或servers但command/args结构一致。如果宿主支持环境变量把密钥类配置放env字段别硬编码进 args。4.3 调用失败时的排查顺序遇到「工具调用了但没结果」或「Agent 说找不到工具」按这个顺序查单独跑 Client 脚本确认list_tools()有输出。没有就是 Server 侧问题。有工具但调用报错看call_tool返回的isError字段和错误文本。参数校验失败对照 Inspector 里的 Schema 逐个核对类型。宿主里不生效检查配置路径是否为绝对路径、命令是否在宿主 PATH 里。提示Agent 宿主通常有日志目录MCP 握手和调用记录会写进去。比起猜直接翻日志里 Server 的 stderr 输出最快。5. MCP 进阶让工具被 Agent 稳定选中5.1 工具描述与参数设计的三条经验工具能不能被正确调用一半取决于描述质量。三条实操经验名字用动词开头search_docs比docs好模型对动作语义更敏感。docstring 写清边界说明参数取值范围、返回结构、什么情况下不该用。比如「仅支持 UTF-8 文本超过 10MB 请改用分片接口」。参数扁平化能用str、int、bool就别嵌套对象嵌套会让模型传参出错率上升。5.2 用 resource 暴露只读上下文当你要给模型喂日志、配置、文档时用 resource 比 tool 更合适。mcp.resource(config://app) def get_config() - str: 返回应用当前配置。 return open(config.yaml, encodingutf-8).read()逻辑说明URI 是 resource 的标识Client 可以按 URI 读取。只读、无副作用模型不会「误执行」。参数说明URI scheme 自定义即可但要保证唯一性和可读性方便在 Client 侧做权限控制。5.3 验证工具是否真的被调用最后一步是确认 Agent 确实走了 MCP而不是自己编了答案。最直接的办法是在 tool 里加一行 stderr 日志import sys mcp.tool() def add(a: int, b: int) - int: print(f[call] add a{a} b{b}, filesys.stderr) return a b跑一次 Agent 任务看宿主日志里有没有这行输出。有说明调用链通了没有说明模型选择了别的路径或工具没被注册。这个技巧在排查「Agent 答对了但不确定是不是调了工具」时特别有用也是把 MCP 从 demo 推向可用工具的关键一步。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价