เซิร์ฟเวอร์ MCP ที่โฮสต์เองมีแต่จะเพิ่มขึ้น ตอนแรกมีตัวหนึ่งสำหรับเอกสารภายใน แล้วอีกตัวสำหรับฐานข้อมูล แล้วมีคนเขียนตัวเล็ก ๆ ให้ pipeline ดีพลอย แต่ละตัวมีพอร์ต URL และความลับของตัวเอง และทุกคนในทีมก็วางทั้งสามไว้ในคอนฟิกไคลเอนต์ การเปลี่ยนโทเคนหมายถึงต้องแจ้งทุกคน
gateway เปลี่ยนเรื่องนี้ให้เหลือที่อยู่เดียวและโทเคนเดียว ไคลเอนต์เชื่อมต่อกับ https://mcp.example.com/docs/mcp, .../db/mcp และอื่น ๆ gateway ตรวจโทเคน ส่งแต่ละ path ไปยังเซิร์ฟเวอร์ที่ถูกต้องบน localhost และตัวเซิร์ฟเวอร์ไม่เคยถูกเปิดสู่ภายนอก ใช้ของน้อยมาก: VPS ขนาดเล็กที่มี IPv4 ของตัวเองกับ Caddy
เราตั้งค่าด้านล่างนี้บนเซิร์ฟเวอร์ทดสอบและตรวจกับไคลเอนต์จริงก่อนเขียน
สิ่งที่ต้องมี
- VPS ที่มี IPv4 สาธารณะ เพื่อให้ไคลเอนต์เข้าถึง 443 ได้ Nano-IP ก็พอ เว้นแต่เซิร์ฟเวอร์ MCP ของคุณทำงานหนักเอง
- โดเมนที่มี A record ชี้มาที่เซิร์ฟเวอร์ ในที่นี้คือ
mcp.example.com - Ubuntu 24.04 หรือ Debian 12/13 Caddy มีอยู่ในคลังแพ็กเกจมาตรฐานของทั้งสอง
1. รันเซิร์ฟเวอร์ MCP บน localhost
แต่ละเซิร์ฟเวอร์รันเป็นบริการ systemd ที่นี่เราใช้เซิร์ฟเวอร์ตัวอย่าง server-everything สองครั้งเพื่อให้ตัวอย่างครบในตัว ให้เปลี่ยนเป็นของคุณ ต้องใช้ Node.js 20 ขึ้นไป:
mkdir -p /opt/mcp && cd /opt/mcp
npm install @modelcontextprotocol/server-everything
# /etc/systemd/system/mcp-everything-1.service
[Unit]
Description=MCP server everything #1
After=network.target
[Service]
WorkingDirectory=/opt/mcp
Environment=PORT=3101
ExecStart=/opt/mcp/node_modules/.bin/mcp-server-everything streamableHttp
Restart=always
User=nobody
[Install]
WantedBy=multi-user.target
ชุดที่สองใช้พอร์ต 3102 จากนั้น:
systemctl daemon-reload
systemctl enable --now mcp-everything-1 mcp-everything-2
สิ่งที่เราสังเกตตอนทดสอบ: เซิร์ฟเวอร์นี้ฟังทุกอินเทอร์เฟซ ไม่ใช่แค่ 127.0.0.1 และตัวอื่นอีกมากก็เป็นแบบนี้ ขั้นที่ 3 จัดการเรื่องนี้
2. Caddy: ตรวจโทเคนก่อน แล้วเลือกเส้นทางตาม path
สร้างโทเคนแล้วส่งให้ Caddy ผ่านไฟล์ environment:
apt install -y caddy
echo "MCP_GATEWAY_TOKEN=$(openssl rand -hex 32)" > /etc/caddy/gateway.env
chmod 600 /etc/caddy/gateway.env
mkdir -p /etc/systemd/system/caddy.service.d
printf '[Service]\nEnvironmentFile=/etc/caddy/gateway.env\n' > /etc/systemd/system/caddy.service.d/env.conf
systemctl daemon-reload
Caddyfile:
mcp.example.com {
route {
@unauthorized not header Authorization "Bearer {$MCP_GATEWAY_TOKEN}"
respond @unauthorized 401
handle_path /everything/* {
reverse_proxy 127.0.0.1:3101 {
flush_interval -1
}
}
handle_path /tools2/* {
reverse_proxy 127.0.0.1:3102 {
flush_interval -1
}
}
respond 404
}
}
caddy validate --config /etc/caddy/Caddyfile && systemctl restart caddy
Caddy ขอใบรับรองสำหรับ mcp.example.com เอง
บล็อก route ไม่ได้มีไว้ประดับ เวอร์ชันแรกของเราวางการตรวจโทเคนกับบล็อก handle_path ไว้ข้างกันในระดับบนสุด แล้วคำขอที่ไม่มีโทเคนก็ผ่านไปได้ด้วย 200 Caddy เรียงลำดับ directive ตามแบบของมันเอง และ handle_path ทำงานก่อน respond ภายใน route จะทำงานตามลำดับที่เขียน ถ้าคุณดัดแปลงคอนฟิกนี้ ให้ทดสอบกรณี "ไม่มีโทเคน" ก่อนอย่างอื่น
handle_path ตัด prefix ออก ดังนั้น /everything/mcp จะไปถึงเซิร์ฟเวอร์เป็น /mcp ส่วน flush_interval -1 ส่งอีเวนต์สตรีมต่อทันทีที่มาถึง
3. ปิดทุกอย่างยกเว้น SSH และ HTTPS
apt install -y ufw
ufw default deny incoming
ufw allow OpenSSH
ufw allow 80,443/tcp
ufw enable
หลังจากนี้ ในการทดสอบของเรา พอร์ต 3101 และ 3102 เข้าจากภายนอกเซิร์ฟเวอร์ไม่ได้ ขณะที่ 22 และ 443 ตอบสนอง พอร์ต 80 เปิดไว้เพียงให้ Caddy ขอและต่ออายุใบรับรอง และเปลี่ยนเส้นทางไป HTTPS
4. ตรวจสอบ
TOKEN=$(cut -d= -f2 /etc/caddy/gateway.env)
INIT='{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"check","version":"1"}}}'
curl -s -o /dev/null -w '%{http_code}\n' -X POST https://mcp.example.com/everything/mcp \
-H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d "$INIT"
curl -s -o /dev/null -w '%{http_code}\n' -X POST https://mcp.example.com/everything/mcp \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d "$INIT"
คำขอแรกควรพิมพ์ 401 และคำขอที่สองพิมพ์ 200 ในการทดสอบของเรา โทเคนผิดและโทเคนที่ถูกตัดได้ 401 ทั้งคู่ และ path ที่ไม่รู้จักได้ 404 แม้ใช้โทเคนถูกต้อง
จากนั้นลองจากไคลเอนต์ เช่น Claude Code:
claude mcp add --transport http everything https://mcp.example.com/everything/mcp \
--header "Authorization: Bearer $TOKEN"
claude mcp list
เซิร์ฟเวอร์ทั้งสองแสดง ✔ Connected ไคลเอนต์เดียวกันที่ใช้โทเคนผิดแสดง ✘ Failed to connect อ่านเพิ่มเรื่องการตั้งค่าไคลเอนต์ได้ใน เชื่อมต่อ EQVPS MCP กับ Claude Code และ Codex
การเพิ่มเซิร์ฟเวอร์ตัวถัดไป
เริ่มมันบนพอร์ต localhost ใหม่ เพิ่มบล็อก handle_path หนึ่งบล็อก แล้วรีโหลด Caddy ไม่มีคอนฟิกของใครเปลี่ยน นอกจาก URL ใหม่ภายใต้โฮสต์เดิมและโทเคนเดิม
ข้อจำกัดที่ควรรู้
- โทเคนเดียวสำหรับทุกคน เรียบง่าย และเปลี่ยนได้ด้วยไฟล์เดียว แต่คุณเพิกถอนสิทธิ์ของคนเดียวโดยไม่เปลี่ยนของทุกคนไม่ได้ ถ้าต้องการสิทธิ์รายผู้ใช้ ให้วาง proxy ยืนยันตัวตนไว้ข้างหน้า หรือให้แต่ละคนมี route และโทเคนของตัวเอง
- gateway ไม่ได้ทำให้เซิร์ฟเวอร์ปลอดภัย เซิร์ฟเวอร์ MCP ที่รันคำสั่ง shell ก็ยังเป็น shell สำหรับใครก็ตามที่ถือโทเคน อย่าเก็บโทเคนไว้ในคอนฟิกที่แชร์กันหรือใน git
- เลือกขนาดตามเซิร์ฟเวอร์ ไม่ใช่ตาม gateway Caddy ใช้เพียงไม่กี่สิบเมกะไบต์ ถ้าเซิร์ฟเวอร์ตัวใดรันโมเดลในเครื่องหรือทำดัชนี repository ขนาดใหญ่ ตัวนั้นคือผู้กำหนดแพ็กเกจ ไม่ใช่ proxy
มีเซิร์ฟเวอร์ MCP ตัวเดียว? VPS สำหรับเซิร์ฟเวอร์ MCP อธิบายกรณีที่ง่ายกว่านั้น อยากให้เอเจนต์ดูแลเซิร์ฟเวอร์ที่มันอาศัยอยู่ด้วย? เซิร์ฟเวอร์ MCP ของ EQVPS ทำได้ (หรือ REST API ถ้าคุณชอบเขียนสคริปต์) และแพ็กเกจที่มี IPv4 ของตัวเอง เริ่มต้นที่ $8 ต่อเดือน
ความคิดเห็น
ยังไม่มีความคิดเห็น เป็นคนแรกสิ