SSD Nodes Learn
คู่มือ Matt Connorโดย Matt Connor · อัปเดตเมื่อ 2026-07-24

วิธีรัน MCP server บน VPS สำหรับ AI Agent

เรียนรู้วิธีติดตั้ง MCP server ทั้งแบบ stdio และ remote HTTP บน VPS โดยใช้ systemd และ nginx พร้อมวิธีตั้งค่า TLS และการรักษาความปลอดภัยของ JSON-RPC

สิ่งที่คุณกำลังสร้าง

การติดตั้ง MCP สองรูปแบบบน VPS เครื่องเดียว รูปแบบแรกคือ stdio server ซึ่งเป็นเครื่องมือจัดการ filesystem หรือ database ที่ Claude Code จะเรียกใช้งานในฐานะ child process และสื่อสารผ่าน pipe รูปแบบที่สองคือ remote HTTP server ซึ่งทำงานเป็น network service แบบ long-lived ภายใต้การดูแลของ systemd และ nginx reverse proxy พร้อม TLS โดยสามารถเข้าถึงได้จาก MCP client ใดก็ได้ การติดตั้งทั้งสองรูปแบบใช้ทรัพยากรน้อย เนื้อหาส่วนใหญ่ในคู่มือนี้จะเน้นไปที่สองประเด็นสำคัญ คือ การรักษาความถูกต้องของ JSON-RPC stream และการไม่เปิดใช้งาน tool endpoint ที่ไม่มีการยืนยันตัวตนบน public internet

MCP คืออะไร

Model Context Protocol คือมาตรฐานที่ช่วยให้ AI client เช่น Claude Code, Claude Desktop, Gemini CLI on a VPS หรือ script ของคุณ สามารถเรียกใช้งาน external tools และอ่าน external resources ได้ ตัว model เองไม่ได้เป็นผู้รันคำสั่งใดๆ แต่จะส่งคำขอไปยัง client จากนั้น client จะสื่อสารผ่าน JSON-RPC 2.0 ไปยัง MCP server เพื่อให้ server รัน tool และส่งผลลัพธ์กลับมา การใช้โปรโตคอลเดียวทำให้ server ที่เขียนขึ้นเพียงครั้งเดียวสามารถใช้งานร่วมกับ client ทุกตัวที่รองรับ MCP ได้

การสื่อสารมี 2 รูปแบบ (transports) ซึ่งเนื้อหาในคู่มือนี้จะแบ่งตามรูปแบบดังกล่าว:

  • stdio. client จะสร้าง server ขึ้นมาเป็น child process และแลกเปลี่ยนข้อความ JSON-RPC ที่คั่นด้วย newline ผ่านทาง standard input และ standard output ไม่มีการใช้ network, port หรือการทำ auth โดยขอบเขตความปลอดภัย (trust boundary) จะขึ้นอยู่กับตัว process เอง เครื่องมือแบบ local เกือบทั้งหมดใช้รูปแบบนี้
  • Streamable HTTP (และรูปแบบเดิมคือ HTTP+SSE) server จะทำงานเป็น web service ที่รันต่อเนื่อง Client จะเชื่อมต่อผ่าน HTTP และ server สามารถส่งข้อมูลกลับมาในรูปแบบ Server-Sent Events วิธีนี้ใช้สำหรับการแชร์ server หนึ่งตัวให้กับ client หลายตัว หรือใช้สำหรับรัน tool ที่ต้องทำงานอยู่บนเครื่องตลอดเวลา

เลือกใช้ stdio เมื่อ tool นั้นใช้งานเฉพาะบนเครื่องเดียวและสำหรับผู้ใช้คนเดียว เลือกใช้ HTTP เมื่อต้องการใช้งานในรูปแบบ shared service

Prerequisites and the honest gotchas

