mustasj / craft-mcp-server
MCP-server for Craft CMS 5 — eksponerer innhold over Model Context Protocol med token-autentisering.
Requires
- php: >=8.2
- craftcms/cms: ^5.0
- illuminate/collections: ^10.42
- mcp/sdk: ^0.4
- nesbot/carbon: ^2.72
- nyholm/psr7: ^1.8
- nyholm/psr7-server: ^1.1
- symfony/finder: ^7.0 || ^8.0
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
MCP-server for Craft CMS 5. Eksponerer innholdet i en Craft-installasjon over Model Context Protocol (streamable HTTP), med personlige bearer-tokens knyttet til Craft-brukere.
Den er en Yii-modul, ikke en plugin — se «Hvorfor modul» nederst.
Installasjon
composer require mustasj/craft-mcp-server
Så i config/app.php:
'modules' => [ 'mcp-api' => [ 'class' => \Mustasj\CraftMcp\Module::class, 'serverName' => 'Mitt nettsted Content API', 'tokenPrefix' => 'mitt_', 'sites' => ['nb' => 'default', 'en' => 'english'], 'sections' => [ 'artikler' => true, 'produkter' => ['read' => true, 'create' => false, 'update' => true], ], 'categoryGroups' => ['hovedkategori'], 'instructionsPath' => '@root/.ai/mcp/instructions.md', 'toolPaths' => ['@root/modules/mcpverktoy'], ], ], 'bootstrap' => ['mcp-api'],
Det er hele oppsettet. Modulen registrerer selv ruta (/mcp), permissionen,
CP-fanen og tokens-tabellen — ingen filer i prosjektet skal røres utover
app.php.
Utsted et token:
php craft mcp-api/tokens/create <brukernavn>
Konfigurasjon
| Nøkkel | Default | Hva den gjør |
|---|---|---|
serverName |
Craft Content API |
Navnet klienten ser i initialize |
serverDescription |
generisk | Én setning om hva serveren er |
serverVersion |
1.0.0 |
Rapporteres til klienten |
instructionsPath |
null |
Markdown-fil med instructions. Craft-alias tillatt |
tokenPrefix |
craft_ |
Må være unikt per prosjekt. Små bokstaver/tall + _ |
routePath |
mcp |
URL-stien endepunktet svarer på |
tokenInPath |
true |
Om /mcp/t/<token> også registreres |
sites |
— | Påkrevd. Språkkode → Craft site-handle |
sections |
— | Påkrevd. Seksjonshandle → policy |
categoryGroups |
[] |
Kategorigrupper som eksponeres |
fieldNotes |
[] |
Felthandle → merknad, for felt der lagret verdi ≠ vist verdi |
toolPaths |
[] |
Mapper med prosjektets egne verktøyklasser |
sections — policy per operasjon, ikke per seksjon
'sections' => [ 'artikler' => true, // alt lov 'produkter' => ['read' => true, 'create' => false, 'update' => true], ],
Formen er ikke overkonstruert; den er målt. Med en flat string[] — som
modulen hadde før — styrte samme liste både lesing og skriving, og i ett
prosjekt ga det stikk motsatt resultat av domenereglene: eiendommer eid av en
ekstern feed kunne opprettes, men ikke leses. Redaksjonen trenger det
omvendte.
Allowlisten er ikke en sikkerhetsgrense — Crafts permissions avgjør hva
tokenets bruker faktisk får gjøre. Den avgrenser hva som er ment for
maskinell redigering, som er nødvendig fordi canSave() alltid er sann for
superadmins.
instructionsPath — pek den på .ai/
MCP har to mekanismer for kontekst, og de er ikke like:
instructionssendes i hverinitializeog koster kontekst hos alle klienter. Hold den kort: de tre–fire tingene som faktisk går galt.- Resources hentes ved behov, og er rett sted for stilguide og ordbok. (Ikke implementert ennå.)
Peker instructionsPath inn i prosjektets .ai/-mappe, arver serveren
vedlikeholdsregelen som alt gjelder der — instruksjonene kan ikke råtne uten at
dokumentasjonen også gjør det.
toolPaths — prosjektets egne verktøy
Pakken eier de generiske verktøyene. Domenespesifikke verktøy (en
RecipeTools, en PropertyTools) hører i prosjektet, og legges i en mappe som
nevnes her. De skrives med vanlige #[McpTool]-attributter og oppdages
automatisk.
Dette er sømmet som avgjør om pakken holder: uten det må hvert prosjekt som trenger ett eget verktøy forke pakken.
Verktøy
list_entries, get_entry, create_entry, update_entry, publish_draft,
list_categories, get_content_model, search_assets, list_asset_folders,
update_asset.
Skriveverktøyene lager utkast. Ingenting går live uten publish_draft.
To designvalg verdt å kjenne
Pakkens verktøy registreres med addTool() og eksplisitte skjemaer, ikke med
attributter. SDK-ens attributt-variant (#[Schema(enum: …)]) krever
konstante uttrykk, og et PHP-attributt kan ikke lese modulkonfigurasjon. Så
lenge seksjonslista lå i et attributt, måtte den være en klassekonstant — og da
måtte hvert prosjekt endre filer i pakken. Prosjektets egne verktøy bruker
attributter, fordi der er konstanter riktig.
Tokens-tabellen opprettes av Tokens::ensureTable(), ikke av en migrering.
Crafts MigrateController kjenner sporene craft, content og
plugin:<handle>; det finnes ikke noe module:-spor, så en modul kan ikke eie
migreringer. Alternativet var å be hver installasjon kopiere en migreringsfil
inn i migrations/.
Hvorfor modul, ikke plugin
En plugin ville løst migreringspunktet over, og gitt et innstillings-UI. Prisen
er plugin-lifecycle, Settings-modell, project config-oppføring og
installasjons-/avinstallasjonsløp — for et internt verktøy med en håndfull
installasjoner er det overhead uten gevinst. Composer-distribusjon krever ikke
plugin-formen; den krever bare et repo.
Blir pakken en dag noe som skal ut av huset, er plugin riktig, og
konfigurasjonssnittet her oversettes rett til en Settings-modell.
For utviklere og AI-agenter
Konvensjoner, arkitektur, domeneregler og beslutningslogg ligger i
.ai/. Ny dokumentasjon rettet mot utviklere eller AI-agenter
hører der, ikke i denne fila — start med .ai/README.md.