اگر توسعهدهنده جنگو هستید و میخواهید مدلهای زبانی به جای توصیف API، واقعاً آن را اجرا کنند، گلوگاه اصلی شما تعریف دستی ابزارهاست. در حال حاضر، تعریف دستی ابزارها بزرگترین مانع برای توسعهدهندگانی است که قصد دارند مدلهای زبانی بزرگ (LLM) را به دادههای خصوصی خود متصل کنند. تصور کنید عاملی را دارید که نه تنها کاتالوگ محصولات شما را میشناسد، بلکه در لحظه موجودی انبار را چک میکند و سفارش ثبت میکند. رویکرد سادهلوحانه — یعنی نوشتن دستی یک ابزار MCP برای هر نقطه اتصال (Endpoint) شامل نام، توصیف و طرحواره ورودی — در روز اول جواب میدهد، اما تا سی روز بعد دچار پوسیدگی میشود. هر تغییر نام فیلد یا تغییر در پارامترهای پرسوجو (Query Parameter)، باعث میشود شما مجبور شوید تغییر را در دو جای مختلف اعمال کنید. این بدان معناست که هزینه نگهداری بهطور خطی با گسترش سطح API رشد میکند؛ یعنی دقیقاً همان چیزی که امیدوار بودید LLM به شما در مهار کردنش کمک کند.
این تحول از طریق تبدیل طرحوارههای drf-spectacular به ابزارهای پروتکل زمینه مدل (Model Context Protocol یا MCP) — شبیه به ساخت یک مترجم اتوماتیک که دفترچه راهنمای فنی API شما را به زبانی تبدیل میکند که Claude بفهمد — رخ میدهد. طبق گزارشی که در ۲۸ ژوئن ۲۰۲۶ در وبسایت dev.to منتشر شد، توسعهدهندگان جنگو میتوانند با تبدیل طرحوارههای OpenAPI به یک سرور MCP فعال، بدون نیاز به نوشتن کدهای رابط (Glue Code) برای تک تک نقاط اتصال، این شکاف را پر کنند. همانطور که در تحلیل قبلی ما دربارهی آسیبپذیریهای امنیتی مانند موارد یافت شده در Claude Opus 4.6 اشاره کردیم، تمرکز اکنون از ایمنی سادهی پرامپت به پایداری حلقهی فراخوانی ابزارها تغییر یافته است. برای یک توسعهدهنده، این یعنی مدل زبانی میتواند از مرحلهی «صرفاً صحبت کردن درباره یک API» به مرحلهی «عملاً بهکارگیری آن API» منتقل شود. این خط لوله (Pipeline) مسیر مشخصی را دنبال میکند: نماهای DRF (از طریق drf-spectacular) $\longrightarrow$ طرحواره OpenAPI $\longrightarrow$ ابزارهای MCP $\longrightarrow$ مدل Claude (یا هر LLM دیگر).
مکانیزم سیمکشی
به نقل از مستندات این پیادهسازی، فرآیند با بازرسی داخلی API آغاز میشود. واکنش متداول توسعهدهندگان این است که مسیر /api/schema/ را از طریق پروتکل HTTP فراخوانی کنند، اما این روش ناکارآمد است. بهجای آن، این پیادهسازی از SchemaGenerator در drf-spectacular استفاده میکند تا طرحواره OpenAPI 3 را مستقیماً بهعنوان یک دیکشنری پایتونی ساده از درون پروژه استخراج کند. این کار اجازه میدهد سیستم بدون نیاز به اجرای سرور، به تمامی مسیرها، پارامترها و انواع دادهها دسترسی داشته باشد.
from drf_spectacular.generators import SchemaGenerator
generator = SchemaGenerator()
schema = generator.get_schema(request=None, public=True)
البته اگر طرحواره شما در جای دیگری قرار دارد — مثلاً در یک سرویس راه دور یا یک API که با DRF ساخته نشده است — در این صورت باید به روش قدیمی بازگشته و URL را فراخوانی کرده و ارجاعات $ref را بهصورت دستی بازگشایی و حل کنید.
جزئیات فنی پیادهسازی
در این مرحله، سیستم مسیرهای طرحواره را پیمایش میکند تا مشخصات ابزار (Tool Specs) را بسازد. operationId هر نقطه اتصال API به نام ابزار تبدیل میشود و پارامترها به JSON Schemas تبدیل میگردند. پارامترهای مسیر (Path Parameters) همیشه بهعنوان «اجباری» علامتگذاری میشوند، در حالی که پارامترهای پرسوجو بر اساس فلگهای خاص خود در طرحواره عمل میکنند.
برای رسیدن به یک نسخه آمادهی تولید (Production-ready)، این پیادهسازی چندین مورد خاص و لبهای (Edge Case) را مدیریت میکند:
- حل ارجاعات ($ref): پارامترها ممکن است بهجای اشیاء داخلی، بهصورت ارجاع ظاهر شوند (مثلاً
{"$ref": "#/components/parameters/Foo"}). سیستم باید این اشارهگرها را حل کند، در غیر این صورت ابزارهای تولید شده خراب خواهند بود. - تداخل نامها و مجموعهکاراکترها: نام ابزارهای MCP تنها مجموعه محدودی از کاراکترها را میپذیرند. از آنجایی که دو عملیات میتوانند
operationIdیکسان داشته باشند، سیستم باید نامها را پاکسازی و تکراریها را حذف کند، در غیر این صورت کلاینت کل لیست ابزارها را رد خواهد کرد. - نگاشت پارامترها: منطق برنامه، «مکان» (location) پارامتر را بررسی میکند. اگر مکان پارامتر «path» یا «query» نباشد، برای حفظ یکپارچگی طرحواره، آن پارامتر نادیده گرفته میشود.
معماری سرور
بر اساس بررسی کدها، در mcp Python SDK یک تمایز حیاتی وجود دارد. در حالی که دکوراتور @tool از FastMCP برای ابزارهای استاتیک (که در زمان نوشتن کد شناخته شدهاند) بسیار راحت است، برای این پروژه ابزار مناسبی نیست. زیرا ابزارها در زمان اجرا با JSON Schemaهای پویایی ساخته میشوند که از قبل قابل پیشبینی نیستند، توسعهدهنده باید از کلاس سطح پایین Server استفاده کند.

