บทความ

บทนำ: คุณจะได้อะไรเมื่ออ่านคู่มือนี้จบ

ลองจินตนาการว่าคุณเปิดแชทกับ AI assistant แล้วพิมพ์ว่า «เข้าไปดูหน้าเว็บของคู่แข่ง รวบรวมชื่อและราคาสินค้าทั้งหมดจากแคตตาล็อก แล้วทำเป็นตารางให้หน่อย» ผู้ช่วยไม่ตอบว่า «ฉันเข้าอินเทอร์เน็ตไม่ได้» แต่โหลดหน้าเว็บจริง ดึงข้อมูลออกมา และส่งผลลัพธ์ที่พร้อมใช้งานกลับมาให้คุณ นั่นคือสิ่งที่คุณจะสร้างเมื่ออ่านคู่มือนี้จนจบ ตัวเชื่อมระหว่างโมเดลภาษาและเว็บก็คือ MCP server ของคุณเองที่เขียนด้วย Python

ขอออกตัวไว้ก่อน: เราจะไม่พูดถึง Playwright MCP สำเร็จรูปหรือโซลูชันแบบกล่องสำเร็จรูปอื่น ๆ เรื่องนั้นมีบทความแยกในบล็อกอยู่แล้ว เป้าหมายตรงนี้ต่างออกไป: เขียนเซิร์ฟเวอร์ตั้งแต่ศูนย์ เพื่อให้คุณเข้าใจทุกบรรทัด เพิ่มเครื่องมือของตัวเองได้ เชื่อมต่อ mobile proxy และปรับตรรกะให้เข้ากับงานเฉพาะของคุณ โซลูชันของตัวเองย่อมยืดหยุ่นกว่าของคนอื่นเสมอ

คู่มือนี้เหมาะกับใคร

  • นักการตลาดและเจ้าของธุรกิจ ที่ต้องเก็บราคา รีวิว คำอธิบายสินค้า และคอนเทนต์ของคู่แข่งอย่างรวดเร็ว โดยไม่ต้องสั่งทำ parser จากนักพัฒนา
  • นัก arbitrage ที่คอยติดตาม offer, landing page และ creative ต่าง ๆ และอยากมอบงานซ้ำ ๆ ให้ AI agent ทำแทน
  • นักพัฒนา ที่เคยได้ยินเรื่องโปรโตคอล MCP แต่ยังไม่เคยสร้างเซิร์ฟเวอร์เอง และอยากได้เทมเพลตที่ใช้งานได้จริง
  • ผู้ใช้ mobile proxy ที่ต้องการให้คำขอของ agent ออกผ่าน proxy ของตัวเอง ไม่ใช่ออกจาก IP ที่บ้านโดยตรง

สิ่งที่ควรรู้ก่อนเริ่ม

คู่มือนี้เขียนสำหรับผู้เริ่มต้น ไม่จำเป็นต้องมีประสบการณ์เขียนโปรแกรม แต่ถ้าเข้าใจว่า command line คืออะไรและเปิดไฟล์ในโปรแกรมแก้ไขข้อความได้ก็จะช่วยได้มาก โค้ดทั้งหมดคัดลอกไปใช้ได้ทั้งดุ้น และอธิบายทุกส่วนด้วยภาษาง่าย ๆ ถ้าคุณเขียน Python อยู่แล้ว มีบล็อกพิเศษเรื่องความสามารถขั้นสูงอยู่ช่วงท้ายบทความ

ต้องใช้เวลานานแค่ไหน

เผื่อเวลาไว้ 2-3 ชั่วโมง สำหรับรอบแรก การติดตั้งเครื่องมือใช้เวลาประมาณ 30 นาที MCP server ที่ทำงานได้ขั้นต่ำจะปรากฏภายในหนึ่งชั่วโมง และเวลาที่เหลือจะหมดไปกับการเพิ่มเครื่องมือดึงข้อมูล การเชื่อมต่อ proxy และการทดสอบ ถ้าทำซ้ำตั้งแต่ต้นบนคอมพิวเตอร์เครื่องอื่น คุณจะทำเสร็จภายใน 20-30 นาที

การเตรียมตัวล่วงหน้า: เครื่องมือ สิทธิ์การเข้าถึง และข้อกำหนดระบบ

ก่อนเขียนโค้ด ให้ตรวจสอบว่าคุณมีทุกอย่างครบแล้ว ส่วนนี้ใช้เวลาประมาณครึ่งชั่วโมง และจะช่วยลดปัญหาที่พบบ่อยลงได้ครึ่งหนึ่งในขั้นตอนถัดไป

ข้อกำหนดระบบ

  • คอมพิวเตอร์ที่ใช้ Windows 10/11, macOS 12 ขึ้นไป หรือ Linux (Ubuntu 22.04 ขึ้นไป) ทุกอย่างที่อธิบายใช้ได้กับทุกระบบ ต่างกันแค่พาธของไฟล์
  • หน่วยความจำอย่างน้อย 4 GB และพื้นที่ว่างบนดิสก์ 1 GB
  • การเชื่อมต่ออินเทอร์เน็ตที่เสถียร

สิ่งที่ต้องติดตั้ง

  1. Python 3.11 ขึ้นไป ในปี 2026 เวอร์ชันที่ใช้กันคือ 3.12 และ 3.13 ดาวน์โหลดตัวติดตั้งจากเว็บไซต์ทางการของโปรเจกต์ Python บน Windows ในหน้าต่างแรกของตัวติดตั้ง ต้องติ๊กถูกที่ Add python.exe to PATH ไม่งั้นคำสั่ง python จะหาไม่เจอในเทอร์มินัล บน macOS ติดตั้ง Python ผ่าน Homebrew ด้วยคำสั่ง brew install python สะดวกกว่า บน Ubuntu ให้รัน sudo apt install python3 python3-venv python3-pip
  2. โปรแกรมแก้ไขข้อความสำหรับเขียนโค้ด เราแนะนำ Visual Studio Code ฟรี มีการไฮไลต์ไวยากรณ์และแสดงข้อผิดพลาด โปรแกรมแก้ไขอื่นก็ใช้ได้ แม้แต่ Notepad แต่ VS Code จะสะดวกกว่า
  3. MCP client คือแอปที่มี AI agent ซึ่งคุณจะเชื่อมเซิร์ฟเวอร์เข้าไป ตัวเลือกที่ง่ายที่สุดสำหรับผู้เริ่มต้นคือ Claude Desktop นอกจากนี้ยังมี Cursor, VS Code ที่มีส่วนขยาย GitHub Copilot และเครื่องมืออื่น ๆ อีกหลายตัวที่รองรับ MCP ติดตั้งอย่างน้อยหนึ่งตัวก่อนเริ่มงาน
  4. Node.js 20 ขึ้นไป ไม่ได้ใช้กับตัวเซิร์ฟเวอร์ แต่ใช้กับยูทิลิตี้ MCP Inspector ที่เราจะใช้ดีบักเครื่องมือ ดาวน์โหลดตัวติดตั้งเวอร์ชัน LTS จากเว็บไซต์ทางการของ Node.js แล้วติดตั้งด้วยการตั้งค่าเริ่มต้น

สิทธิ์การเข้าถึง

สำหรับส่วนที่เกี่ยวกับ proxy คุณจะต้องมีข้อมูล mobile proxy: โฮสต์ พอร์ต ล็อกอิน และรหัสผ่าน รวมถึงลิงก์สำหรับเปลี่ยน IP หากแพ็กเกจของคุณรองรับ ทั้งหมดนี้อยู่ในหน้าสมาชิกของผู้ให้บริการ ถ้ายังไม่มี proxy ก็อ่านคู่มือนี้ได้โดยไม่ต้องมี: เซิร์ฟเวอร์จะทำงานโดยตรง แล้วค่อยเพิ่ม proxy ทีหลังด้วยโค้ดบรรทัดเดียว

การสำรองข้อมูล

เราจะแก้ไขไฟล์คอนฟิกของ MCP client ก่อนอื่นให้คัดลอกไปเก็บไว้ในที่ปลอดภัย เช่นบนเดสก์ท็อป โดยตั้งชื่อว่า «backup» ถ้ามีอะไรผิดพลาด ก็แค่เอาไฟล์สำรองกลับมาวาง ส่วนโค้ดของเซิร์ฟเวอร์ให้เก็บในโฟลเดอร์แยก และหลังจากแต่ละขั้นตอนที่ใช้ได้ ให้บันทึกสำเนาไฟล์หรือ commit ลง Git ถ้าคุณใช้เป็น

เคล็ดลับ: สร้างโฟลเดอร์แยกบนดิสก์ที่มีพาธสั้น ๆ ไม่มีช่องว่างและไม่มีอักษรซีริลลิก เช่น C:/mcp-collector บน Windows หรือ ~/mcp-collector บน macOS และ Linux ช่องว่างและตัวอักษรรัสเซียในพาธทำให้การรันเซิร์ฟเวอร์จากคอนฟิกล้มเหลวบ่อยครั้ง และคุณจะเสียเวลาเป็นชั่วโมงในการหาสาเหตุ

แนวคิดพื้นฐาน: MCP server ทำงานอย่างไรและทำไม AI agent ถึงต้องการมัน

ก่อนเขียนโค้ดบรรทัดแรก มาทำความรู้จักกับศัพท์ต่าง ๆ กันก่อน ถ้าไม่มีส่วนนี้ คำแนะนำจะดูเหมือนคาถาวิเศษ แต่ถ้ามี ทุกการกระทำจะมีเหตุผล

MCP คืออะไร

