MCP सर्वर को npm और PyPI पर स्टेप-दर-स्टेप कैसे प्रकाशित करें
एक ही MCP सर्वर को दोनों रजिस्ट्री पर भेजें, ताकि कोई भी क्लाइंट उसे npx या uvx से शुरू कर सके। package.json और pyproject.toml सेट करें, टारबॉल जाँचें, MCP Inspector में टेस्ट करें, GitHub Actions में trusted publishing से प्रकाशित करें, और API के ज़रिए इमेज और वीडियो टूल जोड़ें।
आपने एक MCP सर्वर बनाया है और वह आपके लैपटॉप पर चलता है। अब कोई साथी, या इंटरनेट पर कोई अजनबी, चाहता है कि वह सिर्फ़ एक लाइन के कॉन्फ़िग से चले: न कोई git clone, न कोई बिल्ड स्टेप, न "आप कौन-सा Node वर्ज़न इस्तेमाल कर रहे हैं?" वाला धागा। रजिस्ट्री ठीक यही देती है। npm पर प्रकाशित करने से क्लाइंट आपका सर्वर npx से शुरू करते हैं। PyPI पर प्रकाशित करने से वे उसे uvx से शुरू करते हैं। दोनों पर प्रकाशित करें, तो Claude Desktop से लेकर Cursor और VS Code तक हर MCP क्लाइंट सिर्फ़ एक पैकेज नाम से आपका सर्वर लॉन्च कर सकता है।
यह गाइड इसी क्रम में चलती है: रेपो का लेआउट, package.json, pyproject.toml, लोकल टेस्ट, पहला मैन्युअल प्रकाशन, और एक GitHub Actions वर्कफ़्लो जो एक ही टैग से दोनों पैकेज भेजता है। हर स्टेप मानकर चलता है कि आपके पास एक stdio सर्वर है जो पहले से लोकल पर चलता है।
💡 शुरू करने से पहले: npm के लिए Node 18+ या PyPI के लिए Python 3.10+ चाहिए, साथ ही 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
अपलोड होने वाली चीज़
dist/ से बनी एक टारबॉल
एक सोर्स आर्काइव और एक wheel
प्रकाशन कमांड
npm publish
uv publish या twine upload
CI में ऑथेंटिकेशन
ट्रस्टेड पब्लिशिंग या ग्रैन्युलर टोकन
ट्रस्टेड पब्लिशिंग या API टोकन
सबसे साफ़ सेटअप है हर भाषा के लिए एक इम्प्लीमेंटेशन, और एक साझा टूल कॉन्ट्रैक्ट। टूल के नाम, इनपुट स्कीमा और विवरण दोनों पैकेज में एक जैसे रहते हैं, इसलिए जो प्रॉम्प्ट npm बिल्ड के साथ काम करता है, वह PyPI बिल्ड के साथ भी उसी तरह व्यवहार करेगा। उस कॉन्ट्रैक्ट को रेपो में एक छोटी JSON फ़ाइल में रखें और CI से दोनों बिल्ड की उसके साथ तुलना कराएँ।
एक पतले Python रैपर का शॉर्टकट न अपनाएँ जो npx को कॉल करता हो। यह तब तक चलता है जब तक यूज़र के पास Node इंस्टॉल न हो, और फिर ऐसी त्रुटि आती है जिसे कोई एक नज़र में समझ नहीं पाता।
पैकेज लेआउट चुनें
दो फ़ोल्डर वाला एक ही रेपो रिलीज़ की प्रक्रिया को सरल रखता है:
हर फ़ोल्डर अपने मैनिफ़ेस्ट के साथ अलग पैकेज है। रिलीज़ वर्कफ़्लो बाद में working-directory से उन्हें अलग-अलग बनाता है, ताकि कुछ भी एक तरफ़ से दूसरी तरफ़ न जाए।
नाम एक बार रखें, दो बार जाँचें
एक नाम चुनें और उसे दोनों रजिस्ट्री पर इस्तेमाल करें। यूज़र उसे याद रखते हैं, और सर्च नतीजे आपस में मेल खाते हैं।
npm: lowercase, URL-safe, बिना स्पेस के। @yourscope/my-mcp-server जैसा scoped नाम टकराव से बचाता है और MCP सर्वर के लिए ठीक काम करता है।
PyPI: नाम case-insensitive होते हैं और -, _ और . को एक ही अक्षर मानते हैं, इसलिए 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 और आपकी entry फ़ाइल की 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 कमांड के नाम को कंपाइल की गई entry फ़ाइल से जोड़ता है। इसके बिना npx के पास चलाने के लिए कुछ नहीं होता।
files एक whitelist है। सिर्फ़ 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 whitelist आपका सेफ़्टी नेट है, इसलिए उसे रखें।
पहला प्रकाशन चलाएँ
npm login
npm publish --access public
Scoped पैकेज डिफ़ॉल्ट रूप से private होते हैं, इसलिए पहले प्रकाशन में --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 चलाएँ।
आधिकारिक Python SDK के FastMCP का इस्तेमाल करता एक न्यूनतम सर्वर:
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 builddist/ में दो फ़ाइलें लिखता है: एक source archive (.tar.gz) और एक wheel (.whl)। Wheels जल्दी इंस्टॉल होते हैं क्योंकि कुछ कंपाइल नहीं करना पड़ता, इसीलिए uvx और pip उन्हें पसंद करते हैं। twine check पुष्टि करता है कि README पैकेज पेज के रूप में सही दिखता है, ताकि मेटाडेटा की गड़बड़ी PyPI से पहले आप पकड़ लें।
TestPyPI पर आज़माएँ, फिर प्रकाशित करें
TestPyPI एक अलग साइट है, जिसके अलग अकाउंट और अलग टोकन हैं। इसका मकसद यह है कि पहला अपलोड विफल हो जाए तो आपका कोई नुकसान न हो।
अतिरिक्त इंडेक्स ज़रूरी है। आपकी dependencies, जिनमें mcp भी शामिल है, असली PyPI पर रहती हैं, और TestPyPI उन्हें नहीं रखता। टेस्ट इंस्टॉल चलने के बाद असली प्रकाशन करें:
uv publish --token <pypi-token>
uvx my-mcp-server
💡 दोनों रजिस्ट्री पर वर्ज़न स्थायी हैं। PyPI एक ही फ़ाइल नाम दोबारा स्वीकार नहीं करता, भले ही उसे हटा दिया गया हो, और npm प्रकाशित वर्ज़न नंबर दोबारा इस्तेमाल होने नहीं देता। कुछ गलत हो तो वर्ज़न बढ़ाएँ और फिर से प्रकाशित करें।
भेजने से पहले टेस्ट करें
MCP Inspector में चलाएँ
MCP Inspector एक लोकल वेब पेज खोलता है, जहाँ आप टूल्स की सूची देखते हैं, आर्गुमेंट भरते हैं और रॉ रिस्पॉन्स पढ़ते हैं। उसे पहले बिल्ड किए गए आउटपुट पर लगाएँ, फिर उस पैकेज पर जैसे यूज़र उसे चलाएगा:
दूसरी कमांड सबसे ज़्यादा मायने रखती है। यह अपने वर्किंग ट्री की बजाय इंस्टॉल किए गए पैकेज को जाँचती है, इसलिए गायब फ़ाइलें और गलत entry points बग रिपोर्ट में नहीं, यहीं दिख जाते हैं।
stdout साफ़ रखें
stdio पर stdout प्रोटोकॉल ढोता है। कोई भटका हुआ console.log() या print() JSON-RPC स्ट्रीम में टेक्स्ट डाल देता है और क्लाइंट parse error के साथ डिस्कनेक्ट हो जाता है। हर लॉग लाइन को इसकी बजाय stderr पर भेजें: Node में console.error(), और Python में print(..., file=sys.stderr) या logging मॉड्यूल से।
क्लाइंट कॉन्फ़िग टेस्ट करें
यही वह कॉन्फ़िग है जिसे आपके यूज़र पेस्ट करेंगे। असली क्लाइंट में दोनों एंट्री आज़माएँ:
प्री-पब्लिश चेकलिस्ट एक temporary फ़ोल्डर में साफ़ shell से चलाएँ। ग्लोबल इंस्टॉल या पास में रखा node_modules किसी गायब फ़ाइल को हफ़्तों तक छिपा सकता है।
npm pack --dry-run में सिर्फ़ वही दिखे जो आप भेजना चाहते हैं
twine check dist/* बिना किसी चेतावनी के पास हो
Inspector npx के ज़रिए और uvx के ज़रिए हर टूल सूचीबद्ध करे
stdout पर प्रोटोकॉल संदेशों के अलावा कुछ न लिखा जाए
README के कॉन्फ़िग ब्लॉक ठीक वैसे ही हों जैसे आपने अभी टेस्ट किए
रिलीज़ को ऑटोमेट और वर्ज़न करें
Trusted publishing, कोई स्टोर किया हुआ टोकन नहीं
दोनों रजिस्ट्री GitHub Actions वर्कफ़्लो को OpenID Connect से प्रकाशित करने देती हैं। आप अपना रेपो और वर्कफ़्लो फ़ाइल एक बार रजिस्ट्री की तरफ़ रजिस्टर करते हैं, और फिर रजिस्ट्री उस ठीक वर्कफ़्लो पर भरोसा करती है। आपके रेपो सीक्रेट्स में कोई लंबे समय वाला टोकन नहीं रहता, इसलिए लीक होने या रोटेट करने को कुछ नहीं होता। वर्कफ़्लो को सिर्फ़ id-token: write की अनुमति चाहिए।
PyPI पर, प्रोजेक्ट की publishing सेटिंग्स में एक trusted publisher जोड़ें। कोई बिल्कुल नया प्रोजेक्ट pending publisher इस्तेमाल कर सकता है, ताकि पहली रिलीज़ भी CI से आ सके। npm पर, पैकेज सेटिंग्स में trusted publisher जोड़ें। सेटअप की स्क्रीन समय-समय पर बदलती रहती हैं, इसलिए मौजूदा निर्देशों का पालन करें।
एक टैग, दो प्रकाशन
v0.1.0 जैसा टैग पुश करने पर दोनों जॉब एक साथ चलते हैं:
npm install -g npm@latest स्टेप यह पक्का करता है कि npm CLI trusted publishing के लिए काफ़ी नया है। अगर आप चाहते हैं कि लाल बिल्ड रिलीज़ को रोक दे, तो अपने टेस्ट जॉब के साथ needs: स्टेप जोड़ें।
ऐसा Semver जिसे क्लाइंट मानें
MCP क्लाइंट और उनके पीछे के एजेंट आपके टूल नामों और इनपुट स्कीमा पर निर्भर करते हैं, इसलिए उन्हें अपना पब्लिक API मानें:
बदलाव
वर्ज़न बंप
बग ठीक करना, स्कीमा में कोई बदलाव नहीं
Patch (0.1.1)
नया टूल या वैकल्पिक आर्ग्युमेंट जोड़ना
Minor (0.2.0)
किसी टूल का नाम बदलना या उसे हटाना, या अनिवार्य आर्ग्युमेंट जोड़ना
Major (1.0.0)
दोनों मैनिफ़ेस्ट को एक ही कमिट में एक ही नंबर पर लाएँ, फिर उस पर टैग लगाएँ। एक छोटी स्क्रिप्ट जो package.json और pyproject.toml को एक साथ बदलती है, उस आम गड़बड़ी को रोकती है जहाँ npm 1.2.0 पर हो और PyPI 1.1.0 पर। जो यूज़र स्थिरता चाहते हैं, वे अपने कॉन्फ़िग में मेजर वर्ज़न पिन कर सकते हैं, जैसे @yourscope/my-mcp-server@1।
दोनों पैकेज लाइव होने के बाद, आप सर्वर को आधिकारिक MCP Registry में भी सूचीबद्ध कर सकते हैं। वह package.json में mcpName फ़ील्ड और PyPI README में एक मेल खाती mcp-name: लाइन पढ़कर स्वामित्व सत्यापित करती है, फिर mcp-publisher कमांड से मेटाडेटा प्रकाशित करती है। यह रजिस्ट्री अभी विकसित हो रही है, इसलिए सटीक फ़ॉर्मेट पर भरोसा करने से पहले उसके मौजूदा डॉक्स पढ़ें।
इमेज और वीडियो टूल जोड़ें
प्रकाशित सर्वर तब और काम का हो जाता है जब वह कुछ बना सके। इमेज और वीडियो जनरेशन सबसे ज़्यादा माँगे जाने वाले टूल हैं, और PicassoIA API इन्हें एक छोटे जोड़ में बदल देता है। बेस URL https://api.picassoia.com/v1 है, ऑथेंटिकेशन एक Bearer टोकन है जो pia_sk_ से शुरू होता है, और जॉब असिंक्रोनस हैं: आप एक prediction बनाते हैं, उसे poll करते हैं, फिर नतीजा पढ़ते हैं।
हर मॉडल के सटीक इनपुट फ़ील्ड के लिए API डॉक्स देखें, क्योंकि output का आकार और स्वीकार्य पैरामीटर मॉडल-दर-मॉडल अलग होते हैं।
टोकन को क्लाइंट कॉन्फ़िग के ज़रिए पास करें। टोकन को कभी पैकेज में फ़िक्स करके न डालें। उसे एनवायरनमेंट से पढ़ें और हर यूज़र को अपने MCP कॉन्फ़िग में सेट करने दें:
💡 अपने README में मुफ़्त उपयोग का वादा करने से पहले PicassoIA API पेज पर मौजूदा प्लान की ज़रूरतें पढ़ें। प्राइसिंग के शब्द बदल सकते हैं, और आपके यूज़र वही माँगेंगे जो आपने लिखा है।
LLM से रिलीज़ नोट्स का ड्राफ़्ट बनाएँ। एक लैंग्वेज मॉडल वह काम संभाल सकता है जिसकी वजह से लोग changelog छोड़ देते हैं। Claude Sonnet 5 के साथ एक त्वरित वर्कफ़्लो यह है:
git log v0.1.0..HEAD --oneline चलाएँ और आउटपुट कॉपी करें।
PicassoIA पर मॉडल पेज खोलें और लॉग को एक लाइन के निर्देश के साथ पेस्ट करें: बदलावों को सादी भाषा में Added, Changed और Fixed में समूहित करें।
उसे बताएँ कि कौन-से बदलाव टूल नामों या स्कीमा को छूते हैं, ताकि उन्हें breaking के रूप में चिह्नित किया जाए।
नतीजा diff से मिलाकर पढ़ें और उसे GitHub release में पेस्ट करें।
अपने 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 पर देखें, अपनी शैली के हिसाब से एक चुनें, और कुछ ऐसा प्रकाशित करें जिसे खोलने लायक हो। आपकी पहली रिलीज़ बस एक टैग दूर है।