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

How to enable notifications

Notifications are unavailable in this browser or on this address. Try a supported browser on the secure SONUB site.

If notifications are blocked, allow them in your browser settings.

  1. Open the site controls beside the address bar, or your browser’s site settings. Set Notifications for this site to Allow.
  2. In your device settings, allow notifications for your browser and check Do Not Disturb or Focus.
  3. Return to SONUB, reload the page, and use the bell to enable notifications.

On iPhone or iPad, add SONUB to your Home Screen, open it there, then allow notifications.

Log in Log out Display theme Default theme Dark theme Pink theme Chat 1:1 Chat Group Chat Forum Notices News Suggestions Main menu
The standard that connects to outside tools

MCP (Model Context Protocol)

Follow messages one by one with a small and a written by hand, without an , then connect it to and see where the setting is saved.

Messages and transports

The messages are 2.0 — small objects such as ("what can you do?") and ("do this, with these arguments"). They travel over one of two standard : stdio (the starts the as a on the same computer and they talk through standard ) or (the server runs at a web address, so many users can reach it).

A hand-made server and client

The server (mcp-server.py) uses only the , so you can see the itself. It reads one JSON-RPC message per line from standard input and writes one reply per line to standard output:

  • : the client says hello with a . The server answers with the same , says that it has and gives its name.
  • tools/list: the server returns its one tool, strange-add, with a description and an input (a and b are numbers).
  • tools/call: the server runs strange-add and returns the result as text.
  • A message without an id is a (such as notifications/initialized), so the server sends no reply. Any other request (such as ping) gets an empty result.

strange-add adds a random number from 1 to 100 to a + b. The cannot work that out by itself, so an answer that is not 5 for 2 + 3 proves that the tool really ran. stdout carries the protocol messages only — one stray () breaks the conversation, so write to stderr. print(..., =True) sends each reply at once.

The client (mcp-client.sh) is a script that plays the host's part without any . It starts the server, sends the whole (initialize, the initialized notification, tools/list, tools/call, ping) and checks each reply, printing PASS or FAIL. Exit 0 means that everything passed. Test a server like this before you connect it to an . In a real client the model joins the loop:

  • send the user's question and the tool list to the model;
  • when the model asks for a tool, the client calls it on the server with tools/call;
  • send the result back, and the model writes the final answer.

This hand-made server speaks the style that starts with initialize (protocol version 2025-06-18), which clients such as still accept. The newest (2026-07-28) carries the version in every request instead of an initialize . For real services, use the official (Python MCPServer, ), which follow the specification for you.

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
Commands to type in your terminal
# 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

These run in a on your own computer or server, not on this page. Read each line before you run it.

Sources

Learn it in the AI Course too

The AI Course MCP chapter — goal · tasks · progress

Guidelines

AI

Agent Tools

Vibe Coding

AI in Practice

Certificate

AI Class

IT Basics

Chat

Forum

Create

Community

More

Glossary

Pick a word you don't know. You'll see a simple explanation and related terms.

No matching term yet.

Pick a term to see its explanation.