7 मिनट पढ़ें

MCP टूल एनोटेशन और अनुमोदन की सीमाएं

MCP tool annotations expected behavior समझाने में मदद कर सकती हैं, लेकिन किन agent actions के लिए approval जरूरी है, यह केवल real side effects की जांच से तय होना चाहिए।

MCP टूल एनोटेशन और अनुमोदन की सीमाएं

MCP tool annotations उपयोगी documentation हैं। साथ ही, ये असुरक्षित approval system को व्यवस्थित दिखाने का आसान तरीका भी बन सकते हैं। अगर कोई client readOnlyHint, destructiveHint या idempotentHint को authorization मान लेता है, तो server author ने असल में user की approval policy लिख दी है, बिना यह साबित किए कि implementation उस भरोसे के लायक है।

यह उलटा तरीका है। Annotation किसी prompt को समझाने, tool list को व्यवस्थित करने या किसी action की समीक्षा कर रहे व्यक्ति के लिए समझदारी भरा default सुझाने में मदद कर सकता है। Approval उस request पर आधारित होना चाहिए जिसे server चलाएगा, उस credential पर जिसे वह इस्तेमाल करेगा, उस target पर जहां वह पहुंचेगा और उन side effects पर जिन्हें वह trigger कर सकता है। मैंने बहुत-से integrations देखे हैं जो get नाम वाले endpoint को call करते हैं, एक विनम्र JSON object लौटाते हैं और फिर भी कहीं और काम शुरू कर देते हैं।

Agents के मामले में यह फर्क सबसे ज्यादा मायने रखता है, क्योंकि agents retry करते हैं, tools को जोड़कर चलाते हैं और इतनी तेजी से काम करते हैं कि छोटी classification mistake भी महंगी पड़ सकती है। कोई tool एक बार सुरक्षित हो सकता है, लेकिन loop में असुरक्षित बन सकता है। एक API के लिए read-only tool दूसरे API के खिलाफ export mechanism बन सकता है। जो tool idempotent दिखता है, वह duplicate work कर सकता है, जब timeout पहली सफलता को छिपा दे।

Annotations behavior बताती हैं, authority नहीं देतीं

Model Context Protocol tool specification annotations को tool के behavior के बारे में hints बताती है। यह शब्दावली जानबूझकर चुनी गई है: client इनका इस्तेमाल अपना interface बेहतर बनाने के लिए कर सकता है, लेकिन verified declaration के बिना इन्हें security decision के रूप में सुरक्षित ढंग से इस्तेमाल नहीं कर सकता।

यहां तीन fields अलग-अलग दावे बताती हैं:

  • readOnlyHint: true का दावा है कि tool अपने environment में बदलाव नहीं करता।
  • destructiveHint: true का दावा है कि tool destructive updates कर सकता है।
  • idempotentHint: true का दावा है कि समान arguments के साथ दोहराई गई calls environment पर कोई अतिरिक्त असर नहीं डालतीं।

इन दावों में किसी call का पूरा risk शामिल नहीं होता। कोई tool पूरा customer database पढ़कर उसका result agent को भेज सकता है और फिर भी ईमानदारी से खुद को read-only बता सकता है। दूसरा tool केवल access timestamp लिख सकता है, जो सुनने में मामूली लगता है, जब तक वही timestamp retention, billing या incident record को न बदल दे। Idempotence यह नहीं बताती कि पहला effect स्वीकार्य था या नहीं।

Specification इन fields के लिए conservative defaults भी देती है। readOnlyHint का default false है। idempotentHint का default false है। destructiveHint का default true है और इसका उपयोगी अर्थ तभी है जब tool read-only न हो। इन defaults को अपनी बनाई हुई rule से न बदलें, जैसे "missing metadata का मतलब safe enough है।" Missing metadata का मतलब अक्सर यह होता है कि server author ने classification पर पर्याप्त विचार नहीं किया।

एक और असहज बात है: अच्छा server भी गलत हो सकता है। Developer readOnlyHint: true इसलिए जोड़ देता है क्योंकि handler SELECT चलाता है, फिर library layer token refresh करती है, cache में entry लिखती है या request hook चलाती है। Behavior बदलने के काफी समय बाद भी annotation true रह सकती है। किसी ने client को धोखा देने की कोशिश नहीं की, लेकिन अगर client ने action को अपने-आप मंजूर किया, तो उसने फिर भी गलत फैसला लिया।

