اگر سرور MCP را با پایتون مینویسید، نسخهی 2.2.0 همین امروز روی PyPI نشسته و کد شما را میشکند. FastMCP به MCPServer تغییر نام داده، inputSchema به input_schema، و پورت دیگر در سازنده پذیرفته نمیشود. در این پست یک سرور واقعی با همین نسخه میسازیم، با کلاینت داخل همان پروسه صدایش میزنیم و خطاهای مهاجرت را با متن واقعیشان نشان میدهیم. همهی عددها و خروجیها روی همین نسخه و روی همین سرور خوانده شدهاند.
این پست یک مهاجرت نیست و یک نظرسنجی هم نیست. یک کار انجام میدهد: از صفر تا اولین فراخوانی موفق، روی mcp==2.2.0. لحظهی خواندن داده: ۲۷ سپتامبر ۲۰۲۶.
نصب و بستههایی که واقعا کشیده میشوند
نصب یک دستور است، اما آنچه کشیده میشود یک عدد دارد که روی تصور شما اثر میگذارد: ۲۸ بسته. mcp-types دیگر بخشی از mcp نیست و یک توزیع جداگانه است که فقط به pydantic و typing-extensions نیاز دارد. کسی که فقط میخواهد شکلهای پروتکل را مصرف کند، میتواند بهتنهایی همان را نصب کند.
$ python3 -m venv .venv
$ .venv/bin/pip install mcp==2.2.0
...
Successfully installed annotated-types-0.8.0 anyio-4.15.1 ... mcp-2.2.0
mcp-types-2.2.0 opentelemetry-api-1.45.0 ... uvicorn-0.54.0
$ .venv/bin/pip show mcp mcp-types
Name: mcp
Version: 2.2.0
Requires: anyio, httpx2, jsonschema, mcp-types, opentelemetry-api, pydantic,
pyjwt, python-multipart, sse-starlette, starlette, typing-extensions,
typing-inspection, uvicorn
Name: mcp-types
Version: 2.2.0
Requires: pydantic, typing-extensions
Required-by: mcp
کف پایتون 3.10 است و این عدد را خود بسته اعلام میکند. یک نکتهی عملی در همین نصب پنهان است: فرمان خط فرمان mcp بدون افزونهی cli کار نمیکند و پیامش دقیقا همین است.
$ .venv/bin/mcp --help
Error: typer is required. Install with 'pip install mcp[cli]'
اگر فقط سرور مینویسید، لازم نیست typer را نصب کنید. برای mcp dev و mcp install اما باید باشد، چون هر دو فرمان را از همین بسته میآورند.
سرور و کلاینت، هر دو در یک فایل
سرور زیر دو ابزار میدهد که JSON پایتونی PyPI را میخوانند. MCPServer در نسخهی 2 دیگر پورت و ترابری نمیگیرد؛ ترابری در run() است. ورودی هر ابزار مستقیم از همان امضای تابع میآید، پس اسکیمای ورودی را خودتان نمینویسید.
import json
import urllib.request
from mcp.server import MCPServer
UA = "hoosh-mcp-demo/1.0"
def _pypi(package: str) -> dict:
# پیشفرض urllib یک User-Agent بینام میفرستد و PyPI خطای 403 میدهد
req = urllib.request.Request(f"https://pypi.org/pypi/{package}/json",
headers={"User-Agent": UA})
with urllib.request.urlopen(req, timeout=30) as r:
return json.load(r)
mcp = MCPServer("pypi-inspector", instructions="Report the newest release.")
@mcp.tool()
def latest_version(package: str) -> str:
"""Newest released version of `package` on PyPI and when it was uploaded."""
data = _pypi(package)
version = data["info"]["version"]
files = data["releases"].get(version) or []
return f"{package} {version} uploaded {files[0]['upload_time']}"
if __name__ == "__main__":
# ترابری و پورت اینجاست، نه در سازنده
mcp.run("streamable-http")
کلاینت در نسخهی 2 یک شیء است، نه سه لایهی تودرتو. شما Client را با خودِ شیء سرور میدهید و هیچ پورتی، هیچ زیرپروسهای و هیچ HTTPای در کار نیست. داخل بلوک، نسخهی پروتکل همان لحظه مذاکره شده و روی خصوصیتها نشسته است.
import anyio
from mcp import Client
from demo_server import mcp
async def main() -> None:
async with Client(mcp) as client:
print("protocol_version :", client.protocol_version)
listing = await client.list_tools()
for t in listing.tools:
print(f"tool {t.name:16} {t.description}")
r = await client.call_tool("latest_version", {"package": "mcp"})
print("latest_version :", r.content[0].text)
r = await client.call_tool("install_floor", {"package": "httpx"})
print("install_floor :", r.content[0].text)
print("structured :", r.structured_content, "| is_error:", r.is_error)
anyio.run(main)
این پنج خط خروجی، همان چیزی است که واقعا چاپ شد. خط اول یعنی دو طرف روی نسخهی 2026-07-28 پروتکل توافق کردهاند. خط آخر نشان میدهد یک برگشتی، سه چیز با هم میدهد: content برای مدل، structured_content برای کد خودتان، و is_error برای اینکه بدانید به اولی اعتماد کنید یا نه.
protocol_version : 2026-07-28
tool latest_version Newest released version of `package` on PyPI and when it was uploaded.
tool install_floor The `requires_python` floor declared by the newest release.
latest_version : mcp 2.2.0 uploaded 2026-09-07T16:06:19
install_floor : httpx 0.28.1 requires_python=>=3.8
structured : {'result': 'httpx 0.28.1 requires_python=>=3.8'} | is_error: False
اگر سرورتان روی HTTP واقعی است، تنها فرق این است که بهجای شیء سرور، نشانی را میدهید: Client("http://127.0.0.1:8000/mcp"). برای سرور زیرپروسهای هم StdioServerParameters را مستقیم به Client میدهید. دادن جفت خواندن و نوشتن بهصورت دستی در نسخهی 2 خطا میدهد.
سه تغییری که هیچ خطایی نمیدهند
بازارنگاشتها با خودشان را میدهند و دقیقا به همین دلیل دیده نشدهاند. این سه مورد را روی همین نصب اندازه گرفتیم.
نخست، تابع همگام روی نخ کارگر اجرا میشود. یک ابزار که با def تعریف شده دیگر حلقهی رویداد را نمیبندد، و بهای آن این است که بدنهاش دیگر روی همان نخ اجرا نمیشود. کدی که به نخ وابسته است باید بازنویسی شود.
$ .venv/bin/python thread_probe.py
main thread : MainThread
sync_tool ran on: AnyIO worker thread
async_tool ran on: loop_thread=MainThread
دوم، خطاها دو مسیر دارند و این مسیرها عوض شدهاند. MCPError داخل ابزار یک خطای پروتکل است و به کلاینت میرسد؛ هر استثنای دیگری به یک نتیجهی is_error=True تبدیل میشود و مدل فقط نام ابزار را میبیند. تنها پیام ToolError است که به مدل میرسد.
$ .venv/bin/python error_probe.py
--- fine ---
is_error: False | text: ok
--- ordinary_error ---
is_error: True | text: Error executing tool ordinary_error
--- protocol_error ---
RAISED MCPError: this is a protocol error
سوم، کلاینت پاسخ سرور را اعتبارسنجی میکند. سروری که پاسخ نیمبند بدهد، جایی که نسخهی 1 بیسروصدا میبلعید، حالا در همان کلاینت ValidationError میدهد. این تغییر آزاردهنده به نظر میرسد و دقیقا همان چیزی است که به درد شما میخورد وقتی به سرورهایی وصل میشوید که در اختیار شما نیستند.
خطاهای مهاجرت، با متن واقعی
سه خطایی که هر کدبیس نسخهی 1 در اولین اجرا میبیند، با پیام کامل اینجا آمدهاند. پیام اول عمدا طولانی است: خود کتابخانه مسیر مهاجرت را در آن میگذارد.
$ .venv/bin/python migration_probe.py
=== 1. the old v1 import path ===
ModuleNotFoundError: No module named 'mcp.server.fastmcp'. This is mcp 2.x, where
FastMCP was renamed to MCPServer (from mcp.server.mcpserver import MCPServer)
and other APIs changed; see the migration guide at ... or pin 'mcp<2' to keep
running v1 code.
=== 2. transport kwargs in the constructor ===
TypeError: MCPServer.__init__() got an unexpected keyword argument 'port'
=== 3. where the field names went ===
Tool fields : ['annotations', 'description', 'execution', 'icons',
'input_schema', 'meta', 'name', 'output_schema', 'title']
has input_schema: True | has inputSchema: False
CallToolResult : ['content', 'is_error', 'meta', 'result_type', 'structured_content']
خط سوم از همهی راهنماهای مهاجرت مهمتر است: روی سیم JSON هنوز camelCase است و فقط نام صفتهای پایتون عوض شده. یعنی inputSchema به input_schema میرود و isError به is_error. هر کدی که صفتهای camelCase را میخواند، در سرور میمیرد و در کلاینت ساکت از کار میافتد.
پین کنیم یا مهاجرت کنیم
خط 1.x هنوز زنده است و در حالت نگهداری اصلاح امنیتی میگیرد. تاریخهای زیر از کلید انتشارهای PyPI خوانده شدهاند و ساعتها به وقت UTC است.
| نسخه | تاریخ آپلود | جایگاه در تاریخ |
|---|---|---|
| 0.9.1 | ۲۰ نوامبر ۲۰۲۴ | نخستین انتشار بسته |
| 1.29.1 | ۲۴ اوت ۲۰۲۶ | آخرین نسخه پیش از 1.30.0 |
| 1.30.0 | ۷ سپتامبر ۱۴:۳۴ | آخرین نسخهی پایدار خط 1 |
| 2.0.0rc1 | ۲۷ ژوئیه ۱۳:۳۵ | آخرین پیشانتشار پیش از 2.0.0 |
| 2.0.0 | ۲۸ ژوئیه ۱۳:۴۵ | نخستین نسخهی پایدار خط 2 |
| 2.2.0 | ۷ سپتامبر ۱۶:۰۶ | آخرین نسخهی خط 2 |
تفاضل دو ساعت آخر 1 ساعت و 32 دقیقه است، یعنی هر دو خط در یک روز زنده شدند و هیچکدام دیگری را متوقف نکرد. از 64 نسخهی پایداری که بسته تا امروز دارد، ۵ تا روی خط 2 است: 5 تقسیم بر 64 برابر 7.8 درصد. بقیه، یعنی 59 نسخه، روی خط 1 ماندهاند و 8 کلید دیگر هم نسخهی پیشانتشار است.
پس انتخاب را اینطور ببندید: اگر کد شما خطای مهاجرت را نمیدهد، همان را پین کنید و نسخه را دست نزنید.
$ .venv/bin/pip install "mcp>=1.28,<2"
Collecting mcp<2,>=1.28
Would install ... mcp-1.30.0 ...
اما اگر کتابخانهی خودتان به mcp وابسته است و هنوز مهاجرت نکردهاید، همین کران بالا را در pyproject.toml بگذارید تا یک بهروزرسانی ناخواسته شما را به نسخهی 2 نبرد. مهاجرت را جدا انجام دهید، روی یک شاخه، وقتی کار دیگری روی شاخه نیست.
اگر تازه سرور MCP مینویسید، نسخهی 2 انتخاب پیشفرض است. اگر دارید کد موجود را مهاجرت میدهید، راهنمای رسمی مهاجرت هر شکست را با قبل و بعد مینویسد. برای سنجیدن یک سرور پیش از پذیرش هم پست ارزیابی سرور MCP چکلیست عملی دارد، و اگر میخواهید ببینید یک سرور واقعی در یک میزبان چطور بالا میآید، سرور MCP کروم همین مسیر را از نصب تا فراخوانی نشان میدهد.
منابع
- صفحهی بسته mcp در PyPI: نسخهها، کف پایتون و تاریخچه
- مستندات رسمی: چه چیزی در نسخهی 2 عوض شده است
- راهنمای نصب و فهرست وابستگیها و افزونهها
- مستندات کلاینت: چهار شکل اتصال و محتوای بازگشتی
- راهنمای مهاجرت از نسخهی 1، با کد پیش و پس از هر تغییر
- تفکیک خطای پروتکل و خطای ابزار
- نسخههای پروتکل و مذاکره در کلاینت
- بستهی mcp-types و وابستگیهای آن
- مشخصات پروتکل MCP، نسخهی 2026-07-28
- مخزن رسمی python-sdk
- انتشارهای مخزن و یادداشت هر نسخه
- صفحهی httpx در PyPI، نمونهی دوم در خروجی بالا
دیدگاهها
۰ موردهنوز دیدگاهی ثبت نشده. اولین نفر باشید.