from mcp.server.lowlevel import Server
import mcp.types as types
server = Server("my-django-api")
@server.list_tools()
async def list_tools():
return [types.Tool(name=s.name, description=s.description, inputSchema=s.input_schema) for s in specs]
@server.call_tool()
async def call_tool(name, arguments):
spec = by_name[name]
text = await execute(spec, arguments)
return [types.TextContent(type="text", text=text)]
عملیات اجرا از طریق تفکیک مجدد آرگومانها به پارامترهای مسیر و پرسوجو انجام میشود. پارامترهای مسیر در قالب URL جایگزین میشوند و پارامترهای پرسوجو بهعنوان یک رشته کوئری (Query String) ضمیمه میگردند. سپس یک درخواست asynchronous از طریق کتابخانه httpx به بکاند جنگو با متد مشخص شده (مثلاً GET یا POST) ارسال میشود:
for key, value in arguments.items():
if key in path_params:
path = path.replace("{" + key + "}", str(value))
elif key in query_params:
query[key] = value
url = base_url.rstrip("/") + path
async with httpx.AsyncClient(timeout=timeout) as client:
resp = await client.request(spec.method, url, params=query, headers=headers)
یک نکته حیاتی در پیادهسازی: در حالت stdio — که توسط Claude Desktop و Claude Code استفاده میشود — خروجی استاندارد (stdout) در واقع کانال انتقال پروتکل است. یک دستور print() ساده در کد میتواند کل جریان داده را مخدوش کند و باعث شود کلاینت بهطور بیصدا، صفر ابزار را نمایش دهد. بنابراین تمام گزارشهای تشخیصی (Diagnostics) باید به stderr ارسال شوند.
نردههای ایمنی و حفاظها
برای جلوگیری از اینکه یک مدل زبانی بهطور تصادفی دادههای محیط تولید (Production) را حذف کند، سیستم بهصورت پیشفرض ایمن طراحی شده است. تنها نقاط اتصال GET به ابزار تبدیل میشوند. اکسپوز کردن خودکار تمام سطوح CRUD، بهخصوص عملیات DELETE، ریسک بزرگی است که میتواند منجر به حذف ردیفهای دیتابیس توسط یک عامل شود. عملیات نوشتن صرفاً بهصورت اختیاری و از طریق یک لیست پیکربندی فعال میشوند: INCLUDE_METHODS = ["GET", "POST"].
توسعهدهندگان میتوانند نقاط اتصال حساس یا پرهزینه — مانند گزارشات سنگین یا تجمیع صورتحسابها — را با استفاده از دکوراتور @extend_schema(exclude=True) پنهان کنند. این کار باعث میشود نقطه اتصال هم از مستندات عمومی و هم از لیست ابزارهای هوش مصنوعی در یک مرحله حذف شود.
چالشهای احراز هویت
احراز هویت «بخشی است که میزند» (The part that bites). هر درخواست خروجی برای مفید بودن نیاز به اعتبارنامه (توکن، Bearer یا هدر سفارشی) دارد. با این حال، پیادهسازی مرجع فعلی از اعتبارنامههای استاتیک استفاده میکند. یک نسخه در سطح استقرار (Deployment-grade) نیازمند این است که اعتبارنامههای کاربرِ فراخوان را پاس دهد تا هر فراخوانی ابزار با مجوزهای خاص همان کاربر اجرا شود، نه با یک حساب سرویس (Service Account) مشترک. آموزشهایی که به یک توکن استاتیک واحد اشاره میکنند، این «سقفِ مشکل» را حل نمیکنند.
نیمه سخت: استدلال عامل
ساخت ابزارها تنها یک بعدازظهر زمان میبرد، اما قرار دادن یک عامل (Agent) پیش روی آنها، لایهی جدیدی از مشکلات مهندسی را آشکار میکند. تولید ابزار صرفاً لایهی انتقال (Transport Layer) است. یک طرحواره خام، برای هر عملیات یک ابزار میسازد، اما این سطح از جزئیات اغلب بیش از حد زیاد (Too Granular) است. برای مثال، اگر کاربر بپرسد «آیا آخرین سفارش آنها هنوز قابل ارسال است؟»، مدل باید تصمیم بگیرد که آیا از orders_list استفاده کند، یا orders_retrieve و یا products_retrieve و این کار را با چه ترتیبی انجام دهد.

