MCP مقابل استدعاء الدوال: كيفية ربط الأدوات بوكلاء الذكاء الاصطناعي
- مقارنة موجزة: MCP مقابل Function Calling
- البنية والربط:
- Function Calling: يربط النموذج مباشرة بمهام/دوال محلية لديك (داخل نفس العملية عادة). مناسب لأدوات قليلة وسريعة الدمج، لكنه يقيّدك بعملية التنفيذ الواحدة ولغة/بيئة محددة.
- MCP (Model Context Protocol): بروتوكول عمومي لأدوات وخدمات خارج العملية عبر JSON-RPC (stdio/شبكي). يمكّن فصل الأدوات في خادم مستقل يمكن إعادة استخدامه من أدوات/وكلاء متعددة وبيئات مختلفة، مع توصيف أدوات قياسي واكتشاف/إدارة أفضل على المدى الطويل.
- التوسّع والصيانة:
- Function Calling: سريع البدء، لكن نمو عدد الأدوات يضاعف صعوبة الحوكمة وإعادة الاستخدام بين تطبيقات/عملاء مختلفين.
- MCP: يفرض فصلًا واضحًا بين العميل/الوكيل والخادم/الأدوات، ما يسهل الحوكمة، مراقبة الإصدارات، والاختبار المستقل، وإعادة الاستخدام عبر محررات وواجهات متعددة.
- الموثوقية والأمان:
- Function Calling: الدالة تعمل ضمن نفس الثقة/الامتيازات التي يعمل بها عميلك.
- MCP: يمكن تشغيل الخادم بصلاحيات معزولة، وتطبيق سياسات وصول، وتسجيل، وخنق (throttling) على مستوى الخادم.
- الاعتمادية والتشغيل:
- Function Calling: لا يتطلب وسيط نقل أو اكتشاف أدوات؛ الاتصال مباشر.
- MCP: يتطلب خادم MCP وتشغيله ونقل البيانات عبر stdio/شبكة، لكنه يتيح تشارك الأدوات بين عدة عملاء بسهولة.
- افتراضات للكود التالي
- سنفترض وجود CometAPI بواجهة REST:
- GET {COMET_API_BASE_URL}/orders/{order_id}
- مصادقة عبر رأس Authorization: Bearer <COMET_API_KEY>
- إعداد البيئة:
- Python 3.10+
- تثبيت الحزم: pip install requests pydantic mcp
- متغيرات البيئة:
- COMET_API_BASE_URL
- COMET_API_KEY
- وحدة مشتركة لاستدعاء CometAPI مباشرة (استخدمها في جميع الأمثلة)
```python
# comet_api.py
# ملاحظة: تُترجم التعليقات/النصوص الظاهرة للمستخدم فقط. لا تُترجم المعرفات أو المنطق.
import os
import requests
from typing import Any, Dict
BASE_URL = os.environ.get("COMET_API_BASE_URL", "").rstrip("/")
API_KEY = os.environ.get("COMET_API_KEY", "")
class CometAPIError(Exception):
"""خطأ عام عند استدعاء CometAPI."""
def _auth_headers() -> Dict[str, str]:
if not API_KEY:
raise CometAPIError("لم يتم ضبط COMET_API_KEY في متغيرات البيئة.")
return {
"Authorization": f"Bearer {API_KEY}",
"Accept": "application/json",
"User-Agent": "comet-demo/1.0",
}
def get_order(order_id: str) -> Dict[str, Any]:
"""استعلام عن طلبية من CometAPI عبر رقم الطلب."""
if not BASE_URL:
raise CometAPIError("لم يتم ضبط COMET_API_BASE_URL في متغيرات البيئة.")
if not order_id:
raise ValueError("معرّف الطلب مطلوب.")
url = f"{BASE_URL}/orders/{order_id}"
resp = requests.get(url, headers=_auth_headers(), timeout=20)
try:
resp.raise_for_status()
except requests.HTTPError as e:
# محاولة إرجاع رسالة مفيدة من الجسم إن وُجدت
try:
data = resp.json()
except Exception:
data = {"message": resp.text}
raise CometAPIError(f"فشل طلب CometAPI: {resp.status_code} - {data}") from e
try:
return resp.json()
except ValueError as e:
raise CometAPIError("استجابة غير صالحة (ليست JSON).") from e
```
- تشغيل مباشر (بدون MCP): نفس الاستعلام مباشرة ضد CometAPI
```python
# run_direct.py
import sys
import json
from comet_api import get_order, CometAPIError
def main() -> None:
if len(sys.argv) < 2:
print("الاستعمال: python run_direct.py <ORDER_ID>")
sys.exit(1)
order_id = sys.argv[1]
try:
data = get_order(order_id)
print(json.dumps(data, ensure_ascii=False, indent=2))
except CometAPIError as e:
print(f"خطأ CometAPI: {e}")
sys.exit(2)
except Exception as e:
print(f"خطأ غير متوقع: {e}")
sys.exit(3)
if __name__ == "__main__":
main()
```
- خادم MCP يغلّف نفس الأداة (lookup_order) فوق CometAPI
```python
# mcp_server.py
# خادم MCP يُعرّف أداة lookup_order ويعيد النتيجة من CometAPI.
import json
from typing import Any, Dict
from pydantic import BaseModel, Field
from comet_api import get_order, CometAPIError
# حزمة mcp (من Anthropic) — تأكد من تثبيتها: pip install mcp
from mcp.server import Server
from mcp.server.stdio import run as run_stdio
server = Server("comet-mcp-server")
class LookupOrderArgs(BaseModel):
order_id: str = Field(..., description="معرّف الطلب المطلوب الاستعلام عنه")
@server.tool(
name="lookup_order",
description="البحث عن طلبية عبر CometAPI باستخدام رقم الطلب.",
args=LookupOrderArgs,
)
async def lookup_order(args: LookupOrderArgs) -> Dict[str, Any]:
"""أداة MCP: تُنادي CometAPI وتعيد JSON كقاموس."""
try:
data = get_order(args.order_id)
# يمكن إعادة dict مباشرة؛ عميل MCP سيعجنه كـ JSON/Text حسب دعمه.
return data
except CometAPIError as e:
# من الأفضل إرجاع رسالة خطأ واضحة ضمن نتيجة الأداة
return {"error": str(e)}
if __name__ == "__main__":
# تشغيل الخادم عبر stdio (يُناسب الربط مع عملاء MCP).
run_stdio(server)
```
- عميل Python يستدعي نفس الأداة عبر MCP (يشغل الخادم ثم يستدعي الأداة)
```python
# run_via_mcp.py
# يشغّل خادم MCP (mcp_server.py) عبر stdio ويستدعي أداة lookup_order بالـ order_id نفسه.
import sys
import json
import asyncio
# واجهات عميل MCP — قد تختلف الأسماء البسيطة بحسب إصدار الحزمة.
from mcp.client.stdio import stdio_transport
from mcp.client.session import ClientSession
async def main_async(order_id: str) -> int:
# يشغّل mcp_server.py كعملية فرعية عبر stdio
transport = stdio_transport(
sys.executable,
[ "mcp_server.py" ],
env=None, # يمكن تمرير بيئة مخصّصة إن لزم
)
async with transport:
session = ClientSession(transport)
# تهيئة بروتوكول MCP (تبادل القدرات، إلخ)
await session.initialize()
# اختيار/تحقق من وجود الأداة
tools = await session.list_tools()
if not any(t.name == "lookup_order" for t in tools):
print("لم يُعثر على الأداة lookup_order في خادم MCP.")
return 2
# استدعاء الأداة وتمرير الوسائط
result = await session.call_tool("lookup_order", {"order_id": order_id})
# result.content عادة قائمة محتويات (نص/JSON). نحاول طباعة JSON إن وجد.
payload = None
for c in getattr(result, "content", []):
if hasattr(c, "type") and c.type == "json":
payload = c.data
break
if hasattr(c, "type") and c.type == "text":
# قد يعيد الخادم نصًا JSONيًا
try:
payload = json.loads(c.text)
except Exception:
payload = c.text
break
if payload is None:
# قد يكون الاسترجاع المباشر لقيمة إرجاع الأداة
payload = getattr(result, "result", None)
print(json.dumps(payload, ensure_ascii=False, indent=2))
return 0
def main() -> None:
if len(sys.argv) < 2:
print("الاستعمال: python run_via_mcp.py <ORDER_ID>")
sys.exit(1)
order_id = sys.argv[1]
code = asyncio.run(main_async(order_id))
sys.exit(code)
if __name__ == "__main__":
main()
```
- تشغيل نفس استعلام الطلب مباشرة وعبر MCP
- إعداد البيئة مرة واحدة:
- export COMET_API_BASE_URL="https://api.example.com"
- export COMET_API_KEY="YOUR_COMET_API_KEY"
- تشغيل مباشر:
- python run_direct.py 123456789
- التشغيل عبر MCP:
- python run_via_mcp.py 123456789
- ملاحظات
- استبدل قيم البيئة بنقاط نهاية CometAPI الفعلية.
- يعتمد شكل الكائن المعاد من CometAPI على الخدمة؛ اطبع المخرجات للتحقق من البنية.
- إذا اختلفت واجهات mcp.client بحسب الإصدار، راجع توثيق الحزمة mcp للإصدار المثبت وعدّل أسماء الوحدات/الدوال التالية عند الحاجة:
- mcp.client.stdio.stdio_transport
- mcp.client.session.ClientSession.initialize / list_tools / call_tool
- يمكنك إضافة أمان/إعادة محاولات/سجلّات وفق احتياجك في comet_api.py دون تغيير واجهة الأداة.
استدعاء الدوال يمنح النموذج طريقة لطلب أداة. يوفّر MCP لتطبيقك طريقة موحّدة لاكتشاف الأدوات على خادم واستدعائها. استخدم التكامل المباشر مع الدوال لأداة أو عدد قليل من الأدوات التي تملكها تطبيقاتك. أضف MCP عندما تريد استهلاك خدمة متوافقة موجودة أو عرض الأدوات عبر واجهة مشتركة. أدناه، ستصل عملية الاستعلام عن الطلبات بالطريقتين عبر CometAPI مستخدماً دورة وكيل كاملة واحدة.
أهم النقاط
ابدأ بالتوجيه المباشر عندما تخدم بضع أدوات تطبيقاً واحداً؛ استخدم MCP عندما تجعل خدمة أدوات متوافقة أو واجهة أدوات مشتركة التكامل أسهل في الصيانة.
كلا المسارين يحتاجان دورة كاملة: وصف الأداة، استقبال الاستدعاء، تنفيذه، إعادة النتيجة وترك النموذج يجيب.
يمكنك الإبقاء على نفس الدالة المواجهة للنموذج بينما تغيّر تنفيذها من معالج مباشر إلى عميل MCP.
تمت المراجعة للوضوح ودقة المصدر ومصطلحات API الحالية.
استخدم هذا الملخص للحصول على إجابة سريعة، ثم اقرأ الدليل لفهم السياق والأمثلة وتفاصيل التنفيذ.
أبقِ عقود الأدوات ضيقة وافحص النتائج مقابل المهمة التي تريد من الوكيل إكمالها.
كيف يتكامل استدعاء الدوال وMCP
يمكن لوكيل الدعم شرح تأخر الشحن، لكنه يحتاج الوصول إلى نظام الطلبات ليخبر العميل أين طردُه. يقدّم استدعاء الدوال طريقةً للنموذج لطلب ذلك الاستعلام. تطبيقك ينفّذ الاستعلام ويعيد النتيجة. يمكن للمعالج استخدام مكتبة محلية، قاعدة بيانات، أو واجهة API بعيدة.
لإنجاز ذلك الطلب عبر MCP، يستخدم التطبيق عميلاً لاكتشاف أدوات الخادم بواسطة tools/list واستدعائها بواسطة tools/call. لا يزال التطبيق يقرر أي الأدوات المُكتشفة يُظهرها لنموذجه.
تمكين النموذج من طلب عملية مسماة ذات معاملات مُهيكلة
توحيد طريقة اكتشاف التطبيقات المتوافقة واستدعائها لأدوات الخادم
تعريفات الأدوات
تعريفات تُزوَّد بصيغة واجهة برمجة تطبيقات النموذج
تعريفات يوفّرها الخادم، بما في ذلك inputSchema
موقع التنفيذ
المعالج الذي يوجّه إليه التطبيق، وقد يستدعي خدمة محلية أو بعيدة
تنفيذ أداة خادم MCP، وقد يستدعي خدمة خلفية
هل يلزم خادم منفصل؟
لا تتطلب واجهة استدعاء الدوال خادماً بحد ذاتها
يلزم خادم MCP، لكن يمكن للعميل إطلاقه كعملية محلية عبر stdio؛ الخدمة البعيدة المنفصلة اختيارية
الاستخدام النموذجي
عدد قليل من الأدوات التي يملكها التطبيق مع توجيه مباشر
خدمات متوافقة موجودة أو واجهة أدوات يُعاد استخدامها عبر تطبيقات متعددة
هل يمكنهما العمل معاً؟
يمكن للتطبيق توجيه طلب وظيفة من النموذج عبر MCP
يلبّي عميل MCP ذلك الطلب عبر tools/call ويعيد النتيجة إلى التطبيق
ذلك الصف الأخير هو المفتاح للبناء بكليهما. يمكن للنموذج طلب get_order_status، بينما يختار التطبيق ما إذا كان سيستدعي معالجه الخاص أو خادم MCP. يمكن أن تبقى دالة النموذج كما هي.
اختر التكامل الذي يحتاجه تطبيقك
نوصي بالبدء بالتكامل المباشر عندما تملك بضع أدوات يستخدمها تطبيق واحد. يكون النشر أقل، والمسار من طلب النموذج إلى شيفرة عملك سهل التتبع.
يصبح MCP مفيداً عندما توفّر خدمة متوافقة القدرة المطلوبة بالفعل، أو عندما تحتاج عدة تطبيقات ذكاء اصطناعي إلى واجهة أدوات مشتركة. يمكن أن تخدم أداة الطلب نفسها مساعد الدعم وتطبيق العمليات الداخلية، مع تحكم كل مضيف في كيفية وصول مستخدميه إليها.
يمكن لمُوجِّه أن يدعم كلّاً من الدوال الداخلية وخدمات MCP، موجِّهاً كل عملية إلى تنفيذها. كما يمكن مشاركة المكتبات وواجهات REST API؛ اختر MCP عندما تكون واجهة الاكتشاف والاستدعاء المعيارية مفيدة للتطبيقات التي ستستهلك الأدوات.
ابنِ دورة أداة كاملة عبر CometAPI
سنستخدم عملية قراءة واحدة فقط، get_order_status، وسنجعل هناك طلباً تخيلياً واحداً، ORD-104. يستدعي المثال العملية مباشرة أولاً، ثم يشغلها عبر خادم MCP محلي. كلا الوضعين يستخدمان CometAPI Responses API لاستدلال النموذج.
الشكل 2. يمكن لدورة وكيل واحدة دعم التنفيذ المباشر وتنفيذ MCP. رسم توضيحي أصلي، يستند إلى معمارية MCP وتدفق استدعاء الدوال في CometAPI.
الخطوة 1 إعداد المشروع
استخدم Python 3.11 أو أحدث ومفتاح API لـ CometAPI. تم اختبار هذا الدليل باستخدام Python 3.12.14 وmcp==2.3.0. اتبع البدء السريع لـ CometAPI لإنشاء مفتاح. على macOS أو Linux، أنشئ مشروعاً وفعّل بيئة افتراضية:
استبدل الموضع المؤقت بمفتاحك وأبقِه خارج الشيفرة العامة. يثبّت هذا الدليل إصدار SDK الخاص بـ MCP المستخدم في المثال؛ يستهدف دليل الخادم الرسمي لـ Python واجهة 2.x. الأمران التاليان للوكيل يرسلان طلبات إلى CometAPI ويستهلكان رصيد API.
الخطوة 2 تعريف استعلام الطلب
احفظ الملف باسم orders.py. تُبقي البيانات الثابتة هذا الدليل مكتفياً ذاتياً؛ لاحقاً يمكنك استبدال الاستعلام بخدمتك الخاصة.
"""Read-only, invented order data; never connects to a real order system."""
import re
def get_order_status(order_id: str) -> dict[str, str]:
"""Look up an invented order; ORD-104 is the only available record."""
if not isinstance(order_id, str) or not re.fullmatch(r"ORD-[0-9]{3}", order_id):
raise ValueError("order_id must have the form ORD-104")
if order_id != "ORD-104":
raise ValueError("Order not found in this demo")
return {"order_id": order_id, "status": "shipped", "source": "fictional_demo"}
استدعاء get_order_status("ORD-104") يعيد هذا المثبّت:
احفظ السكربت الكامل التالي باسم agent.py. يسجل الدالة، يرسل السؤال إلى CometAPI، ينفّذ الاستدعاءات المطلوبة ويعيد كل نتيجة باستخدام call_id الأصلي.
يستخدم التعريف المواجه للنموذج حقل parameters في CometAPI Responses API. يوفّر MCP inputSchema؛ يتحقق هذا المثال من العقد المكتشف مقابل مخطط سلسلة واحدة order_id قبل إتاحة الدالة المُراجَعة.
"""A deliberately narrow direct/MCP bridge, not a general MCP adapter."""
import argparse
import asyncio
import json
import os
from pathlib import Path
import sys
from urllib.request import Request, urlopen
from mcp import Client, StdioServerParameters
from mcp.client.stdio import stdio_client
from orders import get_order_status
NAME = "get_order_status"
SCHEMA = {"type": "object", "properties": {"order_id": {"type": "string"}},
"required": ["order_id"], "additionalProperties": False}
TOOL = {"type": "function", "name": NAME, "description": "Look up fictional order ORD-104.",
"parameters": SCHEMA, "strict": True}
def validate_arguments(arguments):
# Exact validation for SCHEMA above; deliberately not a JSON Schema engine.
if (not isinstance(arguments, dict) or set(arguments) != {"order_id"}
or not isinstance(arguments["order_id"], str)):
raise ValueError("Expected exactly one string argument: order_id")
def validate_catalog(tools):
if len(tools) != 1 or tools[0].name != NAME:
raise RuntimeError("Unexpected MCP tool catalog")
schema = tools[0].input_schema
if (schema.get("type") != "object" or schema.get("required") != ["order_id"]
or set(schema.get("properties", {})) != {"order_id"}
or schema["properties"]["order_id"].get("type") != "string"):
raise RuntimeError("MCP schema does not match this reviewed demo tool")
async def dispatch(name, arguments, client=None):
if name != NAME:
raise ValueError("Tool is not allowlisted")
try:
validate_arguments(arguments)
if client is None:
return {"is_error": False, "data": get_order_status(**arguments)}
except ValueError as error:
return {"is_error": True, "error": str(error)}
result = await client.call_tool(name, arguments)
if getattr(result, "result_type", "complete") != "complete":
raise RuntimeError("Input-required MCP results are outside this demo")
if any(block.type != "text" for block in result.content):
raise RuntimeError("Non-text MCP content is outside this demo")
return {"is_error": bool(result.is_error),
"content": [block.text for block in result.content],
"structured_content": result.structured_content}
async def run_agent(send, execute, question, max_rounds=4):
history = [{"role": "user", "content": question}]
seen_call_ids = set()
for _ in range(max_rounds):
response = send({"model": "gpt-6-astra", "input": list(history),
"tools": [TOOL], "reasoning": {"effort": "low"}})
if response.get("status") != "completed" or response.get("error"):
raise RuntimeError("Model response failed or did not complete")
output = response["output"]
# CometAPI's documented manual replay: keep ALL items, omit top-level ids.
history.extend({key: value for key, value in item.items() if key != "id"}
for item in output)
blocks = [block for item in output if item["type"] == "message"
for block in item.get("content", [])]
if any(block["type"] == "refusal" for block in blocks):
raise RuntimeError("Model refused the request")
calls = [item for item in output if item["type"] == "function_call"]
if not calls:
text = "\n".join(block["text"] for block in blocks
if block["type"] == "output_text")
if not text:
raise RuntimeError("No final text returned")
return text
for call in calls:
call_id = call["call_id"]
if not isinstance(call_id, str) or not call_id or call_id in seen_call_ids:
raise ValueError("Missing or duplicate function call_id")
seen_call_ids.add(call_id)
try:
arguments = json.loads(call["arguments"])
except (ValueError, TypeError):
result = {"is_error": True, "error": "Arguments must be JSON text"}
else:
result = await execute(call["name"], arguments)
print(json.dumps({"tool": call["name"], "arguments": call["arguments"],
"result": result}), file=sys.stderr)
history.append({"type": "function_call_output", "call_id": call_id,
"output": json.dumps(result)})
raise RuntimeError("Tool loop reached its round limit")
def send_live(payload):
key = os.environ["COMETAPI_KEY"] # Only live mode reads the caller's key.
request = Request("https://api.cometapi.com/v1/responses",
data=json.dumps(payload).encode(),
headers={"Authorization": f"Bearer {key}",
"Content-Type": "application/json"})
with urlopen(request, timeout=45) as response:
return json.load(response)
def server_parameters():
return StdioServerParameters(command=sys.executable,
args=[str(Path(__file__).with_name("server.py"))])
async def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--mode", choices=["direct", "mcp"], required=True)
parser.add_argument("--question", default="Use the tool to check order ORD-104.")
args = parser.parse_args()
if args.mode == "direct":
answer = await run_agent(send_live, dispatch, args.question)
else:
async with Client(stdio_client(server_parameters())) as client:
discovered = await client.list_tools()
validate_catalog(discovered.tools)
async def execute(name, arguments):
return await dispatch(name, arguments, client)
answer = await run_agent(send_live, execute, args.question)
print(answer)
if __name__ == "__main__":
asyncio.run(main())
تحافظ الدورة على السؤال الأصلي وكل عنصر مسترجع في الاستجابة. ووفق تنسيق المحادثة في CometAPI Responses، تزيل حقول id على المستوى الأعلى من عناصر الإخراج قبل إعادة التشغيل وتُرفِق function_call_output لكل استدعاء. الحفاظ على بقية العناصر المُعادة يحافظ أيضاً على أي عناصر استدلال مطلوبة للجولة التالية.
الخطوة 4 تشغيل المسار المباشر
شغّل:
python agent.py --mode direct
يصف التطبيق get_order_status للنموذج. عندما يطلبه النموذج، يتحقق dispatch() من الاسم والمعاملات، ثم يستدعي الدالة في orders.py. تعود النتيجة إلى المحادثة، ويمكن للنموذج تحويلها إلى إجابة.
استخدم تتبّع الأداة المطبوع على الطرفية للتحقق من أن الاستعلام استخدم ORD-104 وأعاد status: shipped. ينبغي أن تعكس الإجابة النهائية تلك النتيجة؛ قد تتفاوت الصياغة. لديك الآن دورة استدعاء دوال كاملة، من سؤال المستخدم إلى عملية ينفذها التطبيق واستجابة لاحقة من النموذج.
تُبقي الخطوة التالية النموذج ودورة المحادثة كما هما. تنقل التنفيذ خلف خادم MCP وتسمح للتطبيق باكتشاف الأداة واستدعائها عبر عميل.
الخطوة 5 إتاحة الاستعلام كأداة MCP
احفظ هذا باسم server.py بجانب الملفين الآخرين:
"""One read-only MCP tool, served over stdio. No stdout logging."""
from mcp.server import MCPServer
from mcp.server.mcpserver.exceptions import ToolError
from orders import get_order_status as lookup_order
server = MCPServer("fictional-orders")
@server.tool(structured_output=True)
def get_order_status(order_id: str) -> dict[str, str]:
"""Look up fictional order ORD-104; this demo has no real customer data."""
try:
return lookup_order(order_id)
except ValueError as error:
raise ToolError(str(error)) from error
if __name__ == "__main__":
server.run(transport="stdio")
يقوم SDK بإنشاء تعريف الأداة من توقيع الدالة ونص التوثيق. يستخدم الخادم stdio، حيث يطلقه العميل كعملية فرعية ويتبادل رسائل البروتوكول عبر تدفّقاته القياسية. أبقِ سجلات التطبيق بعيدة عن المخرجات القياسية للخادم.
الخطوة 6 تشغيل مسار MCP
شغّل:
python agent.py --mode mcp
يفتح فرع mcp في main() الملف server.py، ويستدعي list_tools() ويتحقق من عقد أداة الطلب. عندما يطلب النموذج الاستعلام، يستخدم نفس الموجّه الآن client.call_tool(). يشغّل الخادم الدالة، ويعيد التطبيق نتيجتها إلى النموذج.
قارن التشغيلين وفق نفس المعايير: الأداة الصحيحة، ORD-104 كمعاملها، نتيجة ناجحة تحتوي على shipped، وإجابة نهائية متّسقة مع تلك النتيجة. لقد تغيّر مسار التنفيذ؛ بينما بقيت المهمة والدالة المواجهة للنموذج كما هما.
تتضمن الحزمة المثال كل الملفات الثلاثة أعلاه، بالإضافة إلى فحوصات دون اتصال لإعادة الاستخدام بسهولة. تُمارس هذه الفحوصات خادم MCP محلياً حقيقياً مع استجابات نموذج مُبرمجة؛ مخرجات النموذج الحي منفصلة عن ذلك التحقق المحلي.
تكييف المثال مع أدواتك الخاصة
استبدل بيانات الطلب الثابتة بأصغر عملية يحتاجها تطبيقك فعلياً. لسؤال الشحن، أعد معرف الطلب وحقول حالة مفيدة. تمنح النتيجة المدمجة النموذجَ مواد أقل غير ذات صلة ليفسّرها وتجعل الإجابة أسهل للتحقق.
أبقِ وصف الأداة وعقد المعاملات محدداً. يقبل هذا المثال سلسلة واحدة بالضبط، والمضيف يتحقق من اسم الأداة المطلوبة قبل التوجيه. توصي إرشادات أمان MCP بأن تتحقق الخوادم من المدخلات وتطبّق ضوابط الوصول. لخدمة طلبات حقيقية، استمد هوية العميل من سياق التطبيق الموثوق وطبّق الوصول إلى طلب ذلك العميل داخل الخدمة. لا يمكن لمعرف طلب يورّده النموذج أن يثبت الملكية.
بمجرد أن تعمل الأداة، قيّم المهام المكتملة، الزمن من طرف إلى طرف والتكلفة الفعلية. أضف MCP حيث تساعد واجهة خدمته التطبيقات التي تحتاج الأداة، وأبقِ المعالجات المباشرة حيث تكون أسهل في التشغيل.
الأسئلة الشائعة
هل يحل MCP محل استدعاء الدوال؟
يتعاملان مع واجهات مختلفة: يربط MCP عميل التطبيق بخادم. في هذا المثال، يطلب النموذج دالةً ويُلبي التطبيق ذلك الطلب عبر عميل MCP. كلاهما يشاركان في نفس دورة الوكيل.
هل يمكن لأداة MCP استدعاء REST API موجودة؟
نعم. استبدل الاستعلام داخل أداة MCP باستدعاء إلى واجهة API الخاصة بك. ينشر خادم MCP عقد الأداة ويتعامل مع استدعاءات الأدوات؛ بينما تستمر خدمتك الحالية في تقديم سلوكها التجاري.
متى يجب أن أستخدم خادم MCP بعيداً؟
استخدم خدمة بعيدة عندما يحتاج العملاء للوصول إلى خادم مُنتشر منفصلاً بدلاً من إطلاق عملية محلية. يعرّف MCP Streamable HTTP لذلك الاتصال وstdio لعملية فرعية يطلقها العميل. اضبط تفويض الخادم البعيد وفق المتصلين المقصودين.
الخاتمة
لتطبيق واحد، استبدل السجل التخيلي في orders.py باستعلام قراءة واحد من خدمتك وابدأ بالوضع المباشر.
إذا كنت تحتاج خدمة MCP موجودة أو واجهة أدوات مشتركة، فاستخدم مسار MCP مع الحفاظ على نفس الفحوصات: العملية الصحيحة، السجل الصحيح وإجابة مدعومة بالبيانات المُعادة.