فشل @discourse/mcp في التثبيت داخل مجلد فرعي — مسارات البداية بفاصلة (/) تُزيل مسار الموقع الفرعي
ملخص سريع
في نسخ Discourse المثبتة ضمن مسار فرعي (مثل https://example.com/forum)، لا يمكن لـ @discourse/mcp الاتصال لأن كل استدعاء داخلي للـ API يفقد المسار الفرعي، مما يؤدي إلى الوصول إلى جذر المضيف الخاطئ. هذا الأمر يعطل التحقق من صحة الموقع وكل استدعاء أداة لاحق (search، read_topic، إلخ)، وليس فقط التحقق عبر --site.
البيئة
@discourse/mcpالإصدار 0.2.7 (أحدث إصدار حتى وقت الكتابة)- Node عبر
npx -y @discourse/mcp@latest - الهدف: Discourse مستضاف في
https://<host>/forum(تثبيت داخل مجلد فرعي خلف nginx)
خطوات إعادة إنتاج المشكلة
- تأكد من وجود منتدى Discourse ضمن مسار فرعي، مثل
https://example.com/forum. تحقق من أنhttps://example.com/forum/about.jsonتُرجع رمز حالة200. - شغّل الأمر التالي:
npx -y @discourse/mcp@latest --site https://example.com/forum --log_level debug - أرسل أي طلب MCP (أو راقب ببساطة عملية التحقق عند بدء التشغيل).
المتوقع
أن يقوم الخادم بالتحقق من صحة https://example.com/forum/about.json، وأن تستدعي الأدوات https://example.com/forum/<endpoint>.
الفعلي
تُظهر سجلات التصحيح أن الطلب يذهب إلى جذر المضيف وليس المسار الفرعي:
DEBUG HTTP GET https://example.com/about.json
DEBUG HTTP GET https://example.com/about.json -> 403 Forbidden
ERROR Failed to validate --site https://example.com/forum: HTTP 403 Forbidden
يتم تجاهل مقطع /forum بصمت.
السبب الجذري
في الملف dist/http/client.js:42 (وفي مسار الكتابة المطابق عند :85):
const url = new URL(path, this.base).toString();
وفقًا لمواصفات WHATWG URL، تُعتبر حجة path التي تبدأ بـ / مطلقة وتستبدل مسار URL الأساسي. في جميع أنحاء قاعدة الكود، تُمرر المسارات بفاصلة ابتدائية، مثل:
dist/index.js:230—client.get('/about.json')dist/tools/builtin/select_site.js:15—client.get('/about.json')- تتبع جميع الأدوات المدمجة نفس النمط
'/...'.
النتيجة: new URL('/about.json', 'https://example.com/forum') تُنتج https://example.com/about.json. يُفقد المجلد الفرعي في كل استدعاء.
الإصلاح المقترح
إما (أ) توحيد المعالجة في عميل HTTP عن طريق إزالة الفاصلة الابتدائية من path وضمان أن يحتوي this.base على فاصلة نهائية قبل الحل:
const base = this.base.toString().replace(/\/?$/, '/');
const rel = path.replace(/^\//, '');
const url = new URL(rel, base).toString();
أو (ب) تغيير جميع مواقع الاستدعاء لاستخدام مسارات نسبية (بدون فاصلة ابتدائية). الخيار (أ) أكثر أمانًا — نقطة تغيير واحدة، دون مفاجآت سلوكية في أماكن أخرى.
حل بديل للمستخدمين المتأثرين
إذا كان تثبيت Discourse الخاص بك يحتوي أيضًا على نطاق فرعي يُعيد توجيه 301 إلى المسار الفرعي (مثل forum.example.com → example.com/forum/...)، فمرّر نطاق النطاق الفرعي كقيمة لـ --site. يتبع عميل HTTP الخاص بـ MCP إعادة التوجيه، لذا يتم حل كل استدعاء إلى عنوان URL للمسار الفرعي الصحيح، وتستمر المصادقة عبر القفزة. تم التأكد من عمله من البداية إلى النهاية (initialize، search، إلخ) على الإصدار v0.2.7.
إذا لم يكن هناك نطاق فرعي من هذا القبيل، فلا يوجد حاليًا حل بديل من جانب العميل — يجب إصلاح الخطأ في الحزمة.