3天斩获100万赞的秘诀:零基础掌握MCP(源码详解),让AI自动执行任务!

开门见山,先来看看我使用MCP的效果,根据我的要求(在我的工具上生成一个测试背包按钮的用例),自动生成节点并连接
output_1080_compressed

MCP最近在AI相关领域是一个大热点,特别是有部分mcp server网站的每日工具上传量,从10+暴增到1000+

现在越来越多的人投入到mcp协议的怀抱中,上面我的使用效果也证明了这项技术值得大家投身其中

MCP的原理非常简单,不需要编程基础都能理解。看完这篇文章,你就能透彻的明白MCP的原理,并且能够动手将MCP应用到你的工具中提高的效率,玩转MCP

MCP是什么

MCP是什么

MCP (Model Context Protocol,模型上下文协议)是由 AnthropicOpenAI的前成员创立,开发了Claude大模型的公司) 在 2024 年 11 月 25 日发布的文章Introducing the Model Context Protocol提出的一个协议。

MCP的本质 = 提示词辅助大模型进行输出的标准化 + 文本解析

对于一个任务而言,在任务发送给大模型之前,提示词会加入工具信息,并且要求大模型必须以固定格式输出
大模型对任务进行语义理解工具选择,以固定格式输出结果,客户端解析执行函数调用工具

MCP唯一的难点就是,大模型在任务中如何进行 “挑选” ,举个例子:

想象一下,我们在平时如何去发邮件
1.接受到一个任务(让小李下午来办公室一趟
2.我会想一下 「用什么」 + 「发给谁」+ 「什么内容」
3.然后用邮箱小李发送 “下午来办公室一趟”
3天斩获100万赞的技术一次搞定:MCP详解——让AI动手的秘密武器-2

转换到大模型的视角就存在几个问题
1.和人类不同,大模型怎么知道有什么工具
2.大模型只能输出文字,怎么动手执行

所以MCP就使用了提示词告诉了大模型有什么工具大模型如果要使用工具的话输出什么内容,并且执行完之后MCP中的客户端回传执行之后的数据

MCP是C/S架构「客户端/服务端」
我们平时说的大模型,指向的比较笼统,就比如我们说DeepSeek既是DeepSeek的网页端又是DeepSeek模型
但是在MCP的架构中,我们应该把DeepSeek的网页端看做客户端,模型本身属于大模型。
只不过一般我们都会用客户端写好和大模型交互的功能看起来就是一体的。

我们来具体看一个例子,结合Python SDK源码详解MCP的简单原理
还是上面说的你给小李发消息,让我来结合上图,看看MCP中提示词大模型的输出是什么

我是小白,不想看源码,可以下滑到具体例子↓

先来讲一下源码中的具体提示词
mcp_simple_chatbot样例中我们可以看到下面的代码
这就是在我们发送一段文本的时候,客户端额外添加到我们的文本中的内容

tools_description = "\n".join([tool.format_for_llm() for tool in all_tools])

system_message = (
	"You are a helpful assistant with access to these tools:\n\n"
	f"{tools_description}\n"
	"Choose the appropriate tool based on the user's question. "
	"If no tool is needed, reply directly.\n\n"
	"IMPORTANT: When you need to use a tool, you must ONLY respond with "
	"the exact JSON object format below, nothing else:\n"
	"{\n"
	'    "tool": "tool-name",\n'
	'    "arguments": {\n'
	'        "argument-name": "value"\n'
	"    }\n"
	"}\n\n"
	"After receiving a tool's response:\n"
	"1. Transform the raw data into a natural, conversational response\n"
	"2. Keep responses concise but informative\n"
	"3. Focus on the most relevant information\n"
	"4. Use appropriate context from the user's question\n"
	"5. Avoid simply repeating the raw data\n\n"
	"Please use only the tools that are explicitly defined above."
)

messages = [{"role": "system", "content": system_message}]

上面的提示词中也约束了模型的输出格式:

{
	"tool": "tool-name",
	 "arguments": {
	     "argument-name": "value"
	}
}

接着看一下format_for_llm这个函数

class Tool:
    """Represents a tool with its properties and formatting."""

    def __init__(
        self, name: str, description: str, input_schema: dict[str, Any]
    ) -> None:
        self.name: str = name
        self.description: str = description
        self.input_schema: dict[str, Any] = input_schema

    def format_for_llm(self) -> str:
        """Format tool information for LLM.

        Returns:
            A formatted string describing the tool.
        """
        args_desc = []
        if "properties" in self.input_schema:
            for param_name, param_info in self.input_schema["properties"].items():
                arg_desc = (
                    f"- {param_name}: {param_info.get('description', 'No description')}"
                )
                if param_name in self.input_schema.get("required", []):
                    arg_desc += " (required)"
                args_desc.append(arg_desc)

        return f"""
				Tool: {self.name}
				Description: {self.description}
				Arguments:
				{chr(10).join(args_desc)}
				"""

直接看最下面的return,这就是上面提示词中的tools_description

Tool: [工具名称]
Description: [工具描述]
Arguments:
- param1: 参数1的描述 (required)
- param2: 参数2的描述

那么我如果搭建了MCP,我让大模型给小李发消息会是什么样子的呢,提示词我们省略部分,只展示关键内容

也就是说,我们发给大模型的内容

1.你是一个工具调用者
2.工具列表:
{
	Tool: [邮箱]
	Description: [发邮件]
	Arguments:
		- 收件人: 收件人名 (required)
		- 内容: 发送的内容
}
3.如果选好了工具以以下结构输出
{
	 "tool": "tool-name",
	 "arguments": 
	{
		  "argument-name": "value"
	}
}
帮我给小李发送一条信息让他下午来我这里

大模型处理好的输出

{
     "tool": "email_send",
     "arguments": 
    {
          "收件人": "小李"
          "内容":"下午过来一趟"
    }
}

之后客户端解析json执行命令发送请求执行对应命令

tips:
我们知道大模型生成内容具有一定的随机性,根据我们对MCP原理的解析,我们在使用MCP的时候严格要求了输出结果的100%精准(按照某种要求输出)
所以,如果大模型能力比较弱,或者不能被提示词严格要求输出MCP协议就没办法实现
实际中,你会发现使用Claude的模型对MCP工具的调用能力会强一些,感觉应该是针对训练过了

还有之前ChatGPT提出过的 Function Calling,本质上的实现逻辑和上面的是差不多的,个人感觉就是没推广开的罢了(设计之初没有想着给大家一起用,就OpenAI自己内部用的),好在OpenAI现在也宣布支持MCP了,所以MCP是以后的主流协议了,还有最近的谷歌提出的A2A个人感觉也是MCP的原理。

MCP怎么用

MCP怎么用

MCP的使用就更简单一些,这里以CursorCherry Studio为例子
教你如何添加一个MCP Server
MCP Server 有两种方式一种是sse 提供一个api就可以用了(本质上是别人提供的服务器api,要注意安全问题),另一种stdio 是通过npx本地部署 server(推荐)

1.先安装nodejs

先来看看Cursor怎么添加

首先打开一个MCP Server工具网站,例如https://mcp.so/

根据你的需要选择一个 MCP的工具,这里我选择Sequential Thinking
打开之后如果右边有这个按钮就点进去
如果没有就点开Content去看他有没有提供json安装的命令
还没有就点进github仓库看看

这里就可以选择多种安装方式了
sse:别人部署好的提供你api
Streamable HTTP:也是提供api,只不过流式输出,是sse的替代版本
Stdio:本地部署server,你自己访问,这个一般是从这个网站提供的地方下载
Original: 本地部署server,你自己访问,就是这个工具作者自己提供的下载源,从npx上下载

在Cursor中打开「设置」,找到mcp,打开json配置

把复制的json内容粘贴上去
tips:win的系统下使用json来配置MCP 需要使用cmd 去运行npx,在其他MCP Server网站里面提供的json可能没有cmd,如果你是win系统需要自己加。

保存,看到这里是绿色的就行了

使用的时候AI会自动判断使用哪个工具,但是如果没有使用的话也可以强行要求

接下来是Cherry Studio 这个做了win系统的兼容就不用加cmd了,估计是自己帮你加了

打开「设置」、「MCP服务器」注意右上角的这个勾,如果不是勾请点击它安装必要组件

点击「添加服务器」、「编辑MCP服务器」

把json拷贝进入,点击「确认」

「确定」然后运行,查看对应服务的状态就好了

开发MCP

怎么开发MCP

这里以python SDK为例子

掌握几个结构就行了 「FastMCP类」「装饰器」
装饰器
有三类,对应MCP协议中的 提示词工具资源三个概念
tool:能让服务器把可执行能力开放给客户端
resource:它让服务器可以把数据内容开放给客户端读取,作为LLM交互的上下文素材。
prompt:让服务端能定义可复用的提示模板和工作流,客户端可以轻松推送给用户和 LLMs。

所有这些装饰器都支持可选的name和description参数来定义工具/资源/提示的名称和描述
如果不提供这些参数,系统会尝试从函数名和函数文档字符串中提取信息

# mcp实例
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("天气服务")

#tool装饰器
@mcp.tool()
def 你要提供的方法函数:
	你的执行逻辑

#resource
@mcp.resource()
def 你要提供的数据函数:
	你的数据
	
@mcp.prompt()
def 你要提供的提示词函数:
	你的提示词

随便写一个天气的MCP Server

import asyncio
import uvicorn
import datetime
import sys
from typing import Dict, Any, Optional

  

from mcp.server.fastmcp import FastMCP
from mcp.server.stdio import stdio_server

  

# 创建MCP服务器实例
mcp = FastMCP("天气服务")

  

# 模拟天气数据库(实际应用中可以替换为API调用)
WEATHER_DATA = {

    "北京": {"温度": "15°C", "天气": "晴", "湿度": "45%", "风力": "3级"},

    "上海": {"温度": "18°C", "天气": "多云", "湿度": "65%", "风力": "2级"},

    "广州": {"温度": "26°C", "天气": "阵雨", "湿度": "80%", "风力": "2级"},

    "深圳": {"温度": "25°C", "天气": "多云", "湿度": "75%", "风力": "3级"},

    "杭州": {"温度": "17°C", "天气": "晴", "湿度": "55%", "风力": "2级"}

}

@mcp.tool()
def get_weather(city: str) -> Dict[str, Any]:

    """
    获取指定城市的今日天气信息
    参数:
    city: 需要查询天气的城市名称
    返回:
    包含温度、天气状况、湿度和风力的字典
    """

    if city in WEATHER_DATA:

        result = WEATHER_DATA[city].copy()

        result["日期"] = datetime.datetime.now().strftime("%Y-%m-%d")

        result["查询时间"] = datetime.datetime.now().strftime("%H:%M:%S")

        return result

    else:

        return {"错误": f"没有找到城市 {city} 的天气数据"}

  
  

@mcp.tool()
def list_cities() -> list:

    """
    列出所有可查询天气的城市
    返回:
    城市名称列表
    """
    return list(WEATHER_DATA.keys())

  
  

@mcp.resource("weather://{city}")
def weather_resource(city: str) -> str:

    """
    以资源形式提供天气数据
    参数:
    city: 城市名称
    返回:
    格式化的天气信息字符串
    """

    if city in WEATHER_DATA:
        weather = WEATHER_DATA[city]
        return f"{city}天气: {weather['天气']}, 温度: {weather['温度']}, 湿度: {weather['湿度']}, 风力: {weather['风力']}"
    return f"没有找到城市 {city} 的天气数据"

  
  

@mcp.prompt()

def weather_query(city: Optional[str] = None) -> str:

    """
    创建天气查询的提示模板
    参数:
    city: 可选的城市名称,如果不提供则请求模型查询一个城市
    返回:
    格式化的提示字符串
    """

    if city:
        return f"请帮我查询{city}的天气情况,并解释一下天气状况。"
    else:
        return "请帮我查询一个中国城市的天气情况,你可以使用list_cities工具获取可查询的城市列表。"

  
  

# 提供SSE和stdio两种运行方式

async def run_stdio():
    """使用stdio方式运行服务器"""
    async with stdio_server() as (read_stream, write_stream):
        await mcp.run_streams(read_stream, write_stream)

  
  

if __name__ == "__main__":
    if len(sys.argv) > 1 and sys.argv[1] == "stdio":
        # 以stdio模式运行
        asyncio.run(run_stdio())
    else:
        #以SSE模式运行(默认)
        port = 8752
        app = mcp.sse_app()
        uvicorn.run(app, port=port)

推荐内容

MCP Server聚合网站https://mastra.ai/mcp-registry-registry
后续应该会弄一个ai+动漫更新+每日资讯的mcp

最后,想要各位一个赞,激励我出更多优秀文章,谢谢! :sparkling_heart:

不小心发到文档共建了,佬们留言的时候注意不要点到编辑了,会把内容修改了 :joy:

198 Likes

图全裂了

我修改一下

现在是不是好了

大佬很强

先收藏,慢慢看

感谢分享

这地方是不是图放错了

好了,可以了

很详细的介绍

cy mark

感谢提醒,已修改

感谢分享

太强了,大佬!

1 Like

感谢佬友教程

感谢佬友

做得很详细用心,感谢

非常不错,感谢大佬分享

感谢分享,挺清晰的

感谢大佬分享