Phase 13: Tools & Protocols

تطبيقات MCP بشأن بروتوكول العدالة عن الجنسية

النتيجة التفاعلية لا تزال أداة MCP وتبادل الموارد. يجعلها جوهر 2026-07-28 مستقلة عن التبادل ، في حين يضيف امتداد التطبيقات سطح المتصفح المعدن.

Type: Build

Languages: Python

Prerequisites: Phase 13 · 07 (MCP server), Phase 13 · 10 (resources)

Time: ~75 minutes

أهداف التعلم

  • إعلانات عن تطبيقات MCP من خلال server/discoverوقدرات التوسع حسب الطلب.
  • إعلانui://الموارد على أداة قبل أن يتم استدعاء الأداة.
  • أعيد نتائج الأداة والموارد الكاملة على سلك العزل 2026-07-28.
  • إفراز التطبيقات ui/initializeرسالة الجسر من ضغط يد من مركز MCP المزول.
  • تطبيق تصحيح الأصل، ورقعة الرملة، CSP، والإذن أقل امتيازات.

المشكلة

النتيجة النصية يمكن أن تصف خط زمني. لا يمكن أن تعطى للمستخدم خط زمني يمكن أن تصفح، التفتيش، أو التصرف على.

تُحل MCP Apps مشكلة العرض بإضافة اختيارية.ui://الموارد. يمكن للمضيف الحصول على هذه الموارد ومراجعتها قبل تشغيل الأداة ، وإرسالها في إيفريم مربع رمال ، والوساطة بين جميع إجراءات التطبيق عبر جسر JSON-RPC.

تم تغيير بروتوكول الأساس في 2026-07-28. لا تغلف تطبيقًا في دورة حياة الاتصال القديمة:

  • لا يوجد جوهرinitializeطلب أوnotifications/initializedالإخطار
  • لا يوجدMcp-Session-Idرأس
  • كل طلب يحمل نسخة بروتوكول و قدرات العميل في params._meta. . .
  • خادم تنفيذ server/discoverحتى يتمكن العملاء من فحص الإصدارات والقدرات الأساسية والإضافات.
  • كل نتيجة ناجحة لهاresultTypeالتمييز
  • يستخدم HTTP المباشر POST واحد لكل طلب. نقاط دخول GET الحديثة و DELETE تعود 405.

على جسر التطبيقات لا يزال هناك طريقة تسمىui/initializeإنه ينتمي إلى لغة إيفريم "بوستماسج" لا يعيد إنشاء جلسة MCP الأساسية

المفهوم

بروتوكولين، ميزة واحدة

أبقوا الطبقات واضحة:

  1. النواة MCP تحمل server/discover،tools/list،tools/call،resources/listوresources/read. . .
  2. يعلن امتداد MCP Apps عن واجهة المستخدم ويحدد جسر iframe-to-host.
  3. قواعد مربع الرمل المتصفح تحد من ما يمكن للمستخدم الوصول إليه.

هو هو .io.modelcontextprotocol/uiكلا النظاميين يختارون. العميل يرسل دعم التوسع داخل كائن القدرات على كل طلب:

json{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "server/discover",
  "params": {
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientCapabilities": {
        "extensions": {
          "io.modelcontextprotocol/ui": {}
        }
      },
      "io.modelcontextprotocol/clientInfo": {
        "name": "timeline-host",
        "version": "1.0.0"
      }
    }
  }
}

clientInfoيوصى به للتشخيص. إنها بيانات ذاتية الإبلاغ، وليس هوية تصريح.

اكتشاف قبل الترجمة

نتيجة اكتشاف الخادم تعلن عن التوسع:

json{
  "resultType": "complete",
  "supportedVersions": ["2026-07-28"],
  "capabilities": {
    "tools": {},
    "resources": {},
    "extensions": {
      "io.modelcontextprotocol/ui": {}
    }
  },
  "ttlMs": 300000,
  "cacheScope": "public",
  "_meta": {
    "io.modelcontextprotocol/serverInfo": {
      "name": "timeline-app-server",
      "version": "2.0.0"
    }
  }
}