MCP (Model Context Protocol) คือโปรโตคอลเปิดที่อธิบายว่าโมเดลภาษาสื่อสารกับเครื่องมือภายนอกอย่างไร ก่อนหน้านี้แต่ละบริการคิดวิธี «มอบมือให้ AI» ของตัวเอง MCP ทำให้เป็นมาตรฐาน: ถ้าคุณเขียนเซิร์ฟเวอร์ตามโปรโตคอล ไคลเอนต์ที่เข้ากันได้จะเข้าใจ ไม่ว่าจะเป็น Claude Desktop, Cursor หรือ agent ของคุณเอง เปรียบได้กับพอร์ต USB: ต่ออะไรก็ได้ ไม่ว่าจะเป็นแฟลชไดรฟ์หรือเมาส์ พอร์ตก็เป็นแบบเดียวกัน

Client และ Server

ในสถาปัตยกรรม MCP มีสองฝ่าย Client คือแอปที่มี AI ซึ่งถามคำถามและเรียกใช้เครื่องมือ MCP server คือโปรแกรมที่ให้เครื่องมือเหล่านั้น ในกรณีของเรา เซิร์ฟเวอร์จะเป็นความสามารถ «เข้าอินเทอร์เน็ตและดึงข้อมูล» และไคลเอนต์คือ AI assistant ของคุณ เซิร์ฟเวอร์รันบนเครื่องของคุณเอง และไคลเอนต์สื่อสารกับมันโดยตรง

Tools, Resources และ Prompts

MCP server สามารถส่งมอบสิ่งที่ไคลเอนต์เรียกใช้ได้สามประเภท:

  • Tools — ฟังก์ชันที่โมเดลเรียกได้: «โหลดหน้าเว็บ», «ดึงลิงก์ทั้งหมด», «เปลี่ยน IP ของ proxy» นี่คือพื้นฐานของคู่มือนี้
  • Resources — ข้อมูลที่เซิร์ฟเวอร์ให้อ่าน เช่นเนื้อหาไฟล์ตั้งค่าหรือผลลัพธ์การเก็บข้อมูลครั้งล่าสุด
  • Prompts — เทมเพลตคำขอสำเร็จรูปที่ผู้ใช้เรียกได้ด้วยคำสั่งเดียว

สำหรับการเก็บข้อมูล แค่ tools ก็เพียงพอ ส่วน resources และ prompts เราจะพูดถึงในบล็อกขั้นสูง

โมเดลรู้ได้อย่างไรว่าต้องเรียกอะไร

ตรงนี้มีจุดสำคัญ เมื่อไคลเอนต์เชื่อมต่อกับเซิร์ฟเวอร์ มันจะขอรายการเครื่องมือพร้อม ชื่อ คำอธิบาย และพารามิเตอร์ คำอธิบายเหล่านี้จะเข้าไปอยู่ในบริบทของโมเดล จากนั้นโมเดลจะตัดสินใจเองว่าจะเรียกเครื่องมือไหนด้วยอาร์กิวเมนต์อะไร โดยอิงจากข้อความคำอธิบายนั่นเอง ดังนั้นคำอธิบายฟังก์ชันในโค้ดของเราไม่ใช่แค่พิธีการ แต่เป็นคำสั่งสำหรับ AI ยิ่งคุณเขียนชัดเจนว่าเครื่องมือทำอะไรและใช้เมื่อไหร่ agent ก็จะทำงานได้แม่นยำขึ้น

Transport: stdio และ HTTP

เซิร์ฟเวอร์และไคลเอนต์ต้องแลกเปลี่ยนข้อความกัน โปรโตคอลมีสองวิธีหลัก stdio — ไคลเอนต์รันสคริปต์ของคุณเป็นโปรเซสลูกและสื่อสารผ่าน standard input/output นี่คือวิธีที่ง่ายที่สุดสำหรับการทำงานในเครื่อง และเราจะเริ่มจากวิธีนี้ Streamable HTTP — เซิร์ฟเวอร์ทำงานเป็นเว็บเซอร์วิสที่ไคลเอนต์เชื่อมต่อผ่านที่อยู่ วิธีนี้จำเป็นเมื่อเซิร์ฟเวอร์อยู่บนเครื่องระยะไกลหรือมีไคลเอนต์หลายตัวเชื่อมต่อ เราจะพูดถึงในบล็อกขั้นสูง

⚠️ ระวัง: เมื่อใช้ transport แบบ stdio standard output ทั้งหมดของโปรเซสจะถูกใช้สำหรับข้อความโปรโตคอล ถ้าคุณเขียน print ธรรมดาในโค้ดเพื่อดีบัก ไคลเอนต์จะได้ขยะแทนคำตอบที่ถูกต้องและตัดการเชื่อมต่อ ข้อความดีบักให้ส่งไปที่ stderr เท่านั้น จำกฎนี้ไว้ จะช่วยคุณได้มาก

ทำไมการเก็บข้อมูลผ่าน MCP ถึงสะดวก

parser แบบดั้งเดิมถูกกำหนดตายตัว: เก็บฟิลด์เฉพาะจากเว็บไซต์เฉพาะ พอโครงสร้างเว็บเปลี่ยน parser ก็พัง ส่วนการผสมผสาน «AI agent บวก MCP server» ทำงานต่างออกไป: เซิร์ฟเวอร์ให้เครื่องมืออเนกประสงค์ (โหลด ดึงข้อความ หาองค์ประกอบด้วย selector) และโมเดลจะวิเคราะห์โครงสร้างหน้าเว็บเองและสรุปผลลัพธ์ คุณได้ความยืดหยุ่นโดยไม่ต้องเขียนโค้ดใหม่สำหรับทุกแหล่งข้อมูลใหม่

ขั้นตอนที่ 1: สร้างโปรเจกต์และติดตั้ง dependencies

เป้าหมายของขั้นนี้: เตรียมสภาพแวดล้อม Python แยกส่วนและติดตั้งไลบรารีที่จำเป็นสำหรับ MCP server เมื่อจบขั้นตอนนี้คุณจะมีโฟลเดอร์โปรเจกต์ที่มี virtual environment พร้อมใช้งาน

ทำไมต้องมี virtual environment

Virtual environment คือสำเนา Python แยกต่างหากที่มีไลบรารีของตัวเองอยู่ในโฟลเดอร์โปรเจกต์ จำเป็นเพื่อให้เซิร์ฟเวอร์ของเราไม่ขัดแย้งกับโปรแกรม Python อื่นบนเครื่อง และ MCP client รู้แน่ชัดว่าจะรัน interpreter ตัวไหน ถ้าไม่มี ปัญหา «ในเทอร์มินัลใช้ได้ แต่ในไคลเอนต์ใช้ไม่ได้» รับประกันว่าจะเจอครึ่งหนึ่ง

ขั้นตอนทีละขั้น

  1. เปิดเทอร์มินัล บน Windows กด Win+R พิมพ์ powershell แล้วกด Enter บน macOS เปิดแอป Terminal ผ่าน Spotlight (Cmd+Space แล้วพิมพ์ Terminal) บน Linux กด Ctrl+Alt+T
  2. สร้างโฟลเดอร์โปรเจกต์และเข้าไปในนั้น บน Windows รันสองคำสั่ง: mkdir C:/mcp-collector แล้ว cd C:/mcp-collector บน macOS และ Linux: mkdir ~/mcp-collector แล้ว cd ~/mcp-collector
  3. ตรวจสอบเวอร์ชัน Python ด้วยคำสั่ง python --version (บน macOS และ Linux อาจต้องใช้ python3 --version) คุณควรเห็นบรรทัดแบบ Python 3.12.x ถ้าเวอร์ชันต่ำกว่า 3.11 หรือไม่พบคำสั่ง ให้กลับไปที่ส่วนการเตรียมตัวและติดตั้ง Python ใหม่
  4. สร้าง virtual environment ด้วยคำสั่ง python -m venv .venv จะมีโฟลเดอร์ซ่อน .venv ปรากฏในโฟลเดอร์โปรเจกต์ ใช้เวลา 10-20 วินาที
  5. เปิดใช้งาน environment บน Windows ใน PowerShell: .venv/Scripts/Activate.ps1 ถ้า PowerShell แจ้งว่าห้ามรันสคริปต์ ให้รันคำสั่ง Set-ExecutionPolicy -Scope CurrentUser RemoteSigned ยืนยันด้วยตัว Y แล้วเปิดใช้งานอีกครั้ง บน macOS และ Linux: source .venv/bin/activate หลังเปิดใช้งาน จะมีเครื่องหมาย (.venv) ปรากฏที่ต้นบรรทัดของเทอร์มินัล
  6. อัปเดตตัวจัดการแพ็กเกจ: python -m pip install --upgrade pip
  7. ติดตั้งไลบรารีด้วยคำสั่งเดียว: pip install "mcp[cli]" httpx beautifulsoup4 โดย mcp คือ Python SDK ทางการของโปรโตคอล (ในปี 2026 สาย 1.x คือเวอร์ชันที่ใช้กัน) httpx คือไลบรารี HTTP ที่ทันสมัยรองรับ proxy และ beautifulsoup4 คือเครื่องมือสำหรับแยกวิเคราะห์ HTML การติดตั้งใช้เวลา 1-2 นาที
  8. สร้างไฟล์ว่างชื่อ server.py ในโฟลเดอร์โปรเจกต์ ใน VS Code: เปิดโฟลเดอร์ผ่าน File, Open Folder แล้วกดไอคอนไฟล์ใหม่ในแถบด้านซ้ายและพิมพ์ชื่อ

ไลบรารีแต่ละตัวทำอะไร

  • mcp ดูแลโปรโตคอลทั้งหมด: การลงทะเบียนเครื่องมือ การแลกเปลี่ยนข้อความ การอธิบายพารามิเตอร์ โมดูล FastMCP ที่อยู่ข้างในทำให้เราประกาศเครื่องมือเป็นฟังก์ชันธรรมดาที่มี decorator ได้
  • httpx ใช้โหลดหน้าเว็บ ต่างจาก requests ที่เก่ากว่า ตัวนี้รองรับ HTTP/2, async และตั้งค่า proxy ได้สะดวก
  • beautifulsoup4 เปลี่ยน HTML เป็นโครงสร้างต้นไม้ที่ค้นหาองค์ประกอบตามแท็กและ CSS selector ได้ง่าย

