VPS पर MCP server कैसे सेटअप करें: पूरी गाइड
अपने VPS पर MCP server चलाने का तरीका जानें। इस गाइड में stdio और remote HTTP transports, systemd कॉन्फ़िगरेशन, TLS सुरक्षा और JSON-RPC स्ट्रीम की समस्याओं का समाधान दिया गया है।
आप क्या बना रहे हैं
एक VPS पर दो कार्यशील MCP सेटअप। पहला एक stdio सर्वर है, जो एक filesystem या database टूल है जिसे Claude Code एक child process के रूप में लॉन्च करता है और pipe के माध्यम से उससे संवाद करता है। दूसरा एक remote HTTP सर्वर है, जो systemd और TLS युक्त nginx reverse proxy के पीछे एक long-lived network service के रूप में चलता है, और जिसे किसी भी MCP client द्वारा एक्सेस किया जा सकता है। दोनों का इंस्टॉलेशन छोटा है। इस गाइड का अधिकांश भाग उन दो मुख्य चुनौतियों पर केंद्रित है जो अक्सर समस्या पैदा करती हैं: JSON-RPC stream को साफ रखना, और किसी भी unauthenticated टूल endpoint को कभी भी public internet पर न डालना।
MCP वास्तव में क्या है
Model Context Protocol एक मानक तरीका है जिसके माध्यम से एक AI client, जैसे Claude Code, Claude Desktop, VPS पर Gemini CLI, या आपकी अपनी script, बाहरी tools को call कर सकता है और बाहरी resources को पढ़ सकता है। model स्वयं कुछ भी run नहीं करता है। यह client से अनुरोध करता है, client एक MCP server के साथ JSON-RPC 2.0 में संवाद करता है, और server tool को run करके परिणाम वापस भेजता है। वह client ही वह घटक है जिसे लोग agent harness कहते हैं: यह model के चारों ओर का वह loop है जो tool list, permission checks और session state का प्रबंधन करता है, और MCP केवल वह तरीका है जिससे आप इसके tool वाले हिस्से का विस्तार करते हैं। यह एक एकल protocol है, इसलिए आपके द्वारा लिखा गया एक server उन सभी clients के साथ काम करता है जो MCP का समर्थन करते हैं। यदि यह विभाजन आपके लिए नया है, और विशेष रूप से यह प्रश्न कि model किसी tool का उपयोग करने का निर्णय कैसे लेता है, तो इन servers को वास्तविक credentials देने से पहले agent fundamentals के क्रमिक मार्ग को समझने में एक घंटा बिताना सार्थक है।
इसके दो transports हैं, और इस guide का शेष भाग इन्हीं के आधार पर विभाजित है:
- stdio. client server को एक child process के रूप में spawn करता है और अपने standard input तथा standard output के माध्यम से newline-delimited JSON-RPC messages का आदान-प्रदान करता है। इसमें कोई network, कोई port, या कोई auth नहीं होता; trust boundary स्वयं process ही होती है। लगभग सभी local tools इसी तरह काम करते हैं।
- Streamable HTTP (और इसका पुराना संस्करण, HTTP+SSE). server एक long-running web service होता है। client HTTP के माध्यम से connect होता है और server Server-Sent Events के रूप में responses को stream कर सकता है। इसी तरह आप एक server को कई clients के साथ साझा करते हैं, या कोई ऐसा tool run करते हैं जिसे स्थायी रूप से machine पर रहना आवश्यक है।
जब tool एक machine और एक user से संबंधित हो, तो stdio चुनें। जब यह एक shared service हो, तो HTTP चुनें।
पूर्वापेक्षाएँ और व्यावहारिक चुनौतियाँ
मान लें कि आपके पास root या sudo एक्सेस के साथ एक नया Ubuntu 24.04 KVM VPS है। इसके अलावा:
- सर्वर जिस runtime में लिखा गया है। अधिकांश reference servers Node या Python में हैं। Ubuntu 24.04 में Node 18 आता है, और कई वर्तमान MCP packages को Node 20 या उससे नए वर्ज़न की आवश्यकता होती है, इसलिए
aptपर भरोसा करने के बजाय NodeSource या nvm से वर्तमान LTS वर्ज़न इंस्टॉल करें। Python 3.12 पहले से मौजूद है। - एक domain और DNS A record, लेकिन केवल remote HTTP सर्वर के लिए, क्योंकि TLS के लिए एक ऐसे नाम की आवश्यकता होती है जो इस VPS पर resolve हो सके। stdio उदाहरण के लिए किसी DNS की आवश्यकता नहीं है।
- 512 MB RAM पर्याप्त है। MCP servers हल्के JSON-RPC processes होते हैं; मेमोरी की खपत इस पर निर्भर करती है कि आपका tool क्या उपयोग कर रहा है (जैसे database driver, file cache), न कि protocol पर।
- यह spec अभी नया है और इसमें बदलाव हो रहे हैं। 2025-03-26 के revision ने HTTP+SSE को Streamable HTTP से बदल दिया है और SSE को deprecated घोषित कर दिया है। SSE अभी भी काम करता है और कई servers अभी भी इसका उपयोग करते हैं, इसलिए किसी भी transport pin को अंतिम सत्य मानने के बजाय सर्वर के release notes के अनुसार दोबारा जाँचें।
चरण 1: Claude Code में stdio सर्वर को वायर करना
filesystem सर्वर से शुरुआत करें। यह आधिकारिक है, सक्रिय रूप से मेंटेन किया जाता है, और इसके लिए केवल Node की आवश्यकता होती है। नीचे दिया गया एक कमांड इसे Claude Code के साथ रजिस्टर करता है और इसे वर्तमान प्रोजेक्ट तक सीमित करता है ताकि यह एक committable फाइल में सेव हो जाए:
cd /home/matt/projects/api
claude mcp add --scope project --transport stdio filesystem \
-- npx -y @modelcontextprotocol/server-filesystem /home/matt/projects/api-- सेपरेटर महत्वपूर्ण है: इसके बाद का सब कुछ वह कमांड है जिसे Claude Code चलाएगा, न कि Claude Code के लिए कोई फ्लैग। यह प्रोजेक्ट रूट पर एक .mcp.json लिखता है:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/home/matt/projects/api"
]
}
}
}अभी कुछ भी नहीं चल रहा है। जब आप अगली बार इस डायरेक्टरी में Claude Code शुरू करेंगे, तो एजेंट .mcp.json को पढ़ेगा, npx -y @modelcontextprotocol/server-filesystem ... को चाइल्ड प्रोसेस के रूप में spawn करेगा, और उस प्रोसेस के stdin/stdout पर MCP हैंडशेक करेगा। पुष्टि करें कि यह काम कर गया:
claude mcp listएक सही ढंग से काम कर रहा सर्वर अपना कमांड और एक हरा टिक, filesystem: npx -y @modelcontextprotocol/server-filesystem ... - ✔ Connected प्रिंट करता है। सेशन के अंदर, /mcp स्लैश कमांड उन टूल्स को लिस्ट करता है जिन्हें सर्वर एक्सपोज करता है (read_text_file, write_file, list_directory), और एजेंट अब उन्हें उन पाथ्स पर कॉल कर सकता है जिनकी आपने अनुमति दी है। डेटाबेस टूल का तरीका भी समान है, बस पैकेज को बदलें और अंतिम आर्ग्युमेंट के रूप में कनेक्शन स्ट्रिंग पास करें, लेकिन वर्तमान पैकेज नाम के लिए सर्वर की अपनी रिपॉजिटरी देखें, क्योंकि रेफरेंस Postgres सर्वर का स्वामित्व कई बार बदला है।
एजेंट को बॉक्स पर चलाने का मुख्य उद्देश्य यही है: Claude Code सेशन VPS पर tmux के अंदर रहता है, और इसके stdio सर्वर सीधे इसके बगल में चलते हैं, जिन्हें प्रोजेक्ट फाइल्स और लोकल सर्विसेज का सीधा एक्सेस मिलता है, बिना किसी नेटवर्क राउंड-ट्रिप के। एक बार जब एजेंट के पास write_file और read_text_file दोनों का एक्सेस हो जाता है, तो उस पहुँच को ऐसी स्किल के साथ जोड़ना सार्थक है जो इसे सबसे छोटे संभव बदलाव की ओर ले जाए, क्योंकि एक filesystem टूल एक बड़े रीराइट को भी दो-लाइन के फिक्स जितना ही आसान बना देता है। यही वायरिंग लोकल फाइल्स से आगे भी काम करती है: यदि आप पहले से ही VPS पर सर्च इंजन चला रहे हैं, तो आप एजेंट को अपना SearXNG इंस्टेंस सर्च टूल के रूप में दे सकते हैं, जो क्वेरीज को आपके बॉक्स पर ही रखता है लेकिन अनट्रस्टेड पेज टेक्स्ट को सीधे उस कॉन्टेक्स्ट में खींच लेता है जिस पर एजेंट काम करता है।
चरण 2: एक रिमोट HTTP सर्वर बनाना
Stdio सर्वर अपने पैरेंट प्रोसेस के साथ समाप्त हो जाता है और इसे प्रति क्लाइंट एक बार स्पॉन किया जाता है। इसलिए यदि आप बॉक्स पर दो Claude Code सेशन चलाते हैं जो एक-दूसरे को काम सौंपते हैं, तो प्रत्येक को टूल की अपनी निजी कॉपी मिलती है। जब आपको ऐसे टूल की आवश्यकता होती है जो हर क्लाइंट के लिए चालू रहे, जैसे कि एक साझा ops टूल, डेटाबेस गेटवे, या कुछ ऐसा जिसे आपका लैपटॉप और CI दोनों कॉल करते हैं, तो आपको HTTP ट्रांसपोर्ट और एक वास्तविक सर्विस की आवश्यकता होती है। यहाँ आधिकारिक SDK का उपयोग करने वाला एक न्यूनतम Python सर्वर है, जो एक टूल को एक्सपोज़ करता है:
# /opt/mcp-ops/server.py
from mcp.server.mcpserver import MCPServer
import subprocess
mcp = MCPServer("ops-tools")
@mcp.tool()
def disk_free() -> str:
"""Return `df -h` for the server."""
out = subprocess.run(["df", "-h"], capture_output=True, text=True)
return out.stdout
if __name__ == "__main__":
# Serves Streamable HTTP at /mcp on 127.0.0.1:8000
mcp.run(transport="streamable-http", host="127.0.0.1", port=8000)host="127.0.0.1" पर ध्यान दें। सर्वर केवल localhost से बाइंड होता है, बॉक्स के बाहर से कोई भी इसे सीधे एक्सेस नहीं कर सकता है, जो कि ऑथेंटिकेशन (auth) होने से पहले बिल्कुल वैसा ही है जैसा आप चाहते हैं। यह 2.x SDK है जिसे pip install "mcp[cli]" आज पुल करता है (2026-10-20 तक 2.3.0)। इसने FastMCP का नाम बदलकर MCPServer कर दिया है और host तथा port को कंस्ट्रक्टर से हटाकर run() में स्थानांतरित कर दिया है, और पुराना mcp.server.fastmcp इम्पोर्ट अब ModuleNotFoundError के साथ विफल हो जाता है। इसे अपने स्वयं के virtualenv में इंस्टॉल करें ताकि systemd के पास एक स्थिर इंटरप्रेटर पाथ हो:
sudo useradd --system --home /opt/mcp-ops --shell /usr/sbin/nologin mcp
sudo install -d -o mcp -g mcp /opt/mcp-ops
sudo -H -u mcp python3 -m venv /opt/mcp-ops/.venv
sudo -H -u mcp /opt/mcp-ops/.venv/bin/pip install "mcp[cli]"चरण 3: systemd के साथ इसे चालू रखें
यदि कोई टूल तब डाउन हो जब एजेंट उसे एक्सेस करने की कोशिश करे, तो वह टूल न होने से भी बदतर है। यह तब सबसे अधिक मायने रखता है जब क्लाइंट स्वयं एक long-lived process हो: एक always-on agent जो रीबूट के बाद भी अपनी मेमोरी और शेड्यूल को बनाए रखता है वह इन टूल्स को बिना किसी की निगरानी के एक शेड्यूल पर कॉल करेगा, इसलिए सर्वर को अपने आप वापस आना चाहिए। /etc/systemd/system/mcp-ops.service लिखें:
[Unit]
Description=MCP ops-tools server
After=network.target
[Service]
Type=simple
User=mcp
WorkingDirectory=/opt/mcp-ops
ExecStart=/opt/mcp-ops/.venv/bin/python /opt/mcp-ops/server.py
Restart=on-failure
RestartSec=2
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
[Install]
WantedBy=multi-user.targetExecStart में venv Python का absolute path वैकल्पिक नहीं है, इसे /usr/bin/python3 पर पॉइंट करें और प्रोसेस ModuleNotFoundError: No module named 'mcp' के साथ शुरू होगी, क्योंकि system interpreter ने कभी भी आपका pip install नहीं देखा था। इसे enable करें और जाँचें:
sudo systemctl daemon-reload
sudo systemctl enable --now mcp-ops
sudo systemctl status mcp-ops
curl -si -H 'Accept: application/json, text/event-stream' \
-H 'Content-Type: application/json' \
-X POST http://127.0.0.1:8000/mcpstatus को active (running) पढ़ना चाहिए। curl वापस आता है HTTP/1.1 400 Bad Request, जिसमें बॉडी में एक JSON-RPC error होती है, अनुरोध में कोई session और कोई valid JSON payload नहीं था, और आप बिल्कुल यही चाहते हैं: यह साबित करता है कि पोर्ट जवाब देता है और प्रोटोकॉल का पालन करता है। Connection refused या खाली उत्तर का मतलब है कि प्रोसेस वहां bound नहीं है जहां आप सोचते हैं; journalctl -u mcp-ops -n 50 पढ़ें।
चरण 4: TLS और reverse proxy को सामने रखें
सर्वर localhost पर listen करता है। इसे कहीं से भी एक्सेस करने के लिए, आप nginx पर TLS terminate करें और traffic को अंदर proxy करें। nginx install करें, Certbot and Let's Encrypt on nginx का उपयोग करके certificate प्राप्त करें, और फिर location block लिखें। सबसे महत्वपूर्ण हिस्सा buffering को disable करना है, क्योंकि nginx का डिफ़ॉल्ट व्यवहार response को पूरा होने तक रोक कर रखता है, जिससे SSE stream हमेशा के लिए रुक जाती है:
server {
listen 443 ssl;
server_name mcp.example.com;
# ssl_certificate lines managed by Certbot
location /mcp {
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
# The four lines that make SSE work through nginx:
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 3600s;
chunked_transfer_encoding off;
}
}sudo nginx -t && sudo systemctl reload nginx के साथ reload करें। यदि आप पहले से ही containers का उपयोग कर रहे हैं, तो यही काम आपके लिए Traefik reverse proxy with automatic TLS द्वारा किया जा सकता है; यह certificate जारी करता है और hostname के आधार पर routing करता है, और आपको बस MCP container में labels जोड़ने होते हैं। किसी भी स्थिति में, reverse proxy अब public port पर एकमात्र चीज़ है, और यह एक ऐसी service की ओर इशारा करता है जिसे आपने अभी तक सुरक्षित नहीं किया है। URL को कहीं भी register करने से पहले इसे ठीक करें।
चरण 5: सुरक्षा नियम जो इस विषय पर हावी है
किसी unauthenticated MCP endpoint को कभी भी expose न करें। एक MCP server केवल read-only API नहीं है। यह आपके files, database और कभी-कभी shell तक tool access प्रदान करता है। public internet पर एक खुला /mcp एक ऐसे अजनबी के समान है जिसकी पहुँच आपके AI agent जितनी ही है: वे आपके tools की सूची देख सकते हैं और फिर उन्हें call कर सकते हैं। इसे बिल्कुल एक unauthenticated admin socket की तरह मानें, क्योंकि यह वास्तव में वही है। चोरी हुआ token आपको कितनी हानि पहुँचा सकता है, यह इसके पीछे के server पर निर्भर करता है: openGym workout tracker के साथ आने वाला read-only MCP server केवल training data ही दे सकता है, जबकि एक filesystem या shell tool पूरे box का नियंत्रण दे देता है।
प्राथमिकता के क्रम में तीन सुरक्षा उपाय:
- इसे publish न करें। server को
127.0.0.1पर रखें और अपने laptop से SSH tunnel के जरिए उस तक पहुँचें:ssh -L 8000:127.0.0.1:8000 matt@vps, फिर client कोhttp://127.0.0.1:8000/mcpपर point करें। कुछ भी कभी expose नहीं होगा। - इसे private network पर रखें। self-hosted WireGuard VPN के tunnel address को bind करें और केवल VPN peers को ही उस तक पहुँचने दें। public internet को केवल एक बंद port दिखाई देगा।
- यदि इसे public होना ही है, तो token अनिवार्य करें। सही तरीका MCP OAuth flow है जिसे HTTP transport natively support करता है। व्यावहारिक न्यूनतम उपाय proxy पर check किया जाने वाला एक shared bearer token है; यह सस्ता है और drive-by हमलों को पूरी तरह रोकता है:
location /mcp {
if ($http_authorization != "Bearer REPLACE_WITH_LONG_RANDOM") {
return 401;
}
proxy_pass http://127.0.0.1:8000;
# ...buffering-off block from above...
}openssl rand -hex 32 के साथ token generate करें, और इनमें से किसी एक सुरक्षा उपाय के बिना server को कभी भी 0.0.0.0 पर bind न करें। इसके बाद client token को header के रूप में भेजता है। Claude Code में:
claude mcp add --scope project --transport http ops-tools https://mcp.example.com/mcp \
--header 'Authorization: Bearer ${MCP_TOKEN}'अपने shell में MCP_TOKEN set करें ताकि secret कभी भी plaintext में .mcp.json में न जाए, Claude Code read time पर environment से ${MCP_TOKEN} को expand करता है। यदि variable unset है, तो Claude Code खाली string substitute नहीं करता: यह claude mcp list में missing variable को flag करता है और literal ${MCP_TOKEN} text का उपयोग करता है। अपना स्वयं का नाम चुनें, क्योंकि remote server के headers में Claude Code जानबूझकर अपने और आपके cloud provider के credential variables, जैसे ANTHROPIC_API_KEY, को खाली पढ़ता है, साथ ही अन्य credentials जो आपके environment में मौजूद हैं, जैसे NPM_TOKEN।
ऊपर दिए गए सभी उपाय endpoint की सुरक्षा करते हैं, न कि उस agent की जिसके पास पहले से token है, जो समस्या का दूसरा पहलू है: यदि आपका client DeepSeek Harness है, तो plugins जो यह नियंत्रित करते हैं कि agent कौन से tools call कर सकता है और injected instructions के लिए tool output को scan करते हैं उस पक्ष को कवर करते हैं।
चरण 6: MCP Inspector के साथ डिबग करें
जब सर्वर ठीक से काम न करे, तो एजेंट के भीतर से अनुमान न लगाएँ। इसे सीधे Inspector के साथ चलाएँ, जो कि आधिकारिक वेब-आधारित टेस्ट क्लाइंट है। stdio सर्वर के लिए, इसे वही कमांड दें जिसे एजेंट चलाता है:
npx @modelcontextprotocol/inspector \
npx -y @modelcontextprotocol/server-filesystem /tmpयह http://localhost:6274 पर एक वेब सर्वर से अपना UI सर्व करता है और एक URL प्रिंट करता है जिसमें MCP_INSPECTOR_API_TOKEN क्वेरी स्ट्रिंग होती है; पते को याददाश्त से टाइप करने के बजाय उस लिंक को खोलें। v2 (2026-10-20 तक 2.11.0 वर्तमान है) के बाद से, बैकएंड हर लोड पर पेज में टोकन भी इंजेक्ट करता है, इसलिए रीलोड करने पर भी यह काम करता रहता है, और टोकन उन /api/* रूट्स की सुरक्षा करता है जो प्रोसेस शुरू कर सकते हैं। 6277 पर अलग v1 प्रॉक्सी अब हटा दी गई है, लेकिन वेब सर्वर एकमात्र लिसनर नहीं है: v2, MCP_SANDBOX_PORT (डिफ़ॉल्ट रूप से 6275) पर MCP Apps के लिए एक सैंडबॉक्स और MCP_APP_ORIGIN_PORT (डिफ़ॉल्ट रूप से 6278) पर एक समर्पित ऐप-ऑरिजिन सर्वर भी शुरू करता है, जो किसी भी ऐसे MCP App को सर्व करता है जिसका UI रिसोर्स _meta.ui.domain घोषित करता है। यदि आप SSH टनल के माध्यम से Inspector तक पहुँचते हैं या इसे कंटेनर में चलाते हैं और आपको Apps टैब की आवश्यकता है, तो 6274 के साथ 6275 और 6278 को भी फॉरवर्ड करें। कनेक्ट करें, Tools टैब खोलें, एक टूल चुनें, वास्तविक तर्क (arguments) भरें और इसे कॉल करें। यदि यह Inspector में काम करता है लेकिन एजेंट में विफल रहता है, तो बग आपके क्लाइंट कॉन्फ़िगरेशन में है, सर्वर में नहीं। रिमोट HTTP सर्वर के लिए, बिना किसी कमांड के Inspector लॉन्च करें, Streamable HTTP ट्रांसपोर्ट और https://mcp.example.com/mcp के साथ एक सर्वर जोड़ें, इसकी सेटिंग्स में Authorization हेडर डालें, और कनेक्ट करें। किसी भी एजेंट के शामिल होने से पहले ऑथेंटिकेशन और प्रॉक्सी के सही होने की पुष्टि करने का यह सबसे तेज़ तरीका है। Inspector सर्वर कैटलॉग में हेडर्स को बिल्कुल वैसे ही सेव करता है जैसे वे लिखे गए हैं, इसलिए वह टोकन अब ~/.mcp-inspector/mcp.json में भी सुरक्षित रहता है।
सर्वरों को अपडेट रखना
MCP तेजी से विकसित होता है, इसलिए एक निश्चित समय-सारणी के अनुसार पैच करें। बिना पिन किए गए npx -y के साथ लॉन्च किए गए Node सर्वर उस वर्जन को चलाते हैं जिसे npx resolve करता है: यदि स्थानीय प्रोजेक्ट में कोई वर्जन इंस्टॉल है तो वह, अन्यथा npm cache में इंस्टॉल की गई एक कॉपी। -y केवल इंस्टॉल प्रॉम्प्ट को स्किप करता है, यह अपडेट को बाध्य नहीं करता है, इसलिए आप न तो नवीनतम रिलीज को ट्रैक कर पाते हैं और न ही यह सुनिश्चित कर पाते हैं कि आप कौन सा वर्जन चला रहे हैं। जब कोई सर्वर महत्वपूर्ण हो जाए, तो उस सटीक वर्जन को पिन करें जिसका आपने परीक्षण किया है, इसे npm view @modelcontextprotocol/server-filesystem version से पढ़ें और .mcp.json (@modelcontextprotocol/server-filesystem@<version>) में पैकेज नाम के साथ जोड़ें, और इसे सोच-समझकर अपडेट करें। systemd के अंतर्गत Python सर्वर sudo -H -u mcp /opt/mcp-ops/.venv/bin/pip install -U "mcp[cli]" और उसके बाद sudo systemctl restart mcp-ops के साथ अपडेट होते हैं। किसी बड़े वर्जन बदलाव से पहले रिलीज नोट्स पढ़ें: 1.x से 2.x Python SDK पर जाने से 1.x कोड import के समय विफल हो जाता है, और SDK की अपनी माइग्रेशन गाइड यह सलाह देती है कि जब तक आप माइग्रेट न कर लें, तब तक <2 की ऊपरी सीमा, जैसे कि "mcp[cli]<2", बनाए रखें। अपग्रेड करते समय उस spec revision पर ध्यान दें जिसे आपका SDK लक्षित करता है, SSE-to-Streamable-HTTP सीमा के पार जाने से वह ट्रांसपोर्ट बदल सकता है जिसका आपके क्लाइंट्स को अनुरोध करना आवश्यक है।
विफलता के प्रकार और दिखाई देने वाले स्ट्रिंग्स
एजेंट दिखाता है कि सर्वर विफल हो गया है। claude mcp list, ✘ Failed to connect प्रिंट करता है, और वर्तमान संस्करण उस पंक्ति में विफलता का विवरण जोड़ देते हैं। claude --debug चलाएं और आप आमतौर पर Error: spawn npx ENOENT देखेंगे, जिसका अर्थ है कि कमांड एजेंट के PATH में नहीं है। रनटाइम गायब है या वहां नहीं है जहां एजेंट उसे खोजता है: Node इंस्टॉल नहीं है, npx अनुपस्थित है, या किसी virtualenv Python को केवल नाम से संदर्भित किया गया है। कमांड को एब्सोल्यूट पाथ (absolute path) पर ठीक करें या रनटाइम इंस्टॉल करें, फिर पुनः कनेक्ट करें।
एक stdio सर्वर कनेक्ट होता है, फिर तुरंत बंद हो जाता है। क्लाइंट लॉग में JSON पार्स एरर दिखाता है, जैसे Unexpected token 'S', "Server sta"... is not valid JSON या Failed to parse message। इसका कारण हमेशा एक ही होता है: सर्वर ने stdout पर एक लॉग लाइन लिखी है। stdio पर, stdout ही JSON-RPC चैनल होता है, इसलिए कोई भी अतिरिक्त टेक्स्ट स्ट्रीम को दूषित कर देता है और हैंडशेक विफल हो जाता है। Node में, console.log stdout पर जाता है, इसके बजाय console.error का उपयोग करें। Python में, एक साधारण print() stdout पर जाता है, लॉग को logging के साथ लिखें जिसे sys.stderr पर कॉन्फ़िगर किया गया हो, या file=sys.stderr पास करें। नियम स्पष्ट है: stdio पर, stdout पर केवल JSON-RPC होना चाहिए, बाकी सब कुछ stderr पर होना चाहिए।
एक रिमोट सर्वर टाइम आउट हो जाता है या हैंडशेक के बीच में ही बंद हो जाता है। क्लाइंट MCP error -32000: Connection closed के साथ विफल हो जाता है, या इंस्पेक्टर Connect पर अटक जाता है और कोई टूल लिस्ट नहीं करता है। nginx के पीछे इसका कारण बफरिंग है: प्रॉक्सी SSE स्ट्रीम को फ्लश करने के बजाय उसे होल्ड कर लेती है, इसलिए क्लाइंट उस रिस्पॉन्स की प्रतीक्षा करता है जो कभी नहीं आता। proxy_buffering off; (और स्टेप 4 का शेष ब्लॉक) को location में जोड़ें। पब्लिक URL के विरुद्ध curl -N के साथ पुष्टि करें, आपको इवेंट डेटा धीरे-धीरे आता हुआ दिखना चाहिए, न कि अंत में एक साथ।
ऑथेंटिकेशन अस्वीकार कर दिया गया है। क्लाइंट Error POSTing to endpoint (HTTP 401) या सीधे 401 Unauthorized रिपोर्ट करता है। या तो हेडर गायब है, टोकन गलत है, या वेरिएबल एक्सपैंड नहीं हुआ है, जो एक सामान्य गलती है। यदि क्लाइंट द्वारा कॉन्फ़िगरेशन पढ़ते समय MCP_TOKEN सेट नहीं है, तो Claude Code claude mcp list में गायब वेरिएबल के बारे में चेतावनी देता है और शाब्दिक टेक्स्ट भेजता है, इसलिए nginx को Bearer ${MCP_TOKEN} दिखाई देता है। Claude Code, आपके क्लाउड प्रदाता या आपके वातावरण के अन्य क्रेडेंशियल्स में से किसी एक के नाम पर रखा गया वेरिएबल खाली दिखाई देता है, और nginx को बिना किसी मान के Bearer दिखाई देता है। वेरिएबल को echo करें, हेडर को पुनः जोड़ें, और सत्यापित करें कि सटीक बाइट्स nginx if में मौजूद टोकन से मेल खाते हैं।
service systemd के तहत शुरू नहीं होगी। journalctl -u mcp-ops में ModuleNotFoundError: No module named 'mcp' दिखाई देता है, ExecStart venv इंटरप्रेटर के बजाय सिस्टम Python की ओर इशारा करता है। या Address already in use, कोई अन्य प्रक्रिया 8000 पोर्ट का उपयोग कर रही है; इसे sudo ss -ltnp | grep 8000 के साथ खोजें।
FAQ
MCP server वास्तव में क्या है?
यह एक प्रोग्राम है जो Model Context Protocol के माध्यम से AI client को tools और resources उपलब्ध कराता है, जिसमें JSON-RPC 2.0 का उपयोग होता है। AI model स्वयं tool को कभी नहीं चलाता है, बल्कि वह अपने client से अनुरोध करता है, client MCP server को call करता है, और server उसे निष्पादित करके परिणाम वापस भेजता है। चूँकि यह protocol मानक है, इसलिए एक server किसी भी compliant client के साथ काम करता है, चाहे वह Claude Code हो, Claude Desktop हो, या Gemini CLI हो।
stdio और HTTP transport में क्या अंतर है?
एक stdio server को client द्वारा child process के रूप में launch किया जाता है और यह stdin/stdout के माध्यम से संचार करता है, इसलिए यह एक मशीन पर एक client के साथ ही चलता है और इसे किसी network या authentication की आवश्यकता नहीं होती है। एक HTTP server एक लंबे समय तक चलने वाली network service है जिसे कई clients एक साथ access कर सकते हैं, यही कारण है कि इसके लिए TLS और authentication की आवश्यकता होती है। स्थानीय, single-user tools के लिए stdio का उपयोग करें; साझा या persistent किसी भी चीज़ के लिए HTTP (वर्तमान servers पर Streamable HTTP) का उपयोग करें।
मैं remote MCP server को सुरक्षित कैसे करूँ?
यह मानकर चलें कि यह आपकी फाइलों, database या shell तक tool access प्रदान करता है, और इसे कभी भी बिना authentication के expose न करें। सबसे अच्छा तरीका यह है कि इसे localhost तक सीमित रखें और SSH tunnel या private VPN के माध्यम से access करें; यदि इसे public होना ही है, तो इसे एक reverse proxy के पीछे रखें जो bearer token या MCP OAuth flow को लागू करता हो। openssl rand -hex 32 के साथ token generate करें और इनमें से किसी एक सुरक्षा उपाय के बिना server को कभी भी 0.0.0.0 पर bind न करें।
मैं उस server को debug कैसे करूँ जो start नहीं हो रहा है?
सबसे पहले claude mcp list, ✘ Failed to connect की जाँच करें। spawn ... ENOENT का अर्थ है कि command या runtime मौजूद नहीं है, इसलिए path को ठीक करें या उसे install करें। यदि यह connect होने के बाद JSON parse error के साथ drop हो जाता है, तो इसका मतलब है कि server stdout पर logging कर रहा है और JSON-RPC stream को दूषित कर रहा है; सभी logging को stderr पर ले जाएँ। किसी भी अन्य समस्या के लिए, MCP Inspector के तहत सटीक command चलाएँ, जो server को अलग-थलग (isolation) चलाता है ताकि आप server bug और client-config bug के बीच अंतर बता सकें।