رفع مشکل پیکربندی OpenID برای کانکتورهای MCP
این هفته زمان زیادی را صرف رفع مشکل یک کانکتور MCP از راه دور کردم.
کانکتور مدام در پیدا کردن سرور OAuth من شکست میخورد. سرور به درستی کار میکرد. مشکل فقط یک مسیر (route) مفقود و یک ریدایرکت (redirect) بود.
وقتی از OAuth با MCP استفاده میکنید، انتظار دارید اسناد کشف (discovery documents) به درستی کار کنند. اکثر ابزارها به دنبال این دو مسیر هستند:
- /.well-known/oauth-authorization-server
- /.well-known/oauth-protected-resource
این مسیرها به کلاینتها میگویند که نقاط پایانی (endpoints) مربوط به احراز هویت (authorization) و توکن را کجا پیدا کنند.
مشکل اینجاست که بسیاری از کلاینتها به دنبال آن مسیرهای خاص نیستند. در عوض، آنها به دنبال /.well-known/openid-configuration میگردند.
این یک مسیر OpenID Connect است. این یک مشخصه (spec) متفاوت است، اما در همان مکان قرار دارد. پکیج من این مسیر را ثبت نکرده بود، زیرا از مشخصات OAuth پیروی میکرد، نه مشخصات OIDC.
کلاینت به دری میکوبد که وجود ندارد. خطای 404 دریافت میکند و متوقف میشود.
من دو انتخاب داشتم:
استفاده از ریدایرکتِ reverse-proxy در Nginx. این یک راه حل تنبلانه است. منطق برنامه را از کد شما خارج کرده و به زیرساخت منتقل میکند. تست کردن آن سخت است و در حین استقرار (deployment) به راحتی ممکن است دچار مشکل شود.
رفع مشکل در داخل اپلیکیشن. این روش بهتر است.
من تصمیم گرفتم اپلیکیشن را طوری تنظیم کنم که به این درخواست پاسخ دهد. من یک نام مستعار (alias) ایجاد کردم که مسیر OpenID را به مسیر احراز هویت OAuth ریدایرکت میکند.
من از یک 308 Permanent Redirect استفاده کردم.
یک ریدایرکت 302 میتواند یک درخواست POST را به یک درخواست GET تبدیل کند. اما ریدایرکت 308 سختگیرانه است. این کد به کلاینت میگوید که به URL جدید برود و همان متد و بدنه (body) را حفظ کند. این روش صحیح برای مدیریت یک جابهجایی دائمی است.
همچنین این قابلیت را پشت یک پرچم پیکربندی (configuration flag) قرار دادم. این کار به کاربران اجازه میدهد اگر از سیستم کشف OIDC خودشان استفاده میکنند، آن را خاموش کنند.
با انجام این کار در کد، میتوانم تست بنویسم:
- یک تست بررسی میکند که آیا ریدایرکت به درستی انجام میشود یا خیر.
- یک تست ریدایرکت را دنبال میکند تا اطمینان حاصل کند که متادیتا (metadata) معتبر است.
این کار تضمین میکند که اگر ساختار متادیتا تغییر کند، تستهای من بلافاصله با خطا مواجه شوند. در این صورت، من خطا را در خط لوله (pipeline) خود پیدا میکنم، به جای اینکه وقتی کاربر نمیتواند متصل شود، با آن مواجه شوم.
مشخصات (specs) اغلب در عمل با هم تفاوت دارند. حتی زمانی که دو استاندارد اهداف مشابهی دارند، کلاینتها مسیرهای متفاوتی را انتخاب میکنند. به عنوان یک توسعهدهنده سرور، شما باید به هر دو در پاسخ دهید.
آنها را به یک اتاق هدایت کنید، از کد ریدایرکت صحیح استفاده کنید و آن را با تستها پشتیبانی کنید.