MCP协议在2025至2026年突然火了起来,打开技术社区到处都是它的名字。介绍文章很多,但大多数止步于"它是什么"的层面——讲讲JSON-RPC、列几个官方示例就算交差。至于它到底解决了什么问题、为什么现有方案行不通、实际落地怎么设计架构,这些核心问题反而被一笔带过。

本文不做科普复读,做深度拆解。我会从AI Agent的工具调用问题出发,推导出MCP协议诞生的必然性,再深入到架构原理、核心组件的职责边界、完整的代码实现,最后给出真实落地场景和我的判断。

读完这篇文章,你应该能回答:MCP解决的不是"怎么让AI调用工具",而是"怎么让AI调用工具这件事变得可复用、可组合、可信任"。

在这里插入图片描述


一、AI Agent的工具调用困境

在讨论MCP之前,必须先把问题讲清楚。否则你只是在学一个新工具,而不是理解它存在的意义。

传统方案一:直接API调用

最早的AI Agent实践,是把API key交给大模型,大模型自己拼接HTTP请求去调用外部服务。比如让GPT调用GitHub API查PR状态,模型会根据prompt生成这样的请求:

GET https://api.github.com/repos/{owner}/{repo}/pulls/{number}
Authorization: Bearer {token}

这个方案有三个根本性问题:

第一,安全灾难。把API key直接交给模型意味着模型能访问这个key所拥有的全部权限,没有任何权限边界。你让模型查PR,它也可以顺手查repo的所有issue、删除branch、给任意用户发邀请。这不是假设风险,这是真实发生过多起的事故。

第二,能力边界模糊。模型需要"知道"API的URL路径、请求参数格式、鉴权方式、返回结构。这些信息全部塞进prompt里会导致context爆炸,而且模型对API语义的理解并不稳定——同样的功能,换个参数名或返回结构,模型可能就失效了。

第三,上下文丢失。每次API调用是独立的,模型无法维护与外部系统的会话状态。比如先登录获取token,再用token查数据,再把数据发邮件——这一串有状态的操作,传统API调用方案没有优雅的抽象方式。

传统方案二:Function Calling / Tool Use

OpenAI在GPT-4时代引入了Function Calling机制,后续几乎所有大模型厂商都跟进实现了类似功能。这比直接API调用好一些:模型不再直接拼HTTP请求,而是生成结构化的工具调用请求(通常是JSON),由应用程序负责实际执行,然后把结果传回给模型。

这个方案解决了安全问题(API key不用给模型)和上下文维护问题(应用层可以管理状态),但带来了新的问题:每个AI应用和每个工具之间是紧耦合的

具体来说:

如果你的团队有三个AI应用——一个是代码审查Agent,一个是产品文档生成器,还有一个是自动化测试平台。它们都需要调用GitHub API。按照Function Calling的范式,每个应用都要各自实现一遍GitHub的工具定义:描述工具用途、定义参数schema、处理返回结果。这不是代码复用,这是重复造轮子。

更大的问题是,当你的工具需要跨应用共享时,你会发现没有标准。钉钉的AI助手能用的工具,微信的AI助手用不了;AWS Bedrock Agent的工具链,Azure AI Studio不认。每个平台都在构建自己的工具生态,但这些生态之间是隔离的孤岛。

这就是MCP协议要解决的核心问题:不是"怎么让AI调用工具",而是"怎么建立一套标准,让工具提供方和工具消费方解耦,让一个工具可以被多个AI应用复用,让工具生态从封闭走向开放"。


二、MCP协议的原理

MCP全称Model Context Protocol,由Anthropic在2024年11月开源发布。它的设计目标用一句话概括:定义一个标准协议,让AI模型能够以统一的方式发现、调用、与外部数据源和工具交互

协议架构的核心思想

MCP采用了客户端-服务器架构,这一点类似数据库连接池或者gRPC的设计思路。但它的创新在于把"工具"抽象为一种可被发现、可被描述、可被动态发现的服务。

在MCP的世界观里,外部资源(数据库、设计稿、API)都是"Server",AI应用是"Host",而连接两者的中间层是"Client"。这种三角关系是整个协议的核心,理解了这个三角关系,就理解了MCP。

