ข้าม​ไป​ยัง​เนื้อหา

3 primitive: tools / resources / prompts

บท​ที่ 1 วาง​ไว้​ว่า server ห่อ​ระบบ​ภายนอก​จริง​แล้ว​เปิด​ออก​มา​เป็น primitive สาม​แบบ บท​นี้​เจาะ​ที่​สาม​แบบ​นั้น​โดยตรง — แต่​เรา​กลับ​เข้า​ทาง​ที่​คน​ส่วน​ใหญ่​มอง​ข้าม จุด​ที่​ทำให้ tool, resource และ prompt เป็น​คนละ​อย่าง​กัน ไม่ใช่ “อ่าน​ข้อมูล vs เขียน​ข้อมูล” หรือ “GET vs POST” แต่​คือ ใคร​เป็น​ผู้​ตัดสิน​ใจ​ว่า​จะ​เรียก​มัน​เมื่อไร spec วาง​แกน​นี้ไว้ตรงๆ ใน​หน้า​ของ primitive แต่ละ​แบบ และ​มัน​คือ​เลนส์​ที่​จะ​ร้อย​ทั้ง​บท​ที่ 3–6 เข้า​ด้วย​กัน

📦 code ตัวอย่าง

คอร์ส​นี้​เป็น คอร์ส​ออกแบบ code ใน​บท​นี้​เป็น ภาพร่าง ของ primitive ที่ server เปิด​ออก​มา (schema + method + ใคร​ควบคุม) ไม่ใช่ server ที่​รัน​ได้​จริง ต่อยอด​จาก domain เดิม​ที่ repo kaen-food-ordering (กำลัง​จัด​ทำ) — server ออเดอร์ ของ platform ฟู้ด​เดลิ​เวอรี​ที่​ถูก​ห่อ​ให้ ops-copilot เรียก​ใช้

PrimitivePrimitiveหน่วย​พื้นฐาน​สาม​แบบ​ที่ MCP Server เปิด​ให้​ใช้ คือ Tool (model เลือก​เรียก​เอง), Resource (app เป็น​ผู้​แนบ​เข้า context), และ Prompt (ผู้​ใช้​เป็น​ผู้​เรียก​เอง) — สาม​แบบ​นี้​ต่าง​กัน​ตรง 'ใคร​เป็น​ผู้​ตัดสิน​ใจ​ว่า​จะ​เรียก​เมื่อไร' ไม่ใช่​แค่​รูปแบบ​ข้อมูล​ที่​ส่ง​มาArchitecture คือ​หน่วย​พื้นฐาน​ที่ MCP server เปิด​ออก​มา​ให้​ฝั่ง host เรียก​ใช้ มี​สาม​แบบ​พอดี — tool, resource, prompt — และ spec ออกแบบ​ให้​แต่ละ​แบบ​มี เจ้าของ​การ​ตัดสิน​ใจ ต่าง​กัน สรุป​เป็น​ตรี​เอกภาพ “ใคร​ควบคุม” ได้​ว่า tool model ควบคุม, resource app ควบคุม, prompt ผู้​ใช้​ควบคุม เหตุ​ที่​แกน​นี้​สำคัญ​กว่า​แกน “อ่าน/เขียน” ก็​เพราะ​มัน​บอกว่า​เรา​ต้อง ตรวจสอบ​สิทธิ์​และ​ผลลัพธ์​เข้มงวด​แค่​ไหน: สิ่ง​ที่ model เรียก​เอง​ได้​อัตโนมัติ​ต้อง​ระวัง​กว่า​สิ่ง​ที่​ผู้​ใช้​ต้อง​กด​เรียก​เอง​เสมอ

แกน 'ใคร​ควบคุม' คือ​ชั้น​ที่​ทน​ต่อ​การ​เปลี่ยน version

ตรี​เอกภาพ model / app / user นี้​เป็น​ถ้อยคำ เดียวกันเป๊ะ ระหว่าง spec ฉบับ 2025-06-18 กับ 2025-11-25 — ต่าง​จาก​รายละเอียด​สายส่ง/session ที่​กำลัง​ขยับ (ดู​กล่อง version ใน​บท​ที่ 1) มัน​คือ​หนึ่ง​ใน ชั้น​ที่​ทน​ต่อ​การ​เปลี่ยน version ที่​คอร์ส​นี้​เลือก​สอน​เป็น​แกน ใน​บท​นี้​ยัง​อ้าง path 2025-11-25 เสมอ​เพื่อ​ความ​สม่ำเสมอ