เคล็ดลับ: จดพาธเต็มของ interpreter ใน virtual environment ไว้เลย บน Windows คือ C:/mcp-collector/.venv/Scripts/python.exe บน macOS และ Linux คือ /Users/ชื่อ/mcp-collector/.venv/bin/python (หรือ /home/ชื่อ/... บน Linux) จำเป็นตอนเชื่อมต่อกับไคลเอนต์ ดูพาธที่แน่นอนได้ด้วยคำสั่ง where python บน Windows หรือ which python บน macOS และ Linux ขณะเปิดใช้งาน environment

✅ ตรวจสอบ: รันคำสั่ง pip list ในรายการต้องมีแพ็กเกจ mcp, httpx และ beautifulsoup4 จากนั้นรัน python -c "import mcp, httpx, bs4; print('ok')" ควรได้คำว่า ok โดยไม่มีข้อผิดพลาด

ปัญหาที่อาจเจอ

  • หาคำสั่ง python ไม่เจอ บน Windows ให้ติดตั้ง Python ใหม่พร้อมติ๊ก Add to PATH บน macOS ใช้ python3 แทน python
  • pip แจ้งปัญหาสิทธิ์การเข้าถึง น่าจะเป็นเพราะ environment ยังไม่เปิดใช้งาน และคุณกำลังติดตั้งแพ็กเกจลง Python ระบบ ตรวจสอบเครื่องหมาย (.venv) ที่ต้นบรรทัด
  • เกิดข้อผิดพลาดตอน build อัปเดต pip แล้วลองใหม่ ถ้ายังไม่หาย ให้ตรวจสอบว่าเวอร์ชัน Python ไม่ต่ำกว่า 3.11

ขั้นตอนที่ 2: เขียน MCP server ขั้นต่ำพร้อมเครื่องมือแรก

เป้าหมายของขั้นนี้: เขียน MCP server ที่ใช้งานได้พร้อมเครื่องมือหนึ่งตัว ซึ่งโหลดหน้าเว็บตามที่อยู่และคืนค่า HTML นี่คือรากฐานที่เราจะต่อยอดเพิ่มฟีเจอร์

โค้ดของเซิร์ฟเวอร์

เปิดไฟล์ server.py แล้ววางโค้ดต่อไปนี้ทั้งดุ้น:

import sys
import httpx
from mcp.server.fastmcp import FastMCP

mcp = FastMCP('web-collector')

HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0 Safari/537.36',
'Accept-Language': 'ru-RU,ru;q=0.9,en;q=0.8',
}

def log(message: str) -> None:
print(message, file=sys.stderr)

@mcp.tool()
def fetch_page(url: str, max_chars: int = 20000) -> str:
'''Скачивает страницу по указанному URL и возвращает её HTML-код.
Используй, когда нужно посмотреть исходную разметку страницы.
Параметр max_chars ограничивает длину ответа, чтобы не переполнять контекст.'''
log(f'fetch_page: {url}')
with httpx.Client(headers=HEADERS, timeout=20.0, follow_redirects=True) as client:
response = client.get(url)
response.raise_for_status()
return response.text[:max_chars]

if __name__ == '__main__':
mcp.run()

อธิบายโค้ดทีละบรรทัด

  1. FastMCP('web-collector') สร้างออบเจกต์เซิร์ฟเวอร์ชื่อ web-collector ชื่อนี้ไคลเอนต์จะแสดงในรายการเซิร์ฟเวอร์ที่เชื่อมต่อ
  2. HEADERS คือ header ที่เราส่งไปยังเว็บไซต์ หลายเว็บส่งคอนเทนต์ไม่ครบหรือส่ง error ถ้าคำขอมาโดยไม่มี User-Agent แบบเบราว์เซอร์ที่คุ้นเคย header Accept-Language บอกว่าเราต้องการหน้าเว็บเวอร์ชันภาษารัสเซีย
  3. ฟังก์ชัน log เขียนข้อความไปที่ stderr แบบนี้ ไม่ใช่ผ่าน print ธรรมดา เพราะ stdout ถูกใช้โดยโปรโตคอล ข้อความเหล่านี้คุณจะเห็นใน log ของไคลเอนต์และใน MCP Inspector
  4. @mcp.tool() คือ decorator ที่เปลี่ยนฟังก์ชันธรรมดาให้เป็นเครื่องมือ MCP SDK จะอ่านชื่อฟังก์ชัน ชนิดพารามิเตอร์ และ docstring โดยอัตโนมัติ แล้วสร้างคำอธิบายสำหรับโมเดล ค่าเริ่มต้น max_chars = 20000 หมายความว่าพารามิเตอร์นี้ไม่บังคับ
  5. Docstring ในเครื่องหมายคำพูดสามชั้นคือสิ่งที่ AI จะอ่าน เราอธิบายตรงนี้ว่าเครื่องมือทำอะไรและใช้เมื่อไหร่ เขียนคำอธิบายให้ละเอียดและเป็นภาษาที่คุณใช้สื่อสารกับ agent
  6. httpx.Client ที่มีพารามิเตอร์ follow_redirects=True จะตาม redirect อัตโนมัติ และ timeout=20.0 ไม่ให้คำขอค้างไม่จำกัด
  7. raise_for_status() โยน error ถ้าเว็บส่งคืนรหัส 4xx หรือ 5xx SDK จะดักจับและส่งข้อความ error ที่เข้าใจได้ให้ไคลเอนต์แทนความเงียบ
  8. mcp.run() เริ่มเซิร์ฟเวอร์ด้วย transport แบบ stdio ตามค่าเริ่มต้น มันจะรอคำสั่งจากไคลเอนต์

ทดสอบครั้งแรกผ่าน MCP Inspector

การรัน server.py โดยตรงไม่มีประโยชน์ เพราะมันจะรอข้อความจากไคลเอนต์และไม่แสดงอะไร สำหรับการทดสอบ เราใช้ MCP Inspector — เว็บอินเทอร์เฟซที่จำลองไคลเอนต์และให้เราเรียกเครื่องมือด้วยมือ

  1. ตรวจสอบว่า virtual environment เปิดใช้งานอยู่และคุณอยู่ในโฟลเดอร์โปรเจกต์
  2. รันคำสั่ง mcp dev server.py คำสั่งนี้อยู่ในแพ็กเกจ mcp ที่ติดตั้งพร้อมส่วนขยาย cli ครั้งแรกที่รันจะดาวน์โหลด Inspector ผ่าน npx ใช้เวลาประมาณหนึ่งนาที
  3. ในเทอร์มินัลจะมีที่อยู่แบบ http://localhost:6274 และในเวอร์ชันใหม่จะมี token การเข้าถึงด้วย เปิดที่อยู่ในเบราว์เซอร์ (บ่อยครั้งมันเปิดเอง)
  4. ในแผงด้านซ้ายของ Inspector ตรวจสอบว่าเลือก transport เป็น STDIO, command เป็น python, args เป็น server.py กดปุ่ม Connect
  5. ตัวบอกสถานะจะเปลี่ยนเป็นสีเขียวพร้อมข้อความ Connected ไปที่แท็บ Tools ในเมนูด้านบนแล้วกด List Tools
  6. ในรายการจะมีเครื่องมือ fetch_page พร้อมคำอธิบายจาก docstring และพารามิเตอร์สองตัว คลิกที่มัน
  7. ในช่อง url พิมพ์ https://example.com ช่อง max_chars ปล่อยว่างหรือใส่ 5000 กด Run Tool
  8. ทางขวาจะมีผลลัพธ์: โค้ด HTML ของหน้าเว็บที่ขึ้นต้นด้วยแท็ก doctype ด้านล่างในแท็บ log ของเซิร์ฟเวอร์ จะเห็นบรรทัด fetch_page: https://example.com

✅ ตรวจสอบ: Inspector แสดงสถานะ Connected ในรายการ Tools มี fetch_page การเรียกด้วยที่อยู่ example.com คืนค่า HTML โดยไม่มี error ถ้าเป็นแบบนี้ MCP server ตัวแรกของคุณก็ทำงานได้แล้ว

ปัญหาที่อาจเจอ

  • mcp dev บอกว่าหา npx ไม่เจอ ยังไม่ได้ติดตั้ง Node.js ติดตั้งแล้วรีสตาร์ทเทอร์มินัล
  • Inspector เปิดได้ แต่ Connect ขึ้น error ตรวจสอบว่าช่อง command ระบุ python จาก environment ที่เปิดใช้งานอยู่ ใส่พาธเต็มของ python.exe ใน .venv ก็ได้
  • SyntaxError ตอนเชื่อมต่อ โค้ดถูกคัดลอกโดย indent หาย ใน Python indent เป็นสิ่งจำเป็น: เนื้อหาฟังก์ชันต้องเยื้องสี่ช่องว่าง ตรวจสอบไฟล์ในโปรแกรมแก้ไข
  • เครื่องมือคืน error 403 เว็บไม่รับคำขอ สำหรับ example.com จะไม่เกิด แต่สำหรับเว็บจริงเราจะกลับมาที่เรื่องนี้ในขั้นตอน proxy

ขั้นตอนที่ 3: เชื่อมต่อ MCP server กับ AI client

เป้าหมายของขั้นนี้: ลงทะเบียนเซิร์ฟเวอร์ในค่าตั้งของ AI client เพื่อให้ agent เห็นเครื่องมือของคุณและเรียกใช้จากแชทปกติได้ เราจะอธิบายการเชื่อมต่อกับ Claude Desktop ซึ่งเป็นตัวที่ใช้กันแพร่หลายที่สุด และแนะนำทางเลือกอื่นสั้น ๆ

