سرور MCP را با یک فراخوانی واقعی تست کنید، نه با چشم. در همین پست نسخه‌ی 2.8.0 از MCP Inspector روی سرور فایل‌سیستم 2026.8.31 اجرا شد: tools/list چهارده ابزار برگرداند که ده‌تایش readOnly است و سه‌تا destructive، و یک فراخوانی به مسیر بیرون از ریشه با کد خروجی 5 رد شد. زمان خواندن داده: ۲۸ سپتامبر ۲۰۲۶.

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

مشترک رسمی پروتکل برای همین کار یک ابزار مرجع دارد: MCP Inspector. این نوشته حالت خط فرمانی آن را روی یک سرور واقعی اجرا می‌کند، چون همان چیزی است که در خط لوله و داخل ایجنت به کار می‌آید.

اینسپکتور خط فرمان چه چیزی به ما می‌دهد

طبق مستندات رسمی، این بسته سه کلاینت را پشت یک فایل اجرایی می‌دهد: --web برای رابط گرافیکی مرورگر، --cli برای خط فرمان قابل اسکریپت، و --tui برای کار درون خود ترمینال. مستندات می‌گویند هر سه روی یک هسته‌ی مشترک ساخته شده‌اند، پس رفتار اتصال در هر سه یکی است.

تفاوت اصلی در تعداد ابزار نیست، در مالکیت پرچم‌هاست. آنچه مستندات «پرچم‌های راه‌انداز» می‌نامند فقط دو چیز است: پرچم حالت و --help. هر چیز دیگری، از --method تا --server-url، متعلق به کلاینت است و همه‌ی کلاینت‌ها هم یک مجموعه پرچم را تعریف نمی‌کنند.

یک قاعده‌ی باریک و پرتله: پرچم حالت فقط در ابتدای خط فرمان شناخته می‌شود. اولین توکنی که --web، --cli یا --tui نباشد، پایان تجزیه‌ی راه‌انداز است و هر چیزی بعد از آن بدون تغییر به کلاینت می‌رسد.

راه‌اندازی: سرور و اینسپکتور را کنار هم نصب کنید

مستندات Inspector می‌گویند به Node 22.19.0 یا تازه‌تر نیاز دارد. برای اینکه خروجی این نوشته بازتولیدپذیر باشد، هر دو بسته را در یک پوشه نصب کردیم و آدرس واقعی فایل‌های اجرایی را به خط فرمان دادیم.

$ node --version
v26.7.0
$ mkdir -p inspector-lab/project && cd inspector-lab
# یک فایل نمونه می‌سازیم که در گام دوم می‌خوانیم
$ printf 'hello from hoosh\n' > project/note.txt
$ mkdir node && cd node
# هر دو بسته در یک پوشه نصب می‌شوند تا آدرس فایل اجرایی ثابت بماند
$ npm install --no-fund --no-audit \
    @modelcontextprotocol/inspector \
    @modelcontextprotocol/server-filesystem
added 103 packages in 5s
$ cd ..
$ ./node/node_modules/.bin/mcp-inspector --help
Usage: mcp-inspector [options]

MCP Inspector – run web UI, CLI, or TUI

Options:
  --web       Run web UI (default)
  --cli       Run CLI
  --tui       Run TUI
  -h, --help  display help for command

Mode flags (--web, --cli, --tui) must appear before app options. All following arguments are forwarded unchanged.

پوشه‌ی project همان چیزی است که بعداً به سرور به عنوان ریشه‌ی مجاز می‌دهیم. بدون آن سرور هنگام اتصال ریشه‌ای نمی‌شناسد و هر فراخوانی را رد می‌کند.

گام اول: فهرست ابزارها و برچسب‌های خطر

اولین فراخوانی tools/list است. خروجی اینجا بیست و هزار و دویست و نود و نه بایت طول کشید و چهارده ابزار داشت. مهم‌تر از تعداد، برچسب‌هایی است که کنار هر ابزار می‌آید.

$ ./node/node_modules/.bin/mcp-inspector --cli \
    ./node/node_modules/.bin/mcp-server-filesystem \
    $PWD --method tools/list | jq '.tools | length'
14
$ ./node/node_modules/.bin/mcp-inspector --cli \
    ./node/node_modules/.bin/mcp-server-filesystem \
    $PWD --method tools/list | jq -r \
    '.tools[] | [.name, (.annotations.readOnlyHint|tostring), (.annotations.destructiveHint|tostring)] | @tsv'
read_file                    true    null
read_text_file               true    null
read_media_file              true    null
read_multiple_files          true    null
write_file                   false   true
edit_file                    false   true
create_directory             false   false
list_directory               true    null
list_directory_with_sizes    true    null
directory_tree               true    null
move_file                    false   true
search_files                 true    null
get_file_info                true    null
list_allowed_directories     true    null

این جدول همان چیزی است که در یک بازبینی واقعی به درد می‌خورد. از چهارده ابزار، readOnlyHint در ده‌تا true است و destructiveHint در سه‌تا. تنها ابزار بدون هیچ‌کدام از این دو برچسب، create_directory است.

