خادم MCP
يمنح خادم MCP (Model Context Protocol) الخاص بـ SupDesk مساعدي الذكاء الاصطناعي وغيرها من الأدوات المدعومة بنماذج اللغة وصولاً مباشرًا إلى مركز المساعدة ولوحة الملاحظات وسجل التغييرات وسلاسل الرسائل وبرامج بيتا وقائمة الانتظار في مشروع ما.
نقطة النهاية
https://mcp.supdesk.app/mcpالمصادقة
مرّر مفتاح API كأسلوب Bearer:
Authorization: Bearer sd_live_...أنشئ المفاتيح في وحدة تحكّم SupDesk تحت إعدادات مساحة العمل ← مفاتيح API.
يحدّد المفتاح المشروع، ولذلك لا تأخذ أي أداة معامل project_id — فليس هناك ما يمكن
للنموذج أن يخمّنه أو يخطئ فيه.
ما تحصل عليه
تعتمد الأدوات التي تظهر على المشروع. فالميزة المطفأة في إعدادات المشروع تُحذف أدواتها
كليًا من tools/list، تمامًا كما يعيد REST API الرمز 404 لتلك المسارات.
| المجموعة | الأدوات | تتطلّب |
|---|---|---|
| مركز المساعدة | 10 | تفعيل مركز المساعدة |
| لوحة الملاحظات | 5 | تفعيل لوحة الملاحظات |
| سجل التغييرات | 5 | تفعيل سجل التغييرات |
| الرسائل | 5 | تفعيل الرسائل الخاصة |
| الاختبار التجريبي | 8 | تفعيل بيتا |
| قائمة الانتظار | 4 | تفعيل قائمة الانتظار |
| النظرة العامة | 1 | متاحة دائمًا |
القراءات تعمل في كل خطة. أما الكتابات فتتطلّب خطة مدفوعة — فعملية إنشاء أو تحديث أو
حذف بمفتاح للقراءة فقط تعيد forbidden، بينما تعمل القراءات بالمفتاح نفسه دون مشكلة.
مركز المساعدة
list_articles— المقالات، بأحدث تحرير أولاً. تشمل المسودات والمقالات المؤرشفة؛ صفِّ بـstatusللحصول على ما يراه العملاء.get_article— مقال واحد بالمعرّف، بما في ذلك متنه بتنسيق Markdown.search_articles— بحث نصّي كامل عبر المقالات المنشورة، مُرتَّب، مع مقتطف.create_article— ينشئ مسودة. والنشر استدعاء منفصل، فلا يصل شيء إلى العملاء عرضًا.update_article— عدّل أي حقل؛ اضبطstatusعلىpublishedأوarchived.delete_article— نهائي؛ أرشِف بدلاً من ذلك لإخراج مقال تريد الاحتفاظ به من الخدمة.list_article_categoriesوcreate_article_categoryوupdate_article_categoryوdelete_article_category— حذف فئة يترك مقالاتها في مكانها، غير مصنّفة.
متون المقالات بتنسيق Markdown، لا HTML. وتعرضها البوابة عبر عارض لا يُنفّذ HTML أبدًا، فيصل HTML إلى القرّاء كنص حرفي.
يفشل create_article بالخطأ limit_reached بمجرد نفاد حصة مقالات الخطة — Free 5،
وPro 50، وTeam بلا حدود.
لوحة الملاحظات
list_feedback— المنشورات، الأحدث أولاً. تغطي الأنواع الثلاثة (bugوfeatureوfeedback) ما لم تضيّقها بـtype.get_feedbackوcreate_feedbackوupdate_feedback— وupdate_feedbackهو الطريقة التي تنقل بها منشورًا عبرbacklog → open → planned → in_progress → done.delete_feedback— يزيل المنشور وأصواته وتعليقاته.
سجل التغييرات والرسائل وبيتا وقائمة الانتظار
تكافؤ كامل مع REST API، عبر الاستعلامات نفسها:
- سجل التغييرات —
list_changelogوget_changelog_entryوcreate_changelog_entryوupdate_changelog_entryوdelete_changelog_entry. والمدخلات مسودات افتراضيًا، لأن النشر هو ما يرسل البريد إلى مشتركيك. - الرسائل —
list_threadsوget_thread(مع سجل الرسائل الكامل) وcreate_threadوreply_to_threadوupdate_thread. - الاختبار التجريبي —
list_beta_programsوget_beta_programوcreate_beta_programوupdate_beta_programوdelete_beta_programوlist_beta_testersوadd_beta_testerوremove_beta_tester. وadd_beta_testerعملية مُتماثلة بحسب البريد الإلكتروني وتعيد رمز القبول؛ وهذا الخادم لا يرسل بريدًا، فتسليم الدعوة من مسؤوليتك. - قائمة الانتظار —
list_waitlistوadd_waitlist_signup(مُتماثلة بحسب البريد الإلكتروني) وupdate_waitlist_signupوremove_waitlist_signup.
النظرة العامة
يعيد project_stats أعدادًا عبر المشروع — منشورات الملاحظات حسب الحالة، والسلاسل
المفتوحة، والمقالات المنشورة والمسودات، وأصوات مفيد / غير مفيد التي جمعتها تلك المقالات —
حتى يستطيع وكيل الإجابة عن “كم بقي معلّقًا؟” دون المرور على أربع قوائم مُصفّحة.
المخرجات المنظَّمة
تعلن كل أداة عن outputSchema وتعيد كلاً من structuredContent (مُنمَّط ومُتحقَّق منه)
وكتلة نص content تحمل البيانات نفسها بصيغة JSON. حلّل أيًا منهما يدعمه عميلك.
const result = await mcpClient.callTool("get_article", { id: "8f7a..." });
result.structuredContent.article.title; // typed
JSON.parse(result.content[0].text); // same payload, fallbackالتعليقات التوضيحية
تحمل كل أداة تعليقات توضيحية ليعرف العميل ما الذي يستدعيه قبل أن يستدعيه:
| التعليق التوضيحي | مضبوط على |
|---|---|
readOnlyHint: true | list_* وget_* وsearch_* وproject_stats |
idempotentHint: true | القراءات وupdate_* |
destructiveHint: true | delete_* وremove_* |
التصفّح بالصفحات
تأخذ أدوات السرد cursor غير شفاف وتعيد next_cursor — مرّره مرة أخرى للصفحة التالية،
وتوقّف عندما يكون null.
let cursor;
do {
const page = await mcpClient.callTool("list_articles", { status: "published", cursor });
handle(page.structuredContent.data);
cursor = page.structuredContent.next_cursor;
} while (cursor);الـ cursor رمز، لا عملية حسابية — تعامل معه كغير شفاف. والمشوّه منه يعيد
invalid_request بدلاً من أن يبدأ بصمت من الصفحة الأولى، وهو ما كان سيجعل المرور المُصفّح
يدور إلى الأبد.
لاحظ أن هذه مواضعة داخل مخطط معاملات كل أداة على حدة. أما cursor على مستوى بروتوكول MCP فينطبق على سرد الأدوات والموارد، لا على ما تعيده أداة؛ وسرد الموارد أدناه يستخدم الشيء الحقيقي.
الموارد
لإرفاق محتوى المشروع كسياق، بدلاً من استدعاء أداة ولصق النتيجة:
| URI | المحتويات |
|---|---|
supdesk://articles/{slug} | مقال مساعدة منشور، بتنسيق Markdown. |
supdesk://board | منشورات الملاحظات المفتوحة في المشروع، بصيغة JSON. |
سرد المقالات مُصفّح فعليًا على مستوى البروتوكول، ويغطي المقالات المنشورة فقط — فالمورد محتوى قد يعرضه العميل حرفيًا، والمسودة غير منشورة لسبب.
الموجّهات
نقطتا انطلاق، موصولتان ببيانات المشروع الحقيقية:
draft_article_from_thread— يحوّل محادثة دعم محلولة إلى مقال في مركز المساعدة، فيجد العميل التالي صاحب السؤال نفسه الإجابة بدل أن يفتح سلسلة. يحتاج إلى تفعيل مركز المساعدة و الرسائل الخاصة.triage_feedback— يقيّم منشورًا واحدًا ويوصي بحالة، مع التعليل. ويتحقّق منsearch_articlesأولاً، فتُطرح إجابة موجودة بدلاً من اقتراح عمل جديد.
وكلاهما يستخدم قدرة الإكمال في MCP لمعاملاته: فبينما تكتب فئة، يجيب الخادم بـ slugs الفئات الفعلية للمشروع بدلاً من أن يتركك تخمّن.
التسجيل
ترسل الكتابات متعددة الخطوات إشعارات تقدّم عبر تسجيل MCP — فـ create_article يتحقّق من
حصة الخطة، ثم يبحث عن slug متاح، ثم يُدرج، ويعلن ذلك في كل خطوة. والعميل الذي لا يدعم
التسجيل غير متأثر؛ فالكتابة تمضي في الحالتين.
أمثلة
Claude Desktop
أضف إلى ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"sup-desk": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://mcp.supdesk.app/mcp",
"--header",
"Authorization: Bearer sd_live_..."
]
}
}
}أجب عن سؤال، أو اكتب الإجابة
// Check whether the help center already covers it.
const hits = await mcpClient.callTool("search_articles", {
query: "reset password",
limit: 5
});
if (hits.structuredContent.data.length === 0) {
// Nothing yet — draft one. It's created as a draft.
const created = await mcpClient.callTool("create_article", {
title: "How do I reset my password?",
body: "Open **Settings**, then choose *Reset password*.",
category_id: "3c2b..."
});
// Publishing is deliberate and separate.
await mcpClient.callTool("update_article", {
id: created.structuredContent.article.id,
status: "published"
});
}افرز اللوحة
const open = await mcpClient.callTool("list_feedback", {
status: "open",
limit: 10
});
await mcpClient.callTool("update_feedback", {
id: open.structuredContent.data[0].id,
status: "planned"
});كل ما هو معلّق، في استدعاء واحد
const stats = await mcpClient.callTool("project_stats", {});
// { posts_by_status: { open: 12, planned: 3, ... }, open_threads: 4,
// articles_published: 18, articles_draft: 2,
// article_helpful: 240, article_not_helpful: 11 }حدود المعدل
يتشارك خادم MCP حدود REST API نفسها: 120 طلبًا كل 60 ثانية لكل مشروع. راجع حدود المعدل والاستخدام.
الأخطاء
استدعاء أداة يفشل يعيد isError: true بمفردات الأخطاء نفسها التي يستخدمها REST API:
{
"error": {
"code": "limit_reached",
"message": "Your plan allows 5 help-center articles."
}
}| الرمز | المعنى |
|---|---|
unauthorized | مفتاح API مفقود أو مشوّه أو ملغى أو غير معروف. |
forbidden | مفتاح صالح، لكن الخطة بلا وصول كتابة إلى API. |
invalid_request | معاملات خاطئة — بما في ذلك cursor مشوّه. |
not_found | لا يوجد معرّف كهذا في هذا المشروع. |
limit_reached | نفدت حصة من حصص الخطة (مثل سقف المقالات). |
rate_limited | طلبات كثيرة جدًا في النافذة الحالية. |
internal_error | فشل شيء لدينا. من الآمن إعادة المحاولة. |
القائمة الكاملة موثّقة تحت الأخطاء.