ЁЯПл The SchoolтА║ЁЯФМ MCPтА║ЁЯФм рдзрдбрд╛ 06 тАФ Server рдмрд╛рдВрдзрд╛: ~125 рдкреНрд░рд╛рдорд╛рдгрд┐рдХ рдУрд│реА
ЁЯЦ╝я╕П See the drawing + lab ЁЯПа Course home ЁЯМ┐ Branch on GitHub тЬПя╕П View source
ЁЯЦ╝я╕П рдЖрдХреГрддреА рдЖрдгрд┐ labThe drawing + lab рдкреВрд░реНрдг рдкрд╛рдирд╛рд╡рд░ рдЙрдШрдбрд╛ тЖЧOpen full page тЖЧ

ЁЯФм рдзрдбрд╛ 06 тАФ Server рдмрд╛рдВрдзрд╛: ~125 рдкреНрд░рд╛рдорд╛рдгрд┐рдХ рдУрд│реА

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 8 рдкреИрдХреА рдзрдбрд╛ 06 ┬╖ рдорд╛рдЧреЗ: lesson-05-transports-security ┬╖ рдкреБрдвреЗ: lesson-07-build-a-client


ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ

рдзрдбреЗ 01тАУ05, рдЖрдгрд┐ рдПрдХрд╛ рдЦрд▒реНрдпрд╛ MCP server рдЪреЗ рдорд╛рд░реНрдЧрджрд░реНрд╢рд┐рдд рд╡рд╛рдЪрди тАФ server/school_server.py тАФ рдЖрдгрд┐ рддреНрдпрд╛рдд рддреБрдордЪреА рдкрд╣рд┐рд▓реА рднрд░.

ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ

рдЙрдкрдХрд░рдг рдмрд╛рдВрдзрдгреЗ рднреАрддрд┐рджрд╛рдпрдХ рд╡рд╛рдЯрддреЗ, рдЬреЛрдкрд░реНрдпрдВрдд рддреБрдореНрд╣реА рдПрдЦрд╛рджреЗ рдЙрдШрдбрд▓реЗрд▓реЗ рдкрд╛рд╣рдд рдирд╛рд╣реА. рдЖрдкрд▓реНрдпрд╛ рдЙрдкрдХрд░рдгрд╛рдд file рдордзреНрдпреЗ рд╡рд░реВрди рдЦрд╛рд▓реА рдиреЗрдордХреЗ рдЪрд╛рд░ рднрд╛рдЧ рдЖрд╣реЗрдд:

  1. рдЧреБрдВрдбрд╛рд│рд▓реЗрд▓реА рдЧреЛрд╖реНрдЯ ЁЯЧДя╕П тАФ рдПрдХ рдЦреЗрд│рдгреНрдпрд╛рддрд▓рд╛ database (DB, HOMEWORK). рдЦрд▒реНрдпрд╛ servers рдордзреНрдпреЗ рд╣рд╛рдЪ рд░рдВрдЬрдХ рднрд╛рдЧ рдЕрд╕рддреЛ: рддреБрдордЪрд╛ Postgres, рддреБрдордЪрд╛ API, рддреБрдордЪреА filesystem. MCP рдореНрд╣рдгрдЬреЗ рдлрдХреНрдд рдкреБрдвреЗ рд▓рд╛рд╡рд▓реЗрд▓рд╛ plug.
  2. рдХрдкреНрдкреНрдпрд╛рдВрдЪреА рдпрд╛рджреА ЁЯУЛ тАФ TOOLS: рдирд╛рд╡ + рд╡рд░реНрдгрди + inputSchema рдЕрд╢рд╛ рддреАрди рдиреЛрдВрджреА. L03 рдЖрдард╡рд╛: рд╡рд░реНрдгрдиреЗ model рд╕рд╛рдареА рдЕрд╕рддрд╛рдд тАФ рдЖрдкрд▓реА рд╡рд░реНрдгрдиреЗ рдкреНрд░рддреНрдпреЗрдХ tool рдХрд╛рдп рдХрд░рддреЛ рддреЗ рд╕рд╛рдВрдЧрддрд╛рдд рдЖрдгрд┐ add_homework write рдХрд░рддреЛ рд╣реЗрд╣реА (рдзреЛрдХреНрдпрд╛рдЪреЗ рд▓реЗрдмрд▓, L05!).
  3. Dispatcher ЁЯФА тАФ run_tool(name, args): рдкреНрд░рддреНрдпрдХреНрд╖ рдХрд╛рдо рдХрд░рдгрд╛рд░реА рд╕рд╛рдзреА Python if-ladder. рдЗрдереЗ protocol рд╕рд╛рд░рдЦреЗ рдХрд╛рд╣реАрдЪ рдирд╛рд╣реА тАФ рддреБрдореНрд╣реА рддреА рдПрдХрдЯреА unit-test рдХрд░реВ рд╢рдХрддрд╛.
  4. Plumbing ЁЯФз тАФ main(): рдПрдХ рдУрд│ рд╡рд╛рдЪрд╛, JSON parse рдХрд░рд╛, badge рддрдкрд╛рд╕рд╛ (рдЪреБрдХреАрдЪреА рдЖрд╡реГрддреНрддреА тЖТ рдЖрдкрдг рдмреЛрд▓рддреЛ рддреНрдпрд╛ рдЖрд╡реГрддреНрддреНрдпрд╛рдВрд╕рд╣ -32022), L04 рдордзреВрди рддреБрдореНрд╣рд╛рд▓рд╛ рдорд╛рд╣реАрдд рдЕрд╕рд▓реЗрд▓реНрдпрд╛ рддреАрди methods рдирд╛ рдЙрддреНрддрд░ рджреНрдпрд╛ (server/discover, tools/list, tools/call), reply рдЫрд╛рдкрд╛. Tool рдЕрдкрдпрд╢ тЖТ рдирдореНрд░ isError content, рдХрдзреАрдЪ crash рдирд╛рд╣реА; рдЕрдЬреНрдЮрд╛рдд tool тЖТ рдпреЛрдЧреНрдп -32602.

