MCP چیست؟ ساخت سرور Model Context Protocol با سی‌شارپ

پاسخ کوتاه: Model Context Protocol یا MCP یک استاندارد باز است که Anthropic در نوامبر ۲۰۲۴ معرفی کرد، برای وصل کردن اپ‌های هوش مصنوعی به ابزارها و داده‌ها. شما یک سرور MCP می‌نویسید که چند قابلیت را در اختیار می‌گذارد (تابع برای صدا زدن، داده برای خواندن، قالب پرامپت) و هر کلاینت MCP، مثل Cursor، OpenCode یا دستیار یک IDE، می‌تواند آن‌ها را پیدا کند و استفاده کند. کاری که یک استاندارد مشترک API برای سرویس‌ها می‌کند، MCP برای اتصال‌های هوش مصنوعی می‌کند: اتصال را یک بار بنویسید و از همه‌ی اپ‌های سازگار استفاده کنید. در دات‌نت، پکیج رسمی ModelContextProtocol یک کلاس استاتیک را در حدود سی خط به سرور MCP تبدیل می‌کند.

یک مثال واقعی: «وضعیت سفارش AB12CD34EF چیست؟»

فروشگاهی دارید و بیشتر وقتتان در ادیتور می‌گذرد. چند بار در روز می‌خواهید وضعیت یک سفارش، یا تعداد سفارش‌های در انتظار را بدانید. بدون MCP پنل ادمین را باز می‌کنید یا داده را دستی در چت کپی می‌کنید.

با یک سرور MCP که دو ابزار فقط‌خواندنی دارد، get_order_status و count_orders، به زبان ساده از دستیار هوش مصنوعی‌تان می‌پرسید و خودش ابزار را صدا می‌زند. همین سرور بدون تغییر یک خط در Cursor، در OpenCode و در هر کلاینت MCP دیگری کار می‌کند.

اجزای اصلی

یک سرور MCP می‌تواند سه نوع چیز ارائه کند:

  • Tools (ابزارها): تابع‌هایی که مدل می‌تواند صدا بزند، با نام، توضیح و یک JSON Schema برای آرگومان‌ها. بیشتر سرورها با همین شروع می‌کنند.
  • Resources (منابع): داده‌ای که کلاینت می‌تواند بخواند و با یک URI شناخته می‌شود (یک فایل، یک رکورد، یک گزارش).
  • Prompts (پرامپت‌ها): قالب‌های پرامپت قابل استفاده‌ی دوباره که کاربر در کلاینت انتخابشان می‌کند.

پیام‌ها JSON-RPC 2.0 هستند. سرور از طریق یک انتقال (Transport) با کلاینت حرف می‌زند: stdio (کلاینت سرور شما را به‌عنوان یک پروسس اجرا می‌کند و از stdin/stdout حرف می‌زند؛ مناسب ابزارهای محلی) یا Streamable HTTP (سرور به‌صورت یک سرویس وب اجرا می‌شود؛ برای استفاده‌ی اشتراکی یا از راه دور).

جریان همیشه یکی است: کلاینت وصل می‌شود، از سرور می‌پرسد چه ارائه می‌کند (tools/list)، این ابزارها را به مدل نشان می‌دهد، و وقتی مدل تصمیم به استفاده از یکی گرفت، کلاینت tools/call را می‌فرستد و نتیجه را به مدل برمی‌گرداند.

کد قابل‌اجرا: سرور MCP با سی‌شارپ

یک برنامه‌ی کنسول بسازید (dotnet new console)، پکیج‌های ModelContextProtocol و Microsoft.Extensions.Hosting را با dotnet add package اضافه کنید و Program.cs را جایگزین کنید:

using System.ComponentModel;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using ModelContextProtocol.Server;

var builder = Host.CreateApplicationBuilder(args);

// stdout carries the MCP protocol itself, so every log line must go to stderr.
builder.Logging.AddConsole(options => options.LogToStandardErrorThreshold = LogLevel.Trace);

builder.Services
    .AddMcpServer()
    .WithStdioServerTransport()
    .WithToolsFromAssembly();

await builder.Build().RunAsync();

[McpServerToolType]
public static class OrderTools
{
    // A stand-in for your database or internal API.
    private static readonly Dictionary<string, (string Status, string Product)> Orders = new()
    {
        ["AB12CD34EF"] = ("Approved", "DiskWatch"),
        ["GH56JK78MN"] = ("Pending", "Peyk"),
    };

    [McpServerTool, Description("Returns the status and product of a shop order. Read-only.")]
    public static string GetOrderStatus([Description("The 10-character order code, e.g. AB12CD34EF.")] string code) =>
        Orders.TryGetValue(code.Trim().ToUpperInvariant(), out var order)
            ? $"Order {code}: {order.Status} ({order.Product})"
            : $"No order with code {code}.";

    [McpServerTool, Description("Counts orders by status. Read-only.")]
    public static string CountOrders() =>
        string.Join(", ", Orders.Values.GroupBy(o => o.Status).Select(g => $"{g.Key}: {g.Count()}"));
}