يجب على الخادم دعم الاكتشاف. لا يجبر العميل على استدعاء الاكتشاف قبل كل عمل لأن كل عمل يحمل قدراته الخاصة.

إعلان واجهة المستخدم على تعريف الأداة

العقد الحديث للتطبيقات يربط واجهة المستخدم بالداول في tools/list:

json{
  "name": "notes_timeline",
  "description": "Render a timeline of notes.",
  "inputSchema": {
    "type": "object",
    "properties": {}
  },
  "_meta": {
    "ui": {
      "resourceUri": "ui://notes/timeline.html"
    }
  }
}

هذه البيانات المعدنية المقدمة قبل الاتصال بشكل متعمد. يمكن للمضيف تحميل HTML مسبقًا ، والخزينة الآمنة ، ومراجعة الأمن قبل أن يطلب النتيجة عرضها. قد يتم قبول مفاتيح البيانات المعدنية المسطحة القديمة بواسطة رمز التوافق ، ولكن يجب أن تنشر الخوادم الجديدة المضغوطة _meta.ui.resourceUriالنموذج

tools/listيمكن التخفيض في النواة الحالية.ttlMsوcacheScopeاستخدمprivateعندما تختلف الأدوات المرئية حسب المستخدم أو الوهم.

أعيد البيانات، ثم دع المضيف يربط الرؤية

يرد نداء الأداة المحتوى العادي بالإضافة إلى البيانات المهيكلة:

json{
  "resultType": "complete",
  "content": [
    {"type": "text", "text": "Timeline ready."}
  ],
  "structuredContent": {
    "notes": [
      {"id": "note-1", "title": "Discover", "created": "2026-07-28"}
    ]
  },
  "isError": false
}

المضيف يعرف بالفعل أي عرض ينتمي إلى الأداة. تجنب اختراع كتلة محتوى جديدة فقط لتكرار URI.

استخدم التطبيق كمصدر

الخادم يعلنresourcesفي اكتشاف، لذلك فإنه أيضا تنفيذ الالتزامresources/listالعملية. إدخال القائمة التحديدية يتضمن URI القنوني ، والاسم المستقر ، والوصف ، ونوع MIME. نتيجة القائمة تتضمن resultType، بيانات المستخدم المعرفيةttlMsوcacheScope، تماماً مثل قائمة الأدوات التحديدية

المضيف يرسلهresources/readعلى HTTP المباشر ، يكون الطلب:

textPOST /mcp
MCP-Protocol-Version: 2026-07-28
Mcp-Method: resources/read
Mcp-Name: ui://notes/timeline.html

يجب أن تتطابق قيم العنوان و جسم JSON- RPC. عدم التطابق هو خطأ بروتوكول -32020. . .

النتيجة تحتوي على الموارد HTML ومشيرات التخزين:

json{
  "resultType": "complete",
  "contents": [
    {
      "uri": "ui:TOK0
      "mimeType": "text/html;profile=mcp-app",
      "text": "<!doctype html>...",
      "_meta": {
        "ui": {
          "csp": {
            "connectDomains": [],
            "resourceDomains": [],
            "frameDomains": [],
            "baseUriDomains": []
          },
          "permissions": {}
        }
      }
    }
  ],
  "ttlMs": 60000,
  "cacheScope": "public"
}

تخزين موارد واجهة المستخدم كمحتوى يمكن تنفيذه

مواردة التطبيق لا يمكن التبادل مع النص العادي. إدخال التخزين الآلي يمكن تنفيذ رمز الجسر، وتقديم بيانات الأداة، وتطلب إجراءات منتظمة. مفتاحها من خلال القنوات القنونية ui://URI، والهوية والإصدار المعتمدة للخادم، وتحليل محتوى الموارد، والسياق المفوضية عندما cacheScopeهو خاص. لا تستخدم أبداً مصدر خاص للتطبيق عبر المبادئ الرئيسية لأن HTML أو بياناتها المختلفة قد تختلف حتى عندما تكون URI متطابقة.

