DocumentazioneScarica

Server MCP, OAuth e ability

Nucleo 0.2+FreeLettura ~24 minAggiornato 31 ottobre 2026

Il server MCP di Nucleo espone il sito agli agenti AI, che accedono con OAuth e lavorano solo entro gli scope che concedi.

In questa pagina

01Panoramica

Ogni operazione di Nucleo è una ability nucleo/* registrata con l'Abilities API di WordPress. Nucleo aggiunge a ogni ability il controllo dei permessi, il controllo degli scope OAuth e il limite di frequenza sulle scritture.

Il server MCP di Nucleo è un server JSON-RPC 2.0 ed espone le ability come tool MCP. Il server ha due trasporti: HTTP su /wp-json/nucleo/v1/mcp e STDIO con wp nucleo mcp.

Su HTTP il client si autentica con un token OAuth emesso dal sito stesso, che fa anche da authorization server. Il token porta degli scope: ogni ability appartiene a un solo scope. Le stesse ability rispondono anche sull'endpoint REST del core wp-abilities/v1, con i controlli di capability: il token Bearer non vale su quell'endpoint, quindi lo scope OAuth non si applica.

Tutta l'area è Free. Solo dodici ability sono Pro: senza licenza attiva non si registrano.

02Server MCP

Endpoint HTTP /wp-json/nucleo/v1/mcp

Cosa fa: riceve un messaggio JSON-RPC 2.0 nel corpo e risponde con application/json. Ogni risposta porta l'header MCP-Protocol-Version: 2025-06-18.

Come si usa: POST https://<sito>/wp-json/nucleo/v1/mcp con Authorization: Bearer nca_…. Accetta anche un utente già autenticato con application password o cookie WordPress.

Parametri: corpo JSON con jsonrpc: "2.0", method, id e params facoltativi. I metodi supportati sono descritti in Metodi MCP.

Permessi: prima la verifica HTTPS (vedi Limiti noti), poi utente autenticato (is_user_logged_in()). Senza utente risponde 401 con codice nucleo_mcp_unauthorized e header WWW-Authenticate: Bearer resource_metadata="<home>/.well-known/oauth-protected-resource".

Edizione: Free

Limiti noti:

  • Solo POST. Nessun flusso SSE, nessuna sessione (Mcp-Session-Id), nessuna richiesta GET.
  • Un messaggio senza id è una notifica: la risposta è 202 senza corpo.
  • Il batch JSON-RPC (array) è rifiutato con -32600.
  • Una richiesta in chiaro, fuori dagli ambienti local e development, riceve 400 con codice https_required. Il messaggio di errore indica di controllare che il proxy inoltri X-Forwarded-Proto: https.
  • Se il server toglie l'header Authorization, la pagina Agenti AI lo segnala.

Trasporto STDIO wp nucleo mcp

Cosa fa: avvia il server MCP su STDIN e STDOUT. Legge una richiesta JSON-RPC per riga e scrive una risposta per riga.

Come si usa: wp nucleo mcp --user=<id|login>. Il client MCP lancia il comando come processo locale.

Parametri:

NomeTipoValori ammessiDefaultNote
--userstringaid o login di un utentenessunoOpzione globale di WP-CLI. Senza utente il comando termina con errore.

Permessi: quelli dell'utente indicato. Non c'è un token OAuth, quindi nessun filtro per scope: il server elenca tutte le ability registrate.

Edizione: Free

Limiti noti:

  • Le righe vuote si ignorano.
  • Il comando nasconde gli errori del database e scarta ogni altro output su STDOUT.
  • Una risposta non codificabile diventa un errore -32603.

Metodi MCP

Cosa fa: il server risponde a quattro metodi. Gli altri restituiscono -32601.

MetodoRisposta
initializeprotocolVersion: "2025-06-18", capabilities: {tools: {listChanged: false}}, serverInfo: {name: "nucleo", version: <versione plugin>}, instructions
pingoggetto vuoto
tools/listtutte le ability con prefisso nucleo/, filtrate per scope del token
tools/callesegue una ability con params.name e params.arguments

Come si usa: il nome del tool è il nome dell'ability con - al posto di /. Esempio: l'ability nucleo/doc-get diventa il tool nucleo-doc-get. Il campo instructions chiede all'agente di chiamare nucleo-guide prima di scrivere.

Parametri: in tools/list ogni tool ha name, description, inputSchema (lo schema dell'ability, oppure {"type":"object"}) e annotations facoltative. Le annotazioni vengono da meta.annotations dell'ability: readonly diventa readOnlyHint, destructive diventa destructiveHint, idempotent diventa idempotentHint.

Permessi: tools/list filtra solo per scope, non per capability. Un tool elencato può quindi fallire per permessi WordPress insufficienti.

Edizione: Free

Limiti noti: l'esito di tools/call dipende dal caso:

  • l'ability restituisce un array: content (testo JSON), structuredContent (lo stesso array) e isError: true se ok vale false, oppure se l'array non ha ok e ha errors non vuoto (per esempio site-import e kit-apply);
  • l'ability restituisce un WP_Error: isError: true, structuredContent {ok: false, error: {code, message, data?}} e lo stesso JSON come testo. data contiene i dati dell'errore senza status;
  • manca lo scope: isError: true e testo insufficient_scope: requires scope <scope>.. Il server controlla lo scope prima di eseguire.

Errori JSON-RPC:

CodiceCaso
-32700JSON non valido
-32600non è un oggetto, batch, jsonrpc diverso da 2.0, method assente
-32601metodo non supportato
-32602name non stringa, arguments non oggetto, tool sconosciuto
-32603risposta non codificabile (solo STDIO)

Collegare un client MCP

Cosa fa: riassume i passi per collegare un client al server MCP.

Come si usa:

Apri la pagina degli agenti

In wp-admin apri Nucleo AI → Agenti AI (admin.php?page=nucleo-agents). La pagina mostra l'URL del server MCP con il pulsante di copia.

Configura il client

Usa l'URL. La pagina propone due esempi: Claude Code claude mcp add --transport http nucleo <url>, Claude Desktop {"mcpServers":{"nucleo":{"url":"<url>"}}}.

Ricevi il 401

Il client chiama l'endpoint senza token e riceve 401 con WWW-Authenticate.

Leggi i metadati

Il client legge /.well-known/oauth-protected-resource, poi /.well-known/oauth-authorization-server.

Ottieni un client_id

Il client ottiene un client_id in uno di tre modi: URL del proprio documento di metadati, registrazione dinamica (se attiva) o client aggiunto a mano nella pagina AI agents. Un client confidenziale creato nella stessa pagina riceve anche un client secret, da usare allo scambio del codice.

Approva il consenso

Il client apre il browser sulla schermata di consenso. Un utente WordPress collegato approva gli scope.

Scambia il codice

Il client scambia il codice con i token su /wp-json/nucleo/v1/oauth/token e chiama il server MCP con Authorization: Bearer nca_….

Per un client locale sul server, in alternativa: wp nucleo mcp --user=<login>.

Parametri: nessuno.

Permessi: la pagina AI agents richiede manage_options. Il consenso richiede un utente collegato con le capability degli scope scelti.

Edizione: Free

Limiti noti: se la registrazione dinamica è spenta, la pagina avvisa di aggiungere l'agente con Add agent.

03Scoperta OAuth

/.well-known/oauth-protected-resource

Cosa fa: pubblica i metadati della risorsa protetta (RFC 9728).

Come si usa: GET https://<sito>/.well-known/oauth-protected-resource.

Parametri: nessuno. Risposta:

ChiaveValore
resourcerest_url('nucleo/v1/mcp')
authorization_servers[home_url()]
scopes_supportedi cinque scope
bearer_methods_supported["header"]

Permessi: pubblico

Edizione: Free

Limiti noti: il documento passa da parse_request di WordPress. Viene servito solo se il percorso, relativo alla home di WordPress, è esattamente .well-known/oauth-protected-resource. Con il sito in una sottocartella il percorso segue la home di WordPress.

/.well-known/oauth-authorization-server

Cosa fa: pubblica i metadati dell'authorization server (RFC 8414).

Come si usa: GET https://<sito>/.well-known/oauth-authorization-server.

Parametri: nessuno. Risposta:

ChiaveValore
issuerhome_url()
authorization_endpointadmin_url('admin.php?page=nucleo-authorize')
token_endpointrest_url('nucleo/v1/oauth/token')
revocation_endpointrest_url('nucleo/v1/oauth/revoke')
registration_endpointrest_url('nucleo/v1/oauth/register'), solo se la registrazione dinamica è attiva
response_types_supported["code"]
grant_types_supported["authorization_code", "refresh_token"]
code_challenge_methods_supported["S256"]
token_endpoint_auth_methods_supported["none", "client_secret_post", "client_secret_basic"]
scopes_supportedi cinque scope
client_id_metadata_document_supportedtrue

Permessi: pubblico

Edizione: Free

Limiti noti: client pubblici (none) e confidenziali (client_secret_post o client_secret_basic). Il secret dei client confidenziali è descritto in Client confidenziale.

04Client OAuth

I client stanno nella tabella {prefix}nucleo_oauth_clients. Il campo kind vale pre, cimd o dcr. Il client confidenziale ha l'hash del suo secret nel campo secret_hash. Le tabelle si creano all'attivazione o al primo uso (opzione nucleo_oauth_db, versione 2).

Client pre-registrato

Cosa fa: crea un client con un nome e un redirect URL. Il client_id ha prefisso ncl_.

Come si usa: Nucleo AI → Agenti AI, modulo Add agent. Nella stessa tabella Connected agents ci sono Revoke tokens (revoca i token attivi, il client resta) e Delete (elimina il client e tutti i suoi token).

Parametri:

NomeTipoValori ammessiDefaultNote
Namestringa1–200 caratterinessunoobbligatorio
Redirect URLstringavedi Regole sui redirect URInessunoun solo URL

Permessi: manage_options, con nonce check_admin_referer

Edizione: Free

Limiti noti: codici di errore missing_name, name_too_long, invalid_redirect, save_failed. Un solo redirect per client.

Client confidenziale

Cosa fa: crea un client che si autentica al token endpoint con un client secret generato dal plugin di 40 caratteri. Il secret si mostra una sola volta: nel database resta solo il suo hash.

Come si usa: Nucleo AI → Agenti AI, riquadro Add confidential agent, pulsante Create confidential agent. Il secret compare nella stessa pagina subito dopo la creazione. Il transient che lo trasporta dura 60 secondi, poi il secret non è più leggibile. Il client lo presenta allo scambio del codice e al rinnovo (vedi Scambio del codice).

Parametri:

NomeTipoValori ammessiDefaultNote
Namestringafino a 200 caratterinessunoobbligatorio
Redirect URLsstringauno per riga; https, oppure http solo su localhost o 127.0.0.1nessunoobbligatorio

Permessi: manage_options

Edizione: Free

Limiti noti: codice di errore invalid_redirect se manca un redirect o se un redirect non è ammesso. Il secret non si recupera: se si perde, si elimina il client e se ne crea uno nuovo. La registrazione dinamica non crea client confidenziali.

Client ID Metadata Document

Cosa fa: accetta come client_id un URL https. Nucleo scarica il documento JSON a quell'URL, lo valida e salva il client con kind cimd.

Come si usa: il client passa il proprio URL come client_id alla schermata di consenso. Nessuna registrazione preventiva.

Parametri: campi del documento:

NomeTipoValori ammessiDefaultNote
client_idstringaidentico all'URL del documentonessunoobbligatorio
redirect_urisarraylista non vuota; https con host, oppure http su localhost, 127.0.0.1, [::1]; niente frammento né credenzialinessunoobbligatorio
client_namestringamassimo 200 caratteri""facoltativo
logo_uristringaURL httpsassentefacoltativo; la schermata di consenso non lo mostra
token_endpoint_auth_methodstringanoneassentefacoltativo

Permessi: pubblico (il download avviene durante la schermata di consenso)

Edizione: Free

Limiti noti: protezione SSRF: solo https, niente localhost, niente credenziali nell'URL, tutti gli IP risolti devono essere pubblici. La richiesta fissa l'host al primo IPv4 verificato; un host con soli indirizzi IPv6 viene rifiutato. Timeout 5 secondi, nessun redirect, risposta massima 65536 byte, solo stato 200. Cache in un transient per un'ora. Se la lista dei domini ammessi non è vuota, l'host del client_id deve appartenerne a uno (o esserne un sottodominio) prima del download; altrimenti il client non viene risolto.

Registrazione dinamica POST /wp-json/nucleo/v1/oauth/register

Cosa fa: registra un client (RFC 7591) con kind dcr e restituisce 201 con client_id, client_name, redirect_uris. Il client registrato è sempre pubblico: nessun secret.

Come si usa: attiva Dynamic registration in Nucleo AI → Agenti AI (opzione nucleo_oauth_dcr). Poi il client invia JSON o un form.

Parametri:

NomeTipoValori ammessiDefaultNote
redirect_urisarraylista non vuota, vedi Regole sui redirect URInessunoobbligatorio
client_namestringamassimo 200 caratteri""facoltativo

Permessi: pubblico. L'interruttore richiede manage_options.

Edizione: Free

Limiti noti:

  • Disattivata di default. Spenta, risponde 403 con error: access_denied.
  • Metadati non validi: 400 con error: invalid_client_metadata.
  • Con la lista dei domini ammessi non vuota, anche l'host di ogni redirect deve appartenerne a uno (o esserne un sottodominio); altrimenti 400 con error: invalid_client_metadata.
  • Gli altri campi del corpo si ignorano.
  • Nessun limite di frequenza sull'endpoint.

Regole sui redirect URI

Cosa fa: definisce quali redirect si registrano e quali si accettano nella richiesta.

Come si usa: si applicano a tutti e tre i tipi di client.

Parametri: nessuno.

Permessi: non applicabile

Edizione: Free

Limiti noti:

  • In registrazione: https con host e senza credenziali, oppure http su localhost, 127.0.0.1 o [::1]; niente frammento.
  • In autorizzazione: il redirect deve coincidere carattere per carattere con uno registrato.
  • Per http su loopback la porta può variare (RFC 8252): devono coincidere host, path, query e frammento.
  • Ogni altro http è rifiutato.

05Flusso di autorizzazione

Schermata di consenso admin.php?page=nucleo-authorize

Cosa fa: valida la richiesta di autorizzazione, mostra la schermata Authorize AI agent e, all'approvazione, rimanda al client con un codice.

Come si usa: il client apre nel browser https://<sito>/wp-admin/admin.php?page=nucleo-authorize&response_type=code&client_id=…&redirect_uri=…&scope=…&state=…&code_challenge=…&code_challenge_method=S256&resource=…. L'utente sceglie gli scope e preme Approve o Cancel.

Parametri:

NomeTipoValori ammessiDefaultNote
response_typestringacodenessunoaltrimenti unsupported_response_type
client_idstringancl_… registrato, oppure URL https del documento di metadatinessunoobbligatorio
redirect_uristringauno dei redirect del clientnessunoobbligatorio
scopestringascope separati da spazinessunoalmeno uno; uno sconosciuto o ripetuto dà invalid_scope
statestringamassimo 512 caratteri""restituito al client
code_challengestringa43 caratteri base64urlnessunoobbligatorio
code_challenge_methodstringaS256nessunoplain rifiutato
resourcestringaesattamente rest_url('nucleo/v1/mcp')nessunoaltrimenti invalid_target

Permessi: utente collegato (capability read per la pagina). Ogni scope scelto richiede la capability dello scope (vedi Scope). Il POST richiede il nonce nucleo_authorize.

Edizione: Free

Limiti noti:

  • Il consenso è sempre richiesto: il sito non ricorda le approvazioni.
  • Client o redirect non validi, compreso un client fuori dalla lista dei domini ammessi: pagina di errore 400, senza redirect.
  • Dopo la verifica del redirect gli errori tornano al client come ?error=<codice>&state=<state>.
  • Codici restituiti: unsupported_response_type, invalid_request, invalid_scope, invalid_target, access_denied (rifiuto o nessuno scope scelto), server_error.
  • La schermata mostra nome del client, dominio del client_id, redirect, nome dell'utente e risorsa. Gli scope che l'utente non può concedere appaiono disattivati.
  • Il codice emesso ha prefisso ncc_, vale 60 secondi ed è monouso.

PKCE

Cosa fa: lega il codice al client che l'ha chiesto (RFC 7636).

Come si usa: il client genera un code_verifier, invia code_challenge = base64url(SHA-256(verifier)) senza padding e code_challenge_method=S256. Allo scambio invia il code_verifier.

Parametri:

NomeTipoValori ammessiDefaultNote
code_verifierstringa43–128 caratteri A-Z a-z 0-9 - . _ ~nessunoobbligatorio allo scambio
code_challengestringa43 caratteri A-Z a-z 0-9 - _nessunoobbligatorio all'autorizzazione

Permessi: non applicabile

Edizione: Free

Limiti noti: solo S256. Verifier errato: invalid_grant.

Scambio del codice POST /wp-json/nucleo/v1/oauth/token (authorization_code)

Cosa fa: scambia il codice con un access token e un refresh token.

Come si usa: POST con grant_type=authorization_code, in form o JSON. Il client confidenziale presenta il secret con client_secret nel corpo, oppure con l'header Authorization: Basic (client_id e secret codificati, come da RFC 6749). Non si usano entrambi: un client che li presenta insieme riceve invalid_client.

Parametri:

NomeTipoValori ammessiDefaultNote
grant_typestringaauthorization_codenessuno
codestringacodice ncc_…nessunoobbligatorio
client_idstringalo stesso dell'autorizzazionenessunoobbligatorio
client_secretstringasecret del client confidenzialenessunoobbligatorio per i client confidenziali, se non si usa Authorization: Basic
code_verifierstringavedi PKCEnessunoobbligatorio
redirect_uristringaidentico a quello dell'autorizzazionenessunoobbligatorio
resourcestringaidentico a quello dell'autorizzazionenessunoobbligatorio: se manca o è diverso, invalid_target

Risposta 200: access_token, token_type: "Bearer", expires_in: 3600, refresh_token, scope.

Permessi: pubblico. Il client pubblico non si autentica; il client confidenziale si autentica con il secret.

Edizione: Free

Limiti noti:

  • Errori 400 in formato RFC 6749 (error, error_description) con Cache-Control: no-store.
  • Codici: invalid_request (parametro mancante), unsupported_grant_type, invalid_client (client sconosciuto o fuori dalla lista dei domini, credenziali malformate, secret errato o mancante per un client confidenziale), invalid_grant (codice errato, scaduto, già usato, redirect diverso, verifier errato, utente senza più le capability), invalid_target.
  • Fuori dagli ambienti local e development una richiesta in chiaro riceve https_required.
  • Gli scope emessi sono solo quelli per cui l'utente ha ancora la capability.

Rinnovo POST /wp-json/nucleo/v1/oauth/token (refresh_token)

Cosa fa: emette una nuova coppia di token e consuma il refresh token usato (rotazione).

Come si usa: POST con grant_type=refresh_token. Il client confidenziale si autentica come allo scambio del codice.

Parametri:

NomeTipoValori ammessiDefaultNote
client_idstringaclient del tokennessunoobbligatorio
client_secretstringasecret del client confidenzialenessunoobbligatorio per i client confidenziali, se non si usa Authorization: Basic
refresh_tokenstringancr_…nessunoobbligatorio
scopestringasottoinsieme degli scope concessigli scope originalifacoltativo

Permessi: pubblico. Il client confidenziale si autentica con il secret.

Edizione: Free

Limiti noti:

  • Il riuso di un refresh token già ruotato revoca tutta la catena (invalid_grant, "session revoked").
  • Un token revocato da admin o da /oauth/revoke dà invalid_grant e non tocca la catena.
  • Scope più ampi degli originali: invalid_scope.
  • Refresh scaduto: invalid_grant.
  • Client fuori dalla lista dei domini o credenziali errate: invalid_client.

Revoca POST /wp-json/nucleo/v1/oauth/revoke

Cosa fa: revoca un token (RFC 7009). Per access e refresh token revoca l'intera catena.

Come si usa: POST con token=<token>.

Parametri:

NomeTipoValori ammessiDefaultNote
tokenstringaaccess, refresh o codicenessunoobbligatorio

Permessi: pubblico, nessuna autenticazione del client

Edizione: Free

Limiti noti: risponde 200 con {} anche per un token sconosciuto. Senza token risponde 400 invalid_request. Fuori dagli ambienti local e development una richiesta in chiaro riceve https_required.

Autenticazione Bearer

Cosa fa: trasforma l'header Authorization: Bearer nca_… nell'utente WordPress del token e registra gli scope della richiesta. Vale solo sulle rotte REST di Nucleo (/wp-json/nucleo/v1/…).

Come si usa: header Authorization (o REDIRECT_HTTP_AUTHORIZATION) su una richiesta alle rotte nucleo/v1.

Parametri: nessuno.

Permessi: token non revocato, non scaduto, resource uguale a rest_url('nucleo/v1/mcp') (i token senza resource restano validi), client ancora ammesso dalla lista dei domini, utente esistente.

Edizione: Free

Limiti noti:

  • La richiesta è riconosciuta solo se lo schema è Bearer o bearer, seguito da un token nca_.
  • Un token non valido lascia la richiesta anonima: il server MCP risponde 401.
  • last_used del client si aggiorna al più ogni 5 minuti.
Attenzione

Fuori dalle rotte nucleo/v1 il token non autentica nulla. Su wp/v2 e su wp-abilities/v1 la richiesta resta quella di WordPress: cookie o application password, con le sole capability dell'utente. Dentro le rotte nucleo/v1 gli scope limitano le ability nucleo/*.

Formato e durata dei token

Cosa fa: descrive token e catene.

Come si usa: non applicabile.

Parametri:

OggettoPrefissoDurata
Codice di autorizzazionencc_60 secondi, monouso
Access tokennca_3600 secondi
Refresh tokenncr_2592000 secondi (30 giorni)
Clientncl_finché un admin non lo elimina
Client secret (confidenziale)nessuno40 caratteri casuali, finché il client non viene eliminato; nel database solo l'hash
Catenachn_identifica i token nati dallo stesso consenso

Permessi: non applicabile

Edizione: Free

Limiti noti: token opachi di 32 byte casuali in base64url. Nel database ({prefix}nucleo_oauth_tokens) finisce solo l'hash SHA-256. Stato revoked: 0 attivo, 1 consumato, 2 revocato da admin o via RFC 7009. Durate fisse, senza filtri.

06Scope

Ogni scope corrisponde a una capability WordPress. Il consenso e il refresh concedono uno scope solo se l'utente ha quella capability. Ogni ability appartiene a un solo scope. Lo scope si somma alla capability propria dell'ability: servono entrambi. Le ability Pro sono segnate con (Pro).

nucleo:read

Cosa fa: abilita le ability di lettura. Etichetta nel consenso: "Read documents, layouts and site status".

Come si usa: scope=nucleo:read.

Parametri: abilita nucleo/site-describe, nucleo/guide, nucleo/catalog-list, nucleo/catalog-get, nucleo/doc-list, nucleo/doc-get, nucleo/doc-validate, nucleo/doc-preview, nucleo/doc-revisions, nucleo/doc-texts, nucleo/quality-check, nucleo/quality-scan, nucleo/tokens-get, nucleo/layout-list, nucleo/layout-explain, nucleo/audit-list, nucleo/bind-fields, nucleo/section-list, nucleo/menu-list, nucleo/gap-list, nucleo/model-get, nucleo/model-validate, nucleo/components-list, nucleo/fields-get, nucleo/content-list, nucleo/content-get, nucleo/terms-get, nucleo/docs-search, nucleo/assets-report (Pro), nucleo/kit-list (Pro).

Permessi: edit_posts

Edizione: Free

Limiti noti: alcune letture chiedono una capability più alta di quella dello scope: nucleo/assets-report, nucleo/model-get, nucleo/model-validate (manage_options), nucleo/layout-list, nucleo/layout-explain (edit_theme_options).

nucleo:write

Cosa fa: abilita creazione e modifica di documenti, contenuti e media. Etichetta: "Create and edit documents and media".

Come si usa: scope=nucleo:write.

Parametri: abilita nucleo/doc-create, nucleo/doc-patch, nucleo/doc-rollback, nucleo/doc-texts-set, nucleo/media-import, nucleo/media-upload, nucleo/media-formats, nucleo/gap-report, nucleo/fields-set, nucleo/content-upsert, nucleo/terms-set, nucleo/doc-translate (Pro).

Permessi: edit_posts

Edizione: Free

Limiti noti: con un token, publish: true o uno stato publish, future o private al primo livello richiedono anche nucleo:publish, per ogni ability. nucleo/doc-patch, nucleo/doc-texts-set, nucleo/doc-rollback, nucleo/fields-set, nucleo/doc-create con postId e nucleo/layout-conditions-set richiedono nucleo:publish anche su un post già pubblicato, programmato o privato. Senza lo scope la chiamata risponde insufficient_scope.

nucleo:publish

Cosa fa: abilita la pubblicazione. Etichetta: "Publish documents".

Come si usa: scope=nucleo:publish.

Parametri: abilita nucleo/doc-publish. Serve anche alle altre ability per pubblicare e per modificare un post online. Con un token, la route REST nucleo/v1/editor-mode richiede nucleo:write, e anche nucleo:publish se il post è pubblicato, programmato o privato.

Permessi: publish_pages

Edizione: Free

Limiti noti: nessuno rilevato.

nucleo:design

Cosa fa: abilita design system, layout, menu, regole asset e ottimizzazione CSS. Etichetta: "Edit design, tokens, layouts and asset rules".

Come si usa: scope=nucleo:design.

Parametri: abilita nucleo/tokens-set, nucleo/fonts-import, nucleo/menu-set, nucleo/layout-conditions-set, nucleo/assets-rules-set, nucleo/critical-set, nucleo/critical-request, nucleo/model-set, nucleo/assets-audit (Pro), nucleo/css-purge (Pro), nucleo/css-status (Pro), nucleo/css-optimize (Pro), nucleo/css-optimize-apply (Pro), nucleo/css-optimize-off (Pro), nucleo/kit-apply (Pro).

Permessi: edit_theme_options

Edizione: Free per lo scope; alcune ability sono Pro

Limiti noti: nucleo/css-status è una lettura ma sta in questo scope. nucleo/assets-rules-set, nucleo/model-set e tutte le nucleo/css-* e nucleo/assets-audit chiedono manage_options. La mappa contiene anche presets-apply, che non corrisponde a nessuna ability registrata.

nucleo:admin

Cosa fa: abilita stato, cache, impostazioni, import/export e opzioni del sito. Etichetta: "Manage the cache, status and settings".

Come si usa: scope=nucleo:admin.

Parametri: abilita nucleo/status, nucleo/cache-rebuild, nucleo/settings-get, nucleo/settings-set, nucleo/site-export, nucleo/site-import, nucleo/site-options-set, nucleo/icons-set, nucleo/component-activate, nucleo/mail-log, nucleo/woo-checkout-fields-set (Pro), nucleo/woo-checkout-parts-set (Pro).

Permessi: manage_options

Edizione: Free

Limiti noti: nucleo/component-activate chiede in più activate_plugins. nucleo/settings-get, nucleo/site-export e nucleo/mail-log sono letture ma stanno in questo scope.

07Ruolo agente

Ruolo nucleo_agent

Cosa fa: crea il ruolo "Nucleo Agent" per utenti dedicati agli agenti AI. Il ruolo modifica documenti e media, non pubblica e non tocca le opzioni.

Come si usa: crea un utente con ruolo Nucleo Agent e autorizza l'agente con quell'utente nella schermata di consenso, oppure usa wp nucleo mcp --user=<login>.

Parametri: capability del ruolo:

CapabilityValore
readtrue
edit_poststrue
edit_pagestrue
edit_published_pagestrue
upload_filestrue

Permessi: l'installazione avviene all'attivazione del plugin e dopo un aggiornamento di versione.

Edizione: Free

Limiti noti:

  • Con queste capability l'utente può concedere solo nucleo:read e nucleo:write.
  • Il ruolo si crea solo se manca: un ruolo già presente non si aggiorna.
Attenzione

Con edit_published_pages l'agente modifica pagine già pubblicate, e quei salvataggi vanno online.

08Meccanismi comuni delle ability

Registrazione e regola Free/Pro

Cosa fa: registra le ability nucleo/* nella categoria nucleo dell'Abilities API. Salta le ability Pro senza licenza.

Come si usa: automatica, sugli hook wp_abilities_api_categories_init e wp_abilities_api_init. Ogni ability definisce name(), args(), execute() e permitted().

Parametri: l'elenco delle ability Pro è nel blocco qui sotto.

Pro

Le dodici ability Pro sono nucleo/doc-translate, nucleo/assets-audit, nucleo/css-purge, nucleo/assets-report, nucleo/kit-list, nucleo/kit-apply, nucleo/css-status, nucleo/css-optimize, nucleo/css-optimize-apply, nucleo/css-optimize-off, nucleo/woo-checkout-fields-set e nucleo/woo-checkout-parts-set. Senza licenza attiva non esistono: non compaiono in tools/list né in wp-abilities/v1.

Permessi: non applicabile

Edizione: la licenza decide. Senza licenza attiva le ability Pro non si registrano.

Limiti noti:

  • Serve l'Abilities API di WordPress.
  • Un nome con maiuscole non si registra.
  • Un nome già registrato non si sovrascrive.
  • Ogni ability ha meta.show_in_rest: true.
  • Se lo schema di input non ha campi obbligatori, Nucleo aggiunge default: [], così le letture rispondono anche in GET.

Controllo dei permessi

Cosa fa: il permission_callback di ogni ability controlla prima la capability WordPress (permitted()), poi lo scope OAuth.

Come si usa: automatico su ogni superficie (MCP, REST wp-abilities/v1, WP-CLI).

Parametri: nessuno.

Permessi: capability propria dell'ability (vedi Tabella delle ability) e, con token OAuth, lo scope dell'ability.

Edizione: Free

Limiti noti: senza token (cookie, application password, WP-CLI) vale solo la capability. Scope mancante: WP_Error insufficient_scope, status 403, dati scope con lo scope richiesto. Su MCP il server controlla lo scope prima dell'esecuzione, perché WordPress valida l'input prima dei permessi.

Limite di frequenza

Cosa fa: limita le scritture per utente e per gruppo di scope, su una finestra fissa.

Come si usa: si regola con il filtro nucleo/rate_limit.

add_filter('nucleo/rate_limit', fn () => 120);

Parametri:

NomeTipoValori ammessiDefaultNote
nucleo/rate_limitintero (filtro)intero60chiamate per finestra
finestraintero (fissa)60 secondinon filtrabile

Permessi: non applicabile

Edizione: Free

Limiti noti:

  • Vale solo per le ability senza readonly: true nelle annotazioni.
  • Chiave: <id utente>|<scope dell'ability>; ogni scope ha un contatore separato.
  • Finestra fissa allineata a multipli di 60 secondi: a cavallo di due finestre passano fino al doppio del limite.
  • Oltre il limite l'ability non esegue e restituisce {"ok": false, "error": {"code": "rate_limited", "message": "…", "retryAfter": 60}}.
  • Il contatore usa l'object cache persistente se c'è, altrimenti una riga in wp_options.

Formato dell'esito

Cosa fa: definisce la forma delle risposte delle ability.

Come si usa: il chiamante legge ok.

Parametri: tre forme:

FormaEsempioSu MCP
Successo{"ok": true, …campi dell'ability}structuredContent, isError: false
Errore di dominio{"ok": false, "error": {"code": "not_found", "message": "…"}}structuredContent, isError: true
WP_Errorcodice e messaggio, per input non valido o permessistructuredContent {ok: false, error: {code, message, data?}}, isError: true

Codici ricorrenti in error.code: not_found, invalid_input, invalid_document, rate_limited. Codici WP_Error comuni: invalid_input, insufficient_scope.

Permessi: non applicabile

Edizione: Free

Limiti noti: la forma non è imposta dall'interfaccia. Alcune ability restituiscono lo stesso errore come WP_Error o come ok: false secondo il caso (esempio: nucleo/doc-preview usa WP_Error invalid_input e ok: false con not_found). Gli oggetti error possono avere campi in più, come errors o retryAfter. I dettagli sono nelle singole ability.

Compilazione senza salvataggio

Cosa fa: normalizza, valida e compila un documento. Non scrive nulla. Restituisce {"ok": true, "html", "css"} oppure {"ok": false, "error": {"code": "invalid_document", "message", "errors": [...]}}.

Come si usa: la chiama nucleo/doc-preview. La usano anche l'editor backend e l'anteprima dei kit.

Parametri: un documento Nucleo e un flag, false di default. true aggiunge data-nc-id ai nodi, per l'editor.

Permessi: quelli dell'ability chiamante

Edizione: Free

Limiti noti: nessuno rilevato.

Anteprima firmata (?nucleo_preview=)

Cosa fa: mostra nel tema la versione corrente di un documento, anche in bozza, a chi ha il link.

Come si usa: nucleo/doc-preview con postId restituisce previewUrl, valido 1800 secondi. Il link è il permalink del post con ?nucleo_preview=<token>.

Parametri:

NomeTipoValori ammessiDefaultNote
nucleo_previewstringatoken base64url di postId.scadenza.firmanessunofirma HMAC-SHA256 con wp_salt('nonce')
duratainterosecondi600nucleo/doc-preview usa 1800

Permessi: nessuno sulla richiesta: vale il token

Edizione: Free

Limiti noti:

  • Risposte: 403 token non valido o scaduto, 404 documento assente, 422 documento non compilabile.
  • Headers X-Robots-Tag: noindex e Cache-Control: no-store.
Attenzione

Il token non è legato a un utente. Chiunque abbia il link vede la bozza fino alla scadenza.

Dry-run

Cosa fa: controlla l'input e riporta le azioni previste senza scrivere.

Come si usa: parametro dryRun: true nelle ability che lo dichiarano nello schema.

Parametri: lo dichiarano nucleo/doc-create, nucleo/doc-patch, nucleo/content-upsert, nucleo/terms-set, nucleo/kit-apply, nucleo/site-import, nucleo/model-set. nucleo/model-set ha anche confirm per accettare le modifiche distruttive.

Permessi: quelli dell'ability

Edizione: Free (nucleo/kit-apply è Pro)

Limiti noti: non è un meccanismo comune: ogni ability lo implementa a modo suo. Le altre scritture non hanno dry-run. Una chiamata in dry-run non è marcata readonly, quindi conta nel limite di frequenza.

09Tabella delle ability

Tutte le 70 ability registrate. "Tipo" segue l'annotazione readonly. "Capability" riassume la capability principale; i dettagli sono nelle singole ability.

AbilityTipoScopeCapabilityEdizione
nucleo/assets-reportletturanucleo:readmanage_optionsPro
nucleo/audit-listletturanucleo:readedit_postsFree
nucleo/bind-fieldsletturanucleo:readedit_postsFree
nucleo/catalog-getletturanucleo:readedit_postsFree
nucleo/catalog-listletturanucleo:readedit_postsFree
nucleo/components-listletturanucleo:readedit_pagesFree
nucleo/content-getletturanucleo:readedit_posts del tipoFree
nucleo/content-listletturanucleo:readedit_posts del tipoFree
nucleo/css-statusletturanucleo:designmanage_optionsPro
nucleo/doc-getletturanucleo:readedit_postFree
nucleo/doc-listletturanucleo:readedit_postsFree
nucleo/doc-previewletturanucleo:readedit_post o edit_postsFree
nucleo/doc-revisionsletturanucleo:readedit_postFree
nucleo/doc-textsletturanucleo:readedit_postFree
nucleo/doc-validateletturanucleo:readedit_postsFree
nucleo/docs-searchletturanucleo:readedit_postsFree
nucleo/fields-getletturanucleo:readedit_post o edit_termFree
nucleo/gap-listletturanucleo:readedit_postsFree
nucleo/guideletturanucleo:readedit_postsFree
nucleo/kit-listletturanucleo:readedit_postsPro
nucleo/layout-explainletturanucleo:readedit_theme_optionsFree
nucleo/layout-listletturanucleo:readedit_theme_optionsFree
nucleo/mail-logletturanucleo:adminmanage_optionsFree
nucleo/menu-listletturanucleo:readedit_postsFree
nucleo/model-getletturanucleo:readmanage_optionsFree
nucleo/model-validateletturanucleo:readmanage_optionsFree
nucleo/quality-checkletturanucleo:readedit_post o edit_postsFree
nucleo/quality-scanletturanucleo:readedit_postsFree
nucleo/section-listletturanucleo:readedit_postsFree
nucleo/settings-getletturanucleo:adminmanage_optionsFree
nucleo/site-describeletturanucleo:readedit_postsFree
nucleo/site-exportletturanucleo:adminmanage_optionsFree
nucleo/statusletturanucleo:adminmanage_optionsFree
nucleo/terms-getletturanucleo:readedit_posts e assign_termsFree
nucleo/tokens-getletturanucleo:readedit_postsFree
nucleo/assets-auditscritturanucleo:designmanage_optionsPro
nucleo/assets-rules-setscritturanucleo:designmanage_optionsFree
nucleo/cache-rebuildscritturanucleo:adminmanage_optionsFree
nucleo/component-activatescritturanucleo:adminactivate_pluginsFree
nucleo/content-upsertscritturanucleo:writeedit_postsFree
nucleo/critical-requestscritturanucleo:designedit_theme_optionsFree
nucleo/critical-setscritturanucleo:designedit_theme_optionsFree
nucleo/css-optimizescritturanucleo:designmanage_optionsPro
nucleo/css-optimize-applyscritturanucleo:designmanage_optionsPro
nucleo/css-optimize-offscritturanucleo:designmanage_optionsPro
nucleo/css-purgescritturanucleo:designmanage_optionsPro
nucleo/doc-createscritturanucleo:writeedit_pages/edit_posts, edit_theme_options per layout e sezioniFree
nucleo/doc-patchscritturanucleo:writeedit_post (+ publish_post con publish)Free
nucleo/doc-publishscritturanucleo:publishpublish_postFree
nucleo/doc-rollbackscritturanucleo:writeedit_postFree
nucleo/doc-texts-setscritturanucleo:writeedit_post (+ publish_post con publish)Free
nucleo/doc-translatescritturanucleo:writeedit_post (+ publish_post con publish)Pro
nucleo/fields-setscritturanucleo:writeedit_post o edit_termFree
nucleo/fonts-importscritturanucleo:designedit_theme_optionsFree
nucleo/gap-reportscritturanucleo:writeedit_pagesFree
nucleo/icons-setscritturanucleo:adminmanage_optionsFree
nucleo/kit-applyscritturanucleo:designedit_theme_optionsPro
nucleo/layout-conditions-setscritturanucleo:designedit_postFree
nucleo/media-formatsscritturanucleo:writeupload_filesFree
nucleo/media-importscritturanucleo:writeupload_filesFree
nucleo/media-uploadscritturanucleo:writeupload_filesFree
nucleo/menu-setscritturanucleo:designedit_theme_optionsFree
nucleo/model-setscritturanucleo:designmanage_optionsFree
nucleo/settings-setscritturanucleo:adminmanage_optionsFree
nucleo/site-importscritturanucleo:adminmanage_optionsFree
nucleo/site-options-setscritturanucleo:adminmanage_optionsFree
nucleo/terms-setscritturanucleo:writemanage_terms della tassonomiaFree
nucleo/tokens-setscritturanucleo:designedit_theme_optionsFree
nucleo/woo-checkout-fields-setscritturanucleo:adminmanage_optionsPro
nucleo/woo-checkout-parts-setscritturanucleo:adminmanage_optionsPro
Esc
↑↓ per scegliere↵ per aprireEsc per chiudereRicerca locale, nessun dato inviato