MCP服务器到底是什么?从原理到实战一文讲透

MCP本质是AI工具标准协议,真正难点在远程部署时的身份认证与权限控制。
MCP(模型上下文协议)的核心其实极为简单:它是一套标准协议,让AI模型能以统一方式获取并调用外部工具函数,类似AI工具界的USB-C。模型本身从不直接执行工具,只输出调用意图,由宿主程序负责实际执行。MCP服务器有本地(stdio)和远程(HTTP)两种模式,个人开发用本地足矣,生产环境必须走远程。然而远程部署立刻引入访问控制难题——安全审计显示约四分之一的公开MCP服务器毫无认证,大量服务器依赖危险的静态API密钥。MCP官方推荐OAuth 2.1+PKCE方案,通过scope实现精细权限控制,并借助身份服务(如Descope)免去自建授权服务器的复杂工作。开发者使用fastmcp框架,只需用装饰器定义工具函数、配置授权提供者,即可快速搭建具备完整认证体系的多用户MCP服务器。
MCP(Model Context Protocol,模型上下文协议)几乎成了当下AI圈最热的术语之一。Claude有它、Cursor有它、ChatGPT也在用它。但正如一位海外技术博主所言,大多数人把它讲得比实际复杂得多。剥开层层包装后,MCP服务器的本质其实非常简单:它就是一个程序,向AI模型提供一份它被允许调用的函数清单。 仅此而已。
本文基于该博主的硬核拆解,从底层原理讲到Python实战,再到几乎所有教程都会跳过的关键环节——如何把服务器真正上线,并配置合规的身份认证与授权。
语言模型为什么需要工具
单独的语言模型其实什么都做不了。它不能读取你的文件,不能查看你的日历,甚至无法查询数据库。它唯一能做的,就是接收文本、输出文本。
如果你想让模型真正“做事”,就必须给它接入工具。而所谓工具,本质上就是一个函数——有名字、有描述、有输入参数和输出。模型读取这份工具清单后,会判断“我需要调用工具X”。
这里有个关键点常被误解:模型从不直接调用工具。 当模型想调用某个工具时,它只是输出一段文本,说明它想调用哪个工具;随后由你的代码执行该工具,再把结果作为文本返回给模型处理。整个过程中,模型始终只在和文本打交道。
MCP解决了什么问题:AI工具界的USB-C
在MCP出现之前存在一个明显痛点:每个应用都得自己搭建这套“工具管道”,而且针对每个模型、每个工具都要重写一遍。比如你为Claude做了一个GitHub集成,它在Cursor里用不了,在ChatGPT里也用不了。随着Agent越来越多,大家都在重复造轮子。
MCP的诞生就是为了终结这种混乱——它是一套标准协议。你只需把工具写一次,做成一个MCP服务器,任何“会说MCP”的应用都能直接使用这些工具,无论是Claude、Cursor、VS Code还是ChatGPT。
博主用了一个恰当的比喻:MCP就像AI工具界的USB-C,一个插头适配几乎所有设备。

