كيف تبني خادم MCP محليًا وتربطه بتطبيق Claude (مع كود يعمل)

ابنِ خادم MCP محليًا من مجلد فارغ: ثبّت TypeScript SDK، وسجّل أداتين تعملان، واختبرهما في MCP Inspector، ثم اربط الخادم بتطبيق Claude Desktop و Claude Code. يتضمن ملفات الإعداد، وإصلاحات لمسارات Windows، وقائمة تحقق للأخطاء التي تُفسد معظم الإعدادات.

كيف تبني خادم MCP محليًا وتربطه بتطبيق Claude (مع كود يعمل)
Cristian Da Conceicao
مؤسس Picasso IA

تكتفي معظم دروس MCP بمثال "hello world" وتتركك تنظر إلى شارة Disconnected الحمراء. ينتهي هذا الدرس بخادم يعمل على جهازك، وClaude يستدعي أدواته، وقائمة تحقق قصيرة للأخطاء التي توقع معظم الناس فيها. ستكتب نحو 70 سطرًا من TypeScript، وتختبرها في أداة فحص تعمل عبر المتصفح، ثم تربط النتيجة بكلٍ من Claude Desktop وClaude Code.

الخادم أداة صغيرة للملاحظات: يستطيع Claude حفظ ملاحظة في ملف JSON على قرصك، والبحث فيها لاحقًا. وهو بسيط عمدًا، لأن آلية الربط واحدة سواء كانت أدواتك تقرأ ملف ملاحظات، أو تستعلم من قاعدة بيانات، أو تستدعي نموذج صور. جمّعتُ ملف الخادم التالي وشغّلته على الإصدار 1.32 من TypeScript SDK، لذلك يُبنى الكود تمامًا كما هو معروض.

مطوّر يكتب في الطرفية على حاسوب محمول على مكتب من خشب البلوط في ضوء الصباح

ما الذي تبنيه فعلًا

MCP في فقرتين

بروتوكول سياق النموذج (MCP) معيار مفتوح قدّمته Anthropic في نوفمبر 2024، ويتيح لتطبيق الذكاء الاصطناعي التواصل مع الأدوات الخارجية بطريقة واحدة ومتسقة. فبدلًا من أن يخترع كل تطبيق صيغة إضافات خاصة به، يعرض خادم MCP قدراته، ويعثر عليها عميل MCP مثل Claude Desktop أو Claude Code ويستدعيها. الرسائل عبارة عن JSON-RPC 2.0 عادي، لذلك يمكن كتابة الخادم بأي لغة.

يستطيع الخادم أن يقدّم ثلاثة أنواع من الأشياء:

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

يلتزم هذا الدرس بالأدوات فقط، لأنها الأسهل في الاختبار، والأكثر فائدة في اليوم الأول.

منظر علوي لدفتر ملاحظات عليه رسم يدوي لثلاثة صناديق مترابطة بأسهم

لماذا تشغّله محليًا

يعمل الخادم المحلي كعملية فرعية تابعة للعميل، على جهازك، وبملفاتك وصلاحياتك. لا شيء يُعرَّض للإنترنت، ولا توجد فاتورة استضافة، والتكرار سريع: عدّل الملف، ثم أعد البناء، ثم أعد التشغيل. ويستخدم هذا الخادم ناقل stdio: يُشغّل العميل برنامجك ويتواصل معه عبر المدخل والمخرج القياسيين.

stdio (محلي)Streamable HTTP (عن بُعد)
مكان التشغيلعملية فرعية على حاسوبكخادم ويب تستضيفه أنت أو غيرك
من يمكنه الوصولالتطبيق الذي شغّله فقطأي شخص لديه الرابط وبيانات الدخول
المصادقةلا توجد، إذ يرث حساب مستخدمكمطلوبة (OAuth أو رموز)
الأنسب لـالأدوات الشخصية، والوصول إلى الملفات، والتطويرالأدوات المشتركة للفرق، وتكاملات SaaS