إبطال الإدخال عندما يكونttlMsانتهت صلاحية الوسيلة_meta.ui.resourceUriتغييرات ملزمة، أو تغييرات نسخة الخادم أو إدخال إشارة تصريح مسموح بها، أو إدخال إشارة تغيير الموارد معترف بها تسمية URI. إعادة التطبيق وإعادة تطبيق CSP ومراجعة الإذن قبل إعادة التثبيت. لا يجب أن تحتفظ إطار إيفري متجاوز السن بإذنات أوسع ببساطة لأن نسخة الموارد الجديدة لم تحملها بعد.

رفض الغامضة في الأسلاك قبل سياسة الميزات

التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق من التحقق.

ConditionHTTPJSON-RPC error
Header and body version, method, or name disagree400-32020
Header and body agree on an unsupported version400-32022, with data exactly {"supported":["2026-07-28"],"requested":"<actual>"}
resources/read lacks the Apps extension capability400-32021, with data.requiredCapabilities.extensions.io.modelcontextprotocol/ui
Method is unknown404-32601

إشعار JSON-RPC لا يحتوي على أي id، لذلك لا ينشر الخادم أبداً رد JSON-RPC لذلك. إشعار HTTP المقبول يعيد 202 مع جسم فارغ. يمكن أن يغير خطأ حالة HTTP ، ولكن لا يزال لا يمكن إنشاء جسم خطأ JSON-RPC لإشعار.

صندوق الرمل هو الحدود، وليس حكم الثقة

مضيف يسيطر على iframe. لا يمكن للتطبيق قراءة ملفات تعريف الارتباط المضيف، التخزين المحلي، أو صفحة DOM مباشرة. يجب أن يعبر جميع الأعمال المميزة الجسر.

استخدم هذه التشغيلات الافتراضية:

  • اترك جميع قوائم النطاقات CSP فارغة، ثم أضف فقط الأصول التي يحتاجها التطبيق. استخدام connectDomainsلـ (بيتش) ، (إكس آر) ، و (ويب سوكت) ؛ استخدام resourceDomainsللخطوط، والأساليب، والصور، والخطوط.
  • قم بتجميع الرمز والبيانات عندما يكون ذلك ممكناً
  • لا تطلب أي تصريح للكاميرا أو الميكروفون أو الموقع إلا إذا كان هناك شيء مرئي يحتاجه.
  • - أوراقpostMessageإلى أصل أقرانه بالضبط ورفض الأحداث من كل أصل آخر
  • تعامل معدل الأدوات، نتائج الأدوات، نص الموارد، ورسائل الجسر كإدخال غير موثوق به.
  • الحفاظ على موافقة المستخدم في المضيف. لا يمكن أن يوافق الإطار على إجراءاتها التالية.

لا تُنسخ ثابتاًsandboxيجب على المضيف اختيار العلامات بناءً على نموذج أصل التطبيق وتصميم عزله الخاص.

المجال المسموح به لا يزال مسار التنفيذconnectDomains: ["https://api.example.com"]يعني أن أي نص يتم تنفيذه داخل التطبيق يمكنه إرسال البيانات المسموح بها هناك. يمنع التطابق الدقيق في المصدر الخلط في الوجهة، لكنه لا يقرر ما إذا كانت الحمولة المفيدة مناسبة. حافظ على إمكانية الوصول إلى الاتصال فارغة افتراضيًا ، وتجنب وضع رموز حامل في iframe ، وتشغيلات الضيقة من خلال المضيف عندما تكون عملية ، وتحديد حجم الاستجابة والطلب ، والتحقق من عمل المستخدم الذي أدى إلى كل طلب خارجي. العلاجresourceDomainsبشكل منفصل عنconnectDomains؛ يجب ألا يسمح الإذن بتحميل الخط أو النص بالتحميل التعسفي للبيانات.

جسر التطبيقات له دورة حياة خاصة به

