@ainyc/canonry 4.195.0 → 5.0.1

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 (29) hide show
  1. package/LICENSE +21 -105
  2. package/README.md +5 -2
  3. package/assets/agent-workspace/skills/canonry/SKILL.md +24 -5
  4. package/assets/assets/{AuditHistoryPanel-vWUtVXOI.js → AuditHistoryPanel-9F_74jKS.js} +1 -1
  5. package/assets/assets/{BacklinksPage-CSzuMEuv.js → BacklinksPage-DmF2rbwy.js} +1 -1
  6. package/assets/assets/{HistoryPage-DtCTQ7CQ.js → HistoryPage-DKopwAjo.js} +1 -1
  7. package/assets/assets/{MeasurementPropertyPage-B7gTMWNs.js → MeasurementPropertyPage-Dpd_DYQv.js} +1 -1
  8. package/assets/assets/{ProjectPage-Bsm0_jUY.js → ProjectPage-b1-57SzP.js} +1 -1
  9. package/assets/assets/{RunRow-D5k4Rdo4.js → RunRow-BjrSRp6X.js} +1 -1
  10. package/assets/assets/{RunsPage-DIXBB2Om.js → RunsPage-BFrymZ7D.js} +1 -1
  11. package/assets/assets/{SettingsPage-wYhBm6Az.js → SettingsPage-DdVa6pLK.js} +1 -1
  12. package/assets/assets/{SiteHealthSection-YebzsgDh.js → SiteHealthSection-CizmiBjA.js} +3 -3
  13. package/assets/assets/{TrafficPage-DtnSRFO8.js → TrafficPage-N7sZgb9x.js} +1 -1
  14. package/assets/assets/{TrafficSourceDetailPage-DYQ6mpYq.js → TrafficSourceDetailPage-BNQmMJ5D.js} +1 -1
  15. package/assets/assets/{extract-error-message-BdChrkmo.js → extract-error-message-Bh9mRIz9.js} +1 -1
  16. package/assets/assets/{index-C_E2NRYY.js → index-BnR1Tu9j.js} +3 -3
  17. package/assets/assets/{react-sigma_core.esm.min-sKWUk_tG.js → react-sigma_core.esm.min-DGaYwjLZ.js} +1 -1
  18. package/assets/assets/{v2-overview-adapter-CkPt-sRK.js → v2-overview-adapter-eqN-8OK5.js} +1 -1
  19. package/assets/index.html +1 -1
  20. package/dist/{chunk-3WODA4JF.js → chunk-3DL3KV6C.js} +2 -0
  21. package/dist/{chunk-LJKAB4CX.js → chunk-66KGNC4U.js} +2 -2
  22. package/dist/{chunk-H3RVNMOO.js → chunk-GMNZNLVX.js} +11 -6
  23. package/dist/{chunk-UMU3IBXM.js → chunk-LHHJVGH7.js} +39 -26
  24. package/dist/{chunk-B2XM6AQ6.js → chunk-MEQGGODM.js} +21 -9
  25. package/dist/cli.js +6 -5
  26. package/dist/index.js +4 -4
  27. package/dist/{intelligence-service-MGQRJW4V.js → intelligence-service-7XX5ZRYE.js} +2 -2
  28. package/dist/mcp.js +6 -7
  29. package/package.json +28 -12
@@ -115,7 +115,7 @@ import {
115
115
  trafficEventKindSchema,
116
116
  trafficSeriesGranularitySchema,
117
117
  visibilityReportRequestSchema
118
- } from "./chunk-3WODA4JF.js";
118
+ } from "./chunk-3DL3KV6C.js";
119
119
 
120
120
  // src/cli-error.ts