这里要理解两个角色:
- MCP服务器:就是你的代码,负责暴露工具;
- MCP客户端:模型所在的应用,比如Claude桌面版或Cursor。
客户端启动时会问服务器:“你有哪些工具?”服务器返回一份带名称和描述的清单,交给模型。模型想调用某个工具时,客户端向服务器发请求,服务器运行函数并返回结果——所有交互都通过JSON来回传递。
本地运行 vs 远程运行
MCP服务器有两种运行方式。
本地运行
客户端把你的服务器作为子进程启动,运行在你自己的机器上,通过标准输入输出(stdio)直接通信。比如Claude桌面版会直接运行python my_server.py,然后把JSON管道输入进去。
大约90%的教程演示的都是这种方式。它适合个人折腾,但当别人也需要访问服务器时就行不通了。
远程运行
服务器运行在互联网上某处,拥有一个URL,客户端通过HTTP连接。几乎所有真实产品都用这种方式——GitHub的MCP服务器、Notion、Stripe,本质上都只是一个个URL。如果你要给别人用,或想在手机、笔记本、工作电脑等多设备访问工具,远程就是首选,也是走向生产环境的必经之路。
stdio(标准输入输出) 是操作系统提供的最基础的进程间通信方式:父进程与子进程之间通过标准输入流(stdin)和标准输出流(stdout)交换数据。本地模式下,MCP客户端(如Claude桌面版)直接fork出服务器进程,把JSON格式的请求写入其stdin,再从stdout读取响应,整个通信在本机内存中完成,无需网络栈。这种方式延迟极低、配置零成本,但天然只支持单台机器访问,无法跨设备或多用户共享。SSE(Server-Sent Events,服务器推送事件) 和可流式HTTP是远程模式常用的传输层,允许服务器主动向客户端推送消息,适合工具执行时间较长、需要流式返回进度的场景。
一旦远程,安全就成了绕不开的问题
远程MCP服务器引入了本地版本永远不会有的问题:访问控制。
服务器一旦上了公网,任何拿到URL的人都能调用你的工具。而这些工具会读数据、写数据、甚至删除数据。因此每一次请求都必须回答三个问题:谁在调用?他们被允许做什么?他们是代表谁在操作?
博主分享了一组令人震惊的数据:今年的安全审计发现,约四分之一的公开MCP服务器完全没有任何认证;而在有认证的服务器中,大多数只用了静态API密钥——一个长期有效、写在配置文件里、所有人共享的密钥;真正采用正规认证方案(OAuth)的只占极小比例。
静态API密钥为什么危险?想象一下,五个不同的Agent都用同一把密钥访问你的服务器,你根本分不清谁是谁,无法追踪哪个用户让哪个Agent做了什么。一旦其中一个被攻破,你只能作废整把密钥,同时让所有Agent集体瘫痪。短期项目还能凑合,但对任何真实生产系统都是灾难。
OAuth:MCP官方推荐的认证方案
MCP官方规范给出的答案,正是成熟应用早已普遍采用的方案——OAuth,具体引用的是带PKCE的OAuth 2.1。
听起来吓人,但你几乎永远不需要自己从头实现它。理解它的流程即可:
- 你的MCP服务器本身从不登录任何东西。当客户端(如Claude)不带有效令牌来访问时,服务器直接返回
401 未授权,并附上一个可供登录的URL——这个地址指向所谓的授权服务器。 - 客户端跳转过去,用户看到正常的登录界面(Google、邮箱等)和授权同意页。
- 用户点击“允许”后,授权服务器签发一个令牌交给客户端。
- 此后客户端在每次请求中都带上这个令牌,服务器验证令牌签名、确认其面向本服务器、检查内含权限(scope),再运行工具。
令牌里携带的权限称为scope,比如notes:read或notes:write。工具可以声明“我需要某个scope才能执行”。这样你不仅能认证用户身份,还能精细控制他能做什么。令牌里还嵌入了用户ID等信息,让服务器能够代表特定用户操作,从而支持多用户扩展。
此外还有一块叫动态客户端注册(DCR)——客户端在登录前需先向授权服务器注册自己,规范提供了自动化机制,你无需手动配置。
PKCE(Proof Key for Code Exchange,代码交换证明密钥) 是OAuth 2.1中的一项安全扩展,专门针对公开客户端(如桌面应用、移动App)设计。传统OAuth的授权码流程存在一个漏洞:恶意程序可能拦截授权码并冒用。PKCE的应对思路是:客户端在发起授权请求前,随机生成一段"代码验证器",并将其哈希值(即"代码挑战")一起提交;最终换取令牌时必须附上原始验证器,授权服务器比对哈希后才放行。由于哈希不可逆,即便授权码被截获也无法兑换成令牌。MCP规范采用OAuth 2.1+PKCE,正是因为MCP客户端(如Claude桌面版)属于典型的公开客户端,无法安全保管传统OAuth依赖的客户端密钥。
Python实战:从零构建MCP服务器
博主强调,你完全不需要自己实现协议底层。所有关于消息格式、请求/响应结构的细节,都可以在modelcontextprotocol.io查阅,但框架会帮你处理好这一切。开发者真正要负责的,只有授权配置和工具定义。

定义工具
使用fastmcp框架(pip install fastmcp即可),构建过程简单到出人意料:写几个普通Python函数,用@mcp.tool装饰器修饰它们,框架就会自动把这些函数加入可用工具清单,并在客户端连接时告知它们的存在。
博主特别提醒两个提升质量的技巧:
- 写好docstring:默认情况下框架会用函数的docstring作为工具描述,告诉模型这个工具是干什么的;
- 标注类型提示:给参数和返回值加上Python类型注解,能让模型更清楚该传什么、会拿到什么,从而获得更高质量的调用效果。
接入Cursor(本地模式)
在Cursor中,进入设置 → Tools and MCP → Add Custom MCP,添加配置。由于本地采用stdio方式,需要告诉Cursor如何把服务器作为子进程运行。配置里包含服务器名称、执行命令(Python用uv,JavaScript则用node)和参数(运行目录及文件)。

