الأدوات و MCP
امنح وكيلك أدوات من خوادم MCP، وشغّل حلقة استدعاء الأدوات المدمجة، واعرض وكيلك كخادم MCP، وتتبّع كل استدعاء.
الوكيل الذي لا يستطيع سوى المحادثة هو نصف وكيل. بيئة التشغيل التي تستضيف
handler.py الخاص بك تأتي بمنظومة أدوات كاملة: يستطيع وكيلك استهلاك خوادم
أدوات MCP خارجية، وتشغيل حلقة استدعاء أدوات
محدودة الخطوات نيابة عنك، وعرض أدواته هو نفسه كخادم MCP تستهلكه وكلاء آخرون.
وكل استدعاء يُتتبَّع بمعرّف استدعاء يمكنك متابعته.
وصّل خوادم أدوات MCP
عرّف خوادم MCP الخارجية في متغيّر البيئة AGENT_MCP_SERVERS — مصفوفة JSON
تحقنها المنصّة لكل وكيل، فإضافة خادم أدوات تصبح تغييراً في الإعدادات لا في
الكود:
[
{"name": "docs", "url": "https://mcp.example.com/mcp", "token_env": "MCP_DOCS_TOKEN"},
{"name": "legacy", "url": "https://mcp.legacy.example.com/sse", "transport": "sse"}
]- يشير
token_envإلى متغيّر بيئة آخر يحمل رمز الاستيثاق (bearer token). لا تضع الرمز نفسه فيAGENT_MCP_SERVERSأبداً — كل سرّ هو قيد مستقل، يُحقن تماماً كمفاتيح المزوّدين لديك. - يجب أن تكون الروابط
https://. قد تحمل استدعاءات الأدوات وسائط حسّاسة عبر الشبكة، لذا يُرفضhttp://الصريح ما لم تضبطALLOW_INSECURE_MCP=true(للتطوير المحلي فقط). - القيمة الافتراضية لـ
transportهيstreamable-http؛ استخدم"sse"للخوادم القديمة العاملة بـ SSE.
ثم تمنحك حزمة alawadi_agent الأدوات كواصفات (descriptors) محمولة:
from alawadi_agent import list_all_tools, call_tool
tools = list_all_tools() # every configured server, tagged with its name
# → [{"name": "search", "description": "...", "input_schema": {...}, "server": "docs"}]
result = call_tool("docs", "search", {"query": "refund policy"})
# → {"text": "...", "structured": {...} | None, "is_error": False}أما الدوال غير المتزامنة (async) فتستخدم نسخ list_tools_async و
list_all_tools_async وcall_tool_async بدلاً منها.
حلقة استدعاء الأدوات: run_agent()
الشكل الشائع للوكيل هو «نموذج + أدوات، وكرّر حتى يتوقّف النموذج عن استدعاء
الأدوات». وrun_agent هو التنفيذ القياسي لهذه الحلقة في بيئة التشغيل — محدود
بسقف صارم هو max_steps من جولات النموذج، مع تمرير أخطاء الأدوات إلى النموذج
كبيانات بدلاً من إسقاط استدعاءك بالكامل:
from alawadi_agent import run_agent, list_all_tools
def handle(request):
tools = list_all_tools() + [{
"name": "add",
"description": "Add two numbers",
"input_schema": {"type": "object",
"properties": {"a": {"type": "number"}, "b": {"type": "number"}}},
"fn": lambda a, b: a + b, # local callable
}]
return run_agent(request.get("message", ""), tools=tools, max_steps=8)يمكن أن تكون الأدوات واصفات MCP آتية من list_all_tools() (تحمل مفتاح
server وتُنفَّذ عن بُعد) أو دوال محلية تحمل مفتاح fn. تحوّل الحلقة هذه
الأدوات إلى صيغة OpenAI للأدوات نيابة عنك. وتُعيد
{"output": str, "steps": [...]} — حيث يسجّل steps محتوى كل جولة
واستدعاءات الأدوات فيها، وهو ما يغذّي التتبّع أدناه.
للسقف أهميته: حلقة أدوات جامحة تعني فاتورة جامحة. عند بلوغ max_steps، يجري
اتصال أخير دون أدوات لفرض إجابة نصّية ممّا جمعته الحلقة.
اعرض وكيلك كخادم MCP
العقد نفسه يعمل في الاتجاه المعاكس. صدّر TOOLS وhandle_tool من ملف
handler.py، فتخدمهما بيئة التشغيل كخادم MCP على POST /mcp في اسم مضيف
وكيلك — عبر Streamable HTTP JSON-RPC، مع دعم initialize وping و
tools/list وtools/call:
TOOLS = [{"name": "greet", "description": "Greet someone",
"input_schema": {"type": "object",
"properties": {"who": {"type": "string"}}}]
def handle_tool(name, arguments):
if name == "greet":
return "hello " + arguments.get("who", "world")
raise KeyError(name)تقبع /mcp خلف مصادقة رمز الاستدعاء نفسها المستخدمة في /invoke، فلا
يستطيع استعراض أدواتك أو تشغيلها إلا من تثق بهم. ويمكن لوكيل آخر أن يستهلك
وكيلك بإعلانه في AGENT_MCP_SERVERS الخاص به مع
"url": "https://<name>-<id>.alawadi.cloud/mcp". وإن لم يصدّر معالجك
TOOLS وhandle_tool، تُعيد /mcp الرمز 404 (mcp_not_available).
تتبّع كل استدعاء
كل استدعاء لـ /invoke وكل استدعاء tools/call عبر MCP يُعيد ترويسة
X-Invocation-Id في الردّ، ويُسجَّل في مخزن دائري في الذاكرة — المعرّف
والطابع الزمني والنوع والحالة وزمن الاستجابة، دون أجسام الطلبات أو الرموز
أبداً. وتُعيد GET /invocations (بمصادقة رمز الاستدعاء نفسها كما في
/invoke) الاستدعاءات الأخيرة، مرتّبة من الأحدث إلى الأقدم:
curl https://my-agent-a1b2c3.alawadi.cloud/invocations \
-H "Authorization: Bearer $AGENT_INVOKE_TOKEN"يحتفظ المخزن بآخر 200 استدعاء افتراضياً؛ ويمكن ضبطه عبر
AGENT_INVOCATION_LOG_SIZE. هذه هي المغذّاة التي تقف خلف سجلّ كل وكيل في
البوابة — طابقها مع X-Invocation-Id الذي سجّلته لدى الطرف المُستدعي عند
تعقّب تنفيذ سيّئ.
الخطوة التالية
- وكلاء الذكاء الاصطناعي — أنشئ الوكيل نفسه وانشره وأمّنه.
- مرجع API وكلاء الذكاء الاصطناعي — كل نقاط إدارة الوكلاء، مع مخطّطاتها.
- الفوترة والاستخدام — كيف يُقاس إنفاق التوكنات على استدعاء الأدوات.