package seo import ( "net/http" apicontrollers "git.golem15.com/golem15/sm-seo-plugin/controllers/api" "git.golem15.com/golem15/summercms/modules/pact" ) var _ pact.HasMCP = (*Plugin)(nil) // mcpGuard is the guard every SEO tool runs as: the backend account linked // to the MCP user. The routes resolve that administrator themselves. const mcpGuard = "backend" // mcpPermission is the one SEO permission (D-15) every tool is listed with; // the routes check it on every call. const mcpPermission = apicontrollers.PermissionManage // MCP declares the SEO tools (D-10, P-24): one per operation of the SEO // admin (operations.go maps each admin operation to its tool), each bound // to a /_seo/api/v1 management route, run as the backend account linked to // the MCP user and listed only when that account has golem15.seo.manage. // pier prefixes them with seo_. GET tools are read-only, so a read grant // sees only those; deletes and "mark as gone" are destructive. func (p *Plugin) MCP() pact.MCP { destructive := true return pact.MCP{Tools: []pact.MCPTool{ // Pages addressed by URL (D-11, D-13). { Name: "get_url_seo", Title: "Get the SEO of a URL", Description: "Shows the effective SEO of a page addressed by URL: every value with its source (URL rule, record, template, global settings, content or default), the redirect decision, the owner a change would be written to (the record or a URL rule) and the warnings of the SEO tab.", Guard: mcpGuard, Method: http.MethodGet, Path: "/_seo/api/v1/seo", Input: apicontrollers.GetSEOInput{}, Permissions: []string{mcpPermission}, }, { Name: "set_url_seo", Title: "Set the SEO of a URL", Description: "Changes the SEO values of a page addressed by URL. A record behind the URL gets the change in its SEO tab in the URL's locale; otherwise, or with force_rule, an exact URL rule is written. The answer says where it was written.", Guard: mcpGuard, Method: http.MethodPut, Path: "/_seo/api/v1/seo", Input: apicontrollers.SetSEOInput{}, Permissions: []string{mcpPermission}, }, // URL rules (D-02). { Name: "list_rules", Title: "List URL rules", Description: "Lists the URL rules (SEO for an address with or without a record behind it) by address, with a search text and the match kind.", Guard: mcpGuard, Method: http.MethodGet, Path: "/_seo/api/v1/rules", Input: apicontrollers.ListRulesInput{}, Permissions: []string{mcpPermission}, }, { Name: "show_rule", Title: "Show a URL rule", Description: "Shows one URL rule by id.", Guard: mcpGuard, Method: http.MethodGet, Path: "/_seo/api/v1/rules/{id}", Input: apicontrollers.RuleIDInput{}, Permissions: []string{mcpPermission}, }, { Name: "create_rule", Title: "Create a URL rule", Description: "Creates a URL rule: an exact address or a pattern where * matches any text, with the values it sets. A rule wins over the record's SEO tab.", Guard: mcpGuard, Method: http.MethodPost, Path: "/_seo/api/v1/rules", Input: apicontrollers.CreateRuleInput{}, Permissions: []string{mcpPermission}, }, { Name: "update_rule", Title: "Update a URL rule", Description: "Changes the fields sent of one URL rule by id.", Guard: mcpGuard, Method: http.MethodPut, Path: "/_seo/api/v1/rules/{id}", Input: apicontrollers.UpdateRuleInput{}, Permissions: []string{mcpPermission}, }, { Name: "delete_rule", Title: "Delete a URL rule", Description: "Deletes one URL rule by id; history keeps its values.", Guard: mcpGuard, Method: http.MethodDelete, Path: "/_seo/api/v1/rules/{id}", Input: apicontrollers.RuleIDInput{}, Permissions: []string{mcpPermission}, Destructive: &destructive, }, // Redirects (D-16 to D-19). { Name: "list_redirects", Title: "List redirects", Description: "Lists redirects, newest change first, with a search text and the status (301, 302, 410) and origin filters.", Guard: mcpGuard, Method: http.MethodGet, Path: "/_seo/api/v1/redirects", Input: apicontrollers.ListRedirectsInput{}, Permissions: []string{mcpPermission}, }, { Name: "show_redirect", Title: "Show a redirect", Description: "Shows one redirect by id.", Guard: mcpGuard, Method: http.MethodGet, Path: "/_seo/api/v1/redirects/{id}", Input: apicontrollers.RedirectIDInput{}, Permissions: []string{mcpPermission}, }, { Name: "create_redirect", Title: "Create a redirect", Description: "Creates a 301, 302 or 410 redirect from a path, a pattern or a regular expression. A redirect that would create a loop is refused with redirect_loop and the loop's path; a chain is saved with a warning.", Guard: mcpGuard, Method: http.MethodPost, Path: "/_seo/api/v1/redirects", Input: apicontrollers.CreateRedirectInput{}, Permissions: []string{mcpPermission}, }, { Name: "update_redirect", Title: "Update a redirect", Description: "Changes the fields sent of one redirect by id; a loop is refused like a create.", Guard: mcpGuard, Method: http.MethodPut, Path: "/_seo/api/v1/redirects/{id}", Input: apicontrollers.UpdateRedirectInput{}, Permissions: []string{mcpPermission}, }, { Name: "delete_redirect", Title: "Delete a redirect", Description: "Deletes one redirect by id; history keeps its values.", Guard: mcpGuard, Method: http.MethodDelete, Path: "/_seo/api/v1/redirects/{id}", Input: apicontrollers.RedirectIDInput{}, Permissions: []string{mcpPermission}, Destructive: &destructive, }, // 404 log (D-20). { Name: "list_not_found", Title: "List the 404 log", Description: "Lists the addresses that answered 404, most hits first, with whether a redirect answers them now (status open or resolved).", Guard: mcpGuard, Method: http.MethodGet, Path: "/_seo/api/v1/notfound", Input: apicontrollers.ListNotFoundInput{}, Permissions: []string{mcpPermission}, }, { Name: "redirect_not_found", Title: "Redirect a 404 address", Description: "Creates a 301 from a logged 404 address to a target. Refused when a rule already answers the address.", Guard: mcpGuard, Method: http.MethodPost, Path: "/_seo/api/v1/notfound/{id}/redirect", Input: apicontrollers.RedirectNotFoundInput{}, Permissions: []string{mcpPermission}, }, { Name: "gone_not_found", Title: "Mark a 404 address as gone", Description: "Creates a 410 for a logged 404 address, which tells search engines to drop it. Refused when a rule already answers the address.", Guard: mcpGuard, Method: http.MethodPost, Path: "/_seo/api/v1/notfound/{id}/gone", Input: apicontrollers.NotFoundIDInput{}, Permissions: []string{mcpPermission}, Destructive: &destructive, }, { Name: "delete_not_found", Title: "Remove a 404 log entry", Description: "Removes one entry from the 404 log; it comes back on its next 404.", Guard: mcpGuard, Method: http.MethodDelete, Path: "/_seo/api/v1/notfound/{id}", Input: apicontrollers.NotFoundIDInput{}, Permissions: []string{mcpPermission}, Destructive: &destructive, }, // robots.txt and AI bots (D-22, D-24, D-25, D-99). { Name: "show_robots", Title: "Show robots.txt", Description: "Shows the robots.txt rules, the AI bot switches, the file crawlers get in production and whether the site runs outside production (crawlers then get Disallow: /).", Guard: mcpGuard, Method: http.MethodGet, Path: "/_seo/api/v1/robots", Input: struct{}{}, Permissions: []string{mcpPermission}, }, { Name: "update_robots", Title: "Update robots.txt", Description: "Changes the robots.txt rules and the AI bot switches sent. The answer lists noindex addresses the new rules keep Googlebot from.", Guard: mcpGuard, Method: http.MethodPut, Path: "/_seo/api/v1/robots", Input: apicontrollers.UpdateRobotsInput{}, Permissions: []string{mcpPermission}, }, { Name: "test_robots", Title: "Test an address against robots.txt", Description: "Answers whether a crawler may fetch an address under the saved production robots.txt, with Google's matcher and the deciding line.", Guard: mcpGuard, Method: http.MethodGet, Path: "/_seo/api/v1/robots/test", Input: apicontrollers.TestRobotsInput{}, Permissions: []string{mcpPermission}, }, // Settings (D-03, D-05, D-07, D-20b, D-21, D-23, D-104). { Name: "show_settings", Title: "Show the SEO settings", Description: "Shows the SEO settings (templates, defaults, the query parameter list, indexing paths, the address form, verification) and the settings of every content type.", Guard: mcpGuard, Method: http.MethodGet, Path: "/_seo/api/v1/settings", Input: struct{}{}, Permissions: []string{mcpPermission}, }, { Name: "update_settings", Title: "Update the SEO settings", Description: "Changes the SEO settings sent and, under types, the settings of content types by key, with the checks of the settings screen.", Guard: mcpGuard, Method: http.MethodPut, Path: "/_seo/api/v1/settings", Input: apicontrollers.UpdateSettingsInput{}, Permissions: []string{mcpPermission}, }, // History (D-13). { Name: "list_history", Title: "List SEO history", Description: "Lists SEO changes, newest first, with author, time, via (admin, mcp, import, auto, undo), before and after values, filtered by via, kind or batch.", Guard: mcpGuard, Method: http.MethodGet, Path: "/_seo/api/v1/history", Input: apicontrollers.ListHistoryInput{}, Permissions: []string{mcpPermission}, }, { Name: "show_history", Title: "Show an SEO change", Description: "Shows one SEO change by id with its before and after values.", Guard: mcpGuard, Method: http.MethodGet, Path: "/_seo/api/v1/history/{id}", Input: apicontrollers.HistoryIDInput{}, Permissions: []string{mcpPermission}, }, // Audit (D-13, D-14 CMS part). { Name: "list_issues", Title: "List SEO issues", Description: "Lists the CMS-data SEO issues: missing and duplicate titles and descriptions, URL rules overriding a record, redirect chains, canonicals pointing to noindex or redirected addresses, and noindex addresses robots.txt blocks; each names the tool that fixes it.", Guard: mcpGuard, Method: http.MethodGet, Path: "/_seo/api/v1/issues", Input: apicontrollers.ListIssuesInput{}, Permissions: []string{mcpPermission}, }, }} }