إنتقل إلى المحتوى الرئيسي

Agent Client Protocol (ACP) مع Cursor

Agent Client Protocol with Cursor

Agent Client Protocol (ACP) معيار مفتوح يتيح لعميل محرّر ووكيل برمجة التحدّث مع بعضهما البعض عبر واجهة مشتركة قائمة على JSON-RPC. فبدلًا من أن يبني كل محرّر جسرًا خاصًا به إلى كل وكيل، يتحدّث العميل والوكيل كلاهما ACP، فتصبح المزاوجة قابلة للتبادل. ويستطيع Cursor أن يقوم بدور جانب الوكيل في تلك المحادثة عبر cursor-agent، ما يعني أن أي عميل متوافق مع ACP يمكنه تشغيل وكيل Cursor. يشرح هذا الدليل البروتوكول، ودورة حياة الجلسة، وكيفية عرض Cursor عبر ACP، وتدفّق الرسائل عمليًا، وكيفية بناء عميل خاص بك، وأين توجد الثغرات الحالية.

ما هو Agent Client Protocol​

ACP معيار مفتوح يعرّف كيف يتحدّث عميل محرّر مع وكيل برمجة. وقد شاعه Zed، الذي يستخدمه لتمكين محرّره من تشغيل وكلاء مختلفين، لكنه محايد عمدًا تجاه المحرّر والوكيل.

خيارات التصميم الجوهرية بسيطة:

  • النقل هو JSON-RPC عبر stdio. يُشغّل العميل الوكيل كعملية فرعية ويتبادل رسائل JSON-RPC مفصولة بأسطر جديدة على stdin وstdout.
  • يمكن لأي من الجانبين إرسال طلبات وإشعارات. يطلب العميل من الوكيل بدء جلسة وإرسال مطالبات؛ ويطلب الوكيل من العميل الإذن لتشغيل الأدوات ويبثّ التقدّم عائدًا.
  • الجلسات صريحة. يحدث العمل داخل جلسة تُنشأ بـ newSession، تحمل دليل عمل وخيارات.

ولأن النقل stdio عادي والرسائل JSON عادي، يعمل ACP في أي مكان يمكن فيه تشغيل عملية: المحرّرات المحلية، وأدوات الطرفية، ومشغّلات CI بلا واجهة.

ACP ليس MCP

يربط MCP الوكيل بأدوات خارجية ومصادر بيانات. أما ACP فيربط عميل محرّر بوكيل. يحلّان مشكلتين مختلفتين وكثيرًا ما يُستخدمان معًا: فوكيل ACP قد يكون هو نفسه عميل MCP.

معمارية ACP​

للمعمارية ثلاثة أجزاء: العميل والوكيل والنقل بينهما. يملك العميل الواجهة والأذونات؛ ويملك الوكيل النموذج والأدوات.

الطبقةالدورأمثلة
العميليعرض المحادثة، ويجمع إدخال المستخدم، ويجيب طلبات الإذنZed، محرّر مخصّص، سكربت بلا واجهة
الوكيليشغّل النموذج، وينفّذ الأدوات، ويبثّ التحديثاتcursor-agent acp، وكلاء ACP آخرون
النقلينقل رسائل JSON-RPC في الاتجاهينJSON مفصول بأسطر جديدة عبر stdio

دورة حياة الجلسة تسلسل ثابت. وبمجرد أن تفهمها، يُقرأ تدفّق الرسائل كسكربت.

initialize -> client and agent agree on protocol version and capabilities
newSession -> client asks the agent to create a session with a cwd and options
prompt -> client sends user input into the session
session/update -> agent streams progress, tool calls, and messages back (notification)
permission request-> agent asks the client to approve a tool action
cancel -> client aborts the current turn

لا يتصرّف الوكيل على مورد محمي دون أن يسأل العميل أولًا. وتلك الرحلة المزدوجة للأذونات هي ما يُبقي الواجهة مسيطرة على وكيل مستقل.

لماذا يهمّ ACP​

يهمّ ACP لأنه يفصل المحرّر عن الوكيل. وتظهر القيمة في ثلاثة مواضع.

قابلية تنقّل المحرّر​

إذا تحدّث Cursor وعميل آخر كلاهما ACP، يمكنك استخدام نفس الوكيل في أي منهما دون تكامل مخصّص. فإعداد وكيلك واختيارك للنموذج وقواعدك تنتقل مع الوكيل لا مع المحرّر.

أعد استخدام وكيل Cursor في أي عميل متوافق​

