क्या MCP stdio backpressure आपके agent को freeze कर सकती है?
MCP stdio backpressure बड़े tool results पर agent को block कर सकती है। Pipe stalls reproduce करें, results सीमित करें, सुरक्षित रूप से drain करें और cancellation recovery test करें।

बड़ा MCP tool result agent process को freeze कर सकता है, भले ही आपके protocol implementation की हर line तकनीकी रूप से सही हो। समस्या तब आती है जब stdio को असीमित गति वाला message bus समझ लिया जाता है। यह दो processes के बीच चलने वाली सीमित byte stream है। कोई भी पक्ष पढ़ना बंद कर दे तो दोनों दिशाओं में रुकावट आ सकती है।
Agent tools के लिए यह आम command-line programs की तुलना में ज़्यादा महत्वपूर्ण है। कोई tool बहुत बड़ा search result, encoded file, पूरा API payload या verbose command transcript बना सकता है। इसके बाद agent उसे tokenize कर सकता है, summarize कर सकता है, approval का इंतज़ार कर सकता है या तय कर सकता है कि उसके पास पर्याप्त context है। इस दौरान host server के stdout को पढ़ना बंद कर दे तो server response के बीच में block हो सकता है। Block होने के बाद वह stdin से cancellation notification या बाद की request नहीं पढ़ पाएगा।
इसका समाधान कोई एक setting नहीं है। आपको ऐसा response contract चाहिए जो results को छोटा रखे, ऐसा transport loop चाहिए जो agent के काम से स्वतंत्र रूप से stdout पढ़ता रहे और ऐसी cancellation path चाहिए जो उस काम तक पहुँचे जो result बना रहा है। जानबूझकर कठिन payloads के साथ इन तीनों का परीक्षण करें।
Blocked pipe agent bug जैसी दिख सकती है
Blocked stdio pipe के लक्षण teams को अक्सर गलत दिशा में ले जाते हैं। Tool call के बाद agent frozen दिखाई देता है। Server process अभी भी चल रहा होता है। CPU use कम हो सकता है। Timeout हो जाता है, लेकिन retry भी अटक जाती है। कोई model runtime, MCP SDK या tool implementation में lock को दोष देता है।
अक्सर tool अपना काम पहले ही पूरा कर चुका होता है। वह write() में अटका होता है, क्योंकि वह ऐसा response भेजने की कोशिश कर रहा है जिसे host अब पढ़ नहीं रहा। Pipe की capacity सीमित होती है और platform के अनुसार बदलती है। Node के child process documentation में वही बात साफ़ कही गई है जिसे shell programmers दशकों से जानते हैं: subprocess pipe में उसकी capacity से अधिक लिखे और parent उसे capture न करे तो subprocess तब तक block रहता है, जब तक pipe में और bytes स्वीकार करने की जगह न हो।
इस incident में दो अलग queues होती हैं और उन्हें मिलाने से गलत fixes आते हैं।
- Operating system pipe MCP server और host के बीच raw stdout bytes रखती है।
- Host की application queue parsed JSON-RPC messages रखती है, जो agent code, UI code, logging या context assembly का इंतज़ार कर रहे होते हैं।
Application queue बढ़ाने से कुछ नहीं होगा, अगर कोई pipe पढ़ ही नहीं रहा। Pipe या stream buffer बढ़ाने से block कुछ देर टल सकता है, लेकिन server को ऐसा response बनाने की और जगह मिलती है जो agent को कभी मिलना ही नहीं चाहिए था। Result budgeting तय करता है कि conversation में क्या जाना चाहिए। Backpressure handling तय करती है कि एक पक्ष धीमा होने पर क्या होगा। दोनों अलग समस्याएँ हल करते हैं।
Official MCP debugging guidance आपको एक आसान diagnostic boundary भी देती है: local stdio servers को logs stdout से दूर रखने चाहिए। Diagnostics stderr पर भेजें। अगर stdout में banner, stack trace या ऐसी progress line है जो protocol data नहीं है, तो बड़े result की समस्या तक पहुँचने से पहले ही framing टूट चुकी है।
काम जारी रहते हुए stdout पढ़ने योग्य रहना चाहिए
सबसे महत्वपूर्ण नियम host के हाथ में है: server process के पूरे जीवनकाल में stdout reader को जोड़कर लगातार चलाते रहें। उसे ऐसे promise से न बाँधें जो agent के tool result पर विचार पूरा करने का इंतज़ार करता हो। Approval dialog के दौरान उसे pause न करें। अगली bytes स्वीकार करने से पहले renderer, database write या model request का इंतज़ार न करें।
Transport loop की जिम्मेदारियाँ सीमित रखें:
- Operating system bytes उपलब्ध कराए, उसी समय stdout से उन्हें पढ़ें।
- उन bytes को protocol framer को दें।
- Malformed या oversized frames को transport faults की तरह reject करें।
- पूरे messages को reader से अलग bounded dispatcher को दें।
- Dispatcher और काम स्वीकार न कर सके तो bytes पढ़ते रहें या child को जानबूझकर terminate करें।
यहाँ महत्वपूर्ण शब्द «अलग» है। जो reader message handling को inline चलाता है, वह अंततः पढ़ना बंद करने वाला reader बन जाता है। Message बहुत बड़ा हो तो JSON parsing खुद भी नुकसान पहुँचा सकती है, लेकिन आम गलती इससे पहले होती है: reader ऐसे callback पर इंतज़ार करता है जो असंबंधित काम कर रहा है।
Host को हर server session के लिए कम-से-कम ये values दर्ज करनी चाहिए: stdout पर प्राप्त bytes, सबसे बड़ा पूरा frame, parse failures, dispatch capacity के इंतज़ार में लगा समय, भेजी गई cancellation requests और process exits। ये आँकड़े बहस जल्दी खत्म कर देते हैं। अगर result के बीच में stdout bytes बढ़ना बंद हो जाए और server चलता रहे, तो server की write side पर शक करें। अगर bytes आती रहें लेकिन complete-message dispatch रुक जाए, तो host queue या उसके consumer को देखें।
stdout flow control को इस बात पर निर्भर न करें कि tool response model के लिए उपयोगी है या नहीं। सुरक्षित रूप से discard, report या route करने से पहले reader को पूरा protocol message प्राप्त करना होगा। ऐसा host जो frame के बीच में तय कर ले कि message बहुत बड़ा है और फिर पढ़ना बंद कर दे, उसने खुद deadlock बनाया है।
Result limit के लिए दो boundaries चाहिए
Wire limit और content limit दोनों तय करें। केवल character count process की सुरक्षा नहीं करता, क्योंकि JSON escaping, base64 encoding और आसपास का response structure stdout पर byte count बदल देते हैं।
Wire limit एक complete serialized JSON-RPC message का अधिकतम byte size है। Arbitrary JSON parse करने से पहले framer में इसे लागू करें। इससे host की memory और parser time सुरक्षित रहते हैं। Content limit वह अधिकतम उपयोगी मात्रा है जो tool content या structuredContent में लौटाता है। Result serialize करने से पहले tool handler में इसे लागू करें। इससे agent context सुरक्षित रहता है और response अर्थपूर्ण बना रहता है।
इनमें से कोई भी limit केवल tool description में नहीं होनी चाहिए। Model कभी-कभी unbounded search, recursive listing या पूरा document माँग सकता है। Server को ऐसी request का अनुमानित और स्थिर तरीके से सामना करना चाहिए।
Practical tool response बताए कि क्या छोड़ा गया और agent आगे कैसे बढ़ सकता है। यह string को चुपचाप काट देने से बेहतर है, क्योंकि silent truncation complete evidence जैसी लगती है।
{
"jsonrpc": "2.0",
"id": 41,
"result": {
"content": [
{
"type": "text",
"text": "Returned 50 of 4,382 matching records. Results are sorted by updated time. Use cursor \"eyJvZmZzZXQiOjUwfQ\" to continue, or add a narrower path or query."
}
],
"structuredContent": {
"items": [
{"path": "src/auth.ts", "line": 18, "summary": "reads token from environment"}
],
"nextCursor": "eyJvZmZzZXQiOjUwfQ",
"truncated": true,
"totalEstimate": 4382
}
}
}
Text model को सरल explanation देता है। Structured content client को stable continuation token और machine-readable truncation signal देता है। अगर सभी records गिनना महँगा या असंभव है, तो invented total न भेजें। truncated: true कहें और count हटा दें। ईमानदार incomplete result की तुलना में झूठी precision ज़्यादा समय बर्बाद करती है।
«बस file path लौटाएँ» वाली लोकप्रिय सलाह से बचें। यह तभी काम करती है जब host और server एक ही filesystem share करते हों, path authorized हो, agent उसे पढ़ सकता हो और artifact मौजूद रहे। Remote या sandboxed setup में यह अधूरा वादा है। Reference उपयोगी हो सकता है, लेकिन उसके साथ अपनी सीमाओं वाला read या export operation भी होना चाहिए।
Raw exhaust के बजाय decisions लौटाएँ
अधिकांश oversized responses उन tools से आते हैं जिनका output model command line से copy किया गया है। grep -R, git diff, cloud list API और database query terminal पर बैठे इंसान के लिए उपयोगी होते हैं। JSON में wrap कर देने भर से वे अच्छे agent interfaces नहीं बन जाते।
Agent को आम तौर पर अपना अगला action चुनने के लिए पर्याप्त evidence चाहिए। उसे सीमित matches, relevant fields और request को और narrow करने का तरीका दें। पूरा artifact explicit export या retrieval path के लिए रखें, जहाँ caller paging या constrained range चुन सके।
Repository search के लिए file paths, line ranges, छोटे excerpts और इस्तेमाल की गई query लौटाएँ। Monorepo की हर matching line न लौटाएँ। HTTP client के लिए status, चुने हुए headers, सीमित body preview और response handle लौटाएँ, अगर आपका product उसे सुरक्षित रूप से रख सकता है। मनमाने download को content में base64 न करें। SSH के लिए stdout और stderr का capped tail तथा exit status लौटाएँ। बहुत बड़ा generated file छापने वाली command ने आपको बता दिया है कि उसने बहुत बड़ा generated file बनाया है। Agent को तत्काल context में शायद ही हर byte चाहिए।
Expansion के source के पास limits लगाएँ। Remote API call करने वाला server pagination और field selectors उसी remote API को दे। Process चलाने वाला server subprocess capture को सीमित करे और stdout तथा stderr दोनों को पढ़ता रहे। Files search करने वाला server result budget पूरा होते ही रुक जाए, हर match इकट्ठा करके अंतिम string को काटे नहीं।
यह अंतर महत्वपूर्ण है, क्योंकि collection के बाद truncation MCP wire की सुरक्षा करती है, लेकिन काम करने वाली machine की नहीं। Recursive command response layer output हटाने से पहले भी memory, disk और CPU खपा सकती है।
Sallyport यहाँ उपयोगी है, क्योंकि actions उसके local gateway से चलते हैं और HTTP तथा SSH credentials agent से बाहर रहते हैं। यह boundary unbounded API body या shell transcript को लौटाने के लिए सुरक्षित नहीं बनाती। इसलिए tool authors को action boundary पर अब भी स्पष्ट output budgets चाहिए।
Stall को ठीक मानने से पहले उसे reproduce करें
इस failure का परीक्षण केवल tool call करके और यह देखकर नहीं किया जा सकता कि बड़ा result आखिर में दिखाई देता है या नहीं। ऐसा harness बनाएँ जो जानबूझकर stdout पढ़ना रोक दे, फिर साबित करें कि server blocked state में पहुँचता है। उसके बाद साबित करें कि normal host कभी उस स्थिति में नहीं जाता।
यह छोटा Node fixture ऐसा valid JSON-RPC response लिखता है जिसका payload इतना बड़ा है कि parent stdout को अनदेखा करे तो सामान्य pipe capacity से अधिक हो जाए। यह stdin से एक request line लेता है और response को chunks में लिखता है। drain का इंतज़ार इसका प्रमाण है: इससे पता चलता है कि runtime ने server के stdout writer पर backpressure लागू कर दी है।
// oversized-server.mjs
import readline from "node:readline";
import { once } from "node:events";
const rl = readline.createInterface({ input: process.stdin });
for await (const line of rl) {
const request = JSON.parse(line);
const text = "x".repeat(8 * 1024 * 1024);
const response = JSON.stringify({
jsonrpc: "2.0",
id: request.id,
result: { content: [{ type: "text", text }] }
}) + "\n";
for (let start = 0; start < response.length; start += 16 * 1024) {
const chunk = response.slice(start, start + 16 * 1024);
if (!process.stdout.write(chunk)) {
process.stderr.write("stdout backpressure observed\n");
await once(process.stdout, "drain");
}
}
}
अब इसे stdout को pipe करके spawn करें और जानबूझकर child.stdout को unread छोड़ दें। stderr पढ़ते रहें, ताकि backpressure marker दिखाई दे। एक request भेजें और थोड़ी देर इंतज़ार करें। Child चलता रहना चाहिए और writing पूरी नहीं करनी चाहिए। यह अपेक्षित behavior है, Node defect नहीं।
// blocked-parent.mjs
import { spawn } from "node:child_process";
const child = spawn(process.execPath, ["oversized-server.mjs"], {
stdio: ["pipe", "pipe", "pipe"]
});
child.stderr.setEncoding("utf8");
child.stderr.on("data", chunk => process.stderr.write(chunk));
child.stdin.write(JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "tools/call",
params: { name: "large", arguments: {} }
}) + "\n");
setTimeout(() => {
console.error("child still running:", child.exitCode === null);
child.kill("SIGTERM");
}, 1000);
इस parent pattern को production में copy न करें। इसका उद्देश्य failure को स्पष्ट बनाना है। Absent stdout consumer की जगह अपना वास्तविक framer लगाएँ और यही fixture चलाएँ। Child को response पूरा करना चाहिए या client को तय limit के तहत उसे reject करना चाहिए। Parent द्वारा stdout को अनदेखा करने की वजह से उसे wedged नहीं रहना चाहिए।
ऐसे payloads के साथ भी test चलाएँ जिनमें quotes, multibyte characters और लंबे unbroken strings हों। ये ऐसे framers को पकड़ते हैं जो UTF-8 bytes के बजाय JavaScript characters गिनते हैं या मानते हैं कि हर read chunk message boundary पर खत्म होगा।
Giant frame को blockage फिर पैदा किए बिना reject करें
Frame-size check में एक trap है: oversized frame को consume करना बंद करने वाला client भी server को उतनी ही आसानी से block कर सकता है जितना वह client जो reader जोड़ता ही नहीं। Client को recovery rule चाहिए।
अगर आपके framing protocol में स्पष्ट end marker है, तो offending frame को discard करते हुए marker तक पढ़ते रहें। फिर protocol violation report करें और तय करें कि session जारी रह सकता है या नहीं। अगर protocol encoding limit पार होने के बाद framing सुरक्षित रूप से वापस पाने नहीं देती, तो server process terminate करें, stdin बंद करें और नया session शुरू करें। यह कठोर लग सकता है, लेकिन corrupted JSON message कहाँ खत्म होता है, इसका अनुमान लगाना इससे भी खराब है।
MCP stdio local byte stream पर JSON-RPC messages का उपयोग करता है। Implementation को framing को transport code की तरह लेना चाहिए, न कि unbounded text इकट्ठा करने के बाद सुविधा के लिए split("\n") call की तरह। Candidate message जमा करते समय byte counter रखें। हर incoming chunk पर या तो complete frame boundaries खोजकर पूरे frames dispatch करें, या candidate maximum से बड़ा होते ही failure दें।
केवल यह जानने के लिए कि message बहुत बड़ा है, उसे parse न करें। JSON.parse को पूरी in-memory string चाहिए और यह input size से अधिक allocation कर सकता है। Wire limit का उद्देश्य ही यह काम रोकना है।
अगर दोनों ends आपके नियंत्रण में हैं और newline-delimited JSON इस्तेमाल करते हैं, तो हर line में एक JSON object अनिवार्य करें, सामान्य JSON encoding के ज़रिए strings के भीतर literal newlines reject करें और हर complete serialized object के बाद ठीक एक delimiter लिखें। Server को stdout पर human diagnostics कभी नहीं लिखने चाहिए। MCP की debugging documentation local servers को logs stderr पर भेजने को कहती है, क्योंकि stdout protocol के लिए है।
Reader को application handling का इंतज़ार कर रहे complete messages की संख्या पर भी limit लगानी चाहिए। Queue भर जाए तो stdout को हमेशा के लिए pause न करें। जहाँ support हो वहाँ नई requests reject करें, काम cancel करें या session समाप्त करें। सही overload action host पर निर्भर करता है, लेकिन indefinite unread stdout कभी सुरक्षित default नहीं है।
Cancellation तभी काम करती है जब producer तक पहुँचे
Agent UI में timeout cancellation नहीं है। यह केवल request के बारे में UI की राय बदलता है। Server अब भी database query कर सकता है, response download कर सकता है, process चला सकता है और stdout पर megabytes लिख सकता है।
MCP उसी direction में पहले भेजी गई request के लिए notifications/cancelled परिभाषित करता है। Notification में original request ID और optional reason होता है। MCP schema के अनुसार receiver को associated processing रोकनी चाहिए, resources मुक्त करने चाहिए और result को unused मानना चाहिए। यह भी चेतावनी दी गई है कि cancellation completion के साथ race कर सकती है। इसलिए client को late response स्वीकारना चाहिए और server को ऐसी cancellation भी संभालनी चाहिए जो request पूरी होने के बाद पहुँचे।
tools/call के लिए client उसी stdio session से ऐसी notification भेज सकता है:
{
"jsonrpc": "2.0",
"method": "notifications/cancelled",
"params": {
"requestId": 41,
"reason": "result exceeded the client budget"
}
}
Server को request ID से active work तक map चाहिए। हर entry में abort controller या language equivalent, completion state और उसके अंतर्गत आने वाला child process, HTTP request या cursor होना चाहिए। Cancellation notification आने पर work abort करें, result content बनाना बंद करें, map entry साफ़ करें और response शुरू न हुआ हो तो normal response भेजने से बचें।
यहीं teams एक subtle गलती करती हैं। वे tool handler में abort signal जोड़ देती हैं, लेकिन handler ऐसे child process का इंतज़ार करता है जिसका stdout capture उस signal को अनदेखा करता है। या वे HTTP fetch cancel कर देती हैं, लेकिन giant in-memory array को serialize करने वाला transform चलता रहता है। Cancellation तभी वास्तविक है जब वह हर producer और हर waiting operation तक पहुँचे।
Server द्वारा response लिखना शुरू करने के बाद की स्थिति को अलग state मानें। Bytes pipe में जा चुकी हों तो cancellation बाद में पहुँच सकती है। उन्हें वापस नहीं लिया जा सकता। Host को session health बनाए रखने के लिए पर्याप्त bytes पढ़ते रहना चाहिए और cancelled ID से जुड़े late response को ignore करना चाहिए। Cancellation दिखते ही server को अतिरिक्त काम रोक देना चाहिए, लेकिन वह यह वादा नहीं कर सकता कि कोई late bytes मौजूद नहीं होंगी।
Cancellation test में दूसरी request भी होनी चाहिए
अच्छा cancellation test केवल timer चलने का प्रमाण नहीं देता, recovery भी साबित करता है। ऐसा tool शुरू करें जो धीरे-धीरे output बनाए, ताकि उसके active रहने के दौरान client उसे cancel कर सके। Cancellation भेजें। फिर उसी MCP session पर एक छोटी, असंबंधित request भेजें। दूसरी request जल्दी पूरी होनी चाहिए।
यह test sequence महत्वपूर्ण failures पकड़ता है:
- ऐसा
tools/callशुरू करें जिसका handler chunks में बड़ा response भेजता हो या जानबूझकर धीमे producer को चलाता हो। - Harness को पर्याप्त stdout bytes दिखाई देने तक इंतज़ार करें, ताकि पता चले कि response शुरू हो चुका है।
- उस request ID के लिए
notifications/cancelledभेजें। - जाँचें कि producer आपकी तय deadline के भीतर exit करता है या अपना abort path report करता है।
- नई ID के साथ छोटी request भेजें, जैसे health tool या bounded echo tool।
अंतिम request ही असली test है। इससे पता चलता है कि server अब भी लिखते समय blocked है या नहीं, stdin reader को पर्याप्त समय मिल रहा है या नहीं, cancelled task ने global lock पकड़ा है या नहीं, और cancel करने के बाद host ने stdout पढ़ना बंद कर दिया है या नहीं।
Cancellation को काम शुरू होने से पहले, remote I/O के बीच में, subprocess चलने के दौरान और final response शुरू होने के बाद भी test करें। ये अलग-अलग states हैं। जो implementation एक स्थिति को अच्छी तरह संभालती है, वह दूसरी में fail हो सकती है।
यह assert न करें कि cancellation हमेशा response रोक देगी। MCP specification races की अनुमति देती है। यह assert करें कि cancellation के बाद response आए तो host सही रहे और cancellation समय पर पहुँचे तो server work रुक जाए।
Process output के लिए अलग drain path चाहिए
MCP servers अक्सर command-line tools चलाते हैं। इससे server के भीतर pipes की दूसरी जोड़ी जुड़ जाती है: MCP work करते समय server को child process का stdout और stderr पढ़ना होता है। अगर वह child stream को limit तक पढ़कर रुक जाए, तो child exit से पहले block हो सकता है। तब outer MCP server ऐसा दिख सकता है जैसे वह cancellation अनदेखी कर रहा हो, जबकि वह ऐसे child का इंतज़ार कर रहा है जो आगे बढ़ ही नहीं सकता।
Bounded preview capture करें, लेकिन preview limit के बाद भी पढ़ते रहें। बाकी bytes discard करें और output को truncated mark करें। अगर command अपनी result limit support करती है, तो command शुरू करने से पहले वह limit दें। उदाहरण के लिए search utility से maximum matches माँगें, database से limited page माँगें या log command को tail तक सीमित करें। Cap के बाद draining safety net है, primary result strategy नहीं।
stderr को stdout से अलग रखें। Tool stderr पर उपयोगी diagnostics लिख सकता है और फिर भी normal exit status लौटा सकता है। दोनों streams पर अलग-अलग cap और drain लागू करें। Arbitrary process output को MCP server stdout में कभी merge न करें। Outer stdout का केवल एक काम है: serialized MCP messages।
यही नियम SSH commands पर भी लागू होता है। Remote command तब तक लिख सकता है जब तक उसका channel block न हो जाए। Bounded data capture करें, completion या cancellation तक remote streams पढ़ते रहें और लौटाए गए summary में साफ़-साफ़ बताएं कि क्या discard किया गया। पूरा transcript casual tool result में नहीं, purpose-built artifact flow में होना चाहिए।
Failure को release gate में शामिल करें
Result limits और cancellation को गलती से हटाना आसान है। Refactor streaming reader को readFile से बदल सकता है, paginated API call को unbounded बना सकता है या parsing को UI callback में ले जा सकता है। Oversized-result fixture को test suite में रखें।
आपके release gate में wire cap से ठीक नीचे का valid response, उससे ठीक ऊपर का response, बहुत बड़ा single field, कई छोटे content blocks, malformed JSON, noisy stderr, accidental stdout log और output के दौरान cancellation शामिल होने चाहिए। इन्हें केवल in-memory transport पर नहीं, वास्तविक process spawn path पर चलाएँ। In-memory tests pipe backpressure नहीं दिखा सकते।
Expected behavior को सरल भाषा में दर्ज करें: client stdout लगातार पढ़ता है; configured frame limit से ऊपर parse नहीं करता; bounded-result failure report करता है; cancellation active work तक पहुँचती है; और recovery के बाद दूसरी request आगे बढ़ सकती है। Engineers implementation details बदल सकते हैं, लेकिन इन guarantees को कमजोर नहीं कर सकते।
अगर केवल एक बदलाव करना हो, तो यही करें: stdout reader को agent processing से अलग करें और फिर ऐसे server के साथ test करें जो किसी भी sensible tool result से कहीं ज़्यादा लिखता हो। यह test अस्पष्ट «agent freeze हो गया» report को reproducible और measurable failure में बदल देता है, जिसे अगली release से बाहर रखा जा सकता है।
सामान्य प्रश्न
बड़ा tool result लौटाने के बाद MCP server क्यों freeze हो जाता है?
ऐसा तब होता है जब server host के stdout पढ़ने की गति से तेज़ लिखता है, या host result को parse, buffer या आगे भेजते समय रुक जाता है। तब server pipe में जगह मिलने का इंतज़ार करता है और stdin पढ़ना भी बंद कर सकता है। बाद की request, cancellation भी, उसी blockage के पीछे अटक सकती है।
MCP tool result का सुरक्षित अधिकतम आकार कितना होना चाहिए?
MCP में कोई एक सुरक्षित संख्या नहीं है, क्योंकि सही सीमा client, model context budget, result encoding और किए जा रहे काम पर निर्भर करती है। पूरे serialized JSON-RPC response के लिए byte limit और tool content के लिए उससे छोटी semantic limit तय करें। Truncation को साफ़-साफ़ दिखाएँ और बाकी data पाने के लिए caller को cursor, path, query या follow-up tool दें।
क्या stdout buffer बढ़ाने से MCP backpressure की समस्या ठीक हो जाएगी?
नहीं। In-memory buffer बढ़ाने से failure केवल देर से आता है और blocked output की जगह memory spike हो सकता है। Host को pipe लगातार पढ़ते रहना चाहिए और server को शुरुआत से ही बहुत बड़े response objects बनाने से बचना चाहिए।
stdio पर MCP tool cancellation कैसे काम करती है?
MCP cancellation notification का नाम notifications/cancelled है। इसमें मूल request ID और वैकल्पिक reason होता है। यह advisory है और completion के साथ race कर सकती है, इसलिए server को इसे वास्तविक abort signal से जोड़ना चाहिए। Client को उस response के लिए भी तैयार रहना चाहिए जो cancellation से पहले लिखा जा चुका हो।
क्या agent के व्यस्त रहने पर MCP host को stdout पढ़ते रहना चाहिए?
stdout को लगातार framing parser में पढ़ें, bytes आते समय maximum frame size लागू करें और पूरे messages को अलग bounded work queue में भेजें। Agent किसी पुराने tool result पर काम कर रहा हो, केवल इस वजह से stdout पढ़ना बंद न करें। Queue भरने पर transport को बिना पढ़े छोड़ने के बजाय overload के लिए तय किया गया action अपनाएँ।
क्या MCP server में debugging output stdout पर log कर सकते हैं?
Operational details को stdout के बजाय stderr पर log करें। stdout में केवल MCP protocol messages होने चाहिए। एक भी stray log line message framing बिगाड़ सकती है। Local stdio servers के लिए official MCP debugging documentation भी यही स्पष्ट करती है।
जब MCP response तय सीमा से बड़ा हो जाए तो client को क्या करना चाहिए?
Limit पार होते ही पढ़ना बंद न करें। Offending frame के अंत तक bytes पढ़कर discard करते रहें, या server process को बंद करके session restart करें। केवल limit पर रुक जाना उसी pipe blockage को फिर पैदा कर देता है जिसे आप रोकना चाहते थे।
सिर्फ timeout के बजाय MCP cancellation का परीक्षण कैसे करें?
तीन अलग बातें जाँचें: server cancellation पहचानता है, उसका child work रुकता है और cancelled request के बाद client काम करता रहता है। केवल log में cancellation notification दिख जाना पर्याप्त प्रमाण नहीं है। Oversized request cancel होने के बाद एक दूसरी छोटी request भी जल्दी पूरी होनी चाहिए।
बड़ी files या API responses लौटाने के लिए MCP tools को क्या करना चाहिए?
Pagination, filtering, summaries, stable references और explicit export tools इस्तेमाल करें। Directory tree, repository diff, query result या HTTP body लौटाने वाले tool को मौजूदा निर्णय के लिए ज़रूरी हिस्सा देना चाहिए और बाकी माँगने का तरीका भी। केवल serialize करना आसान है, इसलिए पूरा artifact भेजना खराब tool design है।
क्या action gateway इस्तेमाल करने से MCP stdio backpressure का जोखिम खत्म हो जाता है?
Sallyport अपने local app और sp mcp shim के ज़रिए HTTP और SSH actions संभालता है, इसलिए agent को underlying credentials नहीं मिलते। इससे secrets का उपयोग सुरक्षित होता है, लेकिन stdout का व्यवहार नहीं बदलता। Tools और clients को अब भी result limits और cancellation चाहिए, साथ ही ऐसे tests भी जो साबित करें कि oversized response session को अटका नहीं सकता।