MCPTest

MCPTest

An MCP server that provides AI agents with database tools for querying customer profiles and financial audit data, featuring semantic caching and automatic cache invalidation via webhooks to optimize performance and token usage.

Category
Visit Server

README

สรุประบบ: (MCP + AI Agent)


1. ระบบนี้ทำอะไร

ระบบ MCP ที่คอยคุมการทำงานของ AI เป็นผู้ช่วยตอบคำถามเรื่องข้อมูล

  • ผู้ใช้ถาม $\rightarrow$ Agent เลือก tool $\rightarrow$ tool เช็ก cache ก่อน ไม่มีค่อยไป DB จริง $\rightarrow$ ถ้า DB เปลี่ยน ระบบแจ้งเตือนกลับมาล้าง cache ทันที

2. องค์ประกอบหลัก

ไฟล์ หน้าที่
main.py AI Agent — รับคำถาม, ตัดสินใจเรียก tool ผ่าน Gemini
server.py MCP Server — เปิด tools ให้ Agent เรียกใช้ฐานข้อมูล
semantic_cache.py Cache ชั้น 1 — เก็บคำถาม-คำตอบเดิมแบบ embedding
webhook_cdc.py รับแจ้งเตือนจาก Supabase เมื่อข้อมูลเปลี่ยน แล้วล้าง cache
schema.sql โครงสร้าง DB (customers, purchase_ledger, customer_interactions)

3. ในฐานข้อมูล (DB) เก็บอะไรไว้บ้าง และป้องกันยังไง

DB (PostgreSQL บน Supabase) มี 3 ตารางหลัก:

ตาราง เก็บอะไร การป้องกัน / กลไก
customers ข้อมูลโปรไฟล์ลูกค้า (ชื่อ, ข้อมูลติดต่อ ฯลฯ) แก้ไขได้ปกติ แต่ทุกครั้งที่แก้ trigger จะยิง webhook แจ้งล้าง cache
purchase_ledger ประวัติธุรกรรม/ยอดการเงินของลูกค้า Append-only — ห้าม UPDATE/DELETE เด็ดขาด ผ่าน DB Trigger ที่บล็อกไว้ตรงๆ ที่ระดับฐานข้อมูล (ต่อให้เจาะเข้ามาตรงๆ ก็แก้ไม่ได้)
customer_interactions ประวัติการพูดคุย/โต้ตอบกับลูกค้า พร้อมเก็บ embedding vector (ใช้ extension pgvector) ใช้สำหรับ semantic search ย้อนดูบทสนทนาเก่าที่เกี่ยวข้อง

Hash Chain (สำหรับ purchase_ledger โดยเฉพาะ):

  • แต่ละ record ในตารางนี้จะมีค่า entry_hash ที่คำนวณจากข้อมูลของ record นั้น + prev_hash (hash ของ record ก่อนหน้า) ด้วย SHA-256
  • ทำให้ record ทั้งหมดเชื่อมกันเป็น "โซ่" ถ้ามีใครแอบไปแก้ข้อมูลตรงกลางโซ่ (แม้จะพยายามเลี่ยง trigger ก็ตาม) hash ของ record ถัดไปจะไม่ตรงกันทันที ตรวจจับได้ตอน audit
  • พูดง่ายๆ: ต่อให้ป้องกันด้วย trigger แล้ว hash chain คือ "เช็คซ้ำอีกชั้น" ว่าข้อมูลไม่ถูกแตะต้องจริงๆ

PROMPT ของ AI

SYSTEM_PROMPT = """
You are an Enterprise CRM & Financial Audit Ledger AI Assistant.
You have access to trusted backend tools that provide customer profiles, live financial transactions, audit logs, and historical interaction text search.
...
"""

4. Workflow

[1] ผู้ใช้พิมพ์คำถามเข้า main.py
      │
      ▼
[2] ระบบแปลงคำถามเป็น embedding (ด้วย Sentence-Transformers, รันในเครื่อง ไม่เสีย token)
      │
      ▼