рд╣рд╛рдЪ server. рдЕрдзрд┐рдХреГрдд SDKs (Python/TypeScript mcp packages) рддреБрдореНрд╣рд╛рд▓рд╛ decorators, typed schemas, transports рдЖрдгрд┐ spec рдЪреЗ рдЙрд░рд▓реЗрд▓реЗ рдмрд╛рд░реАрдХрд╕рд╛рд░реАрдХ рднрд╛рдЧ рджреЗрддрд╛рдд тАФ рдЦрд▒реНрдпрд╛ рдХрд╛рдорд╛рд╕рд╛рдареА рддреЗ рд╡рд╛рдкрд░рд╛ тАФ рдкрдг рддреЗ рдпрд╛рдЪ рдЪрд╛рд░ рднрд╛рдЧрд╛рдВрдЪреЗ automation рдХрд░рддрд╛рдд, рдЖрдгрд┐ рдЖрддрд╛ рддреБрдореНрд╣реА рддреЗ рднрд╛рдЧ рдкрд╛рд╣рд┐рд▓реЗ рдЖрд╣реЗрдд.

ЁЯЧ║я╕П рдЖрдХреГрддреА

flowchart TB
    subgraph file["server/school_server.py - the four parts"]
        db["1 ЁЯЧДя╕П the wrapped thing<br/>DB + HOMEWORK (yours: Postgres, APIsтАж)"]
        tools["2 ЁЯУЛ the shelf: TOOLS<br/>name ┬╖ description(for the model!) ┬╖ inputSchema"]
        disp["3 ЁЯФА run_tool()<br/>plain Python if-ladder тАФ unit-testable"]
        plumb["4 ЁЯФз main() loop<br/>line in тЖТ JSON-RPC тЖТ line out"]
    end
    host["ЁЯФМ any MCP host"]
    host <-->|"stdio"| plumb
    plumb --> disp --> db
    plumb --> tools

ЁЯУЦ рдпрд╛ рдУрд│реА рд╡рд╛рдЪрд╛ (рдореНрд╣рдгрдЬреЗ рддреБрдореНрд╣реА рд╣рд░рд╡рдгрд╛рд░ рдирд╛рд╣реА)

server/school_server.py:

тЭУ рдХрд╛рдп (рдЪреЛрд░рдгреНрдпрд╛рд╕рд╛рд░рдЦреЗ рддрдкрд╢реАрд▓)

ЁЯдФ рдХрд╛

рдХрд╛рд░рдг "рдЖрдкрд▓реНрдпрд╛ X рд╕рд╛рдареА MCP server рдмрд╛рдВрдзрд▓рд╛ рдкрд╛рд╣рд┐рдЬреЗ" рд╣реЗ рдЖрддрд╛ рдЕрд░реНрдзреНрдпрд╛ рдЙрджреНрдпреЛрдЧрд╛рдд sprint ticket рдЖрд╣реЗ тАФ рдЖрдгрд┐ рддреБрдореНрд╣реА рддреНрдпрд╛рдЪрд╛ рдкреНрд░рд╛рдорд╛рдгрд┐рдХ рдЕрдВрджрд╛рдЬ рджреЗрдК рд╢рдХрддрд╛: plug рдореНрд╣рдгрдЬреЗ рдПрдХ рджрд┐рд╡рд╕ (SDK рдиреЗ рдХрд╛рд╣реА рддрд╛рд╕); рдЦрд░реЗ рдХрд╛рдо рднрд╛рдЧ 1 (рдХрд╛рдп рдЙрдШрдб рдХрд░рд╛рдпрдЪреЗ) рдЖрдгрд┐ рднрд╛рдЧ 2 рдЪреА рд╡рд░реНрдгрдиреЗ + рдзреЛрдХреНрдпрд╛рдЪреА рд▓реЗрдмрд▓реЗ рдЖрд╣реЗ (рд░рдЪрдирд╛, L03/L05). рдЬреЗ teams рд╣реЗ рдмрд░реЛрдмрд░ рдХрд░рддрд╛рдд рддреЗ рдЕрд╕реЗ servers рджреЗрддрд╛рдд рдЬреЗ agents рдЦрд░реЛрдЦрд░ рдмрд░реЛрдмрд░ рд╡рд╛рдкрд░рддрд╛рдд.

ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛ тАФ рдЦрд░реЛрдЦрд░ рд╡рд╛рдврд╡рд╛

