AI 函数调用与 MCP 协议深度解析:从 OpenAI tools 到 Model Context Protocol
如果你 2026 年还在手写”把工具描述拼成 prompt,解析 LLM 返回的 JSON 再调本地函数”——你正在错过 AI 工具生态最大的范式转移。
工具调用(Tool Use / Function Calling)这件事,已经从「各家闭源 API 各搞一套」演化成了一场事实标准的争夺战:
- 2023 年 6 月,OpenAI 在
gpt-4-0613/gpt-3.5-turbo-0613上线tools字段,把 JSON Schema 直接塞进 chat completion 请求 - 2024 年 5 月,Anthropic 在 Claude 3 上线原生 Tool Use,格式与 OpenAI 类似但
input_schema命名不同 - 2024 年 11 月,Anthropic 联合多家厂商发布 Model Context Protocol(MCP),把”工具调用”从「模型 API 的一个参数」升格成了一个独立的、客户端-服务器架构的开放协议
- 2025 年,OpenAI 宣布 Agent SDK 全面支持 MCP,Replit、Sourcegraph、Codeium 等头部厂商跟进
- 2026 年,MCP 已经成为 Agent 工具生态的事实标准——Cursor、Claude Desktop、Continue、Zed 等 IDE 全栈接入
但工具调用与 MCP 协议,对绝大多数工程师来说还是两个模糊的概念。这篇文章的目标,就是把这件事讲透:
- 原理层:OpenAI tools、Claude Tool Use、Gemini Function Calling 三大协议的字段差异到底在哪
- 架构层:MCP 协议为什么不是”另一个工具调用 API”,它的 JSON-RPC + Resources/Prompts/Tools/Sampling 设计哲学是什么
- 工程层:从零写一个 MCP Server,接入 Claude Desktop 与 Claude Agent SDK 的全链路代码
读完后,你将能够独立设计一个支持多模型的工具调用层,并为任何 Agent 系统接入 MCP 生态。
一、为什么 Function Calling 是 Agent 时代的基石?
1.1 没有工具调用时,LLM 只是个”聊天机器人”
在 Function Calling 出现之前,LLM 接入外部系统只有两条路:
| 方式 | 实现 | 缺陷 |
|---|---|---|
| Prompt 注入 | 把”工具描述”塞进 system prompt,让模型输出 Action: get_weather({"city":"北京"}) 字符串 | 输出格式不可控、需要正则解析、Token 浪费严重 |
| RAG 检索 | 把外部文档切片塞进 context window | 只能读,不能写、不能调用 |
Function Calling 的革命性在于:它把”调用工具”从”自然语言生成”变成了”结构化决策”。模型不再生成自由文本,而是输出一个机器可解析的结构化对象(通常是 JSON),由应用层决定下一步行为。
1.2 Function Calling 解决了三个核心问题
┌─────────────────────────────────────────────────┐│ ① 可靠性:从"75% JSON 合法率"提升到"99%+ 结构匹配" ││ ② 可发现性:模型能"看到"可用工具,不需要记硬编码 prompt ││ ③ 可组合性:多工具 + 多轮对话 = 复杂 Agent 任务 │└─────────────────────────────────────────────────┘这三点让 Function Calling 成为 Agent 时代的”TCP/IP”——没有它,Claude Computer Use、OpenAI o3 Deep Research、Manus 这种产品根本不可能存在。
二、三大 Function Calling 协议横评
虽然 OpenAI tools 已经成为事实标准,但 Claude、Gemini、Qwen 在字段命名、Schema 约束、流式行为上仍有差异。下面用同一个”查询天气”工具对照三家的 API。
2.1 OpenAI tools(事实标准)
from openai import OpenAIimport json
client = OpenAI()
tools = [ { "type": "function", "function": { "name": "get_weather", "description": "查询指定城市的实时天气", "parameters": { "type": "object", "properties": { "city": {"type": "string", "description": "城市名称"}, "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]} }, "required": ["city"] } } }]
resp = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": "北京今天天气怎么样?"}], tools=tools, tool_choice="auto" # "auto" | "none" | {"type":"function","function":{"name":"get_weather"}})
msg = resp.choices[0].messageif msg.tool_calls: for tc in msg.tool_calls: args = json.loads(tc.function.arguments) print(f"模型想调用 {tc.function.name}({args})") # → 模型想调用 get_weather({'city': '北京', 'unit': 'celsius'})关键字段:
type: "function":固定值(OpenAI 后续会扩展type: "custom"等)function.name/description/parameters:JSON Schematool_choice:控制是否必须调用、调用哪一个- 响应在
message.tool_calls[i].function.arguments(字符串 JSON,需要自己解析)
2.2 Claude Tool Use(Anthropic)
import anthropicimport json
client = anthropic.Anthropic()
tools = [ { "name": "get_weather", "description": "查询指定城市的实时天气", "input_schema": { # ← 注意字段名不同 "type": "object", "properties": { "city": {"type": "string", "description": "城市名称"}, "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]} }, "required": ["city"] } }]
resp = client.messages.create( model="claude-3-5-sonnet-20241022", max_tokens=1024, tools=tools, messages=[{"role": "user", "content": "北京今天天气怎么样?"}])
for block in resp.content: if block.type == "tool_use": # ← 块类型不同 print(f"模型想调用 {block.name}({block.input})") # → 模型想调用 get_weather({'city': '北京', 'unit': 'celsius'})关键差异:
| 维度 | OpenAI tools | Claude Tool Use |
|---|---|---|
| Schema 字段 | function.parameters | input_schema |
| 响应位置 | message.tool_calls[i].function | content[i] 块,type=tool_use |
| 响应字段 | function.arguments(字符串) | input(直接是 dict) |
| tool_choice | 字符串 + 对象 | 默认 auto,强制调用通过 prompt 实现 |
| 流式 | 通过 tool_calls[i].index 增量 | 通过 content_block_delta 增量 |
2.3 Gemini Function Calling(Google)
import google.generativeai as genai
genai.configure(api_key="YOUR_KEY")
weather_fn = { "name": "get_weather", "description": "查询指定城市的实时天气", "parameters": { "type": "object", "properties": { "city": {"type": "string"}, "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]} }, "required": ["city"] }}
model = genai.GenerativeModel( model_name="gemini-1.5-pro", tools=[weather_fn])
chat = model.start_chat()resp = chat.send_message("北京今天天气怎么样?")
for part in resp.parts: if fn := part.function_call: print(f"模型想调用 {fn.name}({dict(fn.args)})")2.4 三家差异速查表
| 维度 | OpenAI | Claude | Gemini |
|---|---|---|---|
| Schema 字段 | function.parameters | input_schema | parameters |
| 响应包装 | tool_calls[] 数组 | content[] 块 | parts[] 块 |
| 并行调用 | ✅ 原生支持(一次返回多个) | ✅ 单次响应可含多个 tool_use | ✅ 原生支持 |
| 强制调用 | tool_choice="required" | prompt 引导 + system 约束 | tool_config |
| 流式增量 | tool_calls.delta | content_block_delta | 不支持流式 tool call |
| 结构化输出 | response_format + strict: true | tool_use + structured output | responseSchema |
实战建议:如果你写的是单一模型的应用,直接用对应 SDK 即可。如果写的是多模型抽象层,建议抽象成自己的 ToolDefinition + ToolCall,内部做协议转换。这正是 MCP 想要解决的痛点。
三、MCP 协议:工具调用的”USB-C 时刻”
3.1 Function Calling 的局限:每个客户端都要重复实现
MCP 出现之前,假设你想让自己的 IDE(Cursor、Claude Desktop、Continue)接入你的”团队知识库”,你必须:
- 给 Cursor 写一个 Cursor Extension
- 给 Claude Desktop 写一个 Desktop Plugin
- 给 Continue 写一个 Continue Provider
- 给 Zed 写一个 Zed Extension
每个 IDE 都要重复适配一次——和 1995 年之前每个外设都要为每台电脑写驱动一样混乱。
MCP 的核心承诺:你只写一次 MCP Server,所有支持 MCP 的客户端(IDE、Agent、桌面应用)都能用。
┌──────────────────────────────────────────────────────────┐│ MCP 生态 │├──────────────────────────────────────────────────────────┤│ ││ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ││ │ Cursor │ │ Claude │ │ Continue │ │ Zed │ ││ │ (MCP │ │ Desktop │ │ (MCP │ │ (MCP │ ││ │ Client) │ │ (Client) │ │ Client) │ │ Client) │ ││ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ ││ │ │ │ │ ││ └─────────────┴──────┬───────┴─────────────┘ ││ │ MCP 协议(JSON-RPC 2.0) ││ ┌───────────┴───────────┐ ││ │ │ ││ ┌─────▼─────┐ ┌──────▼──────┐ ││ │ Filesystem│ │ GitHub │ ││ │ Server │ │ Server │ ││ └───────────┘ └─────────────┘ ││ ┌───────────┐ ┌─────────────┐ ││ │ Postgres │ │ Brave │ ││ │ Server │ │ Search │ ││ └───────────┘ └─────────────┘ │└──────────────────────────────────────────────────────────┘3.2 MCP 的四大原语(Primitives)
MCP 不是”又一个工具调用 API”,它把模型与外部资源的交互抽象成四个原语:
| 原语 | 角色 | 类比 | 典型用途 |
|---|---|---|---|
| Tools | 模型主动调用的”动作” | REST POST | 查数据库、发邮件、写文件 |
| Resources | 应用读取的”数据” | REST GET | 读文件、读数据库 schema、读知识库 |
| Prompts | 预定义的 prompt 模板 | REST 静态资源 | /review-code、/explain-error |
| Sampling | Server 让 Client 反向调用 LLM | 服务端回调 | 让 MCP Server 也能”思考” |
这个设计的妙处在于:Tools 是”模型 → 外部”的动作,Resources 是”应用 ← 外部”的数据。两者方向相反但都通过同一协议承载,让 LLM 和应用层共享同一套上下文。
3.3 MCP 的传输层(Transport)
MCP 协议本身是 JSON-RPC 2.0,传输层支持三种:
| 传输方式 | 适用场景 | 实现 |
|---|---|---|
| stdio | 本地进程,Claude Desktop 主流 | 标准输入输出流 |
| HTTP + SSE | 远程服务器,Streamable HTTP(2025 标准) | Server-Sent Events 单向流 + HTTP POST |
| WebSocket | 双向长连接(已逐步被 Streamable HTTP 取代) | 全双工 |
对绝大多数本地工具来说,stdio 是最简单也最可靠的选择。你的 MCP Server 就是一个命令行进程,通过 stdin/stdout 跟 Client 通信。
四、自建 MCP Server:从零到接入 Claude Desktop
下面我们手写一个”代码评审助手”MCP Server,让 Claude Desktop 在用户输入”review 一下这个文件”时,自动调用我们的评审逻辑。
4.1 项目结构
mcp-code-reviewer/├── pyproject.toml├── README.md└── src/ └── mcp_code_reviewer/ ├── __init__.py └── server.py # MCP Server 入口4.2 安装依赖
mkdir mcp-code-reviewer && cd mcp-code-reviewerpython -m venv .venv && source .venv/bin/activatepip install "mcp[cli]">=1.04.3 server.py 完整实现(200 行)
"""MCP Server: 代码评审助手功能:- Tool: review_code(评审一段 Python 代码)- Tool: check_security(检测常见安全问题)- Resource: review://rules(评审规则文档)- Prompt: review-pr(生成 PR 评审 prompt 模板)"""
import asyncioimport astimport refrom mcp.server import Serverfrom mcp.server.stdio import stdio_serverfrom mcp.types import ( Tool, TextContent, ImageContent, EmbeddedResource, Prompt, PromptMessage, PromptArgument, Resource,)
# ============ 1. 创建 MCP Server ============app = Server("code-reviewer")
# ============ 2. 列出可用工具 ============@app.list_tools()async def list_tools() -> list[Tool]: return [ Tool( name="review_code", description="对一段 Python 代码进行多维度评审,返回结构化问题列表", inputSchema={ "type": "object", "properties": { "code": {"type": "string", "description": "待评审的 Python 源码"}, "strictness": { "type": "string", "enum": ["loose", "normal", "strict"], "default": "normal", "description": "评审严格度" } }, "required": ["code"] } ), Tool( name="check_security", description="扫描代码中的常见安全问题(SQL 注入、硬编码密钥、eval、shell 注入等)", inputSchema={ "type": "object", "properties": { "code": {"type": "string"} }, "required": ["code"] } ), ]
# ============ 3. 工具实现 ============SECURITY_RULES = [ (r"\beval\s*\(", "使用了 eval(),存在任意代码执行风险"), (r"\bexec\s*\(", "使用了 exec(),存在任意代码执行风险"), (r"subprocess\.(?:call|run|Popen).*shell\s*=\s*True", "subprocess 启用了 shell=True,可能导致命令注入"), (r"os\.system\s*\(", "os.system() 容易受 shell 注入影响,建议用 subprocess.run 并禁用 shell"), (r"password\s*=\s*['\"][^'\"]+['\"]", "硬编码了 password 字段"), (r"api_key\s*=\s*['\"][^'\"]+['\"]", "硬编码了 api_key 字段"), (r"SELECT.*\+.*FROM", "疑似 SQL 拼接,请使用参数化查询"), (r"\.format\(.*\).*(?:SELECT|INSERT|DELETE|UPDATE)", "疑似通过 .format() 拼接 SQL"), (r"pickle\.loads?\s*\(", "pickle 反序列化存在 RCE 风险,请改用 json"),]
STYLE_RULES = [ (r"except\s*:\s*$", "裸 except 会吞掉所有异常,包括 KeyboardInterrupt"), (r"except\s+Exception\s*:\s*$", "过于宽泛的异常捕获"), (r"^\s*print\s*\(", "代码中残留 print 调试语句"), (r"TODO|FIXME|XXX", "存在未完成的 TODO/FIXME"), (r"def\s+\w+\([^)]*\)\s*->\s*$", "函数签名末尾缺返回类型注解"),]
def _review_python(code: str, strictness: str) -> dict: """执行评审逻辑""" issues = [] severities = {"loose": ["high"], "normal": ["high", "medium"], "strict": ["high", "medium", "low"]}
# 静态文本扫描 for pattern, msg in SECURITY_RULES: if re.search(pattern, code, re.IGNORECASE | re.MULTILINE): issues.append({ "type": "security", "severity": "high", "message": msg, "line": _find_line(code, pattern) })
for pattern, msg in STYLE_RULES: if strictness in ("normal", "strict") and re.search(pattern, code, re.MULTILINE): issues.append({ "type": "style", "severity": "medium", "message": msg, "line": _find_line(code, pattern) })
# AST 分析 try: tree = ast.parse(code) issues.extend(_ast_analysis(tree, strictness)) except SyntaxError as e: issues.append({ "type": "syntax", "severity": "high", "message": f"语法错误: {e.msg}", "line": e.lineno })
# 过滤严重等级 issues = [i for i in issues if i["severity"] in severities.get(strictness, ["high", "medium"])]
# 计算分数 high = sum(1 for i in issues if i["severity"] == "high") medium = sum(1 for i in issues if i["severity"] == "medium") low = sum(1 for i in issues if i["severity"] == "low") score = max(0, 100 - high * 20 - medium * 5 - low * 1)
return { "score": score, "summary": f"发现 {len(issues)} 个问题(高:{high} 中:{medium} 低:{low})", "issues": issues, "lines_of_code": len(code.splitlines()), }
def _ast_analysis(tree: ast.AST, strictness: str) -> list[dict]: """AST 层面的深度分析""" issues = [] for node in ast.walk(tree): # 函数过长 if isinstance(node, ast.FunctionDef): length = (node.end_lineno or 0) - node.lineno + 1 if length > 50: issues.append({ "type": "complexity", "severity": "medium", "message": f"函数 `{node.name}` 有 {length} 行,建议拆分", "line": node.lineno, }) # 圈复杂度估算(if/for/while/except 数) complexity = sum( 1 for n in ast.walk(node) if isinstance(n, (ast.If, ast.For, ast.While, ast.ExceptHandler, ast.BoolOp)) ) if complexity > 10: issues.append({ "type": "complexity", "severity": "high", "message": f"函数 `{node.name}` 圈复杂度过高(≈{complexity}),建议提取子函数", "line": node.lineno, })
# 全局可变状态 if isinstance(node, ast.Global): issues.append({ "type": "anti-pattern", "severity": "medium", "message": "使用了 global 语句,可能破坏封装", "line": node.lineno, }) return issues
def _find_line(code: str, pattern: str) -> int: """找到 pattern 第一次出现的行号""" m = re.search(pattern, code, re.IGNORECASE | re.MULTILINE) return m.start() // 80 + 1 if m else 0 # 粗略估算
# ============ 4. 工具分发 ============@app.call_tool()async def call_tool(name: str, arguments: dict) -> list[TextContent]: if name == "review_code": result = _review_python(arguments["code"], arguments.get("strictness", "normal")) return [TextContent(type="text", text=_format_review(result))]
elif name == "check_security": issues = [] for pattern, msg in SECURITY_RULES: if re.search(pattern, arguments["code"], re.IGNORECASE | re.MULTILINE): issues.append(f"⚠️ 第 { _find_line(arguments['code'], pattern) } 行: {msg}") text = "未发现安全问题 ✅" if not issues else "\n".join(issues) return [TextContent(type="text", text=text)]
raise ValueError(f"未知工具: {name}")
def _format_review(result: dict) -> str: out = [f"📊 代码评分: **{result['score']}/100**", result['summary'], ""] for issue in result['issues']: emoji = {"high": "🔴", "medium": "🟡", "low": "🟢"}[issue['severity']] out.append(f"{emoji} [{issue['type']}] 第 {issue['line']} 行: {issue['message']}") return "\n".join(out)
# ============ 5. Resources(应用读取的数据)============@app.list_resources()async def list_resources() -> list[Resource]: return [ Resource( uri="review://rules", name="评审规则文档", description="当前 MCP Server 使用的所有评审规则", mimeType="text/markdown" ) ]
@app.read_resource()async def read_resource(uri: str) -> str: if uri == "review://rules": rules_md = "# 评审规则\n\n## 安全规则\n" for pattern, msg in SECURITY_RULES: rules_md += f"- `{pattern}` → {msg}\n" rules_md += "\n## 风格规则\n" for pattern, msg in STYLE_RULES: rules_md += f"- `{pattern}` → {msg}\n" return rules_md raise ValueError(f"未知资源: {uri}")
# ============ 6. Prompts(预定义模板)============@app.list_prompts()async def list_prompts() -> list[Prompt]: return [ Prompt( name="review-pr", description="生成 PR 评审 prompt 模板", arguments=[ PromptArgument( name="diff", description="PR 的 diff 内容", required=True ) ] ) ]
@app.get_prompt()async def get_prompt(name: str, arguments: dict) -> list[PromptMessage]: if name == "review-pr": return [ PromptMessage( role="user", content=TextContent( type="text", text=f"请评审以下 PR diff,重点关注正确性、安全性、性能:\n\n```diff\n{arguments['diff']}\n```" ) ) ] raise ValueError(f"未知 prompt: {name}")
# ============ 7. 启动 Server ============async def main(): async with stdio_server() as (read_stream, write_stream): await app.run( read_stream, write_stream, app.create_initialization_options() )
if __name__ == "__main__": asyncio.run(main())4.4 接入 Claude Desktop
编辑 ~/Library/Application Support/Claude/claude_desktop_config.json(macOS)或 %APPDATA%\Claude\claude_desktop_config.json(Windows):
{ "mcpServers": { "code-reviewer": { "command": "/绝对路径/mcp-code-reviewer/.venv/bin/python", "args": ["-m", "mcp_code_reviewer.server"] } }}重启 Claude Desktop 后,你就能在对话中直接说”帮我 review 一下这段代码”,Claude 会自动调用我们的 review_code 工具。
4.5 用 MCP Inspector 调试
# 安装官方调试工具pip install "mcp[cli]"
# 启动 Inspector 调试你的 Servermcp dev src/mcp_code_reviewer/server.py打开 http://localhost:5173 就能可视化调用所有 Tools、读取 Resources、应用 Prompts。
五、用 Claude Agent SDK 消费 MCP Server
5.1 什么是 Claude Agent SDK?
Anthropic 在 2025 年发布的 claude-agent-sdk,把 Claude 的 tool use 能力封装成了一个完整的 Agent 运行时。它原生支持 MCP,意味着你可以直接用 Python SDK 调用任何 MCP Server。
pip install claude-agent-sdk5.2 完整可运行示例
"""Claude Agent SDK + MCP Server:让 Claude 调用我们的代码评审工具"""import anyiofrom claude_agent_sdk import query, ClaudeAgentOptions
async def main(): options = ClaudeAgentOptions( model="claude-sonnet-4-5", system_prompt="你是一个代码评审专家,使用 review_code 工具评审用户提交的代码。", mcp_servers={ "code-reviewer": { "command": "python", "args": ["-m", "mcp_code_reviewer.server"], } }, allowed_tools=["review_code", "check_security"], max_turns=5, )
code_to_review = """def get_user(user_id): password = "admin123" query = "SELECT * FROM users WHERE id = " + user_id result = eval(query) return result"""
async for message in query( prompt=f"请评审以下代码:\n```python\n{code_to_review}\n```", options=options, ): if hasattr(message, "content"): print(message.content)
anyio.run(main)运行后,Claude 会自动调用我们的 MCP Server 并返回结构化评审报告。
六、MCP 生态全景与选型建议
6.1 主流 MCP Server 一览(截至 2026 年)
| 类别 | 官方/社区 Server | 能力 |
|---|---|---|
| 文件系统 | @modelcontextprotocol/server-filesystem | 读/写/搜索本地文件 |
| Git | @modelcontextprotocol/server-git | 查看 commit、diff、blame |
| GitHub | @modelcontextprotocol/server-github | 读 issue、PR、code search |
| Postgres | @modelcontextprotocol/server-postgres | SQL 查询、schema 导出 |
| Puppeteer | @modelcontextprotocol/server-puppeteer | 浏览器自动化、截图 |
| Brave Search | @modelcontextprotocol/server-brave-search | 网络搜索 |
| Slack | @modelcontextprotocol/server-slack | 发消息、读频道 |
6.2 自建 MCP Server 的三个时机
| 时机 | 场景 | 推荐方案 |
|---|---|---|
| 个人工具 | 把自己的脚本暴露给 IDE | stdio MCP Server + Claude Desktop |
| 团队协作 | 团队内部的”知识库工具集” | Streamable HTTP MCP Server + 内部 IDE |
| 商业产品 | SaaS 平台开放给客户 Agent | Remote MCP Server + OAuth 鉴权 |
6.3 Function Calling 与 MCP 的关系
很多团队会纠结:到底该直接用 Function Calling,还是上 MCP?
经验法则:
- 单一模型 + 单一客户端 → Function Calling 直接调 SDK 最简单
- 多客户端复用 + 工具需要权限管理 → MCP Server 是更好的选择
- 企业内部 Agent 平台 → MCP 是事实标准,建议直接拥抱
Function Calling 和 MCP 不是替代关系:MCP Server 内部还是要用 SDK 的 Function Calling 能力(Tool Use);Function Calling 是协议层,MCP 是架构层。
七、性能与安全注意事项
7.1 性能优化
- stdio 进程池:每次调用 stdio MCP Server 都要启动一个新进程会有 ~100ms 开销,对短任务用进程池复用,对长任务用 HTTP+SSE
- 工具描述要”短而精”:每个 Tool 的 description 占几百 token,多了会爆 context window
- Streaming 优先:所有支持流式的 Client 都应该用 streaming,避免长任务阻塞
7.2 安全边界
| 风险 | 缓解措施 |
|---|---|
| 任意代码执行 | Tool description 明确权限范围,Client 端需要 user confirmation |
| 密钥泄露 | MCP Server 通过环境变量读密钥,不要硬编码 |
| SSRF | HTTP 类 Tool 限制允许域名 |
| Prompt Injection | Tool 返回值要 sanitize,不要让 Tool 输出被解释为新指令 |
八、总结与延伸阅读
核心要点
- Function Calling 是工具调用的”协议层”——OpenAI tools、Claude Tool Use、Gemini Function Calling 在字段命名上有差异但思想一致
- MCP 是工具调用的”架构层”——通过 JSON-RPC + Resources/Prompts/Tools/Sampling 四原语 + stdio/HTTP/WebSocket 传输,实现”一次开发、多端复用”
- 2026 年,MCP 已成为 Agent 生态事实标准——Cursor、Claude Desktop、Continue、Zed 全栈接入,OpenAI Agent SDK 也已支持
- Function Calling 与 MCP 不是替代关系——MCP Server 内部仍然依赖各模型的 Function Calling 能力
行动清单
- ✅ 跑通官方
mcp-server-git示例,理解 MCP 协议交互 - ✅ 用 Python SDK 写一个 stdio MCP Server,对接 Claude Desktop
- ✅ 在 Cursor 中配置 MCP Server,体验”一次开发、多端复用”
- ✅ 阅读 Claude Agent SDK 文档,了解生产级 MCP 部署
延伸阅读
| 资源 | 链接 |
|---|---|
| MCP 协议规范 | https://modelcontextprotocol.io |
| OpenAI Function Calling 文档 | https://platform.openai.com/docs/guides/function-calling |
| Claude Tool Use 指南 | https://docs.anthropic.com/en/docs/tool-use |
| Claude Agent SDK 文档 | https://docs.anthropic.com/en/api/agent-sdk |
| MCP Server 集合 | https://github.com/modelcontextprotocol/servers |
| Instructor(Python 结构化输出) | https://github.com/jxnl/instructor |
| 配套源码 | https://github.com/anthropics/mcp-python-sdk |
工具调用这件事正在从”模型 API 的一个参数”演化成”Agent 时代的网络协议”。理解 MCP,不仅是为了接一个 IDE,而是为了在下一代 AI 应用架构里有一席之地。
作者:wyb_001 | 博客:https://boke.hackerdream.xyz | 发布时间:2026-06-21
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!