TellWorldAI 世界档案
问档案English

首页›实践›实践

实践

MCP stdio 服务器怎么写

用 stdio 传输写 MCP 服务器:客户端以子进程启动它,通过标准输入输出通信。写两个工具,用 Inspector 调试,再接入 Claude Desktop。

这篇适合谁、读完能做到什么

如果你想写一个只在自己电脑上运行、供 Claude 等客户端调用的 MCP 服务器,这篇适合你。读完你能用 stdio 传输写出一个带工具的 Python 服务器,用 MCP Inspector 测试它,把它接进 Claude Desktop,并且知道出问题时该查哪几处。[1]

stdio 是什么,为什么本地服务器首选它

stdio 传输让 MCP 服务器通过标准输入(stdin)和标准输出(stdout)与客户端通信。这是目前 MCP 规范里最常用的传输方式,这也是本地服务器推荐的做法。[1]

它的工作方式很简单:客户端把服务器当作子进程启动,服务器从 stdin 读取 JSON-RPC 消息,再把响应写到 stdout。每条消息是一条 JSON-RPC 请求、通知或响应,用换行符分隔,消息内部不能含有换行。[1]

和旧的 SSE 方式相比,stdio 服务器不需要搭建 Web 服务器,也不需要 HTTP 端点,实现起来更简单,调试也更直接。SSE 传输在 MCP 规范 2025-06-18 版中已被废弃,由 Streamable HTTP 取代。如果你要做的是远程服务器,应该看 Streamable HTTP;做本地工具,stdio 就够了。[1][3]

几条必须遵守的规则

stdio 对输出非常敏感,下面三条必须记住:[1]

  • 服务器不能往 stdout 写任何不是合法 MCP 消息的内容。stdout 只留给 MCP 消息。
  • 服务器可以把 UTF-8 字符串写到 stderr 用于日志。
  • 客户端也不能往服务器的 stdin 写入不合法的 MCP 消息。

很多新手的 bug 都出在这里:在代码里加一句 print,输出到 stdout,客户端就会解析失败。日志应该写到 stderr。[1]

准备

  • Python 3.8 或更高版本。
  • MCP Python SDK,用 pip install mcp 安装。
  • 对异步编程(async)有基本了解,能看懂 async with 和 await。[1]

这篇的练习是一个 Python 服务器,名字叫 example-stdio-server。它先只有一个问候工具,再加上加法和乘法,最后多一个返回服务器信息的工具。[1]

第一步:写一个最小的 Python 服务器

下面是完整的最小示例,它展示了 stdio 服务器的基本结构:导入类、创建服务器、用装饰器定义工具,再通过 stdio_server 运行。[1]

import asyncio
import logging
from mcp.server import Server
from mcp.server.stdio import stdio_server

# Create server instance
server = Server("example-server")

@server.tool()
def add(a: int, b: int) -> int:
    """Add two numbers"""
    return a + b

async def main():
    async with stdio_server(server) as (read_stream, write_stream):
        await server.run(
            read_stream,
            write_stream,
            server.create_initialization_options()
        )

if __name__ == "__main__":
    asyncio.run(main())

这段代码的关键是 stdio_server 上下文管理器。它负责把 stdin 和 stdout 包装成读写流,然后交给 server.run。服务器自己不需要关心网络或端口。[1]

工具用 @server.tool() 装饰器定义。函数的参数和返回值的类型注解会成为工具的输入和输出描述,函数上方的文档字符串说明工具的用途。[1]

第二步:加入更多工具

在服务器里再加两个工具,一个做乘法,一个返回服务器信息:[1]

@server.tool()
def calculate_sum(a: int, b: int) -> int:
    """Calculate the sum of two numbers"""
    return a + b

@server.tool()
def calculate_product(a: int, b: int) -> int:
    """Calculate the product of two numbers"""
    return a * b

@server.tool()
def get_server_info() -> dict:
    """Get information about this MCP server"""
    return {
        "server_name": "example-stdio-server",
        "version": "1.0.0",
        "transport": "stdio",
        "capabilities": ["tools"]
    }

get_server_info 返回的字典里,服务器名是 example-stdio-server,版本是 1.0.0,传输方式是 stdio,能力是 tools。这个工具适合用来确认你连接的确实是你写的那个服务器。[1]

代码末尾的 if __name__ == "__main__": 让脚本只在直接运行时才启动服务器,asyncio.run(main()) 负责驱动异步的 main 函数。这两处是 Python 版的固定写法,照着保留即可。[1]

运行服务器

把代码保存为 server.py,然后在命令行运行:[1]

