@canonry/canonry 7.98.0 → 7.100.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/README.md +18 -16
  2. package/assets/agent-workspace/AGENTS.md +13 -6
  3. package/assets/agent-workspace/skills/aero/SKILL.md +45 -26
  4. package/assets/agent-workspace/skills/aero/references/agent-operations.md +47 -12
  5. package/assets/agent-workspace/skills/aero/references/memory-patterns.md +1 -1
  6. package/assets/agent-workspace/skills/aero/references/orchestration.md +9 -9
  7. package/assets/agent-workspace/skills/aero/references/reporting.md +8 -4
  8. package/assets/agent-workspace/skills/aero/references/seo-analysis.md +2 -2
  9. package/assets/agent-workspace/skills/aero/references/site-health.md +34 -23
  10. package/assets/agent-workspace/skills/aero/soul.md +2 -2
  11. package/assets/agent-workspace/skills/canonry/SKILL.md +37 -7
  12. package/assets/agent-workspace/skills/canonry/references/aeo-analysis.md +14 -11
  13. package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +122 -53
  14. package/assets/assets/AccessControls-DzO5Y8v9.js +2 -0
  15. package/assets/assets/AgentSetupPage-DWWovaCw.js +36 -0
  16. package/assets/assets/AuditHistoryPanel-BG-n1i8c.js +1 -0
  17. package/assets/assets/BacklinksPage-D6wdOMXt.js +1 -0
  18. package/assets/assets/ChartPrimitives-CtKdkn64.js +3 -0
  19. package/assets/assets/Hint-3TTi0MgX.js +1 -0
  20. package/assets/assets/{HistoryPage-DeN79d3c.js → HistoryPage-B_ReWHbL.js} +1 -1
  21. package/assets/assets/InfoTooltip-D29JcNMW.js +1 -0
  22. package/assets/assets/MeasurementPropertyPage-zdyLL-kl.js +4 -0
  23. package/assets/assets/ProjectPage-KZNKXR4w.js +15 -0
  24. package/assets/assets/RunsPage-DxN0xXQh.js +1 -0
  25. package/assets/assets/ServerTrafficSection-CvISj5pf.js +40 -0
  26. package/assets/assets/SettingsPage-CpRpBlMV.js +1 -0
  27. package/assets/assets/ToneBadge-DcwPruHr.js +60 -0
  28. package/assets/assets/TrafficPage-zk6zMZyz.js +1 -0
  29. package/assets/assets/TrafficSourceDetailPage-DJtsI06Z.js +1 -0
  30. package/assets/assets/{account-context-CdEHcI5S.js → account-context-CoJVqEXZ.js} +1 -1
  31. package/assets/assets/{agent-trust-copy-N6WacCSg.js → agent-trust-copy-BIXDMtBm.js} +1 -1
  32. package/assets/assets/{card-B1O0SunG.js → card-Dwmc7Srx.js} +1 -1
  33. package/assets/assets/index-fh1T5JQY.css +1 -0
  34. package/assets/assets/index-mqc2mWUR.js +42 -0
  35. package/assets/assets/query-client-Tg1fZu4i.js +1 -0
  36. package/assets/assets/react-query-BqcEEfEO.js +1 -0
  37. package/assets/assets/{react-sigma_core.esm.min-f4uuOgrw.js → react-sigma_core.esm.min-D1q0DR_j.js} +3 -3
  38. package/assets/assets/{server-traffic-CkSCFMnL.js → server-traffic-Djnh_9f0.js} +1 -1
  39. package/assets/assets/service-BQjBdN4O.js +1 -0
  40. package/assets/assets/use-tooltip-position-BOzm-6Wy.js +1 -0
  41. package/assets/assets/vendor-lucide-iE5MEh2-.js +1 -0
  42. package/assets/assets/{vendor-markdown-BDQ1GKGP.js → vendor-markdown-BBGbNklj.js} +1 -1
  43. package/assets/assets/{vendor-radix-BGYlvS2l.js → vendor-radix-DKCt5Z_h.js} +1 -1
  44. package/assets/assets/{vendor-recharts-DhEHcK3G.js → vendor-recharts-D3MLFU3q.js} +1 -1
  45. package/assets/assets/{vendor-tanstack-BNuZ37rE.js → vendor-tanstack-B90HW50P.js} +2 -2
  46. package/assets/index.html +16 -15
  47. package/dist/{ads-PQ4OP6OH.js → ads-FVPZ6R6Z.js} +3 -3
  48. package/dist/{agent-B6ZPL2HH.js → agent-2LPU2E5I.js} +7 -7
  49. package/dist/{agent-ask-ZUKNXRAX.js → agent-ask-5ODREK6D.js} +3 -3
  50. package/dist/{agent-conversations-DJ7WU7PL.js → agent-conversations-SNLOOJEM.js} +3 -3
  51. package/dist/{agent-journeys-LGUI3SQG.js → agent-journeys-XDXVL6PK.js} +3 -3
  52. package/dist/{agent-memory-PWZJ7G5Q.js → agent-memory-NKAI2S3U.js} +3 -3
  53. package/dist/{agent-providers-TEERDNJT.js → agent-providers-R5L7A72X.js} +3 -3
  54. package/dist/{agent-transcript-KDPOPK5Z.js → agent-transcript-C5WAGYVC.js} +3 -3
  55. package/dist/{analytics-NFW5RQRT.js → analytics-EJVOLIQL.js} +33 -13
  56. package/dist/{apply-EP4V4UF5.js → apply-I6JOM247.js} +3 -3
  57. package/dist/{backfill-6UTNNVFO.js → backfill-UVUR36IB.js} +10 -10
  58. package/dist/{backlinks-SG5GV5X5.js → backlinks-3VMVACWN.js} +3 -3
  59. package/dist/{bing-Q4W24JNC.js → bing-R5RL3PW2.js} +3 -3
  60. package/dist/{bootstrap-WEMERVNZ.js → bootstrap-GMMSDTNO.js} +12 -12
  61. package/dist/{cdp-3XKBJGHO.js → cdp-FJKUXHEY.js} +7 -7
  62. package/dist/{chunk-KK3Z34AN.js → chunk-2DV7F6XA.js} +91 -2
  63. package/dist/{chunk-MTW37GXF.js → chunk-2FWYWGIR.js} +2 -2
  64. package/dist/{chunk-Q5SNOMRB.js → chunk-56VVRWJM.js} +14 -5
  65. package/dist/{chunk-52M2JWCB.js → chunk-7BEGCVVB.js} +1 -1
  66. package/dist/{chunk-WZSDGC45.js → chunk-7BH53MOB.js} +27 -2
  67. package/dist/{chunk-IX5AC3QB.js → chunk-7J2RIIYU.js} +1450 -1067
  68. package/dist/{chunk-UXXZXXNG.js → chunk-7SNMIXEQ.js} +2 -2
  69. package/dist/{chunk-2XCYEBQV.js → chunk-AMGM55CP.js} +2 -2
  70. package/dist/{chunk-MSI4BGFN.js → chunk-AYKTVQF7.js} +13 -5
  71. package/dist/{chunk-3JWY65XO.js → chunk-BKDRT4VS.js} +7 -7
  72. package/dist/{chunk-FQ3L2TIX.js → chunk-COHSL6KW.js} +1 -1
  73. package/dist/{chunk-X3UXMHWC.js → chunk-DGDLLRS4.js} +1 -1
  74. package/dist/{chunk-YJITDEZR.js → chunk-DHIB7EIA.js} +4 -4
  75. package/dist/{chunk-BLW327AU.js → chunk-EE3QTCLS.js} +18 -6
  76. package/dist/{chunk-3GMBHGQ5.js → chunk-F46TBLXK.js} +204 -94
  77. package/dist/{chunk-RTH5JVC3.js → chunk-FBO25TA3.js} +1 -1
  78. package/dist/{chunk-2Q7JEC6N.js → chunk-FZ3MUTU3.js} +2 -2
  79. package/dist/{chunk-64R66MWZ.js → chunk-G6QN4VFS.js} +16 -10
  80. package/dist/{chunk-ISIJ2NS4.js → chunk-HBHLYWKE.js} +9 -6
  81. package/dist/{chunk-EJZ444VV.js → chunk-HL2LGRTI.js} +8 -6
  82. package/dist/chunk-J6536OL6.js +31 -0
  83. package/dist/{chunk-RLKI2QF7.js → chunk-KVRX7YIH.js} +20 -10
  84. package/dist/{chunk-3BA75QYU.js → chunk-LJO2BKWU.js} +1 -1
  85. package/dist/{chunk-CN6MVUY3.js → chunk-LNVFERI4.js} +1 -1
  86. package/dist/{chunk-ZADRESLB.js → chunk-NQYJHKML.js} +39 -7
  87. package/dist/{chunk-IAGC2MGP.js → chunk-O5UFAXUI.js} +646 -588
  88. package/dist/{chunk-RGFIRJ7F.js → chunk-O6APBEJE.js} +2 -2
  89. package/dist/{chunk-ZBTUISPG.js → chunk-O7S7OHLE.js} +9399 -8388
  90. package/dist/{chunk-ER5ZHAB2.js → chunk-QS5DWJDI.js} +2 -2
  91. package/dist/{chunk-QSL3FXE4.js → chunk-RBG2QXQM.js} +4 -4
  92. package/dist/{chunk-SAKH2RRF.js → chunk-SWZXHHAG.js} +16 -8
  93. package/dist/{chunk-VMGZBH5L.js → chunk-T7UDY7W3.js} +26 -11
  94. package/dist/{chunk-OL2L5ANJ.js → chunk-UGO2FO6V.js} +119 -55
  95. package/dist/{chunk-J6MYB3F4.js → chunk-VHULVUDL.js} +1 -1
  96. package/dist/{chunk-O22WSFWL.js → chunk-YGAQQSCL.js} +56339 -54966
  97. package/dist/{chunk-TNOYUE2L.js → chunk-YIIRS7V7.js} +98 -65
  98. package/dist/{chunk-64KB6YTG.js → chunk-YU2WX7RD.js} +3 -3
  99. package/dist/{citations-5OSQ3ZYU.js → citations-LOEQRDUB.js} +21 -10
  100. package/dist/{cli-catalog-T5OAVKGS.js → cli-catalog-5RXNUFBS.js} +3 -3
  101. package/dist/{cli-commands-VATCVJKW.js → cli-commands-HE2BQY3Y.js} +7 -7
  102. package/dist/cli.js +22 -17
  103. package/dist/{competitor-YIKTMTHY.js → competitor-PIX2BHJW.js} +3 -3
  104. package/dist/{content-DS2LKR7J.js → content-PJGW4WZF.js} +3 -3
  105. package/dist/{dashboard-HLVRRRI4.js → dashboard-7OKBD4MG.js} +6 -6
  106. package/dist/{demo-A5DTVJGK.js → demo-SCOFAWFM.js} +1 -1
  107. package/dist/{demo-server-P2JGAI6C.js → demo-server-SJPI6RSL.js} +38 -36
  108. package/dist/{discover-VNZDO2MU.js → discover-I3WL2QUN.js} +10 -8
  109. package/dist/{discover-eval-ON77LUEN.js → discover-eval-YRECOIP5.js} +3 -3
  110. package/dist/{doctor-7TNNTI7H.js → doctor-F4J6LILX.js} +3 -3
  111. package/dist/{evidence-E54CNGXS.js → evidence-MYQTCY4V.js} +25 -10
  112. package/dist/{export-cmd-XXZ6KLQQ.js → export-cmd-3SUFOJM6.js} +3 -3
  113. package/dist/{ga-ZQB4EJI3.js → ga-VA6FYK4L.js} +3 -3
  114. package/dist/{gbp-ZQL6NQEK.js → gbp-DI6ZVFHL.js} +3 -3
  115. package/dist/{google-7EIHQGSV.js → google-UVKWJCD2.js} +4 -4
  116. package/dist/{google-marketing-RSAO4PG7.js → google-marketing-S63HN733.js} +1 -1
  117. package/dist/{health-cmd-R7WPKGWX.js → health-cmd-DOZXGI46.js} +16 -9
  118. package/dist/{history-2CSWSVCY.js → history-UTJTUDYK.js} +3 -3
  119. package/dist/index.d.ts +204 -12
  120. package/dist/index.js +26 -26
  121. package/dist/{init-FXZRMXZ3.js → init-IVJSS33J.js} +19 -19
  122. package/dist/{insights-EJUL3W6D.js → insights-UHCVCZ76.js} +3 -3
  123. package/dist/intelligence-service-3EENJ5DS.js +16 -0
  124. package/dist/{journeys-YUMBANFH.js → journeys-XIT7WDM2.js} +3 -3
  125. package/dist/{keys-KLOTGT4H.js → keys-MQKW4JUI.js} +3 -3
  126. package/dist/{keyword-5NSJFEOI.js → keyword-EASMKYZ3.js} +3 -3
  127. package/dist/{logs-WW3RLCRG.js → logs-ZHZ6XM55.js} +3 -3
  128. package/dist/{mcp-NTBEIEVX.js → mcp-ECVT2YGU.js} +4 -4
  129. package/dist/mcp.js +10 -10
  130. package/dist/{measurement-plan-BLPAZEXS.js → measurement-plan-7FQKUOMR.js} +5 -5
  131. package/dist/{notify-KAGE6UEN.js → notify-TC7ARC6W.js} +3 -3
  132. package/dist/{organic-evidence-HTYRXRML.js → organic-evidence-M34MWJXE.js} +7 -4
  133. package/dist/overview-P6BRMXJN.js +314 -0
  134. package/dist/{project-NYUWICVC.js → project-WZ2YXFPJ.js} +4 -4
  135. package/dist/project-setup-WV6SPGIV.js +176 -0
  136. package/dist/{query-3CRRDOHD.js → query-WAFJKDHG.js} +3 -3
  137. package/dist/{research-ZULVD3TW.js → research-B5ZPQX7R.js} +3 -3
  138. package/dist/{results-export-STM7SQ4J.js → results-export-NIZV6R3K.js} +3 -3
  139. package/dist/{run-S4MFU4MK.js → run-ICLPZ7QT.js} +7 -4
  140. package/dist/{schedule-6W3Q2FUL.js → schedule-4C44LQ7R.js} +22 -3
  141. package/dist/{search-EKXXN7C4.js → search-UJM7KII3.js} +11 -4
  142. package/dist/{serve-TFBFPFAQ.js → serve-A6UIO6WP.js} +30 -29
  143. package/dist/{session-4B5V3AH6.js → session-RTE22GQT.js} +14 -14
  144. package/dist/settings-BOF5Z7ML.js +211 -0
  145. package/dist/{sitemaps-R7XFCH6E.js → sitemaps-BM7S76H2.js} +4 -4
  146. package/dist/{skills-44XYCTVD.js → skills-X5SR4HRO.js} +2 -2
  147. package/dist/{snapshot-ROAOJI4W.js → snapshot-KLKE37VY.js} +4 -4
  148. package/dist/{src-ZJRIKEDB.js → src-EKLG5A6O.js} +4 -2
  149. package/dist/{status-EN3A2TX5.js → status-OYG57DWU.js} +6 -5
  150. package/dist/{technical-aeo-ZV466F65.js → technical-aeo-KWVWOOTI.js} +23 -23
  151. package/dist/{telemetry-EZHPNZ2A.js → telemetry-KGE6FF3Y.js} +4 -4
  152. package/dist/{tools-IH4M7AAG.js → tools-4R33AZQ3.js} +11 -11
  153. package/dist/{traffic-VFLXWB3Z.js → traffic-SVMOKCSS.js} +7 -11
  154. package/dist/{trends-ZXJIX3Z3.js → trends-RGAKGX3L.js} +4 -4
  155. package/dist/{users-J2BYEWOE.js → users-47WKA2TO.js} +3 -3
  156. package/dist/{visibility-stats-AJ7NY2BP.js → visibility-stats-DTGQJPNV.js} +9 -5
  157. package/dist/{wordpress-U6MS35VE.js → wordpress-2CNUX4UE.js} +3 -3
  158. package/package.json +2 -2
  159. package/assets/assets/AgentSetupPage-h1kJhy9q.js +0 -18
  160. package/assets/assets/AuditHistoryPanel-CNUApNiJ.js +0 -1
  161. package/assets/assets/BacklinksPage-CpKmlAek.js +0 -1
  162. package/assets/assets/ChartPrimitives-CvK6CQrj.js +0 -1
  163. package/assets/assets/Hint-c4a4W87X.js +0 -1
  164. package/assets/assets/InfoTooltip-Drnst4ML.js +0 -1
  165. package/assets/assets/MeasurementPropertyPage-CcHnYn81.js +0 -4
  166. package/assets/assets/ProjectPage-Tmuqmust.js +0 -11
  167. package/assets/assets/RunsPage-BD4k3MjX.js +0 -1
  168. package/assets/assets/SettingsPage-BHy30JP5.js +0 -1
  169. package/assets/assets/SiteHealthSection-SYdtuGjq.js +0 -2
  170. package/assets/assets/ToneBadge-Cii5KNtg.js +0 -60
  171. package/assets/assets/TrafficPage-DuxtRqnc.js +0 -40
  172. package/assets/assets/TrafficSourceDetailPage-DiX1bB02.js +0 -1
  173. package/assets/assets/format-helpers-V8Pyc7cR.js +0 -3
  174. package/assets/assets/index-BAxHW-1G.css +0 -1
  175. package/assets/assets/index-BTz-B9hV.js +0 -60
  176. package/assets/assets/query-client-C1ycmW1c.js +0 -1
  177. package/assets/assets/react-query-DI7VfOND.js +0 -1
  178. package/assets/assets/service-DSgXWhNq.js +0 -1
  179. package/assets/assets/vendor-lucide-DuOM7wVi.js +0 -1
  180. package/dist/intelligence-service-TKK7O3Z5.js +0 -16
  181. package/dist/overview-GSJ4GP2T.js +0 -213
  182. package/dist/settings-VRTDPFR3.js +0 -119
