6. การเชื่อมต่อผ่าน Claude (MCP)#
พนักงานทุกคนมี Claude ใช้อยู่แล้ว จึงให้ Claude เป็น ช่องทางหลักในการส่งข้อมูลเข้าระบบ
โดยเชื่อมผ่าน MCP server ที่ https://work.keycake.com/mcp
6.1 หลักการออกแบบ#
Claude คือช่องทางกรอก ไม่ใช่แหล่งความจริง
Claude อาจเข้าใจผิด เดาโครงการผิด หรือตีความวันที่ผิด ระบบจึงต้องออกแบบโดย สมมติว่าข้อมูลที่ส่งเข้ามาอาจผิดเสมอ
กติกา 5 ข้อ
- ตรวจสอบฝั่งเซิร์ฟเวอร์เสมอ — ห้ามเชื่อค่าที่ Claude ส่งมาโดยไม่ตรวจ
- ทุกการเขียนต้องผ่าน 2 จังหวะ —
preview(สรุปให้ดู) แล้วจึงcommit(บันทึกจริง) - เก็บข้อความดิบ —
raw_inputไว้ตรวจย้อนหลังเมื่อข้อมูลดูผิดปกติ - มีเว็บใช้แทนได้เสมอ — วันที่ Claude ล่ม ทีมต้องยังลงเวลาได้
- ผูกตัวตนกับคนจริง — ไม่มี token กลาง ทุกคนใช้ token ของตัวเอง
6.2 การยืนยันตัวตน#
sequenceDiagram
autonumber
actor U as พนักงาน
participant W as work.keycake.com
participant G as Google Workspace
participant CL as Claude
participant M as MCP Server
U->>W: เข้าเว็บครั้งแรก
W->>G: OAuth (จำกัดโดเมน buildupclick.com)
G-->>W: ยืนยันตัวตน
W-->>U: สร้าง Personal Token (แสดงครั้งเดียว)
U->>CL: ตั้งค่า MCP connector + วาง token
CL->>M: เรียก tool พร้อม token
M->>M: ตรวจ token → รู้ว่าเป็นใคร → ตรวจสิทธิ์
M-->>CL: ผลลัพธ์เฉพาะที่คนนี้มีสิทธิ์เห็น
- Token ผูกกับพนักงานรายคน เพิกถอนได้ทันทีจากหน้าเว็บ
- Token หมดอายุอัตโนมัติทุก 180 วัน
- ทุกการเรียก tool ถูกบันทึกใน audit log พร้อมชื่อคน
6.3 รายการ Tool#
กลุ่มลงเวลา#
| Tool | ทำอะไร | สิทธิ์ |
|---|---|---|
log_time |
ลงเวลาทำงาน (มี confirm เป็น 2 จังหวะ) |
ทุกคน |
get_my_timesheet |
ดู timesheet ตัวเองตามช่วงวันที่ | ทุกคน |
delete_time_entry |
ลบรายการที่ลงผิด (เฉพาะงวดที่ยังไม่ปิด) | เจ้าของรายการ |
get_missing_days |
เช็กว่าตัวเองยังไม่ได้ลงเวลาวันไหนบ้าง | ทุกคน |
กลุ่มกะ · OT · ลา#
| Tool | ทำอะไร | สิทธิ์ |
|---|---|---|
get_my_shifts |
ดูตารางกะตัวเอง | ทุกคน |
request_ot |
ขอ OT | ทุกคน |
request_leave |
ขอลา | ทุกคน |
get_my_requests |
ดูสถานะคำขอของตัวเอง | ทุกคน |
list_pending_approvals |
ดูคำขอที่รออนุมัติ | lead, executive |
approve_request |
อนุมัติ / ไม่อนุมัติ | lead, executive |
กลุ่มโครงการ#
| Tool | ทำอะไร | สิทธิ์ |
|---|---|---|
list_projects |
รายชื่อโครงการที่ตัวเองเกี่ยวข้อง | ทุกคน |
get_project_status |
สถานะโครงการ + ชั่วโมงสะสม | ทุกคน (ไม่เห็นตัวเงิน) |
list_my_work_items |
งานที่ได้รับมอบหมาย | ทุกคน |
update_work_item |
อัปเดตสถานะงาน | ผู้รับผิดชอบ, ba |
create_work_item |
สร้างงานใหม่ | ba, lead |
กลุ่มรายงาน (จำกัดสิทธิ์)#
| Tool | ทำอะไร | สิทธิ์ |
|---|---|---|
get_project_cost |
ต้นทุนโครงการเป็นตัวเงิน | executive, lead (เฉพาะทีมตัวเอง) |
get_client_pnl |
กำไร-ขาดทุนรายลูกค้า | executive |
get_team_hours |
ชั่วโมงรวมของทีม | lead, ba, executive |
กลุ่มคลังความรู้ (Phase 3)#
| Tool | ทำอะไร | สิทธิ์ |
|---|---|---|
search_kb |
ค้นหาความรู้เชิงความหมาย | ทุกคน |
create_kb_note |
บันทึกความรู้ใหม่ | ทุกคน |
6.4 ตัวอย่างสัญญาของ tool#
{
"name": "log_time",
"description": "บันทึกเวลาทำงานของผู้ใช้ปัจจุบัน ต้องเรียกด้วย confirm=false ก่อนเสมอเพื่อให้ผู้ใช้ตรวจสอบ",
"input_schema": {
"type": "object",
"properties": {
"entries": {
"type": "array",
"items": {
"type": "object",
"properties": {
"work_date": { "type": "string", "format": "date" },
"project_code": { "type": "string" },
"hours": { "type": "number", "multipleOf": 0.5 },
"kind": { "enum": ["shift","ot","support","internal","meeting"] },
"note": { "type": "string" }
},
"required": ["work_date","project_code","hours","kind"]
}
},
"confirm": { "type": "boolean", "default": false },
"raw_input": { "type": "string", "description": "ข้อความต้นฉบับที่ผู้ใช้พิมพ์" }
},
"required": ["entries","raw_input"]
}
}
ผลลัพธ์เมื่อ confirm=false — คืนสรุปที่อ่านง่ายให้ผู้ใช้ตรวจ พร้อมคำเตือนถ้ามี
เช่น "ชั่วโมงรวมวันนี้ 11 ชม. เกินเวลากะปกติ 8 ชม. — ต้องมีใบ OT หรือไม่?"
ผลลัพธ์เมื่อ confirm=true — บันทึกจริง คืน id ของแต่ละรายการ
{
"name": "request_ot",
"input_schema": {
"type": "object",
"properties": {
"ot_date": { "type": "string", "format": "date" },
"hours": { "type": "number", "multipleOf": 0.5 },
"project_code": { "type": "string" },
"reason": { "type": "string", "minLength": 10 },
"confirm": { "type": "boolean", "default": false }
},
"required": ["ot_date","hours","project_code","reason"]
}
}
ระบบตรวจก่อนรับ: ชนกะเดิมหรือไม่ · เกินเพดาน OT ของเดือนหรือไม่ · โครงการมีอยู่จริงหรือไม่ เมื่อสร้างสำเร็จ ระบบส่งแจ้งเตือนหาหัวหน้างานใน Google Chat
6.5 การตรวจสอบที่ต้องทำฝั่งเซิร์ฟเวอร์#
ทุกครั้งที่ log_time ถูกเรียกด้วย confirm=true:
| ลำดับ | ตรวจอะไร | ถ้าไม่ผ่าน |
|---|---|---|
| 1 | Token ใช้ได้และยังไม่หมดอายุ | ปฏิเสธ 401 |
| 2 | project_code มีอยู่จริงและยัง active |
ปฏิเสธพร้อมรายชื่อโครงการที่ใกล้เคียง |
| 3 | work_date ไม่เกิน 7 วันย้อนหลัง และไม่เป็นอนาคต |
ปฏิเสธ + แนะให้ขออนุมัติจากหัวหน้า |
| 4 | งวดของวันนั้นยัง open |
ปฏิเสธ — งวดปิดแล้ว |
| 5 | kind = 'ot' → ต้องมีใบ OT ที่อนุมัติแล้วครอบคลุมวัน+ชั่วโมงนั้น |
ปฏิเสธ |
| 6 | ชั่วโมงรวมของวันนั้น ≤ 16 | ปฏิเสธ |
| 7 | ไม่ซ้ำกับรายการเดิม | คืนรายการเดิม ไม่สร้างซ้ำ |
ข้อความ error ต้องบอกวิธีแก้
Claude จะอ่าน error แล้วอธิบายให้ผู้ใช้ต่อ
ดังนั้นแทนที่จะคืน "invalid project" ให้คืน
"ไม่พบโครงการรหัส LSM-MEM — โครงการที่ใกล้เคียงคือ LSM-MEMBER (ระบบสมาชิก LSM99)"
6.6 สิ่งที่ Claude ห้าม ทำ#
- ❌ อนุมัติ OT หรือลาแทนหัวหน้างานโดยอัตโนมัติ (ต้องเป็นการกระทำของหัวหน้างานเอง)
- ❌ แก้ไขข้อมูลของพนักงานคนอื่น
- ❌ เปิดเผยเงินเดือนหรือ cost_rate ให้บทบาทที่ไม่มีสิทธิ์
- ❌ ลบข้อมูลถาวร (มีแต่การทำเครื่องหมายยกเลิก)
- ❌ บันทึกข้อมูลโดยไม่ให้ผู้ใช้ยืนยัน