SONUB
ZH English 한국어 日本語 中文 हिन्दी বাংলা اردو Español Português Français Deutsch Русский العربية Bahasa Indonesia Tiếng Việt ไทย Türkçe

如何开启通知

此浏览器或网址无法使用通知。请使用支持通知的浏览器,通过安全连接访问SONUB。

如果通知被屏蔽,请在浏览器设置中允许通知。

  1. 打开地址栏旁的站点设置或浏览器的站点设置,将此网站的通知设为允许。
  2. 在设备设置中允许浏览器发送通知,并检查勿扰模式或专注模式。
  3. 返回SONUB,刷新页面,然后通过铃铛开启通知。

在iPhone或iPad上,将SONUB添加到主屏幕,从主屏幕打开后允许通知。

登录 退出登录 显示主题 默认主题 深色主题 粉色主题 聊天 1:1 聊天 群聊 论坛 公告 新闻区 建议区 主菜单
把 连接到外部工具的标准

MCP(Model Context Protocol)

不用 ,用亲手写的小型 和 一条条跟着看 消息,再把它连接到 ,看看设置保存在哪里。

消息与传输方式

消息采用 2.0——像 (“你能做什么?”)和 (“用这些做这件事”)这样的小 对象。它们通过两种标准之一来往:stdio(在同一台电脑上把作为启动,双方通过标准对话)或 (服务器运行在一个网址上,所以很多用户都能访问)。

亲手做的服务器和客户端

服务器(mcp-server.py)只用 ,所以你能看到本身。它从标准输入每行读一条 JSON-RPC 消息,并向标准输出每行写一条回复:

  • :客户端带着打招呼。服务器用同一个回答,说明自己有,并报出自己的名字。
  • tools/list:服务器返回它唯一的工具 strange-add,附带描述和输入模式(a 和 b 是数字)。
  • tools/call:服务器运行 strange-add,并把结果作为文本返回。
  • 没有 id 的消息是通知(比如 /initialized),所以服务器不回复。其他任何请求(比如 ping)都会得到一个空结果。

strange-add 会在 a + b 上再加一个 1 到 100 之间的随机数。自己算不出这个值,所以 2 + 3 的答案不是 5,就证明工具真的运行了。stdout 只协议消息——混进一个多余的 () 就会破坏对话,所以要写到 stderr。print(..., =True) 会把每条回复立刻发出去。

客户端(mcp-client.sh)是一个不需要任何 就能扮演主机角色的 脚本。它启动服务器,发送整个(initialize、initialized 通知、tools/list、tools/call、ping),逐条检查回复,并打印 PASS 或 FAIL。退出码 0 表示全部通过。在把服务器连接到之前,先这样测试它。在真正的客户端里,模型会加入这个循环:

  • 把用户的问题和工具列表发给模型;
  • 当模型要求使用某个工具时,客户端用 tools/call 在服务器上它;
  • 把结果发回去,模型写出最终的回答。

这个手写的服务器使用以 initialize 开始的方式(协议版本 2025-06-18), 等客户端仍然接受这种方式。(2026-07-28)不再用 initialize ,而是在每个请求里带上版本。做真正的服务时,请使用官方 (Python MCPServer、),它们会替你遵循规范。

mcp-server.py
"""
mcp-server.py: the smallest MCP server.
One tool, plain Python (standard library only), no SDK.

Who is who
  MCP server  This program. It offers tools (functions the AI
              may use).
  Host        The app the user talks to (Claude Code, Codex).
              It runs one MCP client for each connected server.
  MCP client  The part of the host that talks to this server
              with JSON-RPC messages (here over stdio: one JSON
              message per line).
  Model       The LLM (Claude Opus, GPT, ...). It never talks to
              the server directly. It only talks to the host.

Flow
  1. Discover tools
     The client asks for the tools (tools/list). The server replies
     with each tool's name, description and input schema.
  2. Offer tools
     The host sends the user's message to the model, together
     with the tool list.
  3. Model decides
     The model answers directly, or asks for a tool call
     (tool name + arguments). It never runs the tool itself.
  4. Call the tool
     The client sends the request to the server (tools/call).
  5. Run the tool
     The server runs the function and returns the result.
  6. Model continues
     The host gives the result back to the model. The model may
     call more tools (3-6 again) or write the final answer.

  Model             Host (MCP client)            MCP server
    |                    |  1. tools/list  ------>  |
    |                    |  <------  tool list      |
    | <-- 2. message + tool list                    |
    | 3. tool call -->   |                          |
    |                    |  4. tools/call  ------>  |
    |                    |  <------  5. result      |
    | <-- 6. result      |                          |

Rule for stdio servers: stdout carries protocol messages only.
Never print() anything else there. Write logs to stderr.
"""

import json
import random
import sys

SERVER_INFO = {"name": "strange-add-mcp", "version": "1.0.0"}

# The tool. The model reads the description to decide when to use it.
STRANGE_ADD = {
    "name": "strange-add",
    "description": "Add two numbers with a strange number.",
    "inputSchema": {
        "type": "object",
        "properties": {
            "a": {"type": "number"},
            "b": {"type": "number"},
        },
        "required": ["a", "b"],
    },
}