💡 معلومة مفيدة: حلّ Streamable HTTP محل ناقل HTTP+SSE القديم في مراجعة المواصفة 2025-03-26. ولأن المتصفح لا يستطيع تشغيل عملية على حاسوبك، لا يمكن إضافة خادم stdio إلى claude.ai في المتصفح. الخوادم البعيدة فقط تعمل هناك.

منظر من أسفل لحاسوب صغير رمادي الغرافيت بجانب حاسوب محمول فضي، متصلين بكابل USB-C مضفور

إعداد المشروع

ما تحتاج إلى تثبيته

الأداةالإصدارالتحقق بـ
Node.js20 LTS أو أحدثnode --version
npmيأتي مع Nodenpm --version
Claude Desktopالأحدث، على macOS أو WindowsSettings ثم Developer
Claude Code (اختياري)الأحدثclaude --version

يتوفر Claude Desktop لنظامي macOS وWindows. على Linux، استخدم مسار Claude Code في قسم الربط أدناه؛ الخادم نفسه لا يتغير.

إنشاء المشروع وضبط إعداداته

mkdir local-notes-mcp && cd local-notes-mcp
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node
mkdir src

افتح package.json وأضف ثلاثة أشياء بجوار الاعتماديات التي أنشأها npm: علامة وحدات ES وسكربتين.

{
  "name": "local-notes-mcp",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "build": "tsc",
    "start": "node build/index.js"
  }
}

ثم أنشئ tsconfig.json في جذر المشروع:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "outDir": "build",
    "rootDir": "src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "types": ["node"]
  },
  "include": ["src"]
}

⚠️ انتبه: TypeScript 7، وهو الإصدار الذي يثبّته npm اليوم، لم يعد يحمّل حزم @types من تلقاء نفسه. بدون سطر "types": ["node"] ستحصل على Cannot find name 'process' وأخطاء مشابهة عند كل استيراد في Node.

لقطة مقرّبة ليدي مطوّر وهما تكتبان فوق لوحة المفاتيح على مكتب تضيئه مصباح دافئ

اكتب أول أداتين لك

ملف الخادم الكامل

احفظ هذا الملف باسم src/index.ts. يعرض save_note وsearch_notes، ويخزّن كل شيء في ملف JSON واحد.

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import { promises as fs } from "node:fs";
import os from "node:os";
import path from "node:path";

const NOTES_DIR = process.env.NOTES_DIR ?? path.join(os.homedir(), "mcp-notes");
const NOTES_FILE = path.join(NOTES_DIR, "notes.json");

type Note = { id: number; title: string; body: string; createdAt: string };

async function readNotes(): Promise<Note[]> {
  try {
    return JSON.parse(await fs.readFile(NOTES_FILE, "utf8"));
  } catch {
    return [];
  }
}

const server = new McpServer({ name: "local-notes", version: "1.0.0" });

server.registerTool(
  "save_note",
  {
    title: "Save note",
    description: "Save a short note with a title and a body to the local notes file.",
    inputSchema: {
      title: z.string().min(1).max(120).describe("Short title for the note"),
      body: z.string().min(1).describe("The text of the note"),
    },
  },
  async ({ title, body }) => {
    const notes = await readNotes();
    const note: Note = {
      id: notes.length + 1,
      title,
      body,
      createdAt: new Date().toISOString(),
    };
    await fs.mkdir(NOTES_DIR, { recursive: true });
    await fs.writeFile(NOTES_FILE, JSON.stringify([...notes, note], null, 2));
    return { content: [{ type: "text", text: `Saved note #${note.id}: ${title}` }] };
  }
);

