MCP یک قرارداد برای وصل کردن مدل به context و capability است، نه مهر اعتماد برای هر server. در revision تاریخدار `2026-07-28` باید Host، Client و Server، سه primitive یعنی Tools، Resources و Prompts، و تفاوت stdio و HTTP را جدا بفهمیم. سپس OAuth، resource indicators، validation و allowlist را طوری بهکار ببریم که یک MCP third-party نتواند Agent رزرو وقت را به deputy ناخواستهٔ خود تبدیل کند.
## اهداف
پس از این درس میتوانی معماری MCP را ترسیم کنی؛ primitive مناسب را انتخاب کنی؛ transport و احراز هویت را مقایسه کنی؛ resource indicator و token audience را توضیح دهی؛ ورودی tool را validate و server را allowlist کنی؛ و ریسک third-party را با evidence و rollback ارزیابی کنی.
## جایگاه در چرخه
درسهای ۲۸ و ۲۹ local harness را ساختند. MCP در `Observe` و `Implement` یک مرز خارجی اضافه میکند: Agent ممکن است از resource اطلاعات بگیرد یا tool را صدا بزند. بنابراین authority همچنان Spec و permission profile است، نه خروجی server. این درس پیش از درس ۳۱ capability را از approval و OS sandbox جدا میکند.
## معماری و primitiveها
**Host** برنامهٔ اصلی است که session، مدل، consent و چند connection را مدیریت میکند؛ مثل IDE یا یک CLI. **Client** جزء داخل Host است که با یک Server ارتباط protocol-level دارد و capability negotiation و request/response را نگه میدارد. **Server** provider context یا action است و نباید بهدلیل نام MCP trusted تلقی شود.
**Tools** عمل میکنند: `calendar.findAvailability` یا `booking.getAppointment`. Tool ممکن است read یا write باشد و باید input schema، error و side effect صریح داشته باشد. **Resources** داده یا context addressable هستند؛ خواندن resource بهطور پیشفرض نباید write پنهان انجام دهد. **Prompts** templateهای قابلفراخوانیاند؛ prompt server policy انسانی را override نمیکند و محتوایش untrusted input است.
در **stdio** process محلی از stdin/stdout پیام میگیرد؛ isolation، path، child process و logging مهماند. در **HTTP** endpoint شبکهای و session/auth داریم؛ TLS، origin، token audience، timeout و egress اهمیت پیدا میکند. HTTP الزاماً خطرناکتر نیست و stdio الزاماً امن نیست؛ threat model به capability و boundary بستگی دارد.
مثال بد
یک MCP calendar نصب شد؛ چون Tool نامش read دارد، همهٔ toolها و tokenها را
به Agent بده و خروجی را مستقیماً در SQL یا shell قرار بده.نام و description قابلاعتماد نیستند. Server میتواند over-broad، compromised یا prompt-injecting باشد؛ output هم data است، نه دستور trusted.
مثال خوب: profile محدود
server: booking-calendar@revision-2026-07-28
transport: stdio در sandbox، بدون network
allow: calendar.getAvailability (read-only, tenant از credential)
deny: calendar.delete, admin.export, arbitrary_url
validation: schema + length + timezone allowlist + tenant ownership
approval: write یا بیش از ۳۰ روز range
evidence: request id، tool name، input hash بدون raw secret، outcome## OAuth، resource indicators و validation
در MCP revision `2026-07-28`، مسیر Authorization و OAuth این درس مربوط به **HTTP-based transport** است؛ یعنی جایی که Client به یک protected resource شبکهای و Authorization Server متصل میشود. برای HTTP، access token باید audience/resource server درست داشته باشد. **Resource indicator** میگوید token برای کدام protected resource صادر شده است؛ token عمومی یک حساب را به هر MCP server نفرست. Authorization server، client و resource server را از هم جدا کن؛ scope را کمینه کن؛ expiry و refresh rotation را تعریف کن؛ token را در log یا prompt نگذار. OAuth احراز هویت و delegation را حل میکند، نه درستبودن tool یا کمینهبودن business permission.
در مقابل، **stdio** معمولاً یک Server محلی را بهعنوان child process اجرا میکند و credential آن از محیط محلی، process identity یا credential manager مدیریتشده میآید. این یک قاعدهٔ معماری است، نه تضمین امنیت: implementation میتواند رفتار دیگری داشته باشد و باید مستند رسمی Host/Server بررسی شود. flow HTTP/OAuth، redirect، resource indicator یا refresh token را کورکورانه روی stdio اعمال نکن؛ ابتدا مشخص کن آیا اصلاً protected network resource وجود دارد. اگر stdio به سرویس خارجی وصل میشود، همان egress، secret lifecycle و threat model شبکه را جدا مستند کن. منبع مستقیم برای مرز Authorization، [MCP Authorization در revision 2026-07-28](https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization) است؛ منبع protocol نقش transport را مشخص میکند، اما credential manager هر Host را تضمین نمیکند.
Validation چند لایه است: schema نوع و required field؛ semantic validation برای timezone، range و enum؛ authorization برای tenant/actor از credential؛ rate/size limit؛ و output validation پیش از مصرف downstream. هیچ خروجی MCP مستقیماً به shell، SQL، template یا deployment API وصل نشود. Prompt injection داخل resource باید مثل issue یا صفحهٔ وب untrusted تلقی شود.
Allowlist را بر اساس server identity، pinned revision، tool name، scope، path و environment بنویس. deny-by-default بهتر از blocklist نامهای بد است. Third-party server را با provenance، source، maintainer، release notes، dependency، telemetry، data retention و incident contact بررسی کن. یک server read-only هم میتواند secret یا دادهٔ tenant دیگر را exfiltrate کند.
## سناریوی booking-platform
Agent برای نشاندادن وقتهای آزاد به `booking-calendar` متصل است. Host فقط `calendar.getAvailability` را expose میکند؛ server اجازه ندارد `appointment.reschedule` را صدا بزند. resource `booking://tenant/{tenantId}/availability` با tenant credential resolve میشود و path از input خام پذیرفته نمیشود. پاسخ server فقط پس از schema، tenant و date-range validation وارد planning میشود. برای write reschedule، approval انسانی و tool جدا لازم است؛ OAuth scope read را به write ارتقا نمیدهیم.
## آزمایشگاه گامبهگام
**ورودی:** diagram سادهٔ Host→Client→Server، manifest ساختگی و fixture tenant؛ هیچ token واقعی یا endpoint تولید استفاده نمیشود.
۱. manifest را inspect کن و برای هر capability جدول `primitive / side effect / input / scope / approval / evidence` بساز.
۲. فقط `calendar.getAvailability` را allow کن. نمونهٔ ورودی معتبر:
{"tenantId":"from-credential","clinicTimeZone":"Europe/Tehran","from":"2026-06-20","to":"2026-06-21"}`tenantId` در body ورودی واقعی نیست؛ comment آموزشی است و باید از credential بیاید.
۳. این موارد را رد کن: `to` پیش از `from`، range بیش از ۳۱ روز، timezone ناشناخته، URL دلخواه، tenant body متفاوت، tool ناشناخته و outputی که field اضافی خطرناک دارد.
۴. برای HTTP فرضی، resource indicator را `https://mcp.example.invalid/booking-calendar` بگذار؛ این دامنه فقط یک مقدار نمونهٔ غیرواقعی و مستند آموزشی است. token ساختگی را `EXAMPLE_TOKEN_DO_NOT_USE` بنام و هرگز مقدار secret واقعی ننویس. برای stdio همین flow را تکرار نکن: ثبت کن که process محلی و credential مدیریتشدهٔ محیط، در صورت پشتیبانی Host، چگونه کنترل میشوند و آیا network اصلاً لازم است یا نه.
**خروجی مورد انتظار:** allowlist یک tool، validation errorهای قابلتشخیص، read-only default و audit بدون token. **Recovery:** اگر server manifest مبهم یا revision pinned نبود، اتصال را قطع و وضعیت `DECIDE` بده؛ اگر OAuth audience اشتباه بود، refresh یا scope را حدس نزن، token را revoke و owner را در محیط واقعی مطلع کن. در این آزمایش فقط fixture local را پاک کن.
## خطاهای رایج
- قاطی کردن Host با Server یا تصور اینکه مدل مستقیماً به server وصل است.
- دادن write tool برای کاری که فقط read میخواهد.
- ارسال token برای resource اشتباه و نامگذاری آن بهعنوان «OAuth امن».
- validation صرفاً type-level بدون tenant authorization و limit.
- استفاده از blocklist بهجای allowlist و pin نکردن revision.
- اعتماد به tool description یا prompt/resource خروجی third-party.
- ثبت raw input و token در audit.
## Verification
- [ ] Host، Client و Server در diagram و ownership روشناند.
- [ ] Tools، Resources و Prompts side effect جدا دارند.
- [ ] stdio/HTTP با boundary و محدودیت واقعی توضیح داده شدهاند.
- [ ] OAuth audience/resource indicator، scope، expiry و rotation ثبت شده است.
- [ ] schema، semantic، authorization و output validation وجود دارد.
- [ ] server و revision pinned و tool allowlist هستند.
- [ ] third-party provenance، retention، telemetry، incident و rollback بررسی شده است.
## تمرین و پاسخ نمونه
یک MCP با دو tool `getAvailability` و `reschedule` برای dashboard بساز. آیا هر دو را allow میکنی؟
**پاسخ نمونه:** فقط `getAvailability`، با read scope، tenant از credential، date-range محدود، schema/semantic/output validation و evidence. `reschedule` باید در server/connection جدا، با scope write، approval انسانی، idempotency و rollback قرار گیرد؛ dashboard به آن نیاز ندارد. اگر server فقط ابزارهای broad را ارائه میکند، reject یا wrapper allowlist بساز؛ description آن را کافی ندان.
## جمعبندی
MCP مرز اتصال است، نه مرز اعتماد. Host consent و lifecycle را کنترل میکند، Client protocol را اجرا میکند و Server capability را ارائه میدهد. read-only allowlist، resource indicator، validation، pin revision و audit باید پیش از اتصال third-party برقرار باشند.
## منابع مستقیم
- [MCP specification 2026-07-28](https://modelcontextprotocol.io/specification/2026-07-28) — protocol، primitives و lifecycle با revision تاریخدار.
- [MCP Authorization](https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization) — OAuth و resource indicators؛ implementation باید نسخهٔ pinned را بررسی کند.
- [Cursor MCP](https://cursor.com/docs/mcp.md) — surface رسمی محصول و محدودیتهای deployment.
- [OWASP guide for third-party MCP servers](https://genai.owasp.org/resource/cheatsheet-a-practical-guide-for-securely-using-third-party-mcp-servers-1-0/) — راهنمای ریسک supply chain و trust؛ استاندارد protocol نیست.
به زبان ساده
در MCP، Host جلسه و رضایت را مدیریت میکند، Client ارتباط protocol را نگه میدارد و Server capability میدهد. Tool، Resource و Prompt را trusted فرض نکن و برای HTTP، audience و resource indicator را با scope کمینه کنترل کن.
مثال واقعی
در profile فرضی `booking-calendar` فقط `calendar.getAvailability` با tenant credential و بازهٔ محدود allow میشود؛ tool نوشتن reschedule در اتصال و approval جدا قرار میگیرد.