Read का मतलब harmless result नहीं होता

Read-only operation data उजागर कर सकता है, किसी दुर्लभ resource की खपत कर सकता है या remote service में behavior शुरू कर सकता है। "Write नहीं करता" को "approval की जरूरत नहीं" समझना category error है।

get_build_log नाम वाले tool पर विचार करें, जो job identifier लेता है। Server अपने build system से read करता है और output लौटाता है। वह सही रूप से readOnlyHint: true घोषित कर सकता है। फिर भी log में source code, environment details, signed download URLs या credentials हो सकते हैं, जिन्हें किसी दूसरे system ने गलती से print कर दिया हो। उस response को autonomous agent को भेजने से यह बदल जाता है कि उस जानकारी का इस्तेमाल कौन कर सकता है, भले ही build system का database जस का तस रहे।

यही समस्या administrative APIs में भी दिखती है। get_user recovery codes लौटा सकता है। list_invoices bank details उजागर कर सकता है। search_documents bulk extraction का जरिया बन सकता है, जब agent page size बढ़ा दे या हर prefix पर iteration करे। यहां side effect disclosure है और annotation में disclosure sensitivity के लिए कोई field नहीं है।

Read operations remote service को भी बदल सकती हैं। कुछ APIs last_accessed_at अपडेट करती हैं, single-use download token खर्च करती हैं, preview register करती हैं या metered query चलाती हैं। Cache miss किसी महंगी downstream service को warm कर सकता है। इन effects का मतलब यह नहीं कि हर read खतरनाक है, लेकिन इनके कारण बिना शर्त read-only approval rule का बचाव नहीं किया जा सकता।

Call को दो अलग axes पर classify करें: क्या यह किसी system में mutation करती है, और उस system के बाहर क्या उजागर या trigger कर सकती है? Low-risk status probe और bulk export दोनों non-mutating हो सकते हैं। उन्हें एक जैसा approval treatment नहीं मिलना चाहिए।

Practical review record में data boundary को सरल भाषा में लिखें। "Project A का deployment status पढ़ता है" जैसी बात की समीक्षा की जा सकती है। "get_status को call करता है" की नहीं। दूसरी पंक्ति target, scope, account और इस तथ्य को छिपा देती है कि किसी दूसरे server पर इसी नाम का method कुछ और कर सकता है।

Handler को disposable target पर जांचें

किसी tool name या input schema को पढ़कर annotation की safety तय नहीं की जा सकती। Server को ऐसी जगह चलाएं जहां उसकी request, response और call से पहले और बाद की state देख सकें।

ऐसे fixture account से शुरुआत करें जिसमें वे records हों जिन्हें खोने पर कोई समस्या न हो। उसे अलग API credential दें और notification webhooks को capture endpoint पर भेजें। Server की outgoing requests, database state अगर उसका control आपके पास है, audit events, emails, queued jobs और billing या usage counters रिकॉर्ड करें। Response body evidence है, लेकिन पूरा record नहीं।

हर ऐसे tool के लिए एक छोटा test matrix इस्तेमाल करें जो approvals को प्रभावित कर सकता है:

  1. सामान्य valid input के साथ एक बार call करें और before-and-after state पूरी तरह save करें।
  2. Byte-for-byte identical input के साथ फिर call करें और हर observable effect की तुलना करें।
  3. Absent resource, पहले से पूरी हो चुकी operation और invalid field के साथ call करें।
  4. Server के request प्राप्त करने के बाद client को interrupt करें, फिर वही call दोबारा करें।
  5. अगर agents concurrent calls कर सकते हैं, तो दो identical calls को concurrent रूप से चलाएं।

Timeout case एक आम failure पकड़ता है। मान लें create_ticket ticket request भेजता है, फिर server के response लौटाने से पहले connection टूट जाता है। Agent को error दिखता है और वह retry करता है। अगर ticket system में idempotency token नहीं है, तो tool दो tickets बना देता है। Handler समान input को दो बार स्वीकार करता है, इसलिए उसे idempotent mark करने से remote result नहीं बदलता।

