
جسر بروكسي HTTP لاختبار أمان خوادم MCP البعيدة، مما يسمح لأدوات HTTP القياسية بإرسال رسائل JSON-RPC وإدارة الجلسات.
ينفّذ هذا المشروع خادم HTTP يعمل كجسر بين طلبات HTTP/1.1 وخادم MCP بعيد، باستخدام مكتبة mcp الخاصة ببايثون (GitHub).
الغرض الرئيسي من هذه المبادرة هو تمكين استخدام أدوات أمن HTTP لاختبار خوادم MCP البعيدة باستخدام آليات النقل عن بُعد (HTTP+SSE أو Streamable HTTP).
لُوحظ أنه عند إرسال رسائل JSON-RPC-V2 بنفس المعرّف (id)، باستخدام خيوط (threads) متزامنة، قد يحدث دمج للاستجابات. يرجى أخذ ذلك في الاعتبار عند استخدام الأداة في تقييمك. وإلى أن نُصلح هذه المشكلة، تأكد من أنك تختبر باستخدام خيط واحد فقط.
للبدء، استنسخ المستودع وقم بتثبيت التبعيات المطلوبة:
git clone <repository-url>
cd http-mcp-bridge
pip install -r requirements.txt
لتشغيل خادم HTTP، نفّذ الأمر التالي:
python3 main.py --remote-url="http://127.0.0.1:8787/mcp"
سيستمع خادم HTTP على الواجهة والمنفذ الافتراضيين (http://127.0.0.1:8000)، وسيتم إنشاء اتصال MCP بعنوان URL البعيد المقدَّم. يجب أن يوجد خادم MCP بعيد يطبّق آلية نقل مدعومة على العنوان المحدد. كان خادم HTTP يكتشف تلقائيًا آلية النقل الصحيحة، Streamable HTTP أو HTTP+SSE، لكن ذلك كان يسبب مشاكل مع بعض بيئات الإنتاج، لذا تم تعطيل هذه الميزة الآن. كان يستخدم آلية النقل Streamable HTTP افتراضيًا. سننشئ علامة (flag) لفرض استخدام HTTP+SSE، لكن في هذه الأثناء يمكنك ببساطة تعديل الكود وتمكين آلية النقل تلك.
يمكنك بعد ذلك إرسال طلبات HTTP إلى الخادم، والتي سيقوم بتمريرها إلى عملاء SSE/Streamable HTTP.
الآلية المطبَّقة في python SDK تنشئ قناة قراءة وقناة كتابة للتواصل مع نقطة النهاية باستخدام آلية النقل المقابلة. يقوم هذا الجسر HTTP to MCP Bridge بتمرير طلبات HTTP إلى قناة الكتابة، وينتظر الاستجابة (إن وُجدت) في قناة القراءة. وبمجرد استلامها، يتم تمرير تلك الاستجابة كاستجابة لطلب HTTP.
تدعم طلبات HTTP المعامل timeout، الذي يحدد أقصى عدد من الثواني التي ينتظرها الجسر للاستجابة في قناة القراءة قبل إرجاع رسالة خطأ. إذا كانت قيمة timeout صفرًا، فإن HTTP to MCP Bridge لا ينتظر إطلاقًا.
نظرًا لأن HTTP to MCP Bridge يدعم عدة جلسات مع خادم MCP، فإن الخطوة الأولى هي الحصول على معرف جلسة (session id)، والذي سيُستخدم في الطلبات اللاحقة.
الطلب:
GET /mcp/messages HTTP/1.1
Host: 127.0.0.1:8000
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
User-Agent: python-httpx/0.28.1
Content-Type: application/json
Cache-Control: no-store
Content-Length: 0
الاستجابة:
HTTP/1.1 400 Bad Request
date: Fri, 02 May 2025 15:40:32 GMT
server: uvicorn
content-length: 87
content-type: application/json
{"detail":"Invalid session id. Try /mcp/messages/7fc2cce5-3b0b-4d63-9df6-e703c1df091c"}
هذا المعرّف مختلف ومستقل عن معرف الجلسة المُنشأ بين عميل MCP والخادم. أما الأخير فيتم التعامل معه بواسطة مكتبة mcp داخليًا.
توجد طريقة ping يمكن استدعاؤها للتحقق من أن خدمة MCP موجودة وأن آلية النقل المختارة صحيحة.
الطلب:
POST /mcp/messages/7fc2cce5-3b0b-4d63-9df6-e703c1df091c HTTP/1.1
Host: 127.0.0.1:8000
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
User-Agent: python-httpx/0.28.1
Content-Type: application/json
Cache-Control: no-store
Authorization: Bearer [REDACTED]
Content-Length: 40
{"method":"ping","jsonrpc":"2.0","id":2}
الاستجابة:
[{"jsonrpc":"2.0","id":2,"result":{}}]
الخطوة الأولى في اتصال MCP هي مصافحة التهيئة، حيث يتبادل الطرفان القدرات المتاحة لديهما.
الطلب:
POST /mcp/messages/7fc2cce5-3b0b-4d63-9df6-e703c1df091c HTTP/1.1
Host: 127.0.0.1:8000
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
User-Agent: python-httpx/0.28.1
Content-Type: application/json
Cache-Control: no-store
Authorization: Bearer [REDACTED]
Content-Length: 213
{"method": "initialize", "params": {"protocolVersion": "2024-11-05", "capabilities": {"sampling": {}, "roots": {"listChanged": true}}, "clientInfo": {"name": "mcp", "version": "0.1.0"}}, "jsonrpc": "2.0", "id": 0}
الاستجابة:
[{"jsonrpc":"2.0","id":0,"result":{"protocolVersion":"2024-11-05","capabilities":{"tools":{}},"serverInfo":{"name":"Demo","version":"1.0.0"}}}]
يجب إغلاق المصافحة باستخدام هذه الرسالة، التي لا تحتوي على استجابة، لذا يمكننا استخدام timeout=0 في هذه المرحلة. سنتلقى رسالة خطأ مهلة (timeout)، لكن هذا أمر متوقع.
الطلب:
POST /mcp/messages/7fc2cce5-3b0b-4d63-9df6-e703c1df091c?timeout=0 HTTP/1.1
Host: 127.0.0.1:8000
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
User-Agent: python-httpx/0.28.1
Content-Type: application/json
Cache-Control: no-store
Authorization: Bearer [REDACTED]
Content-Length: 54
{"method":"notifications/initialized","jsonrpc":"2.0"}
الاستجابة:
{"message":"Timeout waiting for messages"}
بمجرد اكتمال المصافحة، يمكننا استدعاء الطرق المتاحة، مثل tools/list (سرد الأدوات).
الطلب:
POST /mcp/messages/7fc2cce5-3b0b-4d63-9df6-e703c1df091c HTTP/1.1
Host: 127.0.0.1:8000
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
User-Agent: python-httpx/0.28.1
Content-Type: application/json
Cache-Control: no-store
Content-Length: 46
{"method":"tools/list","jsonrpc":"2.0","id":1}
الاستجابة:
[{"jsonrpc":"2.0","id":1,"result":{"tools":[{"name":"add","inputSchema":{"type":"object","properties":{"a":{"type":"number"},"b":{"type":"number"}},"required":["a","b"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}]}}]
أخيرًا، يمكننا استدعاء الأدوات أو الاستفادة من القدرات الأخرى.
الطلب:
POST /mcp/messages/7fc2cce5-3b0b-4d63-9df6-e703c1df091c HTTP/1.1
Host: 127.0.0.1:8000
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
User-Agent: python-httpx/0.28.1
Content-Type: application/json
Cache-Control: no-store
Content-Length: 100
{"method":"tools/call","params":{"name":"add","arguments":{"a":1, "b":2 }},"jsonrpc":"2.0","id":2}
الاستجابة:
[{"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":"3"}]}}]
المساهمات مرحّب بها! يرجى فتح issue أو إرسال pull request لأي تحسينات أو إصلاحات للأخطاء.
هذا المشروع مرخّص بموجب رخصة MIT. راجع ملف LICENSE لمزيد من التفاصيل.