เชื่อมต่อกับ Claude Desktop

  1. เปิด Claude Desktop เข้าไปที่การตั้งค่า: บน Windows ผ่านเมนูมุมซ้ายบน หัวข้อ Settings; บน macOS ผ่านเมนู Claude หัวข้อ Settings
  2. ไปที่แท็บ Developer แล้วกดปุ่ม Edit Config โฟลเดอร์ที่มีไฟล์ claude_desktop_config.json จะเปิดขึ้น ถ้าไม่มีไฟล์ ไคลเอนต์จะสร้างให้
  3. สำรองไฟล์นี้โดยคัดลอกไปวางบนเดสก์ท็อป
  4. เปิดไฟล์ใน VS Code หรือโปรแกรมแก้ไขอื่น ถ้าไฟล์ว่าง ให้วางเนื้อหาทั้งดุ้น ถ้ามีเซิร์ฟเวอร์อื่นอยู่แล้ว ให้เพิ่มบล็อกของคุณเข้าไปในออบเจกต์ mcpServers คั่นด้วยเครื่องหมายจุลภาค
{
"mcpServers": {
"web-collector": {
"command": "C:/mcp-collector/.venv/Scripts/python.exe",
"args": ["C:/mcp-collector/server.py"]
}
}
}

บน macOS และ Linux ให้เปลี่ยนพาธเป็นของคุณ เช่น /Users/ivan/mcp-collector/.venv/bin/python และ /Users/ivan/mcp-collector/server.py สังเกตว่าแม้บน Windows พาธก็เขียนด้วย สแลชตรง แบบนี้ง่ายกว่า เพราะแบ็กสแลชใน JSON ต้องเขียนซ้ำสองตัว แต่สแลชตรง Windows เข้าใจได้ไม่มีปัญหา

  1. บันทึกไฟล์ ตรวจสอบว่าไม่มีจุลภาคเกินหลังรายการสุดท้ายและวงเล็บปิดครบ จุลภาคเกินตัวเดียวทำให้ JSON ไม่ถูกต้อง และไคลเอนต์จะเมินคอนฟิกโดยไม่แจ้ง
  2. ปิด Claude Desktop ให้สนิท แล้วเปิดใหม่ บน Windows แค่ปิดหน้าต่างไม่พอ: คลิกขวาที่ไอคอนใน system tray แล้วเลือก Quit ไคลเอนต์อ่านคอนฟิกเฉพาะตอนเริ่มต้นเท่านั้น
  3. หลังเปิด ให้เปิดแชทใหม่ ใต้ช่องพิมพ์ หาไอคอนเครื่องมือ (รูปสไลเดอร์หรือปลั๊ก) คลิกดู: ในรายการต้องมีเซิร์ฟเวอร์ web-collector พร้อมเครื่องมือ fetch_page หนึ่งตัว
  4. พิมพ์ในแชทว่า: «โหลดหน้า https://example.com ด้วย fetch_page แล้วบอกว่าหน้านี้มีหัวข้ออะไร» ไคลเอนต์จะขออนุญาตเรียกเครื่องมือ กด Allow หรือ Allow for this chat
  5. ผ่านไปสองสามวินาที agent จะตอบว่าหัวข้อของหน้าคือ Example Domain มันส่งคำขอจริงผ่านเซิร์ฟเวอร์ของคุณ

เชื่อมต่อกับ Cursor และ VS Code

ใน Cursor เปิด Settings หัวข้อ MCP กด Add new global MCP server ไฟล์ mcp.json จะเปิดขึ้นโดยมีโครงสร้างเหมือน Claude Desktop วางบล็อกเดียวกันแล้วบันทึก ใน VS Code ที่ใช้ Copilot สร้างไฟล์ .vscode/mcp.json ในรากโฟลเดอร์งาน โดยใช้คีย์ servers แทน mcpServers ข้างในมี command และ args เหมือนกัน หลังบันทึกจะมีปุ่ม Start ปรากฏเหนือบล็อกเซิร์ฟเวอร์ ในทุกไคลเอนต์หลักการเหมือนกัน: ระบุคำสั่งรัน interpreter และพาธไปยังสคริปต์

เคล็ดลับ: ใน command ให้ระบุ python จาก virtual environment ไม่ใช่แค่คำว่า python ไคลเอนต์รันโปรเซสด้วยชุด environment variable ของตัวเอง และคำสั่ง python ของระบบอาจเป็นอีกเวอร์ชันที่ไม่มีไลบรารีที่ติดตั้งไว้ พาธเต็ม eliminates ปัญหานี้ได้ตลอดไป

✅ ตรวจสอบ: ในอินเทอร์เฟซไคลเอนต์เห็นเซิร์ฟเวอร์ web-collector agent เรียก fetch_page เมื่อขอ และเล่าเนื้อหาหน้า example.com ได้ถูกต้อง ใน log ของไคลเอนต์ (ใน Claude Desktop คือโฟลเดอร์ logs ข้างคอนฟิก ไฟล์ mcp-server-web-collector.log) เห็นบรรทัด fetch_page: https://example.com

ปัญหาที่อาจเจอ

  • เซิร์ฟเวอร์ไม่ปรากฏในรายการ ตรวจสอบ JSON ว่าถูกต้อง: วางเนื้อหาในตัวตรวจสอบ JSON ออนไลน์หรือเปิดใน VS Code ซึ่งจะขีดเส้นใต้จุดผิด ตรวจสอบว่าไคลเอนต์รีสตาร์ทสนิทแล้ว
  • มีตัวบอก error สีแดงข้างเซิร์ฟเวอร์ เปิดไฟล์ log ส่วนใหญ่จะเป็น ModuleNotFoundError: ระบุ python ผิดตัว ตรวจสอบพาธใน command
  • Agent บอกว่าเข้าอินเทอร์เน็ตไม่ได้ มันไม่เห็นเครื่องมือ ตรวจสอบว่าเปิดใช้เครื่องมือในแผงสไลเดอร์แล้ว และขอให้ชัดเจนว่า «ใช้เครื่องมือ fetch_page»
  • Error spawn ENOENT พาธไปยัง python หรือ server.py ผิด คัดลอกพาธจาก file explorer แล้วเปลี่ยนแบ็กสแลชเป็นสแลชตรง

ขั้นตอนที่ 4: เพิ่มเครื่องมือดึงข้อมูล

เป้าหมายของขั้นนี้: สอนเซิร์ฟเวอร์ให้ส่งไม่ใช่ HTML ดิบ แต่เป็นข้อมูลที่มีประโยชน์: ข้อความล้วน รายการลิงก์ และองค์ประกอบตาม CSS selector หลังจากนี้ agent จะเก็บข้อมูลที่มีโครงสร้างได้โดยไม่เปลืองบริบทไปกับ markup

ทำไม fetch_page ตัวเดียวไม่พอ

HTML ของหน้าจริงมีน้ำหนักหลายร้อยกิโลไบต์ และส่วนใหญ่เป็นสคริปต์ สไตล์ และ markup ที่ไม่เกี่ยวข้อง ถ้าส่งทั้งหมดให้โมเดลทุกครั้ง มันจะชนลิมิตบริบทอย่างรวดเร็ว และคุณจะจ่ายค่าโทเคนเกิน กลยุทธ์ที่ถูกต้องคือ: เซิร์ฟเวอร์ทำการกรองและจัดโครงสร้างข้อมูลคร่าว ๆ แล้วโมเดลทำงานกับข้อมูลที่กะทัดรัดแล้ว ดังนั้นเราจะเพิ่มเครื่องมือเฉพาะทางอีกสามตัว

โค้ดเวอร์ชันอัปเดต

แทนที่เนื้อหาใน server.py ด้วยเวอร์ชันขยาย ฟังก์ชัน fetch_page ยังอยู่ แต่ตรรกะการโหลดทั่วไปถูกแยกออกมาเป็นฟังก์ชัน _get_html ที่เครื่องมือทุกตัวใช้ร่วมกัน

import sys
from urllib.parse import urljoin
import httpx
from bs4 import BeautifulSoup
from mcp.server.fastmcp import FastMCP

mcp = FastMCP('web-collector')

HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0 Safari/537.36',
'Accept-Language': 'ru-RU,ru;q=0.9,en;q=0.8',
}

def log(message: str) -> None:
print(message, file=sys.stderr)

def _get_html(url: str) -> str:
log(f'GET {url}')
with httpx.Client(headers=HEADERS, timeout=20.0, follow_redirects=True) as client:
response = client.get(url)
response.raise_for_status()
return response.text

def _clean(text: str) -> str:
return ' '.join(text.split())

@mcp.tool()
def fetch_page(url: str, max_chars: int = 20000) -> str:
'''Возвращает сырой HTML страницы. Используй только когда нужна именно разметка,
например чтобы подобрать CSS-селектор. Для чтения содержимого используй extract_text.'''
return _get_html(url)[:max_chars]

@mcp.tool()
def extract_text(url: str, max_chars: int = 15000) -> str:
'''Возвращает чистый текст страницы без скриптов, стилей и разметки.
Лучший выбор, когда нужно прочитать статью, описание товара или отзывы.'''
soup = BeautifulSoup(_get_html(url), 'html.parser')
for tag in soup(['script', 'style', 'noscript', 'svg', 'header', 'footer', 'nav']):
tag.decompose()
title = _clean(soup.title.get_text()) if soup.title else ''
body = _clean(soup.get_text(' '))
return f'Заголовок: {title}. Текст: {body}'[:max_chars]

