اگر از حساب شخصی مایکروسافت برای مدیریت یادداشتهایتان استفاده میکنید، احتمالاً متوجه شدهاید که عاملهای هوش مصنوعی در دسترسی به دادههای شما با شکست مواجه میشوند. این مشکل که در ظاهر یک خطای ساده است، در واقع یک تلهٔ فنی در لایهی احراز هویت است که بسیاری از توسعهدهندگان را به بنبست رسانده است. «خطاهای ۴۰۱ خاموش»، تنها سرنخی از یک باگ پنهان در یک سرور MCP واننوت مبتنی بر جاوا اسکریپت بودند که در عمل هر کاربری را که حساب کاری یا تحصیلی Azure AD نداشت، از دسترسی محروم میکرد. اماندپ سینگ (Amandeep Singh)، توسعهدهنده این پروژه، این شکست بحرانی در احراز هویت را — که پیش از این مانع دسترسی حسابهای شخصی مایکروسافت به یادداشتهایشان از طریق هوش مصنوعی میشد — با یک بازنویسی سفارشی در TypeScript حل کرد.
پروتکل زمینهٔ مدل (Model Context Protocol یا MCP) — مثل یک مترجم استاندارد که اجازه میدهد دستیارهای هوش مصنوعی با ابزارهای خارجی صحبت کنند — به ابزارهایی مانند Claude Desktop، Cursor و Claude Code اجازه میدهد تا از طریق JSON-RPC با دادههای خصوصی کاربر تعامل داشته باشند. این معماری از stdio برای ارتباط استفاده میکند: پیامهای JSON-RPC از طریق stdout جریان مییابند، در حالی که تشخیصها و خطاها به stderr هدایت میشوند. این ساختار اجازه میدهد تا یک هوش مصنوعی، در صورت پیکربندی صحیح سرور، بتواند دادههای خصوصی را بخواند و بنویسد. همانطور که در تحلیلهای قبلی ما دربارهی اینکه چرا باتها و عاملها در اکوسیستم مایکروسافت به معماریهای متفاوتی نیاز دارند اشاره کردیم، این پروژه بهطور کامل اصطکاک میان هویتهای مصرفکننده (Consumer) و مجوزهای API در سطح سازمانی را برجسته میکند. این رویکرد استانداردسازی در واقع همان تغییری است که پروتکل MCP توانست بار کاری ادغام هوش مصنوعی را از روشهای ضربدری به ساختاری جمعی تغییر دهد.
تلهی احراز هویت
به گزارش این پروژه، شکست اصلی از استفاده از مجوزهای سطح اپلیکیشن (با پسوند .All) نشأت میگرفت. سرور اولیه درخواست مجوزهای Notes.Read.All و Notes.ReadWrite.All و User.Read را میداد. در حالی که این مجوزها دسترسیهای سطح اپلیکیشن را اعطا میکنند، اما حسابهای شخصی مایکروسافت (MSA) نمیتوانند با آنها موافقت (Consent) کنند؛ این قابلیت تنها مختص حسابهای کاری یا تحصیلی Azure AD است.
وقتی یک حساب شخصی تلاش میکند از این مجوزها استفاده کند، Azure یک توکن صادر میکند، اما Microsoft Graph هر درخواست بعدی را رد میکند. این امر منجر به یک خطای HTTP 401 با کد خطای ۴۰۰۰۱ میشود: «درخواست حاوی یک توکن احراز هویت معتبر نیست». در این فرآیند، هیچ خطایی در مرحلهی احراز هویت رخ نمیدهد و هیچ هشداری نمایش داده نمیشود؛ این یک «شکست خاموش» است که عیبیابی آن را بسیار دشوار میکند.
برای رفع این مشکل، توسعهدهنده مجوزهای سطح اپلیکیشن را با مجوزهای تفویضشدهی منبع-شناخته (Resource-qualified delegated scopes) جایگزین کرد:
https://graph.microsoft.com/Notes.Readhttps://graph.microsoft.com/Notes.ReadWritehttps://graph.microsoft.com/User.Read
این مجوزهای تفویضشده برای هر دو نوع حساب شخصی و کاری/تحصیلی کار میکنند و دسترسی را بهطور خاص به محتوای واننوت خودِ کاربرِ وارد شده محدود میکنند.
نکتهی ظریف فرمت توکنها
یافتهی حیاتی دیگر مربوط به فرمت توکنها بود. حسابهای شخصی مایکروسافت توکنهای فشردهای (غیر-JWT) را برمیگردانند. این توکنها رشتههای مبهمی (Opaque strings) هستند که فاقد ساختار استاندارد سه بخشی «header.payload.signature» در توکنهای وب جیسون (JWT) میباشند.
اگر یک سرور فرمت توکن را از طریق بررسی تخصصی برای JWT اعتبارسنجی کند، بهطور اشتباه توکنهای معتبر حسابهای شخصی را رد خواهد کرد. توسعهدهنده به این نتیجه رسید که رویکرد صحیح این است که از اعتبارسنجی فرمت توکن بهطور کلی اجتناب شود و اجازه داده شود تا Microsoft Graph به عنوان تنها مرجع تصمیم بگیرد که آیا یک توکن معتبر است یا خیر.
بازنگری جامع معماری
این بازنویسی، ده اسکریپت پراکنده جاوا اسکریپت — شامل simple-onenote.js و list-sections.js و get-all-page-contents.js — را با یک معماری ساختاریافته در TypeScript جایگزین کرد که در دایرکتوری src/ قرار دارد. سیستم جدید وظایف را در چندین فایل کلیدی تفکیک کرده است:
config.ts: مدیریت Client ID، Tenant، مجوزها (Scopes) و مسیرها.token-store.ts: مدیریت بارگذاری، ذخیرهسازی و نرمالسازی توکنهای دسترسی.auth.ts: مدیریت جریان احراز هویت کد-دستگاهی (Device-code authentication flow).graph-client.ts: عمل به عنوان کارخانه تولید کلاینت SDK گراف.mcp-server.ts: پیادهسازی سرور MCP با ابزارهای تایپشده توسط Zod.cli.ts: یک رابط خط فرمان (CLI) واحد که جایگزین ده اسکریپت مجزای قبلی شده است.
این ساختار جدید وابستگیهای سنگین مانند jsdom را حذف کرده و node-fetch را با fetch بومی موجود در Node 18+ جایگزین کرده است. همچنین کدبیس را بهروزرسانی کرده تا به جای الگوی callback قدیمی Client.init از متد Client.initWithMiddleware استفاده کند. در حالی که این پیادهسازی بر پایه TypeScript است، مفاهیم مشابهی در ساخت سرورهای MCP با استفاده از .NET دیده میشود که هر دو بر اتصال زنده مدلها به APIهای تجاری تأکید دارند.
بهبودهای مهندسی هسته
بهبودهای فنی کلیدی شامل موارد زیر است:
- طرحهای Zod (Zod Schemas): در سرور اولیه، از متد
tool()در SDK بدون استفاده از طرحها (Schemas) استفاده میشد، به این معنی که پارامترها به صورتparams.random_stringمیرسیدند. بازنویسی جدید، طرحهای صریح Zod را پیاده میکند. برای مثال، ابزارgetPageاکنون به یکqueryنیاز دارد که به عنوانz.string().min(1).describe('Page ID or title substring')تعریف شده است. این امر اطلاعات تایپ و توصیفاتی را فراهم میکند که کلاینتهای هوش مصنوعی برای ارسال آرگومانهای صحیح به آنها نیاز دارند. - پارسر HTML بدون وابستگی: API گراف واننوت، محتوای صفحه را به صورت HTML برمیگرداند. کد قدیمی به
jsdomمتکی بود. تابع جدیدhtmlToText()از Regex برای حذف بلوکهای<script>و<style>، تبدیل<br>و تگهای بسته بلوکی (مانند</p>،</div>و</li>) به خطوط جدید، رمزگشایی موجودیتها (Entities) و فشردهسازی فضای خالی استفاده میکند. - یکپارچگی جریان Stdio: از آنجا که MCP منحصراً از stdout برای JSON-RPC استفاده میکند، هرگونه فراخوانی
console.log()جریان پروتکل را تخریب کرده و باعث کرش کردن اتصال میشود. بازنویسی جدید یک تابع کمکیlog()را پیاده میکند که تمام ثبتهای گزارش را به اجبار بهconsole.error(stderr) هدایت میکند. - کلاس OneNoteClient: تمام عملیات API گراف اکنون کپسولهسازی شدهاند. این امر امکان فراخوانیهای زنجیرهای تمیز را فراهم میکند: مقداردهی اولیه از یک توکن ذخیره شده، لیست کردن دفترچهها، یافتن صفحه بر اساس عنوان و بازیابی محتوا، همگی در یک گردش کار واحد.
اعتبارسنجی و استقرار
توسعهدهنده یک مجموعه تست با استفاده از Vitest و کلاینتهای گراف شبیهسازی شده (Mocked) پیاده کرد. این کار اجازه میدهد ۳۴ تست مجزا را پوشش دهد که شامل تبدیل HTML، مدیریت توکن و عملیات کلاینت بدون نیاز به فراخوانیهای زنده API است. برای مثال، از Mockها برای شبیهسازی بازگشت دادهها از /me/onenote/pages جهت تایید منطق findPage استفاده شده است.
کاربران میتوانند سرور را از طریق گردش کار زیر مستقر کنند:
۱. کلون کردن مخزن و اجرای npm install و npm run build.
۲. اجرای npm run auth برای ورود از طریق جریان کد-دستگاهی (که نیازی به ثبت اپلیکیشن در Azure ندارد).
۳. اجرای npm run verify برای تایید اتصال.
۴. افزودن مسیر dist/mcp-server.js به پیکربندی Claude Desktop در بخش mcpServers.
پس از پیکربندی، هوش مصنوعی میتواند به پرسشهایی مانند «در دفترچههای واننوت من چه خبر است؟» با استفاده از دادههای تایپشده و قابل اعتماد پاسخ دهد.
این گذار از یک رویکرد پراکنده جاوا اسکریپتی به یک معماری تایپشده در TS نشان میدهد که بزرگترین مانع در استفاده از ابزارها توسط عاملهای هوش مصنوعی، استدلال LLM نیست، بلکه شکنندگی لایه احراز هویت است. برای توسعهدهندگان، اثر ثانویه این موضوع روشن است: تکیه بر مجوزهای پیشفرض API میتواند «شکستهای خاموشی» ایجاد کند که عیبیابی آنها بدون بررسی ساختار داخلی توکن تقریباً غیرممکن است.
اگر در حال ساخت سرورهای MCP خود هستید، اطمینان حاصل کنید که ابزارهای شما طرحهای پارامتر صریح را از طریق Zod یا کتابخانههای مشابه ارائه میدهند. بدون اینها، شما عملاً امیدوار هستید که هوش مصنوعی فرمت ورودی صحیح را حدس بزند.
گام بعدی شما
- اگر سرور MCP توسعه میدهید، هرگز به مجوزهای پیشفرض API تکیه نکنید و دامنهی دسترسیها را برای هر نوع حساب کاربر تست کنید.
- برای تعریف پارامترهای ابزارها حتماً از کتابخانههای اعتبارسنجی مانند Zod استفاده کنید تا مدل از حدسزدن فرمت ورودی رهایی یابد.
- لاگهای خود را فقط به
stderrهدایت کنید تا ارتباط مدل با سرور قطع نشود.
اما چالشهای احراز هویت تنها بخشی از مسیر است؛ بررسی تأثیر ساختارهای توکنهای غیر-JWT بر سایر مدلهای عاملمحور را در گزارش بعدی دنبال کنید.




گفتگو