بخش‌های مهم:

  • [McpServerToolType] و [McpServerTool] کلاس و متدهایی را که باید ارائه شوند علامت می‌زنند. WithToolsFromAssembly() پیدایشان می‌کند و SDK آن‌ها را با نام snake_case منتشر می‌کند (get_order_status، count_orders).
  • [Description] همان مستنداتی است که مدل می‌خواند. مدل از روی توضیح تصمیم می‌گیرد کی ابزاری را صدا بزند؛ پس بگویید چه می‌کند، چه برمی‌گرداند و آیا چیزی را تغییر می‌دهد.
  • توضیح پارامترها به JSON Schema تبدیل می‌شود که کلاینت به مدل می‌فرستد. پارامترهای تایپ‌دار (string، int، Enum) اعتبارسنجی را مجانی به شما می‌دهند.
  • لاگ‌ها به stderr می‌روند. در انتقال stdio، هر چیزی که روی stdout چاپ شود و جزو پروتکل نباشد اتصال را خراب می‌کند. این رایج‌ترین باگ اول کار است.

وصل کردن به کلاینت

برای OpenCode، سرور را با دستوری که اجرایش می‌کند ثبت کنید:

opencode mcp add orders -- dotnet run --project /path/to/OrderServer

بعد بپرسید «وضعیت سفارش AB12CD34EF چیست؟» و فراخوانی ابزار را تأیید کنید. Cursor و کلاینت‌های دیگر همین دستور و آرگومان‌ها را در تنظیمات MCP خود می‌گیرند. بدون هیچ اپ هوش مصنوعی هم می‌شود تستش کرد: پیام‌های JSON-RPC initialize، tools/list و tools/call را خودتان به پروسس بفرستید و پاسخ‌ها را بخوانید؛ راه خوبی برای دیدن اینکه پروتکل چقدر ساده است.

امنیت: ابزارها را مثل یک API عمومی ببینید

یک ابزار MCP یک API است که مدل تصمیم به صدا زدنش می‌گیرد، با متنی که ممکن است از کاربر، ایمیل یا صفحه‌ی وب آمده باشد. همین‌طور طراحی‌اش کنید:

  • فقط‌خواندنی شروع کنید. ابزار نوشتنی را فقط وقتی نیاز روشن است اضافه کنید و محدودش نگه دارید (mark_order_shipped، نه run_sql).
  • کمترین دسترسی. یک کاربر دیتابیس یا کلید API جدا با حداقل دسترسی به سرور بدهید.
  • هر آرگومان را اعتبارسنجی کنید، انگار از اینترنت آمده؛ چون به‌طور غیرمستقیم ممکن است آمده باشد.
  • انسان را در حلقه نگه دارید برای هر کار برگشت‌ناپذیر. کلاینت‌های MCP پیش از صدا زدن ابزار تأیید می‌گیرند؛ کاربران را تشویق نکنید این را برای ابزارهای نوشتنی خاموش کنند.
  • فقط از سرورهای مورد اعتماد استفاده کنید. یک سرور MCP شخص ثالث با دسترسی‌های شما اجرا می‌شود.

مزایا و معایب MCP

مزایا

  • یک سرور در اپ‌های هوش مصنوعی زیادی کار می‌کند؛ بدون پلاگین جدا برای هر اپ.
  • تفکیک روشن: سرور شما مالک دسترسی به داده و مجوزهاست، کلاینت مالک مدل و تجربه‌ی کاربر.
  • با SDK رسمی سی‌شارپ، سرور یک اپ معمولی و کوچک دات‌نت است که مثل بقیه تست و مستقر می‌شود.

معایب

  • یک جزء متحرک دیگر که باید امن، مستقر و پایش شود، به‌خصوص سرورهای HTTP راه دور.
  • توضیح ابزارها در عمل پرامپت است؛ توضیح مبهم یعنی فراخوانی اشتباه یا فراخوانی‌نشدن.
  • ابزارهای زیاد هم‌زمان کانتکست مصرف می‌کنند و مدل را گیج می‌کنند؛ چند ابزار با نام خوب ارائه کنید.

جایگاه MCP

MCP روش استاندارد دادن ابزار به مدل است. حلقه‌ای که تصمیم می‌گیرد کی صدایشان بزند در ایجنت‌ها و فراخوانی ابزار در دات‌نت آمده و کل مسیر در نقشه‌ی راه AI Engineering.


می‌خواهید سیستم‌های داخلی‌تان به‌صورت امن از ابزار هوش مصنوعی یا ابزارهای هوش مصنوعی تیم در دسترس باشد؟ ببینید چطور می‌توانم کمک کنم.

پرسش‌های متداول

تفاوت MCP با فراخوانی ابزار (Tool Calling) چیست؟

فراخوانی ابزار روشی است که مدل در یک اپلیکیشن از کد شما می‌خواهد تابعی را اجرا کند. MCP یک پروتکل استاندارد است که به هر اپ هوش مصنوعی سازگار اجازه می‌دهد ابزارهای یک سرور جدا را پیدا کند و صدا بزند؛ پس اتصال را یک بار می‌نویسید، نه یک بار برای هر اپ.

وصل کردن سرور MCP به دیتابیس امن است؟

به اندازه‌ی ابزارهایی که در اختیار می‌گذارید امن است. فقط‌خواندنی شروع کنید، یک کاربر دیتابیس جدا با کمترین دسترسی به سرور بدهید، همه‌ی آرگومان‌ها را اعتبارسنجی کنید و برای هر کاری که داده را تغییر می‌دهد تأیید انسانی در کلاینت بگذارید.

چه اپ‌هایی می‌توانند از سرور MCP من استفاده کنند؟

هر کلاینت MCP، مثلاً Cursor، OpenCode و بسیاری از دستیارهای IDE. سرور محلی از طریق stdio اجرا می‌شود؛ برای اشتراک با تیم یا روی وب، آن را روی HTTP میزبانی کنید.