[3] เช็ค Layer 1 – Semantic Cache ใน Redis
    ค้นด้วย key: semantic_cache:customer:{customer_id}:*
    เทียบ embedding คำถามใหม่ กับคำถามเก่าที่เคยถามและตอบไปแล้ว (cosine similarity)
      │
      ├───────────────────────────────┐
      ▼ (similarity ≥ 0.92)           ▼ ไม่เจอ / ไม่คล้ายพอ (MISS)
[4a] ส่งคำตอบเดิมกลับทันที          [4b] ส่งคำถาม + รายชื่อ tool ที่มีให้ Gemini
     จบ flow ตรงนี้                     (ไม่เรียก DB, ไม่เรียก DB cache เลย)
                                      │
                                      ▼
                                [5] Gemini ตัดสินใจว่าจะเรียก MCP tool ไหน
                                    (เช่น get_customer_profile, get_customer_financial_summary)
                                      │
                                      ▼
                                [6] Tool ทำงานผ่าน server.py
                                    เช็ค Layer 2 – DB Result Cache ใน Redis ก่อน
                                    key: cache:db:profile:{customer_id}
                                    หรือ cache:db:financial:{customer_id}:{page}:{limit}
                                      │
                                ┌─────┴──────┐
                                ▼ HIT        ▼ MISS
                          [7a] ดึงข้อมูล      [7b] Query PostgreSQL จริง
                               จาก Redis          แล้วเก็บผลลัพธ์ลง Redis
                               (เร็ว ไม่กิน DB)     (ตั้ง TTL 24 ชม.)
                                │            │
                                └─────┬──────┘
                                      ▼
                                [8] ได้ข้อมูลดิบกลับมาที่ Agent
                                      │
                                      ▼
                                [9] เรียก Gemini อีกครั้ง เพื่อเรียบเรียงข้อมูลดิบ
                                    ให้เป็นคำตอบภาษาคนอ่านง่าย
                                      │
                                      ▼
                                [10] ตอบกลับผู้ใช้
                                     + บันทึกคำถาม-คำตอบคู่นี้ลง Layer 1 cache
                                     (ไว้ให้คำถามคล้ายๆ กันครั้งหน้า hit ได้)
  • Layer 1 เช็คจาก ความหมายของคำถาม
  • Layer 2 เช็คจาก ผลลัพธ์ของ DB query ที่เคยทำมาก่อน — เป็นด่านที่สองที่กัน DB ไม่ให้โดนถามซ้ำ
  • ทั้งสอง layer แยกกันทำงานคนละหน้าที่ ไม่ใช่ตัวเดียวกัน

5. Webhook + Backend สำหรับล้าง Cache (CDC) — Workflow ละเอียด

[1] มีการเปลี่ยนแปลงข้อมูลจริงในตาราง customers หรือ purchase_ledger
    (เช่น เพิ่มธุรกรรมใหม่ / แก้โปรไฟล์ลูกค้า)
      │
      ▼
[2] PostgreSQL Trigger บนตารางนั้นทำงานทันที (ก่อน trigger นี้จะเรียกฟังก์ชัน notify_cache_invalidation() ที่เขียนไว้)
      │
      ▼
[3] ฟังก์ชันเรียก net.http_post(...) (มาจาก extension pg_net) ยิง HTTP POST ออกไปหา backend ภายนอก
      │
      ▼
[4] Backend ที่ deploy แยกไว้บน Render (ไฟล์ webhook_cdc.py, เขียนด้วย FastAPI) รับ request ที่ endpoint POST /api/webhook/db-change
      │
      ▼
[5] Backend ตรวจสอบ header x-supabase-signature เทียบกับ secret ที่ตั้งไว้
    → ถ้าไม่ตรง ปฏิเสธทันที (กัน webhook ปลอมยิงเข้ามาสั่งล้าง cache มั่ว)
      │
      ▼
[6] แกะ payload ดูว่า:
    - TG_TABLE_NAME = ตารางไหนที่เปลี่ยน (customers หรือ purchase_ledger)
    - ถ้า table = customers → เอา customer_id จาก record.id
    - ถ้า table = purchase_ledger → เอา customer_id จาก record.customer_id
      │
      ▼
