پیادهسازی client (Implementing a client)
عنوان اصلی: Implementing a client
هدف یادگیری: ساخت یک MCP client حداقلی در Python که initialize میکند، tools را list میکند، یک tool را call میکند و یک notification را handle میکند.
مفاهیم کلیدی: ClientSession، stdio_client، initialize()، list_tools()، call_tool()، notification handler.
ClientSession در SDK Python ماشین JSON-RPC را wrap میکند، طوری که کد اپلیکیشن فقط methodهای high-level را میبیند. الگوی استاندارد: یک transport context باز کنید (stdio_client(...) یا streamablehttp_client(...))، read/write streamها را در یک ClientSession بپیچید، await session.initialize() کنید، سپس از list_tools()، call_tool()، list_resources()، read_resource()، list_prompts()، get_prompt() استفاده کنید. session همچنین hook برای notificationها و primitiveهای سمت client (sampling، elicitation، roots) عرضه میکند.
مثال عملی — Python (client کامل minimal با notification handler)
import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
server_params = StdioServerParameters(command="python", args=["server.py"])
async def main():
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
init = await session.initialize()
print("Server:", init.server_info.name, init.server_info.version)
print("Capabilities:", init.capabilities)
tools = await session.list_tools()
for t in tools.tools:
print(f" - {t.name}: {t.description}")
result = await session.call_tool("add", {"a": 2, "b": 3})
print("Result:", result.content[0].text)
asyncio.run(main())
مثال عملی — TypeScript (client مشابه)
import { Client } from '@modelcontextprotocol/client';
import { StdioClientTransport } from '@modelcontextprotocol/client/stdio';
const client = new Client({ name: 'demo-client', version: '1.0.0' }, {});
const transport = new StdioClientTransport({
command: 'node',
args: ['build/index.js'],
});
await client.connect(transport);
const tools = await client.listTools();
const result = await client.callTool({ name: 'greet', arguments: { name: 'Alice' } });
console.log(result.content);
دیاگرام معماری (متنی): Client مالک یک read stream و یک write stream است. requestهای خروجی JSON-RPC بهصورت newline-delimited روی stdin نوشته میشوند؛ responseها و notificationهای ورودی از stdout میرسند و بر اساس id (responseها) یا method (notificationها) dispatch میشوند.
اشتباهات رایج
- فراموش کردن
await session.initialize()— تمام صداهای دیگر fail میشوند. - نگه داشتن session بیرون از بلاک
async with— بسته میشود. - بلاک کردن event loop با I/O sync داخل notification handler.