"""Tool schemas — what the LLM reads to decide when to call these tools. Deliberately small (8 tools). The WordVibe site exposes ~100 tools over MCP; registering all of them would put ~100 schemas on every API call. Everything beyond these wrappers is reachable through `wordvibe_call`. """ _SITE = { "type": "string", "description": ( "Which configured site to use: its name or URL " "(e.g. 'mysite' or 'https://mysite.com'). Omit to use the first configured site." ), } BUILD_PAGE = { "name": "wordvibe_build_page", "description": ( "Build or update a page in the site's Word Page Builder (WPB) from section HTML. Each " "section is wrapped automatically in
, " "so the page opens natively in the builder and stays editable/undoable there. Use this to " "publish a landing page, or to rebuild a page's sections, without a browser." ), "parameters": { "type": "object", "properties": { "title": {"type": "string", "description": "Page title."}, "sections": { "type": "array", "description": ( "Ordered list of sections. Each item: {kind, html} — kind is a kebab-case section " "name (hero, features, pricing, testimonials, faq, cta, footer, gallery, contact, " "about, services, custom); html is the section's inner HTML (inline styles are fine)." ), "items": { "type": "object", "properties": { "kind": {"type": "string", "description": "Section kind, e.g. 'hero'."}, "html": {"type": "string", "description": "Inner HTML for the section."}, }, "required": ["kind", "html"], }, }, "slug": {"type": "string", "description": "URL slug (optional)."}, "status": { "type": "string", "description": "draft, publish, pending or private (default: draft).", }, "post_id": { "type": "integer", "description": "Existing page ID to update; omit to create a new page.", }, "site": _SITE, }, "required": ["title", "sections"], }, } SITES = { "name": "wordvibe_sites", "description": ( "List the WordPress sites this plugin can drive (configured via WORDVIBE_SITE_URL / " "WORDVIBE_MCP_SITES). Optionally probes each one to report whether its WordVibe MCP " "server is reachable and enabled." ), "parameters": { "type": "object", "properties": { "probe": { "type": "boolean", "description": "Also connect to each site and report reachability (default false).", }, }, }, } SITE_INFO = { "name": "wordvibe_site_info", "description": ( "Report what a WordVibe site is running: MCP server name/version (the plugin version), " "WordPress name/version/URL, active theme, and plugin count. Use this first when you need " "to know what you're working with." ), "parameters": {"type": "object", "properties": {"site": _SITE}}, } TOOLS = { "name": "wordvibe_tools", "description": ( "List the tools the WordVibe site exposes over MCP — file read/write/edit, codebase " "search, database queries, posts/media, plugin & theme management, WP-CLI, cron, security " "scans, and more. Call this when you need a capability that isn't covered by the " "wordvibe_read_file / wordvibe_write_file / wordvibe_edit_file / wordvibe_search wrappers, " "then invoke it with wordvibe_call." ), "parameters": { "type": "object", "properties": { "site": _SITE, "filter": { "type": "string", "description": "Optional case-insensitive substring to filter tool names/descriptions.", }, }, }, } CALL = { "name": "wordvibe_call", "description": ( "Call any tool on the WordVibe site by name (see wordvibe_tools for the catalogue). " "This is the escape hatch for everything without a dedicated wrapper — e.g. post_list, " "plugin_list, db_query (SELECT only), cli_exec, security_scan_installed, list_directory, " "file_search, create_post. Arguments are passed through to the site tool as-is." ), "parameters": { "type": "object", "properties": { "tool": {"type": "string", "description": "Site tool name, e.g. 'post_list'."}, "arguments": { "type": "object", "description": "Arguments for the site tool (its own parameter names).", }, "site": _SITE, }, "required": ["tool"], }, } READ_FILE = { "name": "wordvibe_read_file", "description": ( "Read a file from a WordVibe site (any path inside the WordPress install, e.g. " "'wp-content/themes/my-theme/functions.php' or 'wp-config.php'). Always read a file " "before writing or editing it." ), "parameters": { "type": "object", "properties": { "path": {"type": "string", "description": "Path relative to the WordPress root."}, "lines": { "type": "string", "description": "Optional line range, e.g. '1-80' or '120-160'. Omit for the whole file.", }, "site": _SITE, }, "required": ["path"], }, } WRITE_FILE = { "name": "wordvibe_write_file", "description": ( "Write (overwrite) a file on a WordVibe site. The site takes a safety snapshot of the " "previous version before saving, so a rollback is always possible. Read the file first." ), "parameters": { "type": "object", "properties": { "path": {"type": "string", "description": "Path relative to the WordPress root."}, "content": {"type": "string", "description": "Full new file content."}, "site": _SITE, }, "required": ["path", "content"], }, } EDIT_FILE = { "name": "wordvibe_edit_file", "description": ( "Make a targeted edit on a WordVibe site: replace the first exact occurrence of `search` " "with `replace`. Preferred over wordvibe_write_file for small changes — it can't clobber " "the rest of the file." ), "parameters": { "type": "object", "properties": { "path": {"type": "string", "description": "Path relative to the WordPress root."}, "search": {"type": "string", "description": "Exact text to find."}, "replace": {"type": "string", "description": "Replacement text."}, "site": _SITE, }, "required": ["path", "search", "replace"], }, } SEARCH = { "name": "wordvibe_search", "description": ( "Search a WordVibe site's codebase (themes, plugins, mu-plugins, core) and return matching " "lines with context. Supports plain text or regex, scoped to a path and/or file pattern." ), "parameters": { "type": "object", "properties": { "query": {"type": "string", "description": "Text or regex to search for."}, "path": { "type": "string", "description": "Optional subdirectory, e.g. 'wp-content/plugins/my-plugin'.", }, "include": {"type": "string", "description": "Optional file glob, e.g. '*.php'."}, "regex": {"type": "boolean", "description": "Treat `query` as a regular expression."}, "site": _SITE, }, "required": ["query"], }, }