انشر خادم MCP واحدًا على السجلين معًا، ليتمكن أي عميل من تشغيله باستخدام npx أو uvx. جهّز package.json و pyproject.toml، وتحقق من الأرشيف المضغوط، واختبره في MCP Inspector، وانشره عبر النشر الموثوق في GitHub Actions، وأضف أدوات توليد الصور والفيديو عبر API.
بنيت خادم MCP وهو يعمل على حاسوبك المحمول. الآن يريد زميل، أو غريب على الإنترنت، تشغيله بسطر إعداد واحد فقط: بلا git clone، وبلا خطوة بناء، وبلا سلسلة رسائل تسأل "أي إصدار من Node تستخدم؟". هذا بالضبط ما يمنحك إياه السجل. انشر على npm فيبدأ العملاء خادمك باستخدام npx. وانشر على PyPI فيبدأونه باستخدام uvx. إذا فعلت الأمرين، يستطيع كل عميل MCP، من Claude Desktop إلى Cursor و VS Code، تشغيل خادمك بالاعتماد على اسم الحزمة وحده.
يتبع هذا الدليل المسار بالترتيب: بنية المستودع، package.json، pyproject.toml، الاختبارات المحلية، أول نشر يدوي، وسير عمل في GitHub Actions ينشر الحزمتين معًا من وسم واحد. تفترض كل خطوة خادمًا من نوع stdio يعمل محليًا بالفعل.
💡 قبل أن تبدأ: تحتاج إلى Node 18 أو أحدث من أجل npm، أو Python 3.10 أو أحدث من أجل PyPI، إضافة إلى حسابين مجانيين على npmjs.com و pypi.org. فعّل المصادقة الثنائية على الحسابين، لأن كلا السجلين يشترطانها على كل من ينشر.
لماذا النشر في السجلين معًا
معظم خوادم MCP تبدأ بلغة واحدة، غالبًا TypeScript أو Python، وتبقى عندها. وهذا يعمل إلى أن يرغب شخص من بيئة تقنية مختلفة في تجربة خادمك. فريق بيانات يستخدم Python لن يثبّت Node لتشغيل أداة، وفريق الواجهات الأمامية لن يهيّئ بيئة virtualenv. والنشر في السجلين معًا يزيل هذا العذر.
جمهوران، خادم واحد
إليك مقارنة بين المسارين جنبًا إلى جنب:
npm
PyPI
أمر التشغيل
npx -y your-package
uvx your-package
SDK الرسمي
@modelcontextprotocol/sdk
mcp (يتضمن FastMCP)
ملف البيان
package.json
pyproject.toml
ما الذي يُرفع
أرشيف tarball مبني من dist/
أرشيف مصدر بالإضافة إلى wheel
أمر النشر
npm publish
uv publish أو twine upload
المصادقة في CI
النشر الموثوق أو توكن دقيق الصلاحيات
النشر الموثوق أو توكن API
أنظف إعداد هو تنفيذ واحد لكل لغة مع عقد أدوات مشترك واحد. تبقى أسماء الأدوات ومخططات الإدخال وأوصافها متطابقة في الحزمتين، فيعمل الأمر النصي الذي ينجح مع إصدار npm بالطريقة نفسها مع إصدار PyPI. احتفظ بهذا العقد في ملف JSON صغير داخل المستودع، واجعل CI يقارن الإصدارين به.
تجنّب الاختصار المتمثل في غلاف Python رفيع يستدعي npx عبر سطر الأوامر. سيعمل ذلك إلى أن يكون لدى المستخدم Node غير مثبت، وعندها يفشل بخطأ لا يستطيع أحد فهمه بنظرة سريعة.
كل مجلد حزمة مستقلة لها ملف بيانها الخاص. يستخدم سير عمل الإصدار لاحقًا working-directory لبنائها بشكل منفصل، فلا يتسرب شيء من جانب إلى آخر.
سمِّ مرة واحدة، وتحقق مرتين
اختر اسمًا واحدًا واستخدمه في السجلين. يتذكره المستخدمون، وتتطابق نتائج البحث.
npm: أحرف صغيرة، صالحة في الروابط، بدون مسافات. يتجنب اسم ضمن نطاق مثل @yourscope/my-mcp-server التعارضات، ويعمل جيدًا مع خوادم MCP.
PyPI: الأسماء غير حساسة لحالة الأحرف، وتعامل - و _ و . على أنها الحرف نفسه، لذلك يتعارض My_MCP.Server مع my-mcp-server.
التوفر: يعيد npm view my-mcp-server الرمز 404 عندما يكون الاسم متاحًا. وفي PyPI، افتح pypi.org/project/my-mcp-server/، ويعني الرمز 404 الشيء نفسه.
💡 تحقق من الاسمين قبل أن تكتب README حول أحدهما. اكتشاف أن الاسم مأخوذ يوم النشر يكلّفك فترة ما بعد الظهر كاملة في إعادة التسمية.
اكتب README يعمل كتوثيق
يعرض كلا السجلين ملف README الخاص بك كصفحة للحزمة، وبالنسبة لكثير من المستخدمين هو الوثيقة الوحيدة التي يقرؤونها. ضع فيه أربعة أشياء بهذا الترتيب:
جملة واحدة تصف ما يفعله الخادم
إعداد عميل جاهز للنسخ واللصق من أجل npx وآخر من أجل uvx
جدول للأدوات بسطر واحد لكل أداة
كل متغير بيئة يقرؤه الخادم، مع تحديد ما إذا كان مطلوبًا أو اختياريًا
انشر حزمة npm
جهّز package.json
ثلاثة حقول تحدد ما إذا كان npx يعمل من الأساس: bin، و files، و سطر shebang في ملف الدخول.
{
"name": "@yourscope/my-mcp-server",
"version": "0.1.0",
"description": "MCP server that does one useful thing",
"type": "module",
"bin": { "my-mcp-server": "dist/index.js" },
"files": ["dist", "README.md", "LICENSE"],
"engines": { "node": ">=18" },
"scripts": {
"build": "tsc",
"prepublishOnly": "npm run build"
},
"dependencies": { "@modelcontextprotocol/sdk": "^1.0.0" },
"license": "MIT"
}
bin يربط اسم الأمر بملف الدخول المُجمّع. بدونه لا يملك npx ما يشغّله.
files قائمة بيضاء. فقط dist/ و README والترخيص يدخلون إلى الأرشيف.
prepublishOnly يعيد البناء قبل كل نشر، فلا ترفع مخرجات قديمة أبدًا.
سطر shebang#!/usr/bin/env node يجب أن يكون السطر الأول في src/index.ts. تحتفظ TypeScript به في الملف المُجمّع.
تحقق من الأرشيف قبل الإرسال
شغّل npm pack --dry-run واقرأ قائمة الملفات التي يطبعها. تريد أن ترى dist/، و README، والترخيص، و package.json. لا تريد أن ترى .env، أو ملفات الاختبار، أو ملفات source maps لم تقصد مشاركتها، أو node_modules شاردًا.
💡 .env المسرّب هو الخطأ الأكثر شيوعًا في أول نشر، ولا يمكن التراجع عن نسخة منشورة. قائمة files البيضاء هي شبكة أمانك، فاحتفظ بها.
نفّذ أول نشر
npm login
npm publish --access public
الحزم ذات النطاق تكون خاصة افتراضيًا، ولهذا يهم --access public في أول نشر. أدخل رمز المصادقة الثنائية عندما يُطلب منك. ثم أثبت أنها تعمل من مجلد آخر:
cd $(mktemp -d)
npx -y @yourscope/my-mcp-server
ينبغي أن تبدأ العملية وتنتظر الإدخال على stdin. هذا الصمت صحيح، لأن خادم stdio يتكلم فقط عندما يتحدث إليه عميل.
انشر حزمة PyPI
اكتب pyproject.toml
يتكون تغليف Python من ملف واحد. تستخدم هذه النسخة hatchling كخلفية للبناء:
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "my-mcp-server"
version = "0.1.0"
description = "MCP server that does one useful thing"
readme = "README.md"
requires-python = ">=3.10"
license = { text = "MIT" }
dependencies = ["mcp>=1.0"]
[project.scripts]
my-mcp-server = "my_mcp_server.server:main"
جدول [project.scripts] يعادل bin. وهو ينشئ أمرًا عند التثبيت. إذا طابق اسم السكربت اسم الحزمة، فإن uvx my-mcp-server يعمل مباشرة. وإذا اختلفا، شغّل uvx --from my-mcp-server script-name.
خادم بسيط يستخدم FastMCP من SDK Python الرسمي:
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("my-mcp-server")
@mcp.tool()
def ping() -> str:
"""Return pong so clients can confirm the server is alive."""
return "pong"
def main() -> None:
mcp.run() # stdio transport by default
ابنِ الملفات وتحقق منها
cd python
uv build
uvx twine check dist/*
uv build يكتب ملفين داخل dist/: أرشيف مصدر (.tar.gz) و wheel (.whl). تُثبَّت ملفات wheel بسرعة لأنه لا يلزم تجميع شيء، ولهذا يفضلها uvx و pip. twine check يتحقق من أن README يُعرض كصفحة للحزمة، فتكتشف بيانات وصفية معطوبة قبل أن يكتشفها PyPI.
جرّب TestPyPI، ثم انشر
TestPyPI موقع منفصل بحسابات ورموز منفصلة. وُجد كي لا يكلّفك أي رفع فاشل لأول مرة شيئًا.
خيار الفهرس الإضافي مهم. تعتمد حزمتك على اعتماديات، بما فيها mcp، وهي موجودة على PyPI الحقيقي، ولا يحملها TestPyPI. بعد نجاح تثبيت الاختبار، انشر فعليًا:
uv publish --token <pypi-token>
uvx my-mcp-server
💡 الإصدارات دائمة في السجلين. لا يقبل PyPI اسم الملف نفسه مرتين أبدًا، حتى بعد الحذف، ويرفض npm إعادة استخدام رقم إصدار منشور. عندما يكون هناك خطأ ما، ارفع رقم الإصدار وانشر من جديد.
اختبر قبل الإطلاق
شغّله في MCP Inspector
يفتح MCP Inspector صفحة ويب محلية تسرد فيها الأدوات، وتملأ الوسيطات، وتقرأ الاستجابات الخام. وجّهه إلى المخرجات المبنية، ثم إلى الحزمة كما سيشغّلها المستخدم تمامًا:
الأمر الثاني هو الأهم. يختبر الحزمة المثبتة بدلًا من مجلد العمل لديك، فتظهر الملفات المفقودة ونقاط الدخول الخاطئة هنا، لا في تقرير خلل.
أبقِ stdout نظيفًا
في stdio، يحمل stdout البروتوكول. يحقن console.log() أو print() شاردًا نصًا داخل تدفق JSON-RPC، فينقطع العميل بخطأ تحليل. أرسل كل سطر سجل إلى stderr بدلًا من ذلك: console.error() في Node، و print(..., file=sys.stderr) أو وحدة logging في Python.
اختبر إعداد العميل
هذا هو الإعداد الذي سيلصقه مستخدموك. جرّب المدخلين في عميل حقيقي:
شغّل قائمة التحقق قبل النشر من قشرة نظيفة داخل مجلد مؤقت. قد يخفي التثبيت العام أو node_modules قريب ملفًا مفقودًا لأسابيع.
npm pack --dry-run يسرد فقط ما تنوي نشره
twine check dist/* ينجح بدون أي تحذيرات
Inspector يسرد كل أداة عبر npx وعبر uvx
لا يكتب شيء إلى stdout سوى رسائل البروتوكول
كتل إعداد README تطابق ما اختبرته للتو
أتمتة الإصدارات وترقيمها
النشر الموثوق، بلا رموز مخزّنة
يتيح كلا السجلين لسير عمل GitHub Actions النشر عبر OpenID Connect. تسجّل مستودعك وملف سير العمل على جانب السجل مرة واحدة، ويثق السجل بذلك السير بالضبط من ذلك الحين. لا يبقى أي رمز طويل الأمد في أسرار مستودعك، فلا يوجد ما يمكن تسريبه أو تدويره. يحتاج سير العمل فقط إلى صلاحية id-token: write.
في PyPI، أضف ناشرًا موثوقًا من إعدادات النشر للمشروع. يمكن لمشروع جديد تمامًا استخدام pending publisher، فيمكن أن يأتي الإصدار الأول من CI أيضًا. وفي npm، أضف الناشر الموثوق من إعدادات الحزمة. تتغير شاشات الإعداد من حين لآخر، فاتبع المطالبات الحالية.
خطوة npm install -g npm@latest تضمن أن واجهة npm CLI حديثة بما يكفي للنشر الموثوق. أضف خطوة needs: مع مهمة الاختبار إذا أردت أن يمنع فشل البناء الإصدار.
Semver يحترمه العملاء
تعتمد عملاء MCP والوكلاء الذين يقفون خلفها على أسماء أدواتك ومخططات إدخالها، فعامل ذلك كواجهة برمجة عامة لديك:
التغيير
رفع الإصدار
إصلاح خطأ دون تغيير في المخطط
إصدار تصحيحي (0.1.1)
إضافة أداة جديدة أو وسيط اختياري
إصدار فرعي (0.2.0)
إعادة تسمية أداة أو حذفها، أو إضافة وسيط إلزامي
إصدار رئيسي (1.0.0)
حدّث ملفي البيان إلى الرقم نفسه في commit واحد، ثم ضع وسمًا عليه. سكربت صغير يعدّل package.json و pyproject.toml معًا يمنع التعارض الكلاسيكي حيث يكون npm على 1.2.0 و PyPI على 1.1.0. يمكن للمستخدمين الذين يريدون الاستقرار تثبيت رقم رئيسي في إعدادهم، على سبيل المثال @yourscope/my-mcp-server@1.
بعد أن تصبح الحزمتان منشورتين، يمكنك أيضًا إدراج الخادم في MCP Registry الرسمي. يتحقق السجل من الملكية عبر قراءة حقل mcpName في package.json وسطر mcp-name: مطابق في README لحزمة PyPI، ثم ينشر البيانات الوصفية باستخدام أمر mcp-publisher. لا يزال السجل قيد التطوير، فاقرأ وثائقه الحالية قبل أن تعتمد على الصيغة الدقيقة.
أضف أدوات توليد الصور والفيديو
يصبح الخادم المنشور أكثر فائدة لحظة يستطيع أن يصنع شيئًا. توليد الصور والفيديو من أكثر الأدوات طلبًا، وتجعلها واجهة PicassoIA API إضافة قصيرة. عنوان الأساس هو https://api.picassoia.com/v1، والمصادقة بتوكن Bearer يبدأ بالنص pia_sk_، والمهام غير متزامنة: تنشئ توقعًا، ثم تستعلم عنه، ثم تقرأ النتيجة.
💡 اقرأ متطلبات الخطة الحالية في صفحة PicassoIA API قبل أن تعد باستخدام مجاني في README. قد تتغير صياغة التسعير، وسيحاسبك مستخدموك على ما كتبته.
اكتب مسودة ملاحظات الإصدار باستخدام نموذج لغوي. يستطيع نموذج لغوي التعامل مع المهمة الرتيبة التي تجعل الناس يتجاهلون سجلات التغيير. إليك سير عمل سريع مع Claude Sonnet 5:
افتح صفحة النموذج على PicassoIA والصق السجل مع تعليمة من سطر واحد: صنّف التغييرات ضمن فئات Added و Changed و Fixed بلغة بسيطة.
أخبره بالتغييرات التي تمس أسماء الأدوات أو المخططات، حتى تُوسم بأنها تغييرات كاسرة.
اقرأ النتيجة مقابل الفرق (diff) والصقها في إصدار GitHub.
للحصول على رأي ثانٍ في ملف pyproject.toml أو ملف سير العمل، يُعد GPT 5.6 Sol مراجعًا جيدًا لمهام البرمجة.
جرّب بنفسك على Picasso IA
تستحق صفحة حزمتك صورة رئيسية حقيقية ومقطعًا توضيحيًا قصيرًا، لا لقطة شاشة لطرفية. أنشئ الصورة الرئيسية باستخدام Picasso IA Image، ثم حسّن التفاصيل باستخدام Picasso IA Image Editor Pro، ثم حوّل الإطار الأخير إلى مقطع قصير باستخدام Picasso IA Video.
تجربة أولى بسيطة:
اكتب أمرًا نصيًا من 40 كلمة يصف مكتب مطور هادئ في ضوء الصباح
ولّد ثلاث صور متنوعة واحتفظ بأوضحها
احفظها كصورة رئيسية في README
حرّكها للإعلان عن الإصدار
تصفّح كل النماذج المتاحة على picassoia.com/en/all-models، واختر ما يناسب أسلوبك، وانشر شيئًا يستحق الفتح. إصدارك الأول لا يبعد عنك سوى وسم واحد.