इस पेज पर
8 जून 2026 को Anthropic ने Claude की डायरेक्टरी में मौजूद कनेक्टर के मालिकों को एक डैशबोर्ड दिया. यह सक्रिय यूज़र, टूल कॉल की कुल संख्या और डायरेक्टरी में रैंक दिखाता है. यह “एक नज़र में हेल्थ स्कोर, एरर रेट और लेटेंसी, हर टूल के हिसाब से एरर के ब्यौरे के साथ ताकि ठीक-ठीक पता चले कि क्या फ़ेल हो रहा है” दिखाता है.
इससे एक साल पहले, Weights & Biases के Alex Volkov ने यही समस्या दूसरे छोर से बताई थी. जैसे ही उनके एजेंट ने MCP के ज़रिए टूल कॉल करने शुरू किए, “वह सारी ऑब्ज़र्वेबिलिटी, जिसका मैं अपने कोड को शुरू से आख़िर तक चलाने की वजह से आदी हूं, थोड़ी अंधेरी हो गई है”. उनके साथ बोलने वाले Dylibso के Benjamin Eckel ने इसकी वजह दिखाई. रिमोट MCP सर्वर “ट्रेस में हमें एक अकेले सर्विस span की तरह दिखता है”, क्योंकि वह कॉल करने वाले के नियंत्रण से बाहर चलता है.
दोनों नज़रिए सर्वर के बाहर खड़े हैं. क्लाइंट एक अपारदर्शी span देखता है. डायरेक्टरी कुल आंकड़े देखती है. दोनों में से किसी ने नहीं देखा कि सर्वर से क्या मांगा गया, उसने क्या अस्वीकार किया और किस चीज़ को छुआ. यह सिर्फ़ सर्वर ने देखा, इसलिए सिर्फ़ सर्वर ही इसे दर्ज कर सकता है.
Tajo के MCP सर्वर यही दर्ज करते हैं, जैसा कि उन्हें चलाने वाले कोड से पढ़ा गया और डॉक्स में बताया गया है. MCP सर्वर क्या है प्रोटोकॉल को समझाता है. यह लेख पंक्ति को समझाता है.
हर कॉल के लिए एक पंक्ति
डैशबोर्ड हार्बर मास्टर का नज़रिया है: कौन से जहाज़ आए, कौन से गए, कौन से देर से पहुंचे. रिक्वेस्ट लॉग जहाज़ की अपनी लॉगबुक है, जो उसी समय जहाज़ पर लिखी जाती है.
Tajo के वर्कस्पेस सर्वर और हर कनेक्टर सर्वर पर हर tools/call एक पंक्ति पर ख़त्म होती है. पंक्ति जवाब तैयार होने के बाद लिखी जाती है, जवाब चाहे जो भी हो. जो कॉल इसलिए अस्वीकार हुई कि की को लिखने की अनुमति नहीं है, या इसलिए कि एंडपॉइंट सिर्फ़ पढ़ने के लिए है, उसे भी किसी दूसरी कॉल की तरह एक पंक्ति मिलती है. ऐसे टूल की कॉल को भी जो मौजूद ही नहीं है.
पंक्ति में यह होता है, और यह वह है जिसे रखने से वह इनकार करती है.
| फ़ील्ड | क्या रखा जाता है | क्या नहीं रखा जाता |
|---|---|---|
| कौन | कॉल करने वाली API की की आईडी. OAuth साइन इन से मिला टोकन भी एक की है. | की का सीक्रेट या उसका प्रीफ़िक्स. |
| कहां | वर्कस्पेस सर्वर या कोई कनेक्टर सर्वर, उसके कनेक्टर और प्रोफ़ाइल के साथ. | |
| टूल | नाम, जब सर्वर के पास उस नाम का टूल हो. | क्लाइंट का भेजा कोई भी दूसरा नाम: यह (unknown) के रूप में सहेजा जाता है. |
| असर | read, write, send या destructive: कॉल का जो सबसे भारी असर हो सकता था. | |
| नतीजा | ok, या snake_case में एक छोटा एरर कोड, जैसे unknown_tool. | एरर का टेक्स्ट: जो कुछ कोड नहीं है वह tool_error के रूप में सहेजा जाता है. |
| अवधि और साइज़ | पहुंचने से जवाब तक के मिलीसेकंड, और कॉल करने वाले को मिले बाइट. | |
| ट्रेस आईडी | रिक्वेस्ट की आईडी, x-request-id, x-trace-id या W3C traceparent हेडर से, वरना एक नई. | हेडर की ऐसी वैल्यू जो hex या UUID न हो. |
| रिकॉर्ड | उन रिकॉर्ड की 20 तक आईडी जिनका कॉल ने नाम लिया या जिन्हें उसने बनाया: एक संपर्क, एक मैसेज, एक मंज़ूरी. | ख़ुद रिकॉर्ड. |
| बॉडी | आर्ग्युमेंट और जवाब, साफ़ किए हुए, हर एक ज़्यादा से ज़्यादा 4 KB. | सीक्रेट, मुक्त टेक्स्ट, और नीचे दिया गया निजी डेटा. |
इनमें से तीन इनकार डेटा के बारे में नहीं, क्लाइंट के बारे में हैं. टूल का नाम, एरर कोड और ट्रेस आईडी, तीनों बाहर से आते हैं. हर एक को सिर्फ़ उसी रूप में रखा जाता है जिसकी सर्वर गारंटी दे सके. जो लॉग कॉल करने वाले का भेजा सब कुछ सहेज ले, उसे किसी भी चीज़ से भरा जा सकता है, यहां तक कि टूल के नाम वाले कॉलम में किसी ग्राहक के ईमेल पते से भी.
बातचीत के आख़िर में Benjamin Eckel का खुला सवाल यह था कि कलेक्टर को कैसे पता चले कि “यह एक MCP टूल कॉल है जिसमें एरर है”. एक सर्वर पर इसका जवाब एक कॉलम है. ok false होता है, और कोड बताता है कि कौन सा एरर है.
आर्ग्युमेंट: एक नियम जिसे हमने पलट दिया
आपत्ति जायज़ है, और यह हमारी अपनी है. आर्ग्युमेंट लॉग करें, और आपने अपने ग्राहकों के डेटा की एक दूसरी कॉपी बना ली, जो डेटा हटाने के हर अनुरोध की पहुंच से बाहर है. 18 अक्टूबर 2026 तक यही हमारा अपना नियम था. लॉग न आर्ग्युमेंट रखता था न नतीजे की बॉडी, क्योंकि दोनों में निजी डेटा हो सकता है.
यह ग़लत सौदा था. जो रिक्वेस्ट लॉग यह नहीं दिखा सकता कि क्या भेजा गया और क्या वापस आया, वह उस एक सवाल का जवाब नहीं दे सकता जिसके लिए वह मौजूद है: मेरे एजेंट की कॉल क्यों फ़ेल हुई?
इसलिए बॉडी रखी जाती हैं, और जिस वजह से उन्हें नहीं रखा जाता था, उसका हल दूसरे तरीके से किया गया है. हर बॉडी कतार में डाले जाने से पहले एक डिटरमिनिस्टिक चरण से गुज़रती है.
- कोई सीक्रेट नहीं बचता. जिस फ़ील्ड का नाम token, password, secret, signature, cookie, session या लगभग बीस मिलते-जुलते शब्दों में से कोई हो, वह सिर्फ़
[secret]रखता है. किसी जाने-पहचाने क्रेडेंशियल के रूप वाली वैल्यू के साथ भी यही होता है, चाहे वह कहीं भी हो. इसमें bearer टोकन, JWT, प्राइवेट की, पासवर्ड वाले URL और की के 40 या ज़्यादा अक्षरों का कोई भी अपारदर्शी सिलसिला शामिल है. - गद्य बिल्कुल नहीं रखा जाता. जिस फ़ील्ड का नाम
html,text,body,markdownयाcontentहो, वह सिर्फ़[redacted]रखता है. गद्य में नाम और गली के पते होते हैं जिन्हें कोई पैटर्न नहीं पकड़ता. - निजी डेटा हमेशा के लिए छिपा दिया जाता है. जिस फ़ील्ड का नाम निजी डेटा की ओर इशारा करे, जैसे ईमेल, फ़ोन, नाम, पता या नोट, वह सिर्फ़
[redacted]रखता है. किसी भी दूसरी स्ट्रिंग के अंदर ईमेल पता, फ़ोन नंबर, कार्ड या IBAN छिपा दिया जाता है. - बॉडी छोटी रहती हैं. स्ट्रिंग 512 अक्षरों पर काटी जाती हैं, लिस्ट 20 आइटम पर, ऑब्जेक्ट 50 की पर और नेस्टिंग 6 स्तरों पर. पूरी बॉडी 4 KB पर काटी जाती है और उसे कटा हुआ चिह्नित किया जाता है.
दो तरह की कॉल इससे भी कम रखती हैं. जो संपर्क किसी व्यक्ति की चैट किसी दूसरे ऐप से लाई, वे एक निशान और एक गिनती के रूप में लॉग होते हैं, बॉडी के रूप में कभी नहीं. जो कॉल लॉग पढ़ती है वह कोई जवाब नहीं रखती, क्योंकि जवाब सिर्फ़ लॉग की दूसरी पंक्तियां होता.
अब लागत. छिपाना स्थायी है, यह ऐसा एन्क्रिप्शन नहीं जिसकी की किसी के पास हो. लॉग आपको वह ईमेल पता नहीं दिखा सकता जिस पर मैसेज बाउंस हुआ. यह आपको संपर्क की आईडी दिखाता है, और संपर्क, अपने नियमों के तहत, एक कॉल की दूरी पर है. लॉग वर्कस्पेस के डेटा मिटाने की प्रक्रिया से बाहर है, इसीलिए छिपाना उस प्रक्रिया का इंतज़ार नहीं कर सकता.
लॉग ऑडिट ट्रेल क्यों नहीं है
Tajo के पास पहले से एक ऐसा ऑडिट लॉग है जिसमें सिर्फ़ जोड़ा जा सकता है. हर पंक्ति अपने से पहले वाली पंक्ति का एक hash रखती है, इसलिए कहीं भी बदलाव चेन को तोड़ देता है. तो टूल कॉल वहां क्यों न लिखी जाएं?
क्योंकि चेन की एक कीमत है. हर जोड़ वर्कस्पेस के स्तर पर एक लॉक लेता है और चेन को आगे बढ़ाने के लिए पिछली पंक्ति पढ़ता है. अगर हर रीड उसी से गुज़रे, तो वर्कस्पेस की कॉल एक ही लॉक के पीछे कतार में लग जाएंगी. इससे वे स्टेट बदलाव भी, जिन्हें दिखाने के लिए ऑडिट लॉग मौजूद है, हज़ारों रीड के नीचे दब जाएंगे.
इसलिए दोनों रिकॉर्ड सवाल के हिसाब से बंटे हैं. रिक्वेस्ट लॉग बताता है कि एजेंट ने क्या मांगा और क्या हुआ, 30 दिन तक. ऑडिट लॉग बताता है कि क्या बदला, किसने इसकी अनुमति दी, और क्या तब से किसी ने रिकॉर्ड में बदलाव किया है.
मंज़ूरियां ऑडिट वाली तरफ़ हैं. Tajo के कनेक्टर प्रोफ़ाइल पर, एक propose टूल एक घोषित एक्शन तैयार करता है और एक apply टूल मंज़ूरी मिलने के बाद उसे चलाता है. जब तक प्रस्ताव मंज़ूर न हो, किसी व्यक्ति द्वारा या वर्कस्पेस के चालू किए किसी नियम से, प्रोवाइडर तक कुछ नहीं पहुंचता. propose कॉल की पंक्ति अपने रिकॉर्ड में उस मंज़ूरी का नाम लेती है जो उसने बनाई. मंज़ूरी ख़ुद ठीक उसी इनपुट के SHA-256 डाइजेस्ट से बंधी होती है. मंज़ूरी ठीक उसी इनपुट को कवर करती है जो आपने देखा: एक फ़ील्ड बदलें और यह मेल नहीं खाती. जब राइट पूरी होती है, तो उसकी ऑडिट पंक्ति इनपुट का डाइजेस्ट और प्रोवाइडर के जवाब का डाइजेस्ट रखती है, जवाब की वैल्यू कभी नहीं.
पंक्ति की लागत क्या है
एक पंक्ति डेटाबेस में एक राइट है, और राइट का एक कमिट होता है. 8 अक्टूबर 2026 तक हर कॉल जवाब से पहले अपने कमिट का इंतज़ार करती थी, हमारे होस्ट पर लगभग 2.6 ms. एक क्लाइंट के लिए यह एक छोटी टूल कॉल का एक चौथाई था.
अब पंक्ति कॉल ख़त्म होने पर बनती है और कतार में डाल दी जाती है. एक फ़्लश कतार को ज़्यादा से ज़्यादा 100 ms बाद लिखता है, हर वर्कस्पेस के लिए एक ट्रांज़ैक्शन, इसलिए कई कॉल एक कमिट साझा करती हैं. पंक्ति की कोई चीज़ नहीं बदलती, उसका टाइमस्टैम्प भी नहीं. अगर 5,000 पंक्तियां इंतज़ार में हों, तो अगली कॉल कोई पंक्ति गिराने के बजाय फ़्लश का इंतज़ार करती है.
रिकॉर्डिंग कभी किसी कॉल को फ़ेल नहीं करती. जो राइट फ़ेल हो, उसे पंक्ति दर पंक्ति दोबारा आज़माया जाता है, फिर लॉग करके गिरा दिया जाता है. प्रोसेस को ज़बरदस्ती बंद करने से जो खोता है वह वही है जो कतार में पड़ा था: ज़्यादा से ज़्यादा आख़िरी 100 ms की कॉल.
इसे वापस पढ़ना
logs.list वर्कस्पेस की कॉल लौटाता है, सबसे नई पहले, बॉडी के बिना. यह समय, नतीजे या HTTP स्टेटस, सोर्स (MCP या REST API, जो यही टेबल इस्तेमाल करता है) और API की के हिसाब से फ़िल्टर करता है. यह डिफ़ॉल्ट रूप से एक पेज पर 50 दिखाता है, ज़्यादा से ज़्यादा 100. logs.get एक कॉल लौटाता है, की के मौजूदा नाम, उसके स्टेटस, उसकी अवधि, साफ़ की गई रिक्वेस्ट और जवाब, और उन रिकॉर्ड के साथ जिन्हें उसने छुआ.
दोनों सिर्फ़ कॉल करने वाले का वर्कस्पेस पढ़ते हैं. किसी दूसरे वर्कस्पेस की पंक्ति की आईडी नहीं मिलती.
टूल एरर में रिक्वेस्ट आईडी होती है. जब यह आईडी सर्वर ने बनाई हो, या यह hex या UUID के रूप में आई हो, तो यही पंक्ति की ट्रेस आईडी है. जिस एजेंट को एरर मिला, वह किसी व्यक्ति को वह एक वैल्यू दे सकता है जो कॉल की पहचान बताती है.
क्या बना है, और क्या नहीं
इस लेख के लिखे जाने तक जो बना है:
- वर्कस्पेस सर्वर और हर कनेक्टर सर्वर पर हर
tools/callके लिए एक पंक्ति, अस्वीकार की गई और अनजान कॉल समेत. - की की आईडी, सर्वर, कनेक्टर, प्रोफ़ाइल, टूल, असर, नतीजा, अवधि, नतीजे का साइज़, ट्रेस आईडी और छुए गए 20 तक रिकॉर्ड.
- साफ़ किए गए आर्ग्युमेंट और जवाब, हर एक ज़्यादा से ज़्यादा 4 KB.
logs.listऔरlogs.get, वर्कस्पेस तक सीमित, 30 दिन तक रखे जाने के साथ.- इनपुट डाइजेस्ट से बंधी मंज़ूरियां, और hash चेन वाले ऑडिट लॉग में इनपुट और आउटपुट डाइजेस्ट के साथ दर्ज की गई लागू हुई राइट.
जो नहीं बना, और जिस पर भरोसा करने से पहले जानना ज़रूरी है:
- कोई हेल्थ स्कोर नहीं, हर टूल का कोई चार्ट नहीं और बढ़ते एरर रेट पर कोई अलर्ट नहीं. कॉल, एरर और सबसे धीमी अवधियों का हर टूल का सारांश Tajo के ऑपरेटरों के लिए मौजूद है, किसी ऐसी जगह पर नहीं जिसे आप खोल सकें.
logs.listटूल के नाम या ट्रेस आईडी के हिसाब से फ़िल्टर नहीं कर सकता. किसी रिक्वेस्ट आईडी के पीछे की पंक्ति ढूंढने के लिए समय और की से दायरा छोटा करें.- पंक्तियां आपके अपने चलाए ट्रेसिंग सिस्टम में एक्सपोर्ट नहीं होतीं. ट्रेस आईडी सिर्फ़ HTTP हेडर से पढ़ी जाती है, MCP के उस
_metaफ़ील्ड से नहीं जिसका इस्तेमाल बातचीत में ट्रेस कॉन्टेक्स्ट ले जाने के लिए किया गया था. - 30 दिन बाद पंक्ति हटा दी जाती है. कोई आर्काइव या एक्सपोर्ट नहीं है.
- जो छिपाया गया, उसे लॉग से वापस नहीं पाया जा सकता.
- ज़बरदस्ती बंद करने से आख़िरी 100 ms की पंक्तियां खो सकती हैं.
बातचीत इस बात पर ख़त्म हुई कि MCP में ऑब्ज़र्वेबिलिटी “बराबर बंटी हुई नहीं है”. आगे का कोई डैशबोर्ड इसे ठीक नहीं कर सकता, और न ही वह ट्रेस जो सर्वर के दरवाज़े पर रुक जाए. फ़ेल होने वाले सिंक को अपने रिकॉर्ड की ज़रूरत होती है; वैसे ही हर उस कॉल को भी जिसने कुछ मांगा.
कॉल सर्वर ने देखी. किसी और ने नहीं. उसे वहीं दर्ज करें.
अक्सर पूछे जाने वाले प्रश्न
MCP सर्वर को हर टूल कॉल के लिए क्या लॉग करना चाहिए?
हर कॉल के लिए एक पंक्ति, जिसे सर्वर लिखे: किस API की ने कॉल किया, कौन सा सर्वर और कनेक्टर, टूल मौजूद हो तो उसका नाम, उसके असर की श्रेणी, ok या एक छोटा एरर कोड, अवधि, नतीजे का साइज़, रिक्वेस्ट की ट्रेस आईडी, उन रिकॉर्ड की आईडी जिनका कॉल ने नाम लिया या जिन्हें उसने बनाया, और सीक्रेट व निजी डेटा हटाकर आर्ग्युमेंट और जवाब. Tajo के MCP सर्वर अस्वीकार की गई कॉल समेत हर tools/call के लिए यह पंक्ति लिखते हैं और इसे 30 दिन रखते हैं.
क्या MCP रिक्वेस्ट लॉग को टूल के आर्ग्युमेंट रखने चाहिए?
हां, साफ़ करके. आर्ग्युमेंट के बिना लॉग यह नहीं बता सकता कि कॉल क्यों फ़ेल हुई. Tajo ने 18 अक्टूबर 2026 तक कोई बॉडी नहीं रखी थी और अब एक डिटरमिनिस्टिक चरण के बाद दोनों रखता है: सीक्रेट [secret] बन जाते हैं, मुक्त टेक्स्ट और निजी फ़ील्ड [redacted] बन जाते हैं, ईमेल, फ़ोन, कार्ड और IBAN छिपा दिए जाते हैं, और हर बॉडी 4 KB पर काट दी जाती है. छिपाना स्थायी है, इसलिए लॉग रिकॉर्ड की कॉपी बनाने के बजाय उसकी आईडी से उसकी ओर इशारा करता है.
MCP टूल कॉल लॉग को ऑडिट लॉग से अलग क्यों रखें?
क्योंकि दोनों अलग सवालों के जवाब अलग लागत पर देते हैं. Tajo का ऑडिट लॉग स्टेट में बदलावों की एक hash चेन है, और हर नई पंक्ति चेन को आगे बढ़ाने के लिए वर्कस्पेस के स्तर पर एक लॉक लेती है. अगर हर रीड उसी से गुज़रे, तो वर्कस्पेस की कॉल उस लॉक के पीछे कतार में लग जाएंगी और बदलाव रीड के बीच दब जाएंगे. टूल कॉल एक अलग, बिना चेन वाली टेबल में जाती हैं जो 30 दिन रखी जाती है; कॉल जो राइट तैयार करती है, वे अब भी अपनी ऑडिट पंक्तियां छोड़ती हैं.