# 1) prove the baseline:
python3 client/mini_client.py

# 2) YOUR first tool тАФ add to TOOLS in server/school_server.py:
#    {"name":"list_homework","description":"Show the homework list (read-only).",
#     "inputSchema":{"type":"object","properties":{}}}
#    тАжand to run_tool():
#    if name == "list_homework":
#        return f"Homework: {json.dumps(HOMEWORK) or '[]'}"

# 3) rerun the client тАФ your tool appears in discovery, callable:
python3 client/mini_client.py --drive
# model calls> list_homework {}

рддреБрдордЪрд╛ рдкрд╣рд┐рд▓рд╛ MCP server рдмрджрд▓: shipped. ЁЯФм

тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ

list_homework рдЬреЛрдбрд▓реНрдпрд╛рдирдВрддрд░ discovery рдЪрд╛рд░ tools рджрд╛рдЦрд╡рддреЗ рдЖрдгрд┐ --drive тЖТ list_homework {} homework list рдЫрд╛рдкрддреЛ. fly_to_moon {} тЭМ server error -32602: Unknown tool рджреЗрддреЛ (protocol error), рддрд░ lookup_grade {"student":"nobody"} isError рдЪрд┐рдиреНрд╣рд╛рдВрдХрд┐рдд result рджреЗрддреЛ (tool рдмреЛрд▓рддреЛ рдЖрд╣реЗ).

ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ

рддреБрдореНрд╣реА рдЦрд▒реНрдпрд╛ MCP server рдЪрд╛ рдХрдкреНрдкрд╛ рдЖрдгрд┐ dispatcher рддреНрдпрд╛рдЪреНрдпрд╛ plumbing рд▓рд╛ рд╣рд╛рдд рди рд▓рд╛рд╡рддрд╛ рдмрджрд▓рд▓рд╛ тАФ рдЖрдгрд┐ spec рдиреЗ рдард░рд╡рд▓реЗрд▓реНрдпрд╛ рджреЛрдиреНрд╣реА рдкреНрд░рдХрд╛рд░рдЪреНрдпрд╛ errors рдкрд╛рд╣рд┐рд▓реНрдпрд╛.

тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: рдЕрдзрд┐рдХреГрдд SDKs (Python/TypeScript рд╕рд╛рдареА mcp) рд╣реЗ рдЪрд╛рд░ рднрд╛рдЧ automate рдХрд░рддрд╛рдд рдЖрдгрд┐ transports, schemas рдЖрдгрд┐ auth рдЬреЛрдбрддрд╛рдд тАФ рдЦрд▒реНрдпрд╛ servers рд╕рд╛рдареА рддреЗ рд╡рд╛рдкрд░рд╛. рддреЗ рддреБрдордЪреНрдпрд╛рд╕рд╛рдареА рдХрд░реВ рд╢рдХрдд рдирд╛рд╣реАрдд рдЕрд╕реЗ рд░рдЪрдиреЗрдЪреЗ рдХрд╛рдо рдореНрд╣рдгрдЬреЗ рднрд╛рдЧ 1 рдЖрдгрд┐ 2: рдХрд╛рдп рдЙрдШрдб рдХрд░рд╛рдпрдЪреЗ, рдЖрдгрд┐ рдкреНрд░рд╛рдорд╛рдгрд┐рдХ рдзреЛрдХреНрдпрд╛рдЪреНрдпрд╛ рд▓реЗрдмрд▓рд╛рдВрд╕рд╣ рд╡рд░реНрдгрдиреЗ.

тПня╕П рдкреБрдвреЗ

Socket рдЪреА рджреБрд╕рд░реА рдмрд╛рдЬреВ: mini_client.py рд╡рд╛рдЪрдгреЗ тАФ рдЖрдгрд┐ рд╕рддреНрддрд╛ models рдХрдбреЗ рдирд╡реНрд╣реЗ рддрд░ hosts рдХрдбреЗ рдХрд╛ рдЕрд╕рддреЗ.

