−25%

على الدفع السنوي لـ Windows حتى 31 أكتوبر. عرض الخطط

EQVPS
ابدأ الآن

VPS لبوابة MCP: عدة خوادم MCP خلف عنوان واحد ورمز واحد

يستخدم فريقك ثلاثة خوادم MCP مستضافة ذاتيًا، ولدى كل شخص ثلاثة عناوين URL وثلاثة أسرار. ضعها خلف عنوان HTTPS واحد على VPS صغير: يتحقق Caddy من رمز bearer ويوجّه حسب المسار ويُبقي الخوادم نفسها بعيدًا عن الإنترنت. إعداد مُجرَّب.

تتكاثر خوادم MCP المستضافة ذاتيًا. أولًا يوجد واحد للتوثيق الداخلي، ثم واحد لقاعدة البيانات، ثم يكتب أحدهم خادمًا صغيرًا لمسار النشر. لكل منها منفذه وعنوانه وسرّه، ويلصق كل فرد في الفريق الثلاثة في إعدادات عميله. تغيير رمز يعني مراسلة الجميع.

البوابة تحوّل ذلك إلى عنوان واحد ورمز واحد. يتصل العملاء بـ https://mcp.example.com/docs/mcp و.../db/mcp وهكذا. تتحقق البوابة من الرمز، وترسل كل مسار إلى الخادم الصحيح على localhost، ولا تُكشف الخوادم نفسها أبدًا. لا يلزم سوى القليل: VPS صغير بعنوان IPv4 خاص وCaddy.

بنينا الإعداد التالي على خادم اختبار وتحققنا منه بعملاء حقيقيين قبل كتابته.

ما تحتاجه

  • VPS بعنوان IPv4 عام، ليصل العملاء إلى 443. تكفي Nano-IP ما لم تكن خوادم MCP لديك تؤدي عملًا ثقيلًا بنفسها.
  • نطاق بسجل 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

يحصل Caddy بنفسه على شهادة mcp.example.com.

كتلة 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 جديد تحت المضيف نفسه وبالرمز نفسه.

حدود تستحق المعرفة

  • رمز واحد للجميع بسيط وتغييره ملف واحد، لكن لا يمكنك سحب وصول شخص واحد دون تغييره للجميع. للوصول لكل مستخدم، ضع وكيل مصادقة أمامه أو أعطِ كل شخص مساره ورمزه.
  • البوابة لا تجعل الخادم آمنًا. خادم MCP ينفّذ أوامر shell يبقى shell لكل من يملك الرمز. أبعد الرموز عن الإعدادات المشتركة وعن git.
  • اختر الحجم بحسب الخوادم، لا البوابة. يستهلك Caddy نفسه بضع عشرات من الميغابايت. إذا كان أحد خوادمك يشغّل نموذجًا محليًا أو يفهرس مستودعًا كبيرًا، فهو من يحدد الخطة، لا الوكيل.

لديك خادم MCP واحد فقط؟ تتناول VPS لخوادم MCP تلك الحالة الأبسط. تريد أن يدير وكلاؤك أيضًا الخادم الذي يعيشون عليه؟ يقوم بذلك خادم MCP من EQVPS (أو REST API إن فضّلت السكربتات)، والخطط ذات IPv4 خاص تبدأ من $8 شهريًا.

الأسئلة الشائعة

لماذا أضع خوادم MCP خلف بوابة أصلًا؟

عنوان واحد ورمز واحد للفريق بدل واحد لكل خادم، وTLS في مكان واحد، والخوادم نفسها تستمع على localhost فقط. إضافة خادم رابع تصبح تعديل ثلاثة أسطر في البوابة، لا سرًّا جديدًا للجميع.

ما الخطة التي أحتاجها؟

خطة بعنوان IPv4 خاص، لأن العملاء يجب أن يصلوا إلى المنفذين 80 و443. خطة Nano-IP ($8 شهريًا، 2 vCPU، 1 GB) تكفي لبوابة وبضعة خوادم MCP خفيفة. إذا كان أحد الخوادم يؤدي عملًا ثقيلًا بنفسه، فاختر الحجم بحسبه.

هل يعمل البث عبر Caddy؟

نعم. يستخدم Streamable HTTP طلبات POST عادية مع server-sent events. اضبط flush_interval -1 على الوكيل العكسي كي تمر الأحداث فورًا بدل أن تُخزَّن مؤقتًا.

هل رمز مشترك واحد آمن بما يكفي؟

لفريق صغير هو بداية معقولة: الرمز لا يغادر HTTPS أبدًا، وتغيّره بتعديل ملف واحد. عندما تحتاج وصولًا لكل شخص أو إمكانية سحبه، ضع طبقة مصادقة حقيقية أمامه. الرمز المشترك هو الحد الأدنى، لا السقف.

هل يمكن تشغيل هذا على خطة NAT؟

ليس كبوابة عامة. خطة NAT فيها منفذ واحد معاد توجيهه لـ SSH ولا شيء وارد غيره، فلا يصل العملاء إلى 443. يعمل فقط إذا كان جميع العملاء على الخادم نفسه.

التعليقات

لا تعليقات بعد. كن الأول.

اترك تعليقًا

تُراجَع التعليقات قبل ظهورها.