☰
怎么开发 MCP 服务:从 stdio 到 Streamable HTTP 的 SDK 实战大纲
2026/10/3 6:58:51 网站建设 项目流程

1. 从 stdio 到 Streamable HTTP:一个 MCP 服务到底怎么跑起来

MCP(Model Context Protocol)说白了就是给 AI 客户端装外设的协议。你写一个 Server,把本地能力(查数据库、读文件、调内部 API)暴露成 Tool,Cursor、Cline、Claude Desktop 这些 Host 就能通过统一的 JSON-RPC 调它。它解决的问题很具体:以前每接一个 AI 客户端就要写一套适配,现在写一次 Server,多个客户端复用。

这篇面向想让本地工具被 AI 客户端调用的开发者,目标很明确——用官方 SDK 从零搭一个 MCP 服务,先跑通 stdio,再切到 Streamable HTTP,最后用 Cline MCP 这类客户端连上并成功调用工具。全程给可复制的代码和配置,不空谈概念。

先分清三个角色,不然后面配置容易懵。Host 是用户面对的应用,持有模型和授权 UI,比如 Cursor、Claude Desktop;Client 是 Host 内部跟某一个 Server 的 1:1 连接;Server 就是你要开发的那一端。模型不会直接打你的 API,流程是:模型想用工具 → Host 调 Client → Client 用 JSON-RPC 问 Server → 结果回给模型。

Server 能提供的能力有 Tools、Resources、Prompts、Sampling、Roots,多数 Server 只实现一部分就够。对 Agent 来说,Tool 的 description 几乎决定它会不会被正确调用,所以写清楚做什么、不做什么、何时用、参数含义,比代码本身还重要。

传输方式选型也简单:stdio 适合本地开发和桌面/CLI,标准输入输出,最快上手,日志只能打 stderr;Streamable HTTP 适合远程、多人、生产,是当前推荐的远程方案;老的 HTTP + SSE 已弃用,新项目别用。建议路径是先做 stdio 跑通,用 Inspector 测工具,再切 HTTP 上线。

2. 前置准备:SDK 选型、环境与 TaoToken 接入

动手前先把 SDK 和环境定下来。TypeScript 用@modelcontextprotocol/sdk,生态最全;Python 用mcp加 FastMCP,对数据脚本和内部工具友好。我这边用 Python 演示,因为类型注解和 docstring 能自动变成 tool schema,少写一堆样板。

环境初始化用 uv,干净利落:

uv init weather && cd weather uv venv && source .venv/bin/activate uv add "mcp[cli]" httpx

如果你打算让 Server 内部去调大模型(比如做 Sampling 或者自己封装一个智能工具),这里就涉及模型接入。我用 TaoToken 做统一入口,它的 API 地址是https://taotoken.net/api,兼容常见调用方式,Key 在控制台生成。模型对话入口在 https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite ,接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite ,API Keys 管理在 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite 。长期跑编码类 Agent 的话,Coding Plan 在 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite 。

先把 Key 放进环境变量,别硬编码:

export TAOTOKEN_API_KEY="sk-你的key" export TAOTOKEN_BASE_URL="https://taotoken.net/api"

定义工具表面这一步别跳过。先列清楚要暴露哪些 tool、名字和参数是什么、哪些只读哪些会改数据、错误时返回什么让模型能自己修正。设计完再写代码,返工少一半。

3. 可复制配置:stdio 与 Streamable HTTP 两套写法

先写最小 Server。FastMCP 的写法很直观,类型注解和 docstring 直接变成 schema:

from mcp.server.fastmcp import FastMCP mcp = FastMCP("weather") @mcp.tool() async def get_alerts(state: str) -> str: """Get weather alerts for a US state. Args: state: Two-letter US state code (e.g. CA, NY) """ return f"Alerts for {state}: ..." if __name__ == "__main__": mcp.run() # 默认 stdio

stdio 模式下,客户端配置就是写启动命令。以 Cline MCP 或 Cursor 为例,配置片段长这样:

{ "mcpServers": { "weather": { "command": "uv", "args": ["--directory", "/绝对路径/weather", "run", "weather.py"] } } }

切到 Streamable HTTP 时,Server 端改成监听端口:

if __name__ == "__main__": mcp.run(transport="streamable-http", host="0.0.0.0", port=8000)

客户端配置随之变成 URL 形式,单端点如/mcp:

{ "mcpServers": { "weather-http": { "url": "http://127.0.0.1:8000/mcp" } } }

如果你用 Codex 的auth.json或 Cline MCP 这类需要显式声明模型的地方,三件套要写全:Base URL 填https://taotoken.net/api,Key 填你的TAOTOKEN_API_KEY,Model ID 按你选的模型填。缺一个都会在连接阶段报错。

stdio 有个硬规矩:绝不能污染 stdout。print()默认写 stdout,会毁掉 JSON-RPC,Server 会「莫名挂掉」。日志一律走 stderr 或 logging。这个坑我踩过,排查了半天才发现是一行调试 print。

4. 验证请求:Inspector 自测与客户端调用成功结果

别一上来就接 Agent,先用 Inspector 自测。它能列出所有 tool、展示 schema、逐个调用,比在对话里猜失败原因快得多:

npx @modelcontextprotocol/inspector python weather.py # 或 npx @modelcontextprotocol/inspector node ./dist/server.js

打开 UI 后,你应该能看到get_alerts这个 tool,参数state是 string 类型,description 就是 docstring 的内容。手动传CA调用,返回Alerts for CA: ...,说明 Server 本身没问题。

stdio 验证通过后,重启客户端(Cline、Cursor 等),在对话里让它调用这个 tool。成功的标志是:客户端能识别到 Server 的 tools,模型在需要时主动发起调用,结果正确回填到对话里。如果模型不调,八成是 description 太虚,回去改文案。

Streamable HTTP 的验证类似,先确认端口通了:

curl -i http://127.0.0.1:8000/mcp

再在客户端里用 URL 配置连接,重复上面的调用流程。远程部署时记得加鉴权,公开端点无鉴权等于把内部能力暴露到公网,推荐 OAuth 2.1 + PKCE,内网可以用 Bearer 或 mTLS。

5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth

排错时先看报错落在哪一层,协议层和业务层要分开。

401 Unauthorized:多半是 Key 没传对或没带上。检查环境变量是否生效,客户端配置里 Base URL 和 Key 是否写全。用 TaoToken 的话,确认TAOTOKEN_BASE_URL是https://taotoken.net/api,Key 从 API Keys 页面重新生成一次排除复制错误。

local proxy failed:通常是本地端口没起来或地址写错。stdio 模式检查启动命令路径是否为绝对路径;HTTP 模式确认host和port跟客户端 URL 一致,防火墙别挡。

reading choices类报错:一般是返回结构不符合预期,常见于 Server 内部调模型时响应格式没对齐。检查你解析响应的字段路径,确认模型返回的是标准结构。

OAuth相关失败:远程端点开了鉴权但客户端没配 token,或者回调地址不匹配。先在内网用 Bearer 跑通,再上 OAuth 2.1 + PKCE,别一步到位。

还有一个高频坑:一个 Server 塞几十个弱相关 tool,导致模型选型混乱。拆成多个聚焦 Server 更好。tool 名是公开 API,可增不可乱改名,重命名等于破坏性变更。

6. 从玩具到生产:上线前的收尾与接入入口

本地跑通只是第一步。上生产要补几件事:单独开/healthz做健康检查;TLS 在反向代理终止;打 latency 和错误率日志,但慎打入参,可能含敏感信息。默认做成无状态 HTTP 更易水平扩展,只有需要服务端推送或断线续传时再上有状态 session。

如果你要把这个 Server 接到编码类 Agent 长期跑,Coding Plan 在 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite 。需要生成和管理 Key 去 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite ,完整接入步骤看 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite ,想先验证模型效果可以直接在 https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite 对话测试。Claude Code 相关接入参考 https://taotoken.net/claude-code-anthropic?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite 。

最后提醒一句:Skill 和 MCP 容易混。Skill 是 Markdown 说明书,教 Agent「怎么做」;MCP 是独立进程或远程服务,给 Agent「能调用的真工具」。复杂场景两者一起用,Skill 规定何时调用哪些 MCP tools。先把 stdio 跑通,再用 Inspector 验证,最后切 Streamable HTTP 上线,这条路径最稳。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询