ในหน้านี้
เมื่อวันที่ 8 มิถุนายน 2026 Anthropic ได้มอบแดชบอร์ดให้เจ้าของคอนเนกเตอร์ในไดเรกทอรีของ Claude แดชบอร์ดนี้แสดงจำนวนผู้ใช้ที่ใช้งานอยู่ จำนวนการเรียกเครื่องมือทั้งหมด และอันดับในไดเรกทอรี และยังแสดง “คะแนนสุขภาพ อัตราข้อผิดพลาด และเวลาแฝงได้ในพริบตา พร้อมการแจกแจงข้อผิดพลาดรายเครื่องมือเพื่อระบุให้ตรงจุดว่าอะไรล้มเหลว”
หนึ่งปีก่อนหน้านั้น Alex Volkov จาก Weights & Biases ได้อธิบายปัญหาเดียวกันจากอีกฝั่งหนึ่ง เมื่อเอเจนต์ของเขาเรียกเครื่องมือผ่าน MCP “observability ทั้งหมดที่ผมคุ้นเคยตอนที่โค้ดของผมเองทำงานตั้งแต่ต้นจนจบ ก็มืดลงไปเล็กน้อย” ผู้บรรยายร่วมของเขา Benjamin Eckel จาก Dylibso แสดงให้เห็นว่าเพราะอะไร เซิร์ฟเวอร์ MCP ระยะไกล “ปรากฏต่อเราใน trace เป็นสแปนบริการเพียงสแปนเดียว” เพราะมันทำงานอยู่นอกการควบคุมของฝั่งผู้เรียก
มุมมองทั้งสองอยู่นอกเซิร์ฟเวอร์ ไคลเอนต์เห็นสแปนเดียวที่มองไม่เห็นข้างใน ไดเรกทอรีเห็นยอดรวม ไม่มีฝ่ายใดเห็นว่าเซิร์ฟเวอร์ถูกขอให้ทำอะไร ปฏิเสธอะไร และแตะต้องอะไร มีเพียงเซิร์ฟเวอร์ที่เห็น ดังนั้นมีเพียงเซิร์ฟเวอร์ที่บันทึกสิ่งนั้นได้
ต่อไปนี้คือสิ่งที่เซิร์ฟเวอร์ MCP ของ Tajo บันทึกไว้ อ่านจากโค้ดที่รันเซิร์ฟเวอร์เหล่านั้น และระบุไว้ในเอกสาร บทความ เซิร์ฟเวอร์ MCP คืออะไร อธิบายเรื่องโปรโตคอล บทความนี้อธิบายเรื่องแถวในบันทึก
หนึ่งแถวต่อการเรียกหนึ่งครั้ง
แดชบอร์ดคือมุมมองของนายท่า เรือเข้า เรือออก ลำไหนมาช้า ส่วน log คำขอคือสมุดปูมของเรือเอง ซึ่งเขียนบนเรือ ณ เวลานั้น
ทุก tools/call บนเซิร์ฟเวอร์เวิร์กสเปซของ Tajo และบนเซิร์ฟเวอร์คอนเนกเตอร์ทุกตัวจบลงด้วยหนึ่งแถว แถวนี้เขียนขึ้นหลังจากสร้างคำตอบเสร็จแล้ว ไม่ว่าคำตอบนั้นจะเป็นอะไร การเรียกที่ถูกปฏิเสธเพราะคีย์ไม่มีสิทธิ์เขียน หรือเพราะเอนด์พอยต์เป็นแบบอ่านอย่างเดียว ก็ได้แถวเหมือนการเรียกอื่น ๆ การเรียกเครื่องมือที่ไม่มีอยู่จริงก็เช่นกัน
นี่คือสิ่งที่แถวนี้เก็บไว้ และสิ่งที่แถวนี้ปฏิเสธที่จะเก็บ
| ฟิลด์ | เก็บไว้ | ไม่เก็บ |
|---|---|---|
| ใคร | id ของคีย์ API ที่เรียก โทเค็นจากการลงชื่อเข้าใช้ด้วย OAuth ก็นับเป็นคีย์เช่นกัน | ค่าลับของคีย์หรือคำนำหน้าของคีย์ |
| ที่ไหน | เซิร์ฟเวอร์เวิร์กสเปซหรือเซิร์ฟเวอร์คอนเนกเตอร์ พร้อมคอนเนกเตอร์และโปรไฟล์ของมัน | |
| เครื่องมือ | ชื่อ เมื่อเซิร์ฟเวอร์มีเครื่องมือชื่อนั้น | ชื่ออื่นใดที่ไคลเอนต์ส่งมา จะถูกเก็บเป็น (unknown) |
| ผลกระทบ | read, write, send หรือ destructive คือผลกระทบที่หนักที่สุดที่การเรียกนั้นอาจมีได้ | |
| ผลลัพธ์ | ok หรือรหัสข้อผิดพลาดแบบ snake_case สั้น ๆ เช่น unknown_tool | ข้อความอธิบายข้อผิดพลาด สิ่งใดที่ไม่ใช่รหัสจะถูกเก็บเป็น tool_error |
| ระยะเวลาและขนาด | มิลลิวินาทีตั้งแต่คำขอมาถึงจนถึงการตอบกลับ และจำนวนไบต์ที่ผู้เรียกได้รับ | |
| trace id | id ของคำขอ จากเฮดเดอร์ x-request-id, x-trace-id หรือ W3C traceparent หากไม่มีก็สร้างใหม่ | ค่าเฮดเดอร์ที่ไม่ใช่เลขฐานสิบหกหรือ UUID |
| เรกคอร์ด | id ของเรกคอร์ดที่การเรียกระบุถึงหรือสร้างขึ้นสูงสุด 20 รายการ เช่น รายชื่อติดต่อ ข้อความ การอนุมัติ | ตัวเรกคอร์ดเอง |
| เนื้อหา | อาร์กิวเมนต์และคำตอบ ที่ทำความสะอาดแล้ว สูงสุดอย่างละ 4 KB | ข้อมูลลับ ข้อความอิสระ และข้อมูลส่วนบุคคลตามที่ระบุไว้ด้านล่าง |
การปฏิเสธสามข้อในนั้นเกี่ยวกับไคลเอนต์ ไม่ใช่ข้อมูล ชื่อเครื่องมือ รหัสข้อผิดพลาด และ trace id ล้วนมาจากภายนอก แต่ละอย่างจะถูกเก็บเฉพาะในรูปแบบที่เซิร์ฟเวอร์รับรองได้ log ที่เก็บทุกอย่างที่ผู้เรียกส่งมาอาจถูกยัดด้วยอะไรก็ได้ รวมถึงที่อยู่อีเมลของลูกค้าในคอลัมน์ชื่อเครื่องมือ
คำถามปลายเปิดของ Benjamin Eckel ตอนท้ายการบรรยายคือ ตัวรวบรวมข้อมูลจะรู้ได้อย่างไร “ว่านี่คือการเรียกเครื่องมือ MCP ที่มีข้อผิดพลาด” บนเซิร์ฟเวอร์หนึ่งตัว คำตอบคือคอลัมน์หนึ่งคอลัมน์ ok เป็น false และรหัสจะบอกว่าเป็นข้อผิดพลาดใด
อาร์กิวเมนต์: กฎที่เรากลับคำ
ข้อโต้แย้งนี้สมเหตุสมผล และเป็นข้อโต้แย้งของเราเอง ถ้าบันทึกอาร์กิวเมนต์ คุณก็ได้สร้างสำเนาที่สองของข้อมูลลูกค้าไว้นอกขอบเขตของคำขอลบข้อมูลทุกฉบับ จนถึงวันที่ 18 ตุลาคม 2026 นั่นคือกฎของเราเอง log ไม่เก็บทั้งอาร์กิวเมนต์และเนื้อหาของผลลัพธ์ เพราะทั้งสองอย่างอาจมีข้อมูลส่วนบุคคล
นั่นเป็นการแลกที่ผิด log คำขอที่แสดงไม่ได้ว่าส่งอะไรไปและได้อะไรกลับมา ย่อมตอบคำถามเดียวที่มันมีไว้เพื่อตอบไม่ได้ นั่นคือ ทำไมการเรียกของเอเจนต์ของฉันจึงล้มเหลว
เราจึงเก็บเนื้อหาไว้ และจัดการกับเหตุผลที่เคยไม่เก็บด้วยวิธีอื่น เนื้อหาแต่ละส่วนจะผ่านการประมวลผลแบบกำหนดแน่นอนหนึ่งรอบก่อนเข้าคิว
- ไม่มีข้อมูลลับใดหลุดรอด ฟิลด์ที่ชื่อบ่งบอกว่าเป็น token, password, secret, signature, cookie, session หรือคำที่คล้ายกันอีกราวยี่สิบคำ จะเก็บเพียง
[secret]ค่าที่มีรูปแบบของข้อมูลรับรองที่รู้จักก็เช่นกัน ไม่ว่าจะปรากฏที่ใด ซึ่งครอบคลุม bearer token, JWT, คีย์ส่วนตัว, URL ที่มีรหัสผ่าน และสตริงทึบใด ๆ ที่เป็นอักขระคีย์ต่อกันตั้งแต่ 40 ตัวขึ้นไป - ไม่เก็บข้อความร้อยแก้วเลย ฟิลด์ที่ชื่อ
html,text,body,markdownหรือcontentจะเก็บเพียง[redacted]เพราะข้อความร้อยแก้วมีชื่อคนและที่อยู่ที่ไม่มีรูปแบบใดค้นหาเจอ - ข้อมูลส่วนบุคคลถูกปิดบังอย่างถาวร ฟิลด์ที่ชื่อบ่งบอกว่าเป็นข้อมูลส่วนบุคคล เช่น อีเมล โทรศัพท์ ชื่อ ที่อยู่ หรือบันทึก จะเก็บเพียง
[redacted]ที่อยู่อีเมล หมายเลขโทรศัพท์ บัตร หรือ IBAN ที่อยู่ในสตริงอื่นใดจะถูกปิดบัง - เนื้อหามีขนาดเล็กเสมอ สตริงถูกตัดที่ 512 อักขระ ลิสต์ที่ 20 รายการ ออบเจกต์ที่ 50 คีย์ และการซ้อนที่ 6 ระดับ เนื้อหาทั้งหมดถูกตัดที่ 4 KB และมีเครื่องหมายว่าถูกตัด
มีการเรียกสองประเภทที่เก็บน้อยกว่านั้น รายชื่อติดต่อที่แชตของผู้ใช้นำเข้ามาจากแอปอื่นจะถูกบันทึกเป็นเครื่องหมายและจำนวนเท่านั้น ไม่เคยเป็นเนื้อหา การเรียกที่อ่าน log จะไม่เก็บคำตอบ เพราะคำตอบนั้นก็เป็นเพียงแถว log อื่น ๆ
ทีนี้มาดูต้นทุน การปิดบังเป็นแบบถาวร ไม่ใช่การเข้ารหัสที่มีใครถือคีย์อยู่ log ไม่สามารถแสดงที่อยู่อีเมลที่ตีกลับให้คุณเห็นได้ สิ่งที่แสดงคือ id ของรายชื่อติดต่อ และตัวรายชื่อติดต่อนั้นก็อยู่ห่างออกไปเพียงการเรียกครั้งเดียวภายใต้กฎของมันเอง log อยู่นอกกระบวนการลบข้อมูลของเวิร์กสเปซ การปิดบังจึงรอกระบวนการนั้นไม่ได้
ทำไม log นี้จึงไม่ใช่ร่องรอยการตรวจสอบ
Tajo มีlog การตรวจสอบแบบเพิ่มต่อท้ายเท่านั้นอยู่แล้ว แต่ละแถวมีแฮชของแถวก่อนหน้า การแก้ไขที่ใดก็ตามจึงทำให้สายโซ่ขาด แล้วทำไมไม่เขียนการเรียกเครื่องมือลงไปในนั้น
เพราะสายโซ่มีราคาที่ต้องจ่าย การเพิ่มแต่ละครั้งต้องล็อกระดับเวิร์กสเปซและอ่านแถวก่อนหน้าเพื่อต่อสายโซ่ หากเขียนทุกการอ่านผ่านสายโซ่นี้ การเรียกของเวิร์กสเปซจะต้องต่อคิวรอล็อกเดียวกัน และยังทำให้การเปลี่ยนแปลงสถานะ ซึ่งเป็นสิ่งที่ log การตรวจสอบมีไว้แสดง จมอยู่ใต้การอ่านนับพันครั้ง
ดังนั้นบันทึกทั้งสองจึงแบ่งกันตามคำถาม log คำขอบอกว่าเอเจนต์ขออะไรและเกิดอะไรขึ้นเป็นเวลา 30 วัน log การตรวจสอบบอกว่าอะไรเปลี่ยนไป ใครอนุญาต และมีใครแก้ไขบันทึกหลังจากนั้นหรือไม่
การอนุมัติอยู่ฝั่งการตรวจสอบ ในโปรไฟล์คอนเนกเตอร์ของ Tajo เครื่องมือ propose จะเตรียมการดำเนินการที่ประกาศไว้ และเครื่องมือ apply จะรันการดำเนินการนั้นเมื่อได้รับอนุมัติ ไม่มีอะไรไปถึงผู้ให้บริการจนกว่าข้อเสนอจะได้รับอนุมัติ โดยบุคคลหรือโดยกฎที่เวิร์กสเปซเปิดใช้ แถวของการเรียก propose จะระบุการอนุมัติที่มันสร้างขึ้นไว้ในเรกคอร์ดของมัน ตัวการอนุมัติเองผูกกับไดเจสต์ SHA-256 ของอินพุตที่ตรงกันทุกตัวอักษร การอนุมัติครอบคลุมเฉพาะอินพุตที่คุณเห็นอย่างตรงทุกประการ เปลี่ยนเพียงฟิลด์เดียวก็จะไม่ตรงกันอีกต่อไป เมื่อการเขียนเกิดขึ้นจริง แถวการตรวจสอบของมันจะเก็บไดเจสต์ของอินพุตและไดเจสต์ของคำตอบจากผู้ให้บริการ ไม่เคยเก็บค่าในคำตอบนั้น
ต้นทุนของหนึ่งแถว
หนึ่งแถวคือการเขียนลงฐานข้อมูลหนึ่งครั้ง และการเขียนต้องมีการ commit จนถึงวันที่ 8 ตุลาคม 2026 การเรียกแต่ละครั้งต้องรอ commit ของตัวเองก่อนตอบกลับ ประมาณ 2.6 ms บนโฮสต์ของเรา สำหรับไคลเอนต์รายหนึ่ง นั่นคือหนึ่งในสี่ของการเรียกเครื่องมือเล็ก ๆ หนึ่งครั้ง
ตอนนี้แถวถูกสร้างเมื่อการเรียกจบลงและนำเข้าคิว การ flush จะเขียนคิวภายในไม่เกิน 100 ms ต่อมา หนึ่งทรานแซกชันต่อเวิร์กสเปซ การเรียกจำนวนมากจึงใช้ commit เดียวกัน ไม่มีอะไรในแถวเปลี่ยนไป รวมถึงเวลาประทับด้วย หากมีแถวรออยู่ 5,000 แถว การเรียกครั้งถัดไปจะรอการ flush แทนที่จะทิ้งแถวใดแถวหนึ่ง
การบันทึกไม่เคยทำให้การเรียกล้มเหลว การเขียนที่ล้มเหลวจะถูกลองใหม่ทีละแถว จากนั้นจะถูกบันทึกและทิ้งไป สิ่งที่สูญหายเมื่อโปรเซสถูกบังคับปิดคือสิ่งที่ค้างอยู่ในคิว ซึ่งก็คือการเรียกในช่วง 100 ms สุดท้ายเป็นอย่างมาก
การอ่านย้อนหลัง
logs.list คืนค่าการเรียกของเวิร์กสเปซ เรียงจากใหม่ไปเก่า โดยไม่มีเนื้อหา กรองได้ตามเวลา ตามผลลัพธ์หรือสถานะ HTTP ตามแหล่งที่มา (MCP หรือ REST API ซึ่งใช้ตารางเดียวกัน) และตามคีย์ API แบ่งหน้าละ 50 รายการโดยค่าเริ่มต้น สูงสุด 100 รายการ logs.get คืนค่าการเรียกหนึ่งครั้งพร้อมชื่อปัจจุบันของคีย์ สถานะ ระยะเวลา คำขอและคำตอบที่ทำความสะอาดแล้ว และเรกคอร์ดที่การเรียกแตะต้อง
ทั้งสองอ่านเฉพาะเวิร์กสเปซของผู้เรียกเท่านั้น id ของแถวจากเวิร์กสเปซอื่นจะหาไม่พบ
ข้อผิดพลาดของเครื่องมือจะมี id ของคำขอติดมาด้วย เมื่อเซิร์ฟเวอร์เป็นผู้สร้าง id นั้น หรือ id นั้นมาในรูปเลขฐานสิบหกหรือ UUID ก็จะเป็น trace id ของแถว เอเจนต์ที่ได้รับข้อผิดพลาดจึงส่งต่อค่าเดียวที่ระบุการเรียกนั้นให้คนได้
สิ่งที่สร้างแล้ว และสิ่งที่ยังไม่ได้สร้าง
สิ่งที่สร้างแล้ว ณ เวลาที่เขียน
- หนึ่งแถวต่อ
tools/callหนึ่งครั้งบนเซิร์ฟเวอร์เวิร์กสเปซและเซิร์ฟเวอร์คอนเนกเตอร์ทุกตัว รวมถึงการเรียกที่ถูกปฏิเสธและการเรียกที่ไม่รู้จัก - id ของคีย์ เซิร์ฟเวอร์ คอนเนกเตอร์ โปรไฟล์ เครื่องมือ ผลกระทบ ผลลัพธ์ ระยะเวลา ขนาดผลลัพธ์ trace id และเรกคอร์ดที่แตะต้องสูงสุด 20 รายการ
- อาร์กิวเมนต์และคำตอบที่ทำความสะอาดแล้ว สูงสุดอย่างละ 4 KB
logs.listและlogs.getจำกัดขอบเขตที่เวิร์กสเปซ เก็บไว้ 30 วัน- การอนุมัติที่ผูกกับไดเจสต์ของอินพุต และการเขียนที่ดำเนินการแล้วซึ่งบันทึกพร้อมไดเจสต์ของอินพุตและเอาต์พุตใน log การตรวจสอบแบบสายโซ่แฮช
สิ่งที่ยังไม่ได้สร้าง ซึ่งควรรู้ก่อนพึ่งพา
- ไม่มีคะแนนสุขภาพ ไม่มีกราฟรายเครื่องมือ และไม่มีการแจ้งเตือนเมื่ออัตราข้อผิดพลาดเพิ่มขึ้น สรุปรายเครื่องมือของจำนวนการเรียก ข้อผิดพลาด และระยะเวลาที่ช้าที่สุดมีอยู่สำหรับผู้ดูแลระบบของ Tajo ไม่ได้อยู่บนหน้าจอใดที่คุณเปิดได้
logs.listกรองตามชื่อเครื่องมือหรือ trace id ไม่ได้ หากต้องการหาแถวที่ตรงกับ id ของคำขอ ให้จำกัดขอบเขตด้วยเวลาและคีย์- แถวไม่ได้ถูกส่งออกไปยังระบบ tracing ที่คุณดูแล trace id อ่านจากเฮดเดอร์ HTTP เท่านั้น ไม่ได้อ่านจากฟิลด์ MCP
_metaที่การบรรยายใช้ส่งต่อบริบทของ trace - หลัง 30 วัน แถวจะถูกลบ ไม่มีการเก็บถาวรหรือการส่งออก
- สิ่งที่ถูกปิดบังไปแล้วไม่สามารถกู้คืนจาก log ได้
- การบังคับปิดอาจทำให้แถวในช่วง 100 ms สุดท้ายสูญหาย
การบรรยายปิดท้ายด้วยข้อสังเกตว่า observability ใน MCP นั้น “ยังกระจายไม่ทั่วถึง” แดชบอร์ดที่ปลายน้ำแก้ปัญหานี้ไม่ได้ trace ที่หยุดอยู่หน้าประตูเซิร์ฟเวอร์ก็แก้ไม่ได้เช่นกัน การซิงค์ที่ล้มเหลวต้องมีบันทึกของตัวเอง การเรียกทุกครั้งที่ร้องขอบางอย่างก็เช่นกัน
เซิร์ฟเวอร์เห็นการเรียกนั้น ไม่มีใครอื่นเห็น จงบันทึกไว้ที่นั่น
คำถามที่พบบ่อย
เซิร์ฟเวอร์ MCP ควรบันทึกอะไรสำหรับการเรียกเครื่องมือแต่ละครั้ง?
หนึ่งแถวต่อการเรียกหนึ่งครั้ง เขียนโดยเซิร์ฟเวอร์ ได้แก่ คีย์ API ใดเป็นผู้เรียก เซิร์ฟเวอร์และคอนเนกเตอร์ใด ชื่อเครื่องมือหากเครื่องมือนั้นมีอยู่จริง ระดับผลกระทบของเครื่องมือ ok หรือรหัสข้อผิดพลาดสั้น ๆ ระยะเวลา ขนาดของผลลัพธ์ trace id ของคำขอ id ของเรกคอร์ดที่การเรียกระบุถึงหรือสร้างขึ้น รวมถึงอาร์กิวเมนต์และคำตอบที่ลบข้อมูลลับและข้อมูลส่วนบุคคลออกแล้ว เซิร์ฟเวอร์ MCP ของ Tajo เขียนแถวนี้สำหรับทุก tools/call รวมถึงการเรียกที่ถูกปฏิเสธ และเก็บไว้ 30 วัน
log คำขอ MCP ควรเก็บอาร์กิวเมนต์ของเครื่องมือไว้หรือไม่?
ควรเก็บ แต่ต้องทำความสะอาดก่อน log ที่ไม่มีอาร์กิวเมนต์ไม่สามารถบอกได้ว่าทำไมการเรียกจึงล้มเหลว Tajo ไม่ได้เก็บเนื้อหา (body) ใด ๆ เลยจนถึงวันที่ 18 ตุลาคม 2026 และตอนนี้เก็บทั้งสองอย่างหลังผ่านการประมวลผลแบบกำหนดแน่นอนหนึ่งรอบ ข้อมูลลับกลายเป็น [secret] ข้อความอิสระและฟิลด์ข้อมูลส่วนบุคคลกลายเป็น [redacted] อีเมล หมายเลขโทรศัพท์ บัตร และ IBAN ถูกปิดบัง และเนื้อหาแต่ละส่วนถูกตัดที่ 4 KB การปิดบังนี้เป็นแบบถาวร log จึงอ้างถึงเรกคอร์ดด้วย id แทนการคัดลอกเรกคอร์ดนั้นมา
ทำไมจึงแยก log การเรียกเครื่องมือ MCP ออกจาก log การตรวจสอบ?
เพราะทั้งสองตอบคำถามต่างกันด้วยต้นทุนที่ต่างกัน log การตรวจสอบของ Tajo เป็นสายโซ่แฮชของการเปลี่ยนแปลงสถานะ และการเพิ่มแต่ละครั้งต้องล็อกระดับเวิร์กสเปซเพื่อต่อสายโซ่ หากเขียนทุกการอ่านผ่านสายโซ่นี้ การเรียกของเวิร์กสเปซจะต้องต่อคิวรอล็อกนั้น และการเปลี่ยนแปลงจะจมหายไปท่ามกลางการอ่าน การเรียกเครื่องมือจึงถูกบันทึกลงตารางแยกที่ไม่มีสายโซ่และเก็บไว้ 30 วัน ส่วนการเขียนที่การเรียกเตรียมไว้ยังคงทิ้งแถวการตรวจสอบของตัวเองไว้