MCP Server

Zarządzaj contentem workspace'u Cmssy z poziomu agentów AI przez `@cmssy/mcp-server` — most MCP udostępniający narzędzia do stron, bloków, formularzy i mediów przez stdio.

24 kwietnia 2026

Przegląd

@cmssy/mcp-server to serwer Model Context Protocol, który łączy agentów AI (Claude Code, Claude Desktop, dowolne narzędzie wspierające MCP) z workspace'em Cmssy. Po skonfigurowaniu agent może listą i edytować strony, dodawać i usuwać bloki, publikować draftów, zarządzać formularzami i więcej — bez wychodzenia z edytora.

Dystrybuowany jest przez npm i komunikuje się przez stdio, więc nie uruchamiasz długożyjącego procesu: agent startuje go na żądanie przez npx.

Czym różni się od HTTP API

  • Scope'owany do workspace'u — para token + workspace ID, wszystko egzekwowane po stronie serwera
  • Wysokopoziomowe narzędziaadd_block_to_page, publish_page, patch_block_content, nie surowy GraphQL
  • Izolacja tenant wbudowana — każde zapytanie jest filtrowane po Twoim workspace; nie dotkniesz przypadkiem innego tenanta

Setup

1. Stwórz token API

Workspace Settings → API Tokens → Create token. Skopiuj wartość cs_… od razu — tokeny wyświetlane są tylko raz. Scope to wyłącznie authn; co token może zrobić zależy od Twojej roli oraz flagi isSuperAdmin.

2. Znajdź ID workspace'u

Workspace Settings → General ma przycisk copy obok ID. To ten sam workspace, do którego przypisany jest Twój token API.

3. Dodaj do konfiguracji MCP edytora

Dla Claude Code edytuj .mcp.json w root projektu (lub ~/.claude/mcp.json dla instalacji globalnej):

{
  "mcpServers": {
    "cmssy": {
      "command": "npx",
      "args": [
        "-y",
        "@cmssy/mcp-server@latest",
        "--token", "cs_your_token_here",
        "--workspace-id", "507f1f77bcf86cd799439011",
        "--api-url", "https://api.cmssy.io/graphql"
      ]
    }
  }
}

Wspierane są też ekwiwalenty env: CMSSY_API_TOKEN, CMSSY_WORKSPACE_ID, CMSSY_API_URL. Przydatne gdy nie chcesz trzymać tokena w commitowanym configu.

4. Zrestartuj edytor

Claude Code podepnie serwer przy następnym starcie sesji. Powinien pojawić się wpis cmssy w MCP z listą narzędzi.

Dostępne narzędzia

0.50.2 wystawia 81 narzędzi. Wszystkie mają jeden kształt nazw - list_* i get_* do odczytu, create_* / update_* / delete_* do zapisu, plus czasowniki dla przejść stanu - więc grupa znaczy więcej niż pojedyncza nazwa.

Strony i bloki

  • list_pages, get_page - drzewo stron i jedna strona ze wszystkimi blokami i językami. Pełnotekstowe search_content jest zdefiniowane we wspólnym rdzeniu narzędzi, ale nie jest bindowane przez serwer MCP; dostępne jest z asystenta w panelu.
  • create_page, update_page_settings, delete_page. update_page_settings przenosi też stronę pod inny parentId, co przelicza slug całego poddrzewa.
  • publish_page, unpublish_page, revert_to_published.
  • add_block_to_page, update_block_content, patch_block_content, remove_block_from_page, update_page_blocks, update_page_layout.
  • list_block_types - typy bloków, które Twój serwis naprawdę rejestruje, czytane z manifestu zapisanego przez handshake edytora. Wołaj przed dodaniem bloku: to stąd wiesz, co frontend potrafi wyrenderować.
  • list_page_types, create_page_type.

Modele i rekordy

  • list_models, get_model, create_model, update_model, delete_model - usunięcie modelu kaskaduje na wszystkie jego rekordy.
  • list_records, get_record, create_record, update_record, delete_record, import_records (do 1000 na wywołanie).

delete_record odmawia, gdy rekord jest wciąż używany przez blok, i odpowiada listą stron, które go używają. Przekaż force: true, żeby usunąć mimo to.

Media

  • list_media, upload_media, move_media.
  • list_media_folders, create_media_folder, update_media_folder, delete_media_folder.

Formularze

  • list_forms, get_form, create_form, update_form, delete_form.
  • list_form_submissions, get_form_submission, update_form_submission_status, delete_form_submission.

