الدرس 10 من 20

MCP ومهارات الوكيل

بناء خوادم MCP

4 دقيقة للقراءة

بناء خادم MCP يتيح لك كشف أي وظيفة—APIs، قواعد بيانات، منطق مخصص—لنماذج الذكاء الاصطناعي. لنبنِ واحداً من الصفر.

خادم MCP أدنى (Python)

# server.py
from mcp.server import Server
from mcp.types import Tool, TextContent

app = Server("my-tools")

@app.list_tools()
async def list_tools():
    return [
        Tool(
            name="greet",
            description="توليد تحية",
            inputSchema={
                "type": "object",
                "properties": {
                    "name": {"type": "string", "description": "الاسم للتحية"}
                },
                "required": ["name"]
            }
        )
    ]

@app.call_tool()
async def call_tool(name: str, arguments: dict):
    if name == "greet":
        return [TextContent(type="text", text=f"مرحباً، {arguments['name']}!")]
    raise ValueError(f"أداة غير معروفة: {name}")

if __name__ == "__main__":
    import asyncio
    from mcp.server.stdio import stdio_server

    asyncio.run(stdio_server(app))

تشغيل خادمك

# تثبيت MCP SDK
pip install mcp

# تشغيل مباشر
python server.py

# أو استخدم مع Claude Desktop (claude_desktop_config.json)
{
  "mcpServers": {
    "my-tools": {
      "command": "python",
      "args": ["server.py"]
    }
  }
}

إضافة الموارد

كشف البيانات التي يمكن للنموذج قراءتها:

from mcp.types import Resource

@app.list_resources()
async def list_resources():
    return [
        Resource(
            uri="config://settings",
            name="إعدادات التطبيق",
            mimeType="application/json"
        )
    ]

@app.read_resource()
async def read_resource(uri: str):
    if uri == "config://settings":
        return json.dumps({"theme": "dark", "language": "ar"})
    raise ValueError(f"مورد غير معروف: {uri}")

إضافة البرومبتات

قوالب برومبت قابلة لإعادة الاستخدام:

from mcp.types import Prompt, PromptArgument

@app.list_prompts()
async def list_prompts():
    return [
        Prompt(
            name="explain_code",
            description="شرح الكود بمصطلحات بسيطة",
            arguments=[
                PromptArgument(name="language", description="لغة البرمجة"),
                PromptArgument(name="level", description="مستوى الخبرة")
            ]
        )
    ]

@app.get_prompt()
async def get_prompt(name: str, arguments: dict):
    if name == "explain_code":
        return {
            "messages": [{
                "role": "user",
                "content": f"اشرح هذا الكود {arguments['language']} لمطور {arguments['level']}."
            }]
        }

مثال عملي: خادم MCP لقاعدة البيانات

import asyncpg
from mcp.server import Server
from mcp.types import Tool, TextContent

app = Server("postgres-tools")
pool = None

async def get_pool():
    global pool
    if pool is None:
        pool = await asyncpg.create_pool("postgresql://localhost/mydb")
    return pool

@app.list_tools()
async def list_tools():
    return [
        Tool(
            name="query_database",
            description="تنفيذ استعلام SQL للقراءة فقط",
            inputSchema={
                "type": "object",
                "properties": {
                    "sql": {"type": "string", "description": "استعلام SQL SELECT"}
                },
                "required": ["sql"]
            }
        )
    ]

@app.call_tool()
async def call_tool(name: str, arguments: dict):
    if name == "query_database":
        sql = arguments["sql"]

        # الأمان: السماح فقط بـ SELECT
        if not sql.strip().upper().startswith("SELECT"):
            return [TextContent(type="text", text="خطأ: استعلامات SELECT فقط مسموحة")]

        pool = await get_pool()
        async with pool.acquire() as conn:
            rows = await conn.fetch(sql)
            result = [dict(row) for row in rows]
            return [TextContent(type="text", text=json.dumps(result, indent=2))]

بديل TypeScript

// server.ts
import { Server } from "@modelcontextprotocol/sdk/server";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio";

const server = new Server({
  name: "my-tools",
  version: "1.0.0"
});

server.setRequestHandler("tools/list", async () => ({
  tools: [{
    name: "calculate",
    description: "إجراء حسابات",
    inputSchema: {
      type: "object",
      properties: {
        expression: { type: "string" }
      }
    }
  }]
}));

server.setRequestHandler("tools/call", async (request) => {
  if (request.params.name === "calculate") {
    const result = eval(request.params.arguments.expression);
    return { content: [{ type: "text", text: String(result) }] };
  }
});

new StdioServerTransport(server).start();

ملاحظة نيردية: أبقِ خوادم MCP مركزة. خادم واحد لقاعدة البيانات، آخر لعمليات الملفات. القابلية للتركيب تتفوق على المونوليث.

التالي: بناء مهارات وكيل قابلة للتوسيع. :::

اختبار

الوحدة 3: MCP ومهارات الوكيل

خذ الاختبار