Setup and Your First Server
สิ่งที่ต้องมีก่อน
หัวข้อที่มีชื่อว่า “สิ่งที่ต้องมีก่อน”| เครื่องมือ | Version | ทำไม |
|---|---|---|
| Node.js | 22.19 ขึ้นไป | รัน TypeScript SDK และ MCP Inspector (Inspector ต้องการ ≥ 22.19) |
| Python | 3.10 ขึ้นไป | รัน Python SDK |
uv | รุ่นใหม่ ๆ ตัวไหนก็ได้ | ตัวจัดการ project และ dependency ของ Python ที่เร็ว; uvx รัน server ที่เผยแพร่แล้วได้โดยไม่ต้องติดตั้ง |
ตรวจด้วย node --version, python3 --version และ uv --version ที่เหลือ package manager จะดึงมาให้เอง
สร้าง project
หัวข้อที่มีชื่อว่า “สร้าง project”mkdir hello-mcp && cd hello-mcpnpm init -ynpm install @modelcontextprotocol/server zodnpm install -D tsx typescriptuv init hello-mcp && cd hello-mcpuv add mcp@modelcontextprotocol/server คือครึ่งฝั่ง server ของ TypeScript SDK (ครึ่งฝั่ง client เป็น package แยก) ส่วน package mcp ของ Python มีทั้งสองครึ่งอยู่ด้วยกัน
เขียน server ที่มี tool เดียว
หัวข้อที่มีชื่อว่า “เขียน server ที่มี tool เดียว”server ด้านล่างเปิด tool ตัวเดียวชื่อ get-forecast และพูด stdio — transport ที่ host ใช้รัน server เป็น subprocess
import { McpServer } from '@modelcontextprotocol/server';import { serveStdio } from '@modelcontextprotocol/server/stdio';import * as z from 'zod/v4';
serveStdio(() => { const server = new McpServer({ name: 'weather', version: '1.0.0' });
server.registerTool( 'get-forecast', { description: 'Get the weather forecast for a city', inputSchema: z.object({ city: z.string() }), }, async ({ city }) => ({ content: [{ type: 'text', text: `Sunny in ${city} all week.` }], }), );
return server;});from mcp.server import MCPServer
mcp = MCPServer("weather")
@mcp.tool()def get_forecast(city: str) -> str: """Get the weather forecast for a city.""" return f"Sunny in {city} all week."
if __name__ == "__main__": mcp.run() # stdio is the default transportแต่ละส่วนทำอะไร:
McpServer/MCPServer— object ของ servernameและversionจะกลายเป็นio.modelcontextprotocol/serverInfoใน result และใน response ของserver/discoverregisterTool/@mcp.tool()— ลงทะเบียน tool TypeScript รับinputSchemaแบบ Zod ที่ระบุชัด (import จากzod/v4) และส่ง argument ที่มี type ให้คุณ Python สร้าง JSON Schema จาก type hint ของ function และเอา description มาจาก docstring- ค่าที่ handler return — TypeScript return result object ที่มี array
contentPython ให้ return string ธรรมดาได้ แล้ว SDK จะห่อเป็น text content block ให้ serveStdio/mcp.run()— ต่อ server เข้ากับ stdin/stdoutserveStdioรับ factory เพื่อให้ SDK สร้าง server ใหม่ต่อ connection ได้ และ factory รูปร่างเดียวกันนี้จะถูกใช้กับ HTTP ในภายหลัง
บน wire server นี้ตอบ tools/list ด้วย:
{ "resultType": "complete", "tools": [ { "name": "get-forecast", "description": "Get the weather forecast for a city", "inputSchema": { "type": "object", "properties": { "city": { "type": "string" } }, "required": ["city"] } } ]}นั่นคือ contract ทั้งหมดที่ host ต้องการ
รันใน Inspector
หัวข้อที่มีชื่อว่า “รันใน Inspector”MCP Inspector คือเครื่องมือนักพัฒนาอ้างอิง: package npx ตัวเดียวที่มี web UI, CLI และ terminal UI ซึ่งใช้โค้ด connection ร่วมกันทั้งหมด ชี้มันไปที่คำสั่งเปิด server ของคุณ:
npx @modelcontextprotocol/inspector npx tsx server.tsnpx @modelcontextprotocol/inspector uv run server.py# or the SDK's shortcut, which launches the Inspector for you:uv run mcp dev server.pyคำสั่งจะพิมพ์ URL ที่มี session token แบบใช้ครั้งเดียว เปิดมันแล้วคุณจะได้แท็บ Tools ที่แสดง get-forecast, ฟอร์มที่สร้างจาก inputSchema ของมัน และ sidebar monitoring ที่แสดง JSON-RPC message ทุกตัวขณะวิ่งผ่าน — ทั้ง server/discover, tools/list และ tools/call ของคุณ การอ่าน pane นั้นเทียบกับบทเรียนก่อนหน้าคือวิธีที่เร็วที่สุดที่จะทำให้ wire format จับต้องได้
sequenceDiagram participant You as Browser participant I as Inspector participant S as server.ts (subprocess) You->>I: เปิด session URL I->>S: spawn, เขียน JSON-RPC ลง stdin I->>S: server/discover S-->>I: capabilities (tools) I->>S: tools/list S-->>I: get-forecast You->>I: กรอก city แล้วกด Run I->>S: tools/call get-forecast S-->>I: content: Sunny in Lisbon all week.
ตรวจแบบ script ได้จาก CLI
หัวข้อที่มีชื่อว่า “ตรวจแบบ script ได้จาก CLI”สำหรับ CI, shell pipeline หรือเช็กเร็ว ๆ package เดียวกันมีโหมด CLI ที่รัน method เดียวแล้วออก:
npx @modelcontextprotocol/inspector --cli npx tsx server.ts --method tools/listnpx @modelcontextprotocol/inspector --cli npx tsx server.ts \ --method tools/call --tool-name get-forecast --tool-arg city=Lisbonnpx @modelcontextprotocol/inspector --cli uv run server.py --method tools/listnpx @modelcontextprotocol/inspector --cli uv run server.py \ --method tools/call --tool-name get_forecast --tool-arg city=Lisbonเติม --format json แล้ว pipe ไป jq เมื่ออยาก assert กับ output
กฎทองของ stdio
หัวข้อที่มีชื่อว่า “กฎทองของ stdio”บน stdio stdout คือช่องทางของ protocol client อ่านมันทีละบรรทัดและ parse แต่ละบรรทัดเป็น JSON-RPC server ห้าม เขียนอย่างอื่นลงไป แค่ console.log("starting…") หรือ print("debug") หลุดมาบรรทัดเดียว client ก็จะเจอบรรทัดที่ไม่ใช่ JSON และ connection จะพังในแบบที่ดูเหมือน server ค้าง
ให้ log ไปที่ stderr แทน transport spec อนุญาตชัดเจนให้ server เขียน UTF-8 ลง stderr สำหรับ output แบบ informational, debug และ error และบอก client ว่าไม่ต้องถือว่า stderr เป็นสัญญาณ error
console.error('starting weather server'); // fine: stderr// console.log(...) // never in a stdio serverimport sysprint("starting weather server", file=sys.stderr) # fine: stderr# print("...") # never in a stdio serverกฎเดียวกันใช้กับ library ทุกตัวที่ server ของคุณ import: ถ้า dependency ตัวไหนพิมพ์ banner ลง stdout ตอน import มันจะทำ server ของคุณพังก่อน message แรกจะมาถึง
สิ่งที่คุณมีตอนนี้
หัวข้อที่มีชื่อว่า “สิ่งที่คุณมีตอนนี้”MCP server ที่ทำงานได้ วิธีทดลองใช้มัน และ wire traffic ที่พิสูจน์ว่ามันทำอะไรอยู่ จากตรงนี้คอร์สจะขยายออกไป: โมดูล Server Primitives เติม tools, resources และ prompts ลงใน server; โมดูล Transports ย้ายมันจาก subprocess ไปเป็น HTTPS endpoint