Commerce

  • Zamówienia - list_orders, get_order, create_manual_order, edit_order, update_order_details, mark_order_paid, record_order_payment, record_order_invoice, refund_order, cancel_order, transition_order_fulfillment, get_order_pipeline, set_order_pipeline_stage.
  • Produkty - list_products, bulk_update_products, bulk_delete_products, set_product_tiers.
  • Koszyki i rabaty - list_carts, update_cart_config, clear_cart_config, list_discounts, get_discount, create_discount, update_discount, set_discount_enabled.

Webhooki

  • list_webhooks, create_webhook, update_webhook, delete_webhook, rotate_webhook_secret, list_webhook_deliveries.
  • list_webhook_event_types - autorytatywna lista dozwolonych eventów. Odczytaj ją, zamiast zgadywać nazwę eventu.

Sekret podpisujący zwracany jest raz, przy tworzeniu i przy rotacji, i nigdy więcej.

Workspace

  • get_workspace_info - nazwa, plan, limity i zużycie.
  • get_site_config - języki, nawigacja, włączone funkcje, ustawienia koszyka.
  • list_members, list_roles - tylko odczyt.

Nic w tym zestawie nie dotyka Twojego kodu. Żadne narzędzie nie pisze pliku, nie edytuje komponentu ani nie otwiera pull requesta: AI edytuje treść, a schematy bloków zostają w Twoim repo, pod code review.

Dev drafty: blok, który nie jest jeszcze wdrożony

Każde narzędzie zapisu przyjmuje opcjonalny target. "draft" (domyślny) edytuje wspólny draft strony; "devDraft" edytuje Twoją własną nakładkę per użytkownik, która startuje od bieżącej strony i nie zmienia podglądu nikomu innemu.

To dlatego można bezpiecznie składać stronę wokół typu bloku, który na razie istnieje tylko na Twojej maszynie. Gdy blok pojedzie na produkcję, promote_dev_draft przenosi nakładkę na wspólny draft. get_page z target: "devDraft" zwraca nakładkę obok wspólnego draftu albo null, gdy żadnej nie masz.

patch_block_content — surgical edits

Do precyzyjnych edycji na contencie liczącym wiele KB (artykuły docs, długie wpisy blog), patch_block_content wysyła tylko diff — nie pełny string. W środku MongoDB findOneAndUpdate z $set + arrayFilters, tenant-scoped, atomowe. Typowo ~10× taniej w tokenach niż przesyłanie całego HTML przez update_block_content.

Trzy typy operacji

insert_before / insert_after

Wstaw HTML bezpośrednio przed/po unikalnym markerze. Marker MUSI pasować do dokładnie jednej lokalizacji — zero lub wiele dopasowań odrzuca operację z BAD_USER_INPUT.

{
  "op": "insert_after",
  "marker": "<h2>Cennik</h2>",
  "html": "<p>Plany od 0 zł/msc.</p>"
}

replace_section

Zastąp wszystko od startMarker (włącznie) do endMarker (wyłącznie). Oba markery muszą być unikalne.

{
  "op": "replace_section",
  "startMarker": "<h2>Cennik</h2>",
  "endMarker": "<h2>FAQ</h2>",
  "html": "<h2>Cennik</h2><p>Nowe plany.</p>"
}

Wiele operacji w jednym wywołaniu

Operacje wykonują się po kolei na running result. Każde niepowodzenie (brakujący marker, niejednoznaczny itp.) przerywa cały patch — brak stanu połowicznie zastosowanego.

{
  "pageId": "...",
  "blockId": "...",
  "locale": "pl",
  "operations": [
    {
      "op": "insert_before",
      "marker": "<h2>Załącznik</h2>",
      "html": "<h2>Nowa sekcja</h2><p>…</p>"
    },
    {
      "op": "replace_section",
      "startMarker": "<h2>Cennik</h2>",
      "endMarker": "<h2>FAQ</h2>",
      "html": "<h2>Cennik</h2><p>Zaktualizowane.</p>"
    }
  ]
}

