)
作者没有四次元口袋的蓝胖日期2026-10-06标签MCP协议, 自定义开发, AI工具MCP自定义开发官方MCP Server虽然好用但实际项目中总有你自己的业务逻辑需要暴露给AI。这时候就得自己写MCP Server了。这篇笔记从Python和TypeScript两种SDK出发讲清楚自定义MCP Server的开发流程再对比MCP与Function Calling、A2A的关系最后整理面试高频题。核心掌握Python FastMCP开发、TypeScript SDK开发、工具定义的三要素、MCP vs Function Calling对比、MCP vs A2A区别、常见面试陷阱。一、自定义MCP Server开发当官方Server不能满足需求时可以自己开发MCP Server。官方提供了Python和TypeScript两种SDK也支持Java、Kotlin、Go、Rust等语言。1.1 Python版FastMCPFastMCP是Python SDK中的高层封装用装饰器类型提示完成所有定义开发体验极其简洁。安装SDKpipinstallmcp[cli]# 或使用uv推荐uvaddmcp[cli]编写Server# server.pyfrommcp.server.fastmcpimportFastMCP# 1. 创建Server实例名字会显示在Host的工具面板中mcpFastMCP(my-tools)# 2. 定义工具 —— 装饰器 类型提示 docstringmcp.tool()defadd(a:int,b:int)-int:两数相加。 Args: a: 第一个加数 b: 第二个加数 returnabmcp.tool()defget_word_count(text:str)-int:统计文本中的单词数。 Args: text: 要统计的文本 returnlen(text.split())# 3. 启动Serverstdio传输if__name____main__:mcp.run(transportstdio)FastMCP的设计非常优雅类型提示 → JSON Schemaa: int自动生成inputSchema不需要手写docstring → 工具描述模型看到的就是你的docstring零手写JSON Schema告别冗长的Schema定义注册Resource和Prompt# 注册Resource只读数据mcp.resource(config://app/settings)defget_settings()-str:返回应用配置只读returnopen(settings.json).read()# 注册Prompt提示模板mcp.prompt()defreview_code(language:str,code:str)-list:代码审查提示模板。 Args: language: 编程语言 code: 要审查的代码 frommcp.typesimportPromptMessage,TextContentreturn[PromptMessage(roleuser,contentTextContent(typetext,textf请审查以下{language}代码\n\n{code}))]1.2 TypeScript版TypeScript版使用官方的modelcontextprotocol/sdk用Zod库定义输入Schema。项目初始化mkdirmy-mcp-servercdmy-mcp-servernpminit-ynpminstallmodelcontextprotocol/sdk zodnpminstall-Dtypescript types/nodepackage.json必须添加type: moduletsconfig.json必须设置module: Node16和moduleResolution: Node16否则编译会报错。编写Server// src/index.tsimport{McpServer}frommodelcontextprotocol/sdk/server/mcp.js;import{StdioServerTransport}frommodelcontextprotocol/sdk/server/stdio.js;import{z}fromzod;// 1. 创建ServerconstservernewMcpServer({name:my-tools,version:1.0.0,});// 2. 注册工具用Zod定义inputSchemaserver.registerTool(add,{description:两数相加,inputSchema:{a:z.number().describe(第一个加数),b:z.number().describe(第二个加数),},},async({a,b})({content:[{type:text,text:String(ab)}],}));// 3. 连接stdio传输并启动asyncfunctionmain(){consttransportnewStdioServerTransport();awaitserver.connect(transport);// 注意stdio模式下严禁console.log()console.error(MCP Server running on stdio);}main();1.3 工具定义的三要素无论哪种语言每个Tool都需要要素说明示例name工具唯一标识snake_case命名get_weatherdescription工具功能描述模型据此决定何时调用获取指定城市的天气信息返回温度和天气状况inputSchemaJSON Schema格式的输入参数定义{city: {type: string, description: 城市名}}description非常重要它是模型判断是否调用该工具的唯一依据。写得越清晰、越具体模型调用越精准。模糊的描述如处理数据会导致模型不知道什么时候该用它。1.4 接入Host使用开发完成后在配置文件里注册自己的Server{mcpServers:{my-tools:{command:python,args:[/path/to/server.py]}}}重启AI应用自定义工具就会出现在工具列表中。1.5 测试技巧开发过程中可以用MCP Inspector官方调试工具测试Server无需连接真实AI应用npx modelcontextprotocol/inspector python server.py它会在浏览器中展示Server暴露的所有Tools/Resources/Prompts可以直接填写参数调用测试是排查Schema错误的最快方式。1.6 常见开发坑点stdio模式严禁stdout输出TypeScript中不要用console.log()Python中不要用print()。所有调试日志必须走stderr。JSON Schema要合法类型错误、required拼写错误是最常见的问题用Inspector可以快速定位。工具返回值格式必须返回content数组每个元素包含type和对应内容如text。Python版本要求FastMCP需要Python 3.10。二、MCP vs Function Calling面试高频题。两者不是竞争关系而是不同层级的东西。2.1 核心区别维度Function CallingMCP本质模型层能力model-level应用层协议application-level工具在哪内嵌在每次API请求的JSON中独立的外部进程工具发现静态——每次请求都要传Tool定义动态——运行时通过tools/list发现复用性低——与具体应用代码耦合高——一次开发所有MCP Client可用凭证管理应用进程持有所有API Key每个Server独立管理自己的凭证执行位置应用代码本地执行MCP Server执行返回结果状态无状态每次请求独立支持有状态连接跨多轮保持上下文适用场景少量工具、单模型、低延迟多工具、多客户端、共享基础设施2.2 关系理解Function Calling模型决定我要调用什么工具、传什么参数 MCP工具如何被发现、描述、传输给模型一句话Function Calling是模型的能力MCP是工具到达模型的方式。大多数AI应用内部用Function Calling与MCP Server交互——两者是互补的不是替代关系。2.3 代码层面看差异Function Calling方式以Anthropic API为例# 每次API调用都要手动定义toolsresponseclient.messages.create(modelclaude-sonnet-4-20250514,tools[{name:get_weather,description:获取天气,input_schema:{type:object,properties:{city:{type:string}},required:[city]}}],messages[...])# 你自己写代码执行工具、把结果塞回下一轮请求MCP方式# 工具定义在Server端Client自动发现# 你只需配置Server连接工具列表自动获取# 换一个AI应用同一套Server直接用不用改代码2.4 选型建议场景推荐方案快速原型、少量工具Function Calling足够工具需要跨多个AI应用复用MCP需要凭证隔离不暴露API Key给模型MCP工具超过10个且持续增长MCP多团队协作共享工具基础设施MCP对延迟极度敏感的嵌入式场景Function Calling实际项目中两者通常一起使用。Function Calling处理紧耦合的内置工具如自定义打分函数MCP Server处理共享的基础设施工具如Slack、GitHub、数据库。三、MCP vs A2AAgent-to-Agent维度MCPA2A提出者AnthropicGoogle解决什么模型↔工具的连接Agent↔Agent的通信方向纵向向下调工具横向Agent间协作关系互补不是竞争互补不是竞争3.1 协作模式用户 → Agent A ──MCP──→ 工具数据库、API │ A2A协议 │ ↓ Agent B ──MCP──→ 工具邮件、日历MCP负责每个Agent与工具的纵向连接A2A负责Agent之间的横向协作。未来Agent生态中两者会并存。四、常见面试题Q1MCP的通信协议是什么JSON-RPC 2.0。一种轻量级的远程过程调用协议基于JSON格式。请求包含method、params、id三个核心字段。Q2stdio和HTTP传输怎么选本地开发、单用户场景用stdio简单、安全、无需网络端口。远程服务、多租户、云端部署用Streamable HTTP。Q3MCP Server的stdio模式下有什么坑千万不要用console.log()/print()打印日志。因为stdout是JSON-RPC的传输通道任何非协议输出都会破坏消息格式导致连接中断。日志必须打到stderrconsole.error()/logging。Q4MCP如何实现动态工具发现Client连接Server后发送tools/list请求Server返回当前可用的所有工具列表名称描述Schema。模型在运行时才知道有哪些工具可用不需要提前硬编码。这比Function Calling每次都要传tools列表优雅得多。Q5MCP的安全性如何保证权限隔离每个Server只暴露声明的能力无法越权操作凭证隔离API Key等敏感信息存在Server端的环境变量中不会传给模型最小权限如Filesystem Server只开放配置的目录白名单用户确认模型调用工具前通常需要用户确认取决于Host实现Q6MCP有状态吗MCP支持有状态连接stateful connectionsClient和Server之间可以维持持久会话跨多次消息保持上下文。这是相比无状态Function Calling的一大优势特别适合需要多轮交互的复杂任务。Q7为什么说MCP不是又一个API框架API框架如REST、GraphQL定义的是通用的数据交互方式。MCP定义的是AI模型与工具之间的交互方式——它包含了工具描述让模型理解工具干什么、动态发现运行时获取工具列表、能力协商Client和Server互相声明支持的特性。这些是API框架没有的。Q8MCP和Function Calling的关系两者在不同层级。Function Calling是模型层能力——模型根据预定义的工具列表决定调用什么、传什么参数。MCP是应用层协议——定义了工具如何被发现、描述和传输。大多数AI应用内部用Function Calling来调用MCP Server暴露的工具两者互补而非竞争。Q9开发MCP Server需要注意什么stdio模式下严禁stdout输出会破坏JSON-RPC协议帧工具的description要写得清晰具体模型据此决定是否调用凭证放在环境变量中不要硬编码遵循最小权限原则用MCP Inspector做开发调试。️ 思维导图速览MCP自定义开发 ├── 自定义Server开发 │ ├── PythonFastMCP装饰器类型提示→自动Schema │ │ ├── 安装pip install mcp[cli] │ │ ├── mcp.tool() 定义工具 │ │ ├── mcp.resource() 定义只读数据 │ │ ├── mcp.prompt() 定义提示模板 │ │ └── mcp.run(transportstdio) 启动 │ ├── TypeScriptMcpServer Zod │ │ ├── 初始化npm install modelcontextprotocol/sdk zod │ │ ├── server.registerTool() 注册工具 │ │ └── StdioServerTransport 连接传输 │ ├── 工具三要素 │ │ ├── namesnake_case唯一标识 │ │ ├── description模型调用决策的唯一依据写清晰 │ │ └── inputSchemaJSON Schema定义输入参数 │ ├── 接入Host配置文件注册command/args │ ├── 调试工具MCP Inspector浏览器测试 │ └── 常见坑点 │ ├── stdio模式禁止stdout输出 │ ├── JSON Schema合法性校验 │ ├── 返回值必须为content数组格式 │ └── Python需3.10 ├── vs Function Calling │ ├── FC是模型能力MCP是应用协议不同层级 │ ├── FC静态定义MCP动态发现 │ ├── FC低复用MCP高复用 │ ├── FC无状态MCP支持有状态连接 │ └── 两者互补大多数项目同时使用 ├── vs A2A │ ├── MCP纵向模型→工具 │ └── A2A横向Agent→Agent └── 面试高频 ├── stdio模式的stdout陷阱 ├── 动态工具发现机制 ├── 安全性权限隔离凭证隔离最小权限 ├── MCP有状态连接 └── MCP ≠ API框架含工具描述/动态发现/能力协商 写在最后学习建议动手写一个Server跟着Python FastMCP教程写一个自己的Server哪怕只是一个简单的计算器或天气查询跑通整个流程定义→注册→配置→调用。对比思考把MCP和Function Calling对比理解搞清楚它们在不同层级解决的问题。面试中MCP和Function Calling的区别几乎是必考题。掌握TypeScript版如果你的技术栈偏前端/Node.jsTypeScript版的开发体验同样优秀Zod的Schema定义也非常直观。关注生态GitHub上modelcontextprotocol/servers仓库有大量官方和社区Server看看别人怎么写的比读文档有效。面试高频问题速答Q什么是MCPMCPModel Context Protocol是Anthropic开源的标准化协议定义了AI应用与外部工具/数据源的通信方式。它采用Host/Client/Server三层架构基于JSON-RPC 2.0通信通过Tools、Resources、Prompts三大原语暴露能力。核心价值是将M×N的集成问题简化为MN实现一次开发到处接入。QMCP和Function Calling的关系两者在不同层级。Function Calling是模型层能力——模型根据预定义的工具列表决定调用什么、传什么参数。MCP是应用层协议——定义了工具如何被发现、描述和传输。大多数AI应用内部用Function Calling来调用MCP Server暴露的工具两者互补而非竞争。QMCP相比传统API集成的优势①标准化统一接口写一次到处用②动态发现运行时获取可用工具列表不需要硬编码③凭证隔离敏感信息在Server端管理不暴露给模型④生态复用社区已有6000个现成Server⑤有状态连接支持跨多轮交互保持上下文。Q开发MCP Server需要注意什么stdio模式下严禁stdout输出会破坏JSON-RPC协议帧工具的description要写得清晰具体模型据此决定是否调用凭证放在环境变量中不要硬编码遵循最小权限原则用MCP Inspector做开发调试。