สมมติว่าคุณมี Ubuntu 24.04 KVM VPS ที่ติดตั้งใหม่และมีสิทธิ์ root หรือ sudo นอกจากนี้ต้องมีสิ่งต่อไปนี้:

  • Runtime ที่ใช้เขียน server โดยทั่วไป server ตัวอย่างจะใช้ Node หรือ Python ทั้งนี้ Ubuntu 24.04 มาพร้อมกับ Node 18 แต่ MCP package หลายตัวต้องการ Node 20 หรือใหม่กว่า ดังนั้นควรติดตั้งเวอร์ชัน LTS ล่าสุดจาก NodeSource หรือ nvm แทนการใช้ apt นอกจากนี้มี Python 3.12 ติดตั้งมาให้แล้ว
  • Domain และ DNS A record สำหรับ remote HTTP server เท่านั้น เนื่องจาก TLS จำเป็นต้องใช้ชื่อโดเมนที่ชี้มายัง VPS นี้ ส่วนตัวอย่างแบบ stdio ไม่จำเป็นต้องใช้ DNS
  • RAM 512 MB เพียงพอต่อการใช้งาน MCP server เป็นกระบวนการ JSON-RPC ที่ใช้ทรัพยากรน้อย การใช้หน่วยความจำจะขึ้นอยู่กับเครื่องมือที่คุณใช้งาน (เช่น database driver หรือ file cache) ไม่ใช่ขึ้นอยู่กับ protocol
  • Spec ยังอยู่ในช่วงเริ่มต้นและมีการเปลี่ยนแปลง การแก้ไขเมื่อ 2025-03-26 ได้เปลี่ยนจาก HTTP+SSE เป็น Streamable HTTP และระบุว่า SSE กำลังจะถูกยกเลิกการใช้งาน (deprecated) อย่างไรก็ตาม SSE ยังคงใช้งานได้และ server จำนวนมากยังรองรับอยู่ ดังนั้นควรตรวจสอบข้อกำหนดด้าน transport อีกครั้งจาก release notes ของ server แทนการยึดตาม spec เพียงอย่างเดียว

Step 1: wire a stdio server into Claude Code

Start with the filesystem server — it is official, actively maintained, and needs nothing but Node. The one command below registers it with Claude Code and scopes it to the current project so it lands in a committable file:

cd /home/matt/projects/api
claude mcp add --scope project --transport stdio filesystem \
  -- npx -y @modelcontextprotocol/server-filesystem /home/matt/projects/api

The -- separator matters: everything after it is the command Claude Code will run, not a flag for Claude Code. That writes a .mcp.json at the project root:

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/home/matt/projects/api"
      ]
    }
  }
}

Nothing is running yet. When you next start Claude Code in this directory, the agent reads .mcp.json, spawns npx -y @modelcontextprotocol/server-filesystem ... as a child process, and performs the MCP handshake over that process's stdin/stdout. Confirm it took:

claude mcp list

A healthy server prints its command and a green tick — filesystem: npx -y @modelcontextprotocol/server-filesystem ... - ✓ Connected. Inside the session, the /mcp slash command lists the tools the server exposes (read_file, write_file, list_directory), and the agent can now call them on the paths you allowed. A database tool is the same shape — swap the package and pass a connection string as its final argument — but check the server's own repository for the current package name, since the reference Postgres server has moved hands more than once.

This is the whole point of running the agent on the box: the Claude Code session lives on the VPS inside tmux, and its stdio servers run right beside it with direct access to the project files and local services, no network round-trip.

Step 2: สร้าง remote HTTP server

stdio server จะปิดตัวลงเมื่อ process หลักปิดตัวลง หากคุณต้องการเครื่องมือที่ทำงานค้างไว้สำหรับทุก client เช่น เครื่องมือจัดการระบบที่ใช้ร่วมกัน, database gateway หรือเครื่องมือที่ทั้ง laptop และ CI ต้องเรียกใช้งาน คุณจำเป็นต้องใช้ HTTP transport และบริการที่เป็น service จริง นี่คือตัวอย่าง Python server แบบเริ่มต้นที่ใช้ official SDK โดยเปิดใช้งานเพียงหนึ่ง tool:

# /opt/mcp-ops/server.py
from mcp.server.fastmcp import FastMCP
import subprocess

mcp = FastMCP("ops-tools", host="127.0.0.1", port=8000)

@mcp.tool()
def disk_free() -> str:
    """Return `df -h` for the server."""
    out = subprocess.run(["df", "-h"], capture_output=True, text=True)
    return out.stdout

if __name__ == "__main__":
    # Serves Streamable HTTP at /mcp on 127.0.0.1:8000
    mcp.run(transport="streamable-http")

โปรดทราบ host="127.0.0.1" server นี้ bind กับ localhost เท่านั้น อุปกรณ์ภายนอกไม่สามารถเชื่อมต่อโดยตรงได้ ซึ่งเป็นสิ่งที่ควรจะเป็นก่อนที่จะมีการตั้งค่า authentication ให้ติดตั้ง server ใน virtualenv ของตัวเอง เพื่อให้ systemd มี path ของ interpreter ที่คงที่:

sudo useradd --system --home /opt/mcp-ops --shell /usr/sbin/nologin mcp
sudo install -d -o mcp -g mcp /opt/mcp-ops
sudo -H -u mcp python3 -m venv /opt/mcp-ops/.venv
sudo -H -u mcp /opt/mcp-ops/.venv/bin/pip install "mcp[cli]"

Step 3: keep it alive with systemd

เครื่องมือที่หยุดทำงานเมื่อ agent เรียกใช้งาน จะส่งผลเสียยิ่งกว่าการไม่มีเครื่องมือ การเขียน /etc/systemd/system/mcp-ops.service จะเป็นดังนี้:

[Unit]
Description=MCP ops-tools server
After=network.target

[Service]
Type=simple
User=mcp
WorkingDirectory=/opt/mcp-ops
ExecStart=/opt/mcp-ops/.venv/bin/python /opt/mcp-ops/server.py
Restart=on-failure
RestartSec=2
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true

[Install]
WantedBy=multi-user.target

การระบุ absolute path ไปยัง venv Python ใน ExecStart เป็นสิ่งจำเป็น ต้องระบุไปยัง /usr/bin/python3 เพื่อให้ process เริ่มต้นด้วย ModuleNotFoundError: No module named 'mcp' เนื่องจาก system interpreter ไม่สามารถเข้าถึง pip install ของคุณได้ ให้ทำการ enable และตรวจสอบดังนี้:

sudo systemctl daemon-reload
sudo systemctl enable --now mcp-ops
sudo systemctl status mcp-ops
curl -si -H 'Accept: application/json, text/event-stream' \
  -H 'Content-Type: application/json' \
  -X POST http://127.0.0.1:8000/mcp

status ควรแสดงผลเป็น active (running) หาก curl ส่งคืนค่า HTTP/1.1 400 Bad Request พร้อม JSON-RPC error ใน body หมายความว่า request ไม่มี session และไม่มี JSON payload ที่ถูกต้อง ซึ่งเป็นผลลัพธ์ที่ต้องการ เพราะเป็นการยืนยันว่า port ตอบสนองและสื่อสารผ่าน protocol ได้ หากพบ Connection refused หรือการตอบกลับที่ว่างเปล่า แสดงว่า process ไม่ได้ bound อยู่ในตำแหน่งที่ระบุ ให้ตรวจสอบ journalctl -u mcp-ops -n 50

Step 4: การติดตั้ง TLS และ reverse proxy

Server ทำการ listen บน localhost การจะเข้าถึงจากภายนอกได้ต้องทำการ terminate TLS ที่ nginx และทำ proxy เข้าไปด้านใน ให้ติดตั้ง nginx และรับ certificate ด้วย Certbot and Let's Encrypt on nginx จากนั้นเขียน location block ส่วนที่สำคัญคือการปิดการใช้งาน buffering เนื่องจากพฤติกรรมเริ่มต้นของ nginx จะเก็บ response ไว้จนกว่าจะเสร็จสมบูรณ์ ซึ่งจะทำให้ SSE stream หยุดชะงัก:

server {
    listen 443 ssl;
    server_name mcp.example.com;

    # ssl_certificate lines managed by Certbot

    location /mcp {
        proxy_pass http://127.0.0.1:8000;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_set_header Host $host;

        # The four lines that make SSE work through nginx:
        proxy_buffering off;
        proxy_cache off;
        proxy_read_timeout 3600s;
        chunked_transfer_encoding off;
    }
}

ทำการ reload ด้วย sudo nginx -t && sudo systemctl reload nginx หากคุณใช้งาน container จำนวนมาก คุณสามารถใช้ Traefik reverse proxy with automatic TLS เพื่อจัดการแทนได้ โดย Traefik จะออก certificate และ route ตาม hostname เพียงแค่คุณเพิ่ม labels ใน MCP container ไม่ว่าจะใช้วิธีใด reverse proxy จะเป็นส่วนเดียวที่เปิดบน public port และชี้ไปยัง service ที่ยังไม่ได้รักษาความปลอดภัย โปรดแก้ไขส่วนนี้ให้เรียบร้อยก่อนนำ URL ไปลงทะเบียนที่อื่น

Step 5: กฎความปลอดภัยที่สำคัญที่สุดสำหรับหัวข้อนี้

ห้ามเปิดเผย MCP endpoint ที่ไม่มีการยืนยันตัวตนโดยเด็ดขาด MCP server ไม่ใช่ API แบบ read-only แต่เป็นช่องทางที่ให้สิทธิ์การเข้าถึง tool ต่างๆ เช่น ไฟล์, ฐานข้อมูล หรือแม้แต่ shell การเปิด /mcp ไว้บน public internet เปรียบเสมือนการอนุญาตให้บุคคลภายนอกเข้าถึงทรัพยากรได้เท่ากับ AI agent ของคุณ โดยพวกเขาสามารถเรียกดูรายการ tools และสั่งการได้ทันที จงปฏิบัติกับมันเหมือนกับ unauthenticated admin socket เพราะมันคือสิ่งเดียวกัน

แนวทางการป้องกัน 3 ระดับ เรียงตามลำดับความเหมาะสม:

  1. ไม่ต้องเผยแพร่สู่สาธารณะ ให้รัน server ไว้บน 127.0.0.1 และเชื่อมต่อจาก laptop ผ่าน SSH tunnel: ใช้คำสั่ง ssh -L 8000:127.0.0.1:8000 matt@vps จากนั้นกำหนดค่า client ให้ชี้ไปยัง http://127.0.0.1:8000/mcp วิธีนี้จะไม่มีข้อมูลใดถูกเปิดเผยสู่ภายนอก
  2. ใช้งานบน private network ให้ bind address ของ tunnel ผ่าน self-hosted WireGuard VPN และอนุญาตให้เฉพาะ peer ใน VPN เท่านั้นที่เข้าถึงได้ วิธีนี้จะทำให้ public internet มองเห็นเป็นเพียง port ที่ปิดอยู่
  3. หากจำเป็นต้องเปิดสู่สาธารณะ ต้องใช้ token วิธีที่ถูกต้องคือการใช้ MCP OAuth flow ซึ่งรองรับใน HTTP transport โดยตรง ส่วนวิธีที่ทำได้ง่ายที่สุดคือการใช้ shared bearer token ตรวจสอบที่ proxy ซึ่งช่วยป้องกันการโจมตีแบบสุ่มได้:
location /mcp {
    if ($http_authorization != "Bearer REPLACE_WITH_LONG_RANDOM") {
        return 401;
    }
    proxy_pass http://127.0.0.1:8000;
    # ...buffering-off block from above...
}