[7] สั่งลบ key ใน Redis:
    - ลบ Layer 1 เสมอ: semantic_cache:customer:{customer_id}:*
      (เพราะคำตอบเก่าที่เคย cache ไว้อาจอ้างอิงข้อมูลลูกค้ารายนี้ที่เปลี่ยนไปแล้ว)
    - ลบ Layer 2 เฉพาะส่วนที่เกี่ยวกับตารางที่เปลี่ยน:
      cache:db:profile:{id} หรือ cache:db:financial:{id}:*
      │
      ▼
[8] ครั้งต่อไปที่มีคนถามถึงลูกค้ารายนี้ → Layer 1 และ Layer 2 จะ miss โดยอัตโนมัติ
    → ระบบไปดึงข้อมูลจาก DB จริง → ได้ข้อมูลล่าสุดเสมอ (Zero-Stale Data)

6. ทำไมเอา Redis มาใช้ (2-Layer Cache)

ปัญหาที่เจอ: ทุกครั้งที่ผู้ใช้ถามคำถาม ถ้าปล่อยให้ระบบวิ่งไปเรียก LLM หรือ query DB ใหม่ทุกครั้ง จะช้าและสิ้นเปลือง โดยเฉพาะกับคำถามที่ถามซ้ำๆ หรือคล้ายเดิม เลยเพิ่ม Redis เข้ามาเป็น cache 2 ชั้น:

  • ชั้น 1 (Semantic Cache) — คำถามคล้ายเดิม ตอบกลับเลยไม่ต้องเรียก LLM ใหม่
  • ชั้น 2 (DB Result Cache) — ผลลัพธ์จาก DB ที่ไม่ค่อยเปลี่ยน ดึงจาก Redis แทนที่จะยิง query เข้า PostgreSQL ใหม่ทุกครั้ง

7. ปัญหาการใช้ Token (LLM) และวิธีลด

ปัญหา: การเรียก Gemini ทุกครั้งที่มีคำถามเข้ามา ทำให้เสีย token และมี latency สูง โดยเฉพาะเวลาที่มีคนถามคำถามซ้ำๆ หรือคล้ายกัน วิธีที่แก้:

  1. Semantic Cache (Layer 1) — เช็คก่อนเรียก Gemini ทุกครั้งว่าเคยมีคนถามคำถามที่ "ความหมายคล้ายกัน" ไหม ถ้าคล้าย $\ge$ 0.92 $\rightarrow$ ข้ามการเรียก Gemini ไปเลย
  2. ใช้ Local Embeddings (Sentence-Transformers) แทนการยิง embedding ผ่าน API ของ Gemini/OpenAI — ขั้นตอนเช็คความคล้ายนี้เลยไม่เสีย token เพิ่มเลย เพราะรันฟรีแบบ offline
  3. แยก cache ตาม customer_id (multi-tenant) กันคำตอบของลูกค้ารายหนึ่งไปปนกับอีกราย

[!IMPORTANT] ข้อควรรู้: Layer 2 (DB cache) ช่วยลดแค่ฝั่ง DB load/latency เท่านั้น ไม่ได้ลด token ฝั่ง Gemini เพราะไม่ว่า Layer 2 จะ hit หรือ miss ตัว Agent ก็ยังต้องเรียก Gemini อย่างน้อย 2 ครั้งอยู่ดี (เลือก tool + สรุปคำตอบ) — ตัวเดียวที่ลด token จริงคือ Layer 1


8. ภาพรวมทั้งระบบ (End-to-End)

  1. ผู้ใช้ถามผ่าน main.py
  2. เช็ค Semantic Cache ก่อน — คล้ายพอก็ตอบเลย ไม่เรียก Gemini
  3. ถ้าไม่เจอ $\rightarrow$ Gemini เลือก tool ที่เหมาะสม
  4. Tool เช็ค DB Cache ก่อนค่อยไป PostgreSQL จริง
  5. ตอบกลับ + จำคำตอบไว้ใน cache
  6. ถ้า DB เปลี่ยนเมื่อไหร่ $\rightarrow$ Webhook ยิงมาล้าง cache อัตโนมัติทันที

NOTE

python3 -m venv venv
source venv/bin/activate # (สำหรับ Windows ให้ใช้: venv\Scripts\activate)
pip install -r requirements.txt

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured