|
| 1 | +# MCP köprüsü — bağlı sitelerde ajan eylemleri |
| 2 | + |
| 3 | +Kime: Selene, `orbit-remote-mcp` tarafını kuran taraf. |
| 4 | +Durum: **Orbit ucu canlıda ve iki siteyle doğrulandı.** Eksik olan tek şey MCP |
| 5 | +köprüsü. |
| 6 | + |
| 7 | +Sözleşmenin kendisi `baglisite-ajan-eylemleri.md`. Bu dosya onu tekrarlamıyor; |
| 8 | +köprüyü yazarken verilmesi gereken kararları ve benim canlıda çarptığım |
| 9 | +köşeleri yazıyor. |
| 10 | + |
| 11 | +## Kaç araç eklemeli — iki, işlem başına bir değil |
| 12 | + |
| 13 | +`PRIVATE_OPERATIONS` statik ve bunu sen söyledin: API'ye eklenen bir uç MCP'de |
| 14 | +kendiliğinden görünmüyor. Buradaki tasarımın taşıyıcı kısıtı da bu yüzden |
| 15 | +önemli — **Orbit sitelerin işlerini bilmiyor.** İşlem listesi siteden geliyor |
| 16 | +ve site yeni bir işlem eklediğinde Orbit'e kod girmiyor. |
| 17 | + |
| 18 | +İşlem başına bir MCP aracı yazarsan bu kazanç çöper: beşinci site, ya da |
| 19 | +Haber'in eklediği üçüncü bir işlem, seni tekrar `orbit-remote-mcp`'ye gitmeye |
| 20 | +zorlar. Dolayısıyla **iki genel araç** öneriyorum: |
| 21 | + |
| 22 | +| araç | ne yapar | |
| 23 | +|---|---| |
| 24 | +| `baglisite_islemleri_listele` | Ajan erişimi açık siteleri ve her birinin işlemlerini şemalarıyla döndürür. | |
| 25 | +| `baglisite_islem_calistir` | `grantId` + `operationId` + `input` ile bir işlemi çalıştırır. | |
| 26 | + |
| 27 | +Birincisinin çıktısı ikincisinin girdisini tarif ediyor; model şemayı çalışma |
| 28 | +anında okuyup çağrıyı kuruyor. Ajanın hiçbir şey saklamasına gerek yok, ki |
| 29 | +zaten saklayacak yeri yok. |
| 30 | + |
| 31 | +## Uçlar |
| 32 | + |
| 33 | +### 1. Katalog |
| 34 | + |
| 35 | +``` |
| 36 | +GET /v1/me/connected-sites/actions |
| 37 | +Authorization: Bearer <ajan credential> |
| 38 | +``` |
| 39 | + |
| 40 | +Erişimi **kapalı** siteler listede hiç görünmez. Yani liste boşsa cevap |
| 41 | +"yapabileceğin bir şey yok" değil, "insan henüz hiçbir siteyi açmamış". |
| 42 | +Modele bunu ayırt ettir; yoksa kullanıcıya yanlış şeyi söyler. |
| 43 | + |
| 44 | +Bugün canlıda dönen: |
| 45 | + |
| 46 | +``` |
| 47 | +Equinox Haber (2 işlem) · Equinox Rota (4 işlem) |
| 48 | +``` |
| 49 | + |
| 50 | +### 2. Çalıştırma |
| 51 | + |
| 52 | +``` |
| 53 | +POST /v1/me/connected-sites/{grantId}/actions |
| 54 | +Authorization: Bearer <ajan credential> |
| 55 | +Content-Type: application/json |
| 56 | +
|
| 57 | +{ "operationId": "...", "input": { ... }, "idempotencyKey": "..." } |
| 58 | +``` |
| 59 | + |
| 60 | +Canlıda doğrulanmış bir örnek ve cevabı: |
| 61 | + |
| 62 | +```json |
| 63 | +{ "operationId": "rota.listeyiOku", "input": { "limit": 2 }, "idempotencyKey": "…" } |
| 64 | +→ { "action": { "operationId": "rota.listeyiOku", "status": "applied", "output": { … } } } |
| 65 | +``` |
| 66 | + |
| 67 | +## Köşeler |
| 68 | + |
| 69 | +**Gövde TAM olarak üç alan taşır.** `operationId`, `input`, `idempotencyKey`. |
| 70 | +Fazladan alan 400 `invalid_site_action_fields` alıyor — `clientId` göndererek |
| 71 | +denedim, reddedildi. `input` işlem parametresizse bile `{}` olarak gitmeli. |
| 72 | + |
| 73 | +**`idempotencyKey` zorunlu ve mantıksal işlem başına üretilmeli, deneme başına |
| 74 | +değil.** 1–128 basılabilir ASCII. Aynı anahtar + aynı gövde ilk çalışmanın |
| 75 | +cevabını döndürür (`status: "replayed"`); aynı anahtar + FARKLI gövde 409 |
| 76 | +`idempotency_conflict` alır. Yani modelin her denemede yeni anahtar üretmesi |
| 77 | +tekrar korumasını tamamen kapatır — asıl kazanç orada. |
| 78 | + |
| 79 | +**Sitenin hata GÖVDESİ ajana taşınmıyor.** Orbit bunu bilerek yapmıyor: içeriği |
| 80 | +doğrulanmamış bir metni kendi cevabı gibi göstermek olurdu. Sonucu şu: siteden |
| 81 | +dönen her 4xx sana içeriksiz bir `site_action_failed` (502) olarak geliyor. |
| 82 | + |
| 83 | +Haber bu yüzden **alan kararlarını 2xx ile döndürüyor** ve çıktıda |
| 84 | +`uygulandi: false` + sebep taşıyor. Yani `status: "applied"` "iş oldu" demek |
| 85 | +DEĞİL; `output.uygulandi` okunmalı. Rota'da böyle bir ayrım yok, orada 4xx |
| 86 | +gerçekten hata. Köprü her iki biçimi de modele düz aktarsın, yorumlamasın. |
| 87 | + |
| 88 | +**Katalog 10 dakika önbellekte.** Site yeni işlem eklediyse hemen görünmez. |
| 89 | +Kullanıcı "az önce ekledim" diyorsa cevap "yok" değil, "en geç 10 dakika". |
| 90 | + |
| 91 | +**Şema dili dar bir alt küme.** `$ref`, `pattern`, `allOf`/`anyOf`/`oneOf` yok; |
| 92 | +nesnelerde `additionalProperties` varsayılan olarak kapalı. Şemayı MCP |
| 93 | +`inputSchema`'sına düz geçirebilirsin ama tam JSON Schema varsayan bir |
| 94 | +doğrulayıcıya verme. |
| 95 | + |
| 96 | +**403 `agent_access_closed` bir arıza değil, bir kapı.** İnsan Orbit panelinden |
| 97 | +kapatmış ya da hiç açmamış. Tekrar denenmemeli; modele "Orbit panelinde |
| 98 | +Bağlı siteler → <site> → ajan erişimini aç" dedirtmeli. |
| 99 | + |
| 100 | +## Haber'e özel iki şey |
| 101 | + |
| 102 | +**İşlem sırası var.** `haber.panoYaz` bir `briefId` döndürüyor, `haber.yayinla` |
| 103 | +onu tüketiyor. Pano **tek kullanımlık** ve 6 saat sonra doluyor. Tek çağrıda |
| 104 | +yayın yok ve olmayacak: panoyu sabitlemek, seçimin hangi adaylar arasından |
| 105 | +yapıldığını kayda geçiriyor. |
| 106 | + |
| 107 | +**Yayın imzası senin elinde değil.** Gövdeye yazar alanı koyma — reddedilir. |
| 108 | +İmza Haber'in `publishers` tablosundan okunuyor ve senin satırın orada hazır: |
| 109 | +`Selene AI`. Bu kasıtlı; kimse başkasının imzasıyla yayımlayamasın diye. |
| 110 | + |
| 111 | +## Nasıl sınarsın |
| 112 | + |
| 113 | +Rota'da `rota.listeyiOku` ile başla — okuma, geri dönüşü yok, katalogdan |
| 114 | +çağrıya kadar bütün zinciri yürütüyor. Sonra `rota.katalogdaAra`. Yazma |
| 115 | +işlemlerine ancak bu ikisi çalıştıktan sonra geç. |
| 116 | + |
| 117 | +Haber'de `haber.panoYaz` güvenli: pano satırı yazıyor ama hiçbir şey |
| 118 | +yayımlamıyor ve 6 saat sonra kendiliğinden düşüyor. `haber.yayinla`yı canlıda |
| 119 | +denemeden önce Samet'e söyle — o çağrı gerçekten haber yayımlıyor. |
| 120 | + |
| 121 | +## Dokunmaman gerekenler |
| 122 | + |
| 123 | +Orbit'in kendi ajan yolu (`mcp_authorization_grants`, `posts:write` vb.) bu |
| 124 | +işin dışında ve karışmamalı. Orada ajan **kendi adına** davranıyor; burada |
| 125 | +insanın adına. İkisini tek araçta birleştirmek, "kimin adına" sorusunu |
| 126 | +kaybetmek olur. |
0 commit comments