สร้างสะพานเชื่อมสเปกใหม่ WebMCP ของ Google: เจาะลึกปัญหาและสิ่งที่พังระหว่างทาง
นักพัฒนาแชร์ประสบการณ์จริงจากการสร้าง Chrome Extension และ MCP Server เพื่อทดสอบ WebMCP สเปกใหม่จาก W3C พร้อมเผยอุปสรรคและบั๊กที่พบจริงบน Chrome for Testing

ภาพประกอบจากคลังภาพสต็อก ไม่ใช่ภาพจากเหตุการณ์จริง
- WebMCP เป็นสเปกฉบับร่างจาก W3C ที่ให้หน้าเว็บประกาศฟีเจอร์เป็นเครื่องมือสำหรับ AI Agent ได้
- ผู้เขียนได้สร้าง Chrome Extension และ MCP Server ร่วมกันเพื่อแก้ปัญหาเบราว์เซอร์ยังไม่รองรับเนทีฟ
- พบปัญหาจริงเช่น getTools() คืนค่าเป็น Promise และ executeTool ต้องส่ง Object ไม่ใช่ String
- การสื่อสารผ่าน file:// และปัญหา MV3 Service Worker ถูกพักการทำงานคือความท้าทายสำคัญ
สวัสดีผู้อ่านทุกท่าน ผมคือ tanahiro2010 สมาชิกของ GDG Greater Kwansai ผู้บรรยายในช่วงแรกของงาน Google I/O Extended Osaka 2026 ในเซสชันลงมือปฏิบัติในหัวข้อ "Let's Build WebMCP and Call It from an AI Agent!" บทความนี้เป็นการเรียบเรียงเนื้อหาจากเซสชันดังกล่าวสำหรับเผยแพร่บน Qiita และแปลมาลงใน Dev.to โดยมีโคเดลาบที่ใช้งานคือ https://learn.gdgs.jp/webmcp-agent/
บทความนี้เหมาะสำหรับผู้ที่รู้จัก MCP (Model Context Protocol) อยู่แล้วแต่ยังไม่เคยได้ยินชื่อ WebMCP หรือผู้ที่สงสัยว่าสเปกใหม่ล่าสุดที่ Google ผลักดันออกมานี้มีหน้าตาและการทำงานอย่างไรกันแน่ เมื่อผมเริ่มศึกษาและลงมือ implement จริง กลับพบว่ามันเป็นสเปกที่มีความเฉพาะตัวและแปลกใหม่กว่าที่คาดไว้มาก โดยในบทความนี้จะพาไปสำรวจเนื้อหาภายในและสิ่งที่ได้เรียนรู้จากการลงมือทำจริง
ก่อนจะพูดถึง WebMCP เรามาย้อนทบทวน MCP กันก่อนเล็กน้อย โดย MCP คืออินเทอร์เฟซกลางสำหรับเชื่อมต่อเครื่องมือภายนอกเข้ากับ AI Agent สำหรับ WebMCP นั้นเป็นฉบับร่างที่เผยแพร่โดย W3C Web Machine Learning Community Group ซึ่งในขณะที่เขียนนี้คือฉบับเดือนกุมภาพันธ์ 2026 และยังอยู่ในขั้นตอนข้อเสนอ (proposal stage) โดยเปิดให้หน้าเว็บสามารถประกาศฟีเจอร์ของตัวเองเป็นเครื่องมือสำหรับ Agent ได้โดยตรงผ่าน JavaScript หรือการแปลงแท็ก <form> ให้อัตโนมัติ