برای حل این مشکل، توسعهدهندگان باید یک لایه نازک از «غنیسازی معنایی» اضافه کنند — ایندکسی از آنچه هر ابزار نیاز دارد و چه چیزی تولید میکند — تا عامل بتواند روی «قابلیتها» استدلال کند (مثلاً: «من به چیزی نیاز دارم که ID سفارش را برگرداند») بهجای اینکه فقط نامها را تطبیق دهد.
موفقیت در دنیای واقعی نیازمند یک حلقه استدلالی به سبک ReAct است: استدلال $\longrightarrow$ فراخوانی ابزار $\longrightarrow$ افزودن نتیجه به تاریخچه گفتگو $\longrightarrow$ استدلال مجدد. این تاریخچه پیامهای پایدار به مدل اجازه میدهد تا تکهای از داده، مانند ID مشتری را از مرحله اول به مرحله سوم منتقل کند.

بازیابی خطا و قابلیت اطمینان
تلاشهای مجدد (Retries) عمومی برای خطاهای معنایی کافی نیستند. اگر فراخوانی به دلیل نبود یک فیلد اجباری شکست بخورد، تکرار همان درخواست بدون تغییر، دقیقاً منجر به همان شکست میشود. معماری پیشنهادی، شکستها را به استراتژیهای بازیابی خاص تقسیم میکند:
- فیلدهای گمشده: سیستم دادههای لازم را از بافتار گفتگو استخراج میکند (مثلاً استخراج نام کاربری از یک آدرس ایمیل).
- شناسههای اشتباه: اگر مدل یک نام قابل خواندن توسط انسان (مثلاً «آخرین سفارش باب») را در فیلدی که نیاز به ID دارد ارسال کند، سیستم خطا را متوقف کرده، از یک ابزار جستوجو برای یافتن ID استفاده میکند و سپس درخواست اصلی را تکرار میکند.
- دادههای بدشکل: سیستم فرمتهای اشتباه را پیش از ارسال مجدد به API، به شکل صحیح تغییر میدهد.
این استراتژیهای رتبهبندی شده و قابل جایگزینی تضمین میکنند که بخش بزرگی از شکستهای تلاش اول، بدون نیاز به بازگشت به LLM اصلاح شوند که این کار سیستم را سریعتر و ارزانتر میکند.
بقا در لایه مدل
در نهایت، معماری باید با شکستهای لایه مدل مقابله کند. محدودیتهای نرخ درخواست (Rate Limits) و اتمام سهمیه (خطاهای HTTP 429 یا 402) در محیط تولید بسیار رایج هستند. تکرار درخواست برای ارائهدهندهای که سهمیهاش تمام شده، فقط اتلاف زمان است. راهکار این است که یک لایه انتزاعی روی ارائهدهنده قرار گیرد، خطاهای سهمیه را از نوسانات گذرا تفکیک کند و یک سیستم Failover (جابجایی) از ارائهدهنده اصلی به جایگزین پیاده کند.
این جابجایی نشاندهنده حرکت به سمت «مهندسی دفاعی» است. اصل محوری این است: دادهها را استخراج کن، هرگز آنها را اختراع نکن. تغییر فرمت مقداری که کاربر ارائه داده قابل قبول است، اما ساختن دادههای جعلی روشی است که عاملها پاسخهای «با اعتمادبهنفس اما غلط» میدهند. با مسدود کردن عملیات تخریبی در زمان تولید و طبقهبندی خطاها پیش از تکرار، توسعهدهندگان یک افسار قابلاعتماد برای مؤلفهای میسازند که در غیر این صورت غیرقابلپیشبینی است.
راهنمای پیادهسازی
اگر میخواهید همین امروز این سیستم را مستقر کنید، میتوانید از بستههای پشتیبانیشده مانند django-mcp-server، openapi-to-mcp، openapi-mcp-generator یا django-rest-framework-mcp استفاده کنید تا از سیمکشی دستی بینیاز شوید.
برای کسانی که میخواهند آزمایش کنند، مخزن مرجع (https://github.com/Shanahan-Suresh/django-openapi-mcp) یک نمونه قابل اجرا ارائه میدهد. پس از کلون کردن و نصب بسته، موارد زیر را به settings.py جنگو اضافه کنید:
INSTALLED_APPS = [..., "rest_framework", "drf_spectacular", "django_openapi_mcp"]
DJANGO_OPENAPI_MCP = {"BASE_URL": "http://127.0.0.1:8000"}
اجرای دستور python manage.py run_mcp_server --transport stdio و متصل کردن آن به claude_desktop_config.json به Claude اجازه میدهد با یک فروشگاه نمونه (شامل محصولات و سفارشات با فیلتر in_stock) تعامل کند. پرامپتی مانند «لیست تمام محصولاتی که در انبار موجود هستند را بیاور» ابزار products_list را با پارامتر in_stock=true فعال میکند و یک پاسخ JSON برمیگرداند که Claude آن را در قالب یک جدول نمایش میدهد.
اما داستان سختافزاری این تحول حتی شگفتانگیزتر است — به تحلیل ما دربارهی تراشههای Blackwell مراجعه کنید.




گفتگو