اتصال MCP به ایجنت در نمایشهای آموزشی ساده به نظر میرسد؛ کلاینت به سرور وصل میشود، ابزارها را پیدا میکند و یکی را صدا میزند. اما نمونهای که ابزار را پیدا میکند هنوز یک اتصال قابلاعتماد نیست. باید شکل ورودی، نتیجه، خطا و حدود دسترسی را هم بررسی کنیم.
در قسمت قبل با پروتکل MCP آشنا شدیم. در این قسمت از مجموعهی آموزش هوش مصنوعی تخته سبز، از زاویهی مصرفکنندهی ابزار به آن نگاه میکنیم. یک سرور MCP کوچک برای فهرست دورهها میسازیم، کلاینتی مینویسیم که آن را کشف و صدا میزند و بعد قابلیتهای پیشرفتهی MCP برای کارهای طولانی را میبینیم. در پایان خطاهای سرویس را مدیریت میکنیم.
ساخت یک سرور MCP کوچک
فرض کنید فهرست دورههای یک آموزشگاه در سرویس جداگانهای است. میخواهیم این فهرست را از طریق MCP در اختیار دستیار بگذاریم. SDK رسمی پایتون MCP این کار را با کلاس FastMCP بسیار ساده کرده است.
تعریف ابزار با FastMCP
کد زیر یک سرور MCP با یک ابزار جستجو میسازد. تابع پایتون با دکوراتور tool به ابزار MCP تبدیل میشود:
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("courses")
COURSES = [
{"id": "PY-101", "title": "پایتون مقدماتی", "level": "beginner"},
{"id": "DS-201", "title": "تحلیل داده با pandas", "level": "intermediate"},
]
@mcp.tool()
def search_courses(level: str) -> list[dict]:
"""Search courses by level. level must be one of: beginner, intermediate, advanced."""
if level not in {"beginner", "intermediate", "advanced"}:
raise ValueError("level must be beginner, intermediate or advanced")
return [c for c in COURSES if c["level"] == level]
if __name__ == "__main__":
mcp.run()نام تابع، docstring و نوع ورودی خودکار به طرحوارهی ابزار تبدیل میشوند. همان اصولی که در قسمت ابزار ایجنت دیدیم اینجا هم صدق میکند: نام گویا، توضیح دقیق و مقدارهای مجاز روشن.
ابزار فقطخواندنی است
به یک نکتهی طراحی دقت کنید. این سرور فقط ابزار جستجو دارد و هیچ ابزاری برای تغییر داده ندارد. اگر روزی ابزار ثبتنام اضافه شد، بهتر است در سرور جداگانهای با احراز هویت و سطح دسترسی متفاوت باشد.
جدا کردن ابزارهای خواندنی و تغییردهنده در سرورهای مختلف، کنترل دسترسی را ساده میکند. دستیار عمومی فقط به سرور خواندنی وصل میشود؛ دستیار کارمندان به هر دو.
کلاینت؛ کشف و فراخوانی ابزار
حالا کلاینتی مینویسیم که به این سرور وصل شود، ابزارها را کشف کند و یکی را صدا بزند. SDK پایتون برای این کار کلاس ClientSession را دارد.
اتصال، کشف و فراخوانی
کد زیر سرور را بهصورت یک پردازهی محلی اجرا میکند و از طریق ورودی و خروجی استاندارد به آن وصل میشود:
import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
params = StdioServerParameters(command="python", args=["courses_server.py"])
async def main():
async with stdio_client(params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
tools = await session.list_tools()
print([t.name for t in tools.tools])
result = await session.call_tool("search_courses", {"level": "beginner"})
print(result.content)
asyncio.run(main())سه قدم اصلی در این کد هست. initialize جلسه را آغاز میکند و قابلیتهای دو طرف را مبادله میکند. list_tools فهرست ابزارها و طرحوارهی ورودی هر کدام را برمیگرداند. call_tool هم ابزار را با آرگومانها صدا میزند.
وصل کردن به ایجنت
در یک ایجنت واقعی، فهرست ابزارها بهجای چاپ شدن، به مدل داده میشود. توضیح و طرحوارهی هر ابزار MCP مستقیم به قالب ابزار مدل تبدیل میشود. وقتی مدل تصمیم گرفت ابزاری را صدا بزند، کلاینت همان call_tool را اجرا و نتیجه را به مدل برمیگرداند.
بیشتر فریمورکهای ایجنت این تبدیل را آماده دارند. در قسمت ابزارهای smolagents دیدیم ToolCollection.from_mcp همهی ابزارهای یک سرور را یکجا وارد میکند. اما دانستن سازوکار زیرین کمک میکند وقتی مشکلی پیش آمد، بدانید کجا را بررسی کنید.
MCP برای کارهای طولانی و ایجنتگونه
یک تصور قدیمی این است که MCP فقط برای ابزارهای ساده و کوتاه مناسب است. اما مشخصات MCP قابلیتهایی اضافه کرده که ساخت کارهای طولانی و ایجنتگونه را ممکن میکند. چهار قابلیت اصلی وجود دارد.
گزارش پیشرفت و نتیجهی جزئی
الگوی سادهی درخواست و پاسخ برای کارهای طولانی مناسب نیست. کاربری که سی ثانیه منتظر است، باید بداند چه اتفاقی میافتد. MCP اجازه میدهد سرور در طول اجرا اعلان پیشرفت بفرستد:
for i, step in enumerate(steps):
await ctx.session.send_progress_notification(
progress_token=ctx.request_id, progress=i * 25, total=100, message=step,
)کلاینت این اعلانها را دریافت و به کاربر نشان میدهد. همان حالت «انتظار» که در قسمت تجربهی کاربری گفتیم باید طراحی شود، اینجا از خود پروتکل میآید.
درخواست تأیید در میانهی کار
قابلیت الیسیتیشن (Elicitation) به سرور اجازه میدهد در میانهی اجرا از کاربر ورودی یا تأیید بخواهد. مثال درسنامه یک ایجنت سفر است که پیش از رزرو، تأیید قیمت را میخواهد:
result = await ctx.session.elicit(
message=f"هزینهی تقریبی سفر ۱۲۰۰ دلار است. تأیید میکنید؟",
requestedSchema=PriceConfirmation.model_json_schema(),
)
if result.action == "accept":
... # ادامهی رزروکاربر میتواند بپذیرد، رد کند یا لغو کند. این همان تأیید انسانی است که در قسمت سیوسوم طراحی کردیم؛ این بار از طریق پروتکل استاندارد.
کمک مدل و ازسرگیری جلسه
قابلیت نمونهگیری (Sampling) به سرور اجازه میدهد از مدل زبانی کلاینت کمک بخواهد؛ مثلاً برای خلاصه کردن نتیجهای که پیدا کرده است. به این ترتیب سرور لازم نیست مدل خودش را داشته باشد.
قابلیت ازسرگیری هم کارهای طولانی را در برابر قطع ارتباط مقاوم میکند. سرور رویدادها را در یک مخزن رویداد نگه میدارد و کلاینت پس از اتصال دوباره، با شناسهی آخرین رویدادی که دیده، ادامهی کار را میگیرد. برای ماندگاری نتیجهها پس از راهاندازی دوبارهی سرور هم میتوان نتیجه را بهصورت لینک منبع برگرداند.
جدول زیر چهار قابلیت و کاربرد هر کدام را خلاصه میکند.
| قابلیت | کاربرد | نمونه در دستیار آموزشی |
|---|---|---|
| گزارش پیشرفت | اطلاع از وضعیت کار طولانی | «در حال خواندن سرفصل ۳ از ۱۰» |
| الیسیتیشن | ورودی یا تأیید انسان در میانهی کار | تأیید ثبتنام پیش از پرداخت |
| نمونهگیری | کمک مدل کلاینت به سرور | خلاصهی سرفصلها با مدل کلاینت |
| ازسرگیری | ادامه پس از قطع ارتباط | ادامهی ساخت گزارش پس از قطع شبکه |
مدیریت خطای سرویس
اتصال قابلاعتماد یعنی رفتار روشن در موقعیتهای ناخوشایند. سه موقعیت را باید جداگانه طراحی کرد: نبود نتیجه، قطع ارتباط و تغییر ساختار پاسخ.
سه موقعیت خطا
نبود نتیجه سادهترین حالت است؛ ابزار درست اجرا شد اما چیزی پیدا نکرد. دستیار باید صادقانه بگوید «دورهای با این مشخصات پیدا نشد» و شاید پیشنهاد دیگری بدهد؛ نه اینکه دورهای بسازد.
قطع ارتباط، یعنی سرور در دسترس نیست. دستیار باید با سقف زمان و تعداد محدودی تلاش دوباره واکنش نشان دهد و اگر نشد، اعلام کند. تغییر ساختار پاسخ خطرناکترین حالت است؛ سرور بهروزرسانی شده و فیلدها عوض شدهاند. اگر کلاینت پاسخ را بدون اعتبارسنجی بخواند، ممکن است دادهی اشتباه به مدل برسد. طرحوارهی پاسخ را هم مثل ورودی اعتبارسنجی کنید.
دادهی قدیمی بدون اعلام
یک خطای ظریف هم هست. فرض کنید دستیار نتیجهی جستجوی قبلی را در حافظهی گفتوگو دارد. سرور قطع میشود و دستیار بدون اینکه بگوید، از همان دادهی قدیمی جواب میدهد. کاربر فکر میکند اطلاعات بهروز است، در حالی که ظرفیت دوره ساعتها پیش پر شده است.
اگر دستیار از دادهی ذخیرهشده استفاده میکند، باید زمان آخرین بهروزرسانی را صریحاً بگوید. نمودار زیر چرخهی کامل اتصال را از آغاز جلسه تا مدیریت خطا نشان میدهد.

سناریوی عملی؛ فهرست دورهها در سرویس جدا
فهرست دورهها در یک سرویس جداگانه قرار دارد و دستیار باید از طریق MCP به آن وصل شود. ورودی آزمون آدرس سرویس، شرح ابزارها و دادهی آزمایشی دورههاست. اقدام مورد بررسی، کشف ابزار و اجرای درخواست با ورودی معتبر و نامعتبر است.
معیار پذیرش
معیار پذیرش رفتار دستیار در سه موقعیت است: نبود نتیجه، قطع ارتباط و تغییر ساختار پاسخ. هر سه را عمداً بازسازی کنید. سطح پایهای مثل «expert» بفرستید تا خطای ورودی را ببینید. سرور را وسط گفتوگو متوقف کنید. یک فیلد را در پاسخ سرور تغییر نام دهید.
نمونهی شکست
شکستی که باید عمداً دنبالش باشید این است: ادامه دادن گفتوگو با دادهی قدیمی بدون اعلام شکست بهروزرسانی. سرور را پس از اولین جستجو متوقف کنید و دوباره دربارهی همان دورهها بپرسید. آیا دستیار میگوید اطلاعات بهروز در دسترس نیست، یا بیصدا از حافظه جواب میدهد؟
تمرین عملی؛ اتصال آزمایشی مستند
خروجی این تمرین یک اتصال آزمایشی مستند همراه سناریوهای خطای سرویس است:
- سرور
coursesرا با FastMCP بسازید و کلاینت را به آن وصل کنید. - ابزارها را به ایجنت خود بدهید و یک پرسش واقعی را از طریق MCP جواب دهید.
- سه سناریوی خطا را بازسازی و رفتار دستیار را در هر کدام ثبت کنید.
مشخص کنید کدام بخش را واقعاً اجرا کردهاید و کدام هنوز فرض است.
سخن پایانی
اتصال MCP به ایجنت با چند خط کد شروع میشود؛ یک سرور FastMCP و یک کلاینت که ابزار را کشف و صدا میزند. اما اتصال قابلاعتماد به طراحی بیشتری نیاز دارد. ابزارهای خواندنی و تغییردهنده را جدا کنید، از قابلیتهای پیشرفتهی MCP مثل گزارش پیشرفت، درخواست تأیید و ازسرگیری برای کارهای طولانی استفاده کنید و برای نبود نتیجه، قطع ارتباط و تغییر ساختار پاسخ رفتار روشن داشته باشید. مهمتر از همه، هرگز دادهی قدیمی را بیصدا جای دادهی تازه ننشانید.
در قسمت بعد مهندسی زمینه را میبینیم؛ اینکه در هر مرحله چه اطلاعاتی به مدل بدهیم.
این آموزش بر پایهی راهنمای Building Agent-to-Agent Communication Systems with MCP از مجموعهی آزاد AI Agents for Beginners مایکروسافت (مجوز MIT) به فارسی بازنویسی و تکمیل شده است.
پرسشهای پرتکرار
چطور یک سرور MCP ساده با پایتون بسازیم؟
با SDK رسمی پایتون و کلاس FastMCP. یک نمونه FastMCP میسازید، تابعهای پایتون را با دکوراتور tool بهعنوان ابزار ثبت میکنید و سرور را اجرا میکنید. نام، توضیح و نوع ورودی تابع خودکار به طرحوارهی ابزار تبدیل میشود.
آیا MCP فقط برای ابزارهای ساده و کوتاه است؟
نه. مشخصات MCP قابلیتهایی برای کارهای طولانی و ایجنتگونه هم دارد؛ ارسال پیشرفت در طول اجرا، درخواست ورودی از کاربر در میانهی کار، درخواست کمک از مدل و ازسرگیری جلسه پس از قطع ارتباط.
الیسیتیشن (Elicitation) در MCP چیست؟
قابلیتی که به سرور اجازه میدهد در میانهی اجرای یک ابزار از کاربر ورودی یا تأیید بخواهد؛ مثلاً تأیید قیمت پیش از رزرو. کاربر میتواند بپذیرد، رد کند یا لغو کند و سرور بر اساس پاسخ ادامه میدهد.
اگر سرور MCP در دسترس نبود دستیار چه کند؟
باید خطا را صادقانه به کاربر بگوید و از دادهی قدیمی بهجای دادهی تازه استفاده نکند. اگر از دادهی ذخیرهشده استفاده میکند، زمان آخرین بهروزرسانی را صریحاً اعلام کند.







دیدگاهها
هنوز دیدگاهی ثبت نشده است. شروعکننده باشید — پرسش و اصلاح را با آغوش باز میپذیریم.