ऐसा output shape रिकॉर्ड करें जो लोगों को green response पर भरोसा करने के बजाय effects जांचने के लिए मजबूर करे:

case: retry after response timeout
request: {"title":"rotate staging certificate","request_id":"test-104"}
first call: transport timeout after request received
second call: 201 {"ticket":"842"}
remote records: ["841", "842"]
result: not idempotent without a remote idempotency mechanism

उस example में request_id तभी मदद करता है जब remote API उसे store और enforce करे। Server जिस caller-generated identifier को ignore कर दे, वह केवल सजावट है। Exact identifier दोहराकर enforcement की जांच करें और देखें कि remote system नया operation बनाने के बजाय original operation लौटाता है या नहीं।

Tests को server के साथ रखें। Annotation drift आम तौर पर code change, dependency update या नए endpoint के साथ आता है। Declared hint की observable behavior से तुलना करने वाला passing test, tool definition के पास लिखी comment से ज्यादा उपयोगी है।

Read-only claims boundaries पर fail हो जाते हैं

False readOnlyHint का सबसे आसान कारण है केवल main database query को देखना। वास्तविक boundary में handler द्वारा call की जाने वाली हर service और उसके response से होने वाली हर action शामिल है।

ऐसे server tool को लें जो document fetch करता है। उसकी primary request GET /documents/42 है, लेकिन handler पहले refresh token exchange कर सकता है, temporary download URL जारी कर सकता है, local cache अपडेट कर सकता है और access event लिख सकता है। हर operation अलग तरीके से fail हो सकती है। हर operation पर अलग credentials और audit requirements लागू हो सकती हैं।

यह तर्क स्वीकार न करें कि कोई write इतनी छोटी है कि उसे गिनने की जरूरत नहीं। छोटी writes अपनी failure modes लाती हैं। Last-viewed marker retention को प्रभावित कर सकता है। Access खत्म हो जाने के बाद भी cache content सुरक्षित रख सकता है। Access event owner को notify कर सकता है। Usage counter account को paid tier में पहुंचा सकता है। पूछें कि क्या यह write ऐसा fact बदलती है जिसे कोई दूसरा व्यक्ति, process या bill देखेगा। अगर हां, तो उसे document करें।

Response-triggered behavior की भी उतनी ही सावधानी से जांच करें। Signed link लौटाने वाला tool agent को बाद में उसे fetch करने के लिए प्रेरित कर सकता है। Executable command लौटाने वाला tool agent को उसे किसी दूसरे channel में चलाने तक ले जा सकता है। पहला tool संकीर्ण अर्थ में read-only रहता है, लेकिन approval screen पर "safe read" लिखने से human को agent की अगली संभावित action की गलत तस्वीर मिलती है।

जब risks अलग हों, तो अच्छा server operations को अलग रखता है। get_document_metadata एक narrow inspection call रह सकता है। create_download_link अपना अलग tool होना चाहिए क्योंकि वह bearer capability बनाता है, भले ही underlying document bytes में कोई बदलाव न हो। यह विभाजन agents को सही चुनाव करने में मदद करता है और reviewers को ऐसा statement देता है जिसे वे वास्तव में approve कर सकें।

Destructive का मतलब reversibility है, verb list नहीं

ऑडिट चेन जांचें
Sallyport के एन्क्रिप्टेड, hash-chained audit history की ऑफलाइन जांच sp audit verify से करें।

destructiveHint इस आधार पर होना चाहिए कि call ऐसे harmful updates कर सकती है या नहीं जिन्हें वापस लेना कठिन हो, न कि tool name में delete शब्द है या नहीं। Teams दोनों दिशाओं में यह गलती करती हैं।

कुछ स्पष्ट verbs एक system में reversible और दूसरे में permanent हो सकते हैं। archive केवल record को छिपा सकता है या purge timer शुरू कर सकता है। disable_user सभी entitlements और files को सुरक्षित रख सकता है या access इस तरह revoke कर सकता है कि automated process अटक जाए। replace_config draft अपडेट कर सकता है या तत्काल production deployment शुरू कर सकता है। Single Boolean में यह target-aware information आ ही नहीं सकती।

