8 मिनट पढ़ें

MCP stderr सीमाएं agent runs को चलते रखती हैं

MCP stderr की ऐसी सीमाएं तय करें जो शोर करने वाले helpers को memory खपाने, approvals में देरी करने, shutdown रोकने और अधूरे action records छोड़ने से रोकें।

MCP stderr सीमाएं agent runs को चलते रखती हैं

कोई शोर करने वाला helper एक भी JSON-RPC message तोड़े बिना agent run को रोक सकता है। वह stderr को बिना सीमा वाली queue में बदल देता है और फिर stack के किसी दूसरे हिस्से से उसकी कीमत चुकवाता है: pipe भर जाता है, reader megabytes संभालकर रखता है, shutdown हमेशा इंतजार करता रहता है, या approval card तब दिखाई देता है जब user का run पर भरोसा खत्म हो चुका होता है।

stderr को untrusted input मानें और उसके लिए budget तय करें। यह बात तब तक जरूरत से ज्यादा सावधानी जैसी लगती है, जब तक आप किसी सामान्य command को हर retry पर एक diagnostic लिखते नहीं देख लेते, जबकि जिस action के लिए वह command चलाया गया था वह पहले ही पूरा हो चुका है और parent process अब भी उस शोर को जमा करने में लगा है। समाधान logging बंद करना नहीं है। समाधान है उसे लगातार पढ़ते रहना, सीमित मात्रा ही रखना, हटाए गए data का हिसाब रखना और action state को text output से स्वतंत्र रखना।

Stderr backpressure का रास्ता है

जब parent किसी helper को pipe से जोड़ता है और उस pipe को पर्याप्त तेजी से पढ़ नहीं पाता, तो stderr helper को रोक सकता है। Operating systems pipes को सीमित buffer देते हैं। Child के उस buffer को भरते ही उसका अगला write reader के लिए इंतजार करने लगता है। अगर diagnostic लिखने के बाद ही child success path तक पहुंचता है, तो network request, SSH connection या स्थानीय काम सही होने के बावजूद action अटका हुआ दिखाई देता है।

दूसरी समस्या शांत होती है, लेकिन अक्सर ज्यादा महंगी पड़ती है। Parent stderr को समय पर पढ़कर हर byte को string, event buffer या MCP tool result में जोड़ सकता है। Pipe कभी नहीं भरता, फिर भी बहुत बोलने वाला child इतनी memory खा सकता है कि host धीमा हो जाए, memory pressure बढ़ जाए या बाद की calls fail होने लगें। केवल pipe की सुरक्षा करने वाली cap अधूरी है। केवल memory की सुरक्षा करने वाली cap भी अधूरी है।

Agents के साथ यह समस्या और बढ़ जाती है, क्योंकि वे कई helpers को एक साथ चलाते हैं। एक task कई helpers शुरू कर सकता है और पहले burst के पूरी तरह पढ़े जाने से पहले retry loop एक और burst पैदा कर सकता है। Interactive terminal में harmless दिखने वाली log rate तब resource problem बन जाती है, जब कई sessions उसे एक साथ capture करते हैं।

तीन अलग चीजों की सीमा तय करनी होती है:

  • Operating system pipe में इंतजार कर रहे bytes।
  • Bridge किसी call के लिए memory में संभालकर रखे bytes।
  • Bridge agent, user interface या journal projection को दिखाए bytes।

Line limit को byte limit न समझें। एक line में बड़ा response body, certificate chain या minified error object हो सकता है। यह भी न मानें कि UTF-8 हमेशा पूरे characters में आता है। Stream readers bytes को chunks में पाते हैं और multibyte character chunk boundary पर टूट सकता है। Limit को उस स्थिति में भी सही काम करना चाहिए।

एक व्यावहारिक reader पूरे stream के लिए byte counter रखता है और संभाले गए आखिरी हिस्से के लिए अलग ring buffer रखता है। कुल मात्रा cap पार करने के बाद भी वह पढ़ना जारी रखता है, ताकि child बाहर निकल सके। Retained buffer बढ़ना बंद कर देता है और truncation होने का record लिख दिया जाता है। पहली अतिरिक्त मात्रा पर child को तुरंत kill करना उस tool के लिए सही हो सकता है जिसका output खुद abusive है, लेकिन diagnostics के लिए यह सही default नहीं है। अक्सर आपको वास्तविक exit status और वे आखिरी lines चाहिए होती हैं जो समस्या समझाती हैं।

MCP stdout को सीमाओं से बाहर रखता है

MCP stdio server को stdout को protocol territory मानना चाहिए। Model Context Protocol specification के stdio transport guidance के अनुसार server को valid MCP messages के अलावा stdout पर कुछ भी नहीं लिखना चाहिए। इस नियम को केवल formatting hygiene मानना आसान है। व्यवहार में यह failure की एक ज्यादा खराब श्रेणी को रोकता है: helper की सहज progress line host को invalid JSON पढ़ने पर मजबूर कर सकती है और ऐसा session छोड़ सकती है जो बाकी सब तरह से सही था।

मानवीय diagnostics stderr पर रखें, लेकिन यह न मानें कि इससे वे harmless हो जाते हैं। Protocol के अर्थ में stderr out-of-band channel है। Process host फिर भी तय करता है कि वह stream inherit करेगा, pipe करेगा, capture करेगा, terminal पर लिखेगा या structured log में भेजेगा। हर विकल्प failure behavior बदल देता है।

स्थानीय developer के लिए inheritance ठीक रहता है, क्योंकि terminal output को consume करता है और developer उसे देख सकता है। Agent bridge के लिए यह खराब default है। इससे arbitrary text ऐसी जगह पहुंच सकता है जहां वह retained न हो, concurrent calls के output में मिल जाए या ऐसी details रखता हो जो agent को कभी नहीं मिलनी चाहिए। Diagnosis के लिए full capture बेहतर है, लेकिन तभी जब उसकी budget तय हो।

Protocol boundary को सरल रखें। MCP server को stdout पर valid JSON-RPC messages भेजने चाहिए, stderr पर अपने diagnostics की सीमा रखनी चाहिए और helpers को उनकी streams पर स्पष्ट नियंत्रण के साथ शुरू करना चाहिए। Helper को intended channel से structured results लौटाने चाहिए। उसे stderr पर JSON blob छापकर यह उम्मीद नहीं करनी चाहिए कि parent उसे बाद में पहचान लेगा।

यह अंतर एक बार-बार होने वाली गलती रोकता है: stderr को alternate response channel मानना। यह ऐसा channel नहीं है। इसकी framing भरोसेमंद नहीं होती, cancellation के समय output अधूरा रह सकता है और इसमें ऐसी libraries का output आ सकता है जिन्हें आपके action model के बारे में कुछ पता नहीं। अगर caller को retry count, remote error code या बदली हुई files की list चाहिए, तो उसे structured result में जोड़ें। stderr को उस evidence के लिए रखें जिसकी किसी व्यक्ति को failure diagnose करते समय जरूरत पड़ सकती है।

Output capture के लिए अलग memory budget चाहिए

Background task में stderr पढ़ने से capture सुरक्षित नहीं हो जाता। इससे bottleneck pipe से हटकर आपके heap में आ जाता है। मैंने hosts को दोनों streams concurrent तरीके से पढ़कर deadlock ठीक करते देखा है, फिर पता चला कि खराब helper action खत्म होने तक हर byte retain करवा सकता है। Process अब exit हो जाता है, लेकिन host को नुकसान पहुंचता है।

Retained diagnostics के लिए ring buffer इस्तेमाल करें। Capacity भरने के बाद ring buffer सबसे हाल के bytes रखता है, और आम तौर पर उपयोगी error वहीं मिलती है। अगर आपके environment में पहली line महत्वपूर्ण होती है, जैसे command invocation या library version, तो छोटा prefix भी रखें। दोनों को अनिश्चित समय तक न रखें।

नीचे दिया गया pseudocode उस behavior को दिखाता है जिसे लागू करना उपयोगी है। यह किसी खास language पर निर्भर नहीं है।

on_stderr_chunk(bytes):
  stderr_seen += length(bytes)
  if stderr_seen \u003c= capture_limit:
    append_tail(bytes)
  else:
    append_tail(bytes)       # ring buffer evicts older bytes
    stderr_truncated = true
  continue_reading()

इस comment पर ध्यान दें। capture_limit का अर्थ वह मात्रा होना चाहिए जिसे आप रखते हैं, वह बिंदु नहीं जहां पढ़ना बंद कर देते हैं। Strict implementation limit पार करने के बाद append_tail छोड़ सकती है और शुरुआती bytes रख सकती है। मुझे tail पसंद है, क्योंकि failure messages अक्सर progress output के कई pages के बाद आते हैं। जो विकल्प चुनें, उसे record में नाम दें, ताकि बाद में जांच करने वाला जान सके कि वह शुरुआत पढ़ रहा है या अंत।

Agent context में diagnostics ले जाने वाले object के चारों ओर दूसरी cap लगाएं। Retry करना है या नहीं, यह तय करने के लिए agent को multi-megabyte transcript की जरूरत नहीं होती। उसे concise error, exit status और अधिक से अधिक चुना हुआ tail चाहिए। अगर bridge raw helper output को यह सोचकर आगे भेजता है कि «model को शायद इसकी जरूरत पड़े», तो हर helper को बाकी task context पर कब्जा करने का रास्ता मिल जाता है।

सिर्फ text limit लागू करने के लिए बड़े stream को decode और re-encode न करें। Strings बनाने से पहले raw bytes गिनें। Retained slice को invalid sequences के लिए replacement strategy के साथ decode करें और उसे captured stderr के रूप में label करें। इससे memory waste और उस झूठे भरोसे दोनों से बचा जा सकता है जो helper की गलती से binary data भेजने पर पैदा होता है।

Action पूरा होने के बाद भी shutdown में process रुक सकता है

Process shutdown वह जगह है जहां log floods misleading incident reports में बदलते हैं। Action remote side पर सफल हो चुका हो सकता है, helper ने अपना अंतिम diagnostic लिख दिया हो सकता है, फिर भी parent result बनाने में fail कर सकता है, क्योंकि वह गलत event का गलत क्रम में इंतजार करता है।

एक आम sequence ऐसा दिखता है:

  1. Bridge helper शुरू करता है और stdout पढ़ना शुरू कर देता है, लेकिन burst के दौरान stderr reading पीछे रह जाती है।
  2. Helper अपना external action पूरा करता है, फिर इतना diagnostic लिखता है कि stderr pipe भर जाती है।
  3. Parent session cancel करता है या deadline तक पहुंचता है और termination signal भेजता है।
  4. Parent stream readers को बंद या drain करने से पहले child का इंतजार करता है।
  5. एक reader end of file का इंतजार करता है जबकि दूसरा task reader का इंतजार करता है, और session अपने अंतिम record तक कभी नहीं पहुंचता।

External effect पहले ही हो चुका हो सकता है। HTTP request स्वीकार की जा चुकी हो सकती है या SSH command ने remote file बदल दी हो सकती है। उस call को केवल «timed out» बताने से operator को सबसे खराब जवाब मिलता है: उसे पता नहीं होता कि retry करने पर बदलाव दोबारा होगा या नहीं।

हर helper के लिए एक owner रखें जो चार चीजों को साथ संभाले: child handle, stdout reader, stderr reader और cancellation। सामान्य completion पर process exit का इंतजार करें और final result बनाने से पहले readers को end of file तक drain करें। Cancellation पर termination का अनुरोध करें, दोनों streams drain करते रहें, सीमित grace period का इंतजार करें और platform अनुमति दे तो उसके बाद force termination करें। अंत में readers के पूरा होने का इंतजार करें और वास्तव में देखी गई exit state दर्ज करें।

Stream readers को केवल request handler के child न बनाएं। Client disconnect होने पर handler गायब हो सकता है। Helper और उसके readers की ownership इतनी देर तक बनी रहनी चाहिए कि cleanup पूरा हो और terminal state लिखी जा सके। वरना agent process exit कर सकता है, host readers के आखिरी references छोड़ सकता है और कोई child ऐसी pipes के साथ जीवित रह सकता है जिन्हें कोई पढ़ नहीं रहा।

Process groups को भी इसी सावधानी की जरूरत होती है। Shell wrapper ऐसे descendants शुरू कर सकता है जो stderr inherit करते हैं, और केवल wrapper को kill करने से कोई descendant pipe खुली रख सकता है। जहां संभव हो shell से बचें। अगर shell जरूरी हो, तो उसे contained process group में शुरू करें और स्पष्ट रूप से तय करें कि cancellation किन descendants तक पहुंचेगी। फिर उस स्थिति की जांच करें जिसमें wrapper exit हो जाता है, लेकिन grandchild stderr लिखता रहता है।

Approval timing को log volume से स्वतंत्र रखें

कार्रवाई की सीमा स्थानीय रखें
एक signed menu-bar app vault core को process में चलाता है, इसलिए अलग daemon संभालने की जरूरत नहीं होती।

Approval timing को helper diagnostics की गति के बजाय action state का पालन करना चाहिए। अगर interface preflight transcript बनने के बाद ही approval दिखाता है, तो noisy preflight user से निर्णय मांगने का समय बदल देता है। इससे approval random लगता है और लोग यह समझे बिना cards approve करने लगते हैं कि किसी card में ज्यादा समय क्यों लगा।

UI code लिखने से पहले transitions तय करें। कोई call received, validated, awaiting approval, authorized, dispatched, finished, cancelled या failed before dispatch हो सकती है। stderr call से जुड़ सकता है, लेकिन उसे यह तय नहीं करना चाहिए कि कौन सा transition होगा। Bridge को requested target और parameters validate करने चाहिए, call record बनाना चाहिए और approval की जरूरत हो तो approval मांगनी चाहिए, उस action को शुरू करने से पहले जिसके लिए approval जरूरी है।

एक उपयोगी exception है। कभी-कभी यह जानने के लिए helper चाहिए होता है कि कौन सा action होने वाला है, जैसे local configuration name को concrete endpoint में बदलना। ऐसी स्थिति में discovery को अपनी output budget वाली अलग non-action operation मानें। «Preflight» के अंदर action छिपाकर बाद में यह दावा न करें कि user ने उसे approve किया था।

Approval के लिए ऐसा wall-clock deadline रखें जो नए stderr आने पर reset न हो। Card visible रहने के दौरान bounded tail collect करते रहें, लेकिन हर line पर card redraw न करें। Approval से पहले आया retry warning या error summary उपयोगी context हो सकता है, लेकिन वह stable explanation के रूप में दिखना चाहिए, लगातार बदलते log view की तरह नहीं।

Tests में consent और liveness को अलग रखें। Flood test में valid call request से approval card दिखने तक का समय मापें, और stderr को उस समय से पहले और बाद में दोनों समय पैदा करें। Slow-reader test में यह verify करें कि bridge drain करते समय card usable रहता है। Cancellation test में यह verify करें कि card dismiss करने पर कोई helper process चलता न रह जाए और terminal record तैयार हो।

मानवीय असर सीधा है: approval card को किसी खास समय पर किसी खास action का वर्णन करना चाहिए। अगर log output उस समय में देरी कर सकता है, उसे बदल सकता है या उसके बाद भी चलता रह सकता है, तो interface user को control देने के बजाय process की उलझन दिखा रहा है।

Call records में diagnostics से पहले lifecycle facts चाहिए

Call record तब पूरा होता है जब वह action की state समझाता है, न कि तब जब उसमें helper की हर line मौजूद हो। Log output evidence है। Lifecycle events record हैं।

Dispatch से पहले attempt लिखें। इसमें stable call identifier, session identifier, requested action type, approved या denied decision और user को दिखाई गई target information शामिल करें। Dispatch शुरू होने पर वह fact जोड़ें। समाप्त होने पर observed result जोड़ें: success, remote failure, local failure, cancellation, forced termination या process boundary खोने से पैदा हुआ unknown outcome।

इसके बाद diagnostic metadata जोड़ें। कम से कम देखे गए कुल stderr bytes, रखे गए bytes, truncation हुई या नहीं, उपलब्ध होने पर helper का exit status और stream साफ तौर पर समाप्त हुई या नहीं, यह दर्ज करें। इससे छोटा retained tail ईमानदार रहता है। बाद का reader «command ने यह छापा» और «bridge ने command के छापे हुए output का आखिरी हिस्सा रखा» के बीच अंतर समझ सकता है।

Record shape इतनी छोटी हो सकती है:

{
  "call_id": "c_7f2a",
  "state": "cancelled_after_dispatch",
  "stderr_bytes_seen": 184320,
  "stderr_bytes_retained": 16384,
  "stderr_truncated": true,
  "exit_status": null,
  "stream_end": "reader_completed_after_cancel"
}

Parent को successful response body मिल गई हो, केवल इस आधार पर exit_status: 0 न लिखें। Response body और child exit दो अलग observations हैं। Dispatch के बाद cancellation हुई हो और remote side ने action किया हो सकता हो, तो state: failed न लिखें। Implementation के समय यह बारीकी जैसी लग सकती है, लेकिन रात के दो बजे सुरक्षित जांच और आंख मूंदकर किए गए retry के बीच यही अंतर बनती है।

NIST SP 800-92 Guide to Computer Security Log Management एक उपयोगी बात कहता है: log management में generation, transmission, storage, analysis और disposal शामिल हैं, केवल text collect करना नहीं। यही सोच agent actions पर लागू करें। अगर collection completion को रोक सकता है, तो logging path execution का हिस्सा बन चुका है। उसे भी किसी दूसरी execution path की तरह limits, state और failure handling चाहिए।

Sallyport अपने Sessions और Activity journals को एक write-blind encrypted, hash-chained audit log से project करता है। इसलिए caller agent run और individual action records में अंतर कर सकता है, helper transcript को history मानने पर निर्भर नहीं रहना पड़ता।

Noise की सीमा तीन जगह तय करें

stderr से आगे का रिकॉर्ड रखें
इसका write-blind एन्क्रिप्टेड ऑडिट लॉग कार्रवाई के साक्ष्य को सुरक्षित रखता है, बिना helper stderr को इतिहास बनाए।

Stack के ऊपर केवल एक cap लगाने से accidents के लिए बहुत जगह बचती है। Helper, bridge और diagnostic destination, तीनों पर limits तय करें। हर limit अलग boundary की सुरक्षा करती है।

पहले helpers को default रूप से कम chatty बनाएं। Routine progress को explicit debug setting के पीछे रखें, retry sequence के लिए एक summary emit करें और request या response bodies को default रूप से print न करें। Helper को कभी credentials, authorization headers या private key material stderr पर नहीं लिखना चाहिए। Capture के बाद redaction उपयोगी backstop है, लेकिन terminal, crash report या unbounded buffer में रह चुके secret को वह वापस नहीं ले सकता।

दूसरे, bridge लगातार drain करे और bounded prefix या tail रखे। उसे हर stream के लिए maximum duration और maximum retained byte count लागू करना चाहिए। इसके साथ process-wide diagnostic budget भी होनी चाहिए। इस आखिरी control के बिना पचास calls अपनी-अपनी per-call allowance के भीतर रहते हुए भी मिलकर memory spike पैदा कर सकती हैं।

तीसरे, destination को सीमित करें। अगर आप call diagnostics को user interface, agent response या file में export करते हैं, तो वहां भी दूसरी cap लगाएं। Journal structured lifecycle fields और discarded output का digest रख सकता है, बिना हर retry की दोहराई गई stack trace store किए।

Configuration shape स्पष्ट रखें। नाम महत्वपूर्ण नहीं हैं। उनका अलग-अलग होना महत्वपूर्ण है।

helper_output:
  stderr_retained_per_call_bytes: 16384
  stderr_retained_process_bytes: 262144
  stderr_agent_excerpt_bytes: 4096
  shutdown_grace_seconds: 5
  retain: tail

यह configuration उस आम failure को रोकती है जिसमें team agent response limit तय करके मान लेती है कि host सुरक्षित है। Response trim करने से पहले host पूरा data पढ़ और store कर चुका होता है। Retained per-call cap एक action की सुरक्षा करती है। Process cap concurrent actions की सुरक्षा करती है। Agent excerpt cap उस context की सुरक्षा करती है जिसे model को अपने बाकी काम के साथ साझा करना होता है।

quiet नाम वाला एक global switch न बनाएं। इससे production failures diagnose करना कठिन हो जाता है और evidence की जरूरत पड़ने पर developers unlimited logs फिर से चालू करने लगते हैं। Normal output concise रखें, थोड़े समय के लिए controlled debug mode दें और call record में यह fact रखें कि debug mode active था।

stderr को /dev/null पर redirect करने की लोकप्रिय सलाह से बचें। लोग इसे इसलिए सुझाते हैं क्योंकि इससे तत्काल stall हट जाता है और agent responses साफ रहते हैं। लेकिन इससे पहला उपयोगी clue भी मिट जाता है, जैसे SSH helper authenticate न कर पाए, certificate check fail हो या remote command unexpected error लौटाए। Stream को drain करें, सीमित रखें और label करें।

Truncation दिखाई देनी चाहिए, नाटकीय नहीं

Truncation तब सुरक्षित है जब वह स्पष्ट हो और system पढ़ना जारी रखे। यह तब unsafe है जब बाद का reader यह न बता सके कि error message पूरा है या नहीं, bridge पढ़ना बंद करके child को block कर दे या हटाए गए output में उस action का एकमात्र record मौजूद हो जिसका कोई दूसरा record नहीं है।

Retained tail की शुरुआत bridge द्वारा बनाए गए marker से होनी चाहिए, helper द्वारा बनाए गए marker से नहीं। उदाहरण के लिए:

[stderr truncated: kept last 16384 of 184320 bytes]
connection retry 18 failed: remote side closed the channel

यह marker record का हिस्सा है, decoration नहीं। यह user को बताता है कि पहली दिखाई देने वाली line अचानक क्यों शुरू होती है और agent को partial stack trace को पूरी explanation मानने से रोकता है। अगर prefix और tail दोनों रखते हैं, तो दोनों byte counts बताएं। उन्हें कभी चुपचाप जोड़कर एक साथ न दिखाएं।

Caps को किसी दूसरे project की संख्या देखकर copy न करें। Concurrency से पीछे की ओर गणना करें। पूछें कि एक agent run में कितने actions एक साथ चल सकते हैं, host कितने runs स्वीकार करता है, खराब एक मिनट के दौरान diagnostics कितनी memory ले सकते हैं और कोई व्यक्ति वास्तव में कितने text को उपयोगी ढंग से देख सकता है। आखिरी जवाब आम तौर पर लोगों की अपेक्षा से काफी छोटा होता है।

Action result को excerpt से अलग रखें। भले stderr अपनी cap तक पहुंच गया हो, सफल HTTP action को अपना intentional structured result लौटाना चाहिए, जब तक helper overflow को खुद failure signal के रूप में इस्तेमाल न करता हो। इसके उलट, साफ stderr stream action की सफलता साबित नहीं करती। Diagnostics को कई observations में से केवल एक field मानें।

Flood tests सामान्य integration tests के साथ होने चाहिए

API keys को एजेंट से दूर रखें
Sallyport bearer, basic या custom-header क्रेडेंशियल केवल HTTP कॉल करते समय जोड़ता है।

बहुत ज्यादा stderr लिखने वाला helper कोई दुर्लभ security test नहीं है। यह बुनियादी reliability test है। Version change के बाद libraries verbose हो सकती हैं, remote clients retries के दौरान warnings दोहरा सकते हैं और malformed input error loop शुरू कर सकता है। अगर bridge tests में केवल शांत happy-path helpers देखता है, तो उसके पास pressure में process handling काम करने का कोई evidence नहीं है।

ऐसे fixture से शुरू करें जो stderr की तय मात्रा लिखे, चुने हुए status के साथ exit करे और कोई external work न करे। Unix-like system पर यह command local test harness के लिए जानबूझकर flood बनाती है:

yes helper-diagnostic 1\u003e\u00262

इसे short deadline के तहत चलाएं। Expected result केवल deadline का समाप्त होना नहीं है। Confirm करें कि bridge configured amount से अधिक retain न करे, truncation mark करे, child terminate करे, streams के बंद होने तक उन्हें drain करे और terminal lifecycle event लिखे।

फिर वे cases जोड़ें जो ordering errors सामने लाते हैं:

  • Helper approval का इंतजार करने से पहले stderr लिखता है।
  • Helper approval के दौरान लिखता है और approval के तुरंत बाद exit करता है।
  • Helper external रूप से सफल होता है, stderr flood करता है और cleanup के दौरान cancellation पाता है।
  • Wrapper exit हो जाता है, जबकि descendant stderr खुली रखता है।
  • Helper invalid byte sequences और retained cap से बड़ी एक line लिखता है।

हर case के लिए कुछ छोटे facts मापें: peak retained diagnostic bytes, approval तक का समय, cancellation से process exit तक का समय, final state और expected call record मौजूद है या नहीं। केवल ऐसा test पर्याप्त नहीं है जो error string में «truncated» खोजे। वह string तब भी दिखाई दे सकती है जब reader task blocked हो या final record storage तक पहुंचा ही न हो।

इन fixtures को concurrent calls के साथ भी चलाएं। Per-call cap अकेले सही दिख सकती है, फिर भी सभी calls एक साथ cap तक पहुंचें तो system fail कर सकता है। Client disconnect की भी जांच करें। Agent process का चले जाना संभव है, लेकिन host को action को किसी तय तरीके से पूरा या cancel करना ही होगा।

अंतिम जांच audit chain का offline verification और fixture के expected lifecycle से तुलना है। Verification बता सकता है कि stored entries बदली गई हैं या नहीं। Fixture comparison बताता है कि bridge ने शुरुआत में वे entries लिखी भी थीं या नहीं जो उसे लिखनी चाहिए थीं। दोनों जरूरी हैं।

Logs को उपयोगी रखें, लेकिन उन्हें action चलाने न दें

उपयोगी नियम सरल है: stdout में MCP protocol messages, structured results में action outcomes और stderr में bounded diagnostics होने चाहिए। जब इन channels के काम अलग होते हैं, तो approval timing, shutdown, memory accounting और audit records एक ही unstructured text के लिए आपस में नहीं लड़ते।

उस helper से शुरुआत करें जिसने पहले आपको परेशान किया है: जो बहुत शोर के साथ retry करता है, cancellation के बाद अटक जाता है या fail होने पर पूरा remote response print करता है। उसे bounded reader के पीछे रखें और flood fixture तब तक चलाएं, जब तक action record सही बना रहे। शांत logs अच्छे लगते हैं। Bounded logs operational control देते हैं।

सामान्य प्रश्न

क्या stderr आउटपुट सचमुच MCP एजेंट को रोक सकता है?

हां। अगर parent process stderr को बिना सीमा के capture करता है, तो कोई helper diagnostic output को जमा होती memory में बदल सकता है या pipe भर सकता है, जिससे helper रुक जाता है। MCP messages सही हो सकते हैं, फिर भी उन्हें चलाने वाला process अपने ही logs के कारण अटक सकता है।

MCP server को logs stdout पर लिखने चाहिए या stderr पर?

Logs को stdout पर न भेजें। stdio transport में stdout केवल protocol messages के लिए सुरक्षित है, इसलिए एक diagnostic line भी JSON-RPC stream को खराब कर सकती है। Diagnostics को stderr पर भेजें और host से उस stream को लगातार पढ़वाकर सीमित रखें।

एजेंट helper के लिए stderr की कौन सी सीमा तय करनी चाहिए?

शुरुआत के लिए प्रति-कॉल छोटी byte सीमा, उससे छोटा retained tail और एक सख्त process-wide सीमा रखें। सही संख्याएं concurrency और उपलब्ध memory पर निर्भर करती हैं, लेकिन सीमा स्पष्ट और दिखाई देने वाली होनी चाहिए, host runtime की अनजानी विशेषता नहीं।

क्या helper stderr को truncate करना सुरक्षित है?

Bounded tail रखें, देखे गए कुल bytes दर्ज करें और call को truncated के रूप में चिह्नित करें। पूरे audit record के लिए हर debug line की पूरी copy जरूरी नहीं है। जरूरी है कि क्या चला, क्या हुआ और कौन सा evidence हटाया गया, इसका ईमानदार रिकॉर्ड हो।

क्या बहुत ज्यादा logs approval prompt में देरी कर सकते हैं?

Approval को logs की मात्रा के बजाय action lifecycle के अनुसार चलना चाहिए। जब action मानवीय approval के लिए तैयार हो, उसी समय approval clock शुरू करें और card दिखने के दौरान stderr पढ़ते रहें।

क्या stdout और stderr को एक साथ पढ़ना जरूरी है?

दोनों streams को हमेशा concurrent तरीके से पढ़ें। केवल stdout पढ़ने पर stderr pipe भरने से process deadlock हो सकता है। इसी तरह, केवल stderr पढ़ने पर बड़ा response भेजने वाला helper उलटी समस्या पैदा कर सकता है।

Helper को kill करने पर audit log में क्या दर्ज होना चाहिए?

Dispatch से पहले attempted action दर्ज करें। फिर यह लिखें कि dispatch शुरू हुआ या नहीं, पूरा हुआ या नहीं और output truncate हुआ या नहीं। अगर helper client से ज्यादा समय तक चलता रहा या client पहले बंद हो गया, तो journal में यह साफ लिखा होना चाहिए, ताकि clean result का गलत संकेत न मिले।

क्या timeout log flooding से बचा सकता है?

नहीं। छोटा timeout बीता हुआ समय सीमित करता है, जबकि stderr cap जमा होने वाले data और pipe pressure को सीमित करता है। आपको दोनों की जरूरत है, साथ में ऐसा cancellation path भी चाहिए जो streams बंद करे और process exit का इंतजार करे।

शोर करने वाले MCP helpers की जांच कैसे करें?

ऐसा वास्तविक helper इस्तेमाल करें जो नियंत्रित मात्रा में stderr लिखे, फिर उसे production वाले bridge और approval path से चलाएं। Peak retained bytes, approval तक का समय, cancellation latency, exit status और हर lifecycle record की मौजूदगी मापें।

Action gateway को subprocess logs की सीमा क्यों तय करनी चाहिए?

एजेंट की ओर से actions चलाने वाले gateway को helper output को untrusted input मानना चाहिए। उसे उपयोगी tail और diagnostics सुरक्षित रखने चाहिए, साथ ही एजेंट या buggy dependency को memory खपाने या action को अनिश्चित समय तक खुला रखने से रोकना चाहिए।

Sallyport

Sallyport आपके AI एजेंट के लिए API कॉल और SSH कमांड चलाता है। कुंजियाँ आपके Mac पर एक लोकल वॉल्ट में रहती हैं; आप हर रन को स्वीकृत करते हैं और हर क्रिया एक सीलबंद जर्नल में दर्ज होती है।

© 2026 Sallyport · Apache-2.0 के तहत ओपन सोर्स · Oleg Sotnikov