Simon Willison 重新拥抱 MCP:无状态协议为何再次改变 Agent 工具链

2026-08-05 42 预计阅读时间: 1 分钟
来源: oschina.net AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:9 分钟

MCP 的故事并不是“一个协议赢了,另一个概念输了”这么简单。Simon Willison 的态度变化,更像是在提醒 AI 开发者:当 Agent 已经能够访问终端、执行 curl 并组合命令时,工具协议的价值不再只取决于“能不能调用工具”,还取决于它是否足够轻量、可组合、容易部署和观察。

2025 年底,Simon Willison 在年度回顾中用「The Only Year of MCP」概括 MCP 的快速流行。他当时提到,MCP 走红还不到一年,就被 Anthropic 提出的 Skills 概念抢走了部分注意力。一个能够访问终端并运行 curl 的 Agent,确实可以用更通用的方式完成许多工作,不必为每个工具都接入专门的 MCP 服务。

但这并不意味着 MCP 失去意义。进入 2026 年上半年,围绕 MCP 的讨论又出现了新的重心:无状态、低耦合的协议形态,可能比“给模型增加多少个预定义工具”更重要。

从工具清单转向能力边界

传统工具调用通常把能力描述成一组函数:搜索、查询数据库、创建工单、发送消息。模型看到的是名称、参数和返回值,开发者则需要维护工具注册、权限控制、连接生命周期和错误处理。

Skills 和终端型 Agent 的优势在于通用性。只要环境提供了合适的命令行工具,Agent 就能通过脚本和 HTTP 接口完成组合任务。例如,它可以读取配置、调用 API、过滤 JSON,然后把结果交给下一个步骤。这种方式减少了专用适配器,但也把更多责任交给运行环境:凭证怎么注入、命令能访问哪些目录、网络请求是否受限,都必须显式设计。

MCP 的价值则更接近一个稳定的能力边界:客户端不必了解服务内部的实现,只需要按照协议发现和调用能力。若服务端采用无状态设计,每个请求都携带完成任务所需的上下文,服务就可以更容易地水平扩展、重启和调试。

这两种方式并非互斥:

  • Skills 适合快速组合现有命令和 API,尤其适合探索性任务。
  • MCP 适合把经过治理的能力暴露给多个 Agent、客户端或团队。
  • 无状态设计适合云端部署、弹性扩缩容和故障恢复。
  • 有状态会话仍然有用,但应该只在确实需要上下文、事务或长任务时引入。

“无状态”究竟改变了什么

一个无状态工具服务不依赖某台机器内存里的会话对象来理解请求。请求中应包含必要的输入,服务端根据输入完成处理,并返回结构化结果。

可以这样实践:下面这个 Python 示例使用标准库启动一个简单的 HTTP 服务。它提供一个无状态的 lookup 接口,服务端不会保存用户会话;每次请求都通过 JSON 传入查询词。示例只是一个可改造的协议骨架,不代表某个官方 MCP 实现。

把代码保存为 server.py 后运行:

from http.server import BaseHTTPRequestHandler, HTTPServer
import json


class Handler(BaseHTTPRequestHandler):
    def do_POST(self):
        if self.path != "/tools/lookup":
            self.send_error(404, "not found")
            return

        try:
            length = int(self.headers.get("Content-Length", "0"))
            payload = json.loads(self.rfile.read(length))
            query = str(payload.get("query", "")).strip()
            if not query:
                raise ValueError("query is required")

            result = {
                "query": query,
                "items": [
                    {"name": "example", "summary": f"Result for {query}"}
                ],
            }
            body = json.dumps(result).encode("utf-8")
            self.send_response(200)
            self.send_header("Content-Type", "application/json")
            self.send_header("Content-Length", str(len(body)))
            self.end_headers()
            self.wfile.write(body)
        except (ValueError, json.JSONDecodeError) as exc:
            body = json.dumps({"error": str(exc)}).encode("utf-8")
            self.send_response(400)
            self.send_header("Content-Type", "application/json")
            self.send_header("Content-Length", str(len(body)))
            self.end_headers()
            self.wfile.write(body)


if __name__ == "__main__":
    HTTPServer(("127.0.0.1", 8000), Handler).serve_forever()

启动并调用它:

python server.py

curl -s http://127.0.0.1:8000/tools/lookup \
  -H 'Content-Type: application/json' \
  -d '{"query":"MCP"}'

这个例子有三个值得保留的特征:请求输入是显式的,返回结果是结构化 JSON,服务端没有依赖进程内会话。生产环境中还需要补上认证、超时、速率限制、审计日志和输入校验。

终端自由度与协议治理的取舍

“Agent 能运行 curl”确实带来了很强的自由度,但自由度越高,治理成本也越高。一个直接访问终端的 Agent 可能遇到以下问题:

  • 命令注入和参数拼接风险。
  • 访问了不应读取的文件或环境变量。
  • 凭证通过命令行参数、日志或错误信息泄漏。
  • 外部 API 返回恶意内容,进一步影响后续命令。
  • 任务执行缺乏稳定的输入输出契约,导致结果难以测试。

MCP 或类似协议的核心收益,正在于把能力包装成可描述、可授权、可审计的接口。它不一定比直接调用命令更灵活,却更容易成为团队级基础设施。

因此,选择协议时可以按任务性质划分:探索阶段允许 Agent 使用受限终端和少量脚本;进入生产后,把高频、敏感或需要审计的操作收敛为稳定接口。对于接口本身,优先采用无状态请求,只有在长连接、事务协调或大规模流式任务中才引入会话状态。

开发团队应该关注什么

Simon Willison 的重新拥抱更值得被理解为一次工程判断,而不是立场反转。协议的价值会随着 Agent 能力变化而重新排序:当 Agent 可以自己组合命令时,简单的工具封装不再稀缺;可发现性、权限边界、可观测性和部署模型反而成为关键。

落地时可以检查这份清单:

  • 每个工具是否有清晰、稳定的输入输出 schema?
  • 请求是否能够在不同实例之间独立执行?
  • 是否能记录调用者、参数摘要、耗时和错误类型?
  • 凭证是否通过安全的运行时注入,而不是进入提示词或命令行?
  • 终端能力是否限制了目录、网络、系统调用和资源消耗?
  • 哪些能力适合保留为 Skill,哪些能力应该升级为受治理的 MCP 服务?

MCP 的下一阶段未必是工具数量继续增加,而可能是协议变得更轻、更无状态、更容易嵌入已有系统。对开发者来说,最实际的策略不是在 MCP 和 Skills 之间二选一,而是让自由组合能力服务于探索,让稳定协议承载生产边界。


相关推荐