สร้าง token ด้วย openssl rand -hex 32 และห้าม bind server เข้ากับ 0.0.0.0 โดยไม่มีระบบป้องกันข้างต้นเด็ดขาด จากนั้นให้ client ส่ง token ผ่าน header สำหรับ Claude Code:

claude mcp add --scope project --transport http ops-tools https://mcp.example.com/mcp \
  --header 'Authorization: Bearer ${MCP_TOKEN}'

กำหนดค่า MCP_TOKEN ใน shell เพื่อไม่ให้ความลับถูกบันทึกเป็น plaintext ใน .mcp.json เนื่องจาก Claude Code จะดึงค่า ${MCP_TOKEN} จาก environment ในขณะที่อ่านข้อมูลเท่านั้น

Step 6: debug with the MCP Inspector

เมื่อ server ทำงานผิดปกติ ห้ามคาดเดาจากภายใน agent ให้ใช้ Inspector ซึ่งเป็น web-based test client อย่างเป็นทางการในการทดสอบโดยตรง สำหรับ stdio server ให้ใช้คำสั่งเดียวกับที่ agent ใช้รัน:

npx @modelcontextprotocol/inspector \
  npx -y @modelcontextprotocol/server-filesystem /tmp

ระบบจะเริ่มทำงานบน UI ที่ http://localhost:6274 (เวอร์ชันล่าสุดจะแสดง URL พร้อมกับ MCP_PROXY_AUTH_TOKEN query string — โปรดใช้ลิงก์นั้นโดยตรง มิฉะนั้น UI จะปฏิเสธการเชื่อมต่อ) และเริ่มทำงานบน proxy ที่พอร์ต 6277 ให้คลิก Connect จากนั้นเลือก List Tools และเลือก Call Tool พร้อมระบุ arguments จริง หากใช้งานใน Inspector ได้สำเร็จแต่ใช้งานใน agent ไม่ได้ แสดงว่าข้อผิดพลาดอยู่ที่การตั้งค่า client ไม่ใช่ที่ server สำหรับ remote HTTP server ให้เลือก transport แบบ Streamable HTTP จากนั้นระบุ https://mcp.example.com/mcp เพิ่ม header Authorization แล้วทำการเชื่อมต่อ วิธีนี้เป็นวิธีที่รวดเร็วที่สุดในการตรวจสอบว่าการยืนยันตัวตน (auth) และ proxy ทำงานถูกต้องก่อนที่จะเริ่มทดสอบด้วย agent

การรักษาเซิร์ฟเวอร์ให้เป็นเวอร์ชันล่าสุด

MCP มีการพัฒนาอย่างรวดเร็ว ดังนั้นควรติดตั้ง patch ตามกำหนดการที่วางไว้ เซิร์ฟเวอร์ Node ที่รันด้วย npx -y จะดึงเวอร์ชันล่าสุดทุกครั้งที่มีการ spawn ซึ่งสะดวกแต่ไม่สามารถทำซ้ำได้ (non-reproducible) ควรระบุเวอร์ชันที่แน่นอนที่คุณได้ทดสอบแล้ว โดยอ่านค่าจาก npm view @modelcontextprotocol/server-filesystem version และเพิ่มต่อท้ายชื่อ package ใน .mcp.json (@modelcontextprotocol/server-filesystem@<version>) เมื่อเซิร์ฟเวอร์มีความสำคัญ ให้ทำการอัปเดตเวอร์ชันอย่างระมัดระวัง ส่วนเซิร์ฟเวอร์ Python ที่รันภายใต้ systemd ให้ทำการอัปเดตด้วย sudo -H -u mcp /opt/mcp-ops/.venv/bin/pip install -U "mcp[cli]" ตามด้วย sudo systemctl restart mcp-ops ควรตรวจสอบการแก้ไข spec ที่ SDK ของคุณใช้งานเมื่อมีการอัปเกรด เนื่องจากการเปลี่ยนผ่านจาก SSE ไปเป็น Streamable-HTTP อาจทำให้รูปแบบการรับส่งข้อมูล (transport) ที่ client ต้องเรียกใช้นั้นเปลี่ยนแปลงไป