دستهتعدادابزارها
فقط‌خواندنی۱۰خواندن فایل، خواندن چند فایل، فهرست پوشه، درخت پوشه، جست‌وجو، جزئیات فایل
ویرانگر۳نوشتن، ویرایش، جابه‌جایی
بدون برچسب۱ساخت پوشه
جمع۱۴کل فهرست ابزارهای همین سرور

اگر خروجی شما با این اعداد نمی‌خواند، اولین چیزی که باید بررسی شود نسخه‌ی سرور است، نه نصب شما. نام ابزارها در طول زمان عوض شده: همین سرور read_file را با عنوان «منقضی‌شده» برمی‌گرداند و در توضیحش می‌نویسد به‌جایش از read_text_file استفاده کنید.

گام دوم: یک ابزار را واقعاً صدا بزنید

فهرست ابزارها فقط ادعای سرور است. اینجا همان ابزار را اجرا می‌کنیم و محتوای فایلی را که در گام اول ساختیم می‌خوانیم.

$ ./node/node_modules/.bin/mcp-inspector --cli \
    ./node/node_modules/.bin/mcp-server-filesystem \
    $PWD --method tools/call \
    --tool-name read_text_file --tool-arg path=$PWD/project/note.txt
{
  "content": [
    {
      "type": "text",
      "text": "hello from hoosh\n"
    }
  ],
  "structuredContent": {
    "content": "hello from hoosh\n"
  }
}
$ echo "exit=$?"
exit=0

سه نکته در همین خروجی هست که ارزش دیدن دارند. اول اینکه پاسخ فقط در content نیست و یک structuredContent هم دارد، پس اگر ابزار شما طرح‌واره‌ی خروجی اعلام کرده باشد، همان‌جا قابل اتکاست. دوم اینکه exit=0 یعنی فراخوانی موفق بوده است. سوم اینکه متن برگشتی دقیقاً محتوای فایل است و آن \n در انتها، خط جدید انتهای فایل است که خودمان در گام اول نوشته بودیم.

همین فراخوانی با نام منقضی‌شده هم جواب می‌دهد و همان متن را برمی‌گرداند. این را آگاهانه نگه داشتیم، چون برای تست رگرسیون همان نامی که اسکریپت قدیمی شما صدا می‌زند مهم است.

گام سوم: تست منفی، جایی که واقعاً می‌شود خراب شد

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

$ ./node/node_modules/.bin/mcp-inspector --cli \
    ./node/node_modules/.bin/mcp-server-filesystem \
    $PWD --method tools/call \
    --tool-name read_text_file --tool-arg path=/etc/hostname
{
  "content": [
    {
      "type": "text",
      "text": "Access denied - path outside allowed directories: /etc/hostname not in /root/.hermes/hoosh-blog/demo/inspector-lab"
    }
  ],
  "isError": true
}
$ echo "exit=$?"
exit=5

این مهم‌ترین یافته‌ی این نوشته است. سرور در متن پاسخ isError را true می‌گذارد و Inspector هم کد خروجی 5 می‌دهد. یعنی اگر تست منفی شما فقط متن خروجی را نگاه کند و کد خروجی را نه، یک سرور کاملاً شکسته را سالم می‌بیند.

قاعده‌ی عملی همین است: در خط لوله موفقیت را با کد خروجی بسنجید و متن را فقط برای تشخیص بخوانید. درباره‌ی کدهای خروجی کلاینت خط فرمان هم مستندات توضیح داده است. در جای دیگری از همین هفته هم خطاهای مهاجرت نسخه‌ی ۲ SDK را با متن واقعی‌شان بررسی کرده‌ایم و همین روش جواب داد.

در خط لوله چه کار کنیم

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

  1. نصب را از تست جدا نگه دارید تا کش لایه‌ی وابستگی‌ها سریع بماند و نسخه‌ها در یک فایل قفل شوند.
  2. فراخوانی موفق را با کد خروجی صفر بسنجید و شمار ابزارها را با شمار مورد انتظار مقایسه کنید.
  3. تست منفی را در همان اجرا نگه دارید، چون بدون آن یک تغییر امنیتی هم سبز دیده می‌شود.

نکته‌ی پایانی درباره‌ی ریشه‌هاست. مستندات کلاینت خط فرمان می‌گویند فایل پیکربندی تنها راه پایدار برای دادن ریشه به یک اجراست و پرچم مستقیمی برای ریشه وجود ندارد. روی همین نسخه، وقتی ریشه را در خط فرمان به‌عنوان آرگومان دادیم، سرور روی استاندارد خروجی خود این را نوشت: No valid root directories provided by client. برای سروری که به roots/list تکیه می‌کند، ریشه‌ی درست را در فایل پیکربندی بدهید.

برای اینکه بدانید ریشه‌ی مجاز هر ابزار چقدر است، سرورهای مرجع پروتکل را ببینید. آن‌ها نمونه‌ی آموزشی‌اند و طبق هشدار خود مخزن، برای محیط عملیاتی ساخته نشده‌اند.

منابع

  1. MCP Inspector — مستندات رسمی
  2. کلاینت خط فرمان Inspector — متدها، کدهای خروجی و پرچم‌ها
  3. مخزن modelcontextprotocol/inspector
  4. سرورهای مرجع modelcontextprotocol/servers
  5. مفاهیم سرور در MCP
  6. هزینه‌ی توکن سرورهای MCP را چطور بسنجیم