इसे छोड़कर कंटेंट पर जाएं

MCP प्रोटोकॉल और ट्रांसपोर्ट आंतरिक संरचना

यह दस्तावेज़ वर्णन करता है कि coding-agent MCP JSON-RPC मैसेजिंग को कैसे कार्यान्वित करता है और प्रोटोकॉल संबंधी चिंताओं को ट्रांसपोर्ट संबंधी चिंताओं से कैसे अलग किया जाता है।

इसमें शामिल है:

  • JSON-RPC अनुरोध/प्रतिक्रिया और अधिसूचना प्रवाह
  • stdio और HTTP/SSE ट्रांसपोर्ट के लिए अनुरोध सहसंबंध और जीवनचक्र
  • टाइमआउट और रद्दीकरण व्यवहार
  • त्रुटि प्रसारण और विकृत पेलोड हैंडलिंग
  • ट्रांसपोर्ट चयन सीमाएं (stdio बनाम http/sse)
  • कौन सी पुनर्कनेक्ट/पुनर्प्रयास जिम्मेदारियां ट्रांसपोर्ट-स्तरीय हैं बनाम मैनेजर-स्तरीय

इसमें एक्सटेंशन ऑथरिंग UX या कमांड UI शामिल नहीं है।

कार्यान्वयन फ़ाइलें

Section titled “कार्यान्वयन फ़ाइलें”

प्रोटोकॉल परत (JSON-RPC + MCP विधियाँ)

Section titled “प्रोटोकॉल परत (JSON-RPC + MCP विधियाँ)”
  • संदेश आकार types.ts में परिभाषित हैं (JsonRpcRequest, JsonRpcNotification, JsonRpcResponse, JsonRpcMessage)।
  • MCP क्लाइंट लॉजिक (client.ts) विधि क्रम और सत्र हैंडशेक निर्धारित करता है:
    1. initialize अनुरोध
    2. notifications/initialized अधिसूचना
    3. tools/list, tools/call जैसी विधि कॉल

ट्रांसपोर्ट परत (MCPTransport)

Section titled “ट्रांसपोर्ट परत (MCPTransport)”

MCPTransport डिलीवरी और जीवनचक्र को अमूर्त करता है:

  • request(method, params, options?) -> Promise<T>
  • notify(method, params?) -> Promise<void>
  • close()
  • connected
  • वैकल्पिक कॉलबैक: onClose, onError, onNotification

ट्रांसपोर्ट कार्यान्वयन फ्रेमिंग और I/O विवरणों के स्वामी हैं:

  • StdioTransport: सबप्रोसेस stdio पर न्यूलाइन-सीमांकित JSON
  • HttpTransport: HTTP POST पर JSON-RPC, वैकल्पिक SSE प्रतिक्रियाओं/श्रवण के साथ

महत्वपूर्ण वर्तमान चेतावनी

Section titled “महत्वपूर्ण वर्तमान चेतावनी”

ट्रांसपोर्ट कॉलबैक (onClose, onError, onNotification) कार्यान्वित हैं, लेकिन वर्तमान MCPClient/MCPManager प्रवाह इन कॉलबैक में पुनर्कनेक्शन लॉजिक को जोड़ते नहीं हैं। अधिसूचनाएं केवल तभी उपभोग की जाती हैं जब कॉलर हैंडलर पंजीकृत करता है।

ट्रांसपोर्ट चयन

Section titled “ट्रांसपोर्ट चयन”

client.ts:createTransport() कॉन्फ़िगरेशन से ट्रांसपोर्ट चुनता है:

  • type छोड़ दिया गया या "stdio" -> createStdioTransport
  • "http" या "sse" -> createHttpTransport

"sse" को HTTP ट्रांसपोर्ट वेरिएंट (समान क्लास) के रूप में माना जाता है, एक अलग ट्रांसपोर्ट कार्यान्वयन के रूप में नहीं।

JSON-RPC संदेश प्रवाह और सहसंबंध

Section titled “JSON-RPC संदेश प्रवाह और सहसंबंध”

प्रत्येक ट्रांसपोर्ट प्रति-अनुरोध ID उत्पन्न करता है (Math.random + टाइमस्टैम्प स्ट्रिंग)। ID ट्रांसपोर्ट-स्थानीय सहसंबंध टोकन हैं।

  • आउटबाउंड अनुरोध एक JSON ऑब्जेक्ट + \n के रूप में क्रमबद्ध किया जाता है।
  • #pendingRequests: Map<id, {resolve,reject}> इन-फ्लाइट अनुरोधों को संग्रहीत करता है।
  • रीड लूप stdout से JSONL पार्स करता है और #handleMessage को कॉल करता है।
  • यदि इनबाउंड संदेश में मेल खाता id है, तो अनुरोध resolve/reject होता है।
  • यदि इनबाउंड संदेश में method है और कोई id नहीं है, तो इसे अधिसूचना के रूप में माना जाता है और onNotification को भेजा जाता है।

अज्ञात ID को अनदेखा किया जाता है (कोई rejection नहीं, कोई error कॉलबैक नहीं)।

  • आउटबाउंड अनुरोध JSON बॉडी और उत्पन्न id के साथ HTTP POST है।
  • गैर-SSE प्रतिक्रिया पथ: एक JSON-RPC प्रतिक्रिया पार्स करता है और result लौटाता है / error पर throw करता है।
  • SSE प्रतिक्रिया पथ (Content-Type: text/event-stream): इवेंट स्ट्रीम करता है, पहले संदेश को लौटाता है जिसका id अपेक्षित अनुरोध ID से मेल खाता है और जिसमें result या error है।
  • method वाले और बिना id वाले SSE संदेशों को अधिसूचना के रूप में माना जाता है।

यदि SSE स्ट्रीम मेल खाती प्रतिक्रिया से पहले समाप्त हो जाती है, तो अनुरोध No response received for request ID ... के साथ विफल होता है।

क्लाइंट transport.notify(...) के माध्यम से JSON-RPC अधिसूचनाएं उत्सर्जित करता है।

  • Stdio: stdin में अधिसूचना फ्रेम (jsonrpc, method, वैकल्पिक params) प्लस न्यूलाइन लिखता है।
  • HTTP: बिना id के POST बॉडी भेजता है; सफलता 2xx या 202 Accepted स्वीकार करती है।

सर्वर-आरंभित अधिसूचनाएं केवल ट्रांसपोर्ट onNotification के माध्यम से प्रदर्शित की जाती हैं; मैनेजर/क्लाइंट में कोई डिफ़ॉल्ट वैश्विक सब्सक्राइबर नहीं है।

Stdio ट्रांसपोर्ट आंतरिक संरचना

Section titled “Stdio ट्रांसपोर्ट आंतरिक संरचना”

जीवनचक्र और स्थिति संक्रमण

Section titled “जीवनचक्र और स्थिति संक्रमण”
  • प्रारंभिक: connected=false, process=null, pending map खाली
  • connect():
    • कॉन्फ़िगर किए गए command/args/env/cwd के साथ सबप्रोसेस spawn करें
    • connected चिह्नित करें
    • stdout रीड लूप शुरू करें (readJsonl)
    • stderr लूप शुरू करें (read/discard; वर्तमान में मूक)
  • close():
    • disconnected चिह्नित करें
    • सभी pending अनुरोधों को reject करें (Transport closed)
    • सबप्रोसेस kill करें
    • रीड लूप शटडाउन की प्रतीक्षा करें
    • onClose उत्सर्जित करें

यदि रीड लूप अप्रत्याशित रूप से बाहर निकलता है, तो finally #handleClose() को ट्रिगर करता है जो समान pending-request rejection और close कॉलबैक करता है।

टाइमआउट और रद्दीकरण

Section titled “टाइमआउट और रद्दीकरण”

प्रति अनुरोध:

  • टाइमआउट डिफ़ॉल्ट config.timeout ?? 30000 है
  • कॉलर से वैकल्पिक AbortSignal
  • abort और timeout दोनों pending promise को reject करते हैं और map entry साफ़ करते हैं

रद्दीकरण केवल स्थानीय है: ट्रांसपोर्ट सर्वर को प्रोटोकॉल-स्तरीय रद्दीकरण अधिसूचना नहीं भेजता।

विकृत पेलोड हैंडलिंग

Section titled “विकृत पेलोड हैंडलिंग”

रीड लूप में:

  • प्रत्येक पार्स की गई JSONL लाइन try/catch में #handleMessage को पास की जाती है
  • विकृत/अमान्य संदेश हैंडलिंग अपवाद छोड़ दिए जाते हैं (Skip malformed lines टिप्पणी)
  • लूप जारी रहता है, इसलिए एक खराब संदेश कनेक्शन को समाप्त नहीं करता

यदि अंतर्निहित स्ट्रीम पार्सर throw करता है, तो onError invoked होता है (जब अभी भी connected हो), फिर कनेक्शन बंद हो जाता है।

डिस्कनेक्ट/विफलता व्यवहार

Section titled “डिस्कनेक्ट/विफलता व्यवहार”

जब प्रक्रिया बाहर निकलती है या स्ट्रीम बंद होती है:

  • सभी इन-फ्लाइट अनुरोध Transport closed के साथ reject होते हैं
  • कोई स्वचालित पुनरारंभ या पुनर्कनेक्ट नहीं
  • उच्च परतों को एक नया ट्रांसपोर्ट बनाकर पुनर्कनेक्ट करना होगा

बैकप्रेशर/स्ट्रीमिंग नोट्स

Section titled “बैकप्रेशर/स्ट्रीमिंग नोट्स”
  • आउटबाउंड राइट drain सेमांटिक्स की प्रतीक्षा किए बिना stdin.write() + flush() का उपयोग करते हैं।
  • ट्रांसपोर्ट में कोई स्पष्ट कतार या high-watermark प्रबंधन नहीं है।
  • इनबाउंड प्रोसेसिंग स्ट्रीम-संचालित है (readJsonl पर for await), एक समय में एक पार्स किया गया संदेश।

HTTP/SSE ट्रांसपोर्ट आंतरिक संरचना

Section titled “HTTP/SSE ट्रांसपोर्ट आंतरिक संरचना”

जीवनचक्र और कनेक्शन सेमांटिक्स

Section titled “जीवनचक्र और कनेक्शन सेमांटिक्स”

HTTP ट्रांसपोर्ट में तार्किक कनेक्शन स्थिति है, लेकिन अनुरोध पथ प्रति HTTP कॉल स्टेटलेस है:

  • connect() connected=true सेट करता है (कोई सॉकेट/सत्र हैंडशेक नहीं)
  • Mcp-Session-Id हेडर के माध्यम से वैकल्पिक सर्वर सत्र ट्रैकिंग
  • close() वैकल्पिक रूप से Mcp-Session-Id के साथ DELETE भेजता है, SSE लिसनर को abort करता है, onClose उत्सर्जित करता है

इसलिए connected का अर्थ है “ट्रांसपोर्ट उपयोग योग्य है”, न कि “स्थायी स्ट्रीम स्थापित है”।

सत्र हेडर व्यवहार

Section titled “सत्र हेडर व्यवहार”
  • POST प्रतिक्रिया पर, यदि Mcp-Session-Id हेडर उपस्थित है, तो ट्रांसपोर्ट इसे संग्रहीत करता है।
  • बाद के अनुरोध/अधिसूचनाएं Mcp-Session-Id शामिल करती हैं।
  • close() HTTP DELETE के साथ सर्वर सत्र समाप्त करने का प्रयास करता है; समाप्ति विफलताओं को अनदेखा किया जाता है।

टाइमआउट और रद्दीकरण

Section titled “टाइमआउट और रद्दीकरण”

request() और notify() दोनों के लिए:

  • टाइमआउट AbortController (config.timeout ?? 30000) का उपयोग करता है
  • बाहरी सिग्नल, यदि प्रदान किया गया हो, AbortSignal.any([...]) के माध्यम से मर्ज किया जाता है
  • AbortError हैंडलिंग कॉलर abort बनाम timeout को अलग करती है

फेंकी गई त्रुटियां:

  • टाइमआउट: Request timeout after ...ms (या SSE response timeout ..., Notify timeout ...)
  • कॉलर abort: जब बाहरी सिग्नल पहले से abort हो तो मूल AbortError पुनः फेंका जाता है

HTTP त्रुटि प्रसारण

Section titled “HTTP त्रुटि प्रसारण”

गैर-OK प्रतिक्रिया पर:

  • प्रतिक्रिया टेक्स्ट फेंकी गई त्रुटि में शामिल है (HTTP <status>: <text>)
  • यदि उपस्थित हो, WWW-Authenticate और Mcp-Auth-Server से auth संकेत जोड़े जाते हैं

JSON-RPC error ऑब्जेक्ट पर:

  • MCP error <code>: <message> throw करता है

विकृत JSON बॉडी (response.json() विफलता) parse अपवाद के रूप में प्रसारित होती है।

SSE व्यवहार और मोड

Section titled “SSE व्यवहार और मोड”

दो SSE पथ मौजूद हैं:

  1. प्रति-अनुरोध SSE प्रतिक्रिया (#parseSSEResponse)

    • जब POST प्रतिक्रिया content type text/event-stream हो तब उपयोग किया जाता है
    • मेल खाते response id मिलने तक स्ट्रीम का उपभोग करता है
    • समान स्ट्रीम के दौरान इंटरलीव्ड अधिसूचनाओं को संसाधित कर सकता है
  2. पृष्ठभूमि SSE लिसनर (startSSEListener())

    • सर्वर-आरंभित अधिसूचनाओं के लिए वैकल्पिक GET लिसनर
    • वर्तमान में MCP मैनेजर/क्लाइंट द्वारा स्वचालित रूप से शुरू नहीं किया जाता
    • यदि GET 405 लौटाता है, तो लिसनर चुपचाप स्वयं को अक्षम कर देता है (सर्वर इस मोड का समर्थन नहीं करता)

विकृत पेलोड और डिस्कनेक्ट हैंडलिंग

Section titled “विकृत पेलोड और डिस्कनेक्ट हैंडलिंग”

SSE JSON पार्सिंग त्रुटियां readSseJson से बाहर निकलती हैं और अनुरोध/लिसनर को reject करती हैं।

  • अनुरोध SSE पार्स त्रुटियां सक्रिय अनुरोध को reject करती हैं।
  • पृष्ठभूमि लिसनर त्रुटियां onError ट्रिगर करती हैं (AbortError को छोड़कर)।
  • पृष्ठभूमि लिसनर के लिए कोई ऑटो-रिकनेक्ट नहीं।

json-rpc.ts उपयोगिता बनाम ट्रांसपोर्ट अमूर्तता

Section titled “json-rpc.ts उपयोगिता बनाम ट्रांसपोर्ट अमूर्तता”

src/mcp/json-rpc.ts प्रत्यक्ष HTTP MCP कॉल के लिए callMCP() और parseSSE() हेल्पर प्रदान करता है (Exa एकीकरण द्वारा उपयोग किया जाता है), MCPClient/MCPManager द्वारा उपयोग की जाने वाली MCPTransport अमूर्तता नहीं।

HttpTransport से उल्लेखनीय अंतर:

  • पहले संपूर्ण प्रतिक्रिया टेक्स्ट पार्स करता है, फिर पहली data: लाइन निकालता है (parseSSE), JSON फ़ॉलबैक के साथ
  • कोई अनुरोध टाइमआउट प्रबंधन नहीं, कोई abort API नहीं, कोई session-id हैंडलिंग नहीं, कोई ट्रांसपोर्ट जीवनचक्र नहीं
  • कच्चा JSON-RPC envelope ऑब्जेक्ट लौटाता है

यह पथ हल्का है लेकिन पूर्ण ट्रांसपोर्ट कार्यान्वयन से कम मजबूत है।

पुनर्प्रयास/पुनर्कनेक्ट जिम्मेदारियां

Section titled “पुनर्प्रयास/पुनर्कनेक्ट जिम्मेदारियां”

ट्रांसपोर्ट-स्तरीय

Section titled “ट्रांसपोर्ट-स्तरीय”

वर्तमान ट्रांसपोर्ट कार्यान्वयन निम्नलिखित नहीं करते:

  • विफल अनुरोधों का पुनर्प्रयास
  • stdio प्रक्रिया बाहर निकलने के बाद पुनर्कनेक्ट
  • SSE लिसनर को पुनर्कनेक्ट
  • डिस्कनेक्ट के बाद इन-फ्लाइट अनुरोध पुनः भेजना

वे तेजी से विफल होते हैं और त्रुटियां प्रसारित करते हैं।

मैनेजर/क्लाइंट-स्तरीय

Section titled “मैनेजर/क्लाइंट-स्तरीय”

MCPManager खोज/प्रारंभिक कनेक्शन ऑर्केस्ट्रेशन को संभालता है और केवल कनेक्ट प्रवाह (connectToServer/discoverAndConnect पथ) फिर से चलाकर पुनर्कनेक्ट कर सकता है। यह रनटाइम विफलता कॉलबैक पर पहले से जुड़े ट्रांसपोर्ट को ऑटो-हील नहीं करता।

MCPManager में धीमे सर्वरों के लिए स्टार्टअप फ़ॉलबैक व्यवहार है (कैश से स्थगित उपकरण), लेकिन यह उपकरण उपलब्धता फ़ॉलबैक है, ट्रांसपोर्ट पुनर्प्रयास नहीं।

विफलता परिदृश्य सारांश

Section titled “विफलता परिदृश्य सारांश”
  • विकृत stdio संदेश लाइन: छोड़ दी गई; स्ट्रीम जारी रहती है।
  • Stdio स्ट्रीम/प्रक्रिया समाप्त: ट्रांसपोर्ट बंद; pending अनुरोध Transport closed के रूप में reject।
  • HTTP गैर-2xx: अनुरोध/notify HTTP त्रुटि throw करता है।
  • अमान्य JSON प्रतिक्रिया: parse अपवाद प्रसारित।
  • SSE मेल खाते id के बिना समाप्त: अनुरोध No response received for request ID ... के साथ विफल।
  • टाइमआउट: ट्रांसपोर्ट-विशिष्ट टाइमआउट त्रुटि।
  • कॉलर abort: कॉलर सिग्नल से AbortError/कारण प्रसारित।

व्यावहारिक सीमा नियम

Section titled “व्यावहारिक सीमा नियम”

यदि चिंता संदेश आकार, id सहसंबंध, या MCP विधि क्रम से संबंधित है, तो यह प्रोटोकॉल/क्लाइंट लॉजिक में आती है।

यदि चिंता फ्रेमिंग (JSONL बनाम HTTP/SSE), स्ट्रीम पार्सिंग, fetch/spawn जीवनचक्र, टाइमआउट क्लॉक, या कनेक्शन टियरडाउन से संबंधित है, तो यह ट्रांसपोर्ट कार्यान्वयन में आती है।