ToolToolfunction ที่ Server ประกาศ​ให้ model เรียก​เอง​ได้​ระหว่าง​ให้​เหตุผล เช่น ค้น​หา​ออเดอร์ หรือ​ยิง refund มัก​มี​ผล​ข้าง​เคียง​จริง (side effect) — เป็น Primitive แบบ Model-controlled ต้อง​ระวัง parameter ผิด สิทธิ์​เกิน​จำเป็น และ​คำ​อธิบาย tool ที่​ถูก​ฝัง​คำ​สั่ง​แฝงTactical Design คือ function ที่ server ประกาศ​ให้ model ค้น​พบ​และ​เรียก​เอง​ได้​อัตโนมัติ ระหว่าง​ให้​เหตุผล spec ระบุ​ตรง​ว่า “tool ใน MCP ถูก​ออกแบบ​ให้​เป็น model-controlled หมายความ​ว่า model ภาษา​สามารถ​ค้น​พบ​และ​เรียก tool ได้​เอง” (Tools, MCP spec 2025-11-25) model ขอ​รายการ​ที่​มี​ผ่าน tools/list แล้ว​สั่ง​เรียก​ผ่าน tools/call เอง โดย server ประกาศ​ความ​สามารถ tools (มี listChanged เสริม​ไว้​บอกว่า​รายการ tool เปลี่ยน​ได้​ระหว่าง session)

จุด​นี้​เอง​ที่​ทำให้ tool เป็น primitive ที่​ต้อง​ระวัง​ที่สุด: มัน​เป็น​แบบ Model-controlledModel-controlledลักษณะ​ของ Primitive ที่​ตัว model เป็น​ผู้​ตัดสิน​ใจ​เอง​ว่า​จะ​เรียก​เมื่อไร​และ​เรียก​อย่างไร เช่น Tool — ต่าง​จาก App-driven ที่ app เป็น​ผู้​ตัดสิน​ใจ​แทน ความ​แตก​ต่าง​นี้​กำหนด​ว่า​ควร​ตรวจสอบ​สิทธิ์​และ​ผลลัพธ์​เข้มงวด​แค่​ไหน ไม่ใช่​แค่​ดู​ว่า​ข้อมูล​นั้น 'อ่าน​อย่าง​เดียว' หรือ 'แก้ไข​ได้'Architecturemodelเป็น​ผู้​ตัดสิน​ใจ​ว่า​จะ​เรียก​เมื่อไร​และ​ด้วย parameter อะไร ไม่ใช่​มนุษย์ ใน​ตัว​อย่างฟู้ด​เดลิ​เวอรี find_late_orders(zone, since) คือ tool ที่ ops-copilot จะ​เลือก​ยิง​เอง​เมื่อ​มัน​คิด​ว่า​ควร​ยิง — ซึ่ง​เป็น​เหตุผล​ว่า​ทำไม schema และ​สิทธิ์​ของ tool จึง​เป็น​ทั้ง​พื้น​ผิว​การ​ใช้งาน​และ​พื้น​ผิว​การ​โจมตี (แกน​ของ​บท​ที่ 3)

ResourceResourceข้อมูล​ที่ Server เปิด​ให้ Host แนบ​เข้า context ได้ เช่น file log แถว​ใน​ฐาน​ข้อมูล หรือ​เอกสาร​นโยบาย — เป็น Primitive แบบ App-driven: app หรือ​ผู้​ใช้​เป็น​ผู้​เลือก​ว่า​จะ​แนบ​อัน​ไหน​เมื่อไร ไม่ใช่ model เรียก​เอง คล้าย endpoint อ่าน​อย่าง​เดียว​ที่​ไม่มี​ผล​ข้าง​เคียงTactical Design คือ​ข้อมูล​ที่ server เปิด​ให้ host เป็น​ผู้​เลือก​แนบ​เข้า context ไม่ใช่ model เรียก​เอง spec ระบุ​ว่า “resource ใน MCP ถูก​ออกแบบ​ให้​เป็น application-driven โดย app ฝั่ง host เป็น​ผู้​ตัดสิน​ใจ​ว่า​จะ​นำ context เข้า​มา​อย่างไร​ตาม​ความ​ต้องการ​ของ​ตัวเอง” (Resources, MCP spec 2025-11-25) นี่​คือ​แบบ App-drivenApp-drivenลักษณะ​ของ Primitive ที่ Host/Client เป็น​ผู้​ตัดสิน​ใจ​ว่า​จะ​ดึง​เข้า​มา​เมื่อไร​และ​อัน​ไหน ไม่ใช่ model เรียก​เอง เช่น Resource — ความ​เสี่ยง​จึง​ต่าง​จาก Tool เพราะ model ไม่​ได้​เลือก​เอง แต่​เนื้อหา​ที่​ดึง​มายัง​ปน​เปื้อน prompt injection ได้​เหมือน​กันArchitectureapp หรือ​ผู้​ใช้ผ่าน host เป็น​ผู้​ตัดสิน​ใจ​ว่า​จะ​ดึง resource ไหน​เข้า​มา​เมื่อไร

