নিজস্ব হোস্ট করা MCP সার্ভার বাড়তেই থাকে। প্রথমে অভ্যন্তরীণ ডকুমেন্টেশনের জন্য একটা, তারপর ডেটাবেসের জন্য একটা, তারপর কেউ ডিপ্লয় পাইপলাইনের জন্য ছোট একটা লেখে। প্রত্যেকটার নিজস্ব পোর্ট, URL আর সিক্রেট, আর টিমের প্রত্যেকে তিনটাই ক্লায়েন্ট কনফিগে বসায়। টোকেন বদলানো মানে সবাইকে জানানো।
গেটওয়ে এটাকে এক ঠিকানা ও এক টোকেনে পরিণত করে। ক্লায়েন্ট যুক্ত হয় https://mcp.example.com/docs/mcp, .../db/mcp ইত্যাদিতে। গেটওয়ে টোকেন যাচাই করে, প্রতিটি পাথ localhost-এর সঠিক সার্ভারে পাঠায়, আর সার্ভারগুলো কখনো বাইরে খোলা থাকে না। লাগে খুবই কম: নিজস্ব IPv4-সহ একটি ছোট VPS আর Caddy।
নিচের সেটআপ আমরা একটি টেস্ট সার্ভারে বানিয়েছি আর লেখার আগে আসল ক্লায়েন্ট দিয়ে যাচাই করেছি।
যা লাগবে
- পাবলিক IPv4-সহ একটি VPS, যাতে ক্লায়েন্ট 443-এ পৌঁছায়। আপনার MCP সার্ভার নিজে ভারী কাজ না করলে Nano-IP যথেষ্ট।
- সার্ভারের দিকে নির্দেশ করা A রেকর্ডসহ একটি ডোমেন, এখানে
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: আগে টোকেন যাচাই, তারপর পাথে রুট
একটি টোকেন বানান আর এনভায়রনমেন্ট ফাইল দিয়ে Caddy-কে দিন:
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
mcp.example.com-এর সার্টিফিকেট Caddy নিজেই নেয়।
route ব্লক সাজসজ্জা নয়। আমাদের প্রথম সংস্করণে টোকেন যাচাই আর handle_path ব্লক সর্বোচ্চ স্তরে পাশাপাশি ছিল, আর টোকেন ছাড়া রিকোয়েস্ট 200 নিয়ে সোজা পার হয়ে যাচ্ছিল। Caddy নির্দেশগুলো নিজের ক্রমে সাজায়, আর handle_path চলে respond-এর আগে। route-এর ভেতরে তারা লেখা ক্রমে চলে। এই কনফিগ বদলালে সবার আগে "টোকেন ছাড়া" ক্ষেত্রটা পরীক্ষা করুন।
handle_path প্রিফিক্স সরিয়ে দেয়, তাই /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 পেয়েছে, আর অচেনা পাথ সঠিক টোকেন দিয়েও 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 যোগ হয়।
যে সীমাগুলো জানা ভালো
- সবার জন্য এক টোকেন সহজ, আর বদলানো একটি ফাইলের কাজ, কিন্তু সবার জন্য না বদলে একজনের অ্যাক্সেস প্রত্যাহার করা যায় না। প্রতি ব্যবহারকারীর আলাদা অ্যাক্সেসের জন্য সামনে একটি অথ প্রক্সি বসান বা প্রত্যেককে নিজস্ব রুট ও টোকেন দিন।
- গেটওয়ে সার্ভারকে নিরাপদ করে না। shell কমান্ড চালানো MCP সার্ভার টোকেন থাকা যে কারও জন্য shell-ই থাকে। টোকেন শেয়ার করা কনফিগ আর git থেকে দূরে রাখুন।
- মাপ বাছুন সার্ভার দেখে, গেটওয়ে দেখে নয়। Caddy নিজে কয়েক দশ MB নেয়। কোনো সার্ভার লোকাল মডেল চালালে বা বড় রিপোজিটরি ইনডেক্স করলে প্ল্যান ঠিক করে সেটাই, প্রক্সি নয়।
শুধু একটি MCP সার্ভার? সেই সহজ ক্ষেত্রটা আছে MCP সার্ভারের জন্য VPS-এ। চান এজেন্টরা যে সার্ভারে থাকে সেটাও সামলাক? সেটা করে EQVPS MCP সার্ভার (বা স্ক্রিপ্ট পছন্দ হলে REST API), আর নিজস্ব IPv4-এর প্ল্যান শুরু মাসে $8 থেকে।
মন্তব্য
এখনো কোনো মন্তব্য নেই। প্রথম হোন।