# خادم MCP بلغة Go: كيف بُنيت ذكرى على إضافات ToGO

> دراسة حالة لخادم ذاكرة MCP مفتوح المصدر بلغة Go: وحدات ToGO التي تستخدمها ذكرى، وكود حقيقي، وأرقام محسوبة من المستودع، وما الذي كان صعبًا.

*2026-10-19T12:49:02Z*

# خادم MCP بلغة Go: كيف بُنيت ذكرى على إضافات ToGO

إن كنت تبحث عن مثال حقيقي لبناء **خادم MCP بلغة Go** يتجاوز مرحلة التجربة، فهذا مثال كامل. [ذكرى](https://zekra.dev) (Zekra) خدمة ذاكرة مفتوحة المصدر يصل إليها وكلاء الذكاء الاصطناعي عبر MCP، وهي تطبيق مبني على إطار [ToGO](https://github.com/togo-framework/togo). توضح هذه الدراسة أجزاء ToGO المستخدمة، بكود وأرقام مأخوذة من المستودع، مع ما واجهني من صعوبات.

حُسبت كل الأرقام من `github.com/fadymondy/zekra` بتاريخ 19 أكتوبر 2026، وأذكر طريقة حساب كل رقم.

![غلاف دراسة الحالة](/uploads/sites/c797a67b-97b7-4ed5-8459-baafb6981307/media/zekra-togo-case-study-og-ar.png)

## 1. المشكلة

أعمل مع وكلاء في Claude Code وCodex وCursor، وكانت كل جلسة جديدة تبدأ من الصفر. أردت خدمة ذاكرة واحدة يستطيع أي وكيل استدعاءها، وشروطها:

- أن تتحدث MCP حتى لا يحتاج أي وكيل إلى كود وصل خاص؛
- أن تحفظ المعلومات وتحدّثها بدل تكديس نسخ مكررة؛
- أن تسترجع بمزيج من المتجهات وBM25 وشبكة معرفة؛
- أن تعمل بالعربية والإنجليزية؛
- أن يمكن تركيبها على خادمك الخاص.

هذا نظام خلفي ثقيل على قاعدة البيانات: مصادقة، وذاكرة تخزين مؤقت، وأعمال خلفية، وواجهة HTTP، ولوحة ويب، وطبقة MCP. قدر كبير من أعمال الربط، وليس فيه الجزء المهم.

## 2. لماذا ToGO

ToGO إطار Go وReact تأتي ميزاته في صورة إضافات تسجّل نفسها في نواة مشتركة. وكان معنى ذلك لذكرى:

- مشغّلات قاعدة البيانات والتخزين المؤقت والطوابير وتخزين الملفات متوفرة جاهزة كإضافات؛
- يمكن أن يكون منطق الذاكرة إضافة مستقلة بوحدتها (module) واختباراتها؛
- يبقى الجزء المحيط (خادم API والهجرات واللوحة) خفيفًا؛
- ملف تنفيذي واحد يخدم REST وMCP واللوحة.

كان البديل تجميع chi وأداة هجرات ومكتبة مصادقة ومشغّل مهام يدويًا، وهذا الربط يتولاه ToGO.

## 3. المعمارية

من `go.mod`، وحدات ToGO التي تطلبها ذكرى مباشرة:

| الوحدة | الدور |
|---|---|
| `togo` v0.21.0 | النواة |
| `db-postgres` v0.1.0 | مشغّل Postgres |
| `cache` v0.3.0 و`cache-redis` | واجهة التخزين المؤقت وطبقة Redis الأولى |
| `queue` v0.3.0 | الأعمال الخلفية |
| `storage` v0.2.0 | تخزين الكائنات (الطبقة الباردة) |
| `brain` | عضو الذاكرة: المخطط، الحفظ والاسترجاع، الرسم المعرفي، الموصّلات، المحادثة، REST |
| `brain-tei` | التضمينات وإعادة الترتيب عبر Text Embeddings Inference |
| `brain-cognee` | استخراج الكيانات والرسم المعرفي |
| `brain-ocr` | استخراج النص من الصور والمستندات |

إضافة `auth` موصولة على حدة لتسجيل الدخول إلى اللوحة، وخدمة الذاكرة مفصولة عنها عمدًا: تعتمد إضافة brain على المصادقة عبر واجهة (interface) بدالة واحدة، دون استيراد مباشر.

يقع الجزء المحيط في `cmd/api` و`cmd/migrate` و`internal/` و`web/`. أما `cmd/zekra-mcp` فخادم MCP عبر stdio، وهو محوّل رفيع فوق REST API.

أما MCP فتعريفات الأدوات وتوزيع JSON-RPC في حزمة واحدة هي `plugins/brain/mcptools`. يذكر تعليق الحزمة أن هذا السطح مشترك بين الملف التنفيذي stdio ونقطة HTTP البعيدة (`/api/mcp`)، وأن كل وسيلة نقل توفّر واجهة خلفية تنفّذ نداء REST. ويبقى التحقق وتحديد النطاق كله على جهة الخادم في معالجات REST.

التخزين في PostgreSQL مع VectorChord وBM25 وpgvector. والتحكم في الوصول، بحسب الـREADME، نطاق (namespace) لكل «دماغ» مع صلاحيات لكل وكيل ورموز وصول تُفرض من جهة الخادم.

## 4. كود حقيقي

**الإضافة تسجّل نفسها.** من `plugins/brain/plugin.go`:

```go
func init() {
	togo.RegisterProviderFunc(Name, togo.PriorityLate+10, func(k *togo.Kernel) error {
		svc := brain.New(k)
		secured := func(h http.HandlerFunc) http.HandlerFunc { return secure(k, svc, h) }
		svc.RegisterRoutes(k.Router, secured)
		k.Set(Name, svc)
		return nil
	})
}
```

رقم الأولوية مهم، ويشرحه تعليق في الكود: يجب أن تُركَّب مسارات brain بعد أن تثبّت إضافة auth برمجيتها الوسيطة في chi، لأن chi تمنع `Use()` بعد تسجيل أي مسار.

**التطبيق يختار إضافاته بالاستيراد الفارغ.** من `internal/plugins/local.go`:

```go
import (
	_ "github.com/togo-framework/brain"
	_ "github.com/togo-framework/brain-cognee"
	_ "github.com/togo-framework/brain-ocr"
	_ "github.com/togo-framework/brain-tei"
	_ "github.com/togo-framework/cache-redis"
)
```

**الإضافة تصف نفسها.** من `plugins/brain/togo.plugin.yaml`:

```yaml
name: brain
priority: 50
backend:
  package: github.com/togo-framework/brain
frontend:
  dir: web
```

**منطق المنتج Go عادي.** من `plugins/brain/internal/brain/writedecision.go`، العتبتان اللتان تحددان هل الكتابة تكرار أم تحلّ محل ذكرى أقدم:

```go
const (
	simDuplicate = 0.97
	simSupersede = 0.88
)
```

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

## 5. الأرقام وطريقة حسابها

| البند | العدد | طريقة الحساب |
|---|---|---|
| الـcommits على `main` | 350 | `git rev-list --count origin/main` |
| أول commit | 16 يوليو 2026 | `git log --reverse` |
| وحدات الإضافات داخل المستودع | 5 (`brain` و`brain-tei` و`brain-cognee` و`brain-ocr` و`cache-redis`) | المجلدات تحت `plugins/`، لكل منها `go.mod` |
| أدوات MCP المعرَّفة | 69 اسمًا مختلفًا | مدخلات `"name":` في ملفات تعريف الأدوات الستة داخل `plugins/brain/mcptools` |
| جداول مخطط brain | 34 | `CREATE TABLE` في `plugins/brain/internal/brain/schema.sql` |
| الفهارس | 46 | `CREATE INDEX` في الملف نفسه |
| ملفات Go في خدمة الذاكرة | 88 | `*.go` في `plugins/brain/internal/brain` |
| ملفات الاختبار في المستودع | 51 | `*_test.go` دون نسخة عمل مؤقتة |
| إضافات يستوردها ملف العرض | 207 | أسطر الاستيراد في `internal/plugins/showcase.go` |

تنبيهان. الرقم 69 هو ما تعرّفه ملفات الكود؛ أما التوثيق المنشور فيصف مجموعات أصغر لكل ملف تنفيذي (مثلًا 31 لـ`zekra-mcp`)، فاعتبر 69 رقم الكود لا ما يراه كل عميل. وملف العرض (showcase) موجود ليجرّب ذكرى منظومة ToGO الأوسع، ولا يعني أن الإضافات الـ207 كلها أساسية للذاكرة.

لا أذكر هنا أرقام زمن استجابة أو حِمل لأنه ليس في المستودع قياس أستشهد به.

## 6. ما الذي كان صعبًا، وأين ساعد ToGO

**ما ساعد:** جاءت قاعدة البيانات والتخزين المؤقت والطوابير وتخزين الملفات كإضافات؛ وأعطى نظام الأولويات ترتيب إقلاع محددًا؛ وأتاح نمط الإضافات أن يعيش عضو الذاكرة في وحدة مستقلة باختباراتها؛ وملف تنفيذي واحد يخدم كل شيء.

**الصعب، بصراحة:**

- **ترتيب الإقلاع.** قاعدة `Use()` في chi كلفتني وقت تصحيح حقيقيًا. الحل رقم أولوية وتعليق، وهذا مقبول، لكن عليك أن تعرفه.
- **إضافات داخل المستودع.** عائلة `brain` تُطوَّر داخل مستودع ذكرى، لذلك يثبّتها `go.mod` على `v0.0.0` مع توجيهات `replace` إلى `./plugins/...`. ويقول التعليق في `go.mod` إن ذلك يزول حين يستهلك الجزء المحيط الإضافات المنشورة. وإلى ذلك الحين العمل أكثر يدوية من `togo install`.
- **ربط موزع.** ملف `plugins.gen.go` يملكه `togo install`، فوُضعت الإضافات المحلية وauth في ملفين منفصلين (`local.go` و`auth.go`) كي لا يكتب التوليد فوقهما. و`togo.yaml` نفسه فيه `plugins: []`.
- **الكود المولَّد غير مرفوع.** يجب تشغيل `togo generate` (sqlc وgqlgen وatlas وOpenAPI) قبل البناء، كما يذكر دليل الاستضافة الذاتية.
- **ليس من عمل ToGO:** جودة الاسترجاع، وإضافات Postgres، وخوادم النماذج. أعطى ToGO البنية، ولم يقم بالاسترجاع نيابةً عني.

## أسئلة شائعة

**هل ذكرى تطبيق ToGO فعلًا؟** نعم. يطلب `go.mod` الحزمة `github.com/togo-framework/togo` بالإصدار v0.21.0، وخدمة الذاكرة نفسها إضافة ToGO.

**هل تستخدم MCP Go SDK الرسمية؟** حزمة `mcptools` في المستودع هي التي تعرّف الأدوات وتوزّع JSON-RPC، وتشترك فيها نقطة stdio ونقطة HTTP.

**هل أستطيع تركيبها على خادمي؟** نعم، بترخيص AGPL-3.0. تحتاج PostgreSQL مع إضافات VectorChord وخادم تضمين TEI، وفي المستودع دليل الاستضافة الذاتية.

**لماذا إضافات بدل تطبيق واحد؟** لكل جزء (الذاكرة، التضمين، استخراج الرسم المعرفي، OCR، التخزين المؤقت) وحدته واختباراته ونطاق أعطاله، ويمكن استبداله.

## روابط

- مقال المنتج: [ذاكرة مستضافة ذاتيًا لوكلاء الذكاء الاصطناعي مع ذكرى](https://zekra.dev/ar/blog/self-hosted-ai-agent-memory-server)
- مقال المؤسس: [لماذا بنيت ذكرى](https://fadymondy.com/ar/blog/why-i-built-zekra)
- موقع المنتج: [zekra.dev](https://zekra.dev)
- GitHub: [fadymondy/zekra](https://github.com/fadymondy/zekra) (AGPL-3.0)
- Product Hunt: [Zekra](https://www.producthunt.com/products/zekra)
- Discord: [انضم](https://discord.gg/99JBJd6FsR)
- ToGO: [github.com/togo-framework/togo](https://github.com/togo-framework/togo)
- تطبيقات ToGO الأخرى: [معرض ToGO](https://to-go.dev/ar/showcase)

---

Source: https://to-go.dev/ar/blog/zekra-togo-case-study
