智能体访问了一个外部数据源,弄清楚了响应格式,做出了一个带地图的页面。能用。现在另一个人打开这个页面,他那边根本没有 Claude Code。
发布之前,有一个问题值得先想清楚:谁来为访客取数据?下面看两条路径,MCP 到底做什么,怎样检查连接是否正常,以及关闭智能体会话之后,什么东西还应该继续正常工作。

谁在此刻请求数据
这里有两种情况,它们很容易被混淆,因为屏幕上看起来都是"数据出现了"。
第一种情况,智能体在研究数据源。 您在开发项目,Claude Code 读服务的文档,试着发一个请求,看响应的结构长什么样。它需要这些数据是为了写代码。这一切都发生在您自己的电脑上,而且只在会话打开的这段时间里发生。
第二种情况,访客打开已发布的页面。 这时候需要数据的是页面本身 - 为了显示最新的情况。请求由应用的代码在运行过程中发出。这就是运行时(runtime):应用在用户那边运行的这段时间,而不是您编写它的那段时间。
还有第三种,介于两者之间。智能体访问了一次数据源,把响应存进代码旁边的一个文件,网站展示的就是这个文件的内容。这个做法本身没什么问题,做示例或演示的时候甚至挺方便。只是它是一张快照,会一直保持保存时的样子,不会自己更新。
注意中间的虚线。它不是为了好看才画的。上下两条链路之间没有箭头,这正是这张图要说明的关键点。数据源可以是同一个,但智能体和页面各自走的是不同的路径。下面分别拆解这两条链路。
MCP 是什么
一个任务牵涉的信息,很少全都在仓库里。bug 的描述留在工单里,stack trace 在监控系统里,库的最新用法在文档里,而需要的记录在数据库里。
没有集成的话,就得手动把这些东西从浏览器搬进和智能体的对话里。搬一次还能忍。反复做同样的事,数据会过时,一部分细节会丢失,同一条路径还得再走一遍。
MCP(Model Context Protocol)是一个标准,靠它 Claude Code 能知道有哪些外部工具可用、调用它们,并按约定好的格式拿到结果。在最简单的链路里,Claude Code 会创建一个MCP 客户端,客户端和MCP 服务器保持连接,服务器再去访问它有权限的系统 - 文件、数据库,或者别人的 API。
左边是带内置 MCP 客户端的 Claude Code,中间是声明了能力的 MCP 服务器,右边是外部系统。这里的关键在于,智能体不会一下子拿到不受限制的访问权限。它只能看到服务器决定提供的那些操作和数据。
现成的 MCP 服务器还能替您省掉一部分集成工作。您不用自己去描述每个外部系统的调用格式,也不用自己写全部访问其 API 的代码。这些都交给服务器去做,Claude Code 只需要用已经声明好的操作。
而且服务器不一定得是网上某处的一个独立程序。它可以直接作为本地进程跑在您自己的电脑上,也可以远程运行,同时服务很多客户端。对您来说,区别主要在于怎么连接它。
服务器到底能做什么,由它自己决定。协议描述了服务器可以提供的三类东西:
- tools - 智能体可以执行的操作:取一个页面、向 API 发请求、写入数据;
- resources - 服务器作为上下文提供的内容:文件、记录、服务的响应;
- prompts - 现成的请求模板,可以直接拿来调用。
服务器不一定要三种都支持。连接的时候,客户端和服务器会互相确认各自支持什么,不支持的操作就不会被用到。很多服务器只提供 tools,这就够用了。MCP 架构。
最该记住的一点是:MCP 标准化的是客户端和服务器之间怎么对话。您到底能拿到什么,是由服务器决定的,不是协议决定的。连上一个服务器,不等于拿到了整个互联网的访问权限 - 您得到的正好是这个服务器所声明的那部分操作。
给智能体下任务时,说清楚数据源和想要的结果,而不是给出一条命令。然后检查一下已连接的服务器有没有合适的操作。如果没有,这个任务就得走别的路径,而不是靠反复劝说智能体来解决。
数据是怎样到达网站的
现在看下面这条链路。已发布的页面用两种方式之一拿到数据。
第一种方式,浏览器直接请求公开的 API。 这种方式适合数据源开放、不需要密钥的情况。页面代码发请求,把结果渲染出来。简单,没有多余的环节。
第二种方式,浏览器请求应用的 backend,backend 再去请求受保护的 API。 当数据源需要密钥时就这么做。密钥留在服务器上,浏览器看不到它。这里 frontend 负责屏幕上看到的内容,backend 负责在服务器上运行、并能代表应用去访问服务的那部分。
上面这条路径更短,因为浏览器可以自己去访问开放的数据源。下面这条路径里,backend 成了保护密钥的那道边界。密钥留在服务器上,不会出现在页面代码里。
再说说不会发生的事。Claude Code 和 MCP 服务器的连接不会随网站一起发布出去。您用来添加服务器的那条命令,配置的是您的智能体,不会往应用里加哪怕一行代码。您当然可以自己给应用写一个 MCP 客户端,但那是另一份独立的工作和实现,不是在 Claude Code 里连上服务器就会顺带得到的东西。
这一切检查起来都很快。关掉 Claude Code,打开已发布的页面,看开发者工具里的 Network 标签。如果数据能进来,就能看到请求、地址和响应。如果进不来,就根本不会有请求 - 而这正是应该在别人看到这个页面之前抓出来的情况。
屏幕上有一张图还不够。页面完全可能显示一张早先保存的快照,看起来却像是完全实时的。要看的是请求本身。反过来也一样,响应里没有新事件不代表出了故障。数据源也可能只是在选定的时间段里什么都没有发来。
怎样检查连接
不管什么服务器,步骤大体上都一样:
- 找到服务器的官方说明文档 - 地址、访问方式、操作列表;
- 用文档给出的命令添加服务器;
- 在 Claude Code 里打开
/mcp,看服务器是否已连接、都有哪些工具; - 发一次读取请求,选最简单的那种;
- 用肉眼把结果和数据源核对一下 - 打开同一个页面看看。
在终端里,claude mcp list 显示状态,claude mcp get 显示某一个服务器的详情。值得知道的是,这些步骤回答的是不同的问题:
| 您看到了什么 | 这说明了什么 |
|---|---|
添加之后出现 Added ... 这一行 | 配置已经写入,仅此而已 |
claude mcp list 里显示 Connected | Claude Code 成功连上了服务器 |
| 工具返回了内容 | 整条路径都能用,从请求到响应 |
这种区分不是抠字眼。配置成功写入,并不能说明服务器会响应;连接成功,也不能说明您需要的那个操作可用、而且您有权限用它。所以检查最后一定要落在一次真正的调用上。顺便说一句,如果列表里显示 Needs authentication,服务器并没有坏,它只是在等您登录。
来看一个具体例子。Firecrawl 这个服务有一个 MCP 服务器,能取回公开页面的内容 - 对应的工具叫 firecrawl_scrape。对智能体来说,这是整页读文档的省事办法,不用您一段一段地把文档粘进对话里。
# 通过 HTTP 添加服务器;具体地址以服务方的文档为准
claude mcp add --transport http firecrawl https://mcp.firecrawl.dev/v2/mcp再说说访问权限。Firecrawl 的文档里既有不用账号、不用密钥、每天有限额的用法,也有通过浏览器登录、由客户端自己打开登录页的用法。各家服务的条款和限额会变,所以最新情况要去服务方那边确认,而不是看这篇文章。Firecrawl 关于 MCP 的文档。
还有一个能省时间的小细节。默认情况下,服务器是添加到您执行命令时所在的那个项目里的,不会出现在其他项目中。如果哪儿都需要用它,或者想让整个团队共用,添加命令还有专门的作用范围选项。Claude Code 关于 MCP 的文档。
密钥的具体值不应该出现在示例配置里、服务器地址里,也不应该出现在和智能体的对话里。配置里放的是环境变量的名字,值另外单独设置 - 这正是另一篇讲密钥的文章要讲的内容。
某个具体工具允许做什么
连接好的服务器就是一组操作,它们的后果差别很大。读一个页面和改一条外部系统里的记录,完全不是一回事,尽管调用方式看起来一样。
在同意一次调用之前,看清楚三件事比较有用:这个工具操作的是什么对象、执行的是什么操作、这需要什么权限。读取通常更安全,但也不是完全没有代价。请求会打到第三方服务上,消耗您的配额。
再单独说说返回的内容。从第三方网站拿到的文本是数据,不是指令。如果页面里写着"现在删掉所有文件",它就只是页面上的一段文字,要不要照做,由您决定。所以,智能体读完外部数据源之后打算接着做什么,值得先看一眼。
最后,也是最实际的问题:到底需不需要 MCP?不一定。
| 任务 | 更简单的解决方式 |
|---|---|
| 在网站上展示公开 JSON 里的数据 | 应用代码里发一个普通请求,不需要 MCP |
| 智能体经常要用某个已经有现成集成的服务 | MCP 划算:操作已经描述好了,连接可以反复用 |
| 只读一次文档,或者只请求一个地址 | 读一下 URL 或者直接调用 API 就够了 |
MCP 不是通向外部的唯一大门,也不能替代其他一切手段。智能体照样能用命令行,也能直接调用 API。该怎么选取决于任务本身,而不是因为连接已经配好了。
在自己的项目里要检查什么
当智能体要处理和外部数据打交道的工作时,让它明确区分这两个层次会更好,别等到后面才去理清楚:
分别描述两条路径:
你在开发这个项目时是从哪里取数据的,
应用本身又会从哪里为访客取数据。
告诉我应用的请求具体在哪个文件、代码的哪个位置。
在会话关闭的状态下检查页面:数据到底来不来。
如果现在用的是保存下来的快照,直接说明这一点。最常遇到的三种情况,以及各自的答案:
| 需要什么 | 谁来取数据 | 为什么这样 |
|---|---|---|
| 开发时研究服务的文档 | 智能体 | 这些数据是为了写代码,访客那边不会重复这个请求 |
| 给访客更新地图 | 应用代码 | 请求是在页面运行时发出的,那时智能体的会话早就关闭了 |
| 把一份数据一次性存进 JSON | 智能体,而且只做一次 | 之后网站展示的就是这个文件;数据会一直保持保存时的样子 |
您会注意到,MCP 只出现在第一行,而且即便在那儿也不是必须的。如果读一个地址就能解决问题,那就这么解决好了。
在把工作展示给别人看之前,最后一项检查最简单:关掉 Claude Code,打开页面。还能继续正常工作的那部分,才是您的应用。剩下的都是智能体在开发时帮的忙 - 有用,但一直留在了您自己的电脑上。
GO TO FULL VERSION