连接成功后,Cursor里会出现三个工具:列出笔记、添加笔记、删除笔记。你可以直接在Agent对话中说“帮我创建一条笔记”,模型便会调用对应工具完成操作。
切换到远程模式
从本地切到远程只需改一行代码:默认的mcp.run()使用stdio,改成指定transport、host和port后,就会以可流式HTTP方式运行。这样服务器就能通过URL直接接收请求。若部署在VPS或云服务器上,把URL给别人即可让对方连接。
在Cursor添加时只需填名称和URL(注意URL末尾必须加/MCP)。但博主再次提醒:此时依然没有任何访问控制,任何拿到URL的人都能增删笔记,且笔记不隶属于任何具体用户。
加上身份认证:让服务器真正可用于多用户
为了给远程服务器加上真正的身份与权限体系,博主使用了本期赞助商Descope的Agentic Identity Hub。它扮演前文提到的“授权服务器”角色,一站式处理登录界面、同意页、动态客户端注册等所有繁琐部件,开发者无需自己搭建。

配置流程大致如下:
- 在控制台创建MCP服务器,填入服务器URL(同样要带
/MCP); - 定义自定义scope,如
notes:read(允许读取笔记)和notes:write(允许修改、创建笔记); - 拿到一个well-known URL——即授权服务器地址,存入环境变量。
代码层面,使用descope-mcp SDK创建auth provider,把配置URL、基础URL和支持的scope传入,再挂载到fastmcp实例上。工具函数与之前几乎一致,唯一区别是每次操作前会读取当前登录用户、校验其是否拥有相应scope,并把笔记归属绑定到用户ID上——不再是之前那个所有人共享的静态本地ID。
实测效果:Cursor未认证时访问会返回401,并拿到授权URL;点击连接后浏览器弹出登录和同意页,用户可选择授予或拒绝各项scope。授权成功后,用不同账号登录会看到各自独立的笔记,互不可见。Descope控制台里还能管理用户、禁用或删除账号。
更进一步,Descope的Connections功能可存储用户的GitHub、Slack、Notion等第三方令牌,让Agent代表用户调用这些服务,而开发者无需自行保管任何长期密钥。
动态客户端注册(DCR, Dynamic Client Registration) 解决的是一个"鸡生蛋"问题:OAuth要求客户端提前在授权服务器注册并获得client_id,但MCP的客户端(如用户临时安装的某个AI助手)在部署时根本不知道它将来会连接哪些MCP服务器。DCR允许客户端在首次连接时通过标准API接口自动完成注册,无需运营者手动审批或预先配置。服务器的.well-known/oauth-authorization-server元数据端点会声明自己是否支持DCR,兼容客户端看到后即可自动走完注册流程、获取临时client_id,再继续正常的OAuth授权。这是MCP规范能在"任意客户端对任意服务器"场景下顺畅工作的关键机制之一。
小结
这期拆解把MCP从“听起来高深”还原成了“其实很朴素”:它不过是一份标准化的工具清单协议,让AI模型能以统一方式调用外部能力。真正的难点不在协议本身,而在于当你把服务器推向公网、面向真实用户时,如何做好身份认证与权限控制。
对开发者而言,关键结论有三个:用框架(如fastmcp)省去协议底层的苦活;远程部署优先并警惕静态密钥的风险;用OAuth(或成熟的身份服务)解决“谁在调用、能做什么、代表谁”这三个核心问题。
相关推荐

AI检测误判风波:作家被指用AI写作,谁该举证?
2026年英联邦短篇小说奖地区获奖者被Pangram检测工具判定100% AI生成,最终靠草稿自证清白。这起事件揭示了AI检测工具的误判风险与创作者面临的举证困境,以及作家协会承认没有可靠AI检测方法的现实。

Paul Ford新作引热议:Web本身已经足够
Paul Ford 文章《The Web Is More Than Enough》在 Hacker News 引发讨论,主张 Web 标准已足够承载应用开发,反对动辄引入封闭平台。本文梳理其核心论点、与当前 AI 应用潮流的张力,以及对开发者技术选型的实际含义。

斯坦福如何教授AI原生工程:CS146S课程揭秘
斯坦福CS146S课程直面AI一键生成作业的挑战,探索AI原生工程教育。Mihail Eric分享如何将AI作为工程伙伴,培养系统设计和代码审查能力,为工程教育提供新范本。