server.registerTool(
  "search_notes",
  {
    title: "Search notes",
    description: "Find saved notes whose title or body contains a word or phrase.",
    inputSchema: {
      query: z.string().min(1).describe("Word or phrase to look for"),
    },
  },
  async ({ query }) => {
    const q = query.toLowerCase();
    const hits = (await readNotes()).filter((n) =>
      `${n.title} ${n.body}`.toLowerCase().includes(q)
    );
    if (hits.length === 0) {
      return { content: [{ type: "text", text: `No notes match "${query}".` }] };
    }
    const text = hits.map((n) => `#${n.id} ${n.title}\n${n.body}`).join("\n\n");
    return { content: [{ type: "text", text }] };
  }
);

const transport = new StdioServerTransport();
await server.connect(transport);
console.error("local-notes MCP server running on stdio");

وظيفة كل جزء

  • McpServer هو الصنف عالي المستوى. الاسم name والإصدار version اللذان تمررهما يظهران في قائمة الخوادم لدى العميل وفي سجلاته.
  • registerTool يأخذ اسم أداة، وكائن إعداد (title وdescription وinputSchema)، ومعالجًا غير متزامن.
  • مخطط Zod يُتحقق منه قبل تشغيل المعالج، ثم يُحوَّل إلى JSON Schema حتى يستطيع Claude قراءته. كل وصف .describe() يصل إلى النموذج.
  • القيمة المرجعة تكون دائمًا { content: [...] }. النص العادي أبسط نوع محتوى، والصور وروابط الموارد مدعومة أيضًا.
  • StdioServerTransport يقرأ الطلبات من stdin ويكتب الردود إلى stdout.

💡 نصيحة: اكتب الأوصاف للنموذج، لا للبشر. الوصف "ابحث عن الملاحظات المحفوظة التي يحتوي عنوانها أو نصها على كلمة أو عبارة" يخبر Claude متى يستدعي الأداة. أما "بحث" فلا يفعل ذلك. ويختار Claude الأدوات غالبًا من أسمائها وأوصافها.

بما أن search_notes لا يغيّر أي شيء أبدًا، ضع ذلك عليه في إعداداته: annotations: { readOnlyHint: true }. التلميحات استشارية، والعملاء يقررون بأنفسهم مقدار الثقة التي يمنحونها لها، لكنها تساعد العملاء الملتزمين على معاملة الأدوات التي تقرأ فقط بلطف أكبر.

مطوّرة تقف عند مكتب قابل للتعديل الارتفاع وتراجع الكود على شاشة عريضة

لا تطبع إلى stdout أبدًا

مع stdio، يكون stdout هو قناة البروتوكول. سطر console.log("started") واحد شارد يدفع سطرًا غير JSON إلى التدفق، وأغلب العملاء سيقطعون الاتصال أو يعرضون الخادم على أنه فشل. تذكّر هذه القاعدة وستتجنب أكثر أخطاء اليوم الأول شيوعًا:

  • افعل: استخدم console.error("message")، الذي يكتب إلى stderr، حيث تجمع العملاء السجلات.
  • لا تفعل: استخدم console.log(...) أو process.stdout.write(...) في أي موضع من خادمك، بما في ذلك داخل المكتبات التي تستوردها.

اختبره قبل أن يختبره Claude

شغّل MCP Inspector

MCP Inspector هو أداة التصحيح الرسمية. يشغّل خادمك بالطريقة نفسها التي يشغّله بها العميل، ويعطيك أزرارًا بدلًا من الأوامر النصية.

npm run build
npx @modelcontextprotocol/inspector node build/index.js

تفتح صفحة في متصفحك. انقر Connect، وافتح تبويب Tools، واضغط List Tools. يجب أن ترى save_note وsearch_notes مع مخططاتهما. شغّل save_note بعنوان ونص، ثم شغّل search_notes بكلمة من ذلك النص. يعيد الاستدعاء الأول Saved note #1: Standup، ويظهر ملف الملاحظات في مجلد mcp-notes داخل مجلدك الشخصي (أو في NOTES_DIR إذا حددت مسارًا آخر).

زميلان يميلان نحو شاشة حاسوب محمول على طاولة خشبية مشتركة