121
121
  function isMachineFormat(format) {
@@ -190,6 +190,13 @@ var dashboardManagedSweepsSchema = z.boolean().nullish();
190
190
  var researchAllowViewersSchema = z.boolean().nullish();
191
191
  var researchViewerDailyRunLimitSchema = z.number().int().positive().nullish();
192
192
  var dashboardManagedRunKindsSchema = z.array(schedulableRunKindSchema).nullish();
193
+ function resolveOperatorApiKeyIds(source) {
194
+ const raw = source.CANONRY_OPERATOR_KEY_IDS?.trim();
195
+ if (!raw) return [];
196
+ const parsed = z.array(z.string().regex(/^[\w-]{1,256}$/)).max(100).safeParse(raw.split(",").map((id) => id.trim()));
197
+ if (!parsed.success) throw new Error("CANONRY_OPERATOR_KEY_IDS must contain at most 100 comma-separated API key IDs (letters, digits, underscores, hyphens; no wildcards).");
198
+ return [...new Set(parsed.data)];
199
+ }
193
200
  var envSchema = z.object({
194
201
  DATABASE_URL: z.string().default("postgresql://aeo:aeo@postgres:5432/aeo_platform"),
195
202
  API_PORT: z.coerce.number().int().positive().default(3e3),
@@ -10492,7 +10499,7 @@ var canonryMcpTools = [
10492
10499
  defineTool({
10493
10500
  name: "canonry_key_self",
10494
10501
  title: "Get current API key identity",
10495
- description: "Read safe metadata for the credential backing this MCP connection, including its scopes, project reach, and derived read-only status. It never exposes the bearer token or stored hash and does not grant mutation access.",
10502
+ description: "Read safe metadata for the credential backing this MCP connection, including scopes, project reach, read-only status, and host-derived operator authority. It never exposes the bearer token or stored hash and cannot grant authority.",
10496
10503
  access: "read",
10497
10504
  tier: "core",
10498
10505
  inputSchema: emptyInputSchema,
@@ -10503,8 +10510,9 @@ var canonryMcpTools = [
10503
10510
  }),
10504
10511
  defineTool({
10505
10512
  name: "canonry_logs_list",
10513
+ requiresOperator: true,
10506
10514
  title: "Read runtime logs",
10507
- description: "Read bounded, redacted runtime logs, including application and HTTP failures. Filter by actor, request, run, project, level, module, or time. Inspect retention, retentionPolicy, dropped, and captureErrors for coverage; file-backed hosts retain logs across restarts. Separate from audit history. Requires instance-wide logs.read (or wildcard), and an admin role for user sessions; project-scoped keys are refused even with a project filter. Cursors expire on retention eviction; reuse with the same filters. No provider calls.",
10515
+ description: "Read bounded, redacted runtime logs, including application and HTTP failures. Filter by actor, request, run, project, level, module, or time. Inspect retention, retentionPolicy, dropped, and captureErrors for coverage; file-backed hosts retain logs across restarts. Separate from audit history. Requires a host-approved operator bearer and instance-wide logs.read (or wildcard). Customer admins, browser/OAuth/delegated sessions, and project-scoped keys cannot grant access. Cursors expire on retention eviction; reuse with the same filters. No provider calls.",
10508
10516
  access: "read",
10509
10517
  tier: "setup",
10510
10518
  inputSchema: logQuerySchema,
@@ -10515,8 +10523,9 @@ var canonryMcpTools = [
10515
10523
  }),
10516
10524
  defineTool({
10517
10525
  name: "canonry_telemetry_update",
10526
+ requiresOperator: true,
10518
10527
  title: "Update server telemetry preference",
10519
- description: "Set the connected server telemetry preference with explicit approval and settings.write. Returns effective state including environment overrides. Does not change the agent machine configuration.",
10528
+ description: "Set the connected server telemetry preference with explicit approval, host-approved operator authority, and settings.write. Customer roles and scopes alone cannot grant operator access. Returns effective state including environment overrides. Does not change the agent machine configuration.",
10520
10529
  access: "write",
10521
10530
  requiredScope: "settings.write",
10522
10531
  tier: "setup",
@@ -10541,8 +10550,9 @@ var canonryMcpTools = [
10541
10550
  }),
10542
10551
  defineTool({
10543
10552
  name: "canonry_telemetry_get",
10553
+ requiresOperator: true,
10544
10554
  title: "Get telemetry status",
10545
- description: "Read the server telemetry status and effective reason. This safe settings read does not change telemetry collection.",
10555
+ description: "Read internal server telemetry status and effective reason. Requires a host-approved operator bearer, not a customer admin role or scopes alone. Does not change telemetry collection.",
10546
10556
  access: "read",
10547
10557
  tier: "setup",
10548
10558
  inputSchema: emptyInputSchema,
@@ -13063,7 +13073,7 @@ var OPERATIONS_GUIDE = {
13063
13073
  "guidance": "Read the stored report for the selected project and period. Retain evidence dates, scope, sample sizes, missing data, and separate mention/citation signals; do not generate fresh runs implicitly."
13064
13074
  }
13065
13075
  },
13066
- "markdown": "# Canonry Operations Guide v1\n\nCanonry is an agent-first AI visibility platform. MCP is the universal entry\npoint for connected agents. Host-native skills are optional upgrades, not a\nprerequisite or a permission mechanism.\n\n## Connect and choose a route\n\nRead the initialization guidance, then call `canonry_help` with an `intent`:\n`status`, `diagnose`, `operations`, `prospecting`, `measurement`, `integrations`,\n`reports`, or a short task\ndescription. Select an accessible project with `canonry_projects_list` before\nusing its exact name in project tools. Inspect each listed tool's input schema;\nhelp suggests tool names, not invented arguments or authorization.\n\nHelp returns a versioned, compact route: connection `mode`, available `next`\ntools, workflow guidance, approval boundaries, and this guide's URL. It performs\nno provider calls, reads no project data, and changes no permissions.\n`next` lists stored reads. Optional `actions` lists loaded tools for work that\nrequires approval; listing an action does not authorize or execute it.\n`includeCatalog: true` additionally returns toolkit details when needed.\n\nHosted connections use a fixed catalog. Help only suggests tools offered by that\nconnection; it never tells a hosted agent to dynamically load a toolkit. A\nprogressive local stdio connection may return `loadToolkits`: call\n`canonry_load_toolkit` with one returned name, await it, then call help again.\nLoading only changes local tool discovery, never server authority.\n\nThe optional `canonry://agent-operations/v1` MCP resource contains this same\nguide. If the host cannot read resources or open links, continue through help.\nDo not install a plugin, local runtime, or skill merely to use connected MCP.\nAn installed Codex or Claude Canonry skill contains a generated copy of this\nguide plus links to host-native references. It does not replace runtime help.\n\n## Vocabulary and evidence\n\n- **Mentioned** means the brand appears in answer text. **Cited** means its\n domain appears in source links. Either, both, or neither can occur; never\n compute one signal from the other.\n- `answerMentioned: null` means not checked, not false. Missing runs and empty\n populations mean no measurement, not zero visibility.\n- Preserve project, time window, provider, requested/served model, location,\n sample size, and query class when comparing evidence. Use server-returned\n metrics; do not invent a score from incompatible populations.\n- Simple projects and Advanced portfolios share the workflow. For Advanced\n results, preserve Property, Target, market, plan revision, and class scope.\n Groups organize navigation; do not infer an unrequested fan-out.\n- Research is isolated evidence, not tracked measurement. A probe still spends\n quota and persists evidence but is excluded from normal tracking metrics.\n\n## Workflows\n\n**Status:** read the stored overview and freshness first. Say when evidence is\nmissing instead of silently creating it.\n\n**Diagnose:** inspect stored history and comparable evidence. Explain what\nchanged separately from why it might have changed. A hypothesis is not a\nmeasured cause. Propose bounded verification if stored evidence is insufficient.\n\n**Prospecting:** generate a one-shot company snapshot without creating a project.\nInspect stored provider settings first. Agree on the company, domain, selected\nproviders, and queries before starting the quota-spending snapshot action.\nBrowser-only selection requires manual queries. Progressive stdio help offers\nthe discovery toolkit when this connection permits snapshots; load it, then\ncall help again. Fixed catalogs offer only already available actions. Read-only\nand restricted connections must not bypass missing snapshot access.\n\n**Measurement:** inspect the existing setup and results before proposing edits.\nKeep research, query tracking, plan publication, and sweep execution separate.\nFor direct research, submit the final editable query text in one context. For a\nreviewed batch, submit each explicit destination with its final text and one\nidempotency key. Pattern substitution happens in the client before either\nrequest; choosing a market or Property records a destination only and never\nrewrites a query or creates an automatic fan-out. `research.run` does not\nauthorize saving patterns, changing tracking, publishing plans, or settings.\nUse a supported preview where available, inspect its exact destination and\nrevision, then seek approval for the actual change. A preview may itself require\nwrite permission; never treat a dry-run flag as a universal safety guarantee.\n\n**Integrations:** inspect stored connection state and snapshot freshness first.\nProvider configuration evidence does not prove a browser event fired or a\nconversion was recorded. Connection, resource selection, refresh/sync, and live\nreads are separate actions. Credentials belong in the operator's secure setup\nflow, never in chat, tool arguments, reports, or public guidance.\n\n**Reports:** use saved evidence for the requested period and scope. Keep mention\nand citation signals separate, include dates and sample sizes, and state missing\nor stale inputs. For Advanced Property mention rankings, use\n`canonry_measurement_portfolio_summary` and its `mentionRanking.strongest`,\n`.weakest`, and `.excluded` lists. It defaults to non-brand questions; state the\nreturned class and report branded results separately. An unavailable portfolio\naggregate does not invalidate available Property mention rates. Flag excluded\nProperties individually; do not silently replace mention ranking with citation\nranking. Keep sample sizes and ties visible. Preparing a report does not\nauthorize new measurement.\n\n## Authority and approval\n\n### Agent operations\n\nUse `canonry_key_self` to inspect the current credential's scopes and project\nboundary without exposing its token. `canonry_settings_get` and\n`canonry_telemetry_get` describe the connected server, not the agent's local\nmachine. Telemetry reports configured preference, effective state, and any\nenvironment override; inspecting status never creates an anonymous identifier.\nAfter approval, `canonry_telemetry_update` changes that preference and\n`canonry_provider_settings_update` changes an already-configured provider's\nmodel/quota. Both require `settings.write`; neither accepts credentials.\n\n`canonry_logs_list` reads bounded, redacted runtime events from both the\napplication logger and Fastify request/error logging. It requires an\ninstance-wide `logs.read` grant (or wildcard), and\nadmin role for signed-in users. Project-scoped keys cannot use it, even with a\nproject filter. A `logs.read`-only key is read-only automatically, without a\nsecond `read` marker. Named `*.read` scopes cannot grant mutations; an explicit\nwrite grant is needed and remains subject to its route gates. Returned messages\nare sanitized and bounded; raw request or response bodies, headers, cookies,\nprovider payloads, and stacks are not\npart of the queryable surface. The same secret-redaction policy runs before\nconsole output and storage. Do not deliberately log secrets: redaction is a\ndefense in depth, not permission to put credentials into diagnostic strings.\nOpaque escaped payloads containing secret assignments are omitted when safe\npartial masking cannot be guaranteed; correlate their retained error codes and IDs.\n\nFile-backed hosts retain runtime logs in SQLite across restarts, bounded to\n10,000 events and seven days. In-memory hosts report `retention: \"process\"`.\nFilter by `actor`, `requestId`, `runId`, `projectId`, `module`, `level`, or an\ninclusive `since`/`until` interval. Keep filters unchanged when resuming an\nopaque cursor; retention eviction can invalidate it. Inspect `retentionPolicy`,\n`captureErrors`, `dropped`, `truncated`, and `retention` before drawing\nconclusions. Missing logs are not proof that an action did not happen. Use\n`canonry_project_history` or `canonry_history_global` for persistent audit events;\noffset pages have deterministic ordering but are not snapshots of concurrent writes.\n\nAudit `actor` comes from authenticated identity (`user:<id>` or `api-key:<id>`),\nnot a caller-supplied header. A delegated MCP credential records its originating\nuser as actor and the actual credential in `credentialId`. `requestId` correlates\nHTTP events; `userAgent` and `actorSession` are bounded, untrusted client hints,\nnever identity or permission grants. Older audit rows are not backfilled with\nidentities the server cannot prove.\n\nBoth shipped HTTP hosts issue restart-safe UUID request IDs and return them in\n`x-request-id`. Use that value to correlate a CLI/API failure with log entries;\nHTTP diagnostics retain the method and route template, not raw URL parameters.\nRequest-bound loggers retain completion attribution, while generic background\ncontinuations stop inheriting caller identity after the response completes.\nCapture covers the owning server process after initialization, not arbitrary\nconsole output, other worker processes, or host/container logs. Run one server\ninstance per process and database, as required by the single-tenant deployment\nmodel; this is not a cross-tenant or distributed log collector.\n\nFor CLI use, settings reads are remote. Google setup and telemetry retain their\nlocal defaults: pass `--target server` explicitly to configure the connected\nserver. `schedule list <project>` lists all schedule kinds, and\n`notify events --target server` discovers the server's event catalog.\n\nMCP returns legacy text JSON plus structured results. Objects keep their shape;\narrays use `{items: [...]}` in `structuredContent`, and scalars use `{value: ...}`.\nErrors preserve the existing envelope and CLI exit codes: HTTP 4xx (including\n429 policy limits) use exit 1; HTTP 5xx use exit 2. Server-provided `Retry-After`\nand request IDs are exposed as `retryAfterMs` and `requestId` when available;\nclients do not infer retryability from HTTP 429 or retry automatically.\nFor a write with an ambiguous outcome, inspect saved state or its receipt before\nretrying; a retry hint is not proof that repeating a write is safe.\n\n### Action boundaries\n\nStart with stored evidence. Before a live provider read, sweep, probe, research\nrun, sync, write, or externally visible action, obtain approval covering its\nexact target, action, and bounded work. Approval already given for that exact\noperation need not be asked for again, but does not extend to more projects,\nlarger batches, retries with new identities, or recurring work.\n\nHTTP GET and MCP `readOnlyHint` describe aspects of an operation, not its cost\nor permission. Provider discovery, account reads, and live diagnostics may\nconsume quota even when labeled read-only. If the tool's effect is unclear,\ninspect its description and request direction before calling it.\n\nAuthentication, role/scope checks, project restrictions, quotas, and guarded\napproval receipts are enforced by the server. Help, skills, resources, and tool\nvisibility cannot grant authority. Never change credentials, endpoints, or\nproject identifiers to work around a missing tool or a `403` response.\n\nFor guarded ads writes, inspect unresolved operation receipts before retrying.\nUse the receipt's supported recovery action; do not replay a mutation under a\nnew identity. An executor cannot create or widen its own human approval grant.\nOn ambiguous results, exhausted bounds, or refusal, stop and report what is\nknown and what permission or operator action is needed.\n\n## Version and source\n\nThis public, versioned document is the source for initialization guidance,\nintent routes, the optional resource, and generated Canonry `SKILL.md` files.\nGuide v1 may receive compatible clarifications; incompatible routing contracts\nrequire a new guide version. The running server's help describes its actual\ncatalog and remains usable without fetching this document.\n"
13076
+ "markdown": "# Canonry Operations Guide v1\n\nCanonry is an agent-first AI visibility platform. MCP is the universal entry\npoint for connected agents. Host-native skills are optional upgrades, not a\nprerequisite or a permission mechanism.\n\n## Connect and choose a route\n\nRead the initialization guidance, then call `canonry_help` with an `intent`:\n`status`, `diagnose`, `operations`, `prospecting`, `measurement`, `integrations`,\n`reports`, or a short task\ndescription. Select an accessible project with `canonry_projects_list` before\nusing its exact name in project tools. Inspect each listed tool's input schema;\nhelp suggests tool names, not invented arguments or authorization.\n\nHelp returns a versioned, compact route: connection `mode`, available `next`\ntools, workflow guidance, approval boundaries, and this guide's URL. It performs\nno provider calls, reads no project data, and changes no permissions.\n`next` lists stored reads. Optional `actions` lists loaded tools for work that\nrequires approval; listing an action does not authorize or execute it.\n`includeCatalog: true` additionally returns toolkit details when needed.\n\nHosted connections use a fixed catalog. Help only suggests tools offered by that\nconnection; it never tells a hosted agent to dynamically load a toolkit. A\nprogressive local stdio connection may return `loadToolkits`: call\n`canonry_load_toolkit` with one returned name, await it, then call help again.\nLoading only changes local tool discovery, never server authority.\n\nThe optional `canonry://agent-operations/v1` MCP resource contains this same\nguide. If the host cannot read resources or open links, continue through help.\nDo not install a plugin, local runtime, or skill merely to use connected MCP.\nAn installed Codex or Claude Canonry skill contains a generated copy of this\nguide plus links to host-native references. It does not replace runtime help.\n\n## Vocabulary and evidence\n\n- **Mentioned** means the brand appears in answer text. **Cited** means its\n domain appears in source links. Either, both, or neither can occur; never\n compute one signal from the other.\n- `answerMentioned: null` means not checked, not false. Missing runs and empty\n populations mean no measurement, not zero visibility.\n- Preserve project, time window, provider, requested/served model, location,\n sample size, and query class when comparing evidence. Use server-returned\n metrics; do not invent a score from incompatible populations.\n- Simple projects and Advanced portfolios share the workflow. For Advanced\n results, preserve Property, Target, market, plan revision, and class scope.\n Groups organize navigation; do not infer an unrequested fan-out.\n- Research is isolated evidence, not tracked measurement. A probe still spends\n quota and persists evidence but is excluded from normal tracking metrics.\n\n## Workflows\n\n**Status:** read the stored overview and freshness first. Say when evidence is\nmissing instead of silently creating it.\n\n**Diagnose:** inspect stored history and comparable evidence. Explain what\nchanged separately from why it might have changed. A hypothesis is not a\nmeasured cause. Propose bounded verification if stored evidence is insufficient.\n\n**Prospecting:** generate a one-shot company snapshot without creating a project.\nInspect stored provider settings first. Agree on the company, domain, selected\nproviders, and queries before starting the quota-spending snapshot action.\nBrowser-only selection requires manual queries. Progressive stdio help offers\nthe discovery toolkit when this connection permits snapshots; load it, then\ncall help again. Fixed catalogs offer only already available actions. Read-only\nand restricted connections must not bypass missing snapshot access.\n\n**Measurement:** inspect the existing setup and results before proposing edits.\nKeep research, query tracking, plan publication, and sweep execution separate.\nFor direct research, submit the final editable query text in one context. For a\nreviewed batch, submit each explicit destination with its final text and one\nidempotency key. Pattern substitution happens in the client before either\nrequest; choosing a market or Property records a destination only and never\nrewrites a query or creates an automatic fan-out. `research.run` does not\nauthorize saving patterns, changing tracking, publishing plans, or settings.\nUse a supported preview where available, inspect its exact destination and\nrevision, then seek approval for the actual change. A preview may itself require\nwrite permission; never treat a dry-run flag as a universal safety guarantee.\n\n**Integrations:** inspect stored connection state and snapshot freshness first.\nProvider configuration evidence does not prove a browser event fired or a\nconversion was recorded. Connection, resource selection, refresh/sync, and live\nreads are separate actions. Credentials belong in the operator's secure setup\nflow, never in chat, tool arguments, reports, or public guidance.\n\n**Reports:** use saved evidence for the requested period and scope. Keep mention\nand citation signals separate, include dates and sample sizes, and state missing\nor stale inputs. For Advanced Property mention rankings, use\n`canonry_measurement_portfolio_summary` and its `mentionRanking.strongest`,\n`.weakest`, and `.excluded` lists. It defaults to non-brand questions; state the\nreturned class and report branded results separately. An unavailable portfolio\naggregate does not invalidate available Property mention rates. Flag excluded\nProperties individually; do not silently replace mention ranking with citation\nranking. Keep sample sizes and ties visible. Preparing a report does not\nauthorize new measurement.\n\n## Authority and approval\n\n### Agent operations\n\nUse `canonry_key_self` (CLI `canonry key whoami --format json`) to inspect the\ncurrent credential's scopes, project boundary, and host-derived `operator`\nauthority without exposing its token. Missing `operator` means unapproved.\n`canonry_settings_get` and\n`canonry_telemetry_get` describe the connected server, not the agent's local\nmachine. Telemetry reports configured preference, effective state, and any\nenvironment override; inspecting status never creates an anonymous identifier.\nAfter approval, `canonry_telemetry_update` changes that preference and\n`canonry_provider_settings_update` changes an already-configured provider's\nmodel/quota. Both require `settings.write`; neither accepts credentials.\nServer telemetry reads and updates additionally require operator authority.\nOrdinary audit-history reads omit internal telemetry events and their state.\n\nOperator authority is deny-by-default and separate from customer admin roles.\nThe deployment owner must approve a dedicated, instance-wide API key's ID in\nthe server environment variable `CANONRY_OPERATOR_KEY_IDS` (comma-separated IDs),\nthen restart the server. Empty/unset approves nobody; wildcards are invalid.\nKeep the bearer private to internal operators; never approve a customer-held or\nshared proxy/bootstrap key. Use `logs.read` for read-only diagnostics, adding\n`settings.write` only when telemetry control is required. Ordinary key creation,\naccount roles, OAuth consent, and caller headers cannot grant operator status.\nRevoking an approved key invalidates it immediately. Host enrollment is a trust\nbootstrap step, intentionally unavailable through customer-facing APIs.\nAPI, CLI, and MCP enforce the same boundary; MCP hides internal tools unless\nthe server confirms operator authority, including in explicit read-only mode.\nProject analytics, research, and normal project permissions are unchanged.\n\n`canonry_logs_list` reads bounded, redacted runtime events from both the\napplication logger and Fastify request/error logging. It requires an\ninstance-wide `logs.read` grant (or wildcard) and a host-approved direct bearer.\nBrowser sessions, OAuth/delegated credentials, customer admins, and project-scoped\nkeys cannot use it, even with a project filter or a matching allowlist ID.\nA `logs.read`-only key is read-only automatically, without a\nsecond `read` marker. Named `*.read` scopes cannot grant mutations; an explicit\nwrite grant is needed and remains subject to its route gates. Returned messages\nare sanitized and bounded; raw request or response bodies, headers, cookies,\nprovider payloads, and stacks are not\npart of the queryable surface. The same secret-redaction policy runs before\nconsole output and storage. Do not deliberately log secrets: redaction is a\ndefense in depth, not permission to put credentials into diagnostic strings.\nOpaque escaped payloads containing secret assignments are omitted when safe\npartial masking cannot be guaranteed; correlate their retained error codes and IDs.\n\nFile-backed hosts retain runtime logs in SQLite across restarts, bounded to\n10,000 events and seven days. In-memory hosts report `retention: \"process\"`.\nFilter by `actor`, `requestId`, `runId`, `projectId`, `module`, `level`, or an\ninclusive `since`/`until` interval. Keep filters unchanged when resuming an\nopaque cursor; retention eviction can invalidate it. Inspect `retentionPolicy`,\n`captureErrors`, `dropped`, `truncated`, and `retention` before drawing\nconclusions. Missing logs are not proof that an action did not happen. Use\n`canonry_project_history` or `canonry_history_global` for persistent audit events;\noffset pages have deterministic ordering but are not snapshots of concurrent writes.\n\nAudit `actor` comes from authenticated identity (`user:<id>` or `api-key:<id>`),\nnot a caller-supplied header. A delegated MCP credential records its originating\nuser as actor and the actual credential in `credentialId`. `requestId` correlates\nHTTP events; `userAgent` and `actorSession` are bounded, untrusted client hints,\nnever identity or permission grants. Older audit rows are not backfilled with\nidentities the server cannot prove.\n\nBoth shipped HTTP hosts issue restart-safe UUID request IDs and return them in\n`x-request-id`. Use that value to correlate a CLI/API failure with log entries;\nHTTP diagnostics retain the method and route template, not raw URL parameters.\nRequest-bound loggers retain completion attribution, while generic background\ncontinuations stop inheriting caller identity after the response completes.\nCapture covers the owning server process after initialization, not arbitrary\nconsole output, other worker processes, or host/container logs. Run one server\ninstance per process and database, as required by the single-tenant deployment\nmodel; this is not a cross-tenant or distributed log collector.\n\nFor CLI use, settings reads are remote. Google setup and telemetry retain their\nlocal defaults: pass `--target server` explicitly to configure the connected\nserver. `schedule list <project>` lists all schedule kinds, and\n`notify events --target server` discovers the server's event catalog.\n\nMCP returns legacy text JSON plus structured results. Objects keep their shape;\narrays use `{items: [...]}` in `structuredContent`, and scalars use `{value: ...}`.\nErrors preserve the existing envelope and CLI exit codes: HTTP 4xx (including\n429 policy limits) use exit 1; HTTP 5xx use exit 2. Server-provided `Retry-After`\nand request IDs are exposed as `retryAfterMs` and `requestId` when available;\nclients do not infer retryability from HTTP 429 or retry automatically.\nFor a write with an ambiguous outcome, inspect saved state or its receipt before\nretrying; a retry hint is not proof that repeating a write is safe.\n\n### Action boundaries\n\nStart with stored evidence. Before a live provider read, sweep, probe, research\nrun, sync, write, or externally visible action, obtain approval covering its\nexact target, action, and bounded work. Approval already given for that exact\noperation need not be asked for again, but does not extend to more projects,\nlarger batches, retries with new identities, or recurring work.\n\nHTTP GET and MCP `readOnlyHint` describe aspects of an operation, not its cost\nor permission. Provider discovery, account reads, and live diagnostics may\nconsume quota even when labeled read-only. If the tool's effect is unclear,\ninspect its description and request direction before calling it.\n\nAuthentication, role/scope checks, project restrictions, quotas, and guarded\napproval receipts are enforced by the server. Help, skills, resources, and tool\nvisibility cannot grant authority. Never change credentials, endpoints, or\nproject identifiers to work around a missing tool or a `403` response.\n\nFor guarded ads writes, inspect unresolved operation receipts before retrying.\nUse the receipt's supported recovery action; do not replay a mutation under a\nnew identity. An executor cannot create or widen its own human approval grant.\nOn ambiguous results, exhausted bounds, or refusal, stop and report what is\nknown and what permission or operator action is needed.\n\n## Version and source\n\nThis public, versioned document is the source for initialization guidance,\nintent routes, the optional resource, and generated Canonry `SKILL.md` files.\nGuide v1 may receive compatible clarifications; incompatible routing contracts\nrequire a new guide version. The running server's help describes its actual\ncatalog and remains usable without fetching this document.\n"
13067
13077
  };
13068
13078
 
13069
13079
  // src/mcp/operations-guide.ts
@@ -13117,7 +13127,7 @@ function createCanonryMcpServerWithCatalog(options = {}) {
13117
13127
  });
13118
13128
  server.validateToolInput = async (_tool, args) => args;
13119
13129
  const entries = [];
13120
- for (const registryTool of getCanonryMcpTools(scope, options.tiers, options.credentialScopes)) {
13130
+ for (const registryTool of getCanonryMcpTools(scope, options.tiers, options.credentialScopes, options.operator)) {
13121
13131
  const tool = registryTool;
13122
13132
  const handler = tool.handler;
13123
13133
  const registered = server.registerTool(
@@ -13189,10 +13199,11 @@ function registerMetaTools(server, catalog, opts) {
13189
13199
  })
13190
13200
  );
13191
13201
  }
13192
- function getCanonryMcpTools(scope = "all", tiers, credentialScopes) {
13202
+ function getCanonryMcpTools(scope = "all", tiers, credentialScopes, operator = false) {
13193
13203
  const readOnly = scope === "read-only" || credentialScopes !== void 0 && isReadOnlyKey(credentialScopes);
13194
13204
  const restricted = credentialScopes && restrictedWriteScopes(credentialScopes);
13195
- const byScope = readOnly ? canonryMcpTools.filter((tool) => tool.access === "read") : canonryMcpTools.filter((tool) => {
13205
+ const authorized = canonryMcpTools.filter((tool) => !tool.requiresOperator || operator);
13206
+ const byScope = readOnly ? authorized.filter((tool) => tool.access === "read") : authorized.filter((tool) => {
13196
13207
  if (!restricted || tool.access === "read") return true;
13197
13208
  if (tool.requiredScope && restricted.includes(tool.requiredScope)) return true;
13198
13209
  return restricted.some((grant) => grant !== RESEARCH_RUN_SCOPE) && tool.tier === "ads";
@@ -13582,6 +13593,7 @@ function parseSkillsClient(value) {
13582
13593
 
13583
13594
  export {
13584
13595
  dashboardManagedRunKindsSchema,
13596
+ resolveOperatorApiKeyIds,
13585
13597
  getBootstrapEnv,
13586
13598
  isMachineFormat,
13587
13599
  EXIT_USER_ERROR,
package/dist/cli.js CHANGED
@@ -29,11 +29,11 @@ import {
29
29
  trackCliCommandFinished,
30
30
  trackEvent,
31
31
  waitForServerRuntimeStartup
32
- } from "./chunk-H3RVNMOO.js";
32
+ } from "./chunk-GMNZNLVX.js";
33
33
  import {
34
34
  autoSyncSkills,
35
35
  formatAutoSyncNotice
36
- } from "./chunk-LJKAB4CX.js";
36
+ } from "./chunk-66KGNC4U.js";
37
37
  import {
38
38
  CliError,
39
39
  EXIT_SYSTEM_ERROR,
@@ -59,7 +59,7 @@ import {
59
59
  saveConfigPatch,
60
60
  systemError,
61
61
  usageError
62
- } from "./chunk-B2XM6AQ6.js";
62
+ } from "./chunk-MEQGGODM.js";
63
63
  import {
64
64
  CLOUDFLARE_WORKER_BINDINGS,
65
65
  CLOUDFLARE_WORKER_GENERATED_MARKER,
@@ -73,7 +73,7 @@ import {
73
73
  projects,
74
74
  queries,
75
75
  renderReportHtml
76
- } from "./chunk-UMU3IBXM.js";
76
+ } from "./chunk-LHHJVGH7.js";
77
77
  import {
78
78
  AdsDeliverySnapshotStatuses,
79
79
  AdsHistoricalCampaignRollupStatuses,
@@ -152,7 +152,7 @@ import {
152
152
  snapshotProviderModeSchema,
153
153
  visibilityReportRequestSchema,
154
154
  winnabilityClassSchema
155
- } from "./chunk-3WODA4JF.js";
155
+ } from "./chunk-3DL3KV6C.js";
156
156
 
157
157
  // src/cli.ts
158
158
  import { pathToFileURL } from "url";
@@ -9235,6 +9235,7 @@ async function showApiKeySelf(format) {
9235
9235
  console.log(`API key "${key.name}" (${key.keyPrefix})`);
9236
9236
  console.log(` Scopes: ${key.scopes.join(", ")}`);
9237
9237
  console.log(` Read-only: ${key.readOnly ? "yes" : "no"}`);
9238
+ console.log(` Operator: ${key.operator === true ? "yes" : "no"}`);
9238
9239
  console.log(` Reach: ${keyReach(key)}`);
9239
9240
  console.log(` Status: ${keyStatus(key)}`);
9240
9241
  }
package/dist/index.js CHANGED
@@ -3,12 +3,12 @@ import {
3
3
  createGoogleMarketingCredentialStore,
4
4
  createGoogleMarketingRuntime,
5
5
  createServer
6
- } from "./chunk-H3RVNMOO.js";
6
+ } from "./chunk-GMNZNLVX.js";
7
7
  import {
8
8
  loadConfig
9
- } from "./chunk-B2XM6AQ6.js";
10
- import "./chunk-UMU3IBXM.js";
11
- import "./chunk-3WODA4JF.js";
9
+ } from "./chunk-MEQGGODM.js";
10
+ import "./chunk-LHHJVGH7.js";
11
+ import "./chunk-3DL3KV6C.js";
12
12
  export {
13
13
  GoogleMarketingRuntimeError,
14
14
  createGoogleMarketingCredentialStore,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  IntelligenceService
3
- } from "./chunk-UMU3IBXM.js";
4
- import "./chunk-3WODA4JF.js";
3
+ } from "./chunk-LHHJVGH7.js";
4
+ import "./chunk-3DL3KV6C.js";
5
5
  export {
6
6
  IntelligenceService
7
7
  };
package/dist/mcp.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  autoSyncSkills
3
- } from "./chunk-LJKAB4CX.js";
3
+ } from "./chunk-66KGNC4U.js";
4
4
  import {
5
5
  createApiClient,
6
6
  createCanonryMcpServer
7
- } from "./chunk-B2XM6AQ6.js";
7
+ } from "./chunk-MEQGGODM.js";
8
8
  import {
9
9
  isReadOnlyKey
10
- } from "./chunk-3WODA4JF.js";
10
+ } from "./chunk-3DL3KV6C.js";
11
11
 
12
12
  // src/mcp/cli.ts
13
13
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
@@ -54,19 +54,18 @@ async function resolveEffectiveScope(client, flagScope) {
54
54
  return (await resolveEffectiveAuthorization(client, flagScope)).scope;
55
55
  }
56
56
  async function resolveEffectiveAuthorization(client, flagScope) {
57
- if (flagScope === "read-only") return { scope: "read-only" };
58
57
  try {
59
58
  const self = await client.getApiKeySelf();
60
59
  if (isReadOnlyKey(self.scopes)) {
61
60
  process.stderr.write(
62
61
  "canonry-mcp: configured API key is read-only \u2014 restricting to read tools.\n"
63
62
  );
64
- return { scope: "read-only", credentialScopes: self.scopes };
63
+ return { scope: "read-only", credentialScopes: self.scopes, operator: self.operator === true };
65
64
  }
66
- return { scope: flagScope, credentialScopes: self.scopes };
65
+ return { scope: flagScope, credentialScopes: self.scopes, operator: self.operator === true };
67
66
  } catch {
68
67
  }
69
- return { scope: flagScope };
68
+ return { scope: flagScope, operator: false };
70
69
  }
71
70
  function parseCliOptions(argv, env = process.env) {
72
71
  if (argv.includes("--help") || argv.includes("-h")) {
package/package.json CHANGED
@@ -1,9 +1,24 @@
1
1
  {
2
2
  "name": "@ainyc/canonry",
3
- "version": "4.195.0",
3
+ "version": "5.0.1",
4
4
  "type": "module",
5
5
  "description": "Self-hosted AI visibility (AEO) platform: track how ChatGPT, Claude, Gemini, and Perplexity cite your domain, join it with Search Console, GA4, server-side traffic, and paid media, and fix what you find through agent tools (CLI, REST, MCP). Local SQLite.",
6
- "license": "FSL-1.1-ALv2",
6
+ "keywords": [
7
+ "aeo",
8
+ "answer-engine-optimization",
9
+ "geo",
10
+ "generative-engine-optimization",
11
+ "ai-visibility",
12
+ "citation-tracking",
13
+ "seo",
14
+ "mcp",
15
+ "chatgpt",
16
+ "claude",
17
+ "gemini",
18
+ "perplexity",
19
+ "self-hosted"
20
+ ],
21
+ "license": "MIT",
7
22
  "homepage": "https://canonry.ai",
8
23
  "repository": {
9
24
  "type": "git",
@@ -34,7 +49,8 @@
34
49
  "assets/",
35
50
  "package.json",
36
51
  "README.md",
37
- "THIRD_PARTY_NOTICES.md"
52
+ "THIRD_PARTY_NOTICES.md",
53
+ "LICENSE"
38
54
  ],
39
55
  "engines": {
40
56
  "node": ">=22.14.0 <27"
@@ -71,31 +87,31 @@
71
87
  "tsup": "^8.5.1",
72
88
  "tsx": "^4.19.0",
73
89
  "@ainyc/canonry-web": "0.0.0",
74
- "@ainyc/canonry-api-client": "0.0.0",
90
+ "@ainyc/canonry-api-routes": "0.0.0",
75
91
  "@ainyc/canonry-config": "0.0.0",
76
92
  "@ainyc/canonry-contracts": "0.0.0",
77
- "@ainyc/canonry-api-routes": "0.0.0",
93
+ "@ainyc/canonry-api-client": "0.0.0",
78
94
  "@ainyc/canonry-db": "0.0.0",
79
95
  "@ainyc/canonry-integration-bing": "0.0.0",
80
96
  "@ainyc/canonry-integration-cloudflare-queue": "0.0.0",
81
- "@ainyc/canonry-integration-cloud-run": "0.0.0",
82
- "@ainyc/canonry-integration-commoncrawl": "0.0.0",
83
97
  "@ainyc/canonry-integration-cloudflare-worker": "0.0.0",
84
- "@ainyc/canonry-integration-google": "0.0.0",
98
+ "@ainyc/canonry-integration-cloud-run": "0.0.0",
85
99
  "@ainyc/canonry-integration-google-ads": "0.0.0",
86
100
  "@ainyc/canonry-integration-google-business-profile": "0.0.0",
101
+ "@ainyc/canonry-integration-commoncrawl": "0.0.0",
87
102
  "@ainyc/canonry-integration-google-places": "0.0.0",
103
+ "@ainyc/canonry-integration-google": "0.0.0",
88
104
  "@ainyc/canonry-integration-google-tag-manager": "0.0.0",
89
105
  "@ainyc/canonry-integration-openai-ads": "0.0.0",
90
106
  "@ainyc/canonry-integration-traffic": "0.0.0",
107
+ "@ainyc/canonry-provider-cdp": "0.0.0",
91
108
  "@ainyc/canonry-integration-wordpress": "0.0.0",
92
109
  "@ainyc/canonry-intelligence": "0.0.0",
93
- "@ainyc/canonry-provider-gemini": "0.0.0",
94
110
  "@ainyc/canonry-provider-claude": "0.0.0",
111
+ "@ainyc/canonry-provider-gemini": "0.0.0",
95
112
  "@ainyc/canonry-provider-local": "0.0.0",
96
- "@ainyc/canonry-provider-cdp": "0.0.0",
97
- "@ainyc/canonry-provider-perplexity": "0.0.0",
98
- "@ainyc/canonry-provider-openai": "0.0.0"
113
+ "@ainyc/canonry-provider-openai": "0.0.0",
114
+ "@ainyc/canonry-provider-perplexity": "0.0.0"
99
115
  },
100
116
  "scripts": {
101
117
  "build": "pnpm run build:cli && pnpm run build:web",