कुछ मासूम नाम वाले tools साफ तौर पर destructive होते हैं। sync_members submitted list में मौजूद न होने वाले accounts हटा सकता है। apply_labels सावधानी से बनाई गई taxonomy को overwrite कर सकता है। reconcile external ledger को ऐसे journal entries से ठीक कर सकता है जिन्हें कोई casually create नहीं करना चाहिए। जो server author इन्हें false mark करता है क्योंकि API इन्हें technically undo कर सकती है, वह repair की operational cost छिपा रहा है।

Reversibility को checkbox नहीं, sequence की तरह देखें। पूछें कि result को कौन undo कर सकता है, उसे कौन-सा evidence चाहिए, undo कितने समय तक उपलब्ध रहेगा और क्या कोई बाद का process किसी के reverse करने से पहले change को consume कर लेगा। अगर bulk update के बाद किसी human को logs से intent फिर से बनाना पड़े, तो action destructive classification का हकदार है, भले ही API inverse method उपलब्ध कराती हो।

लोकप्रिय गलत recommendation यह है कि approval केवल explicit deletion के लिए रखा जाए। यह इसलिए लोकप्रिय है क्योंकि agents चलते रहते हैं और demo smooth दिखता है। Production में यह fail होता है, क्योंकि destructive changes आम तौर पर replacements, revocations, sends या reconciliations होते हैं। Vocabulary नहीं, meaningful state change को approve करें।

Collection को प्रभावित करने वाली action के लिए review record में selection rule और count शामिल होना चाहिए। "Sync users" बहुत vague है। "Supplied IDs से चुने गए 14 inactive contractors को हटाएं" से व्यक्ति scope का आकलन कर सकता है। अगर server action से पहले यह scope report नहीं कर सकता, तो client के पास गंभीर approval prompt के लिए पर्याप्त जानकारी नहीं है।

Idempotence को retries और concurrency में भी कायम रहना चाहिए

असल कॉल को मंजूरी दें
ऐसे क्रेडेंशियल के हर उपयोग पर निर्णय जरूरी करें, जिनकी कार्रवाइयों की सावधानी से समीक्षा होनी चाहिए।

idempotentHint एक narrow claim है: identical arguments को पहली call के बाद दोहराने पर कोई अतिरिक्त effect नहीं होना चाहिए। इसका मतलब यह नहीं कि call safe, सस्ती, reversible है या agent उसे हमेशा दोहराता रह सकता है।

अगर state=closed दो बार सेट करने से record वही closed state में रहता है, तो status update idempotent हो सकता है। लेकिन handler हर बार email भेजे, audit comment जोड़े या version counter बढ़ाए, तो वह idempotent नहीं रहेगा। लोग अक्सर database row देखते हैं और secondary effects भूल जाते हैं, जिन्हें users सबसे पहले notice करते हैं।

Input equality की भी सटीक definition चाहिए। JSON object ordering मायने नहीं रखनी चाहिए। अगर server omitted note को note: "" से अलग समझता है, तो agent जिसे एक ही request मानता है, server दो अलग updates चला सकता है। Time values, generated defaults और tomorrow जैसी relative expressions इस claim को कमजोर करती हैं, क्योंकि visible arguments स्थिर दिखने पर भी effective command बदल जाती है।

Concurrency में casual idempotence सबसे जल्दी टूटती है। दो worker processes यह दोनों check कर सकते हैं कि object मौजूद नहीं है और फिर दोनों उसे create कर सकते हैं। Unique constraint, transactional upsert या remote idempotency facility इसे रोक सकती है। एक MCP server process की memory cache उस deployment को सुरक्षित नहीं कर सकती जो एक से अधिक process चलाता है।

Idempotency record का इस्तेमाल तभी करें जब उसका scope पहले तय कर लिया हो। Caller-supplied token को authenticated identity, normalized request body, result और operation के अनुकूल expiry के साथ store करें। अलग normalized input के साथ reused token को reject करें। वरना agent गलती से पुराने token को नई request के साथ जोड़ सकता है और किसी अलग action का result पा सकता है।