بدلًا من إعادة تنفيذ سلوك الوكيل في كل محرّر، يمكنك توجيه أي عميل ACP إلى cursor-agent والحصول على تفكير Cursor واستخدام أدواته واختيار النموذج داخل واجهة ذلك العميل. وهذا مفيد خاصةً للفرق التي توحّدت على محرّر ليس Cursor لكنها تريد سلوك وكيل Cursor.

الأتمتة بلا واجهة​

ولأن النقل stdio، يمكنك تشغيل الوكيل من سكربت أو مهمة CI بلا محرّر إطلاقًا. وهذا يجعل تشغيلات الوكيل المبرمجة والقابلة للتكرار ممكنة في خطوط الأنابيب.

# A headless run is just a client that writes JSON-RPC to the agent's stdin
cat initialize.json newSession.json prompt.json | cursor-agent acp
التشغيلات بلا واجهة لا تزال تحتاج أذونات

عندما تشغّل الوكيل من سكربت، لا يوجد إنسان ينقر «موافقة» على استدعاء أداة. حدّد نمط الأذونات مسبقًا، ولا تجعل التشغيل التلقائي افتراضيًا في بيئة فيها بيانات اعتماد حسّاسة.

عرض Cursor عبر ACP باستخدام cursor-agent​

cursor-agent هو CLI الذي يمكنه أداء دور جانب وكيل ACP في الاتصال. ثبّته بنفس طريقة تثبيت Cursor CLI.

# Install via npm
npm install -g cursor-agent

# Or install via the Cursor CLI script
curl https://cursor.com/install -fsS | bash

# Confirm it is on your PATH
cursor-agent --version

التشغيل في نمط ACP​

نقطة دخول ACP أمر فرعي. وعند تشغيله، تتحدّث العملية JSON-RPC على stdio وتنتظر اتصال عميل.

# Start the agent as an ACP server, talking JSON-RPC over stdio
cursor-agent acp

# Useful flags
cursor-agent acp --cwd /path/to/project # set the working directory
cursor-agent acp --model claude-sonnet-4-5 # pin a model for the session
cursor-agent acp --verbose # log messages for debugging

المصادقة​

يحتاج الوكيل بيانات اعتماد قبل أن يخدم المطالبات. سجّل الدخول مرة وتُخزَّن بيانات الاعتماد محليًا.

# Interactive login, opens a browser flow
cursor-agent login

# Check current auth status
cursor-agent status

# Log out and clear stored credentials
cursor-agent logout

إذا بدأ الوكيل لكن فشلت كل مطالبة، فالسبب تقريبًا دائمًا مصادقة مفقودة أو منتهية. شغّل cursor-agent status قبل تصحيح أي شيء آخر.

ضبط جلسة​

تُنشأ الجلسة بدليل عمل وخيارات تحكم كيف يتصرّف الوكيل لتلك المحادثة.

اختيار النموذج​

يمكن تثبيت النموذج عند الإطلاق أو اختياره لكل جلسة. وتمريره لكل جلسة يتيح لعملية وكيل واحدة خدمة عملاء مختلفين بتفضيلات نماذج مختلفة.

{
"method": "session/new",
"params": {
"cwd": "/home/dev/project",
"model": "claude-sonnet-4-5",
"mcpServers": []
}
}

الإبلاغ عن استخدام نافذة السياق​

يعرض بعض العملاء مدى امتلاء نافذة السياق. ويُبلّغ الوكيل عن استخدام الرموز كجزء من تحديثات الجلسة حيث يدعمه العميل.

{
"method": "session/update",
"params": {
"sessionId": "sess_01HXYZ",
"update": {
"type": "usage",
"inputTokens": 12480,
"outputTokens": 2310,
"contextLimit": 200000
}
}
}

أنماط الأذونات ودليل العمل​

تحدّد أنماط الأذونات ما إذا كان الوكيل يسأل قبل تشغيل أداة. في عميل تفاعلي، الافتراضي هو السؤال. وفي الأتمتة بلا واجهة، تختار عمدًا.

  • اسأل لكل أداة: يرسل الوكيل طلب إذن وينتظر. الأسلم، والأفضل للمحرّرات التفاعلية.
  • التشغيل التلقائي: ينفّذ الوكيل داخل دليل العمل دون سؤال. سريع، ولا يصلح إلا في صندوق رمل.
  • القراءة فقط: قد يقرأ الوكيل ويبحث لكنه لا يكتب أبدًا. جيد للجلسات المخصّصة للمراجعة.

الـ cwd في newSession يحدّ ما يعتبره الوكيل المشروع. ولا ينبغي لمس الملفات خارجه.

مثال لتدفّق رسائل JSON-RPC​