@mcp.tool()
def extract_links(url: str, limit: int = 100, contains: str = '') -> list[dict]:
'''Возвращает список ссылок со страницы: текст ссылки и полный адр��с.
Параметр contains фильтрует ссылки, в адресе которых есть указанная подстрока,
например /product/ или /catalog/.'''
soup = BeautifulSoup(_get_html(url), 'html.parser')
result = []
seen = set()
for a in soup.find_all('a', href=True):
full = urljoin(url, a['href'])
if full in seen or (contains and contains not in full):
continue
seen.add(full)
result.append({'text': _clean(a.get_text())[:120], 'url': full})
if len(result) >= limit:
break
return result

@mcp.tool()
def select_elements(url: str, css_selector: str, limit: int = 50) -> list[str]:
'''Находит на странице элементы по CSS-селектору и возвращает их текст.
Примеры селекторов: h2, .price, div.product-card, table tr.
Используй, когда нужны конкретные повторяющиеся блоки: цены, названия, строки таблицы.'''
soup = BeautifulSoup(_get_html(url), 'html.parser')
elements = soup.select(css_selector)[:limit]
return [_clean(el.get_text(' ')) for el in elements]

if __name__ == '__main__':
mcp.run()

แต่ละเครื่องมือทำอะไร

  1. extract_text ลบสคริปต์ สไตล์ header footer และเมนูออกจากเอกสาร แล้วรวมข้อความที่เหลือเป็นบรรทัดเดียวโดยมีช่องว่างเดี่ยว ฟังก์ชัน _clean ใช้ split และ join ลบการขึ้นบรรทัดใหม่และแท็บที่ไม่จำเป็น หัวข้อของหน้าจะถูกเพิ่มไว้ต้นคำตอบ เพื่อให้ agent เข้าใจทันทีว่ากำลังดูอะไรอยู่
  2. extract_links รวบรวมแท็ก a ทั้งหมด เปลี่ยนที่อยู่สัมพัทธ์เป็นที่อยู่เต็มด้วย urljoin ลบรายการซ้ำผ่านเซ็ต seen และให้กรองลิงก์ตามสตริงย่อยได้ ดังนั้น agent จึงได้การ์ดสินค้าทั้งหมดจากแคตตาล็อกในคำขอเดียว
  3. select_elements คือเครื่องมือที่ทรงพลังที่สุด มันรับ CSS selector และคืนข้อความขององค์ประกอบที่พบ agent สามารถดู HTML ส่วนหนึ่งผ่าน fetch_page ก่อน เข้าใจว่าราคาอยู่ในคลาส price แล้วค่อยเรียก select_elements ด้วย selector .price

สังเกต docstring: เราบอกใบ้โมเดลอย่างชัดเจนว่าเครื่องมือไหนควรใช้ในสถานการณ์ไหน ช่วยให้คุณภาพการทำงานของ agent ดีขึ้นชัดเจน

วิธีทดสอบ

  1. รัน mcp dev server.py และเชื่อมต่อใน Inspector ในรายการ Tools ตอนนี้มีสี่เครื่องมือ
  2. เรียก extract_links ด้วย url ของเว็บข่าวหรือแคตตาล็อกใดก็ได้ และพารามิเตอร์ contains เป็นส่วนหนึ่งของที่อยู่หมวด ผลลัพธ์คือรายการออบเจกต์ที่มีฟิลด์ text และ url
  3. เรียก select_elements ด้วยที่อยู่เดิมและ selector h2 คุณจะได้รายการหัวข้อ
  4. รีสตาร์ท Claude Desktop (ไม่ต้องแก้คอนฟิก เพราะแก้แค่โค้ด) แล้วขอว่า: «เก็บหัวข้อ h2 ทั้งหมดจากหน้าแรกของเว็บนั้น และลิงก์ที่นำไปยังหมวดข่าว แล้วทำเป็นตาราง»

เคล็ดลับ: ถ้าไม่รู้ว่าต้องใช้ selector อะไร เปิดหน้าเว็บในเบราว์เซอร์ กด F12 เลือกเครื่องมือเลือกองค์ประกอบ (ไอคอนลูกศรมุมซ้ายบนของแผง) แล้วคลิกที่บล็อกที่ต้องการ ในโค้ดจะเห็นคลาสของมัน selector ที่มีจุดและชื่อคลาส เช่น .product-title มักใช้ได้ ยิ่งไปกว่านั้น คุณขอ agent ได้เลยว่า: «โหลด HTML แล้วเลือก selector สำหรับราคาเอง»

✅ ตรวจสอบ: ทั้งสี่เครื่องมือปรากฏใน Inspector และไคลเอนต์ extract_text คืนข้อความที่อ่านได้โดยไม่มีแท็ก extract_links คืนรายการที่มีที่อยู่เต็ม select_elements ด้วย selector h2 คืนหัวข้อ

ปัญหาที่อาจเจอ

  • select_elements คืนรายการว่าง อาจเป็นเพราะ selector ผิด หรือคอนเทนต์ถูกโหลดด้วย JavaScript หลังหน้าโหลดเสร็จ ตรวจสอบผ่าน fetch_page: ถ้า HTML ไม่มีข้อมูลที่ต้องการ เว็บเรนเดอร์ที่ฝั่งไคลเอนต์ สำหรับเว็บแบบนี้ต้องใช้เอนจินเบราว์เซอร์ ซึ่งเป็นเรื่องของบทความแยก
  • extract_text แสดงตัวอักษรเพี้ยน เว็บส่ง encoding ที่ไม่มาตรฐาน เพิ่มบรรทัด response.encoding = response.charset_encoding or 'utf-8' หลัง response.raise_for_status()
  • คำตอบถูกตัด เพิ่ม max_chars ในการเรียก หรือขอให้ agent ขอหน้าเว็บเป็นส่วน ๆ ผ่าน selector หลายตัว

ขั้นตอนที่ 5: เชื่อมต่อ mobile proxy และการหมุน IP

เป้าหมายของขั้นนี้: ส่งคำขอทั้งหมดของ MCP server ผ่าน mobile proxy เพิ่มเครื่องมือเปลี่ยน IP และตรวจสอบที่อยู่ปัจจุบัน หลังจากนี้ agent จะทำงานในนามของผู้ให้บริการมือถือ ไม่ใช่จาก IP ที่บ้านหรือที่ออฟฟิศของคุณ

ทำไมนักเก็บข้อมูลต้องใช้ mobile proxy

เมื่อคุณเก็บข้อมูลจาก IP เดียว เว็บจะเห็นคำขอซ้ำ ๆ หลายสิบครั้งติดกันและเริ่มส่ง captcha คอนเทนต์ที่ถูกตัด หรือ error 429 «คำขอมากเกินไป» Mobile proxy แก้ปัญหาหลายอย่างพร้อมกัน อย่างแรก ที่อยู่เป็นของผู้ให้บริการมือถือจริง และที่อยู่แบบนี้มีผู้ใช้หลายพันคนแชร์กัน เว็บจึงมองอย่างเป็นมิตรกว่า อย่างที่สอง คุณเปลี่ยน IP ตามลิงก์หรือตามเวลาได้ กระจายโหลด อย่างที่สาม คุณแยกกิจกรรมการทำงานของ agent ออกจากเซสชันส่วนตัวของคุณ สำหรับนักการตลาดยังเป็นวิธีเห็นเว็บอย่างที่ผู้ใช้มือถือในภูมิภาคนั้นเห็นอีกด้วย

⚠️ ระวัง: Proxy เป็นเครื่องมือสำหรับให้ตัวเก็บข้อมูลทำงานเสถียรและถูกต้อง ไม่ใช่เพื่อละเมิดกฎ เก็บเฉพาะข้อมูลที่เข้าถึงได้สาธารณะ ปฏิบัติตามเงื่อนไขการใช้งานของเว็บไซต์และไฟล์ robots.txt ไม่สร้างโหลดเกินจำเป็น และไม่เก็บข้อมูลส่วนบุคคลโดยไม่มีฐานทางกฎหมาย ความรับผิดชอบในการใช้เครื่องมือเป็นของคุณ

ขั้นตอนทีละขั้น

  1. เปิดหน้าสมาชิกของผู้ให้บริการ mobile proxy และหาข้อมูลการเชื่อมต่อ: โฮสต์ พอร์ต ล็อกอิน รหัสผ่าน ปกติรวบรวมไว้เป็นบรรทัดเดียวแบบ login:password@host:port คัดลอกลิงก์เปลี่ยน IP ด้วยถ้ามี
  2. ในไฟล์ server.py เพิ่มบรรทัด import os ที่ด้านบน หลัง import อื่น ๆ จากนั้นใต้บล็อก HEADERS เพิ่มการตั้งค่า:
PROXY_URL = os.environ.get('MOBILE_PROXY_URL', '')
ROTATE_URL = os.environ.get('PROXY_ROTATE_URL', '')

def _client() -> httpx.Client:
kwargs = {'headers': HEADERS, 'timeout': 30.0, 'follow_redirects': True}
if PROXY_URL:
kwargs['proxy'] = PROXY_URL
return httpx.Client(**kwargs)
  1. ในฟังก์ชัน _get_html เปลี่ยนบรรทัดที่มี httpx.Client เป็นการเรียก _client() ตอนนี้จะดูเป็นแบบนี้: with _client() as client เครื่องมือทั้งหมดจะผ่าน proxy โดยอัตโนมัติ
  2. เพิ่มเครื่องมือใหม่สองตัวก่อนบรรทัด if __name__:
@mcp.tool()
def current_ip() -> str:
'''Показывает IP-адрес, с которого сервер сейчас выходит в интернет.
Используй, чтобы убедиться, что прокси подключён, или после смены IP.'''
with _client() as client:
return client.get('https://api.ipify.org').text.strip()

