הספרייה external_mcp היא הלקוח שדרכו ה-CMS מגיע לכלים של שירותי Wizzo Market שהאתר משלם עליהם: אנליטיקה, הפצה, חדשות ועוד. במקום חיבור נפרד לכל מוצר יש שער אחד, והספרייה מציגה את הכלים שלו כאילו היו כלים של האתר, כך ש-שרת ה-MCP, סוכני ה-AI ו-צ'אט האדמין משתמשים בהם בלי לדעת מאיפה הם באו.
איך זה עובד#
- האתר מתחבר לשער פעם אחת:
connect_gateway()שולחת למרקט את כתובת ה-MCP של האתר (<env_url>/system/mcp) ואת טוקן אתר, ומקבלת טוקן לשער. המצב נשמר ב-PARAMSתחתmcp_gateway. remote_tools()שואלת את השער אילו כלים קיימים, ושומרת את התשובה במטמון ל-6 שעות (CACHE_HOURS).- כל כלי מתפרסם בשם
<product>_<tool>, למשלkama_sql_query. השער עצמו משתמש ב-<product>__<tool>(קו תחתון כפול), והספרייה מתרגמת בשני הכיוונים. call()מעבירה קריאה לשער ומחזירה["ok" => true, "data" => ...]או["ok" => false, "error" => ...].
חיבור לא דורש רכישה נפרדת של "mcp": האתר מקבל גישה לכלים של מוצרים שכבר משולמים לו. החיבור כן דורש מפתח API של המרקט (wizzo_market_api_key).
המוצרים wizzo ו-cms תמיד מוסרים מהרשימה כדי שלא יתנגשו בכלי האתר. גם seok מוסר, חוץ מכשמנוע ה-SEO המאוחסן פעיל (SeoHosted::enabled()), ואז הכלים seok_* הם כלי ה-SEO היחידים של האתר.
קבועים#
| קבוע | ערך | משמעות |
|---|---|---|
GATEWAY_URL_DEFAULT | https://mcp.wizzo.market/mcp | כתובת השער כשלא נשמרה כתובת אחרת |
GATEWAY_PARAM | mcp_gateway | שם הפרמטר שבו נשמר מצב החיבור |
MARKET_CONNECT_URL | https://market.wizzo.media/api/mcp?api_action=cms_connect | נקודת ההתחברות במרקט |
MARKET_AGENT_SERVERS_URL | https://market.wizzo.media/api/agent_servers | טוקנים ייעודיים לסוכנים |
CACHE_KEY, CACHE_HOURS | external_mcp_tools, 6 | מטמון רשימת הכלים |
CONNECT_BACKOFF_HOURS | כ-5 דקות | השהיה אחרי כשל חיבור, כדי לא לנסות בכל בקשה |
CONNECT_TIMEOUT, TIMEOUT | 6 ו-40 שניות | זמני קריאה |
READONLY_SERVERS | ["kama"] | מוצרים שנחשבים לקריאה בלבד כשאין annotation |
EXCLUDED_PRODUCTS | ["seok"] | מוצרים שלא מתפרסמים (ראו למעלה) |
KNOWN_LABELS | מפה | שמות תצוגה בעברית ל-target, kama, poosh, radar, wizzoai |
API ציבורי#
כל המתודות סטטיות. המתודות הפנימיות (gateway_token, gateway_cms_token, gateway_rpc ועוד) הן private ואינן חלק מהחוזה.
| חתימה | מחזיר | הערות |
|---|---|---|
gateway_state() | מערך או null | מצב החיבור השמור ב-PARAMS mcp_gateway |
connect_gateway($rotate = false) | ["ok" => bool, ...] | מתחברת לשער. $rotate = true מנפיקה טוקן חדש. נכשלת אם אין מפתח מרקט |
vouch_token() | מחרוזת | טוקן האתר שנשלח למרקט כ-X-Cms-Token. ריק כשהאתר לא מחובר |
servers() | [name => ["name","url","token"]] | שרת לכל מוצר מותקן. כולם מצביעים לאותו שער |
server($name) | שורת שרת או null | |
agent_servers() | רשימה | טוקנים ייעודיים לכל מוצר, מטמון של 5 דקות |
rpc($server, $method, $params = null) | תשובה מפוענחת | קריאת JSON-RPC גולמית. ב-tools/call מוסיפה לשם את <product>__ |
remote_tools() | [product => [tools]] | רשימת הכלים, ממטמון |
manifest() | רשימת כלים בפורמט MCP | שמות <product>_<tool>, עם annotations אם יש |
by_server() | [["server","tools"], ...] | אותה רשימה מקובצת, בצורה שהצ'אט צורך |
resolve($tool) | [product, bare_name] או null | פותרת מול הרשימה, לא לפי פיצול בקו תחתון |
is_external($tool) | bool | האם השם שייך לשירות חיצוני |
is_write($tool) | bool | האם הכלי כותב |
server_is_write($name) | bool | האם אחד מכלי המוצר עלול לכתוב |
product_label($name) | מחרוזת | תווית תצוגה: מהשער, אחר כך KNOWN_LABELS, אחר כך שם באותיות גדולות |
call($tool, $args) | ["ok","data"] או ["ok"=>false,"error","extra"] | הקריאה עצמה |
flush() | - | מרוקנת את המטמון באתר, וגם POST <gateway>/flush |
flush_gateway() | - | רק את צד השער |
קריאה לכלי מהקוד#
if (!class_exists("external_mcp")) {
require_once CONFIG::$core_path . "/libraries/external_mcp.php";
}
// אילו כלים חיצוניים יש לאתר הזה
foreach (external_mcp::by_server() as $srv) {
echo $srv["server"] . ": " . count($srv["tools"]) . " tools\n";
}
$tool = "kama_sql_query"; // שם בפורמט <product>_<tool>
if (external_mcp::is_external($tool)) {
$res = external_mcp::call($tool, [
"sql" => "SELECT referrer_subtype AS engine, SUM(total_visits) AS visits
FROM kama_page_referrals
WHERE app_id = {APP_ID} AND date_day >= '2026-09-01'
GROUP BY referrer_subtype ORDER BY visits DESC",
"limit" => 50,
]);
if ($res["ok"]) {
$data = $res["data"]; // JSON מפוענח, או טקסט
} else {
error_log("external tool failed: " . $res["error"]);
}
}
השמות והארגומנטים של כל כלי נקבעים על ידי המוצר ולא על ידי הליבה (בדוגמה, sql ו-limit של KAMA, כפי ש-SeoGeo קורא להם, ו-{APP_ID} מוחלף על ידי השירות). בדקו את inputSchema ב-external_mcp::manifest() לפני שאתם קוראים לכלי חדש.
איך מחליטים אם כלי כותב#
הכרעה חשובה כי היא קובעת אם הכלי עובר dry-run וכניסה לתור האישורים (כלי ה-MCP). הסדר:
- אם ל-tool יש annotation
readOnlyHint, הכלי כותב אם הערךfalse. - אחרת, אם יש
destructiveHintאמיתי, הכלי כותב. - בלי annotation: כותב, אלא אם המוצר ב-
READONLY_SERVERS.
הגישה הזהירה היא בכוונה: טעות לכיוון "כותב" עולה הערת dry-run מיותרת, וטעות לכיוון "קורא" עלולה להפעיל קמפיין או שידור אמיתיים.
דלת המרקט: connector#
המרקט מחבר ומנהל אתרים דרך /system/connector. האימות הוא מפתח ה-API של המרקט של האתר (בכותרת Authorization או X-Wizzo-Key, או בגוף ב-_key, api_key או _token), מושווה עם WIZZO_KEY::matches. כל פעולה נתמכת גם כ-?do=<action>.
| פעולה | מה עושה |
|---|---|
| GET (גילוי) | מחזיר connector, גרסת ליבה, פרטי האתר, רשימת שירותים ויכולות |
status | מצב MCP, סוכנים וביצועים |
mcp_connect | קורא ל-connect_gateway, גוף אפשרי {rotate: true}. כשל מחזיר 502 |
agents_ready | רושם את האתר ב-stream ומעביר סוכנים ישנים פעם אחת. דורש WizzoAI פעיל, אחרת 409 |
seo_ready | הכנת מנוע ה-SEO |
oleg_ready | הכנת יועץ הביצועים (בריאות וביצועים) |
מלכודות#
flush() פונה גם לשער במרקט. אם הוא לא זמין, הקריאה נכשלת בשקט, והרשימה אצל חיבורי ChatGPT או Claude עלולה להישאר ישנה עד שתפוג. אחרי פריסה שמשנה כלים, הפעילו delete_cache דרך הגשר או את external_mcp::flush() ובדקו ב-tools/list.- הטוקן לשער נשמר באתר ב-
PARAMS. הוא מקנה גישה לכלי המוצרים של האתר, לכן אל תחשפו אתmcp_gatewayבלוגים או בצילומי מסך. - אחרי כשל חיבור הספרייה לא מנסה שוב כ-5 דקות, ובינתיים הרשימה ריקה. זו לא תקלה בכלים עצמם.
- עדכון גרסה מרוקן את המטמון (
external_mcp::flush()מתבצע בסוף העדכון).