التالي محادثة أدنى لكن كاملة. كل رسالة سطر JSON واحد على السلك.

التهيئة​

يفتتح العميل بـ initialize، فيردّ الوكيل بقدراته وإصدار البروتوكول.

{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": 1,
"clientCapabilities": {
"fs": { "readTextFile": true, "writeTextFile": true },
"terminal": true
}
}
}
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": 1,
"agentCapabilities": {
"promptCapabilities": { "image": false },
"loadSession": true
}
}
}

جلسة جديدة​

بمجرد الاتفاق على القدرات، يُنشئ العميل جلسة ويستعيد معرّفًا.

{
"jsonrpc": "2.0",
"id": 2,
"method": "session/new",
"params": { "cwd": "/home/dev/project", "mcpServers": [] }
}
{
"jsonrpc": "2.0",
"id": 2,
"result": { "sessionId": "sess_01HXYZ" }
}

المطالبة​

يرسل العميل دورة المستخدم. لاحظ أن هذا طلب؛ يقرّ به الوكيل، لكن المحتوى الفعلي يصل كإشعارات مُتدفّقة.

{
"jsonrpc": "2.0",
"id": 3,
"method": "session/prompt",
"params": {
"sessionId": "sess_01HXYZ",
"content": [{ "type": "text", "text": "Add input validation to the signup route." }]
}
}

التحديثات المُتدفّقة​

بينما يعمل الوكيل، يُصدر إشعارات session/update بلا معرّف، لأنها أحادية الاتجاه.

{
"jsonrpc": "2.0",
"method": "session/update",
"params": {
"sessionId": "sess_01HXYZ",
"update": { "type": "agent_message_chunk", "text": "Reading src/routes/signup.ts" }
}
}

طلب الإذن​

قبل إجراء محمي، يسأل الوكيل العميل. ويردّ العميل عبر آلية طلب JSON-RPC القياسية.

{
"jsonrpc": "2.0",
"id": "perm-1",
"method": "session/request_permission",
"params": {
"sessionId": "sess_01HXYZ",
"toolCall": {
"title": "Write file",
"path": "src/routes/signup.ts"
}
}
}
{
"jsonrpc": "2.0",
"id": "perm-1",
"result": { "outcome": { "outcome": "selected", "optionId": "allow" } }
}

الإلغاء​

لإحباط دورة، يرسل العميل session/cancel. يوقف الوكيل العمل الحالي وينهي طلب المطالبة بسبب إيقاف الإلغاء.

{
"jsonrpc": "2.0",
"method": "session/cancel",
"params": { "sessionId": "sess_01HXYZ" }
}

بناء عميل ACP خاص بك​

يشغّل العميل الأدنى الوكيل، ويكتب أسطر JSON-RPC إلى stdin، ويحلّل JSON المفصول بأسطر جديدة من stdout. يُظهر المقتطف أدناه الشكل في TypeScript.

import { spawn } from "node:child_process";
import { createInterface } from "node:readline";

const agent = spawn("cursor-agent", ["acp", "--cwd", process.cwd()], {
stdio: ["pipe", "pipe", "inherit"],
});

let nextId = 1;

function send(method: string, params: unknown): void {
const message = { jsonrpc: "2.0", id: nextId++, method, params };
agent.stdin.write(JSON.stringify(message) + "\n");
}

// Read newline-delimited JSON-RPC from the agent
const reader = createInterface({ input: agent.stdout });
reader.on("line", (line) => {
if (!line.trim()) return;
const msg = JSON.parse(line);

// Notifications have no id
if (!("id" in msg)) {
if (msg.method === "session/update") {
console.log("update:", JSON.stringify(msg.params.update));
}
return;
}

// A request from the agent needs a reply
if (msg.method === "session/request_permission") {
const reply = {
jsonrpc: "2.0",
id: msg.id,
result: { outcome: { outcome: "selected", optionId: "allow" } },
};
agent.stdin.write(JSON.stringify(reply) + "\n");
return;
}

console.log("response:", JSON.stringify(msg.result ?? msg.error));
});

// Kick off the session
send("initialize", { protocolVersion: 1, clientCapabilities: {} });
send("session/new", { cwd: process.cwd(), mcpServers: [] });

القواعد الأساسية التي يجب تذكّرها: كل طلب له id وينتظر ردًّا مطابقًا، والإشعارات لا تحمل id أبدًا، ويمكن للوكيل إرسال طلبات إليك أيضًا، لذا يجب أن يتعامل قارئك مع الاتجاهين.

سجّل السلك الخام