@mcp.tool()
def rotate_ip() -> str:
'''Запрашивает смену IP-адреса мобильного прокси через ссылку из личного кабинета.
Вызывай, если сайт начал отдавать ошибки 429 или капчу. После вызова подожди 5-10 секунд.'''
if not ROTATE_URL:
return 'Ссылка смены IP не настроена в переменной PROXY_ROTATE_URL'
response = httpx.get(ROTATE_URL, timeout=15.0)
log(f'rotate_ip: status {response.status_code}')
return f'Запрос смены IP отправлен, ответ прокси-сервиса: {response.status_code}'
  1. ส่งข้อมูล proxy ผ่าน environment variable ในคอนฟิกไคลเอนต์ เราตั้งใจไม่เขียนล็อกอินและรหัสผ่านลงในโค้ด เพื่อไม่ให้หลุดไปที่ไหนพร้อมไฟล์ เปิด claude_desktop_config.json แล้วเพิ่มส่วน env ในบล็อกเซิร์ฟเวอร์:
{
"mcpServers": {
"web-collector": {
"command": "C:/mcp-collector/.venv/Scripts/python.exe",
"args": ["C:/mcp-collector/server.py"],
"env": {
"MOBILE_PROXY_URL": "http://login:password@proxy-host:port",
"PROXY_ROTATE_URL": "https://ссылка-смены-ip-из-кабинета"
}
}
}
}
  1. ใส่ค่าจริงแทน login, password, proxy-host และ port ถ้าผู้ให้บริการให้ proxy ผ่านโปรโตคอล SOCKS5 ให้เปลี่ยน http:// เป็น socks5:// และติดตั้งแพ็กเกจเพิ่มด้วยคำสั่ง pip install httpx[socks]
  2. บันทึกคอนฟิก แล้วรีสตาร์ทไคลเอนต์ให้สนิท
  3. ขอ agent ว่า: «เรียก current_ip แล้วบอกว่าเรามีที่อยู่อะไร จากนั้นเรียก rotate_ip รอสิบวินาที แล้วตรวจ IP อีกครั้ง» ที่อยู่ต้องต่างกัน

ทดสอบผ่าน Inspector พร้อม proxy

Inspector ก็ส่ง environment variable ได้เช่นกัน ในแผงด้านซ้าย ขยายส่วน Environment Variables เพิ่ม MOBILE_PROXY_URL และ PROXY_ROTATE_URL พร้อมค่าของคุณ เชื่อมต่อแล้วเรียก current_ip คำตอบต้องตรงกับ IP ที่หน้าสมาชิกของผู้ให้บริการแสดง

เคล็ดลับ: อย่าเรียก rotate_ip ก่อนทุกคำขอ ผู้ให้บริการส่วนใหญ่ใช้เวลาหลายวินาทีในการเปลี่ยน IP และคำขอที่ถี่เกินไปอาจชนลิมิตการเปลี่ยน กลยุทธ์ที่สมเหตุสมผล: เปลี่ยนที่อยู่ทุก 30-100 คำขอ หรือเฉพาะเมื่อเจอ error 429 และ 403 สามารถฝังตรรกะนี้ลงใน _get_html ได้เลย ซึ่งเราจะทำในขั้นตอนถัดไป

✅ ตรวจสอบ: เครื่องมือ current_ip คืนที่อยู่ของ proxy ไม่ใช่ที่อยู่ที่บ้าน หลัง rotate_ip และรอสักครู่ ที่อยู่เปลี่ยนไป เครื่องมือ extract_text และ extract_links ยังทำงานได้ และใน log เห็นบรรทัด GET พร้อมที่อยู่ของหน้าเว็บ

ปัญหาที่อาจเจอ

  • Error 407 Proxy Authentication Required ล็อกอินหรือรหัสผ่านผิด หรือมีอักขระพิเศษอยู่ในนั้น อักขระอย่าง @ หรือ : ในรหัสผ่านต้อง encode: @ แทนด้วย %40, : แทนด้วย %3A
  • Error ConnectTimeout โฮสต์หรือพอร์ตผิด หรือ IP ของคุณยังไม่ถูกเพิ่มในรายการที่อนุญาตในหน้าสมาชิกผู้ให้บริการ ถ้าแพ็กเกจมีการผูกแบบนั้น
  • current_ip แสดงที่อยู่ของคุณเอง Environment variable ไม่ถึงเซิร์ฟเวอร์ ตรวจสอบตัวสะกดของ MOBILE_PROXY_URL ในคอนฟิก และตรวจสอบว่ารีสตาร์ทไคลเอนต์แล้ว
  • rotate_ip คืนสถานะ 429 หรือข้อความเกี่ยวกับลิมิต คุณเปลี่ยน IP ถี่กว่าที่แพ็กเกจอนุญาต ให้เพิ่มช่วงเวลา

ขั้นตอนที่ 6: ทำให้เซิร์ฟเวอร์ทนทาน: retry, delay, cache และลิมิต

เป้าหมายของขั้นนี้: เปลี่ยนตัวอย่างฝึกหัดให้เป็นเครื่องมือที่ไม่ล้มจาก error เครือข่ายครั้งแรก ไม่ยิงคำขอถล่มเว็บ และไม่ทำบริบทโมเดลล้น นี่คือขั้นตอนบังคับขั้นสุดท้ายก่อนใช้งานจริงจัง

เพิ่มอะไรและทำไม

  • Retry อัตโนมัติ ข้อผิดพลาดเครือข่ายเกิดขึ้นได้ แทนที่จะคืน error ให้ agent ทันที ให้ลองคำขออีกสองครั้งพร้อมหยุดพัก
  • เปลี่ยน IP อัตโนมัติเมื่อถูกบล็อก ถ้าเว็บตอบ 429 หรือ 403 และตั้งค่าลิงก์หมุนไว้ เซิร์ฟเวอร์จะเปลี่ยนที่อยู่เองและลองคำขอใหม่
  • หน่วงเวลาระหว่างคำขอ ตัวเก็บข้อมูลที่สุภาพไม่ส่งคำขอหลายสิบครั้งต่อวินาที การหยุดพักหนึ่งถึงสองวินาทีลดโหลดบนเว็บและความเสี่ยงในการถูกบล็อก
  • Cache agent มักขอหน้าเว็บเดียวกันหลายครั้งผ่านเครื่องมือต่างกัน cache ในหน่วยความจำไม่กี่นาทีช่วยลดการโหลดซ้ำ
  • ลิมิตขนาด เราจะไม่ดาวน์โหลดหน้าเว็บที่หนักเกินสองสามเมกะไบต์

โค้ด

เพิ่ม import time ที่ด้านบนไฟล์ แล้วแทนที่ฟังก์ชัน _get_html ด้วยอันนี้:

CACHE: dict[str, tuple[float, str]] = {}
CACHE_TTL = 300
REQUEST_DELAY = 1.5
MAX_BYTES = 3_000_000
_last_request = 0.0

def _get_html(url: str) -> str:
global _last_request
now = time.time()
cached = CACHE.get(url)
if cached and now - cached[0] < CACHE_TTL:
log(f'cache hit: {url}')
return cached[1]
last_error = None
for attempt in range(3):
wait = REQUEST_DELAY - (time.time() - _last_request)
if wait > 0:
time.sleep(wait)
try:
with _client() as client:
_last_request = time.time()
response = client.get(url)
if response.status_code in (403, 429) and ROTATE_URL:
log(f'status {response.status_code}, rotating ip')
httpx.get(ROTATE_URL, timeout=15.0)
time.sleep(8)
continue
response.raise_for_status()
if len(response.content) > MAX_BYTES:
raise ValueError(f'Страница слишком большая: {len(response.content)} байт')
html = response.text
CACHE[url] = (time.time(), html)
return html
except httpx.HTTPError as error:
last_error = error
log(f'attempt {attempt + 1} failed: {error}')
time.sleep(2 * (attempt + 1))
raise RuntimeError(f'Не удалось загрузить {url} после 3 попыток: {last_error}')

ทำงานอย่างไร

  1. ดิกชันนารี CACHE เก็บเวลาโหลดและ HTML สำหรับแต่ละที่อยู่ ถ้าหน้านั้นถูกขอไม่เกินห้านาทีที่แล้ว จะคืนสำเนาที่บันทึกไว้โดยไม่ส่งคำขอ
  2. ก่อนทุกคำขอ จะคำนวณเวลาที่ผ่านไปจากคำขอก่อนหน้า และถ้าจำเป็นให้ sleep เพิ่มจนครบ REQUEST_DELAY วินาที
  3. ลูปสามครั้ง ถ้าได้คำตอบ 403 หรือ 429 พร้อมตั้งค่าหมุนไว้ เซิร์ฟเวอร์จะเปลี่ยน IP รอแปดวินาทีแล้วลองใหม่ ถ้าเป็น error เครือข่าย จะรอสอง สี่ หกวินาทีระหว่างครั้ง
  4. ถ้าหน้ามีขนาดเกินสามเมกะไบต์ ถือเป็น error: เอกสารแบบนั้นยังไงก็ไม่พอดีกับบริบท
  5. ถ้าล้มเหลวสามครั้ง จะโยน error ที่เข้าใจได้พร้อมที่อยู่และสาเหตุ agent จะได้รับเป็นข้อความและบอกคุณหรือลองเส้นทางอื่น

เรายังแนะนำให้เพิ่มเครื่องมือสำหรับล้าง cache เพื่อให้ agent บังคับโหลดหน้าใหม่ได้:

@mcp.tool()
def clear_cache() -> str:
'''Очищает кэш загруженных страниц. Вызывай, если нужно получить свежую версию страницы.'''
count = len(CACHE)
CACHE.clear()
return f'Кэш очищен, удалено записей: {count}'

เคล็ดลับ: ค่าของ REQUEST_DELAY และ CACHE_TTL ควรย้ายไปเป็น environment variable เช่นเดียวกับ proxy เพื่อเปลี่ยนได้โดยไม่แก้โค้ด สำหรับการติดตามราคา ใช้ delay สองถึงสามวินาทีและ cache หนึ่งนาที สำหรับเก็บบทความ ใช้ delay หนึ่งวินาทีและ cache หนึ่งชั่วโมง