Failure modes, with the strings you will see

The agent shows the server failed. claude mcp list prints ✗ Failed to connect และ TUI รายงานว่า MCP server 'filesystem' failed to start ให้รัน claude --debug ซึ่งโดยปกติจะพบ Error: spawn npx ENOENT — สาเหตุคือคำสั่งไม่ได้อยู่ใน PATH ของ agent หาก runtime ไม่ได้ติดตั้งไว้หรืออยู่ในตำแหน่งที่ agent หาไม่พบ เช่น ไม่ได้ติดตั้ง Node, ไม่มี npx หรือมีการอ้างอิง Python virtualenv ด้วยชื่อเรียกสั้นๆ ให้แก้ไขคำสั่งเป็น absolute path หรือติดตั้ง runtime ให้เรียบร้อย แล้วจึงเชื่อมต่อใหม่

A stdio server connects, then instantly drops. Client บันทึกข้อผิดพลาด JSON parse เช่น Unexpected token 'S', "Server sta"... is not valid JSON หรือ Failed to parse message สาเหตุเกิดจาก server เขียน log ลงใน stdout เนื่องจากบน stdio นั้น stdout คือช่องทางของ JSON-RPC ดังนั้นข้อความอื่นที่หลุดออกมาจะทำให้ stream เสียหายและทำให้การ handshake ล้มเหลว ใน Node การใช้ console.log จะส่งข้อมูลไปที่ stdout — ให้ใช้ console.error แทน ใน Python การใช้ print() จะส่งข้อมูลไปที่ stdout — ให้เขียน log ด้วย logging ที่ตั้งค่าไปยัง sys.stderr หรือส่ง file=sys.stderr กฎสำคัญคือ บน stdio ต้องมีเพียง JSON-RPC บน stdout เท่านั้น ส่วนข้อความสำหรับมนุษย์ต้องส่งไปที่ stderr

A remote server times out or closes mid-handshake. Client ล้มเหลวด้วยข้อผิดพลาด MCP error -32000: Connection closed หรือ Inspector ค้างที่สถานะ Connect และไม่แสดงรายการ tools หากอยู่หลัง nginx สาเหตุเกิดจากการทำ buffering โดย proxy จะกักเก็บ SSE stream ไว้แทนที่จะ flush ข้อมูล ทำให้ client รอการตอบสนองที่ไม่มีวันมาถึง ให้เพิ่ม proxy_buffering off; (และส่วนที่เหลือใน block ของ Step 4) ลงใน location และตรวจสอบด้วย curl -N ผ่าน public URL — คุณควรเห็นข้อมูล event ค่อยๆ ทยอยมา ไม่ใช่มาพร้อมกันทั้งหมดในตอนท้าย

Auth is rejected. Client รายงานข้อผิดพลาด Error POSTing to endpoint (HTTP 401) หรือ 401 Unauthorized สาเหตุอาจเกิดจาก header หายไป, token ไม่ถูกต้อง หรือ shell variable ว่างเปล่าขณะที่ client อ่าน config — ซึ่งเป็นปัญหาที่พบบ่อย เนื่องจาก ${MCP_TOKEN} จะไม่แสดงค่าใดๆ หากตัวแปรไม่ได้ถูกตั้งค่า และ nginx จะเห็น Bearer ที่ไม่มีค่า ให้ลอง echo ตัวแปรดังกล่าว, เพิ่ม header อีกครั้ง และตรวจสอบว่า byte ตรงกับ token ใน nginx if หรือไม่

The service will not start under systemd. journalctl -u mcp-ops แสดง ModuleNotFoundError: No module named 'mcp'ExecStart ชี้ไปยัง system Python แทนที่จะเป็น interpreter ใน venv หรือแสดง Address already in use — มี process อื่นใช้งาน port 8000 อยู่ ให้ตรวจสอบด้วย sudo ss -ltnp | grep 8000