सिर्फ इसलिए auto-retry न करें कि hint true है। उन्हीं failures को retry करें जिनमें आपको पता हो कि server ने call प्राप्त की थी या नहीं। अगर यह पता नहीं चल सकता, तो actual mutation point पर idempotency mechanism लगाना समाधान है। Client-side hint नहीं।

Approval को executed action से बनाएं

Approval system को इन सवालों का जवाब देना चाहिए: कौन-सा process request कर रहा है, कौन-सा credential इस्तेमाल होगा, कौन-सा external target request प्राप्त करेगा, कौन-सी state या data scope में है और call सफल होने पर क्या होगा। Tool annotations इस explanation को छोटा कर सकती हैं। वे ऐसे facts नहीं दे सकतीं जिन्हें server ने expose ही नहीं किया।

Session approval और per-call approval को अलग रखें। Session approval उस known agent process के लिए ठीक है जो ordinary capabilities के साथ bounded run कर रहा हो। Per-call approval उन credentials के लिए ठीक है जो money transfer कर सकते हैं, production access बदल सकते हैं, messages भेज सकते हैं, sensitive records उजागर कर सकते हैं या irreversible external commitment बना सकते हैं। Decision credential और action context पर निर्भर होना चाहिए, optimistic readOnlyHint पर नहीं।

एक उपयोगी prompt concrete operation का नाम लेता है: "इस authority द्वारा signed agent account Y में deployment credential का इस्तेमाल करके service X restart करेगा।" कमजोर prompt कहता है: "Tool deploy की अनुमति दें?" पहले prompt में reviewer के पास मूल्यांकन करने के लिए कुछ ठोस है। दूसरा उनसे implementation detail पर भरोसा करने को कहता है।

Sallyport इस separation को अपनाता है। यह API और SSH credentials को अपने encrypted vault में रखता है, HTTP या SSH action को खुद execute करता है और credential के बजाय result agent को लौटाता है। इसका session authorization requesting process की पहचान करता है, जबकि per-credential setting हर उपयोग पर decision जरूरी कर सकती है। Human control रखने के लिए यह server द्वारा दिए गए Boolean से बेहतर जगह है।

Credentials के सामने gate होने पर भी final request target और result वाला activity record रखें। Approval बताता है कि action आगे बढ़ सकती है या नहीं। Audit record बताता है कि आगे बढ़ने पर हुआ क्या। इन दोनों सवालों को "tool used" नाम की एक अस्पष्ट event में न मिलाएं।

Annotation checks को server maintenance का हिस्सा बनाएं

क्रेडेंशियल टूल से बाहर रखें
Sallyport HTTP या SSH कॉल को खुद चलाता है, जबकि क्रेडेंशियल उसके एन्क्रिप्टेड वॉल्ट में सुरक्षित रहता है।

MCP tool annotations का सही उपयोग honest communication है, जिसे tests का सहारा मिला हो। Server author को इन्हें conservatively set करना चाहिए, boundary cases document करने चाहिए और behavior बदलने पर इन्हें बदलना चाहिए। Client author को इन्हें interface design के एक input की तरह लेना चाहिए, permission के लिए एकमात्र input की तरह नहीं।

ऐसे tests जोड़ें जो जानबूझकर claimed property के विपरीत हों। Read-only declaration के लिए test तब fail होना चाहिए जब fixture कोई write, outbound notification, credential refresh या बाद में retrieval के लिए बनाई गई capability देखे। Destructive declaration के लिए failure path और undo path जांचें, जिसमें downstream job के change को consume करने के बाद का behavior भी शामिल हो। Idempotence के लिए simulated timeout के बाद और concurrent callers के साथ वही normalized request चलाएं।

Mismatch छिपाने के लिए test target को तब तक न बदलें जब तक test pass न हो जाए। या तो tool को narrow करें ताकि hint true हो जाए, annotation बदलें या approval details में effect दिखाएं। हर विकल्प अगले maintainer को बताता है कि code वास्तव में क्या करता है।

जब Sallyport action gateway हो, तो incident review के हिस्से के रूप में sp audit verify चलाएं। यह encrypted hash chain को offline verify करता है, इसलिए vault खोले बिना जांच सकते हैं कि recorded action history सही बनी रही है या नहीं। इससे server annotation के ईमानदार होने का प्रमाण नहीं मिलता, लेकिन इसके आधार पर हुई calls का tamper-evident record जरूर मिलता है।

