第六课

MCP 从零实现教程(六)

第六课:让你的 Mini MCP Server 真正跑起来

目标:让另一个 Python 程序真的能够连接你的 MCP Server。


📚 本课目标

学完本课后,你将理解:

  • Server 为什么要一直运行
  • Client 和 Server 是如何通信的
  • 什么是 Transport(传输层)
  • 为什么 MCP 有 STDIO 和 HTTP 两种运行方式

今天最大的变化:

前五课我们都是:

Python 函数
    │
    ▼
dispatch(request)

今天开始变成:

Client
    │
    ▼
发送请求
    │
    ▼
Server
    │
    ▼
dispatch(request)

这一步开始,你写的不再只是一个 Python 程序,而是一个真正意义上的 Server

根据 MCP 官方规范,目前标准支持两种 Transport:

  • STDIO(标准输入输出)
  • Streamable HTTP

对于本地工具,客户端通常启动 MCP Server 子进程,然后通过 STDIN/STDOUT 通信。 


📖 第一部分:为什么需要 Server?

目前我们的程序是这样的:

request = {
    "method": "tools/call",
    ...
}

dispatch(request)

程序执行一次:

开始

↓

执行 dispatch()

↓

结束

结束以后:

程序退出。

但是真正的 MCP Server 不是这样。

它应该:

启动

↓

等待请求

↓

处理请求

↓

继续等待

↓

处理请求

↓

继续等待

也就是说:

Server 是一直运行的。


📖 第二部分:什么叫监听请求?

最简单的方法:

一直循环。

while True:
    print("等待客户端请求...")

运行以后:

等待客户端请求...
等待客户端请求...
等待客户端请求...
...

当然,

真正服务器不会一直打印。

它会一直:

等待输入。


💻 第三部分:模拟客户端发送请求

最简单的方法:

使用:

input()

例如:

while True:

    command = input("请输入:")

    print(command)

运行:

请输入:

hello

输出:

hello

这就是:

等待客户端输入。


💻 第四部分:输入 JSON

上一课:

我们写的是:

request = {

    "method": "tools/call"

}

现在:

改成:

import json

while True:

    text = input()

    request = json.loads(text)

    print(request)

运行:

输入:

{
    "method":"tools/list"
}

Python 输出:

{
    "method": "tools/list"
}

是不是已经开始接收 JSON 了?


💻 第五部分:调用 Dispatcher

现在:

收到 JSON 后,

直接:

while True:

    text = input()

    request = json.loads(text)

    response = dispatch(request)

    print(response)

是不是很自然?

整个流程:

JSON

↓

Dispatcher

↓

Tool

↓

Result

↓

打印

💻 第六部分:输出 JSON

真正 MCP 不会:

print(response)

因为:

Python 字典:

{
    "a":1
}

不是 JSON。

所以:

改成:

print(json.dumps(response))

完整:

import json

while True:

    text = input()

    request = json.loads(text)

    response = dispatch(request)

    print(json.dumps(response))

💻 第七部分:完整 Server

import json

def server():

    print("Mini MCP Server 已启动")

    while True:

        text = input()

        request = json.loads(text)

        response = dispatch(request)

        print(json.dumps(response))


server()

运行:

终端:

Mini MCP Server 已启动

输入:

{
    "method":"tools/list"
}

输出:

{
    "result":{

        "tools":[

            ...

        ]

    }
}

是不是已经有 Server 的样子了?


💻 第八部分:写一个 Client

以前:

客户端不存在。

今天:

我们自己写。

import json

request = {

    "method":"tools/list"

}

print(json.dumps(request))

是不是很简单?

Client:

负责:

发送 JSON

Server:

负责:

接收 JSON

📖 第九部分:真正 MCP 是怎么通信的?

我们今天:

Client

↓

input()

↓

Server

真实 MCP(STDIO):

Claude Desktop

↓

STDIN

↓

你的 MCP Server

↓

STDOUT

↓

Claude Desktop

也就是说:

今天我们写的:

input()

未来:

其实就是:

stdin.read()

今天的:

print()

未来:

其实就是:

stdout.write()

本质完全一样。

MCP 官方要求:

  • Client 启动 Server 子进程
  • Client 把 JSON-RPC 消息写入 Server 的 stdin
  • Server 把 JSON-RPC 响应写入 stdout
  • stdout 不能输出任何非协议内容(日志应该写到 stderr)。 

📖 第十部分:为什么官方喜欢 STDIO?

因为:

不用网络。

例如:

Cursor

↓

启动

filesystem_server.py

↓

stdin/stdout

↓

完成

整个过程:

没有:

  • HTTP

没有:

  • Socket

没有:

  • Web Server

速度非常快。

所以:

本地 Tool:

几乎都是:

STDIO

远程 MCP:

才使用:

Streamable HTTP

🧪 本课练习

修改你的 Server。

要求:

支持连续执行:

第一次:

{
    "method":"tools/list"
}

返回:

{
    "result":{
        "tools":[...]
    }
}

第二次:

{
    "method":"tools/call",

    "params":{

        "name":"add",

        "arguments":{

            "a":10,

            "b":20

        }

    }
}

返回:

{
    "result":30
}

要求:

程序不要退出

能够一直等待新的请求。


🎯 本课总结

今天,你已经拥有了:

✅ Tool Registry

✅ Dispatcher

✅ JSON-RPC

tools/list

tools/call

持续运行的 Mini MCP Server

这是一个重要的里程碑。

你已经不再只是写几个 Python 函数,而是在构建一个真正可以与其他程序通信的服务。


🚀 第七课预告(真正进入 MCP SDK)

前六课,我们一直在自己造轮子。

下一课,我们会第一次引入官方 MCP SDK。

但不同的是:

别人学习 SDK 时看到:

@mcp.tool()
def weather():
    ...

可能觉得这是魔法。

而你已经知道:

实际上 SDK 只是帮你完成了:

@tool

↓

Registry

↓

Dispatcher

↓

JSON-RPC

↓

STDIO

↓

Server

所以第七课我们会做一件非常有意思的事情:

把我们自己写的 Mini MCP Server,与官方 MCP SDK 的实现逐行对照。

你会发现,两者在核心思想上几乎一致,只是官方 SDK 把很多重复工作自动化了。这也是为什么我一直坚持先带你手写,再学框架。

posted @ 2026-07-31 17:51  zwx901323  阅读(3)  评论(0)    收藏  举报