FAQ

MCP server คืออะไรกันแน่?

คือโปรแกรมที่เปิดใช้งาน tools และ resources ให้กับ AI client ผ่าน Model Context Protocol โดยใช้ JSON-RPC 2.0 ตัว AI model จะไม่ได้รัน tool ด้วยตัวเอง แต่จะส่งคำขอไปยัง client จากนั้น client จะเรียกใช้งาน MCP server และ server จะดำเนินการพร้อมส่งผลลัพธ์กลับมา เนื่องจากโปรโตคอลนี้เป็นมาตรฐาน เซิร์ฟเวอร์หนึ่งตัวจึงสามารถใช้งานร่วมกับ client ใดก็ได้ที่รองรับ ไม่ว่าจะเป็น Claude Code, Claude Desktop หรือ Gemini CLI

stdio และ HTTP transport ต่างกันอย่างไร?

stdio server จะถูกเรียกใช้งานโดย client ในฐานะ child process และสื่อสารผ่าน stdin/stdout จึงทำงานและสิ้นสุดการทำงานไปพร้อมกับ client หนึ่งตัวบนเครื่องเดียว โดยไม่จำเป็นต้องใช้ network หรือการยืนยันตัวตน ส่วน HTTP server เป็นบริการเครือข่ายที่ทำงานต่อเนื่องซึ่ง client หลายตัวสามารถเข้าถึงได้พร้อมกัน จึงจำเป็นต้องใช้ TLS และการยืนยันตัวตน ให้ใช้ stdio สำหรับเครื่องมือที่ใช้งานเฉพาะภายในเครื่องและใช้งานคนเดียว ส่วน HTTP (Streamable HTTP ในเซิร์ฟเวอร์ปัจจุบัน) ให้ใช้สำหรับงานที่ต้องแชร์หรือต้องการความคงทน

จะรักษาความปลอดภัยให้กับ remote MCP server ได้อย่างไร?

เนื่องจากเซิร์ฟเวอร์สามารถเข้าถึงไฟล์, database หรือ shell ของคุณได้ จึงห้ามเปิดใช้งานโดยไม่มีการยืนยันตัวตน วิธีที่ดีที่สุดคือการกำหนดให้เซิร์ฟเวอร์ทำงานบน localhost และเข้าถึงผ่าน SSH tunnel หรือ private VPN หากจำเป็นต้องเปิดสู่สาธารณะ ให้ใช้งานผ่าน reverse proxy ที่บังคับใช้ bearer token หรือ MCP OAuth flow โปรดสร้าง token ด้วย openssl rand -hex 32 และห้ามกำหนดให้เซิร์ฟเวอร์ผูกกับ 0.0.0.0 โดยไม่มีระบบป้องกันข้างต้น

จะ debug เซิร์ฟเวอร์ที่เริ่มทำงานไม่ได้อย่างไร?

อันดับแรกให้ตรวจสอบ claude mcp list — หากพบ ✗ Failed to connect ร่วมกับ spawn ... ENOENT แสดงว่าคำสั่งหรือ runtime หายไป ให้แก้ไข path หรือทำการติดตั้งใหม่ หากเซิร์ฟเวอร์เชื่อมต่อได้แต่หลุดด้วย JSON parse error แสดงว่าเซิร์ฟเวอร์กำลัง log ข้อมูลออกทาง stdout ซึ่งทำให้ข้อมูล JSON-RPC เสียหาย ให้เปลี่ยนการ log ทั้งหมดไปที่ stderr สำหรับปัญหาอื่นๆ ให้รันคำสั่งเดียวกันภายใต้ MCP Inspector ซึ่งจะรันเซิร์ฟเวอร์แบบแยกส่วน เพื่อให้คุณแยกแยะได้ว่าเป็น bug จากเซิร์ฟเวอร์หรือ bug จากการตั้งค่าของ client