پروتکل زمینه مدل (MCP) به سرعت در حال تبدیل شدن به استاندارد عملی برای اتصال مدلهای زبانی بزرگ (LLMs) به منابع داده و ابزارهای خارجی است. در حالی که بخش زیادی از بحثهای اولیه بر ساخت MCP *سرورها* که قابلیتهای خاصی را ارائه میدهند، متمرکز بوده است، قدرت واقعی اکوسیستم در کلاینت MCP نهفته است. کلاینت پلای است که به برنامه یا IDE شما امکان میدهد بهصورت یکپارچه این سرورها را کشف، به آنها متصل شود و با آنها تعامل برقرار کند.
در این پست، ما معماری یک کلاینت MCP را بررسی خواهیم کرد، نحوه مدیریت لایههای انتقال را توضیح میدهیم و نمونههای کد عملی برای ساخت آن از صفر ارائه خواهیم داد.
درک رابطه کلاینت-سرور
در هسته خود، یک کلاینت MCP به عنوان واسطه بین رابط کاربری (مانند یک برنامه LLM) و سرورهای مختلف MCP عمل میکند. کلاینت مسئول موارد زیر است:
- کشف: یافتن ابزارها و منابع در دسترس که توسط سرورهای متصل ارائه میشوند.
- ارتباط: مدیریت چرخه حیات اتصال، از جمله عبور پیامهای JSON-RPC 2.0.
- اجرا: آغاز فراخوانی ابزارها و مدیریت نتایج بازگشتی از سرور.
برخلاف کلاینتهای API سنتی، کلاینتهای MCP از عملکرد خاص سرور بیتفاوت هستند. آنها به یک اسکیما استاندارد برای درک آنچه سرور در زمان اجرا ارائه میدهد، تکیه میکنند. این الگوی "کشف پویا" به یک کلاینت واحد امکان میدهد همزمان به یک سرور سیستم فایل، یک سرور GitHub و یک سرور پایگاه داده متصل شود، بدون نیاز به منطق سختکد شده برای هر کدام.
لایههای انتقال: چگونه با هم صحبت میکنند
مشخصات MCP دو مکانیزم انتقال اصلی برای کلاینتها را تعریف میکند:
- ورودی/خروجی استاندارد (Stdio): برای ارتباط محلی استفاده میشود. کلاینت سرور را به عنوان یک زیرفرآیند ایجاد میکند و از طریق جریانهای استاندارد ارتباط برقرار میکند. این رایجترین روش برای توسعه محلی و برنامههای دسکتاپ است.
- رویدادهای ارسالشده توسط سرور (SSE): برای ارتباط از راه دور از طریق HTTP استفاده میشود. سرور یک نقطه پایانی (endpoint) را ارائه میدهد که رویدادها را به کلاینت پخش میکند و امکان اتصالات پایدار را فراتر از مرزهای شبکه فراهم میآورد.
برای اکثر برنامههای اولویتمحور محلی، Stdio به دلیل سادگی و عدم وجود بار شبکه ترجیح داده میشود. کلاینت فقط نیاز دارد چرخه حیات فرآیند را مدیریت کند و پیامهای JSON را پخش کند.
پیادهسازی یک کلاینت MCP پایه در TypeScript
در حالی که SDKهای MCP پوششهای سطح بالا ارائه میدهند، درک تعاملات سطح پایین در عیبیابی و سفارشیسازی رفتار کمک میکند. در زیر یک نمونه سادهشده از نحوه آغاز اتصال کلاینت و فهرست ابزارهای در دسترس با استفاده از SDK TypeScript آورده شده است.
import { Client } from "@modelcontextprotocol/sdk/client";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio";
const main = async () => {
// 1. تعریف لایه انتقال
const transport = new StdioClientTransport({
command: "node",
args: ["path/to/mcp/server.js"],
});
// 2. نمونهسازی کلاینت
const client = new Client(
{
name: "MyAdvancedClient",
version: "1.0.0",
},
{
capabilities: {
// اعلام آنچه کلاینت پشتیبانی میکند (مثلاً prompts, roots)
prompts: {},
roots: {},
},
}
);
try {
// 3. اتصال به سرور
await client.connect(transport);
console.log("Connected to MCP server");
// 4. کشف ابزارهای در دسترس
const toolsResponse = await client.listTools();
console.log("Available Tools:");
toolsResponse.tools.forEach((tool) => {
console.log(`- ${tool.name}: ${tool.description}`);
});
// 5. فراخوانی یک ابزار (نمونه)
// const result = await client.callTool({ name: "search", arguments: { query: "test" } });
// console.log(result.content);
} catch (error) {
console.error("Error:", error);
} finally {
// 6. پاکسازی اتصال
await client.close();
}
};
main();
نکته کلیدی: به جداسازی صریح Client و Transport توجه کنید. این طراحی به شما امکان میدهد روش ارتباطی را (مثلاً از Stdio به SSE) بدون تغییر منطق اصلی برنامه کلاینت خود تعویض کنید.
مدیریت Prompts و Roots
کلاینتهای مدرن MCP فقط ابزارها را فراخوانی نمیکنند؛ آنها همچنین Prompts و Roots را مدیریت میکنند.
- Prompts: اینها قالبهای از پیش تعریف شدهای هستند که توسط سرور ارائه میشوند. کلاینت میتواند اینها را دریافت کرده و در زمینه LLM تزریق کند. برای مثال، یک سرور اسناد حقوقی ممکن است یک prompt "بازبینی قرارداد" ارائه دهد که شامل دستورالعملها و قواعد قالببندی خاصی است.
- Roots: اینها به کلاینت امکان میدهند به سرور بگوید چه فایلها یا پوشههایی در دسترس هستند. این برای سرورهای سیستم فایل حیاتی است. کلاینت یک لیست از URIهای ریشه ارسال میکند و سرور از این محدوده برای محدود کردن عملیات خود استفاده میکند، که اطمینان از امنیت و مرتبط بودن را تضمین میکند.
پیادهسازی مناسب مدیریت Root برای امنیت حیاتی است. هرگز کل سیستم فایل را به یک سرور MCP آشکار نکنید. همیشه roots کلاینت را به پوشههای پروژه خاص محدود کنید.
بهترین روشها برای توسعه کلاینت
- مقاومت در برابر خطا: سرورهای MCP ممکن است کرش کنند یا زمانبندی آنها تمام شود. همیشه منطق اتصال را در بلوکهای try-catch قرار دهید و مکانیزمهای تکرار (retry) برای شکستهای گذرا پیادهسازی کنید.
- مذاکره قابلیتها: در مرحله راهاندازی، کلاینت و سرور قابلیتهای خود را مبادله میکنند. اطمینان حاصل کنید که کلاینت شما فقط آنچه را که واقعاً پشتیبانی میکند اعلام میکند تا از خطاهای غیرمنتظره جلوگیری شود.
- مدیریت ناهمگام: از آنجا که فراخوانی ابزارها میتواند طولانی باشد (مثلاً اجرای یک کوئری پایگاه داده)، بهطور سختگیرانه از الگوهای async/await استفاده کنید. هرگز رشته اصلی را مسدود نکنید.
- لاگنویسی: لاگنویسی جزئی برای پیامهای JSON-RPC پیادهسازی کنید. از آنجا که MCP از یک جریان دوطرفه استفاده میکند، لاگنویسی هم پیامهای ارسالی و هم دریافتی برای عیبیابی تعاملات پیچیده حیاتی است.
نتیجهگیری
ساخت یک کلاینت MCP بیشتر از ارسال درخواستهای HTTP است؛ این درباره هماهنگسازی یک رابط پویا، امن و استاندارد بین برنامه هوش مصنوعی شما و دنیای واقعی است. با بهرهگیری از SDKها و پایبندی به مدلهای انتقال و قابلیت پروتکل، میتوانید برنامههای مستحکمی ایجاد کنید که هم قابل توسعه و هم قابل نگهداری هستند.
با بلوغ اکوسیستم، انتظار میرود ویژگیهای کلاینت پیشرفتهتری را مشاهده کنیم، مانند تجمیع چند سرور، که در آن یک کلاینت واحد اتصالات به دهها سرور تخصصی را مدیریت میکند و یک پنجره زمینه یکپارچه برای LLM فراهم میآورد. امروز کلاینت خود را بسازید و تمام پتانسیل پروتکل زمینه مدل را آزاد کنید.