@ainyc/canonry 4.190.1 → 4.192.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.
- package/assets/agent-workspace/skills/canonry/SKILL.md +124 -216
- package/assets/assets/{AuditHistoryPanel-Dob_85ay.js → AuditHistoryPanel-C7MwfCl9.js} +1 -1
- package/assets/assets/{BacklinksPage-BDm4gQsa.js → BacklinksPage-1Nq1zbRk.js} +1 -1
- package/assets/assets/{ChartPrimitives-DLEICrrL.js → ChartPrimitives-Bxa_vFmq.js} +1 -1
- package/assets/assets/{HistoryPage-BUGJKNWJ.js → HistoryPage-BNACyEiz.js} +1 -1
- package/assets/assets/MeasurementPropertyPage-BqjpIYAw.js +1 -0
- package/assets/assets/ProjectPage-BhBzznlv.js +8 -0
- package/assets/assets/{RunRow-Cja3vahD.js → RunRow-DINPo5ES.js} +1 -1
- package/assets/assets/{RunsPage-BdVfLW9Z.js → RunsPage-BFuDLm7p.js} +1 -1
- package/assets/assets/{SettingsPage-Xw9rdDPd.js → SettingsPage-CkqmyTSK.js} +1 -1
- package/assets/assets/SiteHealthSection-DzFKj9lX.js +4 -0
- package/assets/assets/{TrafficPage-D5ZqJrJm.js → TrafficPage-CkIGVLET.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-DB5V8cdH.js → TrafficSourceDetailPage-CTmn_FmZ.js} +1 -1
- package/assets/assets/{extract-error-message-lzuarNEg.js → extract-error-message-CC2kxd3e.js} +1 -1
- package/assets/assets/{index-BjjM151x.css → index-BtTEcbcB.css} +1 -1
- package/assets/assets/{index-YVHujfy1.js → index-CCPMPGar.js} +26 -26
- package/assets/assets/{react-sigma_core.esm.min-Ddu-c40B.js → react-sigma_core.esm.min-DkpQa1sf.js} +1 -1
- package/assets/assets/{vendor-lucide-dNHw1I5G.js → vendor-lucide-CW2qe0uH.js} +1 -1
- package/assets/assets/{vendor-markdown-9tTeP8v7.js → vendor-markdown-B-Oq2NYq.js} +1 -1
- package/assets/assets/{vendor-radix-BpmvLvpp.js → vendor-radix-twS1M3FF.js} +1 -1
- package/assets/assets/{vendor-recharts-FA0uySU7.js → vendor-recharts-D-cUuLZo.js} +1 -1
- package/assets/assets/{vendor-tanstack-CYBjbqVr.js → vendor-tanstack-ZXXkndVj.js} +1 -1
- package/assets/index.html +7 -7
- package/dist/{chunk-2II4ZMMH.js → chunk-32Q2NZ4S.js} +2 -2
- package/dist/{chunk-32QBVRMN.js → chunk-36RKISAI.js} +213 -32
- package/dist/{chunk-ROPJUNQN.js → chunk-BULKBROE.js} +1368 -1223
- package/dist/{chunk-ECPN4OUR.js → chunk-FTKZAOFD.js} +649 -249
- package/dist/{chunk-BE366UCM.js → chunk-JOSSB4QC.js} +73 -22
- package/dist/cli.js +65 -10
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-QCKX2W4G.js → intelligence-service-MEQ5VX5L.js} +2 -2
- package/dist/mcp.js +13 -8
- package/package.json +11 -11
- package/assets/assets/MeasurementPropertyPage-H2g4VdcA.js +0 -1
- package/assets/assets/ProjectPage-d7iOSkrd.js +0 -8
- package/assets/assets/SiteHealthSection-CjioXMWy.js +0 -4
package/assets/index.html
CHANGED
|
@@ -12,14 +12,14 @@
|
|
|
12
12
|
<link rel="icon" type="image/png" sizes="32x32" href="./favicon-32.png" />
|
|
13
13
|
<link rel="apple-touch-icon" href="./apple-touch-icon.png" />
|
|
14
14
|
<title>Canonry</title>
|
|
15
|
-
<script type="module" crossorigin src="./assets/index-
|
|
16
|
-
<link rel="modulepreload" crossorigin href="./assets/vendor-tanstack-
|
|
17
|
-
<link rel="modulepreload" crossorigin href="./assets/vendor-radix-
|
|
18
|
-
<link rel="modulepreload" crossorigin href="./assets/vendor-recharts-
|
|
19
|
-
<link rel="modulepreload" crossorigin href="./assets/vendor-lucide-
|
|
20
|
-
<link rel="modulepreload" crossorigin href="./assets/vendor-markdown-
|
|
15
|
+
<script type="module" crossorigin src="./assets/index-CCPMPGar.js"></script>
|
|
16
|
+
<link rel="modulepreload" crossorigin href="./assets/vendor-tanstack-ZXXkndVj.js">
|
|
17
|
+
<link rel="modulepreload" crossorigin href="./assets/vendor-radix-twS1M3FF.js">
|
|
18
|
+
<link rel="modulepreload" crossorigin href="./assets/vendor-recharts-D-cUuLZo.js">
|
|
19
|
+
<link rel="modulepreload" crossorigin href="./assets/vendor-lucide-CW2qe0uH.js">
|
|
20
|
+
<link rel="modulepreload" crossorigin href="./assets/vendor-markdown-B-Oq2NYq.js">
|
|
21
21
|
<link rel="modulepreload" crossorigin href="./assets/vendor-yaml-GWJz5H2G.js">
|
|
22
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
22
|
+
<link rel="stylesheet" crossorigin href="./assets/index-BtTEcbcB.css">
|
|
23
23
|
</head>
|
|
24
24
|
<body>
|
|
25
25
|
<div id="root"></div>
|
|
@@ -5,11 +5,11 @@ import {
|
|
|
5
5
|
installSkills,
|
|
6
6
|
loadConfigRaw,
|
|
7
7
|
saveConfigPatch
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-36RKISAI.js";
|
|
9
9
|
import {
|
|
10
10
|
SKILL_MANIFEST_FILENAME,
|
|
11
11
|
SkillsClients
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-BULKBROE.js";
|
|
13
13
|
|
|
14
14
|
// src/skills-autosync.ts
|
|
15
15
|
import fs from "fs";
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
DISCOVERY_MAX_PROBES_CAP,
|
|
7
7
|
DISCOVERY_PROBE_CONCURRENCY_CAP,
|
|
8
8
|
GOOGLE_MARKETING_STORED_SNAPSHOT_PAGE_MAX,
|
|
9
|
+
RESEARCH_RUN_SCOPE,
|
|
9
10
|
SKILL_MANIFEST_FILENAME,
|
|
10
11
|
SkillsClients,
|
|
11
12
|
adsActivateTreeRequestSchema,
|
|
@@ -36,6 +37,7 @@ import {
|
|
|
36
37
|
gaMeasurementHostScopeSchema,
|
|
37
38
|
googleAdsMetricsWindowSchema,
|
|
38
39
|
gscPerformanceOrderBySchema,
|
|
40
|
+
isReadOnlyKey,
|
|
39
41
|
keywordBatchRequestSchema,
|
|
40
42
|
keywordGenerateRequestSchema,
|
|
41
43
|
measurementChangesQuerySchema,
|
|
@@ -88,7 +90,9 @@ import {
|
|
|
88
90
|
queryTrackingCommitRequestSchema,
|
|
89
91
|
queryTrackingPreviewRequestSchema,
|
|
90
92
|
reportPeriodSchema,
|
|
93
|
+
researchBatchCreateSchema,
|
|
91
94
|
researchRunCreateSchema,
|
|
95
|
+
restrictedWriteScopes,
|
|
92
96
|
resultsClearRequestSchema,
|
|
93
97
|
runTriggerRequestSchema,
|
|
94
98
|
schedulableRunKindSchema,
|
|
@@ -100,7 +104,7 @@ import {
|
|
|
100
104
|
trafficEventKindSchema,
|
|
101
105
|
trafficSeriesGranularitySchema,
|
|
102
106
|
visibilityReportRequestSchema
|
|
103
|
-
} from "./chunk-
|
|
107
|
+
} from "./chunk-BULKBROE.js";
|
|
104
108
|
|
|
105
109
|
// src/cli-error.ts
|
|
106
110
|
function isMachineFormat(format) {
|
|
@@ -2316,6 +2320,22 @@ var postApiV1ProjectsByNameResearchRuns = (options) => {
|
|
|
2316
2320
|
}
|
|
2317
2321
|
});
|
|
2318
2322
|
};
|
|
2323
|
+
var postApiV1ProjectsByNameResearchBatches = (options) => {
|
|
2324
|
+
return (options.client ?? client).post({
|
|
2325
|
+
security: [
|
|
2326
|
+
{
|
|
2327
|
+
scheme: "bearer",
|
|
2328
|
+
type: "http"
|
|
2329
|
+
}
|
|
2330
|
+
],
|
|
2331
|
+
url: "/api/v1/projects/{name}/research/batches",
|
|
2332
|
+
...options,
|
|
2333
|
+
headers: {
|
|
2334
|
+
"Content-Type": "application/json",
|
|
2335
|
+
...options.headers
|
|
2336
|
+
}
|
|
2337
|
+
});
|
|
2338
|
+
};
|
|
2319
2339
|
var getApiV1ProjectsByNameQueryTracking = (options) => {
|
|
2320
2340
|
return (options.client ?? client).get({
|
|
2321
2341
|
security: [
|
|
@@ -8093,12 +8113,20 @@ var ApiClient = class {
|
|
|
8093
8113
|
})
|
|
8094
8114
|
);
|
|
8095
8115
|
}
|
|
8116
|
+
/** Atomically accept reviewed destinations with a shared retry identity. */
|
|
8117
|
+
async startResearchBatch(project, request) {
|
|
8118
|
+
return this.invoke(() => postApiV1ProjectsByNameResearchBatches({
|
|
8119
|
+
client: this.heyClient,
|
|
8120
|
+
path: { name: project },
|
|
8121
|
+
body: request
|
|
8122
|
+
}));
|
|
8123
|
+
}
|
|
8096
8124
|
async listResearchRuns(project, opts) {
|
|
8097
8125
|
return this.invoke(
|
|
8098
8126
|
() => getApiV1ProjectsByNameResearchRuns({
|
|
8099
8127
|
client: this.heyClient,
|
|
8100
8128
|
path: { name: project },
|
|
8101
|
-
query: { limit: opts?.limit !== void 0 ? String(opts.limit) : void 0 }
|
|
8129
|
+
query: { limit: opts?.limit !== void 0 ? String(opts.limit) : void 0, cursor: opts?.cursor }
|
|
8102
8130
|
})
|
|
8103
8131
|
);
|
|
8104
8132
|
}
|
|
@@ -9557,7 +9585,12 @@ var researchRunStartInputSchema = z4.object({
|
|
|
9557
9585
|
});
|
|
9558
9586
|
var researchRunsListInputSchema = z4.object({
|
|
9559
9587
|
project: projectNameSchema,
|
|
9560
|
-
limit: z4.number().int().positive().max(100).optional().describe("Max saved research runs returned. Default 20.")
|
|
9588
|
+
limit: z4.number().int().positive().max(100).optional().describe("Max saved research runs returned. Default 20."),
|
|
9589
|
+
cursor: z4.string().min(1).optional().describe("Opaque cursor from the previous page.")
|
|
9590
|
+
});
|
|
9591
|
+
var researchBatchStartInputSchema = z4.object({
|
|
9592
|
+
project: projectNameSchema,
|
|
9593
|
+
request: researchBatchCreateSchema.describe("Reviewed concrete runs, at most 20 destinations and 50 total queries. Specify provider, model and location (null means none) for every run. Pin the plan revision for each market or Property. Reuse the same idempotencyKey and unchanged request after an uncertain response.")
|
|
9561
9594
|
});
|
|
9562
9595
|
var researchRunIdInputSchema = z4.object({
|
|
9563
9596
|
project: projectNameSchema,
|
|
@@ -11501,6 +11534,7 @@ var canonryMcpTools = [
|
|
|
11501
11534
|
}),
|
|
11502
11535
|
defineTool({
|
|
11503
11536
|
name: "canonry_research_run_start",
|
|
11537
|
+
requiredScope: RESEARCH_RUN_SCOPE,
|
|
11504
11538
|
title: "Start research query run",
|
|
11505
11539
|
description: "Run final free-form queries once each against one API provider, with an optional exact model, location, or one configured market or Property destination. Scope never changes query text or fans out a group. Optional template provenance records the source template ID and version; callers must submit the fully expanded, editable final query text. Results retain that destination and provenance for later inspection. This does not add any query to the tracked basket or affect overview tracking.",
|
|
11506
11540
|
access: "write",
|
|
@@ -11510,6 +11544,18 @@ var canonryMcpTools = [
|
|
|
11510
11544
|
openApiOperations: ["POST /api/v1/projects/{name}/research/runs"],
|
|
11511
11545
|
handler: (client2, input) => client2.startResearchRun(input.project, input.request)
|
|
11512
11546
|
}),
|
|
11547
|
+
defineTool({
|
|
11548
|
+
name: "canonry_research_batch_start",
|
|
11549
|
+
requiredScope: RESEARCH_RUN_SCOPE,
|
|
11550
|
+
title: "Start reviewed research across destinations",
|
|
11551
|
+
description: "Accept a reviewed research batch across explicit markets, Properties, or configured locations. Submit fully expanded, editable final queries with explicit provider/model/location for each destination; the API does not expand patterns or groups. All runs are saved together or none are saved, then processed independently. The required idempotencyKey prevents duplicate work on retries; changed input with the same key conflicts. Each run retains its scope, location and optional pattern provenance. Uses paid answer engines, never adds tracked queries or affects visibility measurements.",
|
|
11552
|
+
access: "write",
|
|
11553
|
+
tier: "discovery",
|
|
11554
|
+
inputSchema: researchBatchStartInputSchema,
|
|
11555
|
+
annotations: writeAnnotations({ idempotentHint: true, openWorldHint: true }),
|
|
11556
|
+
openApiOperations: ["POST /api/v1/projects/{name}/research/batches"],
|
|
11557
|
+
handler: (client2, input) => client2.startResearchBatch(input.project, input.request)
|
|
11558
|
+
}),
|
|
11513
11559
|
defineTool({
|
|
11514
11560
|
name: "canonry_research_runs_list",
|
|
11515
11561
|
title: "List research query runs",
|
|
@@ -11519,7 +11565,7 @@ var canonryMcpTools = [
|
|
|
11519
11565
|
inputSchema: researchRunsListInputSchema,
|
|
11520
11566
|
annotations: readAnnotations(),
|
|
11521
11567
|
openApiOperations: ["GET /api/v1/projects/{name}/research/runs"],
|
|
11522
|
-
handler: (client2, input) => client2.listResearchRuns(input.project, input.limit === void 0 ? void 0 : { limit: input.limit })
|
|
11568
|
+
handler: (client2, input) => client2.listResearchRuns(input.project, input.limit === void 0 && input.cursor === void 0 ? void 0 : { limit: input.limit, cursor: input.cursor })
|
|
11523
11569
|
}),
|
|
11524
11570
|
defineTool({
|
|
11525
11571
|
name: "canonry_research_run_get",
|
|
@@ -12600,7 +12646,7 @@ var DynamicToolCatalog = class {
|
|
|
12600
12646
|
loadedToolkits: [...this.loaded].sort(),
|
|
12601
12647
|
coreTools: this.entries.filter((entry) => entry.tool.tier === "core").map((entry) => entry.tool.name),
|
|
12602
12648
|
toolkits: CANONRY_MCP_TOOLKITS.map((toolkit) => this.toolkitEntry(toolkit)).filter((entry) => entry.toolCount > 0),
|
|
12603
|
-
usage: "Call canonry_load_toolkit with one of the toolkit names listed in `toolkits[].name` to register its tools for the rest of this session. Wait for its response before calling any newly enabled tool."
|
|
12649
|
+
usage: this.eager ? "All tools available on this connection are already loaded. Use their listed schemas; tool visibility does not grant server permissions." : "Call canonry_load_toolkit with one of the toolkit names listed in `toolkits[].name` to register its tools for the rest of this session. Wait for its response before calling any newly enabled tool."
|
|
12604
12650
|
};
|
|
12605
12651
|
}
|
|
12606
12652
|
toolkitEntry(toolkit) {
|
|
@@ -12639,28 +12685,139 @@ var DynamicToolCatalog = class {
|
|
|
12639
12685
|
}
|
|
12640
12686
|
};
|
|
12641
12687
|
|
|
12688
|
+
// src/mcp/operations-guide.generated.ts
|
|
12689
|
+
var OPERATIONS_GUIDE = {
|
|
12690
|
+
"guideVersion": "v1",
|
|
12691
|
+
"operationsGuideUrl": "https://github.com/Canonry/canonry/blob/main/docs/agent-operations/v1.md",
|
|
12692
|
+
"resourceUri": "canonry://agent-operations/v1",
|
|
12693
|
+
"initialize": 'Canonry tracks how AI answer engines mention brands and cite domains.\nStart with canonry_help({intent:"status"}), or name your intended workflow. It returns a small route of currently available tools and approval boundaries. Follow its stored-evidence reads before proposing action. No skill, resource reader, plugin installation, or local CLI is required for connected MCP clients. A host-native Canonry skill, if installed, is optional additional guidance.\nmentioned = brand in answer TEXT; cited = domain in SOURCE links. Never compute one from the other. A null answerMentioned means not checked, not false. No recorded sweep means no measured figure.\nGet explicit approval for live provider reads, sweeps, probes, research, syncs, and writes, bounded to the target and requested work. A readOnlyHint or GET is not proof of a free operation. Live ads reads include canonry_ads_account, canonry_ads_geo_search, canonry_ads_live_delivery, canonry_ads_conversion_pixels, canonry_ads_conversion_event_settings. Google live reads/syncs include canonry_google_ads_customers, canonry_gtm_accounts, canonry_gtm_containers, canonry_gtm_workspaces, canonry_google_ads_sync, canonry_gtm_sync.\nHelp and skills grant no permissions. The server enforces authority. On missing tools or 403, report the boundary; do not switch credentials or endpoints to bypass it. Hosted catalogs are fixed; only use canonry_load_toolkit when help explicitly offers it.\n',
|
|
12694
|
+
"approvalBoundary": [
|
|
12695
|
+
"provider reads",
|
|
12696
|
+
"sweeps",
|
|
12697
|
+
"writes"
|
|
12698
|
+
],
|
|
12699
|
+
"approvalRule": "Get explicit approval for the exact target, action, and bounded provider work before crossing a boundary. Existing approval covers only its stated scope; stop on refusal or ambiguous results.",
|
|
12700
|
+
"authority": "Guidance and tool visibility are not permission grants. Server-side roles, scopes, project boundaries, quotas, and approval receipts remain authoritative. Never bypass a refusal with different credentials or endpoints.",
|
|
12701
|
+
"workflows": {
|
|
12702
|
+
"status": {
|
|
12703
|
+
"keywords": [
|
|
12704
|
+
"status",
|
|
12705
|
+
"overview",
|
|
12706
|
+
"health"
|
|
12707
|
+
],
|
|
12708
|
+
"next": [
|
|
12709
|
+
"canonry_projects_list",
|
|
12710
|
+
"canonry_project_overview"
|
|
12711
|
+
],
|
|
12712
|
+
"guidance": "Select an accessible project, then read its stored overview. Report freshness and missing evidence; do not start a sweep to fill a gap."
|
|
12713
|
+
},
|
|
12714
|
+
"diagnose": {
|
|
12715
|
+
"keywords": [
|
|
12716
|
+
"diagnose",
|
|
12717
|
+
"diagnosis",
|
|
12718
|
+
"regression",
|
|
12719
|
+
"changed",
|
|
12720
|
+
"change",
|
|
12721
|
+
"troubleshoot"
|
|
12722
|
+
],
|
|
12723
|
+
"next": [
|
|
12724
|
+
"canonry_projects_list",
|
|
12725
|
+
"canonry_project_overview",
|
|
12726
|
+
"canonry_project_history"
|
|
12727
|
+
],
|
|
12728
|
+
"guidance": "Compare stored history in the same project, period, provider/model, location, and query-class scope. Separate observed changes from possible causes; propose any live verification for approval."
|
|
12729
|
+
},
|
|
12730
|
+
"measurement": {
|
|
12731
|
+
"keywords": [
|
|
12732
|
+
"measurement",
|
|
12733
|
+
"measure",
|
|
12734
|
+
"portfolio",
|
|
12735
|
+
"property",
|
|
12736
|
+
"target",
|
|
12737
|
+
"query",
|
|
12738
|
+
"queries",
|
|
12739
|
+
"research"
|
|
12740
|
+
],
|
|
12741
|
+
"next": [
|
|
12742
|
+
"canonry_projects_list",
|
|
12743
|
+
"canonry_measurement_overview",
|
|
12744
|
+
"canonry_measurement_setup",
|
|
12745
|
+
"canonry_research_runs_list"
|
|
12746
|
+
],
|
|
12747
|
+
"guidance": "Inspect existing measurement before editing it. Preserve Simple versus Advanced scope, Property/Target identity, market, provider/model, and query class. Direct research submits final queries in one context; reviewed batches submit explicit destinations under one retry key. Expand patterns client-side: scope records a destination and never rewrites queries or fans out a group. Research is separate from tracking; publication does not authorize a sweep."
|
|
12748
|
+
},
|
|
12749
|
+
"integrations": {
|
|
12750
|
+
"keywords": [
|
|
12751
|
+
"integrations",
|
|
12752
|
+
"integration",
|
|
12753
|
+
"connect",
|
|
12754
|
+
"connection",
|
|
12755
|
+
"traffic",
|
|
12756
|
+
"gsc",
|
|
12757
|
+
"ga4",
|
|
12758
|
+
"ads",
|
|
12759
|
+
"gtm"
|
|
12760
|
+
],
|
|
12761
|
+
"next": [
|
|
12762
|
+
"canonry_projects_list",
|
|
12763
|
+
"canonry_project_get",
|
|
12764
|
+
"canonry_ga_status",
|
|
12765
|
+
"canonry_google_ads_status"
|
|
12766
|
+
],
|
|
12767
|
+
"guidance": "Inspect stored connection status and snapshot freshness. Use the currently listed specialist tools for stored evidence. Connecting, selecting resources, syncing, and live provider reads require scoped approval; never request credentials in chat."
|
|
12768
|
+
},
|
|
12769
|
+
"reports": {
|
|
12770
|
+
"keywords": [
|
|
12771
|
+
"reports",
|
|
12772
|
+
"report",
|
|
12773
|
+
"reporting",
|
|
12774
|
+
"summary"
|
|
12775
|
+
],
|
|
12776
|
+
"next": [
|
|
12777
|
+
"canonry_projects_list",
|
|
12778
|
+
"canonry_report"
|
|
12779
|
+
],
|
|
12780
|
+
"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."
|
|
12781
|
+
}
|
|
12782
|
+
},
|
|
12783
|
+
"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`, `measurement`, `integrations`, `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`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**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. Preparing a report does not authorize new measurement.\n\n## Authority and approval\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"
|
|
12784
|
+
};
|
|
12785
|
+
|
|
12786
|
+
// src/mcp/operations-guide.ts
|
|
12787
|
+
function operationsHelp(catalog, mode, intent = "", includeCatalog = false) {
|
|
12788
|
+
const workflows = Object.keys(OPERATIONS_GUIDE.workflows);
|
|
12789
|
+
const words = new Set(intent.toLowerCase().split(/[^a-z0-9-]+/));
|
|
12790
|
+
const workflow = workflows.find((name) => OPERATIONS_GUIDE.workflows[name].keywords.some((word) => words.has(word))) ?? "status";
|
|
12791
|
+
const route = OPERATIONS_GUIDE.workflows[workflow];
|
|
12792
|
+
const available = /* @__PURE__ */ new Set([...catalog.coreTools, ...catalog.toolkits.filter((t) => t.loaded).flatMap((t) => t.tools)]);
|
|
12793
|
+
const next = route.next.filter((name) => available.has(name)).slice(0, 4);
|
|
12794
|
+
if (next.length < 2 && available.has("canonry_project_overview") && !next.includes("canonry_project_overview")) {
|
|
12795
|
+
next.push("canonry_project_overview");
|
|
12796
|
+
}
|
|
12797
|
+
const wanted = route.next;
|
|
12798
|
+
const loadToolkits = mode === "stdio-progressive" ? catalog.toolkits.filter((t) => !t.loaded && t.tools.some((name) => wanted.includes(name))).map((t) => t.name) : [];
|
|
12799
|
+
return {
|
|
12800
|
+
guideVersion: OPERATIONS_GUIDE.guideVersion,
|
|
12801
|
+
mode,
|
|
12802
|
+
scope: catalog.scope,
|
|
12803
|
+
workflow,
|
|
12804
|
+
next,
|
|
12805
|
+
workflows,
|
|
12806
|
+
guidance: route.guidance,
|
|
12807
|
+
approvalBoundary: OPERATIONS_GUIDE.approvalBoundary,
|
|
12808
|
+
approvalRule: OPERATIONS_GUIDE.approvalRule,
|
|
12809
|
+
authority: OPERATIONS_GUIDE.authority,
|
|
12810
|
+
operationsGuideUrl: OPERATIONS_GUIDE.operationsGuideUrl,
|
|
12811
|
+
...loadToolkits.length ? { loadToolkits } : {},
|
|
12812
|
+
...includeCatalog ? catalog : {}
|
|
12813
|
+
};
|
|
12814
|
+
}
|
|
12815
|
+
|
|
12642
12816
|
// src/mcp/server.ts
|
|
12643
12817
|
function createCanonryMcpServer(options = {}) {
|
|
12644
12818
|
return createCanonryMcpServerWithCatalog(options).server;
|
|
12645
12819
|
}
|
|
12646
|
-
var SERVER_INSTRUCTIONS =
|
|
12647
|
-
|
|
12648
|
-
Load the "canonry" skill before operator work (project setup, integrations, traffic sources, sweeps, diagnosis). It carries the procedures and the failure modes; this text is only a pointer. Use "aero" for analyst work: regression diagnosis, reporting.
|
|
12649
|
-
|
|
12650
|
-
Two signals, never interchangeable:
|
|
12651
|
-
- mentioned = the brand appears in the answer TEXT the model wrote.
|
|
12652
|
-
- cited = the domain appears in the SOURCE links behind the answer.
|
|
12653
|
-
A model can do either, both or neither. Never compute one from the other, and never report a number for one under the other's name.
|
|
12654
|
-
|
|
12655
|
-
Sweeps, probes, and research runs spend provider quota and write rows. Get explicit approval before any run, apply, or other mutation.
|
|
12656
|
-
|
|
12657
|
-
Most reads are free. Five ads reads are NOT: canonry_ads_account, canonry_ads_geo_search, canonry_ads_live_delivery, canonry_ads_conversion_pixels and canonry_ads_conversion_event_settings call the provider live and spend against the advertiser account. They are marked read, so nothing in the tool list warns you. Get approval for those exactly as for a mutation.
|
|
12658
|
-
|
|
12659
|
-
Google Marketing also calls providers live. Get approval before canonry_google_ads_customers, canonry_gtm_accounts, canonry_gtm_containers, canonry_gtm_workspaces, canonry_google_ads_sync or canonry_gtm_sync.
|
|
12660
|
-
|
|
12661
|
-
A null answerMentioned means NOT CHECKED, not "not mentioned". Never coerce it to false.
|
|
12662
|
-
|
|
12663
|
-
If no sweep has run, say so. Never state a mention or citation figure that no run produced.`;
|
|
12820
|
+
var SERVER_INSTRUCTIONS = OPERATIONS_GUIDE.initialize;
|
|
12664
12821
|
function createCanonryMcpServerWithCatalog(options = {}) {
|
|
12665
12822
|
const clientFactory = options.clientFactory ?? createApiClient;
|
|
12666
12823
|
const client2 = clientFactory();
|
|
@@ -12673,7 +12830,7 @@ function createCanonryMcpServerWithCatalog(options = {}) {
|
|
|
12673
12830
|
});
|
|
12674
12831
|
server.validateToolInput = async (_tool, args) => args;
|
|
12675
12832
|
const entries = [];
|
|
12676
|
-
for (const registryTool of getCanonryMcpTools(scope, options.tiers)) {
|
|
12833
|
+
for (const registryTool of getCanonryMcpTools(scope, options.tiers, options.credentialScopes)) {
|
|
12677
12834
|
const tool = registryTool;
|
|
12678
12835
|
const handler = tool.handler;
|
|
12679
12836
|
const registered = server.registerTool(
|
|
@@ -12694,22 +12851,40 @@ function createCanonryMcpServerWithCatalog(options = {}) {
|
|
|
12694
12851
|
const eager = options.eager === true || options.tiers !== void 0;
|
|
12695
12852
|
const catalog = new DynamicToolCatalog(server, entries, scope, { eager });
|
|
12696
12853
|
catalog.applyInitialEnablement();
|
|
12697
|
-
|
|
12854
|
+
const mode = options.tiers !== void 0 ? "hosted-fixed-catalog" : eager ? "stdio-fixed-catalog" : "stdio-progressive";
|
|
12855
|
+
registerMetaTools(server, catalog, { includeToolkitLoader: options.tiers === void 0, mode });
|
|
12856
|
+
server.registerResource("canonry-agent-operations-v1", OPERATIONS_GUIDE.resourceUri, {
|
|
12857
|
+
title: "Canonry Operations Guide v1",
|
|
12858
|
+
description: "Optional public operations guidance. Use canonry_help when resources are unavailable.",
|
|
12859
|
+
mimeType: "text/markdown"
|
|
12860
|
+
}, async (uri) => ({ contents: [{ uri: uri.href, mimeType: "text/markdown", text: OPERATIONS_GUIDE.markdown }] }));
|
|
12698
12861
|
return { server, catalog };
|
|
12699
12862
|
}
|
|
12700
12863
|
var loadToolkitInputSchema = z5.object({
|
|
12701
12864
|
name: z5.enum(CANONRY_MCP_TOOLKIT_NAMES).describe("Toolkit name. List options with canonry_help.")
|
|
12702
12865
|
});
|
|
12866
|
+
var helpInputSchema = z5.object({
|
|
12867
|
+
intent: z5.string().max(200).optional().describe("Workflow (status, diagnose, measurement, integrations, reports) or a short task description."),
|
|
12868
|
+
includeCatalog: z5.boolean().optional().describe("Include full toolkit details. Omit for a compact, actionable route.")
|
|
12869
|
+
});
|
|
12703
12870
|
function registerMetaTools(server, catalog, opts) {
|
|
12704
12871
|
server.registerTool(
|
|
12705
12872
|
"canonry_help",
|
|
12706
12873
|
{
|
|
12707
|
-
title: "
|
|
12708
|
-
description: "
|
|
12709
|
-
inputSchema:
|
|
12710
|
-
annotations: { readOnlyHint: true }
|
|
12874
|
+
title: "Guide a Canonry workflow",
|
|
12875
|
+
description: "Start here: route an intent to available stored-evidence tools, workflow guidance, and approval boundaries. No provider calls or installation required. Optionally include full toolkit details.",
|
|
12876
|
+
inputSchema: helpInputSchema.shape,
|
|
12877
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false }
|
|
12711
12878
|
},
|
|
12712
|
-
async () =>
|
|
12879
|
+
async (input) => {
|
|
12880
|
+
try {
|
|
12881
|
+
const parsed = helpInputSchema.parse(input ?? {});
|
|
12882
|
+
const result = operationsHelp(catalog.helpResult(), opts.mode, parsed.intent, parsed.includeCatalog);
|
|
12883
|
+
return { ...jsonToolResult(result), structuredContent: result };
|
|
12884
|
+
} catch (error) {
|
|
12885
|
+
return errorToolResult(error);
|
|
12886
|
+
}
|
|
12887
|
+
}
|
|
12713
12888
|
);
|
|
12714
12889
|
if (!opts.includeToolkitLoader) return;
|
|
12715
12890
|
server.registerTool(
|
|
@@ -12726,8 +12901,14 @@ function registerMetaTools(server, catalog, opts) {
|
|
|
12726
12901
|
})
|
|
12727
12902
|
);
|
|
12728
12903
|
}
|
|
12729
|
-
function getCanonryMcpTools(scope = "all", tiers) {
|
|
12730
|
-
const
|
|
12904
|
+
function getCanonryMcpTools(scope = "all", tiers, credentialScopes) {
|
|
12905
|
+
const readOnly = scope === "read-only" || credentialScopes !== void 0 && isReadOnlyKey(credentialScopes);
|
|
12906
|
+
const restricted = credentialScopes && restrictedWriteScopes(credentialScopes);
|
|
12907
|
+
const byScope = readOnly ? canonryMcpTools.filter((tool) => tool.access === "read") : canonryMcpTools.filter((tool) => {
|
|
12908
|
+
if (!restricted || tool.access === "read") return true;
|
|
12909
|
+
if (tool.requiredScope && restricted.includes(tool.requiredScope)) return true;
|
|
12910
|
+
return restricted.some((grant) => grant !== RESEARCH_RUN_SCOPE) && tool.tier === "ads";
|
|
12911
|
+
});
|
|
12731
12912
|
if (!tiers) return byScope;
|
|
12732
12913
|
const wanted = new Set(tiers);
|
|
12733
12914
|
return byScope.filter((tool) => wanted.has(tool.tier));
|