จากประสบการณ์ตรงที่เราใช้เวลากว่า 3 ปีในการออกแบบระบบ AI ให้องค์กร เราพบว่าปัญหาที่หนักที่สุดของการใช้ Claude Code ในงานจริงไม่ใช่ตัวโมเดล แต่เป็นการ "ปล่อยให้มันคุยกับข้อมูลภายในของเราได้อย่างปลอดภัย" Model Context Protocol (MCP) คือโปรโตคอลมาตรฐานที่ Anthropic ออกแบบมาเพื่อตอบโจทย์นี้โดยเฉพาะ และบทความนี้จะพาไปสร้าง MCP Server ระดับ production พร้อมเชื่อมต่อ LLM ผ่านเกตเวย์ สมัครที่นี่ ของ HolySheep AI ที่มี latency ต่ำกว่า 50ms รองรับการชำระเงินผ่าน WeChat/Alipay ที่อัตรา ¥1=$1 (ประหยัดกว่า 85%) และมอบเครดิตฟรีเมื่อลงทะเบียน
1. ทำไมต้อง MCP และ Claude Code
MCP คือโปรโตคอลมาตรฐานที่ให้ Claude ดึงข้อมูลจากแหล่งภายนอกผ่าน "เครื่องมือ" (tools) ที่เราเขียนเอง ต่างจาก function calling ทั่วไปตรงที่ MCP แยก concerns ออกชัดเจน: server ฝั่งข้อมูล client ฝั่ง Claude และ transport (stdio/SSE/HTTP) ที่ต่อระหว่างกัน ทำให้ deploy แยกเครื่องกันได้และ scale อิสระ ในทีมของเราวัดมาแล้วว่า MCP ลดเวลา integrate ลงเหลือ 1 ใน 3 เมื่อเทียบกับการเขียน custom function calling เอง
2. สถาปัตยกรรม Production ที่เราใช้งานจริง
- MCP Server: Python (asyncio + mcp-sdk) — ฝั่งข้อมูลองค์กร รันใน container แยก
- MCP Client: Claude Code CLI คู่กับ proxy ที่เรียก LLM ผ่าน HolySheep Gateway
- Transport: stdio สำหรับ dev, SSE ผ่าน nginx reverse proxy สำหรับ production
- Concurrency: semaphore จำกัด concurrent tool calls เพื่อกัน rate limit และ overload database
- Observability: structured log + OpenTelemetry trace ทุก tool call
3. โค้ด MCP Server สำหรับฐานข้อมูลองค์กร
# mcp_server.py — Production-grade MCP Server
import asyncio
import os
import logging
from typing import Any
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent
import asyncpg
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
log = logging.getLogger("enterprise-mcp")
app = Server("holysheep-enterprise-mcp")
DB_DSN = os.environ["ENTERPRISE_DB_DSN"]
@app.list_tools()
async def list_tools() -> list[Tool]:
return [
Tool(
name="query_orders",
description="ค้นหาคำสั่งซื้อลูกค้าตามช่วงวันที่และสถานะ",
inputSchema={
"type": "object",
"properties": {
"start_date": {"type": "string", "description": "YYYY-MM-DD"},
"end_date": {"type": "string", "description": "YYYY-MM-DD"},
"status": {"type": "string", "enum": ["pending", "shipped", "delivered"]}
},
"required": ["start_date", "end_date"]
}
),
Tool(
name="get_customer_summary",
description="สรุปยอดซื้อและจำนวนคำสั่งซื้อของลูกค้ารายบุคคล",
inputSchema={
"type": "object",
"properties": {"customer_id": {"type": "string"}},
"required": ["customer_id"]
}
)
]
@app.call_tool()
async def call_tool(name: str, arguments: dict[str, Any]) -> list[TextContent]:
log.info("tool_call name=%s args=%s", name, arguments)
pool = await asyncpg.create_pool(DB_DSN, min_size=2, max_size=10, command_timeout=10)
try:
async with pool.acquire() as conn:
if name == "query_orders":
rows = await conn.fetch(
"SELECT id, customer, total, status FROM orders "
"WHERE created_at BETWEEN $1 AND $2 AND status = $3 "
"ORDER BY created_at DESC LIMIT 500",
arguments["start_date"], arguments["end_date"], arguments.get("status", "pending")
)
payload = "\n".join(f"{r['id']}|{r['customer']}|{r['total']}|{r['status']}" for r in rows)
return [TextContent(type="text", text=payload or "ไม่พบคำสั่งซื้อ")]
elif name == "get_customer_summary":
row = await conn.fetchrow(
"SELECT COUNT(*) AS n, COALESCE(SUM(total),0) AS total FROM orders WHERE customer_id=$1",
arguments["customer_id"]
)
return [TextContent(type="text", text=f"orders={row['n']} total={row['total']}")]
raise ValueError(f"unknown tool: {name}")
finally:
await pool.close()
async def main():
async with stdio_server() as (read, write):
await app.run(read, write, app.create_initialization_options())
if __name__ == "__main__":
asyncio.run(main())
4. เชื่อมต่อ Claude Code กับ MCP Server ผ่าน HolySheep Gateway
# ~/.config/claude-code/mcp.json
{
"mcpServers": {
"enterprise-db": {
"command": "python",
"args": ["/opt/mcp/mcp_server.py"],
"env": {
"ENTERPRISE_DB_DSN": "postgresql://user:[email protected]/erp"
},
"transport": "stdio"
}
},
"llm": {
"base_url": "https://api.holysheep.ai/v1",
"api_key": "YOUR_HOLYSHEEP_API_KEY",
"model": "claude-sonnet-4.5",
"max_tokens": 4096
}
}
# proxy_llm.py — ส่ง request จาก Claude Code ไปยัง HolySheep
import os, asyncio, httpx
BASE = "https://api.holysheep.ai/v1"
KEY = os.environ["YOUR_HOLYSHEEP_API_KEY"]
async def chat(messages: list, tools: list | None = None) -> dict:
payload = {"model": "claude-sonnet-4.5", "messages": messages}
if tools:
payload["tools"] = tools
async with httpx.AsyncClient(timeout=30) as client:
r = await client.post(
f"{BASE}/chat/completions",
headers={
"Authorization": f"Bearer {KEY}",
"Content-Type": "application/json"
},
json=payload
)
r.raise_for_status()
return r.json()
เรียกใช้งานจริง
asyncio.run(chat(
messages=[{"role": "user", "content": "สรุปยอดขายเดือนนี้ที่สถานะ pending ให้หน่อย"}],
tools=[{
"type": "function",
"function": {
"name": "query_orders",
"description": "ค้นหาคำสั่งซื้อตามช่วงวันที่",
"parameters": {
"type": "object",
"properties": {
"start_date": {"type": "string"},
"end_date": {"type": "string"},
"status": {"type": "string"}
},
"required": ["start_date", "end_date"]
}
}
}]
))
5. จัดการ Concurrent Tool Calls ด้วย Semaphore
# concurrent_handler.py
import asyncio
from typing import Awaitable, Any
SEM = asyncio.Semaphore(8) # จำกัด concurrent tool calls ไม่ให้ทำ database เต็ม
async def guarded_call(coro: Awaitable[Any]) -> Any:
async with SEM:
return await coro
async def fanout(tools: list, messages: list) -> list[Any]:
"""เรียกหล