┌─────────────────────────────────────────────────────────────┐
│                        AI Host (Host)                        │
│   ┌──────────┐   ┌──────────┐   ┌──────────┐               │
│   │ Client A │   │ Client B │   │ Client C │  ← 各自维护     │
│   │ (连接DB) │   │(连设计稿)│   │(连搜索API)│    一个状态     │
│   └────┬─────┘   └────┬─────┘   └────┬─────┘               │
│        │              │              │                      │
└────────┼──────────────┼──────────────┼──────────────────────┘
         │              │              │
    ┌────▼────┐    ┌────▼────┐    ┌────▼────┐
    │Server:  │    │Server:  │    │Server:  │
    │Database │    │Figma    │    │Search   │
    │         │    │         │    │Engine   │
    └─────────┘    └─────────┘    └─────────┘

这张图描述了一个关键事实:一个Host可以同时连接多个Server,一个Server也可以被多个Host复用。这不是传统API调用的点对点模式,而是星型拓扑结构,协议本身是hub。

通信机制:JSON-RPC 2.0 over stdio or HTTP/SSE

MCP底层协议采用JSON-RPC 2.0,这是个经过充分验证的远程过程调用标准。选择JSON-RPC而不是GraphQL或gRPC,核心考量是简洁性和嵌入性——JSON-RPC的消息格式足够简单,可以走stdio(标准输入输出流),这意味着MCP Server可以是一个本地进程,通过管道与Host通信,不需要启动网络服务。这对安全和本地工具场景非常重要。

除了stdio,MCP还支持HTTP+SSE(Server-Sent Events)传输层。这使得MCP Server可以部署为远程服务,适合企业级场景。

协议的消息类型分为三类:

请求(Request):从Client发往Server,带method名称和params参数,等待response。比如tools/list请求让Server告诉Client自己提供了哪些工具。

响应(Response):Server返回给Client,携带result或error。比如调用tools/call后,Server返回工具执行结果。

通知(Notification):单向消息,不需要响应。比如Server推送日志更新或者进度通知。

采样(Sampling):这是MCP的一个独特设计——Server也可以反过来调用AI的能力。比如一个代码搜索Server在找不到精确匹配时,可以"采样"AI的语义理解能力来扩展搜索结果。这是双向通信的体现,打破了传统请求-响应模型的单向性。


三、核心组件拆解:Host、Client、Server

Host:AI应用层

Host是MCP架构中最"高"的一层,通常是AI应用本身——Claude Desktop、Cursor、Continue.dev,或者你自己开发的AI Agent。

Host的职责是什么?三个核心职责:

第一,管理用户会话。Host知道用户在做什么,知道当前任务的上下文,知道什么时候需要调用外部工具。

第二,协调多个Client。一个Host可以同时连接多个MCP Client,每个Client连接到不同的Server。Host负责决定在什么时机调用哪个工具,把多个工具的结果汇聚后一起传给AI模型处理。

第三,控制权限边界。Host决定哪些Server被允许连接、哪些工具可以被调用、返回的结果是否包含敏感信息。这是安全策略的执行点。

Client:协议适配层

Client是Host与Server之间的中间层。每个Client实例与一个Server保持一对一的长期连接,维护该连接的状态——包括已发现的工具列表、活跃的会话上下文、认证令牌等。

Client不包含业务逻辑。它只做两件事:把Host的指令翻译成MCP协议消息发往Server,把Server的响应翻译成结构化数据返回给Host。Client的存在,使得Host不需要关心底层Server的通信细节——无论Server是通过stdio还是HTTP连接,对Host来说接口是一致的。

从实现角度,Client还需要处理:

  • 连接生命周期管理(重连、心跳、断开)
  • 协议版本协商
  • 错误传播与重试

Server:工具提供方

Server是MCP架构中最灵活的一层。任何提供数据或能力的外部系统,都可以包装为一个MCP Server。

Server的核心职责是暴露资源、定义工具、处理调用。具体来说:

Server维护一个manifest,声明自己提供哪些资源(比如一个数据库Server会暴露"用户表"、“订单表"等资源)、哪些工具(比如"查询用户”、“更新订单”)、哪些prompt模板(如果Server支持预定义的提示词)。

当Client调用tools/call时,Server负责执行实际逻辑。执行可以是在本地进程里调一个Python函数,也可以是调一个远程HTTP API,甚至可以是执行一段shell命令。Server的内部实现对协议是完全透明的。

一个Server可以动态注册/注销工具。这意味着Server可以根据运行时状态改变自己提供的工具集。比如一个文件系统Server,平时只暴露读操作,但当用户切换到某个特定目录后,Server可以动态更新自己的工具列表,把该目录下的特定操作暴露出来。这比传统的固定API schema灵活得多。


四、代码实战:实现一个MCP Server

下面实现一个完整的MCP Server,用Python实现,支持通过工具查询本地SQLite数据库。这是一个真实的、可运行的例子。

"""
MCP Server 实现:SQLite 数据库查询工具
功能:通过自然语言描述查询数据库,Server 将 AI 的结构化查询
      请求转换为 SQL 并执行。
"""

import sqlite3
import json
from typing import Any
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent
from pydantic import AnyUrl

# 初始化 Server,名称要与客户端引用一致
APP = Server("sqlite-query-server")


def init_db(db_path: str) -> None:
    """初始化示例数据库"""
    conn = sqlite3.connect(db_path)
    cursor = conn.cursor()
    cursor.execute("""
        CREATE TABLE IF NOT EXISTS products (
            id INTEGER PRIMARY KEY,
            name TEXT NOT NULL,
            category TEXT,
            price REAL,
            stock INTEGER DEFAULT 0
        )
    """)
    # 插入示例数据
    cursor.execute("SELECT COUNT(*) FROM products")
    if cursor.fetchone()[0] == 0:
        sample_data = [
            ("MacBook Pro 14", "Electronics", 14999.0, 50),
            ("AirPods Pro", "Electronics", 1899.0, 200),
            ("机械键盘 K100", "Electronics", 599.0, 80),
            ("人体工学椅", "Furniture", 1299.0, 30),
            ("台灯 D3", "Furniture", 299.0, 120),
        ]
        cursor.executemany(
            "INSERT INTO products (name, category, price, stock) VALUES (?, ?, ?, ?)",
            sample_data
        )
    conn.commit()
    conn.close()


@APP.list_tools()
async def list_tools() -> list[Tool]:
    """声明 Server 提供的工具"""
    return [
        Tool(
            name="query_products",
            description="查询产品表,支持按类别筛选、按价格排序、限制返回数量",
            inputSchema={
                "type": "object",
                "properties": {
                    "category": {
                        "type": "string",
                        "description": "产品类别(如 Electronics、Furniture),不传则查全部"
                    },
                    "min_price": {
                        "type": "number",
                        "description": "最低价格筛选"
                    },
                    "max_price": {
                        "type": "number",
                        "description": "最高价格筛选"
                    },
                    "sort_by": {
                        "type": "string",
                        "enum": ["price", "stock", "name"],
                        "description": "排序字段,默认按价格"
                    },
                    "order": {
                        "type": "string",
                        "enum": ["asc", "desc"],
                        "description": "升序或降序"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "最多返回多少条,默认10"
                    }
                }
            }
        ),
        Tool(
            name="get_product_stock",
            description="查询指定产品的库存数量",
            inputSchema={
                "type": "object",
                "required": ["product_name"],
                "properties": {
                    "product_name": {
                        "type": "string",
                        "description": "产品名称(支持模糊匹配)"
                    }
                }
            }
        )
    ]


@APP.call_tool()
async def call_tool(name: str, arguments: Any) -> TextContent:
    """处理工具调用请求"""
    db_path = "example.db"
    init_db(db_path)
    
    try:
        if name == "query_products":
            return await _handle_query_products(arguments, db_path)
        elif name == "get_product_stock":
            return await _handle_get_stock(arguments, db_path)
        else:
            raise ValueError(f"Unknown tool: {name}")
    except sqlite3.Error as e:
        return TextContent(type="text", text=f"数据库错误: {str(e)}")


async def _handle_query_products(args: dict, db_path: str) -> TextContent:
    """处理产品查询"""
    conn = sqlite3.connect(db_path)
    conn.row_factory = sqlite3.Row
    cursor = conn.cursor()
    
    # 构建查询
    conditions = []
    params = []
    
    if args.get("category"):
        conditions.append("category = ?")
        params.append(args["category"])
    
    if args.get("min_price") is not None:
        conditions.append("price >= ?")
        params.append(args["min_price"])
    
    if args.get("max_price") is not None:
        conditions.append("price <= ?")
        params.append(args["max_price"])
    
    where_clause = " AND ".join(conditions) if conditions else "1=1"
    
    sort_by = args.get("sort_by", "price")
    order = args.get("order", "asc")
    limit = args.get("limit", 10)
    
    query = f"""
        SELECT id, name, category, price, stock 
        FROM products 
        WHERE {where_clause}
        ORDER BY {sort_by} {order.upper()}
        LIMIT ?
    """
    params.append(limit)
    
    cursor.execute(query, params)
    rows = cursor.fetchall()
    conn.close()
    
    if not rows:
        return TextContent(type="text", text="没有找到匹配的产品")
    
    result_text = "查询结果:\n"
    result_text += f"{'ID':<4} {'名称':<20} {'类别':<12} {'价格':>10} {'库存':>6}\n"
    result_text += "-" * 56 + "\n"
    
    for row in rows:
        result_text += (
            f"{row['id']:<4} {row['name']:<20} {row['category']:<12} "
            f"¥{row['price']:>8.2f} {row['stock']:>6}\n"
        )
    
    result_text += f"\n共 {len(rows)} 条记录"
    return TextContent(type="text", text=result_text)


async def _handle_get_stock(args: dict, db_path: str) -> TextContent:
    """处理库存查询"""
    conn = sqlite3.connect(db_path)
    conn.row_factory = sqlite3.Row
    cursor = conn.cursor()
    
    cursor.execute(
        "SELECT name, stock FROM products WHERE name LIKE ?",
        (f"%{args['product_name']}%",)
    )
    rows = cursor.fetchall()
    conn.close()
    
    if not rows:
        return TextContent(type="text", text=f"未找到包含 '{args['product_name']}' 的产品")
    
    result = []
    for row in rows:
        stock_status = "充足" if row["stock"] > 50 else ("紧张" if row["stock"] > 10 else "缺货")
        result.append(f"• {row['name']}: 库存 {row['stock']} 件 ({stock_status})")
    
    return TextContent(type="text", text="\n".join(result))


async def main():
    """Server 入口,启动 stdio 传输层"""
    async with stdio_server() as (read_stream, write_stream):
        await APP.run(
            read_stream,
            write_stream,
            APP.create_initialization_options()
        )


if __name__ == "__main__":
    import asyncio
    asyncio.run(main())

这段代码完整展示了一个MCP Server的核心结构:

工具声明list_tools()中定义。返回值是Tool对象,包含工具名称(Client调用的标识)、自然语言描述(供AI理解工具用途)、以及JSON Schema格式的参数定义。这个schema非常重要——它是大模型理解"什么时候该用这个工具、参数怎么填"的关键依据。

工具执行call_tool()中分发。协议层只负责传递调用请求,具体逻辑由子函数_handle_*实现。这里用SQLite演示,但换成HTTP API调用、文件系统操作、或者调用LLM本身都可以——Server对内部实现完全自主。

stdio传输main()中配置。Server通过标准输入输出与Host通信,不需要监听端口。这让它可以安全地运行在本地环境中。

安装依赖:

pip install "mcp[dev]" pydantic

五、代码实战:Client如何调用MCP Server

Server写好了,Client怎么用?下面是基于官方mcp Python SDK的客户端实现,演示如何连接到上面的SQLite Server、调用工具、获取结果:

"""
MCP Client 实现:连接到本地 SQLite Server 并调用工具
"""

import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client


async def main():
    # 定义 Server 启动参数
    # 注意:command 是你启动 Server 的方式,args 是传给 Server 的参数
    server_params = StdioServerParameters(
        command="python",                    # 用 python 解释器运行
        args=["sqlite_mcp_server.py"],       # Server 脚本路径
        env=None,                            # 可选:传递环境变量
    )
    
    async with stdio_client(server_params) as (read, write):
        async with ClientSession(read, write) as session:
            # 1. 初始化连接,交换协议版本等元信息
            await session.initialize()
            print("✓ 已连接到 MCP Server\n")
            
            # 2. 发现 Server 提供的工具
            tools = await session.list_tools()
            print(f"发现 {len(tools.tools)} 个工具:")
            for tool in tools.tools:
                print(f"  - {tool.name}: {tool.description}")
            print()
            
            # 3. 调用 query_products 工具
            print("调用 query_products(查询价格低于2000的电子产品):")
            result = await session.call_tool(
                "query_products",
                arguments={
                    "category": "Electronics",
                    "max_price": 2000,
                    "sort_by": "price",
                    "order": "asc",
                    "limit": 5
                }
            )
            # result.content 是 ToolResult.content 列表
            for item in result.content:
                if hasattr(item, 'text'):
                    print(item.text)
            
            print()
            
            # 4. 调用 get_product_stock 工具
            print("调用 get_product_stock(查询键盘库存):")
            result = session.call_tool(
                "get_product_stock",
                arguments={"product_name": "键盘"}
            )
            result = await result
            for item in result.content:
                if hasattr(item, 'text'):
                    print(item.text)


if __name__ == "__main__":
    asyncio.run(main())

Client端的代码非常简洁。核心流程就三步:initialize()建立握手、list_tools()获取可用工具清单、call_tool()执行具体调用。

值得注意的是,Client不需要关心Server是stdio连接还是HTTP连接。StdioServerParametersSseServerParameters(HTTP场景)共用同一个ClientSession接口。这正是MCP协议抽象层设计的精妙之处——传输层和协议层完全解耦

如果你用Claude Desktop,连接MCP Server只需要在配置文件中声明Server路径,根本不需要写任何Client代码:

// ~/.claude.json 或 Desktop 配置
{
  "mcpServers": {
    "sqlite-tools": {
      "command": "python",
      "args": ["/path/to/sqlite_mcp_server.py"]
    }
  }
}

Claude Desktop会自动启动Server、维护连接、在对话中根据上下文决定何时调用工具。对用户来说,工具是"透明"的——AI直接告诉你结果,而不暴露工具调用的技术细节。


六、落地场景

场景一:把数据库接进AI Agent

架构描述

用户聊天界面(Claude/Custom Agent)
    │
    ├── MCP Host(应用层)
    │       │
    │       ├── Client A → SQLite MCP Server → 业务数据库
    │       ├── Client B → Figma MCP Server → 设计稿数据库
    │       └── Client C → REST MCP Server → 第三方API
    │
    └── AI Model(接收结构化结果,生成自然语言回复)

在这个架构里,AI Agent的每个外部依赖都是一个独立的MCP Server。Host通过多个Client并发连接它们。当用户问"Q2收入最高的产品线是哪个"时,Host识别出这是一个数据库查询任务,通过Client A发送给SQLite Server,执行聚合查询,把结果喂给模型,模型生成自然语言回答。

关键价值:多个AI应用可以复用同一套数据库Server。不需要在每个Agent里重复写SQL连接逻辑,只需要配置一次Server。

场景二:Figma设计稿接入AI审查流程

场景描述:设计师上传Figma文件,AI自动审查标注规范、色彩一致性、字体使用等问题。

传统方案需要写Figma API调用代码、处理OAuth认证、解析Figma的文件格式。换成MCP,AI可以直接通过Figma MCP Server与Figma交互。Server暴露的工具包括get_file_nodes(获取设计节点)、get_comments(获取评论)、list_styles(获取样式库)。

开发者不需要写Figma API代码,只需要:

  1. 运行Figma MCP Server
  2. 配置好OAuth token
  3. 让AI直接调用list_styles查看色彩规范,再调用get_file_nodes对比实际使用情况

整个流程的代码量从几百行降到配置声明。

场景三:多工具链编排

场景描述:一个AI Agent需要完成"查邮件→提取任务→创建Jira ticket→发Slack通知"的全流程。

用户: "帮我把邮箱里关于项目X的需求提取出来,创建Jira工单并通知团队"

Host处理流程:
  1. Client A → Email MCP Server → 读取邮件列表,提取相关内容
  2. AI分析邮件内容,提取结构化任务信息
  3. Client B → Jira MCP Server → 根据提取的信息创建工单
  4. Client C → Slack MCP Server → 发送工单链接到指定频道
  5. AI汇总结果,返回给用户

每个步骤由不同的Server负责,Host负责编排调用顺序和传递上下文。这比写一个包含邮件SDK、Jira SDK、Slack SDK的 monolith 应用优雅得多——每个Server职责单一、可独立测试、可按需替换。


七、当前局限性

MCP很好,但它不是银弹。坦诚地讲清楚它的局限性,是技术判断的基本素养。

协议成熟度