ภาพประกอบจากคลังภาพสต็อก ไม่ใช่ภาพจากเหตุการณ์จริง
การที่ W3C พยายามผลักดัน WebMachine Learning และมาตรฐานอย่าง WebMCP ถือเป็นก้าวสำคัญที่จะทำให้เว็บเบราว์เซอร์กลายเป็นรันไทม์หลักสำหรับแอปพลิเคชัน AI แทนที่จะพึ่งพาแค่ฝั่งเซิร์ฟเวอร์ การเปิดให้หน้าเว็บประกาศตัวตนเป็นเครื่องมือผ่าน API มาตรฐานจะช่วยลดช่องว่างระหว่างเว็บไซต์แบบดั้งเดิมและเอเจนต์อัจฉริยะในอนาคต
เนื่องจากชื่อและหน้าตาของ API มีความใกล้เคียงกันมาก ความประทับใจแรกของผมจึงคิดว่ามันก็คือ "เวอร์ชันเว็บของ MCP" แต่พอได้เจาะลึกดูแล้ว กลับพบจุดที่แตกต่างกันอย่างชัดเจน โดยเฉพาะเรื่องอายุของเซสชัน (session lifetime) และการที่ฟีเจอร์นี้ยังเป็นฟีเจอร์ที่กำลังจะมา (upcoming feature) ในเบราว์เซอร์ ทำให้เราไม่สามารถคาดหวังได้ว่าผู้เข้าร่วมงานทุกคนจะมีเบราว์เซอร์ที่เปิดใช้งานฟีเจอร์นี้แบบเนทีฟเอาไว้แล้ว
นั่นจึงเป็นเหตุผลที่ผมตัดสินใจสร้างชุดเครื่องมือขึ้นมาเพื่อเชื่อมช่องว่างระหว่างข้อกำหนดของเวิร์กช็อปและสเปก WebMCP เข้าด้วยกัน โดยสร้าง Chrome Extension และ MCP Server ขึ้นมาเป็นชุด โดยยึดมั่นว่าจะตรวจจับและรันเฉพาะ API ที่กำหนดโดยสเปก WebMCP แท้ๆ (document.modelContext และ <form> ที่ระบุแอนโนเทชัน) เท่านั้น ไม่สร้างโปรโตคอลเสริมขึ้นมาเองเพื่อไม่ให้เนื้อหาที่เรียนกับสิ่งที่รันจริงเกิดความคลาดเคลื่อน
การเชื่อมต่อ WebSocket ใช้พอร์ต 58787 บน ws://127.0.0.1:58787 โดยหลีกเลี่ยงพอร์ต 8787 เนื่องจากไปชนกับพอร์ตเริ่มต้นของ wrangler dev (Cloudflare Workers) ส่วนฝั่ง Extension เป็นสถาปัตยกรรมแบบ MV3 ที่มีโครงสร้างสองชั้นและมีเครื่องมือที่มองเห็นได้สำหรับ Agent ทั้งหมด 6 ตัวด้วยกัน
นี่คือส่วนที่ผมอยากเขียนถึงมากที่สุด เพราะปัญหาที่ไม่เคยคาดคิดจากการอ่านเอกสารอย่างเดียวเริ่มปรากฏขึ้นเมื่อนำไปรันจริงบน Chrome for Testing 150 โดยพบว่าฟังก์ชัน getTools() คืนค่าออกมาเป็น Promise<ModelContextTool[]> ไม่ใช่ฟังก์ชันแบบซิงโครนัสอย่างที่เข้าใจจากเอกสารสรุป และ executeTool() ก็บังคับว่าต้องส่งออบเจ็กต์เครื่องมือจริงเข้าไปแทนที่จะเป็นแค่ชื่อสตริง มิฉะนั้นจะเจอข้อผิดพลาด TypeError ทันที
นอกจากนี้ ในส่วนของการสื่อสาร postMessage ระหว่าง content.ts และ injected.ts ที่เคยใช้ window.location.origin เป็น targetOrigin ปรากฏว่าเมื่อเปิดหน้าเว็บผ่านโพรโทคอล file:// ค่าดังกล่าวจะกลายเป็นสตริง "null" ทำให้การจับมือ (handshake) ไม่สำเร็จและหน้าต่าง overlay ไม่แสดงผล ผมจึงเปลี่ยนมาใช้ "*" เป็น targetOrigin แทน และรับรองความปลอดภัยด้วยแชนแนลไอดีแบบสุ่มแทน ซึ่งเป็นบั๊กที่จะไม่มีทางสังเกตเห็นเลยหากไม่ได้ทดลองเปิดไฟล์โดยตรง
ที่มา: Dev.to
พบข้อมูลผิดพลาดในบทความนี้? แจ้งปัญหาบทความนี้
ความคิดเห็น
แสดงความคิดเห็น