Kiedy operacja zawodzi

  • 0 dopasowań — marker nie znaleziony. Sprawdź pasowanie znak po znaku; whitespace i kolejność atrybutów ma znaczenie.
  • 2+ dopasowań — marker nie jest unikalny. Dodaj otoczenie HTML do disambiguation. Nakładające się dopasowania też liczą ("aa" w "aaa" liczy się jako 2), więc unikaj ultra-krótkich markerów.
  • Pole nie jest stringiem — docelowy fieldPath wskazuje na tablicę lub obiekt. Użyj update_block_content dla pól strukturalnych.
  • Bloki layoutu nie są wspierane — header/footer i inne bloki layoutu lecą przez update_block_content.

patch_block_content vs update_block_content

 patch_block_contentupdate_block_content
Kiedy użyćPunktowe edycje na stringu HTMLPełny rewrite contentu, dowolny kształt
Koszt w tokenachProporcjonalny do diffuProporcjonalny do pełnego contentu
Typowe oszczędności~10× na contencie wielo-KB
Typy pólTylko string (przez fieldPath)Dowolne (stringi, tablice, obiekty)
Częściowe niepowodzenieCały patch przerywany — brak stanu połowicznegoCały zapis się udaje lub zawodzi
Bloki layoutuNie wspieraneWspierane

Reguła kciuka: jeśli wcześniej wysyłałeś cały HTML tylko żeby zmienić jeden paragraf, użyj patch_block_content. W innym razie zostań przy update_block_content.

Troubleshooting

  • „Workspace not found” — użytkownik stojący za tokenem nie jest członkiem podanego --workspace-id albo id jest złe. Token uwierzytelnia osobę; co wolno, wynika z roli tej osoby w tym workspace. Sprawdź parę w Workspace Settings.
  • „Not authenticated” — token wygasał lub został revoked. Stwórz nowy w Workspace Settings → API Tokens.
  • Serwer MCP niewidoczny w edytorze — zrestartuj edytor po zmianach configu. W Claude Code sprawdź Settings → MCP → cmssy dla logów startowych.
  • Limity rate / plan — serwer MCP respektuje limity planu workspace'u (max stron, storage, tokeny AI). get_workspace_info pokazuje aktualne użycie vs limity.

Tryb odpowiedzi

Od 0.6.0 każde write tool akceptuje opcjonalny parametr response: "minimal" | "full" (default "minimal"). Minimal zwraca małe compact-JSON ack (~100-200 bajtów) z samymi ID i stanem potrzebnym do następnego wywołania — nie pełny zmutowany zasób.

Typowa sesja masowej edycji (agent dotykający tej samej strony docs ~6 razy) odbijała ~170kB HTML na stronę przed 0.6. Minimal mode redukuje to do ~1kB — ~95% cięcia kosztu tokenów odpowiedzi.

Kształty minimalnego ack

  • Narzędzia stron (create_page, update_page_blocks, update_page_settings, publish_page, unpublish_page, revert_to_published, update_page_layout) — {id, slug, hasUnpublishedChanges, updatedAt} (+published dla publish/unpublish)
  • Narzędzia block-on-page (add_block_to_page, update_block_content, remove_block_from_page) — {pageId, blockId, hasUnpublishedChanges, updatedAt}
  • Narzędzia formularzy (create_form, update_form) — {id, slug, status, updatedAt}
  • Narzędzia modeli (create_model, update_model) — {id, slug, updatedAt}
  • Narzędzia recordów (create_record, update_record) — {id, status, updatedAt}

Kiedy użyć full

Przekaż response: "full" gdy faktycznie potrzebujesz pełnego zmutowanego zasobu w tym samym wywołaniu — np. aby zweryfikować pełną transformację, odczytać pole generowane serwerowo lub debugować. W innym razie łańcuchuj kolejny tool odczytu (get_page / get_form / get_model / get_record).

Narzędzia które nie biorą response

Już zwracają compact ack i są bez zmian: patch_block_content, wszystkie delete_*, update_form_submission_status, import_records.

Wersja

Ta dokumentacja opisuje @cmssy/mcp-server 0.50.2, który binduje 81 narzędzi z @cmssy/ai-tools 0.34.0. Punkty orientacyjne: patch_block_content wszedł w 0.5.0, minimalne odpowiedzi w 0.6.0, list_block_types w 0.45.0, parametr target dla dev draftów w 0.48.0 - choć samo promote_dev_draft zostało zbindowane dopiero w 0.50.2, bezpieczne usuwanie rekordów z force w 0.48.0, narzędzia folderów mediów w 0.49.2, clear_cart_config w 0.50.1. Przypnij @cmssy/mcp-server@latest w .mcp.json żeby zawsze mieć najnowsze narzędzia.