python server.py

服务器启动后会停在那里,等待 stdin 的输入。这是正常的,它在等客户端发来的消息。你不需要自己去输入 JSON-RPC 消息,交给 Inspector 或 Claude 去做就行。[1]

命令里的 python server.py 也是 Inspector 要启动的服务器命令。npx @modelcontextprotocol/inspector 是 Inspector 本身,后面跟的内容告诉它怎样启动你的服务器,所以写错服务器的启动命令,Inspector 也连不上。[1]

用 MCP Inspector 测试

MCP Inspector 是一个调试和测试工具。它可以查看服务器的能力、用不同参数测试工具、监控 JSON-RPC 消息,还能帮你定位连接问题。[1][2]

启动 Inspector 并指向你的服务器,用这条命令:[1][2]

npx @modelcontextprotocol/inspector python server.py

打开 Inspector 之后,建议按这个顺序测试:先看服务器能力,再用 get_greeting 试几个不同的名字,用 calculate_sum 试几组数字,最后调用 get_server_info 核对元数据。Inspector 还会显示客户端和服务器之间交换的 JSON-RPC 消息,遇到问题时可以对照检查格式。[1]

接入 Claude Desktop

Claude Desktop 的配置文件位置是:Windows 上为 %APPDATA%\Claude\claude_desktop_config.json,Mac 上为 ~/Library/Application Support/Claude/claude_desktop_config.json。在文件里用 mcpServers 注册服务器,启动命令是 python,参数是服务器文件的路径:[1]

{
  "mcpServers": {
    "example-stdio-server": {
      "command": "python",
      "args": ["path/to/your/server.py"]
    }
  }
}

注意示例里的 path/to/your/server.py 要换成你电脑上 server.py 的真实路径。保存之后重启 Claude,让新配置生效。[1]

然后在对话里试几句话,比如「Can you greet me using the greeting tool?」「Calculate the sum of 15 and 27」或者「What's the server info?」。如果 Claude 能调用你的工具并返回结果,说明整条链路已经通了。[1]

调试技巧

  • 日志写到 stderr,不要写到 stdout。
  • 确保每条 JSON-RPC 消息都用换行分隔。
  • 先用简单的工具测试,确认通了再加复杂功能。
  • 用 Inspector 核对消息格式。[1]

想在 VS Code 里断点调试,可以在 .vscode/launch.json 里加一个 Python 调试配置:"type": "python","program": "server.py","console": "integratedTerminal"。设好断点后启动调试器,再用 Inspector 发请求。[1]

常见问题

服务器起不来时,先确认依赖装好了(pip install mcp),检查 Python 语法和缩进,再看控制台报错。[1]

工具没有出现在列表里,通常是 @server.tool() 装饰器漏写了,或者工具函数定义在 main() 之后。[1]

连接出问题时,检查服务器是否正确使用了 stdio 传输,确认没有其他进程干扰,并核对 Inspector 的命令格式。[1]

TypeScript 版怎么写

TypeScript 版用的是底层的 Server 类,并要自己注册 ListToolsRequestSchema 和 CallToolRequestSchema 两个请求处理函数,分别负责列出工具和调用工具。下面是它的导入和启动部分:[1]

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

const server = new Server(
  {
    name: "example-server",
    version: "1.0.0",
  },
  {
    capabilities: {
      tools: {},
    },
  }
);

async function runServer() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
}

runServer().catch(console.error);

调用工具时,处理函数返回的是 type 为 text 的内容数组。如果请求的工具名不认识,就抛出错误。[1]

Python 版只需要用装饰器定义工具,TypeScript 版则要自己写列出工具和调用工具的两个处理函数,所以示例明显更长。两种写法的目标是一样的:让客户端能看到工具清单,并能调用其中的工具。[1]

下一步

下一步可以学习 Streamable HTTP,它是另一种支持的传输方式,适合远程服务器。安全和部署方面,也可以继续看 MCP 的安全最佳实践和部署策略。[1]

本文改编自 Microsoft 开源课程《MCP for Beginners》第 3 课中关于 stdio 服务器的一节[1],原文以 MIT 许可证发布。

来源

  1. 1
    MCP Server with stdio TransportMicrosoft mcp-for-beginners (MIT)
  2. 2
    MCP InspectorModel Context Protocol
  3. 3
    MCP Specification 2026-07-28Model Context Protocol

引用本页: MCP stdio 服务器怎么写. TellWorld, https://www.tellworld.net/zh/practice/practice-mcp-stdio-server. 更新于 2026-11-14

相关动态