@@ -2,11 +2,11 @@ import {
2
2
  dedupeGscSitemapUrls,
3
3
  resolveDiscoveredGscSitemapUrls,
4
4
  submitGscSitemapBatches
5
- } from "./chunk-X3UXMHWC.js";
5
+ } from "./chunk-DGDLLRS4.js";
6
6
  import {
7
7
  measurementDraftOperationSchema,
8
8
  runMeasurementDraftAction
9
- } from "./chunk-52M2JWCB.js";
9
+ } from "./chunk-7BEGCVVB.js";
10
10
  import {
11
11
  CliError
12
12
  } from "./chunk-HGMYEDAQ.js";
@@ -108,9 +108,14 @@ import {
108
108
  projectConfigSchema,
109
109
  projectPatchRequestSchema,
110
110
  projectUpsertRequestSchema,
111
+ providerConnectionSettingsDtoSchema,
112
+ providerConnectionTestResultDtoSchema,
113
+ providerDisconnectRequestSchema,
111
114
  providerQuotaPolicySchema,
112
115
  providerReloadRequestSchema,
113
116
  providerReloadResponseDtoSchema,
117
+ providerSettingsResetSchema,
118
+ providerSettingsUpdateRequestSchema,
114
119
  providerSummaryEntryDtoSchema,
115
120
  queryBatchRequestSchema,
116
121
  queryClassSchema,
@@ -127,6 +132,8 @@ import {
127
132
  runTriggerRequestSchema,
128
133
  schedulableRunKindSchema,
129
134
  scheduleDtoSchema,
135
+ schedulePreviewDtoSchema,
136
+ schedulePreviewRequestSchema,
130
137
  scheduleUpsertRequestSchema,
131
138
  sentimentBackfillPreviewReadSchema,
132
139
  sentimentBackfillRequestSchema,
@@ -188,7 +195,7 @@ import {
188
195
  trendSurfaceSchema,
189
196
  visibilityCompareSelectionSchema,
190
197
  visibilityReportRequestSchema
191
- } from "./chunk-ZBTUISPG.js";
198
+ } from "./chunk-O7S7OHLE.js";
192
199
 
193
200
  // src/mcp/tool-registry.ts
194
201
  import { z as z2 } from "zod";
@@ -1034,7 +1041,7 @@ var technicalAeoTrendInputSchema = z2.object({
1034
1041
  });
1035
1042
  var trendsInputSchema = z2.object({
1036
1043
  project: projectNameSchema,
1037
- surface: trendSurfaceSchema.describe("Which card: index-coverage (Google and Bing indexed pages by day), site-health (site score and pages checked per scan), backlinks (referring domains, linking hosts and top-10 concentration per Common Crawl release, crawler and proxy hosts left out)."),
1044
+ surface: trendSurfaceSchema.describe("Which card: index-coverage (Google and Bing indexed pages by day), site-health (Agent Readiness score and pages checked per scan), backlinks (referring domains, linking hosts and top-10 concentration per Common Crawl release, crawler and proxy hosts left out)."),
1038
1045
  window: metricsWindowSchema.optional().describe("Window ending on the latest reading. Defaults to 90d for index-coverage and all otherwise. Leave it out when you pass startDate or endDate."),
1039
1046
  startDate: calendarDateSchema.optional().describe("First calendar day (YYYY-MM-DD) of your own range instead of a window."),
1040
1047
  endDate: calendarDateSchema.optional().describe("Last calendar day (YYYY-MM-DD) of your own range instead of a window.")
@@ -1053,12 +1060,12 @@ var siteHealthIssuesInputSchema = siteAuditIssueListQuerySchema.extend({
1053
1060
  cursor: siteAuditIssueListQuerySchema.shape.cursor.describe("Opaque nextCursor from this same scan and issue feed.")
1054
1061
  });
1055
1062
  var siteHealthIssuePagesInputSchema = siteHealthIssuesInputSchema.extend({
1056
- issueId: z2.string().min(1).describe("Exact issue ID from canonry_site_health_issues. Keep the returned runId when inspecting affected pages.")
1063
+ issueId: z2.string().min(1).describe("Exact issue ID from canonry_agent_readiness_issues. Keep the returned runId when inspecting affected pages.")
1057
1064
  });
1058
1065
  var siteHealthPageAuditInputSchema = z2.object({
1059
1066
  project: projectNameSchema,
1060
1067
  runId: crawlRunIdSchema,
1061
- nodeKey: z2.string().min(1).optional().describe("Exact crawl node key, as returned by Site Health page or subgraph reads."),
1068
+ nodeKey: z2.string().min(1).optional().describe("Exact crawl node key, as returned by Agent Readiness page or subgraph reads."),
1062
1069
  url: z2.string().url().optional().describe("Exact page URL. Use this only when a crawl node key is unavailable.")
1063
1070
  }).refine((value) => Boolean(value.nodeKey || value.url), {
1064
1071
  message: "Provide nodeKey or url.",
@@ -1105,7 +1112,7 @@ var siteHealthChangesInputSchema = z2.object({
1105
1112
  toRunId: runIdSchema.optional().describe("Later complete crawl run ID. Omit to compare the latest complete crawl."),
1106
1113
  scope: z2.enum(["all", "pages", "links"]).optional().describe("Limit the diff to page or link changes. Omit or use all for both."),
1107
1114
  change: z2.enum(["all", "added", "removed", "changed"]).optional().describe("Limit the diff to one change kind. Omit or use all for every kind."),
1108
- cursor: z2.string().min(1).optional().describe("Opaque cursor from the previous Site Health changes result."),
1115
+ cursor: z2.string().min(1).optional().describe("Opaque cursor from the previous Agent Readiness changes result."),
1109
1116
  limit: z2.number().int().positive().max(25).default(25).describe("Hard MCP cap: 25 records, because each change carries before and after DTOs.")
1110
1117
  });
1111
1118
  var technicalAeoCrawlPagesInputSchema = z2.object({
@@ -1719,7 +1726,7 @@ var rawCanonryMcpTools = [
1719
1726
  defineTool({
1720
1727
  name: "canonry_project_overview",
1721
1728
  title: "Get project overview (composite)",
1722
- description: `Sentiment headline is sentiment.branded; nonBrand is a separate exception population. pooledOverall and deprecated overall are explicitly pooled compatibility figures and must never be reported as a class-specific headline. One-call summary for "how is project X doing?". Returns independent mention and citation coverage, separate query-level movement for each signal, query-basket comparability with added/removed counts, latest run and health, insights, provider/model breakdowns, competitors, attention items, and recent history. Movement excludes queries not shared by both sweeps. Filterable by location and time window. Prefer this over fanning out to separate read tools for the same question. queryClassScope says which figures pool branded and non-brand: the coverage, scores (except scores.mentionShare) and movement count queries across both classes, so never report them as one class or as answers. latestRun.admission describes the scheduled sweep; latestRun.manualAdmission describes a default full manual sweep. Each says whether its provider scope would be refused or skip providers that keep failing on their accounts. They can differ when the schedule names fewer providers; use manualAdmission before a default manual sweep. The latest run's status and health are not a completeness check: for expected, executed and missing answers read canonry_measurement_data_quality or, for a plan run, canonry_run_completeness. canonry_doctor checks configuration and integrations, not sweeps. SCOPE LIMIT: this returns nothing about Advanced Measurement: no plan, Targets, Properties, groups, or segments. Its silence is not evidence that a project lacks them. When the system prompt has no Project shape line, call canonry_measurement_plan_get before stating that a project has no Properties, no Advanced plan, or cannot break out per-Property performance; use canonry_measurement_portfolio_summary to rank Properties.`,
1729
+ description: 'One-call project summary with latest run, health, insights and movement. whatChanged is the dashboard\'s "What changed": queries that lost a mention and queries that lost a citation in the latest check (each query once, mentions and citations counted apart, with engines, locations and Advanced Properties), runs in progress, and the rows the dashboard lists; comparison says when nothing could be compared. mentionCoverage preserves independent branded, non-brand and unknown answer populations with frozen Simple or Advanced selection; default headlines use non-brand. queryClassScope names legacy pooled fields, including scores.mention: never use those as class-specific coverage or as a fallback. Sentiment headline is sentiment.branded; non-brand exceptions remain separate. Read canonry_visibility_report for Property, group and market detail, canonry_run_preview for the next full manual sweep workload and admission, and canonry_run_completeness or canonry_measurement_data_quality for saved-run completeness. Run status and health are not a completeness check; canonry_doctor checks configuration and integrations, not sweeps. When the system prompt has no Project shape line, call canonry_measurement_plan_get before inferring the absence of an Advanced plan or Properties. Cited figures leave out answers whose engine returns no sources: `citationNotMeasured` / `queryCounts.citationNotMeasuredQueries` count them, and a cited rate with none measured is null, never 0. Filterable by location and time window.',
1723
1730
  access: "read",
1724
1731
  tier: "core",
1725
1732
  inputSchema: z2.object({
@@ -1751,7 +1758,7 @@ var rawCanonryMcpTools = [
1751
1758
  defineTool({
1752
1759
  name: "canonry_analytics_metrics",
1753
1760
  title: "Get citation & mention trend",
1754
- description: "Citation and mention rates over time for a project, bucketed adaptively (daily \u2192 monthly by span) and probe-excluded. Returns overall + per-provider window aggregates AND a per-bucket `byProvider` breakdown so you can read how each engine's cited/mentioned rate moved run-over-run \u2014 the same data the dashboard's \"Citations & mentions over time\" chart plots. Includes trend direction (improving/declining/stable) for both signals and query-set-change annotations. Filter the range with `window` (7d/30d/90d/all). Without `queryClass` every rate pools branded and non-brand answers, where branded queries inflate your own mentions; set `queryClass` non-brand for the competitive read and branded for brand recall, as two calls.",
1761
+ description: "Citation and mention rates over time for a project, bucketed adaptively (daily \u2192 monthly by span) and probe-excluded. Returns overall + per-provider window aggregates AND a per-bucket `byProvider` breakdown so you can read how each engine's cited/mentioned rate moved run-over-run \u2014 the same data the dashboard's \"Citations & mentions over time\" chart plots. Includes trend direction (improving/declining/stable) for both signals and query-set-change annotations. Citation rates leave out answers whose engine returns no sources (`citationNotMeasured`); a citation rate with no measured answer is null, not 0. Filter the range with `window` (7d/30d/90d/all). Without `queryClass` every rate pools branded and non-brand answers, where branded queries inflate your own mentions; set `queryClass` non-brand for the competitive read and branded for brand recall, as two calls.",
1755
1762
  access: "read",
1756
1763
  tier: "monitoring",
1757
1764
  inputSchema: z2.object({
@@ -1766,7 +1773,7 @@ var rawCanonryMcpTools = [
1766
1773
  defineTool({
1767
1774
  name: "canonry_analytics_sources",
1768
1775
  title: "Get cited-source rankings",
1769
- description: "Where AI engines cite from for a project: cited domains ranked by how many answers cite them, each tagged with a category and a surface class (own / direct-competitor / ota-aggregator / editorial-media / other), plus a surface-class roll-up and a per-provider breakdown. Every entry carries rank, its position by count in that list over the whole scope (equal counts share a rank); state where a domain places only from its rank, never by counting rows. Project-wide: without `queryClass` it pools branded and non-brand answers, where branded queries inflate your own domain. With `queryClass` set and neither `runId` nor `window`, this tool reads the latest sweep (`runId` latest); pass `window` to pool every sweep in it. `pooledAcrossRuns` true (`runCount` above 1) means the counts sum several runs and `runIds` is their scope; the legacy `runId` field is then only the newest run in the window. On a v2 measurement plan the class comes from the plan, the same answers as canonry_competitor_landscape with scope=all-markets. `countUnits` says what each count counts: `domainTotal` is distinct domains, never answers or citations. Compare engines by answer count or `answerShare`, never by rank position. Counts come from each answer's stored source list, so every engine is included, Gemini too. A domain counts at most once per answer; `answerShare` is the share of all answers in scope that cite it. `providersWithoutSources` names engines that answered but cited nothing. `limit` caps each ranked list (default 10 for this tool, which keeps each engine list whole); a long-tail rollup keeps the totals. The per-query breakdown is omitted unless `includeByQuery` is true. No LLM calls; probe runs excluded.",
1776
+ description: "Where AI engines cite from for a project: cited domains ranked by how many answers cite them, each tagged with a category and a surface class (own / direct-competitor / ota-aggregator / editorial-media / other), plus a surface-class roll-up and a per-provider breakdown. Every entry carries rank, its position by count in that list over the whole scope (equal counts share a rank); state where a domain places only from its rank, never by counting rows. Project-wide: without `queryClass` it pools branded and non-brand answers, where branded queries inflate your own domain. With `queryClass` set and neither `runId` nor `window`, this tool reads the latest sweep (`runId` latest); pass `window` to pool every sweep in it. `pooledAcrossRuns` true (`runCount` above 1) means the counts sum several runs and `runIds` is their scope; the legacy `runId` field is then only the newest run in the window. On a v2 measurement plan the class comes from the plan, the same answers as canonry_competitor_landscape with scope=all-markets. `countUnits` says what each count counts: `domainTotal` is distinct domains, never answers or citations. Compare engines by answer count or `answerShare`, never by rank position. Counts come from each answer's stored source list, so every engine is included, Gemini too. A domain counts at most once per answer; `answerShare` is the share of the answers in scope whose sources were checked that cite it. `providersWithoutSources` names engines whose checked answers cited nothing. An engine that returns no sources at all (a local model) is in `providersCitationNotMeasured` instead, and its answers are outside every count (`citationNotMeasuredAnswers`). `limit` caps each ranked list (default 10 for this tool, which keeps each engine list whole); a long-tail rollup keeps the totals. The per-query breakdown is omitted unless `includeByQuery` is true. No LLM calls; probe runs excluded.",
1770
1777
  access: "read",
1771
1778
  tier: "monitoring",
1772
1779
  inputSchema: z2.object({
@@ -1834,7 +1841,7 @@ var rawCanonryMcpTools = [
1834
1841
  defineTool({
1835
1842
  name: "canonry_search",
1836
1843
  title: "Search project (composite)",
1837
- description: "Search query snapshots and intelligence insights for the given text. Looks at snapshot answer text, cited domains, raw provider responses, and insight title/query/recommendation/cause. Returns ranked hits with snippets \u2014 use it instead of paginating snapshots when you need to find a competitor mention or term.",
1844
+ description: "Search query snapshots and intelligence insights for the given text. Looks at snapshot answer text, cited domains, raw provider responses, and insight title/query/recommendation/cause. Returns ranked hits with snippets \u2014 use it instead of paginating snapshots when you need to find a competitor mention or term. A snapshot hit's `citationState: not-measured` means its engine returns no sources.",
1838
1845
  access: "read",
1839
1846
  tier: "core",
1840
1847
  inputSchema: z2.object({
@@ -1883,7 +1890,7 @@ var rawCanonryMcpTools = [
1883
1890
  defineTool({
1884
1891
  name: "canonry_results_clear",
1885
1892
  title: "Preview or clear saved results",
1886
- description: "Clear only explicitly selected visibility runs and research batches. Preview is the default; back up evidence and set confirm=true to delete. Refuses active work and other run kinds. Preserves queries, plans, schedules, Site Health, backlinks, usage, and the audit trail.",
1893
+ description: "Clear only explicitly selected visibility runs and research batches. Preview is the default; back up evidence and set confirm=true to delete. Refuses active work and other run kinds. Preserves queries, plans, schedules, Agent Readiness, backlinks, usage, and the audit trail.",
1887
1894
  access: "write",
1888
1895
  tier: "monitoring",
1889
1896
  inputSchema: resultsClearRequestSchema.safeExtend({ project: projectNameSchema }),
@@ -1935,6 +1942,17 @@ var rawCanonryMcpTools = [
1935
1942
  openApiOperations: ["GET /api/v1/projects/{name}/runs"],
1936
1943
  handler: (client, input) => client.listRuns(input.project, input.limit, input.kind, input.status, input.excludeKind, input.excludeKinds, input.since)
1937
1944
  }),
1945
+ defineTool({
1946
+ name: "canonry_run_preview",
1947
+ title: "Preview the next manual sweep",
1948
+ description: "Preview the default full manual sweep without spending or writing. Returns frozen Advanced revision or Simple saved defaults, separate query-class and assignment counts, engines/models, locations, planned answers, runnable requests, and provider holds. requestCount excludes unavailable and held engines; expectedRequestCount includes their planned slots. Does not preview scoped, forced, or all-location launch overrides and does not reserve work. Use before canonry_run_trigger with the default request.",
1949
+ access: "read",
1950
+ tier: "monitoring",
1951
+ inputSchema: projectInputSchema,
1952
+ annotations: readAnnotations(),
1953
+ openApiOperations: ["GET /api/v1/projects/{name}/run-preview"],
1954
+ handler: (client, input) => client.previewRun(input.project)
1955
+ }),
1938
1956
  defineTool({
1939
1957
  name: "canonry_runs_latest",
1940
1958
  title: "Get latest project run",
@@ -1949,7 +1967,7 @@ var rawCanonryMcpTools = [
1949
1967
  defineTool({
1950
1968
  name: "canonry_run_get",
1951
1969
  title: "Get run",
1952
- description: "Get a Canonry run with its snapshots. skippedProviders records the providers this run did not call because they kept failing on their accounts; error.providers marks their entries skipped. This is a stored run, not the next sweep's admission: read canonry_runs_latest for scheduled admission and default full-sweep manualAdmission, which can differ when a schedule names fewer providers.",
1970
+ description: "Get a Canonry run with its snapshots. skippedProviders records the providers this run did not call because they kept failing on their accounts; error.providers marks their entries skipped. This is a stored run, not the next sweep's admission: read canonry_runs_latest for scheduled admission and default full-sweep manualAdmission, which can differ when a schedule names fewer providers. `citationState: not-measured` means the engine returns no sources (a local model), so whether it cites the project was never observed; it is never a miss. queryCounts.citationNotMeasuredQueries counts queries no answer measured. queryCountsByClass splits queryCounts into nonBrand and branded, each its own denominator: lead with nonBrand, and never add the two together. While a run is queued or running, providerFailures lists each engine failing so far (first reason, failed queries, and whether the run stopped calling it).",
1953
1971
  access: "read",
1954
1972
  tier: "monitoring",
1955
1973
  inputSchema: runGetInputSchema,
@@ -1985,7 +2003,7 @@ var rawCanonryMcpTools = [
1985
2003
  defineTool({
1986
2004
  name: "canonry_timeline_get",
1987
2005
  title: "Get project timeline",
1988
- description: "Get per-query citation history for a Canonry project.",
2006
+ description: "Get per-query citation history for a Canonry project. Each run's state combines its answers: cited when any answer cites the project, `not-measured` only when no answer carries sources (the engine returns none). A `not-measured` run has transition `not-measured`; lost/emerging compare measured runs only.",
1989
2007
  access: "read",
1990
2008
  tier: "monitoring",
1991
2009
  inputSchema: timelineInputSchema,
@@ -1996,7 +2014,7 @@ var rawCanonryMcpTools = [
1996
2014
  defineTool({
1997
2015
  name: "canonry_snapshots_list",
1998
2016
  title: "List query snapshots",
1999
- description: "List paginated query snapshots for a Canonry project.",
2017
+ description: "List paginated query snapshots for a Canonry project. `citationState: not-measured` means the engine returns no sources (a local model), so whether it cites the project was never observed; it is never a miss.",
2000
2018
  access: "read",
2001
2019
  tier: "monitoring",
2002
2020
  inputSchema: snapshotsListInputSchema,
@@ -2011,7 +2029,7 @@ var rawCanonryMcpTools = [
2011
2029
  defineTool({
2012
2030
  name: "canonry_snapshots_diff",
2013
2031
  title: "Diff snapshots",
2014
- description: "Compare query snapshot states between two Canonry runs.",
2032
+ description: "Compare query snapshot states between two Canonry runs. A query's run state is `not-measured` only when none of its answers carries sources; `changed` is never true for a `not-measured` side, since nothing observed a change.",
2015
2033
  access: "read",
2016
2034
  tier: "monitoring",
2017
2035
  inputSchema: snapshotsDiffInputSchema,
@@ -2044,7 +2062,7 @@ var rawCanonryMcpTools = [
2044
2062
  defineTool({
2045
2063
  name: "canonry_health_latest",
2046
2064
  title: "Get latest health",
2047
- description: 'Get the latest health snapshot for a Canonry project. Always returns a snapshot once the project exists: real data carries `status: "ready"`; newly-created projects (or projects with only failed runs) carry `status: "no-data"` with `reason: "no-runs-yet"` and zeroed metrics.',
2065
+ description: 'Get the latest health snapshot for a Canonry project. Always returns a snapshot once the project exists: real data carries `status: "ready"`; newly-created projects (or projects with only failed runs) carry `status: "no-data"` with `reason: "no-runs-yet"` and zeroed metrics. Cited rates are out of the pairs whose sources were checked (`totalPairs` minus `citationNotMeasuredPairs`, answers of an engine that returns no sources); null when none was.',
2048
2066
  access: "read",
2049
2067
  tier: "monitoring",
2050
2068
  inputSchema: projectInputSchema,
@@ -2066,7 +2084,7 @@ var rawCanonryMcpTools = [
2066
2084
  defineTool({
2067
2085
  name: "canonry_citations_visibility",
2068
2086
  title: "Get citation visibility",
2069
- description: 'Single-call AI citation surface for a Canonry project. Returns the project headline (cited by N of M engines), per-query engine coverage rows from the latest snapshot per (query \xD7 provider), and a competitor-gap list (queries where a configured competitor is cited but the project is not). Carries `status: "no-data"` with `reason: "no-queries"` or `"no-runs-yet"` when inputs are missing.',
2087
+ description: 'Single-call AI citation surface for a Canonry project. Returns the project headline (cited by N of M engines; `providersCitationNotMeasured` engines return no sources and are out of M), per-query engine coverage rows from the latest snapshot per (query \xD7 provider) where `citationState: not-measured` with `cited: null` is never a miss, and a competitor-gap list (queries where a configured competitor is cited but the project is not). `queriesCitationNotMeasured` counts queries no answer measured; they are in no other bucket. Carries `status: "no-data"` with `reason: "no-queries"` or `"no-runs-yet"` when inputs are missing.',
2070
2088
  access: "read",
2071
2089
  tier: "monitoring",
2072
2090
  inputSchema: projectInputSchema,
@@ -2077,7 +2095,7 @@ var rawCanonryMcpTools = [
2077
2095
  defineTool({
2078
2096
  name: "canonry_visibility_stats",
2079
2097
  title: "Get aggregated mention/citation stats",
2080
- description: 'Per-query mention (answer-text) and citation (source-list) counts WITH a sample size, pooled across many answer-visibility runs (probe-excluded) \u2014 the data to compute a confidence-aware (Wilson) proportion or detect drift without fetching every run. Tri-state aware: `checked` (the n for the mention proportion) counts only snapshots where answerMentioned was recorded; `null` ("not checked") is excluded, never counted as not-mentioned. Returns per-query `total`/`checked`/`mentioned`/`cited` + derived `mentionRate` (mentioned/checked) and `citedRate` (cited/total), `firstObserved`/`lastObserved`, and pooled `totals`. Window with `since`/`until` (ISO), `lastRuns`, or `month=YYYY-MM` (mutually exclusive); with none set, EVERY completed/partial run is pooled (`window.runCount` says how many) \u2014 pass `lastRuns` for a recent sample. Set `groupBy=provider` for a per-provider breakdown whose counts sum to the pooled counts (`groupBy` is omitted from the response otherwise). Set `shareOfVoice=true` for brand-mention share with explicit basis, availability, and reason. Tracked competitors are exclusive when configured; otherwise 3 stored direct competitors must each have 3 answer mentions. Raw names and platforms are excluded. Advanced portfolios use frozen assignments across all markets; Simple sites use the same attributed snapshot set \u2014 scoped to NON-BRAND queries by default, because a branded query names the project (it is mentioned on nearly all of them and a competitor cannot be), so a pooled figure reports brand recall as category placement. Pass `queryClass="branded"` for the recall figure; the response echoes which class it served.',
2098
+ description: 'Per-query mention (answer-text) and citation (source-list) counts WITH a sample size, pooled across many answer-visibility runs (probe-excluded) \u2014 the data to compute a confidence-aware (Wilson) proportion or detect drift without fetching every run. Tri-state aware: `checked` (the n for the mention proportion) counts only snapshots where answerMentioned was recorded; `null` ("not checked") is excluded, never counted as not-mentioned. Returns per-query `total`/`checked`/`mentioned`/`cited` + derived `mentionRate` (mentioned/checked) and `citedRate` (cited over the answers whose sources were checked: `total` minus `citationNotMeasured`, the answers of an engine that returns no sources; null when none), `firstObserved`/`lastObserved`, and pooled `totals`. Window with `since`/`until` (ISO), `lastRuns`, or `month=YYYY-MM` (mutually exclusive); with none set, EVERY completed/partial run is pooled (`window.runCount` says how many) \u2014 pass `lastRuns` for a recent sample. Set `groupBy=provider` for a per-provider breakdown whose counts sum to the pooled counts (`groupBy` is omitted from the response otherwise). Set `shareOfVoice=true` for brand-mention share with explicit basis, availability, and reason. Tracked competitors are exclusive when configured; otherwise 3 stored direct competitors must each have 3 answer mentions. Raw names and platforms are excluded. Advanced portfolios use frozen assignments across all markets; Simple sites use the same attributed snapshot set \u2014 scoped to NON-BRAND queries by default, because a branded query names the project (it is mentioned on nearly all of them and a competitor cannot be), so a pooled figure reports brand recall as category placement. Pass `queryClass="branded"` for the recall figure; the response echoes which class it served.',
2081
2099
  access: "read",
2082
2100
  tier: "monitoring",
2083
2101
  inputSchema: z2.object({
@@ -2105,7 +2123,7 @@ var rawCanonryMcpTools = [
2105
2123
  defineTool({
2106
2124
  name: "canonry_visibility_compare",
2107
2125
  title: "Compare AEO visibility month over month",
2108
- description: "Statistically honest month-over-month AEO comparison in ONE call \u2014 use this instead of hand-computing deltas from two visibility-stats calls. Share of voice (`mention-share-of-voice`, `driftRobust: true`) is less exposed to broad model-wide naming propensity than absolute rates, but it never overrides model continuity. Branded and non-brand mention/cited rates are separate additive metrics; classification-unavailable never falls back to pooling. provider and location narrow every frame; scope, scopeKey and marketKey answer from the frozen Advanced frame alone (refused when a month holds unreconstructable schema-v1 runs) and deduplicate shared executions. Without scope/marketKey, Advanced class metrics use classComparison for their basket and continuity while the four original metrics keep the project frame. On frozen frames, answers with incomplete source capture leave every citation figure (excludedUnknown). The response restricts to common query/provider pairs, then includes only providers with exactly one known, identical configured model id in both months. `continuity` surfaces every provider, its model evidence, and whether it was excluded for a changed, mixed mid-month, or unknown model. When no provider remains, metrics return `model-discontinuous` or `model-unknown`, never a directional call. A silent upstream version bump under an unchanged configured id remains undetectable. `from` must be a month strictly before `to`.",
2126
+ description: "Statistically honest month-over-month AEO comparison in ONE call \u2014 use this instead of hand-computing deltas from two visibility-stats calls. Share of voice (`mention-share-of-voice`, `driftRobust: true`) is less exposed to broad model-wide naming propensity than absolute rates, but it never overrides model continuity. Branded and non-brand mention/cited rates are separate additive metrics; classification-unavailable never falls back to pooling. provider and location narrow every frame; scope, scopeKey and marketKey answer from the frozen Advanced frame alone (refused when a month holds unreconstructable schema-v1 runs) and deduplicate shared executions. Without scope/marketKey, Advanced class metrics use classComparison for their basket and continuity while the four original metrics keep the project frame. On frozen frames, answers with incomplete source capture leave every citation figure (excludedUnknown). Answers from an engine that returns no sources (a local model) leave every citation figure in every frame and are counted apart (excludedNotMeasured), never as a miss or as unknown capture. The response restricts to common query/provider pairs, then includes only providers with exactly one known, identical configured model id in both months. `continuity` surfaces every provider, its model evidence, and whether it was excluded for a changed, mixed mid-month, or unknown model. When no provider remains, metrics return `model-discontinuous` or `model-unknown`, never a directional call. A silent upstream version bump under an unchanged configured id remains undetectable. `from` must be a month strictly before `to`.",
2109
2127
  access: "read",
2110
2128
  tier: "monitoring",
2111
2129
  inputSchema: z2.object({
@@ -2255,6 +2273,18 @@ var rawCanonryMcpTools = [
2255
2273
  openApiOperations: ["GET /api/v1/projects/{name}/competitors"],
2256
2274
  handler: (client, input) => client.listCompetitors(input.project)
2257
2275
  }),
2276
+ defineTool({
2277
+ name: "canonry_schedule_preview",
2278
+ title: "Preview schedule timing",
2279
+ description: "Calculate the next occurrence for proposed timing and timezone. Does not save a schedule, enable recurrence, or call a provider.",
2280
+ access: "read",
2281
+ tier: "setup",
2282
+ inputSchema: projectInputSchema.extend({ timing: schedulePreviewRequestSchema }),
2283
+ outputSchema: schedulePreviewDtoSchema,
2284
+ annotations: readAnnotations(),
2285
+ openApiOperations: ["POST /api/v1/projects/{name}/schedule/preview"],
2286
+ handler: (client, input) => client.previewSchedule(input.project, input.timing)
2287
+ }),
2258
2288
  defineTool({
2259
2289
  name: "canonry_schedule_get",
2260
2290
  title: "Get schedule",
@@ -2382,16 +2412,44 @@ var rawCanonryMcpTools = [
2382
2412
  defineTool({
2383
2413
  name: "canonry_provider_settings_update",
2384
2414
  title: "Update non-secret provider settings",
2385
- description: "Change model or quota for an already-configured provider, with explicit approval and settings.write. Preserves existing credentials. Does not accept API keys, base URLs, or credential rotation; use the secure operator setup flow for those.",
2415
+ description: "With explicit approval and settings.write, change or reset model/quota overrides for an already-configured provider, restore its built-in endpoint, or remove an optional Local API key. Resets require install administrator authority. Read canonry_provider_settings_get first and supply its revision as expectedRevision to reject stale edits. Does not accept API keys, base URLs, or credential rotation; use secure operator setup for those.",
2386
2416
  access: "write",
2387
2417
  requiredScope: "settings.write",
2388
2418
  tier: "setup",
2389
- inputSchema: z2.object({ provider: z2.string().min(1), model: z2.string().trim().min(1).optional(), quota: providerQuotaPolicySchema.partial().strict().optional() }).strict().refine((input) => input.model !== void 0 || input.quota !== void 0 && Object.keys(input.quota).length > 0, "Provide a model or at least one quota field"),
2419
+ inputSchema: z2.object({ provider: z2.string().min(1), model: z2.string().trim().min(1).optional(), quota: providerQuotaPolicySchema.partial().strict().optional(), reset: providerSettingsResetSchema.optional(), expectedRevision: z2.string().min(1).optional() }).strict().superRefine(({ provider: _provider, ...request }, context) => {
2420
+ const parsed = providerSettingsUpdateRequestSchema.safeParse(request);
2421
+ if (!parsed.success) for (const issue of parsed.error.issues) context.addIssue({ code: "custom", path: issue.path, message: issue.message });
2422
+ }),
2390
2423
  outputSchema: providerSummaryEntryDtoSchema,
2391
2424
  annotations: writeAnnotations({ idempotentHint: true }),
2392
2425
  openApiOperations: ["PUT /api/v1/settings/providers/{name}"],
2393
2426
  handler: async (client, { provider, ...request }) => client.updateProvider(provider, request)
2394
2427
  }),
2428
+ defineTool({
2429
+ name: "canonry_provider_settings_get",
2430
+ title: "Inspect provider connection",
2431
+ description: "Read credential-free saved provider configuration, inherited defaults, edit capabilities, host-managed settings, blockers, affected projects (Simple and Advanced) and lastTest, the stored result of the latest connection test of the active settings (null when none has run since they changed). Requires install administrator authority. Makes no provider calls. Use impactRevision when approving a disconnect, and revision when updating settings.",
2432
+ access: "read",
2433
+ tier: "setup",
2434
+ inputSchema: z2.object({ provider: z2.string().min(1) }).strict(),
2435
+ outputSchema: providerConnectionSettingsDtoSchema,
2436
+ annotations: readAnnotations(),
2437
+ openApiOperations: ["GET /api/v1/settings/providers/{name}"],
2438
+ handler: (client, input) => client.getProviderSettings(input.provider)
2439
+ }),
2440
+ defineTool({
2441
+ name: "canonry_provider_disconnect",
2442
+ title: "Disconnect provider",
2443
+ description: "With explicit operator approval, remove a saved provider connection. First inspect canonry_provider_settings_get and show affected projects, any projects whose usage could not be read (usage.unknown: they may also use this connection), host uses and blockers; pass its impactRevision. Requires install administrator authority and settings.write. Preserves project engine selections and historical results. Does not revoke the vendor key. Stale impact or active work blocks the change.",
2444
+ access: "write",
2445
+ requiredScope: "settings.write",
2446
+ tier: "setup",
2447
+ inputSchema: providerDisconnectRequestSchema.required().extend({ provider: z2.string().min(1) }),
2448
+ outputSchema: providerConnectionSettingsDtoSchema,
2449
+ annotations: writeAnnotations({ idempotentHint: true, destructiveHint: true }),
2450
+ openApiOperations: ["DELETE /api/v1/settings/providers/{name}"],
2451
+ handler: (client, { provider, ...request }) => client.disconnectProvider(provider, request)
2452
+ }),
2395
2453
  defineTool({
2396
2454
  name: "canonry_providers_reload",
2397
2455
  title: "Reload saved provider configuration",
@@ -2405,6 +2463,20 @@ var rawCanonryMcpTools = [
2405
2463
  openApiOperations: ["POST /api/v1/settings/providers/reload"],
2406
2464
  handler: (client, input) => client.reloadProviders(input)
2407
2465
  }),
2466
+ defineTool({
2467
+ name: "canonry_provider_test",
2468
+ title: "Test a saved provider connection",
2469
+ description: "With explicit operator approval, check one saved provider connection against the provider now. Most answer engines answer one tiny prompt on the provider account, Local lists its models, OpenRouter reads its key, and a search answer service with no free key check makes no request. Requires install administrator authority and settings.write. Accepts no credentials and changes no settings. Returns status connected, failed (with the provider's redacted reason) or not-verified, and the model checked. A failed check is a result with ok false, not a tool error. The result is kept as lastTest on canonry_provider_settings_get until the key, endpoint, model, Vertex project, region or credentials, or CDP endpoint changes, or the connection is disconnected, so read that before testing again. A connection whose previous test is still running returns OPERATION_IN_PROGRESS; wait for that result. Unsupported deployments return NOT_IMPLEMENTED.",
2470
+ access: "write",
2471
+ requiredScope: "settings.write",
2472
+ tier: "setup",
2473
+ inputSchema: z2.object({ provider: z2.string().min(1).describe("Connection name from canonry_settings_get, such as gemini, local or openrouter. Never a model route.") }).strict(),
2474
+ outputSchema: providerConnectionTestResultDtoSchema,
2475
+ // Repeating it changes nothing, but every call reaches the provider.
2476
+ annotations: writeAnnotations({ idempotentHint: true, openWorldHint: true }),
2477
+ openApiOperations: ["POST /api/v1/settings/providers/{name}/test"],
2478
+ handler: (client, input) => client.testProvider(input.provider)
2479
+ }),
2408
2480
  defineTool({
2409
2481
  name: "canonry_telemetry_get",
2410
2482
  requiresOperator: true,
@@ -3349,10 +3421,21 @@ var rawCanonryMcpTools = [
3349
3421
  openApiOperations: ["POST /api/v1/snapshot"],
3350
3422
  handler: (client, input) => client.createSnapshot(input)
3351
3423
  }),
3424
+ defineTool({
3425
+ name: "canonry_project_setup",
3426
+ title: "Get project setup status",
3427
+ description: "Read one project's first-run setup from stored state, with no provider calls, crawls or writes: the Agent Readiness audit scan and the AI Visibility check, each the latest non-probe run of its kind (state not_started, queued, running, completed, partial, failed or cancelled) with its stored progress, result or error, plus the server's nextAction. nextAction is one step, in row order: run_agent_readiness (no scan yet, or the last was cancelled), retry_agent_readiness (the scan failed), then for AI Visibility connect_engine, add_queries or publish_plan (what blocks the first check: no AI engine, no tracked queries, an unpublished Advanced Measurement draft), run_ai_visibility (a check can start), repair_ai_visibility (every engine keeps failing on its account, or the check failed), wait (a scan or check is in progress) and open_project (both have results). It names a step and grants nothing: the scan (canonry_agent_readiness_run) and the check (canonry_run_trigger, which spends the operator's AI engine accounts) each need their own approval. Results keep non-brand and branded query counts apart (queryCountsByClass): mentioned means the brand is in the answer text, cited means the domain is in its sources.",
3428
+ access: "read",
3429
+ tier: "setup",
3430
+ inputSchema: projectInputSchema,
3431
+ annotations: readAnnotations(),
3432
+ openApiOperations: ["GET /api/v1/projects/{name}/setup"],
3433
+ handler: (client, input) => client.getProjectSetup(input.project)
3434
+ }),
3352
3435
  defineTool({
3353
3436
  name: "canonry_project_upsert",
3354
3437
  title: "Create or replace project",
3355
- description: "Create or replace a Canonry project. PUT semantics: fields not in the request are reset to their defaults. Provide the full intended project shape. Exceptions: an omitted providerDispatchModes (provider \u2192 sync|batch for scheduled sweeps) keeps the stored preference; send {} to clear it. An omitted qualifiedAliases (the aliases Simple sentiment treats as this brand's own names) keeps the stored list, minus names that no longer qualify (a removed alias, a spelling of the display name, or a competitor's name); send [] to clear it. Competitors are not part of this request, but a new identity (display name, aliases, domains) that claims a tracked competitor's curated alias drops that alias, and the drop is audited. An omitted siteAuditMaxPages (the Site Health page budget for scans that set none, 1 to 50,000) keeps the stored budget; send null for the full site. An omitted competitorAutoAliases keeps the stored answer-derived competitor alias mode: `off` (no unattended detection pass), `preview` (the default: detect and log, store nothing) or `apply` (store the detected names, which restates history).",
3438
+ description: "Create or replace a Canonry project. PUT semantics: fields not in the request are reset to their defaults. Provide the full intended project shape. Exceptions: an omitted providerDispatchModes (provider \u2192 sync|batch for scheduled sweeps) keeps the stored preference; send {} to clear it. An omitted qualifiedAliases (the aliases Simple sentiment treats as this brand's own names) keeps the stored list, minus names that no longer qualify (a removed alias, a spelling of the display name, or a competitor's name); send [] to clear it. Competitors are not part of this request, but a new identity (display name, aliases, domains) that claims a tracked competitor's curated alias drops that alias, and the drop is audited. An omitted siteAuditMaxPages (the Agent Readiness page budget for scans that set none, 1 to 50,000) keeps the stored budget; send null for the full site. An omitted competitorAutoAliases keeps the stored answer-derived competitor alias mode: `off` (no unattended detection pass), `preview` (the default: detect and log, store nothing) or `apply` (store the detected names, which restates history).",
3356
3439
  access: "write",
3357
3440
  tier: "setup",
3358
3441
  inputSchema: projectUpsertInputSchema,
@@ -3374,7 +3457,7 @@ var rawCanonryMcpTools = [
3374
3457
  defineTool({
3375
3458
  name: "canonry_apply_config",
3376
3459
  title: "Apply project config",
3377
- description: "Apply one Canonry config-as-code project document. Replaces the project to match the config; fields omitted from the spec are reset to defaults, with these exceptions: a spec with neither queries nor keywords leaves the tracked-query basket unchanged (to clear the basket, pass an explicit empty queries list); an omitted providerDispatchModes keeps the stored preference; an omitted qualifiedAliases keeps the stored list, minus names that no longer qualify (a removed alias, a spelling of the display name, or a competitor's name); send [] to clear it; and a competitor given as a plain domain keeps its stored curated aliases, while `{ domain, aliases }` sets them exactly (`[]` clears). A spec identity that claims a competitor's alias drops that alias (audited); a new competitor whose name overlaps another competitor's alias (one brand key contains the other) or that is the project's own site fails the apply. An omitted siteAuditMaxPages keeps the stored Site Health page budget (null means the full site). An omitted competitorAutoAliases keeps the stored answer-derived competitor alias mode (off, preview or apply). For multi-document YAML, call this tool once per project document. Call canonry_apply_config_preview first.",
3460
+ description: "Apply one Canonry config-as-code project document. Replaces the project to match the config; fields omitted from the spec are reset to defaults, with these exceptions: a spec with neither queries nor keywords leaves the tracked-query basket unchanged (to clear the basket, pass an explicit empty queries list); an omitted providerDispatchModes keeps the stored preference; an omitted qualifiedAliases keeps the stored list, minus names that no longer qualify (a removed alias, a spelling of the display name, or a competitor's name); send [] to clear it; and a competitor given as a plain domain keeps its stored curated aliases, while `{ domain, aliases }` sets them exactly (`[]` clears). A spec identity that claims a competitor's alias drops that alias (audited); a new competitor whose name overlaps another competitor's alias (one brand key contains the other) or that is the project's own site fails the apply. An omitted siteAuditMaxPages keeps the stored Agent Readiness page budget (null means the full site). An omitted competitorAutoAliases keeps the stored answer-derived competitor alias mode (off, preview or apply). For multi-document YAML, call this tool once per project document. Call canonry_apply_config_preview first.",
3378
3461
  access: "write",
3379
3462
  tier: "core",
3380
3463
  inputSchema: applyConfigInputSchema,
@@ -4319,26 +4402,26 @@ var rawCanonryMcpTools = [
4319
4402
  handler: (client, input) => client.promoteDiscovery(input.project, input.sessionId, input.request)
4320
4403
  }),
4321
4404
  defineTool({
4322
- name: "canonry_site_health_overview",
4323
- title: "Get Site Health overview",
4324
- description: "For a requested scan date pass date=YYYY-MM-DD. If the year was omitted and that date has no data, use availableScanDates.matchingMonthDayDates to resolve the year and request the exact returned date before concluding the historical scan is missing. recentDates and matchingMonthDayDates are bounded; totalDates and matchingMonthDayTotal report their full counts. No automatic date fallback. inventorySummary provides complete eligibility counts and disjoint excluded reasons, including terminal redirects. Start a Site Health investigation with the latest or selected scan summary: root URL, completeness, crawl and link counts, budgets, versions, termination, and dead-link check state. Follow with a focused Site Health subgraph, shortest path, or scan changes; never request the interactive graph projection through MCP.",
4405
+ name: "canonry_agent_readiness_overview",
4406
+ title: "Get Agent Readiness overview",
4407
+ description: "For a requested scan date pass date=YYYY-MM-DD. If the year was omitted and that date has no data, use availableScanDates.matchingMonthDayDates to resolve the year and request the exact returned date before concluding the historical scan is missing. recentDates and matchingMonthDayDates are bounded; totalDates and matchingMonthDayTotal report their full counts. No automatic date fallback. inventorySummary provides complete eligibility counts and disjoint excluded reasons, including terminal redirects; unknown indexability is not canonical-away. Start an Agent Readiness investigation with the latest or selected scan summary: root URL, completeness, crawl and link counts, budgets, versions, termination, and dead-link check state. An older scorecard-only scan has no crawl, and this never fabricates one. Follow with a focused subgraph (canonry_agent_readiness_subgraph), shortest path (canonry_agent_readiness_path), or scan changes (canonry_agent_readiness_changes); never request the interactive graph projection through MCP.",
4325
4408
  access: "read",
4326
4409
  tier: "monitoring",
4327
4410
  inputSchema: technicalAeoCrawlInputSchema,
4328
4411
  annotations: readAnnotations(),
4329
- openApiOperations: ["GET /api/v1/projects/{name}/technical-aeo/crawl"],
4412
+ openApiOperations: ["GET /api/v1/projects/{name}/agent-readiness/crawl"],
4330
4413
  handler: (client, input) => client.getTechnicalAeoCrawl(input.project, { runId: input.runId, date: input.date })
4331
4414
  }),
4332
4415
  defineTool({
4333
- name: "canonry_site_health_issues",
4334
- title: "List stored Site Health issues",
4335
- description: "Read paginated finding groups from a saved audit, including duplicate metadata and critical defects regardless of aggregate score. Never starts a crawl. Preserve scan date, run/attempt identity, coverage and partial/unavailable states: an empty result does not prove the site is clean. Disposition separates actionable findings, advisory guidance, unverified checks and information; severity retains the recorded critical-defect level. recommendationsScope distinguishes issue-specific defect guidance from whole-factor advice. stableIdentity=false means the ID cannot establish continuity across scans. Follow nextCursor with the returned runId, or inspect one issue with canonry_site_health_issue_pages.",
4416
+ name: "canonry_agent_readiness_issues",
4417
+ title: "List stored Agent Readiness issues",
4418
+ description: "Read paginated finding groups from a saved Agent Readiness audit scan, including duplicate metadata and critical defects regardless of aggregate score. Never starts a crawl. Preserve scan date, run/attempt identity, coverage and partial/unavailable states: an empty result does not prove the site is clean. Disposition separates actionable findings, advisory guidance, unverified checks and information; severity retains the recorded critical-defect level. recommendationsScope distinguishes issue-specific defect guidance from whole-factor advice. stableIdentity=false means the ID cannot establish continuity across scans. Follow nextCursor with the returned runId, or inspect one issue with canonry_agent_readiness_issue_pages.",
4336
4419
  access: "read",
4337
4420
  tier: "monitoring",
4338
4421
  inputSchema: siteHealthIssuesInputSchema,
4339
4422
  outputSchema: siteAuditIssuesResponseSchema,
4340
4423
  annotations: readAnnotations(),
4341
- openApiOperations: ["GET /api/v1/projects/{name}/technical-aeo/issues"],
4424
+ openApiOperations: ["GET /api/v1/projects/{name}/agent-readiness/issues"],
4342
4425
  handler: (client, input) => client.getSiteAuditIssues(input.project, {
4343
4426
  runId: input.runId,
4344
4427
  cursor: input.cursor,
@@ -4346,15 +4429,15 @@ var rawCanonryMcpTools = [
4346
4429
  })
4347
4430
  }),
4348
4431
  defineTool({
4349
- name: "canonry_site_health_issue_pages",
4350
- title: "Read pages affected by a saved audit issue",
4351
- description: "Read paginated affected URLs and saved messages for one issue in the selected audit. Use the issue ID and runId from canonry_site_health_issues; continue with nextCursor without changing the selection. Null node keys and unavailable/partial coverage remain explicit. recommendationsScope identifies issue-specific defect guidance or broader factor advice; do not present factor advice as an exact fix for this finding. This stored read never crawls, changes content or authorizes edits.",
4432
+ name: "canonry_agent_readiness_issue_pages",
4433
+ title: "Read pages affected by a saved Agent Readiness issue",
4434
+ description: "Read paginated affected URLs and saved messages for one issue in the selected Agent Readiness audit scan. Use the issue ID and runId from canonry_agent_readiness_issues; continue with nextCursor without changing the selection. Null node keys and unavailable/partial coverage remain explicit. recommendationsScope identifies issue-specific defect guidance or broader factor advice; do not present factor advice as an exact fix for this finding. This stored read never crawls, changes content or authorizes edits.",
4352
4435
  access: "read",
4353
4436
  tier: "monitoring",
4354
4437
  inputSchema: siteHealthIssuePagesInputSchema,
4355
4438
  outputSchema: siteAuditIssuePagesResponseSchema,
4356
4439
  annotations: readAnnotations(),
4357
- openApiOperations: ["GET /api/v1/projects/{name}/technical-aeo/issues/{issueId}/pages"],
4440
+ openApiOperations: ["GET /api/v1/projects/{name}/agent-readiness/issues/{issueId}/pages"],
4358
4441
  handler: (client, input) => client.getSiteAuditIssuePages(input.project, input.issueId, {
4359
4442
  runId: input.runId,
4360
4443
  cursor: input.cursor,
@@ -4362,14 +4445,14 @@ var rawCanonryMcpTools = [
4362
4445
  })
4363
4446
  }),
4364
4447
  defineTool({
4365
- name: "canonry_site_health_page_audit",
4366
- title: "Get Site Health page audit",
4367
- description: "Connect one graph page's audit score to its exact persisted evidence: factor scores and each factor's `sharePct` of the page score (its `weight` is relative, never a percentage), stable finding codes and messages, recommendations, and critical defects. The response includes crawl provenance and explicit no-crawl, details-unavailable, not-found, not-audited, ready/scores-only states. Use nodeKey from a Site Health page or subgraph read when possible. Link score remains an importance signal, not an audit finding.",
4448
+ name: "canonry_agent_readiness_page_audit",
4449
+ title: "Get Agent Readiness page audit",
4450
+ description: "Connect one graph page's audit score to its exact persisted evidence: factor scores and each factor's `sharePct` of the page score (its `weight` is relative, never a percentage), stable finding codes and messages, recommendations, and critical defects. The response includes crawl provenance and explicit no-crawl, details-unavailable, not-found, not-audited, ready/scores-only states. Use nodeKey from canonry_agent_readiness_pages or canonry_agent_readiness_subgraph when possible. Link score remains an importance signal, not an audit finding.",
4368
4451
  access: "read",
4369
4452
  tier: "monitoring",
4370
4453
  inputSchema: siteHealthPageAuditInputSchema,
4371
4454
  annotations: readAnnotations(),
4372
- openApiOperations: ["GET /api/v1/projects/{name}/technical-aeo/crawl/pages/audit"],
4455
+ openApiOperations: ["GET /api/v1/projects/{name}/agent-readiness/crawl/pages/audit"],
4373
4456
  handler: (client, input) => client.getTechnicalAeoPageAudit(input.project, {
4374
4457
  runId: input.runId,
4375
4458
  nodeKey: input.nodeKey,
@@ -4377,14 +4460,14 @@ var rawCanonryMcpTools = [
4377
4460
  })
4378
4461
  }),
4379
4462
  defineTool({
4380
- name: "canonry_site_health_subgraph",
4381
- title: "Inspect focused Site Health subgraph",
4463
+ name: "canonry_agent_readiness_subgraph",
4464
+ title: "Inspect focused Agent Readiness subgraph",
4382
4465
  description: "Read a compact canonical neighborhood around one page or the crawl root. Defaults to 25 nodes and 50 edges; expand hops or refocus only when needed. `countAccuracy=lower-bound` means traversal reached a cap, and `complete`/`termination` qualify partial-crawl results. This intentionally omits visualization coordinates and never materializes the full site graph.",
4383
4466
  access: "read",
4384
4467
  tier: "monitoring",
4385
4468
  inputSchema: siteHealthSubgraphInputSchema,
4386
4469
  annotations: readAnnotations(),
4387
- openApiOperations: ["GET /api/v1/projects/{name}/technical-aeo/subgraph"],
4470
+ openApiOperations: ["GET /api/v1/projects/{name}/agent-readiness/subgraph"],
4388
4471
  handler: (client, input) => client.getSiteHealthSubgraph(input.project, {
4389
4472
  runId: input.runId,
4390
4473
  nodeKey: input.nodeKey,
@@ -4395,14 +4478,14 @@ var rawCanonryMcpTools = [
4395
4478
  })
4396
4479
  }),
4397
4480
  defineTool({
4398
- name: "canonry_site_health_path",
4399
- title: "Find shortest Site Health path",
4481
+ name: "canonry_agent_readiness_path",
4482
+ title: "Find shortest Agent Readiness link path",
4400
4483
  description: "Find the shortest directed path of followable internal links from the crawl root or a selected page to one required destination. Use `complete` and `termination` to qualify unreachable or truncated outcomes from a partial crawl; it returns one path, not a graph traversal.",
4401
4484
  access: "read",
4402
4485
  tier: "monitoring",
4403
4486
  inputSchema: siteHealthPathInputSchema,
4404
4487
  annotations: readAnnotations(),
4405
- openApiOperations: ["GET /api/v1/projects/{name}/technical-aeo/path"],
4488
+ openApiOperations: ["GET /api/v1/projects/{name}/agent-readiness/path"],
4406
4489
  handler: (client, input) => client.getSiteHealthPath(input.project, {
4407
4490
  runId: input.runId,
4408
4491
  fromNodeKey: input.fromNodeKey,
@@ -4413,14 +4496,14 @@ var rawCanonryMcpTools = [
4413
4496
  })
4414
4497
  }),
4415
4498
  defineTool({
4416
- name: "canonry_site_health_changes",
4417
- title: "Compare Site Health scans",
4499
+ name: "canonry_agent_readiness_changes",
4500
+ title: "Compare Agent Readiness audit scans",
4418
4501
  description: "Compare two immutable complete scans (or the latest pair) for added, removed, and changed canonical pages or links. Results echo resolved filters and scan IDs; the first page has an exact summary, while continuations omit summary/total. MCP pages cap at 25 because every change carries before/after DTOs; filter before paging.",
4419
4502
  access: "read",
4420
4503
  tier: "monitoring",
4421
4504
  inputSchema: siteHealthChangesInputSchema,
4422
4505
  annotations: readAnnotations(),
4423
- openApiOperations: ["GET /api/v1/projects/{name}/technical-aeo/changes"],
4506
+ openApiOperations: ["GET /api/v1/projects/{name}/agent-readiness/changes"],
4424
4507
  handler: (client, input) => client.getSiteHealthChanges(input.project, {
4425
4508
  fromRunId: input.fromRunId,
4426
4509
  toRunId: input.toRunId,
@@ -4431,25 +4514,25 @@ var rawCanonryMcpTools = [
4431
4514
  })
4432
4515
  }),
4433
4516
  defineTool({
4434
- name: "canonry_technical_aeo_score",
4435
- title: "Get Technical AEO score",
4436
- description: "pagesFailing and pagesPartial are independent counts; their sum is the number of audited pages below pass for that factor. Any failing page makes a factor fail, independently of its average score or affected-page count. These counts use the audited-page population; crawl eligibility is a separate inventory population. affectedPageRanking orders recorded per-factor below-pass counts from largest to smallest; this is affected-page breadth, not a prediction of mention or citation lift. Factor cohorts overlap, so do not add their counts together. runSelection flags same-date ambiguity and prefers a complete run on the latest scan date, otherwise the largest page sample. Get the Technical AEO scorecard for a project: the latest site-audit aggregate 0\u2013100 score, per-factor site-level averages (with pass/partial/fail distribution), cross-cutting issues, prioritized fixes, and the delta vs the previous audit. A factor's share of the site score is `sharePct` (0\u2013100, the shares add up to 100; null for a scan that did not record it); its `weight` is relative and never a percentage. When `hasData` is false, no scored audit is available for the selected scan; a stored crawl may still exist. Inspect the stored crawl before proposing a new audit.",
4517
+ name: "canonry_agent_readiness_score",
4518
+ title: "Get Agent Readiness score",
4519
+ description: "pagesFailing and pagesPartial are independent counts; their sum is the number of audited pages below pass for that factor. Any failing page makes a factor fail, independently of its average score or affected-page count. These counts use the audited-page population; crawl eligibility is a separate inventory population. affectedPageRanking orders recorded per-factor below-pass counts from largest to smallest; this is affected-page breadth, not a prediction of mention or citation lift. Factor cohorts overlap, so do not add their counts together. runSelection flags same-date ambiguity and prefers a complete run on the latest scan date, otherwise the largest page sample. Get the Agent Readiness scorecard for a project: the aggregate 0\u2013100 score of the latest scan, per-factor site-level averages (with pass/partial/fail distribution), cross-cutting issues, prioritized fixes, and the delta vs the previous audit. A factor's share of the site score is `sharePct` (0\u2013100, the shares add up to 100; null for a scan that did not record it); its `weight` is relative and never a percentage. When `hasData` is false, no scored audit is available for the selected scan; a stored crawl may still exist. Inspect the stored crawl with canonry_agent_readiness_overview before proposing a new scan.",
4437
4520
  access: "read",
4438
4521
  tier: "monitoring",
4439
4522
  inputSchema: technicalAeoScoreInputSchema,
4440
4523
  annotations: readAnnotations(),
4441
- openApiOperations: ["GET /api/v1/projects/{name}/technical-aeo"],
4524
+ openApiOperations: ["GET /api/v1/projects/{name}/agent-readiness"],
4442
4525
  handler: (client, input) => client.getTechnicalAeoScore(input.project, { runId: input.runId })
4443
4526
  }),
4444
4527
  defineTool({
4445
- name: "canonry_technical_aeo_pages",
4446
- title: "List Technical AEO pages",
4447
- description: "List the per-page breakdown of the latest site-audit run (paginated). Filter status=error to surface unreachable pages, or sort score-asc (default) to surface the worst-scoring pages first. Use after canonry_technical_aeo_score to drill into which pages drag the site score down.",
4528
+ name: "canonry_agent_readiness_page_scores",
4529
+ title: "List Agent Readiness page scores",
4530
+ description: "List the per-page scores of the latest Agent Readiness audit scan (paginated). Filter status=error to surface unreachable pages, or sort score-asc (default) to surface the worst-scoring pages first. Use after canonry_agent_readiness_score to drill into which pages drag the site score down.",
4448
4531
  access: "read",
4449
4532
  tier: "monitoring",
4450
4533
  inputSchema: technicalAeoPagesInputSchema,
4451
4534
  annotations: readAnnotations(),
4452
- openApiOperations: ["GET /api/v1/projects/{name}/technical-aeo/pages"],
4535
+ openApiOperations: ["GET /api/v1/projects/{name}/agent-readiness/pages"],
4453
4536
  handler: (client, input) => client.getTechnicalAeoPages(input.project, {
4454
4537
  runId: input.runId,
4455
4538
  status: input.status,
@@ -4459,20 +4542,20 @@ var rawCanonryMcpTools = [
4459
4542
  })
4460
4543
  }),
4461
4544
  defineTool({
4462
- name: "canonry_technical_aeo_trend",
4463
- title: "Get Technical AEO trend",
4464
- description: 'Get the aggregate Technical AEO score over time (oldest-first) across past site-audit runs. Use to answer "is our technical AEO improving?".',
4545
+ name: "canonry_agent_readiness_trend",
4546
+ title: "Get Agent Readiness score trend",
4547
+ description: 'Get the aggregate Agent Readiness score over time (oldest-first) across past scans. Use to answer "is our Agent Readiness improving?".',
4465
4548
  access: "read",
4466
4549
  tier: "monitoring",
4467
4550
  inputSchema: technicalAeoTrendInputSchema,
4468
4551
  annotations: readAnnotations(),
4469
- openApiOperations: ["GET /api/v1/projects/{name}/technical-aeo/trend"],
4552
+ openApiOperations: ["GET /api/v1/projects/{name}/agent-readiness/trend"],
4470
4553
  handler: (client, input) => client.getTechnicalAeoTrend(input.project, input.limit !== void 0 ? { limit: input.limit } : void 0)
4471
4554
  }),
4472
4555
  defineTool({
4473
4556
  name: "canonry_sitemaps",
4474
4557
  title: "Compare sitemaps across the site, Google and Bing",
4475
- description: `Read, from stored data, the sitemap files the latest Site Health scan read pages from, each engine's sitemap list (status, URL count, submitted and last read) and what each engine is missing: sitemaps the site declares or someone submitted to the other engine. google or bing is null when that engine is not connected or its list was never read. Use for "are my sitemaps in Google and Bing?" before submitting anything.`,
4558
+ description: `Read, from stored data, the sitemap files the latest Agent Readiness audit scan read pages from, each engine's sitemap list (status, URL count, submitted and last read) and what each engine is missing: sitemaps the site declares or someone submitted to the other engine. google or bing is null when that engine is not connected or its list was never read. Use for "are my sitemaps in Google and Bing?" before submitting anything.`,
4476
4559
  access: "read",
4477
4560
  tier: "monitoring",
4478
4561
  inputSchema: projectInputSchema,
@@ -4497,25 +4580,14 @@ var rawCanonryMcpTools = [
4497
4580
  })
4498
4581
  }),
4499
4582
  defineTool({
4500
- name: "canonry_technical_aeo_crawl",
4501
- title: "Get persisted Technical AEO crawl",
4502
- description: "For a historical question pass its exact UTC date (YYYY-MM-DD). If the year was omitted and that date has no data, use availableScanDates.matchingMonthDayDates to resolve the year and request the exact returned date before concluding the historical scan is missing. recentDates and matchingMonthDayDates are bounded; totalDates and matchingMonthDayTotal report their full counts. No automatic date fallback. inventorySummary gives whole-snapshot eligibility and disjoint excluded reasons; unknown is not canonical-away. Read persisted full-crawl metadata for the latest or selected Technical AEO site-audit run: root URL, crawl/indexability/link-score versions, effective budgets, completeness, counts, and explicit dead-link check state. This does not fabricate a graph from older scorecard-only audits.",
4503
- access: "read",
4504
- tier: "monitoring",
4505
- inputSchema: technicalAeoCrawlInputSchema,
4506
- annotations: readAnnotations(),
4507
- openApiOperations: ["GET /api/v1/projects/{name}/technical-aeo/crawl"],
4508
- handler: (client, input) => client.getTechnicalAeoCrawl(input.project, { runId: input.runId, date: input.date })
4509
- }),
4510
- defineTool({
4511
- name: "canonry_technical_aeo_crawl_pages",
4512
- title: "List Technical AEO crawl pages",
4583
+ name: "canonry_agent_readiness_pages",
4584
+ title: "List Agent Readiness crawl pages",
4513
4585
  description: "For a requested scan date pass date=YYYY-MM-DD. If the year was omitted and that date has no data, use availableScanDates.matchingMonthDayDates to resolve the year and request the exact returned date before concluding the historical scan is missing. recentDates and matchingMonthDayDates are bounded; totalDates and matchingMonthDayTotal report their full counts. No automatic date fallback. inventorySummary gives whole-snapshot eligible/excluded counts, disjoint excluded reasons, and urlVersions (parameter copies of a page the audit did not score; pass urlVersions=exclude to list pages only); healthReasonCounts covers the filtered list before paging. Use these exact counts, never infer canonical-away from unknown indexability. healthReason distinguishes terminal redirects from canonical-to-other pages. Default runSelection reports same-date ambiguity and selects complete or most-pages evidence on the latest scan date. Read one bounded, cursor-paged list of canonical crawl nodes. Filter crawler-derived indexability and audit state, then follow nextCursor; this is technical inventory eligibility, not a claim about Google index coverage. `complete: false` means the crawl stopped at the budget named by `termination`, so a missing page or link is not proof it does not exist.",
4514
4586
  access: "read",
4515
4587
  tier: "monitoring",
4516
4588
  inputSchema: technicalAeoCrawlPagesInputSchema,
4517
4589
  annotations: readAnnotations(),
4518
- openApiOperations: ["GET /api/v1/projects/{name}/technical-aeo/crawl/pages"],
4590
+ openApiOperations: ["GET /api/v1/projects/{name}/agent-readiness/crawl/pages"],
4519
4591
  handler: (client, input) => client.getTechnicalAeoCrawlPages(input.project, {
4520
4592
  runId: input.runId,
4521
4593
  date: input.date,
@@ -4530,14 +4602,14 @@ var rawCanonryMcpTools = [
4530
4602
  })
4531
4603
  }),
4532
4604
  defineTool({
4533
- name: "canonry_technical_aeo_structure",
4534
- title: "List Technical AEO site structure",
4605
+ name: "canonry_agent_readiness_structure",
4606
+ title: "List Agent Readiness site structure",
4535
4607
  description: "Read one bounded level of the persisted site hierarchy below parentPath. Follow nextCursor for more siblings; request a child path separately rather than attempting to materialize the entire website tree. `complete: false` means the crawl stopped at the budget named by `termination`, so a missing page or link is not proof it does not exist.",
4536
4608
  access: "read",
4537
4609
  tier: "monitoring",
4538
4610
  inputSchema: technicalAeoStructureInputSchema,
4539
4611
  annotations: readAnnotations(),
4540
- openApiOperations: ["GET /api/v1/projects/{name}/technical-aeo/structure"],
4612
+ openApiOperations: ["GET /api/v1/projects/{name}/agent-readiness/structure"],
4541
4613
  handler: (client, input) => client.getTechnicalAeoStructure(input.project, {
4542
4614
  runId: input.runId,
4543
4615
  parentPath: input.parentPath,
@@ -4546,14 +4618,14 @@ var rawCanonryMcpTools = [
4546
4618
  })
4547
4619
  }),
4548
4620
  defineTool({
4549
- name: "canonry_technical_aeo_internal_links",
4550
- title: "List Technical AEO internal links",
4551
- description: "Read a bounded, cursor-paged list of persisted internal crawl edges. Filter by source URL, target URL, followability, or link kind. Nav, header, and footer links are marked isTemplate; templateSource says which rule decided each one (placement, ubiquity, or unmeasured when neither had evidence) and templateDetection reports the same for the scan, so an empty content-only list is not evidence of no content links and two scans classified by different rules are never compared as if they were the same measurement. Use the neighbors tool for one page rather than loading a graph. `complete: false` means the crawl stopped at the budget named by `termination`, so a missing page or link is not proof it does not exist.",
4621
+ name: "canonry_agent_readiness_links",
4622
+ title: "List Agent Readiness internal links",
4623
+ description: "Read a bounded, cursor-paged list of persisted internal crawl edges. Filter by source URL, target URL, followability, or link kind. Nav, header, and footer links are marked isTemplate; templateSource says which rule decided each one (placement, ubiquity, or unmeasured when neither had evidence) and templateDetection reports the same for the scan, so an empty content-only list is not evidence of no content links and two scans classified by different rules are never compared as if they were the same measurement. Use canonry_agent_readiness_link_neighbors for one page rather than loading a graph. `complete: false` means the crawl stopped at the budget named by `termination`, so a missing page or link is not proof it does not exist.",
4552
4624
  access: "read",
4553
4625
  tier: "monitoring",
4554
4626
  inputSchema: technicalAeoInternalLinksInputSchema,
4555
4627
  annotations: readAnnotations(),
4556
- openApiOperations: ["GET /api/v1/projects/{name}/technical-aeo/internal-links"],
4628
+ openApiOperations: ["GET /api/v1/projects/{name}/agent-readiness/internal-links"],
4557
4629
  handler: (client, input) => client.getTechnicalAeoInternalLinks(input.project, {
4558
4630
  runId: input.runId,
4559
4631
  sourceUrl: input.sourceUrl,
@@ -4565,14 +4637,14 @@ var rawCanonryMcpTools = [
4565
4637
  })
4566
4638
  }),
4567
4639
  defineTool({
4568
- name: "canonry_technical_aeo_link_neighbors",
4569
- title: "Get Technical AEO page link neighbors",
4640
+ name: "canonry_agent_readiness_link_neighbors",
4641
+ title: "Get Agent Readiness page link neighbors",
4570
4642
  description: "Read bounded inbound and outbound internal links for exactly one crawl node, selected by nodeKey or URL. Filter by link kind to separate editorial links from nav, header, and footer links. It returns independent truncation flags for inbound and outbound edges, not a transitive traversal. `complete: false` means the crawl stopped at the budget named by `termination`, so a missing page or link is not proof it does not exist.",
4571
4643
  access: "read",
4572
4644
  tier: "monitoring",
4573
4645
  inputSchema: technicalAeoLinkNeighborsInputSchema,
4574
4646
  annotations: readAnnotations(),
4575
- openApiOperations: ["GET /api/v1/projects/{name}/technical-aeo/internal-links/neighbors"],
4647
+ openApiOperations: ["GET /api/v1/projects/{name}/agent-readiness/internal-links/neighbors"],
4576
4648
  handler: (client, input) => client.getTechnicalAeoInternalLinkNeighbors(input.project, {
4577
4649
  runId: input.runId,
4578
4650
  nodeKey: input.nodeKey,
@@ -4582,14 +4654,14 @@ var rawCanonryMcpTools = [
4582
4654
  })
4583
4655
  }),
4584
4656
  defineTool({
4585
- name: "canonry_technical_aeo_dead_links",
4586
- title: "List Technical AEO dead links",
4657
+ name: "canonry_agent_readiness_dead_links",
4658
+ title: "List Agent Readiness dead links",
4587
4659
  description: "Read the persisted dead-link check state and a bounded, cursor-paged list of findings. A disabled result means the crawl was run without opt-in checks; it never means zero dead links.",
4588
4660
  access: "read",
4589
4661
  tier: "monitoring",
4590
4662
  inputSchema: technicalAeoDeadLinksInputSchema,
4591
4663
  annotations: readAnnotations(),
4592
- openApiOperations: ["GET /api/v1/projects/{name}/technical-aeo/dead-links"],
4664
+ openApiOperations: ["GET /api/v1/projects/{name}/agent-readiness/dead-links"],
4593
4665
  handler: (client, input) => client.getTechnicalAeoDeadLinks(input.project, {
4594
4666
  runId: input.runId,
4595
4667
  cursor: input.cursor,
@@ -4597,14 +4669,14 @@ var rawCanonryMcpTools = [
4597
4669
  })
4598
4670
  }),
4599
4671
  defineTool({
4600
- name: "canonry_technical_aeo_run",
4601
- title: "Run Technical AEO site audit",
4602
- description: "Start a site-audit run. The run discovers root, sitemap, and linked pages. Without maxPages it uses the project's saved page budget (siteAuditMaxPages), else the full site (up to 50,000 pages), and the engine derives the link-observation budget from that page count with a 100,000 floor, so raising maxPages raises it too. An explicit maxEdges is a ceiling that replaces the derivation and can sit below it. It returns {runId, status} and continues in the background. If an active run has identical effective options, this tool returns it; different options are refused. Poll canonry_run_get, then read the crawl and score tools.",
4672
+ name: "canonry_agent_readiness_run",
4673
+ title: "Run Agent Readiness audit scan",
4674
+ description: "Start an Agent Readiness audit scan (a site-audit run). The scan discovers root, sitemap, and linked pages. Without maxPages it uses the project's saved page budget (siteAuditMaxPages), else the full site (up to 50,000 pages), and the engine derives the link-observation budget from that page count with a 100,000 floor, so raising maxPages raises it too. An explicit maxEdges is a ceiling that replaces the derivation and can sit below it. It returns {runId, status} and continues in the background. If an active run has identical effective options, this tool returns it; different options are refused. Poll canonry_run_get, then read canonry_agent_readiness_overview and canonry_agent_readiness_score.",
4603
4675
  access: "write",
4604
4676
  tier: "monitoring",
4605
4677
  inputSchema: technicalAeoRunInputSchema,
4606
4678
  annotations: writeAnnotations({ idempotentHint: false, openWorldHint: true }),
4607
- openApiOperations: ["POST /api/v1/projects/{name}/technical-aeo/runs"],
4679
+ openApiOperations: ["POST /api/v1/projects/{name}/agent-readiness/runs"],
4608
4680
  handler: (client, input) => client.triggerSiteAudit(input.project, {
4609
4681
  sitemapUrl: input.sitemapUrl,
4610
4682
  limit: input.limit,
@@ -5117,10 +5189,47 @@ var rawCanonryMcpTools = [
5117
5189
  handler: (client, input) => client.triggerAdsSync(input.project)
5118
5190
  })
5119
5191
  ];
5120
- var canonryMcpTools = rawCanonryMcpTools.map((tool) => {
5192
+ var canonicalCanonryMcpTools = rawCanonryMcpTools.map((tool) => {
5121
5193
  if (tool.access !== "read" || toolOperationAccess(tool) !== OperationAccesses.live) return tool;
5122
5194
  return { ...tool, annotations: { ...tool.annotations, openWorldHint: true } };
5123
5195
  });
5196
+ var DEPRECATED_MCP_TOOL_ALIASES = {
5197
+ canonry_technical_aeo_score: "canonry_agent_readiness_score",
5198
+ canonry_technical_aeo_pages: "canonry_agent_readiness_page_scores",
5199
+ canonry_technical_aeo_trend: "canonry_agent_readiness_trend",
5200
+ canonry_site_health_overview: "canonry_agent_readiness_overview",
5201
+ canonry_technical_aeo_crawl: "canonry_agent_readiness_overview",
5202
+ canonry_technical_aeo_crawl_pages: "canonry_agent_readiness_pages",
5203
+ canonry_site_health_page_audit: "canonry_agent_readiness_page_audit",
5204
+ canonry_site_health_issues: "canonry_agent_readiness_issues",
5205
+ canonry_site_health_issue_pages: "canonry_agent_readiness_issue_pages",
5206
+ canonry_technical_aeo_structure: "canonry_agent_readiness_structure",
5207
+ canonry_technical_aeo_internal_links: "canonry_agent_readiness_links",
5208
+ canonry_technical_aeo_link_neighbors: "canonry_agent_readiness_link_neighbors",
5209
+ canonry_technical_aeo_dead_links: "canonry_agent_readiness_dead_links",
5210
+ canonry_site_health_subgraph: "canonry_agent_readiness_subgraph",
5211
+ canonry_site_health_path: "canonry_agent_readiness_path",
5212
+ canonry_site_health_changes: "canonry_agent_readiness_changes",
5213
+ canonry_technical_aeo_run: "canonry_agent_readiness_run"
5214
+ };
5215
+ var DEPRECATED_MCP_TOOL_ALIAS_NAMES = Object.keys(DEPRECATED_MCP_TOOL_ALIASES);
5216
+ function deprecatedAliasTool(alias) {
5217
+ const canonicalName = DEPRECATED_MCP_TOOL_ALIASES[alias];
5218
+ const canonical = canonicalCanonryMcpTools.find((tool) => tool.name === canonicalName);
5219
+ if (!canonical) throw new Error(`Deprecated MCP tool ${alias} names a missing tool: ${canonicalName}`);
5220
+ return {
5221
+ ...canonical,
5222
+ name: alias,
5223
+ title: `${canonical.title} (deprecated name)`,
5224
+ description: `Deprecated name for ${canonical.name}; call that tool instead. Same input and output.`,
5225
+ inputJsonSchema: toJsonSchema(canonical.inputSchema, alias),
5226
+ deprecatedAliasOf: canonical.name
5227
+ };
5228
+ }
5229
+ var canonryMcpTools = [
5230
+ ...canonicalCanonryMcpTools,
5231
+ ...DEPRECATED_MCP_TOOL_ALIAS_NAMES.map(deprecatedAliasTool)
5232
+ ];
5124
5233
  var CanonryMcpToolNames = Object.freeze(
5125
5234
  Object.fromEntries(canonryMcpTools.map((tool) => [tool.name, tool.name]))
5126
5235
  );
@@ -5128,6 +5237,7 @@ var CanonryMcpToolNames = Object.freeze(
5128
5237
  export {
5129
5238
  mcpOutputSchema,
5130
5239
  toolOperationAccess,
5240
+ DEPRECATED_MCP_TOOL_ALIAS_NAMES,
5131
5241
  canonryMcpTools,
5132
5242
  CanonryMcpToolNames
5133
5243
  };