MCP正式发布至今不足两年,协议本身还在活跃迭代中。2025年中的某个版本对工具schema格式做了breaking change,导致早期实现的Server和Client出现了兼容性问题。在协议没有达到1.0稳定版之前,每次升级都可能需要跟着改动。这对企业级长期维护是一个现实挑战。

工具生态碎片化

虽然MCP已经吸引了大量工具开发者,但"有没有人做了我要用的工具"仍然是首要问题。目前质量较高的MCP Server集中在GitHub、Figma、Slack等海外主流SaaS,对国内工具(钉钉、企业微信、飞书自建应用)的支持要么缺失,要么是社区志愿者维护的第三方实现,质量和维护及时性参差不齐。

安全问题依然存在

MCP解决了"API key不给模型"的问题,但它引入了新的安全考量。当MCP Server以本地进程运行并通过stdio通信时,模型实际上获得了执行任意代码的潜在能力——只要Server实现者愿意,他可以在call_tool里执行任何操作。

Anthropic意识到了这个问题,提出了采样机制的安全边界设计,但完整的权限隔离和审计方案仍在讨论中。在企业场景里,把MCP Server的权限控制交给每个Server自己实现是不够的,需要Host层有强制性的权限策略——比如声明式地限定"这个Server只能读、不能写"。

Server实现的工程质量

由于MCP Server的开发门槛很低(只要实现几个协议方法就行),社区涌现了大量质量差异极大的Server实现。有的正确处理了错误和超时,有的直接panic崩溃;有的工具描述写得清晰准确,有的只是随便填了一个字符串。

AI模型对工具的理解完全依赖工具的描述质量。如果一个Server的工具描述写得很差,模型根本无法正确使用它。这不是一个协议问题,而是一个生态系统成熟度问题——需要时间和社区积累。

调试工具缺失

在开发阶段,当你的AI调用了一个MCP工具但得到意外结果时,调试体验还很原始。你需要在Server端加日志、在Client端抓通信内容、靠打印语句排查问题。官方目前没有提供类似于Postman的MCP协议调试工具,Charles/mitmproxy也抓不到stdio通道的通信。这对开发者体验是一个明显的短板。


八、作者观点

技术领域有一种常见的叙事套路:每当一个新协议/框架出现,就有人宣称它会"重新定义"一切。MCP有潜力,但它不是这种级别的革命——它更像是HTTP在Web发展史上的角色,一个让生态从混乱走向秩序的协议层抽象

我的核心判断:

MCP的价值不在于它比Function Calling更先进,而在于它解决了一个Function Calling根本不想解决的问题——工具的发现机制和复用网络。 Function Calling解决的是"模型怎么调用工具",MCP解决的是"工具怎么被整个生态发现和使用"。这两个问题是不同层次的抽象。

当工具生态从十几个扩展到数百个时,复用和发现的问题就会成为瓶颈。想象一下,你的团队有20个AI Agent,每个Agent需要调用8种不同的外部服务。按照传统方案,这需要160个点对点的集成实现。但如果每个外部服务都提供MCP Server,你只需要20个Client配置加上8个Server实现。这就是协议标准化的规模效应。

关于MCP会不会被取代:短期内不会。它背后的设计思想——以Server为中心的服务抽象、工具的可发现性、协议层与传输层解耦——是经过验证的架构模式,不是临时方案。只要AI Agent需要与外部世界交互,这套范式就有生命力。

但MCP不会一统天下。在高度安全敏感的金融、医疗领域,中心化的工具发现机制可能不符合合规要求。在低延迟的边缘计算场景,HTTP+JSON-RPC的开销可能被认为不必要。在这些场景下,专有协议或直接API集成仍然是合理选择。

最后给实践者的建议:不要为了用MCP而用MCP。如果你的AI应用只需要调用两三个固定API,直接集成是最简单可靠的方案。当你的工具数量超过五个、或者需要在多个AI应用间复用工具时,MCP的架构优势就开始体现。从小场景开始验证,而不是一开始就把所有服务都MCP化。

技术选型从来不是选最好的,而是选最合适的。理解MCP解决的是什么问题,才能判断它适不适合你的问题。


本文代码基于 mcp Python SDK 官方接口编写,测试环境为 Python 3.11+。MCP协议仍在活跃发展中,部分接口细节可能随版本更新而变化,建议以官方文档为准。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