The connector is supervised, not autonomous: an AI drafts and edits through these tools, but it is bound by the partner's capabilities and per-file ACLs, the deny-list (it can never read or write delivery secrets), and - for write actions - the AI client's own per-call approval. Reads are not audited; writes are recorded as material events.
The connector is a single MCP endpoint, Streamable HTTP / JSON-RPC:
https://YOUR-SITE/cgi-bin/lazysite-mcp.pl
initialize and tools/list are open (discovery); a tools/call requires
authentication. An unauthenticated tool call returns HTTP 401 with a
WWW-Authenticate challenge so an OAuth client starts the sign-in flow.
Two credential shapes, same capability + ACL enforcement:
Authorization: Bearer <partner-id>:<lzs_ token> - the token comes from
Generate credential on the Users page.
whoami returns an auth block - { method: "oauth"|"bearer", expires_at } - so
the agent can see how the session is authenticated and when it lapses.
A partner's grant (visible in whoami.capabilities) gates the tools:
manage_content - read/write content pages and use the file tools (most tools).
Defaults to the webdav grant; set off for a theme-only partner.manage_themes - activate themes.manage_layouts - activate layouts.manage_domains - manage the domains this instance serves, and move whole
sites between them (the site_backup / site_apply tools; the domain-*
control-API actions).webdav - the WebDAV transport / file-API mechanism flag.manage_config - site configuration (control API, not exposed as MCP tools).manage_connectors - where site data may be sent: define connectors, set their
secrets, read the call record (control API only in this release; see
/docs/connectors). Calling a connector as a logged-in user needs no
capability - the connector's own callers groups decide.analytics - read the visitor-log analysis. Off by default; an explicit grant,
since it exposes (aggregated, IP-anonymised, path-free) log data. Visitor analysis
is available both as the MCP analyse_visitors tool AND as the control-API
analyse_visitors action (?action=analyse_visitors&window=N), so an API-channel
client gets it too.audit - read the audit trail (the in-page Audit view plus the control-API
audit action). A separate capability from analytics; off by default.Per-file ACLs (owner + read/write lists, with @groups) bind a token client
exactly as over WebDAV - a tool call is refused if the partner lacks access to the
target, regardless of capability.
The connector deliberately cannot reach operator-only surfaces. Attempts return a
machine-readable kind:
lazysite/forms/*.conf and other config - blocked-config (use the handler
tools below - save_handler, bind_form, save_schedule - rather than the
files; SMTP credentials are operator-only).lazysite/auth/*, .pl scripts, the manager - blocked.37 tools. Reads are not audited; writes are recorded in the audit log as
material events and may trigger the AI client's per-call approval. All file tools
need manage_content unless noted.
user), capabilities, account, active layout/theme, the
full tools manifest, and the auth block (method + expiry). No capability
required. Call it first. capabilities holds exactly the capability keys, as
booleans - ui among them is manager access. account holds what the account
is rather than what it may do: groups, email, display_name, provenance
(created_by, created_at, managed_by), token and MFA state, scopes, and
interactive_login (whether it may sign in to the manager at all). The control
API's whoami carries the same two blocks from the same builder (SM821).
holds - what THIS account
currently has. No capability required. The task recipes are the sanctioned
sequences: follow them (e.g. switch-layout, restore-from-history) rather
than improvising an order.
{ path }/) with size, mtime, ext
and generated. Brief presence left the listing with SM245 - ask list_briefs.
{ path }kind: binary) and files over 512 KB
(kind: too-large).
{ path }{ path }{ query, path }{ path }{ path | content }{ window }analytics
capability). Returns per-day totals, a people/AI-assistant/bot/noise breakdown,
top pages, referrers, status codes, and a capped recent event stream over the
last window days (1-365, default 30). Never the raw log, any filesystem path,
or a visitor IP. Read /docs/ai-briefing-stats for how to interpret it and what
may/may not be reported.
{ path }set_permissions.
cap) and what uses it (used_by); plus every form's handler list (forms)
and the fields each type takes (types). Opens for manage_forms,
manage_data or manage_connectors.
{ id, type, name, ... } / delete_handler { id }table
handler needs manage_data, a connector handler manage_connectors, smtp
and file need manage_forms; a refusal names the capability that would
work. A handler still used by a form or schedule entry is not deleted - the
answer names them. There is no webhook type: outbound HTTP is a connector.
{ id, handler, every, payload } / delete_schedule { id }manage_themes.
install_layout can pull without downloading anything. Needs manage_layouts.
When the operator has enabled the Content history plugin, every save
(manager, WebDAV, or this connector) is recorded as a version, and these tools
let you inspect and undo content changes. If list_versions returns
enabled: false, versions are not being recorded - ask the operator to enable
the plugin; do not try to build your own history. All three need
manage_content.
{ path, limit }{ path, version }{ path, version }Remote sync of the history (push/pull to a git host) is operator-only by design - it is configured and driven from the manager UI (Remote sync plugin) and is not exposed over the connector or the control API.
{ path, content }created (1 new / 0 overwrite) and runs
validate_page on the content, returning any warnings/issues. Audited as
create or edit.
{ slug, title, subtitle, body, register }{ slug }still_referenced_in (nav, other pages) for cleanup; generated indexes
refresh automatically.
{ old, new, update_links }update_links, rewrites
internal links to the old path across pages (nav.conf is not rewritten).
{ path, old, new }old is absent (no silent clobber); reports the replacement count.
{ from, to }{ from, to }{ path }delete.
{ path, read, write, draft }@groups), and the draft flag. A partial update: omitted fields keep their
current value. Setting a read list on a draft section leaves it draft -
still a 404 - so the API equivalent of the Publish button is
{"draft": false} alongside your grants. A field agent replicated the UI
flow, granted access, and the section kept 404ing; least surprise says the
trap gets named where the tool is learned.
{ form, handler } or { form, handlers: [...] }list_handlers.
Needs manage_forms only - and nothing but handler ids: to deliver
somewhere new, create the handler first.
{ items }items is an ordered list of { label, url }
(a children list becomes a sub-menu; an item with no url is a section header).
Writes nav.conf and rebuilds the cache.
{ theme }manage_themes.
{ layout, theme }manage_layouts.
{ layout, theme, all, update, activate }manage_layouts. To switch the site to a different
layout, this one call is the whole switch - it installs AND activates.
Only delete the old layout afterwards, if at all. Use
list_layout_catalogue first to see names.
{ layout }list_layout_catalogue -> install_layout -> (optionally) delete_layout.
A recovery snapshot is kept. Needs manage_layouts.
{ summary, good, bad, rating, context }{ path }"*" for all). A normal write
already clears its own page; use this for pages that embed another.
A site package is a portable snapshot of ONE domain's site: its content, its
navigation, the theme and layout it uses, and its presentation settings. It
deliberately excludes plugins, instance settings and any secrets, so it is safe
to hand to another instance. Use it to turn an agency demo into a client's live
site, or to copy a site to another domain. Both tools need manage_domains and
access to the domain.
{ host }lazysite-site-<host>-<stamp>.tar.gz in the backups area (fetch it with the
backup download if you need to move it to another instance). Returns the
package name.
{ name, host, clean }host to apply to the default site; clean: true clears
the target content first. Apply overwrites the target - take a backup first
if you want a rollback point. The target domain must already be registered
(domain-add on the control API) unless you are applying to the default site.
The end-to-end recipe (migrate-site) is in describe_capabilities under
tasks: site_backup on the source -> (download + site-backup-upload if a
different instance) -> site_apply on the target -> verify.
A failed tool result is { ok: 0, error, kind }. The kind lets an agent tell
causes apart: blocked, blocked-config, not-found, permission, binary,
too-large, invalid-path. A 401 carries error.data.reason -
sign-in-incomplete (no credential reached the server - re-authorise the
connector) vs credential-invalid (expired/revoked - reconnect).
Over the control API (/cgi-bin/lazysite-manager-api.pl) the same refusal
also answers with an HTTP status taken from its kind (SM670): forbidden,
permission, blocked, disabled 403; not-found 404 (an unknown action too);
exists, in-use, confirm 409; too-large 413; rate 429; a failure on the
server 500; partial - part of the write happened - 207; anything else, and a
refusal with no kind, 400. The body keeps ok: false either way, so a client may
key on either. MCP tool results are JSON-RPC and stay 200.
whoami - confirm identity, capabilities, and that tools are loaded.list_files / list_pages / read_page - orient; read before you edit.validate_page (with content) - catch front-matter / form / public-data
issues before writing.write_file or replace_text - make one change at a time.preview_page - confirm the render in-channel (not a web fetch). page_status
confirms it will reach visitors.audit_site after a set of changes - catch broken links / orphans / duplicates.Pages are Markdown files served at their path (about.md → /about); a page that
registers in a feed lists it in front matter (register: [sitemap, llms]).