Appearance
AI Agents
Connect Claude, Cursor or any other MCP client to the site and it runs the site for you: posts, media, settings, and everything the installed modules add. It works with the rights of the user whose key it holds — nothing more.
The other way: AI inside the admin
Here your agent, with your subscription, works on the site from the outside. For the site itself to ask a model — a "Translate with AI" button, with an API key saved on the site and a monthly budget — see AI Writer. The same tools in a chat inside the admin, with the site's model, are the Assistant; Three Ways to Use AI compares them.
Video lessons
First connect an agent, then watch it at work: clearing out demo content and bringing a post back, filling the site with sample content, SEO and redirects, the day's orders, the shop's sales, the site's health. The chat on the left is a real agent's, and every tool it calls changes the site on the right.
Connecting an agent
Turning it on
AI agents → Settings: turn on AI agents. Until then
/mcpanswers 404.The permission Let AI agents work with my application passwords (
use_ai_agents). Administrators have it; give it to another role on the roles screen only if that role should have agents.A key — an application password of the REST API, shown once:
- Filament AI agents → Connect an agent makes one for you, with the settings ready to paste into the agent;
- Nova AI agents → Connect an agent shows the address and the settings, and links to REST API → Add New Application Password for the key.
Any application password works the same way.
A key that writes lets the agent create and change records; a read-only key gets the reading tools only.
The address and the key
The address is https://your-site/mcp; the key goes in the Authorization header as Bearer <id>|<secret>.
bash
claude mcp add --transport http kitloom https://your-site/mcp --header "Authorization: Bearer 12|…"json
// .cursor/mcp.json
{
"mcpServers": {
"kitloom": {
"url": "https://your-site/mcp",
"headers": { "Authorization": "Bearer 12|…" }
}
}
}json
// claude_desktop_config.json, through mcp-remote
{
"mcpServers": {
"kitloom": {
"command": "npx",
"args": ["mcp-remote", "https://your-site/mcp", "--header", "Authorization: Bearer 12|…"]
}
}
}claude.ai
claude.ai — on the web, on phones and as Claude Desktop's own connectors — takes the key in a header, like the other clients. In Settings → Connectors → Add custom connector:
| Field | What goes in |
|---|---|
| Name | anything, e.g. My site |
| URL | https://your-site/mcp |
| Authentication | No sign-in |
| Request headers → Add header | Authorization, with the value Bearer 12|… |
Then, in a new chat, turn the connector on in the tools menu and ask away. Connect an agent — and the dashboard, for a key made ahead — shows the URL and the header's value ready made: in Filament with a new key, in Nova with a place for yours.
A client without headers
A client that cannot send a header can take the key inside the address instead, with the bar of the key written as a dot:
https://your-site/mcp/k/12.…Such an address is a password
It lands in the web server's logs, in browser histories and in error reports that keep the URL, so use the header wherever the client has one. Make a key of its own for it, with an expiry, and revoke it when it is no longer used: a revoked or expired address answers 404, as one that never was. kitloom-ai.mcp.secret_address set to false turns these addresses off. Signing in with OAuth is not offered yet.
On the same machine
php artisan mcp:start kitloom serves the same tools over stdio — for Claude Code working in the project itself:
bash
claude mcp add kitloom -e KITLOOM_AI_USER=admin -- php artisan mcp:start kitloomIt acts as the user KITLOOM_AI_USER names (login or email), who needs use_ai_agents too; with nobody named, every tool refuses. It does not depend on the settings switch: whoever runs it has the console anyway.
How it works
A kitloom site can be run by an AI agent — Claude, Cursor or any other client of the Model Context Protocol. kitloom/ai is an MCP server at /mcp: its tools read and write posts, pages, terms, media and settings, tell what lives at an address and show a page as the site renders it. Installed modules add tools of their own — menus, widgets, SEO, redirects, custom fields, forms, comments, the shop, sliders, bookings, courses, listings, languages, webhooks, maintenance mode, backups, the activity log, Site Health and more.
The agent works with the rights of the user whose key it holds, through the same code the admins use. It cannot do what that user may not do, it cannot delete anything for good, and a revoked key stops it at once.
| Package | Gives |
|---|---|
kitloom/ai | The MCP server, the core tools, the local server for the console |
kitloom/ai-filament / kitloom/ai-nova | The AI agents section: Connect an agent, Settings, How it works |
bash
composer require kitloom/ai kitloom/ai-filament # or kitloom/ai-novaIt needs the REST API module: its application passwords are the agents' keys.
What an agent can do
Content, media and settings
The core tools, always there:
| Tool | What it does |
|---|---|
describe_site | The site, its post types and taxonomies with what they support, the statuses, what the key may do with each type. The agent's first call |
list_content | Records of a post type, every status but the trash: search, status, terms, parent, author, dates, pages |
get_content | One record in full, with its stored HTML |
create_content | A new record — a draft unless the agent gives a status — with terms, a featured image and, for types with comments, whether they are open |
update_content | Changes to a record: only the fields sent |
trash_content, restore_content | Into the trash and back, with the status it had |
content_revisions, restore_revision | A record's saved versions — when, by whom, whether an agent made it, what changed — and one brought back; the restore is a version too, so it can be undone the same way |
list_terms | Terms of a taxonomy: search, parent, the terms of a record; or those in the trash |
create_term, update_term | A new term, changes to one |
trash_term, restore_term | A term into the trash and back — never the default category |
list_media | The media library with the address of each file; images without alt text, and files nothing seems to use |
upload_media | A file into the library — from a public web address, or sent as base64 with its name — with title, alt text and caption |
update_media | Title, alt text or caption of a file |
list_users | Users by name, for author ids — without emails |
list_settings | The declared settings by group, with values and whether the agent may change each |
update_setting | One setting, checked against its declaration and the user's permission |
resolve_url | What lives at an address: the kind of page, the record or term, the records of an archive, the templates the theme tries and the one it has |
render_page | A page as the site shows it — the text a visitor reads, the HTML, or the page's parts as JSON (an object, page); a draft as its preview |
get_page_schema | The JSON Schema of that page, or of one part — the parts this site has installed, the theme's own among them |
Tools from modules
An installed module adds its tools; an agent sees them only when its user has the module's permission.
| Module | Tools | What for |
|---|---|---|
| Navigation | menus_list, menu_get, menu_save | Menus and their places |
| Widgets | widgets_list, widgets_save | The widgets of each zone; a widget left out goes to the inactive ones |
| SEO | seo_get, seo_update | Title, description, robots, canonical, Facebook card, primary category — of a record or a term |
| Redirects | redirects_list, redirects_create, redirects_update, redirects_trash, redirects_settings_get, redirects_settings_update, not_found_list, redirect_from_404 | Redirects, their settings and the 404 log |
| Custom Fields | fields_get, fields_set, field_groups_get, field_groups_save | Field values, checked as the edit form checks them; field groups made and fields added or changed — never removed |
| Forms | forms_list, form_get, form_create, form_update, submissions_list, submission_spam | Contact forms and their messages; a new form mails the site's admin — where messages go is a person's choice |
| Comments | comments_list, comments_moderate, comments_reply | Comments and product reviews: list, approve, hold, spam, trash, restore, answer |
| Shop | products_list, product_get, product_save, product_category_image, attributes_list, attribute_save, orders_list, order_get, order_create, order_set_status, order_add_note, sales_report, top_products, customers_list, coupons_list, coupon_save | The catalogue, its attributes, the orders, the sales and the customers, the coupons. A new product is a draft; an order taken by phone starts pending or on hold at the catalogue's prices — nothing is charged; a completed or refunded order is not reopened; refunds stay in the admin; notes are internal |
| Sliders | sliders_list, slider_get, slider_save | Sliders and their slides |
| Bookings | bookings_catalog, bookings_slots, bookings_list, bookings_create, bookings_decide, bookings_clients, bookings_client, bookings_client_note, bookings_service_save, bookings_staff_get, bookings_staff_save, bookings_close | Services and free times, appointments and their decisions, the clients and notes about them; the services, the staff with their hours and time off, the salon closed for a holiday. Nothing is deleted, and which account a staff member signs in with stays a person's choice |
| Backup | backup_status, backup_run | The backups and a new one; archives are downloaded and deleted in the admin |
| Activity Log | activity_list | Who changed what |
| Site Health | health_report, health_run, health_failed_jobs | The checks and their results; the queue's failed jobs — which and when, never the message |
| Languages | languages_list, languages_get_translations, languages_save_translation, languages_translate | The site's languages and the translations of posts, terms and users; a machine translation is saved as a draft |
| Link Checks | link_checks_list, link_checks_recheck, link_checks_dismiss, link_checks_replace | Broken links with the posts they are in: check again, dismiss, replace or unlink an address everywhere |
| Post Types | post_types_list, post_types_get, post_types_create, post_types_update, post_types_trash, post_types_restore | Post types and taxonomies made in the admin, checked as the form checks them; a trashed type keeps its records |
| Search | search_status, search_reindex | How the search index is doing, and a rebuild on the queue; its settings are options of update_setting |
| Image compression | media_optimizer_status, media_regenerate | Which compression tools the server has and how to install the missing ones; the sizes of a few images cut — and compressed — again, no file deleted |
| Import & Export | imports_list, import_get, import_start | The history of imports, and an import of a WXR file from a public address; exports stay in the admin |
| Courses | courses_list, courses_get, courses_save, courses_enroll, courses_students | Courses with their curriculum, enrolling a user by hand, the students and their progress. A new course is a draft; lessons and quizzes are written with the core tools |
| Listings | listings_search, listings_get, listings_save, listings_enquiries, listings_enquiry_status | Properties and directory listings, and the enquiries sent from their pages. A new one is a draft |
| Webhooks | webhooks_list, webhooks_create, webhooks_update, webhooks_deliveries | Outgoing webhooks, a test delivery and the delivery log. The secret is shown once, on creation; a webhook is disabled, not deleted |
| Maintenance mode | maintenance_settings_get, maintenance_settings_update | The holding page — coming soon or maintenance — its words, the roles that still see the site, the access link |
| Users (core) | users_create, users_update, users_set_role | A user invited by email to choose their own password, a public profile, a role — never an address or a password, never a role that runs the site or manages users, nor anyone who holds one |
| Search & Replace | search_replace_dry_run, search_replace_run, search_replace_runs | A change counted first, then made exactly as counted — in posts, comments, terms and their meta only; options and user meta stay with the admin |
| Internal Links | internal_links_report, internal_links_list, internal_links_recount | Link counts, the orphans nobody links to, the links of a post and to it |
| Privacy | privacy_requests_list, privacy_request_create, privacy_request_complete | Personal data requests; a new one is always confirmed by the person; exports and erasures stay in the admin |
| AI Writer | ai_writer_usage | The month's spending against the budget — never the key |
| Pulse | pulse_report | Slow pages, queries and jobs, and the exceptions thrown |
| Payments | payments_methods | Which ways to pay are on and which credentials are missing — never a value |
| Site (core) | site_cache_clear | The page cache cleared, as Settings → Cache's button |
| Site (core) | theme_customize | The active theme's settings — colours, the logo, the footer's line — as on Appearance → Customize, published at once; describe_site lists them under theme_settings |
describe_site also lists the shortcodes the site draws, each with an example, so an agent writing content puts in one the site knows.
describe_site also names each module's tools and what the module tells about the site: which field groups show where, the menu places, what each SEO name means. Each module turns its own tools off with kitloom-<name>.ai.register.
What to ask
A few things an agent does well on a kitloom site:
- "Write a draft post about our spring collection, put it in News, and take the cover from this link."
- "Find the pages that still mention the old phone number and fix them."
- "Which addresses gave 404 this week? Redirect the ones that have a new page."
- "Fill in the SEO descriptions of the products that have none."
- "Show me how the About page looks now, then shorten its first section."
Safety
Who sees and writes what. An agent sees with the eyes of the key's user, type by type: every record of a type whose others' records the user may edit (edit_others_posts, edit_others_pages, …), otherwise what is published and the user's own. Only the declared post types are read through the content tools — a module's own records come through its tools and permission — and the text of a password-protected record only for a user who may edit it. It writes as the key's user, through the same writers the admins use: the slug is made unique, the dates are filled, and whatever the user may not do — publish, edit another author's record, manage terms — is refused with a message the agent reads. The activity log shows an agent's changes under the key's user.
Nothing is deleted for good. The agent moves records to the trash; permanent deletion is left to a person in the admin.
Every change can be undone. Each save of a record keeps a revision, as WordPress keeps them — the title, the content, the excerpt, the custom fields and the SEO meta. A revision an agent's change left is marked so: content_revisions lists them, restore_revision and the Revisions panel of both admins bring an older version back, and the restore is a revision too. A search and replace keeps each record as it was before the run.
Settings agents leave alone. Protected settings — the site address, the roles, secrets — are never shown to an agent. Some more are locked: the agent sees them without their values and may not change them, because text it reads could try to talk it into it. These are who gets in (registration, the default role, the admin email, two-factor, social login), the doors agents and apps come through (AI agents, REST API), and the code on every page and the data that leaves the site (Header & Footer, Tag Manager, Analytics, Ad Pixels, Sentry, Backups, the mail server). A person changes those in the admin; kitloom-ai.settings.locked holds the list.
Files from the web. upload_media fetches only from public hosts, redirects included, and — from an address or sent as base64 — takes only file types the library takes, up to its size limit (kitloom-media.max_size, kitloom-media.remote).
Every request carries its key. The address has no session and no CSRF. Requests are limited per user: kitloom-ai.mcp.rate_limit a minute (120; 0 — no limit).
Configuration
bash
php artisan vendor:publish --tag=kitloom-ai-config| Key | Default | Meaning |
|---|---|---|
mcp.register | true | The MCP server at all |
mcp.path | mcp | Its address |
mcp.rate_limit | 120 | Requests a minute per user; 0 — no limit |
mcp.secret_address | true | The /mcp/k/… addresses for claude.ai |
local.user | KITLOOM_AI_USER | Who the local server acts as |
render.max_chars, render.max_chars_limit | 20000, 200000 | The default and the largest length of render_page |
settings.locked | the list above | The settings agents may not change; * matches any end |
filament.register, nova.register | true | The admin sections |
filament.dashboard, nova.dashboard | true | Connect an AI agent at the top of the dashboard, while agents are on, for a user who may use them and has no key yet. Nova cannot add to the host's dashboard: there the host lists Kitloom\Ai\Nova\Cards\AgentCard in its Main, and false hides it |
Tools of your own
A module offers tools without requiring kitloom/ai: a Kitloom\WpSchema\Contracts\AgentTool in its domain package, tagged AgentTool::TAG, and what the agent should know first as an AgentContext. See Extension Points → AI agents and Testing → Agent tools.
Next
- Headless & APIs — page JSON and the REST root
- Module Catalog