osFoundry, Claude से exact Slides tab का नाम और हर citation पर key क्यों माँगता है? A developer rebuilt osFoundry's public MCP tools for Claude in Python and tested eight plausible model-generated payloads against the published tools/list schema, finding that narrow input schemas with additionalProperties: false, enums and idempotency keys block common malformed calls such as unexpected fields, invalid operation names and oversized slide decks. The rebuild validator also missed a maximum: 50 constraint on list_note_attachments that the live schema enforces, and the connector's outline format supports only title, body and notes, leaving themes and layouts to the desktop app. यह वह create call है जो osFoundry https://osfoundry.io/hi Notes के लिए Claude connection को मिलती है। इसे 2026-11-09 को public MCP endpoint पर बिना authentication के tools/list चलाकर लिया गया है, थोड़ा छोटा करके: {"name": "create note tab", "description": "Create a new Slides or Sheet tab in an approved Note. Use the version from list note tabs; returns the exact new tab ID for later edits. An optional outline fills a Slides tab. A repeated idempotency key returns the first tab.", "inputSchema": { "required": "note id", "expected version", "idempotency key", "tab type" , "properties": { "tab type": {"enum": "slides", "sheet" }, "label": {"type": "string"}, "slides": {"type": "array", "minItems": 1, "maxItems": 20, "items": {"required": "title" , "additionalProperties": false, "properties": {"title": {}, "body": {}, "notes": {}}}}}, "additionalProperties": false}, "annotations": {"readOnlyHint": false, "destructiveHint": true}, "securitySchemes": {"type": "oauth2", "scopes": "osfoundry:write" } } इस काम के लिए इसके दो पड़ोसी tools: {"name": "add note source", "description": "Add an HTTP or HTTPS citation to the Sources tab of an approved Note. Uses the Note version and an idempotency key; returns the new source ID.", "inputSchema": {"required": "note id", "expected version", "idempotency key", "title", "url" }} {"name": "list note tabs", "description": "List every tab instance and its type. A Note may have multiple Slides or Sheet tabs; use the exact tab ID returned here."} पूरा design तीन phrases पर टिका है: "every tab instance", "returns the exact new tab ID" और "a repeated idempotency key returns the first"। बाकी post इन tools को Python में फिर से बनाता है और मापता है कि इनमें से हर phrase किस गड़बड़ी को रोकता है। Note version पर optimistic locking एक अलग post का विषय है, और यहाँ सिर्फ़ वहीं आता है जहाँ उसका असर बाकी दोनों पर पड़ता है। Desktop app के अपने assistant से कम। osFoundry के अंदर Note assistant के slide create deck from outline और slide add slide apps/web/src/screens/notes/lib/note-surface-tools.ts में layouts, bullets, two-column content, tables, images और पाँच में से एक theme लेते हैं। Connector का outline item सिर्फ़ title , body , notes है, additionalProperties: false के साथ। edit note tab एक slide के लिए slide add और array के लिए slides add outline देता है, दोनों में यही तीन fields हैं। code/note store.py सेव किया हुआ tools/list response load करता है और एक छोटे validator required, enum, additionalProperties , minItems / maxItems से payloads को उसके ख़िलाफ़ check करता है। आठ payloads जो कोई model आराम से भेज सकता है: edit note tab {"operation": "slide add", "title": "Sources", "body": "3 links"} - ok edit note tab {"operation": "slide add", "title": "Sources", "index": 0} - unexpected index edit note tab {"operation": "slides add", "slides": {"title": "a"} } - operation: not in enum edit note tab {"operation": "slides add outline", "slides": {... "bullets"} } - slides: 0 unexpected bullets create note tab {"tab type": "slides", "slides": " 21 items "} - slides: maxItems 20 create note tab {"tab type": "markdown"} - tab type: not in enum add note source {"url": "https://example.org/report"} - missing title list note attachments {"kind": "sources", "limit": 100} - ok आख़िरी वाला इस validator से पास हो जाता है, लेकिन पूरे live schema से नहीं: limit पर maximum: 50 है, जिसे rebuild check नहीं करता। slide add position नहीं चुन सकता, create note tab Markdown tab नहीं बना सकता, और 20 से ज़्यादा slides वाले deck के लिए एक से ज़्यादा call चाहिए। Narrow schema इस बात का फ़ैसला है कि deck को style कौन करेगा: connector content लिखता है, और desktop app में बैठा व्यक्ति themes और layout लगाता है। क्योंकि desktop app ख़ुद अब भी यह shortcut मानता है, और shortcut पहला match उठा लेता है। apps/web/src/screens/notes/types.ts में resolveTabInstanceId : js if cfg.some t = t.id === rawTabId return rawTabId const byType = cfg.find t = t.type === rawTabId if byType return byType.id यह fallback …/slides जैसे पुराने links को चालू रखता है। Agent के लिए इसका मतलब है कि "edit slides" उस Slides tab में जाएगा जो strip में सबसे पहले है। नए tabs को NotesContentPanel.tsx के nextTabId से slides-9-mh8z1k2a जैसे IDs मिलते हैं, fixed tabs markdown , files और sources हैं, और कोई भी व्यक्ति जितने चाहे Slides tabs जोड़ सकता है, drag करके उनका क्रम बदल सकता है और उनका नाम बदल सकता है, duplicate नाम भी handleRename सिर्फ़ trim करता है । Rebuild एक Note को अलग-अलग labels वाले K Slides tabs देता है। एक scripted agent tabs list करता है, एक deck को target चुनता है और उसका एक handle रखता है: strip में उसकी position, उसका type, उसका label या उसका ID। Agent के turns के बीच व्यक्ति शून्य से दो random बदलाव करता है tab हिलाना 40%, किसी Slides tab का नाम पाँच labels में से किसी एक पर रखना 35%, नया Slides tab जोड़ना 25% । फिर agent दोबारा list करता है और अपना handle resolve करता है। हर K के लिए 10,000 trials, seed 7: | K decks | handle | सही | ग़लत deck | नहीं मिला | |---|---|---|---|---| | 2 | position | 83.7% | 16.3% | 0.0% | | 2 | type | 50.7% | 49.3% | 0.0% | | 2 | label | 85.6% | 2.1% | 12.3% | | 2 | ID | 100% | 0 | 0 | | 5 | position | 82.7% | 17.3% | 0.0% | | 5 | type | 19.7% | 80.3% | 0.0% | | 5 | label | 92.1% | 3.0% | 5.0% | | 5 | ID | 100% | 0 | 0 | Type वाला handle, उम्मीद के मुताबिक, 1/K बार सही होता है। Position तब fail होता है जब कोई drag target के ऊपर से गुज़रता है, K चाहे कुछ भी हो। Label सबसे लुभावना है, क्योंकि व्यक्ति prompt में यही लिखता है, और ज़्यादातर बार यह सही निकलता है। जो 2–3% ग़लत होते हैं वही बुरे cases हैं: अब किसी दूसरे deck पर वह label है, और agent बिना किसी error के उसमें लिख देता है। "नहीं मिला" safe failure है। ID एक बार दिया जाता है और कभी दोबारा इस्तेमाल नहीं होता, इसलिए tab strip में व्यक्ति के हर बदलाव के बाद भी बचा रहता है। नहीं। ऊपर के हर tab-strip बदलाव से Note version बढ़ता है, तो stale write ठुकरा दिया जाता है और agent दोबारा list करता है। दोबारा list करने से उसे current version मिल जाता है, और फिर वह अपने पुराने handle को नई list पर resolve करता है। Rebuild में इनमें से 100% writes version check पास कर लेते हैं, ग़लत deck पर जाने वाले सभी writes भी। Version यह साबित करता है कि agent ने latest Note देखा है। इससे कुछ पता नहीं चलता कि agent को उसमें सही tab मिला या नहीं। वह काम tab ID करता है। पहले, वरना tool description का वादा टूट जाता है। हर run में create note tab 50 बार चलाया जाता है, और 30% replies server के commit करने के बाद खो जाते हैं, client की तरफ़ से host timeout ऐसा ही दिखता है। Client वही call फिर भेजता है। तीन client policies, दो server orders, seeds 1–3: | server क्या check करता है | client की key policy | बने tabs भेजी गई calls | |---|---|---| | पहले key, फिर version | हर call पर नई key | 63 76 / 75 100 / 62 74 | | पहले key, फिर version | retry पर वही key | 50 67 / 50 81 / 50 62 | | पहले key, फिर version | conflict के बाद नई key | 50 67 / 50 81 / 50 62 | | पहले version, फिर key | हर call पर नई key | 63 76 / 75 100 / 62 74 | | पहले version, फिर key | retry पर वही key | 50 79 / 50 98 / 50 72 | | पहले version, फिर key | conflict के बाद नई key | 72 94 / 73 96 / 61 72 | Resend में खोए हुए commit से पहले वाला version होता है। जो server पहले version check करता है, उसे stale version दिखता है और वह पहला result लौटाने के बजाय conflict लौटाता है। जो client conflicts पर समझदारी से react करता है, यानी दोबारा पढ़ता है और अगली कोशिश को नई key के साथ नया intent मानता है, वह अब दूसरा deck बना देता है। जो client अपनी key बनाए रखता है, वह भी 16–21% ज़्यादा calls भेजता है। अगर key पहले check हो, तो resend original tab ID लौटाता है, version चाहे जो कहे। "a repeated idempotency key returns the first tab" का मतलब यही होना चाहिए। Rebuild 300 research sessions चलाता है। हर session में तीन turns हैं, हर turn 8 में से 6 pages cite करता है, और एक page सात में से किसी भी spelling में वापस आ सकता है: आख़िर में slash के साथ, www. , ?utm source=… , fragment , http:// , या बिना scheme के। 20% replies खो जाते हैं और उसी key के साथ फिर भेजे जाते हैं। | key | stored sources | duplicates | प्रति session | |---|---|---|---| | हर citation पर नया UUID, resend पर वही | 5,400 | 3,038 | 10.13 | | जैसा लिखा है वैसे URL का hash | 4,814 | 2,452 | 8.17 | | normalized URL और Note ID का hash | 2,362 | 0 | 0.00 | हर citation पर नई key खोए हुए replies को संभाल लेती है पहली line की कोई भी entry resend से नहीं आई और इससे ज़्यादा कुछ नहीं। Research अगले turn में उसी page को फिर cite करता है, और हर नया turn एक नई key है। जैसा लिखा है वैसे URL का hash exact repeats पकड़ लेता है, लेकिन ?utm source= या आख़िरी slash नहीं। Duplicates हटाने वाली key intent का नाम लेती है, "यह page इस Note का एक source है", यानी note id और normalized URL https, www. के बिना lower-case host, कोई fragment नहीं, कोई utm नहीं, आख़िर में slash नहीं का hash। Desktop app का अपना Sources form इसी का हल्का version करता है। NotesSourcesTab.tsx टाइप किए गए link को new URL ... से normalize करता है और पहले से attached link को मना कर देता है "This source is already attached" । Rebuild में browser-style hrefs की तुलना पहली row के 3,038 duplicates में से 725 पकड़ लेती। Connector का add note source किसी URL check की बात नहीं करता, इसलिए agent यह बात key के ज़रिए कहता है। URL से बनी key का एक side effect है: उसी page को बेहतर description के साथ दोबारा जोड़ने पर पहली row ही लौटती है। उसे edit करना Sources tab का काम है। 12-slide deck की लागत, हर request live schema पर validate: | तरीका | writes | request bytes | प्रति deck conflicts | |---|---|---|---| | slides के साथ create note tab | 1 | 1,673 | 0.070 | | ख़ाली create + 12 × slide add | 13 | 5,237 | 0.817 | Conflict वाला column एक model है, osFoundry का measurement नहीं: agent के read और write के बीच 4 s, Note में कहीं न कहीं औसतन हर मिनट एक बार save करता व्यक्ति exponential , 2,000 simulated decks। हर write एक नई window है जिसमें Note-level version बदल सकता है, इसलिए slide-by-slide बनाने में लगभग बारह गुना ज़्यादा re-reads लगते हैं। Deck को outline में डालें 20 slides तक और slide add उस slide के लिए रखें जिसके बारे में आपको बाद में पता चलता है। Paging दूसरी गिनती है जो जानने लायक है। list note attachments limit को 50 पर cap करता है, तो 120 sources वाले Note को list करने में 3 calls लगती हैं। इस machine पर कोई Claude binary नहीं चलती। code/run.py agent का role निभाता है और सीधे code/note store.py को call करता है। Store memory में एक lock के पीछे है, version के तौर पर एक counter के साथ। Tool names, required fields, enums और item limits code/tools list.raw के live schema से आते हैं, और tab IDs nextTabId को follow करते हैं। Error shapes, keys का scope यहाँ per Note और idempotency order rebuild के अपने choices हैं, और दूसरा order सिर्फ़ यह दिखाने के लिए है कि क्या गड़बड़ होती है। Apple Silicon पर Python 3.9.6, पाँचों experiments 1.0 s wall time में। Output code/run.out में है। व्यक्ति की तरफ़ Sources tab में क्या रहता है, यह Sources tab page https://osfoundry.io/hi/platform/sources-tab पर है। नीचे का protocol osFoundry की MCP glossary entry https://osfoundry.io/hi/glossary/mcp में संक्षेप में बताया गया है।