أرسل رسائل JSON-RPC خام

إذا أردت رؤية البروتوكول نفسه، فإن stdio يستخدم رسالة JSON واحدة في كل سطر. ضع هذه الأسطر الثلاثة في requests.jsonl:

{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"smoke","version":"0.0.1"}}}
{"jsonrpc":"2.0","method":"notifications/initialized"}
{"jsonrpc":"2.0","id":2,"method":"tools/list"}

ثم مرّرها إلى الخادم، وأبقِ stdin مفتوحًا لحظة حتى تتمكن الردود من الخروج:

(cat requests.jsonl; sleep 2) | node build/index.js

يؤكد الرد الأول المصافحة، مع إصدار البروتوكول الذي اتفق عليه الخادم وserverInfo الخاص بك:

{"result":{"protocolVersion":"2025-06-18","capabilities":{"tools":{"listChanged":true}},"serverInfo":{"name":"local-notes","version":"1.0.0"}},"jsonrpc":"2.0","id":1}

يسرد الرد الثاني الأداتين مع مخططات JSON الخاصة بهما. هذا التبادل هو كل ما يفعله Claude عند الاتصال: مصافحة، ثم سرد الأدوات، ثم استدعاؤها.

اربطه بـ Claude

عدّل إعداد Claude Desktop

في Claude Desktop، افتح Settings ثم Developer ثم Edit Config. يكشف ذلك عن claude_desktop_config.json:

نظام التشغيلمكان ملف الإعداد
Windows%APPDATA%\Claude\claude_desktop_config.json
macOS~/Library/Application Support/Claude/claude_desktop_config.json

أضف خادمك تحت mcpServers. استخدم مسارات مطلقة، لأن Claude Desktop يشغّل عمليتك من مجلد عمله الخاص، لا من مجلد مشروعك.

{
  "mcpServers": {
    "local-notes": {
      "command": "node",
      "args": ["C:/Users/you/projects/local-notes-mcp/build/index.js"],
      "env": {
        "NOTES_DIR": "C:/Users/you/mcp-notes"
      }
    }
  }
}

على macOS يبدو المسار كالتالي /Users/you/projects/local-notes-mcp/build/index.js. احفظ الملف، ثم أغلق Claude Desktop إغلاقًا كاملًا (على Windows، من علبة النظام لا بزر الإغلاق في النافذة فقط)، ثم أعد فتحه. ستظهر أدواتك في قائمة الأدوات بجوار حقل الدردشة، ويطلب Claude إذنك قبل تشغيل أي منها.

مطوّر يعمل على طاولة رخامية في مقهى ومعه حاسوب محمول فضي وقهوة فلات وايت

أضفه إلى Claude Code

لا يحتاج Claude Code إلى تعديل أي ملف. أمر واحد يسجّل الخادم:

claude mcp add --transport stdio --env NOTES_DIR=/home/you/mcp-notes local-notes -- node /home/you/projects/local-notes-mcp/build/index.js

كل ما يأتي بعد الشرطتين المزدوجتين هو الأمر الذي يشغّل خادمك. تحقق منه بـ claude mcp list، أو اكتب /mcp داخل جلسة لترى حالته. ويحدد علم النطاق من يحصل على الخادم:

النطاقمكان التخزينمن يراه
local (الافتراضي)إعداداتك الخاصة بهذا المشروعأنت فقط، في هذا المشروع
project (--scope project).mcp.json في المستودعكل من يستنسخه، بعد أن يوافق عليه
user (--scope user)إعدادات مستخدمكأنت فقط، في كل المشاريع

جرّب أمرًا نصيًا حقيقيًا

اسأل Claude شيئًا يفرض استدعاء أداة:

احفظ ملاحظة بعنوان "Standup" تقول "Ship the MCP post on Friday". ثم ابحث في ملاحظاتي عن "Friday".