✅ ตรวจสอบ: เรียก extract_text กับหน้าเดียวกันสองครั้งติดกัน ครั้งที่สองใน log จะมีบรรทัด cache hit และคำตอบมาทันที ลองใส่โดเมนที่ไม่มีอยู่ ผ่านไปไม่กี่วินาที agent จะได้ข้อความ «ไม่สามารถโหลด... ได้หลังลอง 3 ครั้ง» ไม่ใช่ค้าง

ปัญหาที่อาจเจอ

  • NameError: ROTATE_URL ไม่ถูกกำหนด ฟังก์ชัน _get_html ประกาศอยู่เหนือบล็อกการตั้งค่า proxy ย้ายการตั้งค่า PROXY_URL และ ROTATE_URL ขึ้นไปด้านบนไฟล์
  • Agent บ่นว่าทำงานช้า เป็นเรื่องปกติ: delay และการหมุน IP ใช้เวลา ถ้ารีบ ลด REQUEST_DELAY เหลือ 0.5 แต่ระวังความเสี่ยงในการถูกบล็อก
  • หน่วยความจำเพิ่มขึ้น cache เก็บทุกหน้าในเซสชัน สำหรับเซสชันยาว ให้เพิ่มการล้างรายการที่เก่ากว่า TTL ทุกครั้งที่เรียก หรือจำกัดขนาดดิกชันนารี

ตรวจสอบผลลัพธ์: เช็กลิสต์ MCP server ที่พร้อมใช้

ไล่ตามเช็กลิสต์และติ๊กทุกข้อ ถ้าทุกข้อผ่าน MCP server สำหรับเก็บข้อมูลของคุณก็พร้อมใช้งานจริง

อะไรต้องทำงานได้

  • คำสั่ง mcp dev server.py รันได้ไม่มี error Inspector เชื่อมต่อและแสดงสถานะ Connected
  • ในรายการเครื่องมือมี fetch_page, extract_text, extract_links, select_elements, current_ip, rotate_ip และ clear_cache
  • เซิร์ฟเวอร์ web-collector ปรากฏในแผงเครื่องมือของ AI client โดยไม่มีตัวบอก error
  • Agent เลือกเครื่องมือที่เหมาะสมและเรียกเองได้ตามคำขอในรูปแบบอิสระ
  • current_ip แสดงที่อยู่ของ mobile proxy และหลัง rotate_ip ที่อยู่เปลี่ยนไป
  • คำขอซ้ำกับหน้าเดิมถูกส่งจาก cache
  • ที่อยู่ผิดพลาดนำไปสู่ข้อความ error ที่เข้าใจได้ ไม่ใช่ค้าง

ทดสอบแบบครบวงจร

  1. เลือกเว็บสาธารณะที่มีแคตตาล็อกหรือฟีดบทความ ซึ่งอนุญาตให้ใช้ข้อมูลได้
  2. ขอ agent ว่า: «เปิดหน้าแรกของเว็บ หาลิงก์ไปยังหมวดแคตตาล็อก เข้าไปในห้าการ์ดแรก เก็บชื่อและราคา แล้วทำเป็นตารางที่มีคอลัมน์ ชื่อ ราค ลิงก์»
  3. สังเกตลำดับการเรียก: agent ต้องเรียก extract_links พร้อมตัวกรอง จากนั้นเรียก select_elements หรือ extract_text หลายครั้ง และสร้างตารางในตอนท้าย
  4. ตรวจสอบหลายแถวด้วยมือโดยเปิดการ์ดในเบราว์เซอร์ ข้อมูลต้องตรงกัน

ตัวชี้วัดความสำเร็จ

การเก็บห้าการ์ดใช้เวลาไม่เกิน 30-40 วินาทีเมื่อรวม delay ใน log ของไคลเอนต์ไม่มี error ระดับ traceback agent ไม่ถามกลับว่าจะใช้เครื่องมือไหน แต่ลงมือเอง ถ้าเป็นแบบนี้ ขอแสดงความยินดี: คุณสร้าง MCP server ของตัวเองและเชื่อม AI agent เข้ากับเว็บได้แล้ว

ข้อผิดพลาดทั่วไปในการสร้าง MCP server และวิธีแก้

รวบรวมปัญหาที่แทบทุกคนเจอในรอบแรก รูปแบบ: ปัญหา สาเหตุ วิธีแก้

1. เซิร์ฟเวอร์เชื่อมต่อใน Inspector ได้ แต่ไม่ทำงานในไคลเอนต์

สาเหตุ: คอนฟิกไคลเอนต์ระบุ python ของระบบที่ไม่มีไลบรารีติดตั้ง หรือพาธไปยังไฟล์ผิด วิธีแก้: ใส่พาธเต็มของ python ใน .venv และพาธเต็มของ server.py ใช้สแลชตรง รีสตาร์ทไคลเอนต์ให้สนิท

2. ไคลเอนต์ตัดการเชื่อมต่อทันทีหลังเริ่ม

สาเหตุ: โค้ดยังมี print ธรรมดาที่ไม่มี file=sys.stderr และสตรีม stdout ที่ใช้สำหรับโปรโตคอลถูกปนเปื้อน วิธีแก้: เปลี่ยน print ทั้งหมดเป็นฟังก์ชัน log ตรวจสอบด้วยว่าไลบรารีไม่เขียนไปที่ stdout เช่น progress bar บางตัวเขียนโดยค่าเริ่มต้น

3. Agent ไม่เรียกเครื่องมือและตอบจากความรู้ของตัวเอง

สาเหตุ: คำอธิบายเครื่องมือสั้นหรือคลุมเครือเกินไป โมเดลไม่เข้าใจว่าใช้เมื่อไหร่ วิธีแก้: ขยาย docstring เพิ่มวลี «ใช้เมื่อ...» และตัวอย่าง ในคำขอแรก ๆ ให้ระบุชื่อเครื่องมืออย่างชัดเจน

4. Error 403 ตอนโหลดเว็บจริง

สาเหตุ: เว็บไม่รับคำขอที่ไม่มี header แบบเบราว์เซอร์ หรือมาจาก IP ที่น่าสงสัย วิธีแก้: ตรวจสอบว่า HEADERS ถูกส่ง อัปเดต User-Agent เป็นเวอร์ชันเบราว์เซอร์ปัจจุบัน เชื่อมต่อ mobile proxy และตรวจสอบว่าการหมุนทำงาน

5. select_elements คืนผลว่างทั้งที่ selector ถูก

สาเหตุ: ข้อมูลถูกโหลดด้วย JavaScript หลังหน้าโหลด และไม่มีใน HTML ต้นฉบับ วิธีแก้: ตรวจสอบผ่าน fetch_page ถ้าไม่มีข้อมูล ให้ลองหาภายใน API ของเว็บในแท็บ Network ของเบราว์เซอร์: บ่อยครั้งการ์ดมาอยู่ในรูป JSON ที่ที่อยู่แยก ซึ่งเรียกตรงได้ด้วย extract_text เหมือนกัน

6. Error 407 หรือ ConnectTimeout เมื่อใช้ proxy

สาเหตุ: ข้อมูลรับรองผิด อักขระพิเศษในรหัสผ่านยังไม่ encode หรือพอร์ตผิด วิธีแก้: คัดลอกสตริงการเชื่อมต่อจากหน้าสมาชิกใหม่ encode อักขระพิเศษ ตรวจสอบโปรโตคอล http หรือ socks5

7. คอนฟิก JSON ไม่ถูกนำไปใช้

สาเหตุ: จุลภาคเกิน เครื่องหมายคำพูดขาด หรือแบ็กสแลชในพาธ วิธีแก้: ตรวจสอบไฟล์ในตัวตรวจสอบ เปลี่ยนแบ็กสแลชเป็นสแลชตรง ตรวจสอบว่าไม่มีจุลภาคหลังรายการสุดท้าย

8. เซิร์ฟเวอร์ทำงานได้ แต่ข้อมูลมาใน encoding ผิด

สาเหตุ: เว็บไม่ระบุ encoding ใน header วิธีแก้: กำหนด response.encoding อย่างชัดเจน หรือใช้แอตทริบิวต์ response.content แล้ว decode ด้วยมือผ่าน decode('utf-8', errors='ignore')

ความสามารถเพิ่มเติม: บล็อกสำหรับขั้นสูง

เซิร์ฟเวอร์พื้นฐานพร้อมแล้ว ถ้าคุณเขียน Python อย่างมั่นใจและอยากได้มากกว่านี้ นี่คือแนวทางพัฒนาต่อยอด แต่ละอย่างทำเสร็จได้ในหนึ่งเย็น

เซิร์ฟเวอร์ระยะไกลผ่าน Streamable HTTP

เพื่อให้เซิร์ฟเวอร์ทำงานบนเครื่องแยกหรือมีไคลเอนต์หลายตัวเชื่อมต่อ ให้เปลี่ยนบรรทัดสุดท้ายเป็น mcp.run(transport='streamable-http') ตามค่าเริ่มต้นเซิร์ฟเวอร์จะขึ้นบนพอร์ต 8000 และที่อยู่เชื่อมต่อจะเป็น http://ที่อยู่เครื่อง:8000/mcp ในคอนฟิกไคลเอนต์ แทน command และ args ให้ใส่คีย์ url พร้อมที่อยู่นั้น ในโหมดนี้เขียนไปที่ stdout ได้ แต่ยังควรติดนิสัย log ไปที่ stderr ต้องปิดพอร์ตจากภายนอกอย่างแน่นอน และเพิ่มการตรวจสอบ token ใน header ถ้าเซิร์ฟเวอร์เข้าถึงได้ไม่เฉพาะจากเครือข่ายภายใน

Resources และ Prompts

Resource ที่มีค่าตั้งปัจจุบันจะช่วยให้ agent เข้าใจบริบทการทำงาน:

@mcp.resource('collector://settings')
def settings() -> str:
'''Текущие настройки сборщика.'''
return f'proxy: {"on" if PROXY_URL else "off"}, delay: {REQUEST_DELAY}, cache ttl: {CACHE_TTL}'

Prompt กำหนดสถานการณ์สำเร็จรูปที่ผู้ใช้เรียกด้วยคำสั่งเดียว:

@mcp.prompt()
def price_monitor(url: str) -> str:
'''Сценарий мониторинга цен в каталоге.'''
return f'Открой {url}, собери ссылки на карточки товаров, зайди в каждую, вытащи название и цену и составь таблицу. Если увидишь ошибку 429, вызови rotate_ip и продолжи.'

บันทึกผลลัพธ์ลงไฟล์

เพิ่มเครื่องมือ save_csv ที่รับรายการดิกชันนารีและพาธไฟล์ แล้วเขียนข้อมูลผ่านโมดูล csv agent จะไม่เพียงเก็บข้อมูล แต่ยังเก็บผลลัพธ์ลงตารางที่คุณเปิดใน Excel ได้ จำกัดพาธบันทึกให้อยู่ในโฟลเดอร์เดียว เพื่อไม่ให้ agent เขียนที่ไหนบนดิสก์ก็ได้

Async และการเก็บข้อมูลแบบขนาน

FastMCP รองรับฟังก์ชัน async: ประกาศเครื่องมือด้วย async def และใช้ httpx.AsyncClient จากนั้นเครื่องมือ fetch_many จะโหลดสิบหน้าพร้อมกันผ่าน asyncio.gather ได้ อย่าลืม semaphore ที่จำกัดจำนวนคำขอขนาน และ记住ว่าการหน่วงเวลาระหว่างคำขอเมื่อทำงานขนานต้องคำนวณต่างออกไป

หลาย proxy และการหมุนอย่างชาญฉลาด

ถ้าคุณมี mobile proxy หลายตัวสำหรับภูมิภาคต่าง ๆ ให้เก็บเป็น environment variable แบบคั่นด้วยจุลภาค และเพิ่มพารามิเตอร์ region ให้เครื่องมือ เซิร์ฟเวอร์จะเลือก proxy ตามภูมิภาค และ agent จะเปรียบเทียบราคาที่เว็บแสดงต่อผู้ใช้จากต่างเมืองได้ นี่เป็นหนึ่งในงานที่เป็นที่ต้องการมากที่สุดของนักการตลาดและนัก arbitrage

แพ็กเป็น Docker

สำหรับรันบนเซิร์ฟเวอร์ ให้ build image จาก python:3.12-slim คัดลอก server.py และไฟล์ dependencies ติดตั้งแพ็กเกจ แล้วระบุ entrypoint ที่ใช้ HTTP transport ส่ง environment variable ของ proxy ตอนรันคอนเทนเนอร์ ไม่ใช่ฝังใน image

⚠️ ระวัง: อย่าเผยแพร่โค้ดที่มีล็อกอิน รหัสผ่าน และลิงก์หมุนในรีโพสาธารณะ เก็บไว้เฉพาะใน environment variable หรือไฟล์ .env ที่ใส่ใน .gitignore การรั่วของลิงก์เปลี่ยน IP จะทำให้คนอื่นควบคุม proxy ของคุณได้

FAQ: คำถามที่พบบ่อยเกี่ยวกับการสร้าง MCP server

เขียน MCP server ด้วยภาษาอื่นได้ไหม

ได้ SDK ทางการมีสำหรับ TypeScript, Java, Kotlin, C# และภาษาอื่น ๆ หลักการเหมือนกัน: ประกาศเครื่องมือพร้อมคำอธิบายและเริ่ม transport ที่เลือก Python ในคู่มือนี้เพราะง่ายและมีไลบรารีสำหรับจัดการ HTML มากมาย

ต้องมีแพ็กเกจเสียเงินของ AI client ถึงจะใช้ MCP ได้ไหม

Claude Desktop รองรับ MCP server ในเครื่องแม้ในแพ็กเกจฟรี แต่มีลิมิตจำนวนข้อความ Cursor และ VS Code ก็เชื่อมต่อเซิร์ฟเวอร์ได้เช่นกัน ตรวจสอบเงื่อนไขปัจจุบันของแต่ละไคลเอนต์

จำเป็นต้องใช้ proxy ไหม

ไม่จำเป็น เซิร์ฟเวอร์ทำงานโดยตรงได้ proxy จำเป็นเมื่อปริมาณคำขอมาก เว็บไวต่อความถี่ในการเข้าถึง หรือคุณต้องการเห็นคอนเทนต์จากภูมิภาคเฉพาะและจาก IP มือถือ

จะรู้ได้อย่างไรว่าคำขอผ่าน proxy จริง

เรียกเครื่องมือ current_ip แล้วเทียบที่อยู่กับที่หน้าสมาชิกผู้ให้บริการแสดง เพิ่มเติมคือขอ agent โหลดหน้าของบริการตรวจสอบ IP ผ่าน extract_text ได้

เพิ่มเครื่องมือบนเซิร์ฟเวอร์เดียวได้กี่ตัว

ทางเทคนิคแทบไม่มีขีดจำกัด แต่ทุกคำอธิบายกินที่ในบริบทโมเดล ในทางปฏิบัติ 5-15 เครื่องมือที่อธิบายดีทำงานได้ดีกว่า 50 เครื่องมือเล็ก ๆ จัดกลุ่มฟังก์ชันที่ใกล้กันด้วยพารามิเตอร์

อัปเดตเซิร์ฟเวอร์โดยไม่รีสตาร์ทไคลเอนต์ได้ไหม

เมื่อใช้ transport แบบ stdio ไคลเอนต์จะรันโปรเซสตอนเริ่มต้น ดังนั้นการแก้โค้ดจะมีผลหลังรีสตาร์ทไคลเอนต์เท่านั้น ในโหมดพัฒนา สะดวกกว่าที่จะตรวจแก้ไขผ่าน Inspector แล้วรีสตาร์ทไคลเอนต์เมื่อเสร็จ

ถ้าเว็บส่งข้อมูลหลังรัน JavaScript เท่านั้น ควรทำอย่างไร

เซิร์ฟเวอร์ของเราทำงานกับ HTML ต้นฉบับและจะไม่เห็นข้อมูลแบบนั้น ทางเลือก: หาภายใน API ของเว็บในแท็บ Network ของเบราว์เซอร์ หรือเชื่อมต่อเอนจินเบราว์เซอร์ วิธีหลังมีอธิบายในบทความแยกของบล็อก ตรงนี้เราตั้งใจไม่แตะ

จะจำกัด agent ไม่ให้เข้าเว็บที่ไม่ต้องการได้อย่างไร

เพิ่มการตรวจสอบโดเมนแบบ whitelist หรือ blacklist จาก environment variable ใน _get_html แล้วคืน error ที่เข้าใจได้สำหรับที่อยู่ต้องห้าม วิธีนี้น่าเชื่อถือกว่าการพึ่งคำสั่งในแชท

ใช้ MCP server ตัวเดียวจากหลายไคลเอนต์พร้อมกันได้ไหม

เมื่อใช้ stdio แต่ละไคลเอนต์รันสำเนาโปรเซสของตัวเอง และนี่เป็นเรื่องปกติ: ไม่รบกวนกัน แต่ cache ก็แยกกัน สำหรับ cache ร่วมและ proxy เดียว ให้เปลี่ยนไปใช้ HTTP transport จากบล็อกขั้นสูง

บทสรุป: คุณทำอะไรไปแล้วและจะไปต่ออย่างไร

มาสรุปกัน คุณเตรียม environment Python และติดตั้ง SDK ทางการของโปรโตคอล เขียน MCP server ตั้งแต่ศูนย์และเข้าใจว่าโมเดลเข้าใจเครื่องมือผ่านคำอธิบายอย่างไร เชื่อมเซิร์ฟเวอร์กับ AI client และเห็น agent โหลดหน้าเว็บเอง เพิ่มเครื่องมือดึงข้อความ ลิงก์ และองค์ประกอบตาม selector ส่งทราฟฟิกผ่าน mobile proxy พร้อมการหมุน IP สุดท้ายทำให้เซิร์ฟเวอร์ทนทาน: retry, delay, cache และลิมิต นี่ไม่ใช่ตัวอย่างฝึกหัดอีกต่อไป แต่เป็นเครื่องมือทำงานสำหรับงานประจำวัน

จะทำอะไรต่อ เริ่มใช้เซิร์ฟเวอร์ในสถานการณ์จริง: ติดตามราคาคู่แข่ง เก็บรีวิว ตรวจ landing page วิเคราะห์คอนเทนต์ในตลาดของคุณ ระหว่างทางคุณจะเข้าใจว่าเครื่องมือไหนที่คุณยังขาด และเพิ่มตามแบบอย่างที่มีอยู่ ทุกเครื่องมือใหม่คือฟังก์ชันที่มีคำอธิบายชัดเจน ไม่มีอะไรซับซ้อนกว่านั้น

ระดับถัดไปคือบล็อกขั้นสูง: เซิร์ฟเวอร์ระยะไกลผ่าน HTTP การเก็บข้อมูลขนาน การใช้ proxy หลายตัวตามภูมิภาค และการบันทึกผลลัพธ์ลงตาราง และเมื่อคุณเจอเว็บที่มีคอนเทนต์ไดนามิก ให้ไปดูบทความที่เกี่ยวข้องในบล็อกเรื่องการทำงานอัตโนมัติด้วยเบราว์เซอร์ สิ่งสำคัญคุณทำไปแล้ว: AI agent ของคุณออกสู่เว็บผ่าน MCP server ของตัวเอง และคุณควบคุมทุกอย่างว่ามันทำอย่างไร