- 教程
- 文档
- 人工智能
【免费下载链接】mcp-for-beginners
This open-source curriculum introduces the fundamentals of Model Context Protocol (MCP) through real-world, cross-language examples in .NET, Java, TypeScript, JavaScript, Rust and Python. Designed for developers, it focuses on practical techniques for building modular, scalable, and secure AI workflows from session setup to service orchestration.
MCP(Model Context Protocol)自 2025-06-18 规范起,将独立的 SSE(Server-Sent Events)传输标记为废弃,并明确推荐stdio 传输作为本地 MCP 服务器的首选方案。本文以本仓库03-GettingStarted/05-stdio-server课程的完整解决方案为主体,逐行剖析 TypeScript、Python、.NET 三种运行时的 stdio 服务器实现,覆盖传输原理、工具定义、JSON-RPC 消息处理、Inspector 调试与 Claude Desktop 集成,帮助你快速掌握当前规范下构建 MCP 服务器的标准姿势。
背景:为什么 stdio 成为推荐的 MCP 传输方式
根据 课程主文档 的说明,MCP 规范定义了两种主要的传输机制:
- stdio—— 通过标准输入/输出流通信,推荐用于本地服务器;
- Streamable HTTP—— 用于远程服务器,内部可能使用 SSE。
在 2025-06-18 规范之前,独立的 SSE 端点方案需要搭建 HTTP 服务器、配置路由与会话管理,复杂度高且引入了额外的攻击面。规范更新后,该方案被Streamable HTTP取代;对于本地场景,stdio 是更简单、更安全、性能更好的选择。本课程的解决方案也据此全部升级为 stdio 传输。
stdio 传输的工作原理
stdio 传输的通信模型非常直接:
- 简单通信:服务器从标准输入(
stdin)读取 JSON-RPC 消息,并向标准输出(stdout)写入消息; - 基于进程:客户端将 MCP 服务器作为子进程启动;
- 消息格式:每条消息是独立的 JSON-RPC 请求、通知或响应,以换行符分隔;
- 日志:服务器可以通过标准错误(
stderr)写入 UTF-8 字符串用于日志输出。
同时规范对协议交互提出了三点硬性要求(见课程主文档):
- 消息必须以换行符分隔,且不得包含内嵌换行;
- 服务器不得向
stdout写入任何非 MCP 消息的内容; - 客户端不得向服务器的
stdin写入任何非 MCP 消息的内容。
这解释了为什么所有解决方案的日志输出都严格走stderr——stdout是 MCP 协议的专属通道,任何污染都会破坏客户端与服务器之间的 JSON-RPC 解析。
解决方案总览:三种运行时的完整实现
本课程的 solution 目录 提供了三种语言的标准答案,每种方案都完整演示了:
- stdio 传输的搭建(Setup);
- 服务器工具的声明与实现(Tools);
- 正确的 JSON-RPC 消息处理(JSON-RPC handling);
- 与 Claude 等 MCP 客户端的集成(Integration)。
| 运行时 | 实现位置 | 技术要点 |
|---|---|---|
| TypeScript | solution/typescript | MCP TypeScript SDK + Zod 参数校验 |
| Python | solution/python | MCP Python SDK + asyncio |
| .NET | solution/dotnet | Microsoft.Extensions.Hosting + 依赖注入 |
三个服务器暴露的工具体系保持一致:add(a, b)加法、multiply(a, b)乘法、get_greeting(name)个性化问候、get_server_info()服务器信息,便于对照学习各语言 SDK 的差异。
TypeScript:基于 MCP SDK 的 stdio 服务器
依赖与工程配置
参考 package.json,核心依赖是@modelcontextprotocol/sdk(>= 1.26.0)与zod(^3.24.2),工程脚本中已预置好构建、启动与调试命令:
{ "scripts": { "build": "tsc", "start": "node build/index.js", "inspector": "npx @modelcontextprotocol/inspector node build/index.js" } }安装依赖并编译:
npm install npm run build服务器实例与传输接入
在 src/index.ts 中,首先创建Server实例并声明工具能力:
import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; const server = new Server( { name: "example-stdio-server", version: "1.0.0", }, { capabilities: { tools: {}, }, } );随后用 Zod 为每个工具定义参数模式(如add需要两个 number 类型的参数a、b),为请求处理阶段提供运行时校验:
import { z } from "zod"; const AddArgsSchema = z.object({ a: z.number().describe("First number"), b: z.number().describe("Second number"), });工具注册与 JSON-RPC 请求处理
MCP 客户端通过两个标准 JSON-RPC 方法与服务器交互:tools/list(列出工具)与tools/call(调用工具)。SDK 以 Schema 常量形式暴露它们,服务器只需注册对应的请求处理器:
ListToolsRequestSchema处理器返回工具清单,每个工具包含name、description与符合 JSON Schema 规范的inputSchema(见 src/index.ts#L47-L95);CallToolRequestSchema处理器根据request.params.name分发到对应工具,先用 Zod 解析参数,再执行逻辑并以content: [{ type: "text", text: ... }]结构返回(见 src/index.ts#L98-L164)。
实现get_server_info时返回 JSON 序列化的服务器元数据:
case "get_server_info": { return { content: [ { type: "text", text: JSON.stringify({ server_name: "example-stdio-server", version: "1.0.0", transport: "stdio", capabilities: ["tools"], }, null, 2), }, ], }; }启动与优雅退出
入口函数创建StdioServerTransport实例并connect到服务器,实现 stdin/stdout 通信(src/index.ts#L167-L172):
async function runServer() { console.error("Starting MCP stdio server..."); // 日志走 stderr const transport = new StdioServerTransport(); await server.connect(transport); }同时监听SIGINT/SIGTERM信号实现优雅退出(src/index.ts#L175-L183)。启动方式:
npm start启动后服务器会"看似卡住"——这是正常现象,它正在等待来自stdin的 JSON-RPC 消息。
Python:基于 asyncio 的 stdio 服务器
依赖与运行环境
按 Python 解决方案文档,需要 Python 3.8+,并建议使用uv管理环境。安装 MCP SDK:
python -m venv venv source venv/bin/activate # macOS/Linux;Windows 用 venv\Scripts\activate pip install mcp使用 list_tools / call_tool 处理器定义工具
server.py 采用 Python SDK 的显式处理器风格:用@server.list_tools()装饰器声明工具清单,每个工具通过Tool模型描述名称、描述与inputSchema(server.py#L28-L72):
@server.list_tools() async def list_tools() -> list[Tool]: return [ Tool( name="add", description="Add two numbers together", inputSchema={ "type": "object", "properties": { "a": {"type": "number", "description": "First number"}, "b": {"type": "number", "description": "Second number"} }, "required": ["a", "b"] } ), # multiply / get_greeting / get_server_info 同理 ]工具调用逻辑由@server.call_tool()处理器统一接管,根据工具名分发并返回TextContent列表(server.py#L74-L103):
@server.call_tool() async def call_tool(name: str, arguments: dict) -> list[TextContent]: if name == "add": result = arguments["a"] + arguments["b"] logger.info(f"Adding {arguments['a']} + {arguments['b']} = {result}") return [TextContent(type="text", text=str(result))] # ... else: raise ValueError(f"Unknown tool: {name}")使用 stdio_server 上下文管理器运行
入口函数通过mcp.server.stdio.stdio_server()上下文管理器拿到读写流,再交给server.run()启动事件循环(server.py#L105-L123):
async def main(): logger.info("Starting MCP stdio server...") async with stdio_server() as (read_stream, write_stream): await server.run( read_stream, write_stream, server.create_initialization_options() ) if __name__ == "__main__": asyncio.run(main())启动与 TypeScript 一样简单:
python server.py补充说明:课程主文档还演示了 Python SDK 的另一种装饰器风格——直接用@server.tool()装饰普通函数即可暴露工具(见 课程主文档的 Python 示例)。两种写法等价,前者适合对工具注册过程做更精细控制,后者更简洁。
.NET:基于依赖注入的 stdio 服务器
主机构建:从 WebApplication 到 Host
.NET 方案的核心差异在于:旧的 HTTP/SSE 服务器需要WebApplication.CreateBuilder()+app.MapMcp()路由配置,而 stdio 方案退化为普通控制台主机(Program.cs):
var builder = Host.CreateApplicationBuilder(args); builder.Services .AddMcpServer() .WithStdioServerTransport() .WithTools<Tools>();.WithStdioServerTransport()替代了旧的.WithHttpTransport(),工具类Tools直接注册进 DI 容器。日志同样配置为输出到控制台(即 stderr 通道,见 Program.cs#L24-L29):
builder.Services.AddLogging(logging => { logging.ClearProviders(); logging.AddConsole(); logging.SetMinimumLevel(LogLevel.Information); });构建后调用app.RunAsync()启动(Program.cs#L39-L47)。
用特性声明工具
工具定义在 Tools.cs 中:类标注[McpServerToolType],每个方法标注[McpServerTool]并配合[Description]提供人类可读说明;构造函数注入ILogger<Tools>,实现结构化日志:
[McpServerToolType] public sealed class Tools { private readonly ILogger<Tools> _logger; public Tools(ILogger<Tools> logger) => _logger = logger; [McpServerTool, Description("Add two numbers together")] public async Task<string> AddNumbers( [Description("The first number")] int a, [Description("The second number")] int b) { var result = a + b; _logger.LogInformation("Adding {A} + {B} = {Result}", a, b, result); return await Task.FromResult($"{a} + {b} = {result}"); } // MultiplyNumbers / GetGreeting / GetServerInfo 同理 }.NET 实现天然获得依赖注入、结构化日志、异步支持和特性驱动的工具元数据,运行时可直接复用宿主容器的全部能力。
运行与测试:
dotnet restore dotnet build dotnet run测试与调试:使用 MCP Inspector
MCP Inspector 是调试 stdio 服务器的标准工具,它会将你的服务器作为子进程启动,并提供一个 Web 界面用于:
- 查看服务器能力(capabilities);
- 用不同参数交互式测试工具;
- 监控客户端与服务器之间的 JSON-RPC 消息;
- 排查连接问题。
三种运行时对应的启动命令:
| 运行时 | Inspector 命令 |
|---|---|
| TypeScript | npm run inspector(等价于npx @modelcontextprotocol/inspector node build/index.js) |
| Python | npx @modelcontextprotocol/inspector python server.py |
| .NET | npx @modelcontextprotocol/inspector dotnet run |
也可以不经过 Inspector,直接向服务器进程发送 JSON-RPC 消息验证响应(Python 示例,见 Python 方案文档):
{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}服务器会返回可用工具清单。这种方式适合快速验证传输层是否工作正常。
调试要点(课程主文档与三份方案文档共同强调):
- 日志一律走
stderr,严禁写stdout——那是 MCP 消息的专属通道; - 确保所有 JSON-RPC 消息以换行符分隔、不含内嵌换行;
- 先实现简单工具验证链路,再逐步添加复杂功能;
- 使用 Inspector 校验消息格式与工具参数 Schema。
与 Claude Desktop / VS Code 集成
构建完成的 stdio 服务器可以直接接入 Claude Desktop 等 MCP 客户端。以 Windows 的%APPDATA%\Claude\claude_desktop_config.json(macOS 为~/Library/Application Support/Claude/claude_desktop_config.json)为例,三种运行时的配置如下:
Python:
{ "mcpServers": { "example-stdio-server": { "command": "python", "args": ["path/to/server.py"] } } }TypeScript:
{ "mcpServers": { "example-stdio-server": { "command": "node", "args": ["path/to/build/index.js"] } } }.NET:
{ "mcpServers": { "example-stdio-server": { "command": "dotnet", "args": ["run", "--project", "path/to/server.csproj"] } } }配置完成后重启 Claude即可加载新服务器。之后便可在对话中自然调用工具,例如:"Calculate the sum of 15 and 27"、"Can you greet me using the greeting tool?"、"What's the server info?"。
若要在 VS Code 中直接调试服务器,可创建.vscode/launch.json调试配置,以 Python 为例(见 课程主文档):
{ "version": "0.2.0", "configurations": [ { "name": "Debug MCP Server", "type": "python", "request": "launch", "program": "server.py", "console": "integratedTerminal" } ] }设置断点后即可配合 Inspector 边调试边验证消息交互。
小结与后续学习路径
通过本课的三份解决方案,你已经掌握了:
- 为什么 stdio 是当前 MCP 规范推荐的本地传输方式,以及它相比废弃 SSE 方案的优势(无 HTTP 服务器、子进程模型、JSON-RPC over stdin/stdout、更安全更易调试);
- 在 TypeScript、Python、.NET 三种运行时下搭建 stdio 服务器、注册工具、处理 JSON-RPC 请求的完整方法;
- 使用 MCP Inspector 测试工具、排查连接问题的标准流程;
- 将服务器接入 Claude Desktop / VS Code 的配置方式。
stdout通道纪律(只写协议消息)、stderr日志约定、换行分隔的 JSON-RPC 格式是贯穿三种实现的共同内核——理解这三条,你就掌握了 stdio 传输的精髓。
继续深入学习可以接着阅读本仓库的相邻主题:
- HTTP Streaming(Streamable HTTP):远程 MCP 服务器的另一种受支持传输;
- MCP 安全最佳实践:为服务器实现安全防护;
- 部署策略:将服务器投入生产环境;
- 更多跨语言可运行示例见 samples 目录(Java / C# / JavaScript / TypeScript / Python / Rust)。
- 教程
- 文档
- 人工智能
【免费下载链接】mcp-for-beginners
This open-source curriculum introduces the fundamentals of Model Context Protocol (MCP) through real-world, cross-language examples in .NET, Java, TypeScript, JavaScript, Rust and Python. Designed for developers, it focuses on practical techniques for building modular, scalable, and secure AI workflows from session setup to service orchestration.
相关推荐
MCP stdio 传输实战:基于 mcp-for-beginners 多语言示例构建本地 MCP Server
MCP stdio 传输实战:基于 mcp for beginners 多语言示例构建本地 MCP Server 本文以 mcp for beginners 仓
教程文档人工智能基于 stdio 传输构建 MCP Server:TypeScript、Python 与 .NET 多语言实战指南
基于 stdio 传输构建 MCP Server:TypeScript、Python 与 .NET 多语言实战指南 本指南以 mcp for beginners
教程文档人工智能基于 stdio 传输构建 MCP Python 服务器:搭建、测试与客户端集成的完整实战指南(mcp-for-beginners)
基于 stdio 传输构建 MCP Python 服务器:搭建、测试与客户端集成的完整实战指南(mcp for beginners) 本教程以开源课程 mcp
教程文档人工智能
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考