يستدعي Claude save_note، ثم search_notes، ويعيد اقتباس النتيجة لك. افتح notes.json لتتأكد من أن البيانات وصلت إلى قرصك. إن وصلت، فلديك خادم MCP محلي يعمل.

إصلاح الأعطال وتأمين الخادم

إصلاح الأخطاء الشائعة

العَرَضالسبب المرجحالحل
الخادم يظهر كفاشل أو غير متصلمخرجات على stdout، أو تعطل عند البدءشغّل node build/index.js يدويًا واقرأ stderr؛ وأزل كل console.log
لا توجد أدوات بعد تعديل الإعدادالعميل ما زال يعمل، أو JSON غير صالحأغلقه بالكامل؛ وتحقق من الفواصل الزائدة في آخر العناصر
spawn node ENOENTالتطبيق لا يجد node في PATH الخاص بهاستخدم المسار المطلق لملف node التنفيذي بدلًا من command
يعمل في Inspector ويفشل في Claudeمسارات نسبية أو متغيرات بيئة مفقودةمسارات مطلقة، وضع المتغيرات في env
تغييرات الكود بلا أثرلم تُعِد البناء أو لم تُعِد التشغيلشغّل npm run build، ثم أعد تشغيل العميل

تسبب تفصيلتان في Windows نصف المتاعب المتبقية. يجب مضاعفة الشرطات المائلة للخلف داخل نصوص JSON (C:\\Users\\you\\...)، أو يمكنك ببساطة استخدام الشرطات المائلة للأمام كما في المثال أعلاه. وعلى Windows الأصلي، غالبًا ما تحتاج الخوادم التي تُشغَّل عبر npx إلى غلاف cmd /c في command؛ أما أمر node العادي فلا يكفي.

عندما يستمر أي عطل، اقرأ السجلات. يكتب Claude Desktop سجلًا لكل خادم، في ~/Library/Logs/Claude على macOS وفي %APPDATA%\Claude\logs على Windows. وتظهر أسطر console.error الخاصة بك هناك.

مهندس يميل إلى الخلف على كرسي مكتب مع ابتسامة مرتاحة في ضوء مصباح نحاسي دافئ

إعدادات أمان افتراضية تستحق الاحتفاظ بها

يرث خادم stdio صلاحياتك أنت، لذلك عامل كل أداة كأنها كود يمكنه التصرف باسمك.

  • حدّ من نطاق الضرر. أبقِ الوصول إلى الملفات داخل مجلد واحد. إذا قبلت أداة مسارًا، فحوّله إلى مسار كامل وارفض كل ما يقع خارج المجلد المسموح به.
  • تحقق من كل مدخل. قواعد Zod مثل min وmax وenum لا تكلّف شيئًا، وتمنع الاستدعاءات المشوهة قبل تشغيل معالجك.
  • أبعد الأسرار عن الكود. ضع الرموز في كتلة env من إعدادك، واحتفظ بهذا الملف بعيدًا عن نظام التحكم بالإصدارات.
  • اقرأ قبل أن تثبّت. لا تضف إلا خوادم الطرف الثالث التي فحصت مصدرها. إنها تعمل بصلاحيات حسابك.
  • عامل مخرجات الأدوات كأنها غير موثوقة. قد يحمل النص الذي تجلبه أداتك من صفحات الويب أو رسائل البريد تعليمات موجّهة إلى النموذج. أعده كبيانات، وأبقِ عمليات الكتابة خلف تأكيد.

الانتقال من stdio إلى HTTP

عندما يحتاج زملاؤك إلى الأدوات نفسها، بدّل ناقل الاتصال. يأتي SDK مع StreamableHTTPServerTransport، الذي يقدّم McpServer نفسها عبر HTTP خلف مصادقتك الخاصة. لا تتغير استدعاءات registerTool لديك. الذي يتغير فقط هو الناقل وتسجيل العميل، على سبيل المثال claude mcp add --transport http notes https://your-host/mcp.