git checkout lesson-07-build-a-client

ЁЯФм Lesson 06 тАФ Build a server: ~125 honest lines

ЁЯУН You are here: Lesson 06 of 8 ┬╖ Previous: lesson-05-transports-security ┬╖ Next: lesson-07-build-a-client


ЁЯУж What's in this branch

Lessons 01тАУ05, plus the guided read of a REAL MCP server тАФ server/school_server.py тАФ and your first extension to it.

ЁЯзТ Explain like I'm 5

Building an instrument sounds scary until you see one opened up. Ours has exactly four parts, top to bottom of the file:

  1. The thing being wrapped ЁЯЧДя╕П тАФ a toy database (DB, HOMEWORK). In real servers this is the interesting part: your Postgres, your API, your filesystem. MCP is just the plug on the front.
  2. The shelf list ЁЯУЛ тАФ TOOLS: three entries of name + description + inputSchema. Remember L03: descriptions are for the model тАФ ours say what each tool does AND that add_homework writes (danger label, L05!).
  3. The dispatcher ЁЯФА тАФ run_tool(name, args): a plain Python if-ladder doing the actual work. Nothing protocol-ish here тАФ you could unit-test it alone.
  4. The plumbing ЁЯФз тАФ main(): read a line, parse JSON, check the badge (wrong revision тЖТ -32022 with the revisions we do speak), answer the three methods you know from L04 (server/discover, tools/list, tools/call), print the reply. Tool failures тЖТ polite isError content, never a crash; unknown tool тЖТ a proper -32602.

That's a server. The official SDKs (Python/TypeScript mcp packages) give you decorators, typed schemas, transports and the long tail of the spec тАФ use them for real work тАФ but they're automating THESE four parts, and now you've seen the parts.

ЁЯЧ║я╕П Diagram

flowchart TB
    subgraph file["server/school_server.py - the four parts"]
        db["1 ЁЯЧДя╕П the wrapped thing<br/>DB + HOMEWORK (yours: Postgres, APIsтАж)"]
        tools["2 ЁЯУЛ the shelf: TOOLS<br/>name ┬╖ description(for the model!) ┬╖ inputSchema"]
        disp["3 ЁЯФА run_tool()<br/>plain Python if-ladder тАФ unit-testable"]
        plumb["4 ЁЯФз main() loop<br/>line in тЖТ JSON-RPC тЖТ line out"]
    end
    host["ЁЯФМ any MCP host"]
    host <-->|"stdio"| plumb
    plumb --> disp --> db
    plumb --> tools

ЁЯУЦ Read these lines (so you don't get lost)

server/school_server.py:

тЭУ What (the details worth stealing)

ЁЯдФ Why

Because "we should build an MCP server for our X" is now a sprint ticket in half the industry тАФ and you can estimate it honestly: the plug is a day (SDK makes it hours); the REAL work is part 1 (what to expose) and part 2's descriptions + danger labels (design, L03/L05). Teams that get those right ship servers agents actually use correctly.

ЁЯзк Try it тАФ extend it for real

# 1) prove the baseline:
python3 client/mini_client.py

# 2) YOUR first tool тАФ add to TOOLS in server/school_server.py:
#    {"name":"list_homework","description":"Show the homework list (read-only).",
#     "inputSchema":{"type":"object","properties":{}}}
#    тАжand to run_tool():
#    if name == "list_homework":
#        return f"Homework: {json.dumps(HOMEWORK) or '[]'}"

# 3) rerun the client тАФ your tool appears in discovery, callable:
python3 client/mini_client.py --drive
# model calls> list_homework {}

Your first MCP server change: shipped. ЁЯФм

тЬЕ Verify тАФ what you should see

After adding list_homework, discovery lists four tools and --drive тЖТ list_homework {} prints the homework list. fly_to_moon {} gives тЭМ server error -32602: Unknown tool (a protocol error), while lookup_grade {"student":"nobody"} gives a result flagged isError (the tool talking).

ЁЯПБ What you just proved

You changed a real MCP server's shelf and dispatcher without touching its plumbing тАФ and you saw both error kinds the spec defines.

тЪая╕П Common mistakes

ЁЯПн Why this matters in production: the official SDKs (mcp for Python/TypeScript) automate these four parts and add transports, schemas and auth тАФ use them for real servers. The design work they cannot do for you is parts 1 and 2: what to expose, and descriptions with honest danger labels.

тПня╕П Next

The other side of the socket: reading mini_client.py тАФ and why hosts, not models, hold the power.

git checkout lesson-07-build-a-client
тЖР Previoustransports securityNext тЖТbuild a client

This page is the lesson's README from the lesson-06-build-a-server branch, shown here so the whole School stays on one site. Code files open on GitHub at the same branch.