عندما يتصرّف تكامل عميل بشكل خاطئ، سجّل كل سطر في الاتجاهين قبل لمس المنطق. أخطاء ACP عادةً id مفقود أو سطر جديد مفقود أو ردّ لم يُرسَل قط، والسلك الخام يجعل الثلاثة جميعًا واضحة.

القيود والثغرات الحالية​

ACP حديث، وليست كل قدرة في Cursor معروضة عبره. اعرف ما تتخلى عنه قبل أن تبني عليه.

لا تخصيص لمطالبة النظام​

لا تتيح خيارات جلسة ACP حاليًا لعميل استبدال مطالبة النظام لدى الوكيل أو توسيعها كما يفعل .cursor/rules داخل IDE. فالقواعد المضبوطة في المشروع لا يزال الوكيل يطبّقها، لكن العميل لا يستطيع حقن قواعده الخاصة.

إبلاغ غير مكتمل عن نافذة السياق​

الإبلاغ عن الاستخدام موجود لكنه ليس مضمونًا أن يكون مكتملًا أو آنيًا. ولا ينبغي لعميل يريد عدّاد سياق دقيق أن يعتمد فقط على تحديثات استخدام ACP.

فروق تكافؤ الميزات مقابل IDE​

عدة ميزات في IDE غير متاحة أو مخفّضة عبر ACP:

  • لا مراجعة مرئية للفرق للتعديلات المقترحة داخل العميل ما لم ينفّذها العميل.
  • الوكلاء في الخلفية ووكلاء السحابة لا تُشغَّل عبر هذا المسار.
  • تختلف بعض سلوكيات الأدوات وMCP عن نمط وكيل IDE.
  • إكمال Tab نظام منفصل وليس جزءًا من ACP إطلاقًا.

استكشاف الأخطاء​

الوكيل غير موجود​

إذا شغّل العميل cursor-agent وحصل على ENOENT، فالملف التنفيذي ليس على PATH للعملية التي تُشغّله. استخدم مسارًا مطلقًا في نداء التشغيل، وتذكّر أن عميل GUI قد يرث PATH مختلفًا عن طرفيتك.

# Find the absolute path and use it in the client config
which cursor-agent

أخطاء المصادقة​

كل مطالبة تفشل بخطأ مصادقة تعني أن الوكيل لا يملك بيانات اعتماد صالحة. شغّل cursor-agent status ثم cursor-agent login، وتحقق من أن العميل لا يعمل تحت مستخدم أو دليل رئيسي مختلف عن الذي سجّلت الدخول به.

لا تحديثات مُتدفّقة​

إذا عاد طلب المطالبة لكن التحديثات لا تصل أبدًا، فالعميل على الأرجح لا يحلّل الإشعارات بشكل صحيح. الإشعارات بلا id، فقارئ يتعامل مع الردود فقط يُسقطها. أكّد أن قارئ أسطرك يُصدر عند السطر الجديد وأن محلّلك يتعامل مع الرسائل بلا id.

العميل لا يستقبل طلبات الإذن أبدًا​

إذا شغّل الوكيل أدوات دون سؤال، فقد أُنشئت الجلسة بنمط أذونات تشغيل تلقائي، أو لم يُعلن العميل قدرته على التعامل مع طلبات الإذن أثناء initialize. تحقّق من خيارات الجلسة والقدرات التي أرسلتها معًا.

العرضالسببالإصلاح
ENOENT عند التشغيلالملف التنفيذي للوكيل ليس على PATHاستخدم مسارًا مطلقًا في نداء التشغيل
كل مطالبة تفشلمصادقة مفقودة أو منتهيةشغّل cursor-agent status ثم cursor-agent login
لا رسائل session/updateالقارئ يتعامل فقط مع الردود التي تحمل idتعامل مع الإشعارات بلا id
لا طلبات إذننمط تشغيل تلقائي أو قدرة عميل مفقودةاضبط اسأل-لكل-أداة وأعلن القدرة
المطالبة تتعلّق للأبدردّ على طلب لم يُرسَل قطردّ بـ id مطابق لكل طلب من الوكيل
أخطاء تحليل الردّرسائل مدموجة بلا أسطر جديدةاكتب واقرأ كائن JSON واحدًا بالضبط لكل سطر

يحوّل ACP علاقة المحرّر-الوكيل إلى عقد، وذلك العقد هو ما يجعل وكيل Cursor قابلًا للاستخدام من أي مكان يتحدّث البروتوكول. ابدأ بتدفّق الرسائل أعلاه، وسجّل السلك، فيصبح التكامل قليلًا من التوصيلات لا إعادة بناء كاملة.