يمكنك رؤية هذا النمط في الاستخدام الفعلي. موصل PicassoIA في claude.ai هو خادم MCP بعيد يعرض توليد الصور وتحريرها وتوليد الفيديو كأدوات، ويستدعيها Claude دون أي عملية محلية على الإطلاق.

لقطة مقرّبة لرف خوادم أسود مطفي، مع كابلات إيثرنت رمادية مرتبة بعناية

صِغ مواصفات الأدوات على PicassoIA

تبدأ الأدوات الجيدة بأسماء وأوصاف جيدة، ونموذج لغوي طريقة سريعة لصياغتها قبل كتابة الكود. يستضيف PicassoIA 75 نموذجًا نصيًا في فئة النماذج اللغوية الكبيرة لديه، ومنها Claude Sonnet 5، المصمم لمهام البرمجة. إليك طريقة استخدامه في تصميم الأدوات.

كيفية استخدام Claude Sonnet 5 على PicassoIA

  1. افتح صفحة Claude Sonnet 5 على PicassoIA.
  2. صِف الأداة بلغة بسيطة: ما الذي تفعله، وما المدخلات التي تأخذها، وما الذي تعيده، وهل تغيّر أي شيء.
  3. اطلب صيغة مخرجات ثابتة: اسم أداة بصيغة snake_case، ووصفًا من جملتين على الأكثر مكتوبًا للنموذج، ومخطط Zod مع .describe() على كل حقل، وثلاث حالات حدّية يجب أن تفشل في التحقق.
  4. ألصق الناتج في استدعاء registerTool، وأعد البناء، واختبره في Inspector.
  5. عدّل الوصف لا المخطط عندما يختار Claude الأداة الخطأ. الصياغة هي المشكلة عادةً.

أمر نصي يعمل جيدًا:

أنا أبني أداة MCP اسمها list_overdue_tasks. تقرأ ملف tasks.json، وتعيد المهام التي يسبق فيها dueDate تاريخ اليوم، ولا تغيّر أي شيء. اكتب اسم الأداة، ووصفًا من جملتين لنموذج ذكاء اصطناعي، ومخطط إدخال Zod مع describe() على كل حقل، وثلاثة مدخلات غير صالحة يجب أن ترفضها.

بالنسبة إلى إعادة الهيكلة الأكبر، مثل تقسيم خادم من 600 سطر إلى وحدات، جرّب Claude Fable 5 أو Claude Opus 4.7 مع لصق ملفك كاملًا.

أنشئ أول صورة لك على PicassoIA

خادم الملاحظات الخاص بك قالب جاهز. استبدل ملف JSON باستدعاء لنموذج صور، وسيستطيع Claude عندها رسم الصور عند الطلب. لا تحتاج إلى بناء ذلك أولًا لترى النتيجة. كل صورة في هذا المقال أُنشئت بواسطة P-Image، وهو أحد نماذج تحويل النص إلى صورة على Picasso IA.

افتح Picasso IA، واكتب جملة واحدة تصف مشهدًا، ثم أنشئ الصورة. بعد ذلك جرّب ثلاث تجارب:

  • غيّر العدسة. أعد كتابة الأمر النصي نفسه مرة بعبارة "35mm" ومرة بعبارة "85mm"، وقارن التكوين.
  • غيّر الإضاءة. استبدل "ضوء نافذة الصباح" بـ "ضوء مصباح مكتب دافئ"، وراقب تغير المزاج.
  • غيّر الزاوية. اطلب لقطة من الأعلى، ثم لقطة من زاوية منخفضة للشخص نفسه.

ابنِ أداة واحدة تتمنى أن يكون لدى Claude، واربطها بالخطوات أعلاه، ثم اقضِ عشر دقائق على Picasso IA لإنشاء الصور لمشروعك. يستغرق بناء الخادم فترة بعد الظهر، أما الصور فتستغرق ثوانٍ.

شارك هذا المقال

اختر لغتك

مقالات ذات صلة