def strange_add(a, b):
    """Add a + b and a random number from 1 to 100 (always > a + b).

    The model cannot guess the answer, so a right answer proves
    that the tool was really called.
    """
    return a + b + random.randint(1, 100)


def handle(method, params):
    """Return the result for one request. Others (like ping) get {}."""
    if method == "initialize":
        # Use the client's protocol version and say "I have tools".
        return {
            "protocolVersion": params["protocolVersion"],
            "capabilities": {"tools": {}},
            "serverInfo": SERVER_INFO,
        }
    if method == "tools/list":
        return {"tools": [STRANGE_ADD]}
    if method == "tools/call":
        args = params["arguments"]
        total = strange_add(args["a"], args["b"])
        return {"content": [{"type": "text", "text": str(total)}]}
    return {}


def main():
    # One JSON-RPC message per line comes in, one reply per line goes out.
    for line in sys.stdin:
        request = json.loads(line)
        # No id means a notification: send no reply.
        if "id" not in request:
            continue
        result = handle(request["method"], request.get("params", {}))
        reply = {"jsonrpc": "2.0", "id": request["id"], "result": result}
        # flush=True sends the reply at once.
        print(json.dumps(reply), flush=True)


if __name__ == "__main__":
    main()
mcp-client.sh
#!/bin/sh
# mcp-client.sh: the simplest MCP client, a shell script.
# It starts mcp-server.py, talks to it over stdio (one JSON-RPC
# message per line) and checks every reply.
# Exit code 0 means every check passed.

SERVER="python3 $(dirname "$0")/mcp-server.py"

# 1. Send the whole session at once and keep the replies.
#    id 1     initialize                 agree on a version
#    (no id)  notifications/initialized  "ready" (no reply)
#    id 2     tools/list                 which tools are there?
#    id 3     tools/call                 run strange-add(2, 3)
#    id 4     ping                       is the server alive?
replies=$(
  $SERVER <<'EOF'
{"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {"protocolVersion": "2025-06-18", "capabilities": {}, "clientInfo": {"name": "shell-mcp-client", "version": "1.0.0"}}}
{"jsonrpc": "2.0", "method": "notifications/initialized"}
{"jsonrpc": "2.0", "id": 2, "method": "tools/list"}
{"jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": {"name": "strange-add", "arguments": {"a": 2, "b": 3}}}
{"jsonrpc": "2.0", "id": 4, "method": "ping"}
EOF
)

echo "--- Server replies ---"
echo "$replies"
echo "--- Checks ---"

failed=0

# 2. check <label> <reply id> <text the reply must contain>
check() {
  reply=$(echo "$replies" | grep -F "\"id\": $2,")
  if echo "$reply" | grep -qF "$3"; then
    echo "PASS   $1"
  else
    echo "FAIL   $1 (expected: $3)"
    failed=1
  fi
}

check "initialize: protocol version"  1 '"protocolVersion": "2025-06-18"'
check "initialize: server info"       1 '"serverInfo": {'
check "initialize: has tools"         1 '"capabilities": {"tools": {}}'
check "tools/list: strange-add"       2 '"name": "strange-add"'
check "ping: empty result"            4 '"result": {}'

# 3. strange-add adds a random 0 to 100,
#    so the answer only has to be >= 2 + 3.
total=$(echo "$replies" | grep -F '"id": 3,' |
  sed 's/.*"text": "\([0-9]*\)".*/\1/')
if [ "$total" -ge 5 ] 2>/dev/null; then
  echo "PASS   tools/call: strange-add(2, 3) >= 5 (got $total)"
else
  echo "FAIL   tools/call: strange-add(2, 3) >= 5 (got $total)"
  failed=1
fi

exit $failed
在终端中输入的命令
# put the two files above into one folder
mkdir -p ~/tmp/mcp && cd ~/tmp/mcp
#   mcp-server.py   mcp-client.sh

# 1) test the server without any AI
sh mcp-client.sh               # -> 6 x PASS, exit code 0

# 2) connect it to Claude Code (no --scope: the "local" scope)
claude mcp add strange-add -- python3 ~/tmp/mcp/mcp-server.py
claude mcp list                # strange-add: ... - Connected
claude mcp get strange-add     # Scope: Local config

# 3) where it was saved: NOT in this folder (no new file here)
#    ~/.claude.json -> projects -> "<this folder>" -> mcpServers
jq '.projects["'"$PWD"'"].mcpServers' ~/.claude.json

# 4) use it: start Claude Code in THIS folder
claude                         # "Use strange-add to add 2 and 3"
                               # -> not 5 (e.g. 61): the tool ran

claude mcp remove strange-add -s local

这些在你自己的电脑或服务器的里运行,而不是在这个页面上。运行前请逐行读一遍。

出处

在 AI 课程里一起学

AI 课程的 MCP 章节——目标 · 任务 · 进度

学习指南

人工智能

智能体工具

Vibe 编程

AI 应用

AI证书

AI课堂

IT 基础

聊天

论坛

创作

社区

更多

术语词典

选一个你不认识的词吧,可以看到简单的解释和相关术语。

还没有匹配的术语。

选择一个术语即可查看解释。