جسر التطبيقات هو لهجة JSON-RPC على postMessageيمكن أن يتبادلui/initializeوui/*الإخطارات ويمكن أن تتمثل في أساليب البحث الأساسية مثلtools/call. . .

الرؤية تُرسل ui/initializeمعappInfoوappCapabilitiesالمضيف يعيد قدراته و سياق المضيف. فقط بعد ذلك الإجابة يرسل عرض ui/notifications/initializedيجب على المضيف الانتظار لهذا الإخطار قبل إرسال الرسائل إلى المشاهدة.

هذا الضغط المحلي يخلق جسرا بين إطار واحد و إطار مضيف واحد. لا يتفاوض على إصدار بروتوكول MCP ، أو يخلق حالة الخادم ، أو يخلق جلسة نقل. لاحظ المقبلة الدقيقة:notifications/initializedتم إزالة، بينما تطبيقات ui/notifications/initializedيظل طلبًا أساسيًا يتم إنشاؤه من خلال اتصال أداة جريدية هو طلب جديد مستقل مع معرف JSON-RPC الجديد ومعلومات بيانات الطلب الكاملة.

السياق المضيف والإجراءات والإلغاء

يظل المضيف هو السلطة بعد تشغيل الجسر. يمكن للمشاهدة طلب إجراء أداة أو التنقل أو استخدام لوحة المقطوعة أو تأثير امتياز آخر فقط من خلال قدرة يعلن عنها المضيف. يؤكد المضيف الطلب المطبوع والمستخدم الحالي والهدف والحجج ، ويطبق سياسة الموافقة ، ويمكنه رفضه. تنقر زر نقرة رسالة الجسر صالحة على نية تعبير ؛ لا يمنح أي منها السلطة.

تعامل الموضوع والحجم والوصول إلى النطاق المتغير للمضيف بدلاً من إدخال الإصدار المفرد:

  • تطبيق رموز الألوان والطباعة التي يقدمها المضيف، ثم التفاعل عندما تتغير تفضيلات الموضوع أو التناقض.
  • دع المشاهدة تقرير الأبعاد المرغوبة، ولكن دع المضيف القفز وتطبيق حجم iframe حتى المحتوى لا يمكن أن تفلت من التخطيط أو خلق التداخلات الخادعة.
  • الحفاظ على ترتيب لوحة المفاتيح، والتركيز المرئي، والأسماء المتاحة، وحالة قارئ الشاشة، والتباين الكافي، والزيادة، والسلوك الحد من الحركة داخل iframe.
  • إعادة اختبار نقل التركيز بين عناصر التحكم في المضيف و إدارة المشاهدة بعد تغيير الحجم وإعادة تقديمها.

يمكن إلغاء القدرات أثناء فتح التطبيق لأن المستخدم يغير الحساب أو تغييرات في السياسة أو يتم تعقيد خادم أو يضييق المضيف الموافقة. تحقق من القدرة والإذن في وقت العمل ، وليس فقط خلالui/initializeعند الإلغاء، رفض المكالمات المتميزة المنتظرة، وقف نشاط الشبكة الذي لم يعد يتناسب مع السياسة، تنظيف الحالة الحساسة المقدمة، وإعادة التثبيت أو العودة إلى النص عندما لا يتم قبول موارد واجهة المستخدم نفسها. يجب على عرض التعامل مع الرفض كنتيجة طبيعية، وليس محاولة أخرى حتى يستسلم المضيف.

الاحتمالات العائدة جزء من العقد

لا يزال خادم مطلع على التطبيقات قادرًا على خدمة مضيفين لا يعلنون عن امتدادات واجهة المستخدم:

  • أعد نفس الأداة بدون _meta.uiفيtools/list. . .
  • إحتفظ بنتيجة نصية مفيدةtools/call. . .
  • رفضresources/readلـ UI مع خطأ في القدرة المفقودة.
  • لا نفترض أبدا وجود iframe عند اتخاذ قرار بشأن إتمام الأداة.

بناءها

code/main.pyيقوم ببناء نموذج بروتوكول صغير في العملية دون SDK. يؤكد تغطية الطلب الحالية وقيم توجيه HTTP المباشرة ، ويعلن عن التطبيقات من خلال server/discover، يردد الأدوات والموارد، وينفذ الأداة، ويعمل على مصدر HTML مستقل.

يتلقى النموذج أجسامًا تم تحليلها بالفعل و عناوين توجيه. إنه ليس مُعدلاً HTTP كاملاً ولا يحلل Content-TypeأوAccept. استخدم الدروس 09 لتحويلات HTTP المباشرة الكاملة التي تتطلب Content-Type: application/jsonوAcceptقيمة تحتوي على كلتا application/jsonوtext/event-stream. . .

إشغله

bashcd phases/13-tools-and-protocols/14-mcp-apps
python3 code/main.py
python3 -m unittest discover code/tests -v

تحقق من أربعة أشياء في الخروج:

  1. كل مكالمة مستقلة
  2. كل طلب لديه_metaالقدرات
  3. resources/listيعيد وصف مستقر قبل أي قراءة للموارد.
  4. كل نتيجة لهاresultTypeو البيانات المعدنية لتحديد هوية الخادم
  5. لا يظهر أي معرف الجلسة الأساسية.

استخدمها

ابدأ بـserver/discoverتأكّدio.modelcontextprotocol/uiيظهر في خريطة امتداد الخادم. ثم الاتصال tools/listمرتين، مرة مع قدرة التطبيقات ومرة بدونها. الإجابة الأولى تعلن الموارد. الثانية تظل أداة نصية فقط قابلة للاستخدام.

اقرأui://notes/timeline.html. ابحث عن HTMLhostOriginو event.originهذه الخطتين هي أدنى دليل مرئي على أن الجسر لا يستخدم هدفًا

أرسله

هذه الدروس تُسافرoutputs/skill-mcp-apps-spec.mdاستخدمها لمراجعة عقد التطبيق قبل كتابة رمز الإطار. يضطر المؤلف إلى إشارة الغلاف الأساسي الحالي، ومفاوضات التوسع، والعودة إلى الوراء، ومصدر UI، وسياسة التخزين الآلي، و CSP، والإذن، وأساليب الجسر، وحدود الموافقة.

التمارين

  1. تغيير قدرة العميل إلى خريطة امتداد فارغة. تأكيد tools/listيحتفظ بالأداة لكنه يزيل الالتزام بالواجهة
  2. أرسلMcp-Name: ui://notes/other.htmlمع جسم يقرأ خط الزمن. تأكيد الخطأ-32020. . .
  3. تغيير الموارد إلى cacheScope: private. وصف حالة المستخدم المحددة التي تبرهن ذلك.
  4. تحرك النص إلى https://static.example.com/app.jsإضافة هذا الأصل إلىresourceDomainsويشرح مخاطر سلسلة التوريد الجديدة
  5. إضافة notes_openأداة وتوجيه زر النقل من خلال المضيف. الحفاظ على موافقة المستخدم في المضيف.

الشروط الرئيسية

TermMeaning
MCP AppsOptional extension for interactive HTML rendered by an MCP host
io.modelcontextprotocol/uiExtension identifier advertised by both peers
ui://Resource scheme for an App's UI template
text/html;profile=mcp-appMIME type for MCP App HTML
server/discoverCurrent RPC for protocol and capability discovery
resources/listMandatory resource listing method when the server advertises resources
resultTypeRequired discriminator for modern successful results
ui/initializeFirst Apps bridge request, separate from removed core initialization
ui/notifications/initializedApps View readiness notification sent after the host responds
CSPBrowser policy that restricts scripts, styles, images, and network origins
Text fallbackTool behavior retained for a host without Apps support

المزيد من القراءة

This free lesson is part of the AI Engineering from Scratch curriculum. Read the full explanation, run the lesson code, and verify the result in the interactive reader or from the repository source.

Browse the complete course catalog or open this lesson on GitHub.