Practical standard सरल है: annotation को उस effect के खिलाफ adversarial test में टिकना चाहिए जो user के लिए मायने रखता है। अगर वह टिक नहीं सकती, तो उसे conservative रखें और approval वहीं रखें जहां action होती है।

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

क्या readOnlyHint वाले MCP टूल को अपने-आप मंजूरी दी जा सकती है?

इसे अनुमति देने वाला संकेत नहीं, बल्कि ऐसे दावे की तरह देखें जिसके लिए सबूत चाहिए। सर्वर का implementation जांचें, फिर टूल को disposable target पर चलाकर उसके सभी संभावित side effects देखें।

idempotentHint वास्तव में क्या सुनिश्चित करता है?

इसका मतलब है कि लेखक का मानना है कि समान arguments के साथ बार-बार की गई कॉल environment पर कोई अतिरिक्त असर नहीं डालेगी। फिर भी external systems, retry behavior, timestamps, notifications और argument normalization की जांच जरूरी है।

क्या MCP tool annotations security boundary हैं?

नहीं। Model Context Protocol specification इन fields को behavior संबंधी hints बताती है, client के security decision का विकल्प नहीं। कोई malicious, पुराना या केवल गलती से गलत server भ्रामक metadata प्रकाशित कर सकता है।

किन MCP tools के लिए अब भी approval जरूरी होना चाहिए?

जब कोई कॉल business state बदल सकती हो, sensitive data उजागर कर सकती हो, महंगा job शुरू कर सकती हो या controlled test target से बाहर किसी system तक पहुंच सकती हो, तब approval बनाए रखें। साधारण नाम और optimistic annotation इन जोखिमों को खत्म नहीं करते।

मैं कैसे जांचूं कि कोई टूल idempotent है?

Disposable account या local fixture इस्तेमाल करें, शुरुआती state रिकॉर्ड करें, टूल को समान arguments के साथ दो बार चलाएं और परिणामी state तथा बाहरी evidence की तुलना करें। Malformed input और interrupted request के साथ भी दोहराएं, क्योंकि retry paths अक्सर नुकसान दिखाते हैं।

क्या कोई destructive tool तब सुरक्षित हो सकता है जब कुछ बदले ही नहीं?

किसी खास record के लिए deletion tool non-destructive हो सकता है क्योंकि record पहले ही मौजूद नहीं है, फिर भी सामान्य रूप से वह destructive capability हो सकता है। Approval design में केवल एक कॉल के परिणाम के बजाय capability और target context को वर्गीकृत करें।

MCP annotations न होने पर क्या होता है?

Omission को conservative मानें और automation लिखने से पहले field semantics जांचें। मौजूदा MCP tool annotations में omitted destructiveHint का default true है, जबकि omitted readOnlyHint और idempotentHint का default false है।

Read-only API call के side effects कैसे हो सकते हैं?

कोई टूल plausible response लौटा सकता है, audit entry बना सकता है, last-accessed field अपडेट कर सकता है, webhook trigger कर सकता है या account से शुल्क ले सकता है, जबकि स्पष्ट resource में कोई बदलाव न दिखे। केवल tool response पर निर्भर न रहें, downstream records, network calls और system logs भी जांचें।

Autonomous coding agents के लिए approvals कैसे डिजाइन करने चाहिए?

पहले code-signing authority और intended scope की पहचान करके agent run को मंजूर करें। फिर उन credentials या actions के लिए per-call approval रखें, जिनके हर उपयोग पर मानव निर्णय चाहिए। Metadata approval copy लिखने में मदद कर सकता है, लेकिन उसे approval outcome तय नहीं करना चाहिए।

Sallyport MCP actions को नियंत्रित करने में कैसे मदद करता है?

Sallyport credentials को agent से बाहर रखता है और व्यक्ति को session approve करने या चुने हुए credential के हर उपयोग पर approval जरूरी करने देता है। इससे approval scheme server द्वारा दिए गए annotation के बजाय वास्तव में चलाए गए action पर आधारित रहती है।

Sallyport

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

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