resource มี​สอง​อย่าง​ที่ tool ไม่มี อย่าง​แรก​คือ ตัวตน (identity): ทุก resource ระบุ​ด้วย URI (ตาม RFC 3986) และ​ถ้า​มี​รูปแบบ​ซ้ำๆ ก็​ประกาศ​เป็น Resource TemplateResource TemplateURI ที่​มี parameter (เช่น orders://{orderId}) ให้ Server ประกาศ​ชุด Resource ที่​มี​รูปแบบ​เดียวกัน​ได้​โดย​ไม่​ต้อง​แจง​ที​ละ​รายการ — Host เติม​ค่า parameter ก่อน​ขอ Resource จริง​ตาม​รูปแบบ​นั้น รองรับ​การ subscribe ฟัง​การ​อัปเดต​ได้​ด้วยTactical Design ด้วย URI Template (RFC 6570) ได้ เช่น orders://{orderId} แทนที่​จะ​แจง​ทุกออเดอร์​ที​ละ​รายการ อย่าง​ที่​สอง​คือ การ​ติดตาม​การ​เปลี่ยนแปลง: host ขอ​ผ่าน resources/list และ resources/read และ​ถ้า server รองรับ​ก็ resources/subscribe เพื่อ​รับ notifications/resources/updated เมื่อ​ข้อมูล​เปลี่ยน — เหมาะ​กับ context ที่​ต้อง​สด เช่น​สถานะ​ออเดอร์​ที่​กำลัง​วิ่ง

Prompt (MCP)Prompt (MCP primitive)template คำ​สั่ง/ขั้นตอน​สำเร็จรูป​ที่ Server เตรียม​ไว้​ให้​ผู้​ใช้​เรียก​เอง​ตรง ๆ เช่น​ผ่าน​เมนู​หรือ slash command — เป็น Primitive ที่​ผู้​ใช้​เป็น​ผู้​ควบคุม ต่าง​จาก Tool ที่ model เรียก​เอง และ​ต่าง​จาก Resource ที่ app เป็น​ผู้​แนบ​ให้ ใช้​มาตรฐาน​ขั้นตอน​งาน​ที่​ทำซ้ำ​บ่อยTactical Design คือ template คำ​สั่ง​หรือ​ขั้นตอน​สำเร็จรูป​ที่ server เตรียม​ไว้​ให้ ผู้​ใช้​เรียก​เองตรงๆ spec ระบุ​ว่า “prompt ถูก​ออกแบบ​ให้​เป็น user-controlled… โดย​ผู้​ใช้​สามารถ​เลือก​ใช้​มัน​ได้​อย่าง​ชัด​แจ้ง” (Prompts, MCP spec 2025-11-25) UI ตาม​แบบฉบับ​คือ slash command — ผู้​ใช้​พิมพ์ /triage_late_order เอง ไม่ใช่ model ไป​หยิบ​มา​เรียก​กลาง​ทาง host ขอ​รายการ​ผ่าน prompts/list และ​ดึง template จริง​ผ่าน prompts/get

เส้น​แบ่ง​จึง​คม​ชัด: prompt คือ​ของ​ที่ ผู้​ใช้ กด​เรียก, tool คือ​ของ​ที่ model เรียก​เอง, resource คือ​ของ​ที่ app แนบ​ให้ ทั้ง​สาม​อาจ “อ่าน​ข้อมูล​ออเดอร์” เหมือน​กัน​ได้ แต่​ต่าง​กัน​ที่​เจ้าของ​การ​ตัดสิน​ใจ ไม่ใช่​ที่​ชนิด​ของ​งาน

sampling กับ elicitation ไม่ใช่ primitive ของ server — เก็บ​ไว้​บท​ที่ 7

เดี๋ยว​จะ​เจอ​คำ​ว่า sampling (server ขอ​ให้ client ยิง completion จาก LLM แทน) และ elicitation (server ขอ​ข้อมูล​เพิ่ม​จาก​ผู้​ใช้​กลาง​ทาง) — สอง​อย่าง​นี้ ไม่ใช่ primitive ฝั่ง server แต่​เป็น ความ​สามารถ​ฝั่ง client ที่​ไหล​ย้อน​ทิศทาง เอา​มา​ปน​กับ​ตรี​เอกภาพ tool/resource/prompt จะ​ทำให้​ภาพ​เบลอ เรา​จะ​เปิด​มัน​ใน​บท​ที่ 7 ตอน​พูด​เรื่อง​การ​ประกอบ​และ​ระบบ​นิเวศ

flowchart LR
  M["model (LLM)<br/>ค้นพบ + เรียกเองอัตโนมัติ"]
  A["app / Host<br/>เลือกแนบเข้า context"]
  U["ผู้ใช้<br/>เรียกเองตรง ๆ"]
  subgraph SERVER["MCP Server (เช่น server ออเดอร์)"]
    T["Tool<br/>tools/list · tools/call"]
    R["Resource<br/>URI · template · subscribe<br/>resources/read"]
    P["Prompt<br/>prompts/list · prompts/get"]
  end
  M -->|"model-controlled"| T
  A -->|"application-driven"| R
  U -->|"user-controlled · slash command"| P
  classDef ctrl fill:#c7d2fe,stroke:#3730a3,color:#1a1a1f;
  classDef prim fill:#bbf7d0,stroke:#065f46,color:#1a1a1f;
  class M,A,U ctrl;
  class T,R,P prim;

คำ​บรรยาย​ภาพ: ผู้​ควบคุม​สาม​ฝ่าย (น้ำเงิน) จับ​คู่​กับ primitive สาม​แบบ (เขียว) แบบ​หนึ่ง​ต่อ​หนึ่ง — modelเรียก tool เอง​ผ่าน tools/call, app/host เลือก​แนบ resource เข้า context ตาม​ที่​เห็น​ควร, ผู้​ใช้กด​เรียก prompt เอง​ผ่าน slash command เส้น​แบ่ง​ของ primitive อยู่​ที่ ลูกศร​มา​จาก​ใคร ไม่ใช่​ที่​ตัว primitive อ่าน​หรือ​เขียน​ข้อมูล

พอ​มอง​ผ่าน​เลนส์ “ใคร​ควบคุม” การ​ออกแบบ server ก็​กลาย​เป็นการ​ตัดสิน​ใจ​ว่า​งาน​แต่ละ​อย่าง​ควร​ให้ ใครเป็น​ผู้​เรียก ภาพร่าง​ข้าง​ล่าง​คือ server ออเดอร์​ที่​เปิด​ครบ​ทั้ง​สาม​แบบ:

ภาพร่าง: primitive ของ server ออเดอร์ (ไม่ใช่ code รัน​ได้​จริง)
# Tool — model ควบคุม: ops-copilot เลือกยิงเองผ่าน tools/call
tools:
- name: find_late_orders # โผล่ให้ model เห็นผ่าน tools/list
# model ตัดสินใจเรียกเอง → ต้องรักษาสิทธิ์และตรวจผลลัพธ์เข้มที่สุด
# Resource — app ควบคุม: host เลือกแนบเข้า context เมื่อเห็นควร
resources:
- uri: orders://policy/refund # resources/read — เอกสารนโยบาย (คงที่)
- uriTemplate: orders://{orderId} # Resource Template (RFC 6570)
# subscribe → notifications/resources/updated เมื่อสถานะออเดอร์เปลี่ยน
# Prompt — ผู้ใช้ควบคุม: ผู้ใช้พิมพ์เรียกเองผ่าน slash command
prompts:
- name: triage_late_order # prompts/get — ผู้ใช้กด /triage_late_order เอง

ตรี​เอกภาพ​นี้​ต่อ​ตรง​เข้า​กับ​วินัย​จาก​คอร์ส Agent as Bounded Context: การ​เลือก​ว่า “อะไร​ควร​เป็น tool” คือ​การ​เลือก​ว่า อะไร​ที่​ยอม​ให้ model กด​ปุ่ม​เอง​ได้ — คือ​การ​วาง Anti-Corruption Layer / ACL ว่า model เอื้อม​ถึง​อะไร​ได้​บ้าง (บท​ที่ 3) ส่วน​ชื่อ​และ​คำ​อธิบาย​ของ primitive ทั้ง​สาม​แบบ​รวม​กัน​คือ ภาษา​ที่​เผยแพร่ (published language) ของ bounded context นั้น — เป็น​ภาษา​ที่ model ใช้​ให้​เหตุผล (บท​ที่ 5) และ​เพราะ ops-copilot เป็น host ที่​เห็น​บทสนทนา​ทั้งหมด การ​จับ​คู่ “งาน​ไหน​ให้​ใคร​เรียก” ให้​ถูก​จึง​เป็น​ก้าว​แรก​ของ​ความ​ปลอดภัย ก่อน​จะ​ไป​ถึง​เรื่อง trust boundary ใน​บท​ที่ 6


🔗 แหล่ง​อ้างอิง​หลัก​ของ​บท​นี้

บท​นี้​อ้างอิง​แหล่ง​ปฐม​ภูมิ​โดยตรง (ยัง​ไม่มี​การ์ด DevIQ สำหรับ primitive ของ MCP โดย​เฉพาะ):

เช็กความเข้าใจ — บทที่ 2

ข้อ 1 / 3

ในตรีเอกภาพ 'ใครควบคุม' ของ MCP — tool ถูกควบคุมโดยใคร (ณ spec 2025-11-25)?