@ainyc/canonry 2.6.0 → 2.9.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/README.md +23 -2
- package/assets/assets/{index-BsNi8T7D.js → index-U1lA1GKP.js} +29 -29
- package/assets/index.html +1 -1
- package/dist/{chunk-3DUTT6H2.js → chunk-FPZUQADO.js} +11 -3
- package/dist/{chunk-LF4O276A.js → chunk-MGBXRWLX.js} +159 -27
- package/dist/cli.js +484 -73
- package/dist/index.js +2 -2
- package/dist/mcp.js +282 -14
- package/package.json +4 -4
package/dist/mcp.js
CHANGED
|
@@ -3,11 +3,14 @@ import {
|
|
|
3
3
|
competitorBatchRequestSchema,
|
|
4
4
|
createApiClient,
|
|
5
5
|
keywordBatchRequestSchema,
|
|
6
|
+
keywordGenerateRequestSchema,
|
|
6
7
|
notificationCreateRequestSchema,
|
|
7
8
|
notificationEventSchema,
|
|
9
|
+
projectConfigSchema,
|
|
10
|
+
projectUpsertRequestSchema,
|
|
8
11
|
runTriggerRequestSchema,
|
|
9
12
|
scheduleUpsertRequestSchema
|
|
10
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-FPZUQADO.js";
|
|
11
14
|
import "./chunk-MLKGABMK.js";
|
|
12
15
|
|
|
13
16
|
// src/mcp/cli.ts
|
|
@@ -15,6 +18,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
15
18
|
|
|
16
19
|
// src/mcp/server.ts
|
|
17
20
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
21
|
+
import { z as z3 } from "zod";
|
|
18
22
|
|
|
19
23
|
// src/package-version.ts
|
|
20
24
|
import { createRequire } from "module";
|
|
@@ -146,10 +150,21 @@ var keywordsInputSchema = z2.object({
|
|
|
146
150
|
project: projectNameSchema,
|
|
147
151
|
request: keywordBatchRequestSchema
|
|
148
152
|
});
|
|
149
|
-
var
|
|
153
|
+
var keywordGenerateInputSchema = z2.object({
|
|
154
|
+
project: projectNameSchema,
|
|
155
|
+
request: keywordGenerateRequestSchema
|
|
156
|
+
});
|
|
157
|
+
var competitorsInputSchema = z2.object({
|
|
150
158
|
project: projectNameSchema,
|
|
151
159
|
request: competitorBatchRequestSchema
|
|
152
160
|
});
|
|
161
|
+
var projectUpsertInputSchema = z2.object({
|
|
162
|
+
project: projectNameSchema,
|
|
163
|
+
request: projectUpsertRequestSchema
|
|
164
|
+
});
|
|
165
|
+
var applyConfigInputSchema = z2.object({
|
|
166
|
+
config: projectConfigSchema
|
|
167
|
+
});
|
|
153
168
|
var scheduleSetInputSchema = z2.object({
|
|
154
169
|
project: projectNameSchema,
|
|
155
170
|
schedule: scheduleUpsertRequestSchema
|
|
@@ -170,6 +185,7 @@ var canonryMcpTools = [
|
|
|
170
185
|
title: "List Canonry projects",
|
|
171
186
|
description: "List all Canonry projects available through the configured API.",
|
|
172
187
|
access: "read",
|
|
188
|
+
tier: "core",
|
|
173
189
|
inputSchema: emptyInputSchema,
|
|
174
190
|
annotations: readAnnotations(),
|
|
175
191
|
openApiOperations: ["GET /api/v1/projects"],
|
|
@@ -180,6 +196,7 @@ var canonryMcpTools = [
|
|
|
180
196
|
title: "Get project",
|
|
181
197
|
description: "Get a Canonry project by name.",
|
|
182
198
|
access: "read",
|
|
199
|
+
tier: "core",
|
|
183
200
|
inputSchema: projectInputSchema,
|
|
184
201
|
annotations: readAnnotations(),
|
|
185
202
|
openApiOperations: ["GET /api/v1/projects/{name}"],
|
|
@@ -190,6 +207,7 @@ var canonryMcpTools = [
|
|
|
190
207
|
title: "Export project config",
|
|
191
208
|
description: "Export a Canonry project in config-as-code format.",
|
|
192
209
|
access: "read",
|
|
210
|
+
tier: "setup",
|
|
193
211
|
inputSchema: projectInputSchema,
|
|
194
212
|
annotations: readAnnotations(),
|
|
195
213
|
openApiOperations: ["GET /api/v1/projects/{name}/export"],
|
|
@@ -200,6 +218,7 @@ var canonryMcpTools = [
|
|
|
200
218
|
title: "Get project history",
|
|
201
219
|
description: "Get audit history for a Canonry project.",
|
|
202
220
|
access: "read",
|
|
221
|
+
tier: "monitoring",
|
|
203
222
|
inputSchema: projectInputSchema,
|
|
204
223
|
annotations: readAnnotations(),
|
|
205
224
|
openApiOperations: ["GET /api/v1/projects/{name}/history"],
|
|
@@ -210,6 +229,7 @@ var canonryMcpTools = [
|
|
|
210
229
|
title: "List project runs",
|
|
211
230
|
description: "List runs for a Canonry project.",
|
|
212
231
|
access: "read",
|
|
232
|
+
tier: "monitoring",
|
|
213
233
|
inputSchema: runsListInputSchema,
|
|
214
234
|
annotations: readAnnotations(),
|
|
215
235
|
openApiOperations: ["GET /api/v1/projects/{name}/runs"],
|
|
@@ -220,6 +240,7 @@ var canonryMcpTools = [
|
|
|
220
240
|
title: "Get latest project run",
|
|
221
241
|
description: "Get the latest run and total run count for a Canonry project.",
|
|
222
242
|
access: "read",
|
|
243
|
+
tier: "monitoring",
|
|
223
244
|
inputSchema: projectInputSchema,
|
|
224
245
|
annotations: readAnnotations(),
|
|
225
246
|
openApiOperations: ["GET /api/v1/projects/{name}/runs/latest"],
|
|
@@ -230,6 +251,7 @@ var canonryMcpTools = [
|
|
|
230
251
|
title: "Get run",
|
|
231
252
|
description: "Get a Canonry run with its snapshots.",
|
|
232
253
|
access: "read",
|
|
254
|
+
tier: "monitoring",
|
|
233
255
|
inputSchema: runGetInputSchema,
|
|
234
256
|
annotations: readAnnotations(),
|
|
235
257
|
openApiOperations: ["GET /api/v1/runs/{id}"],
|
|
@@ -240,6 +262,7 @@ var canonryMcpTools = [
|
|
|
240
262
|
title: "Get project timeline",
|
|
241
263
|
description: "Get per-keyword citation history for a Canonry project.",
|
|
242
264
|
access: "read",
|
|
265
|
+
tier: "monitoring",
|
|
243
266
|
inputSchema: timelineInputSchema,
|
|
244
267
|
annotations: readAnnotations(),
|
|
245
268
|
openApiOperations: ["GET /api/v1/projects/{name}/timeline"],
|
|
@@ -250,6 +273,7 @@ var canonryMcpTools = [
|
|
|
250
273
|
title: "List query snapshots",
|
|
251
274
|
description: "List paginated query snapshots for a Canonry project.",
|
|
252
275
|
access: "read",
|
|
276
|
+
tier: "monitoring",
|
|
253
277
|
inputSchema: snapshotsListInputSchema,
|
|
254
278
|
annotations: readAnnotations(),
|
|
255
279
|
openApiOperations: ["GET /api/v1/projects/{name}/snapshots"],
|
|
@@ -264,6 +288,7 @@ var canonryMcpTools = [
|
|
|
264
288
|
title: "Diff snapshots",
|
|
265
289
|
description: "Compare query snapshot states between two Canonry runs.",
|
|
266
290
|
access: "read",
|
|
291
|
+
tier: "monitoring",
|
|
267
292
|
inputSchema: snapshotsDiffInputSchema,
|
|
268
293
|
annotations: readAnnotations(),
|
|
269
294
|
openApiOperations: ["GET /api/v1/projects/{name}/snapshots/diff"],
|
|
@@ -274,6 +299,7 @@ var canonryMcpTools = [
|
|
|
274
299
|
title: "List insights",
|
|
275
300
|
description: "List intelligence insights for a Canonry project.",
|
|
276
301
|
access: "read",
|
|
302
|
+
tier: "monitoring",
|
|
277
303
|
inputSchema: insightsListInputSchema,
|
|
278
304
|
annotations: readAnnotations(),
|
|
279
305
|
openApiOperations: ["GET /api/v1/projects/{name}/insights"],
|
|
@@ -284,6 +310,7 @@ var canonryMcpTools = [
|
|
|
284
310
|
title: "Get insight",
|
|
285
311
|
description: "Get one intelligence insight for a Canonry project.",
|
|
286
312
|
access: "read",
|
|
313
|
+
tier: "monitoring",
|
|
287
314
|
inputSchema: insightInputSchema,
|
|
288
315
|
annotations: readAnnotations(),
|
|
289
316
|
openApiOperations: ["GET /api/v1/projects/{name}/insights/{id}"],
|
|
@@ -294,6 +321,7 @@ var canonryMcpTools = [
|
|
|
294
321
|
title: "Get latest health",
|
|
295
322
|
description: "Get the latest health snapshot for a Canonry project.",
|
|
296
323
|
access: "read",
|
|
324
|
+
tier: "monitoring",
|
|
297
325
|
inputSchema: projectInputSchema,
|
|
298
326
|
annotations: readAnnotations(),
|
|
299
327
|
openApiOperations: ["GET /api/v1/projects/{name}/health/latest"],
|
|
@@ -304,6 +332,7 @@ var canonryMcpTools = [
|
|
|
304
332
|
title: "Get health history",
|
|
305
333
|
description: "Get health snapshot history for a Canonry project.",
|
|
306
334
|
access: "read",
|
|
335
|
+
tier: "monitoring",
|
|
307
336
|
inputSchema: healthHistoryInputSchema,
|
|
308
337
|
annotations: readAnnotations(),
|
|
309
338
|
openApiOperations: ["GET /api/v1/projects/{name}/health/history"],
|
|
@@ -314,6 +343,7 @@ var canonryMcpTools = [
|
|
|
314
343
|
title: "List keywords",
|
|
315
344
|
description: "List tracked keywords for a Canonry project.",
|
|
316
345
|
access: "read",
|
|
346
|
+
tier: "setup",
|
|
317
347
|
inputSchema: projectInputSchema,
|
|
318
348
|
annotations: readAnnotations(),
|
|
319
349
|
openApiOperations: ["GET /api/v1/projects/{name}/keywords"],
|
|
@@ -324,6 +354,7 @@ var canonryMcpTools = [
|
|
|
324
354
|
title: "List competitors",
|
|
325
355
|
description: "List tracked competitors for a Canonry project.",
|
|
326
356
|
access: "read",
|
|
357
|
+
tier: "setup",
|
|
327
358
|
inputSchema: projectInputSchema,
|
|
328
359
|
annotations: readAnnotations(),
|
|
329
360
|
openApiOperations: ["GET /api/v1/projects/{name}/competitors"],
|
|
@@ -334,6 +365,7 @@ var canonryMcpTools = [
|
|
|
334
365
|
title: "Get schedule",
|
|
335
366
|
description: "Get the scheduled run configuration for a Canonry project.",
|
|
336
367
|
access: "read",
|
|
368
|
+
tier: "setup",
|
|
337
369
|
inputSchema: projectInputSchema,
|
|
338
370
|
annotations: readAnnotations(),
|
|
339
371
|
openApiOperations: ["GET /api/v1/projects/{name}/schedule"],
|
|
@@ -344,6 +376,7 @@ var canonryMcpTools = [
|
|
|
344
376
|
title: "Get settings",
|
|
345
377
|
description: "Get Canonry API settings and configured provider status.",
|
|
346
378
|
access: "read",
|
|
379
|
+
tier: "core",
|
|
347
380
|
inputSchema: emptyInputSchema,
|
|
348
381
|
annotations: readAnnotations(),
|
|
349
382
|
openApiOperations: ["GET /api/v1/settings"],
|
|
@@ -354,6 +387,7 @@ var canonryMcpTools = [
|
|
|
354
387
|
title: "List Google connections",
|
|
355
388
|
description: "List configured Google connections for a Canonry project.",
|
|
356
389
|
access: "read",
|
|
390
|
+
tier: "gsc",
|
|
357
391
|
inputSchema: projectInputSchema,
|
|
358
392
|
annotations: readAnnotations(),
|
|
359
393
|
openApiOperations: ["GET /api/v1/projects/{name}/google/connections"],
|
|
@@ -364,6 +398,7 @@ var canonryMcpTools = [
|
|
|
364
398
|
title: "Get GSC performance",
|
|
365
399
|
description: "Get stored Google Search Console performance rows for a Canonry project.",
|
|
366
400
|
access: "read",
|
|
401
|
+
tier: "gsc",
|
|
367
402
|
inputSchema: gscPerformanceInputSchema,
|
|
368
403
|
annotations: readAnnotations(),
|
|
369
404
|
openApiOperations: ["GET /api/v1/projects/{name}/google/gsc/performance"],
|
|
@@ -374,6 +409,7 @@ var canonryMcpTools = [
|
|
|
374
409
|
title: "List GSC inspections",
|
|
375
410
|
description: "List stored URL inspection rows for a Canonry project.",
|
|
376
411
|
access: "read",
|
|
412
|
+
tier: "gsc",
|
|
377
413
|
inputSchema: gscInspectionsInputSchema,
|
|
378
414
|
annotations: readAnnotations(),
|
|
379
415
|
openApiOperations: ["GET /api/v1/projects/{name}/google/gsc/inspections"],
|
|
@@ -384,6 +420,7 @@ var canonryMcpTools = [
|
|
|
384
420
|
title: "List deindexed GSC URLs",
|
|
385
421
|
description: "List URLs that appear to have become deindexed in Google Search Console data.",
|
|
386
422
|
access: "read",
|
|
423
|
+
tier: "gsc",
|
|
387
424
|
inputSchema: projectInputSchema,
|
|
388
425
|
annotations: readAnnotations(),
|
|
389
426
|
openApiOperations: ["GET /api/v1/projects/{name}/google/gsc/deindexed"],
|
|
@@ -394,6 +431,7 @@ var canonryMcpTools = [
|
|
|
394
431
|
title: "Get GSC coverage",
|
|
395
432
|
description: "Get Google Search Console coverage summary for a Canonry project.",
|
|
396
433
|
access: "read",
|
|
434
|
+
tier: "gsc",
|
|
397
435
|
inputSchema: projectInputSchema,
|
|
398
436
|
annotations: readAnnotations(),
|
|
399
437
|
openApiOperations: ["GET /api/v1/projects/{name}/google/gsc/coverage"],
|
|
@@ -404,6 +442,7 @@ var canonryMcpTools = [
|
|
|
404
442
|
title: "Get GSC coverage history",
|
|
405
443
|
description: "Get Google Search Console coverage history snapshots for a Canonry project.",
|
|
406
444
|
access: "read",
|
|
445
|
+
tier: "gsc",
|
|
407
446
|
inputSchema: gscCoverageHistoryInputSchema,
|
|
408
447
|
annotations: readAnnotations(),
|
|
409
448
|
openApiOperations: ["GET /api/v1/projects/{name}/google/gsc/coverage/history"],
|
|
@@ -414,6 +453,7 @@ var canonryMcpTools = [
|
|
|
414
453
|
title: "Get GSC sitemaps",
|
|
415
454
|
description: "Get sitemap data from Google Search Console for a Canonry project.",
|
|
416
455
|
access: "read",
|
|
456
|
+
tier: "gsc",
|
|
417
457
|
inputSchema: projectInputSchema,
|
|
418
458
|
annotations: readAnnotations(true),
|
|
419
459
|
openApiOperations: ["GET /api/v1/projects/{name}/google/gsc/sitemaps"],
|
|
@@ -424,6 +464,7 @@ var canonryMcpTools = [
|
|
|
424
464
|
title: "Get GA status",
|
|
425
465
|
description: "Get Google Analytics connection status for a Canonry project.",
|
|
426
466
|
access: "read",
|
|
467
|
+
tier: "ga",
|
|
427
468
|
inputSchema: projectInputSchema,
|
|
428
469
|
annotations: readAnnotations(),
|
|
429
470
|
openApiOperations: ["GET /api/v1/projects/{name}/ga/status"],
|
|
@@ -434,6 +475,7 @@ var canonryMcpTools = [
|
|
|
434
475
|
title: "Get GA traffic",
|
|
435
476
|
description: "Get Google Analytics traffic summary for a Canonry project.",
|
|
436
477
|
access: "read",
|
|
478
|
+
tier: "ga",
|
|
437
479
|
inputSchema: gaTrafficInputSchema,
|
|
438
480
|
annotations: readAnnotations(),
|
|
439
481
|
openApiOperations: ["GET /api/v1/projects/{name}/ga/traffic"],
|
|
@@ -444,6 +486,7 @@ var canonryMcpTools = [
|
|
|
444
486
|
title: "Get GA coverage",
|
|
445
487
|
description: "Get Google Analytics page coverage for a Canonry project.",
|
|
446
488
|
access: "read",
|
|
489
|
+
tier: "ga",
|
|
447
490
|
inputSchema: projectInputSchema,
|
|
448
491
|
annotations: readAnnotations(),
|
|
449
492
|
openApiOperations: ["GET /api/v1/projects/{name}/ga/coverage"],
|
|
@@ -454,6 +497,7 @@ var canonryMcpTools = [
|
|
|
454
497
|
title: "Get GA AI referral history",
|
|
455
498
|
description: "Get AI referral sessions per day grouped by source.",
|
|
456
499
|
access: "read",
|
|
500
|
+
tier: "ga",
|
|
457
501
|
inputSchema: gaWindowInputSchema,
|
|
458
502
|
annotations: readAnnotations(),
|
|
459
503
|
openApiOperations: ["GET /api/v1/projects/{name}/ga/ai-referral-history"],
|
|
@@ -464,6 +508,7 @@ var canonryMcpTools = [
|
|
|
464
508
|
title: "Get GA social referral history",
|
|
465
509
|
description: "Get social referral sessions per day grouped by source.",
|
|
466
510
|
access: "read",
|
|
511
|
+
tier: "ga",
|
|
467
512
|
inputSchema: gaWindowInputSchema,
|
|
468
513
|
annotations: readAnnotations(),
|
|
469
514
|
openApiOperations: ["GET /api/v1/projects/{name}/ga/social-referral-history"],
|
|
@@ -474,6 +519,7 @@ var canonryMcpTools = [
|
|
|
474
519
|
title: "Get GA social referral trend",
|
|
475
520
|
description: "Get social referral trend with biggest mover for a Canonry project.",
|
|
476
521
|
access: "read",
|
|
522
|
+
tier: "ga",
|
|
477
523
|
inputSchema: projectInputSchema,
|
|
478
524
|
annotations: readAnnotations(),
|
|
479
525
|
openApiOperations: ["GET /api/v1/projects/{name}/ga/social-referral-trend"],
|
|
@@ -484,6 +530,7 @@ var canonryMcpTools = [
|
|
|
484
530
|
title: "Get GA attribution trend",
|
|
485
531
|
description: "Get per-channel attribution trends for organic, AI, social, and total sessions.",
|
|
486
532
|
access: "read",
|
|
533
|
+
tier: "ga",
|
|
487
534
|
inputSchema: projectInputSchema,
|
|
488
535
|
annotations: readAnnotations(),
|
|
489
536
|
openApiOperations: ["GET /api/v1/projects/{name}/ga/attribution-trend"],
|
|
@@ -494,16 +541,65 @@ var canonryMcpTools = [
|
|
|
494
541
|
title: "Get GA session history",
|
|
495
542
|
description: "Get total sessions per day for a Canonry project.",
|
|
496
543
|
access: "read",
|
|
544
|
+
tier: "ga",
|
|
497
545
|
inputSchema: gaWindowInputSchema,
|
|
498
546
|
annotations: readAnnotations(),
|
|
499
547
|
openApiOperations: ["GET /api/v1/projects/{name}/ga/session-history"],
|
|
500
548
|
handler: (client, input) => client.gaSessionHistory(input.project, compactStringParams(input, ["window"]))
|
|
501
549
|
}),
|
|
550
|
+
defineTool({
|
|
551
|
+
name: "canonry_project_upsert",
|
|
552
|
+
title: "Create or replace project",
|
|
553
|
+
description: "Create or replace a Canonry project. PUT semantics \u2014 fields not in the request are reset to their defaults. Provide the full intended project shape.",
|
|
554
|
+
access: "write",
|
|
555
|
+
tier: "setup",
|
|
556
|
+
inputSchema: projectUpsertInputSchema,
|
|
557
|
+
annotations: writeAnnotations({ idempotentHint: true, destructiveHint: true }),
|
|
558
|
+
openApiOperations: ["PUT /api/v1/projects/{name}"],
|
|
559
|
+
handler: (client, input) => client.putProject(input.project, input.request)
|
|
560
|
+
}),
|
|
561
|
+
defineTool({
|
|
562
|
+
name: "canonry_apply_config",
|
|
563
|
+
title: "Apply project config",
|
|
564
|
+
description: "Apply one Canonry config-as-code project document. Replaces the project to match the config \u2014 fields omitted from the spec are reset to defaults. For multi-document YAML, call this tool once per project document.",
|
|
565
|
+
access: "write",
|
|
566
|
+
tier: "core",
|
|
567
|
+
inputSchema: applyConfigInputSchema,
|
|
568
|
+
// Declarative apply is safe to repeat, but it replaces configured child state.
|
|
569
|
+
annotations: writeAnnotations({ idempotentHint: true, destructiveHint: true }),
|
|
570
|
+
openApiOperations: ["POST /api/v1/apply"],
|
|
571
|
+
handler: (client, input) => client.apply(input.config)
|
|
572
|
+
}),
|
|
573
|
+
defineTool({
|
|
574
|
+
name: "canonry_keywords_generate",
|
|
575
|
+
title: "Generate keyword suggestions",
|
|
576
|
+
description: "Generate candidate key phrases using a configured provider. Returns suggestions only; use canonry_keywords_add to persist them.",
|
|
577
|
+
access: "write",
|
|
578
|
+
tier: "setup",
|
|
579
|
+
inputSchema: keywordGenerateInputSchema,
|
|
580
|
+
annotations: writeAnnotations({ idempotentHint: false, openWorldHint: true }),
|
|
581
|
+
openApiOperations: ["POST /api/v1/projects/{name}/keywords/generate"],
|
|
582
|
+
handler: (client, input) => client.generateKeywords(input.project, input.request.provider, input.request.count)
|
|
583
|
+
}),
|
|
584
|
+
defineTool({
|
|
585
|
+
name: "canonry_keywords_replace",
|
|
586
|
+
title: "Replace keywords",
|
|
587
|
+
description: "Replace the tracked keyword set for a Canonry project.",
|
|
588
|
+
access: "write",
|
|
589
|
+
tier: "setup",
|
|
590
|
+
inputSchema: keywordsInputSchema,
|
|
591
|
+
annotations: writeAnnotations({ idempotentHint: true, destructiveHint: true }),
|
|
592
|
+
openApiOperations: ["PUT /api/v1/projects/{name}/keywords"],
|
|
593
|
+
handler: async (client, input) => {
|
|
594
|
+
await client.putKeywords(input.project, uniqueStrings(input.request.keywords));
|
|
595
|
+
}
|
|
596
|
+
}),
|
|
502
597
|
defineTool({
|
|
503
598
|
name: "canonry_run_trigger",
|
|
504
599
|
title: "Trigger run",
|
|
505
600
|
description: "Trigger an answer-visibility run for a Canonry project.",
|
|
506
601
|
access: "write",
|
|
602
|
+
tier: "core",
|
|
507
603
|
inputSchema: runTriggerInputSchema,
|
|
508
604
|
annotations: writeAnnotations({ idempotentHint: false, openWorldHint: true }),
|
|
509
605
|
openApiOperations: ["POST /api/v1/projects/{name}/runs"],
|
|
@@ -514,6 +610,7 @@ var canonryMcpTools = [
|
|
|
514
610
|
title: "Cancel run",
|
|
515
611
|
description: "Cancel a queued or running Canonry run.",
|
|
516
612
|
access: "write",
|
|
613
|
+
tier: "core",
|
|
517
614
|
inputSchema: runGetInputSchema,
|
|
518
615
|
annotations: writeAnnotations({ idempotentHint: false, destructiveHint: true }),
|
|
519
616
|
openApiOperations: ["POST /api/v1/runs/{id}/cancel"],
|
|
@@ -524,6 +621,7 @@ var canonryMcpTools = [
|
|
|
524
621
|
title: "Add keywords",
|
|
525
622
|
description: "Append tracked keywords to a Canonry project; existing keywords are skipped by the API.",
|
|
526
623
|
access: "write",
|
|
624
|
+
tier: "setup",
|
|
527
625
|
inputSchema: keywordsInputSchema,
|
|
528
626
|
annotations: writeAnnotations({ idempotentHint: true }),
|
|
529
627
|
openApiOperations: ["POST /api/v1/projects/{name}/keywords"],
|
|
@@ -536,6 +634,7 @@ var canonryMcpTools = [
|
|
|
536
634
|
title: "Remove keywords",
|
|
537
635
|
description: "Remove tracked keywords from a Canonry project.",
|
|
538
636
|
access: "write",
|
|
637
|
+
tier: "setup",
|
|
539
638
|
inputSchema: keywordsInputSchema,
|
|
540
639
|
annotations: writeAnnotations({ idempotentHint: true, destructiveHint: true }),
|
|
541
640
|
openApiOperations: ["DELETE /api/v1/projects/{name}/keywords"],
|
|
@@ -548,13 +647,25 @@ var canonryMcpTools = [
|
|
|
548
647
|
title: "Add competitors",
|
|
549
648
|
description: "Add tracked competitor domains to a Canonry project.",
|
|
550
649
|
access: "write",
|
|
551
|
-
|
|
650
|
+
tier: "setup",
|
|
651
|
+
inputSchema: competitorsInputSchema,
|
|
552
652
|
annotations: writeAnnotations({ idempotentHint: true }),
|
|
553
|
-
openApiOperations: ["
|
|
653
|
+
openApiOperations: ["POST /api/v1/projects/{name}/competitors"],
|
|
654
|
+
handler: async (client, input) => {
|
|
655
|
+
await client.appendCompetitors(input.project, uniqueStrings(input.request.competitors));
|
|
656
|
+
}
|
|
657
|
+
}),
|
|
658
|
+
defineTool({
|
|
659
|
+
name: "canonry_competitors_remove",
|
|
660
|
+
title: "Remove competitors",
|
|
661
|
+
description: "Remove tracked competitor domains from a Canonry project.",
|
|
662
|
+
access: "write",
|
|
663
|
+
tier: "setup",
|
|
664
|
+
inputSchema: competitorsInputSchema,
|
|
665
|
+
annotations: writeAnnotations({ idempotentHint: true, destructiveHint: true }),
|
|
666
|
+
openApiOperations: ["DELETE /api/v1/projects/{name}/competitors"],
|
|
554
667
|
handler: async (client, input) => {
|
|
555
|
-
|
|
556
|
-
const merged = uniqueStrings([...existing.map((c) => c.domain), ...input.request.competitors]);
|
|
557
|
-
await client.putCompetitors(input.project, merged);
|
|
668
|
+
await client.deleteCompetitors(input.project, uniqueStrings(input.request.competitors));
|
|
558
669
|
}
|
|
559
670
|
}),
|
|
560
671
|
defineTool({
|
|
@@ -562,6 +673,7 @@ var canonryMcpTools = [
|
|
|
562
673
|
title: "Set schedule",
|
|
563
674
|
description: "Create or replace the scheduled run configuration for a Canonry project.",
|
|
564
675
|
access: "write",
|
|
676
|
+
tier: "setup",
|
|
565
677
|
inputSchema: scheduleSetInputSchema,
|
|
566
678
|
annotations: writeAnnotations({ idempotentHint: true }),
|
|
567
679
|
openApiOperations: ["PUT /api/v1/projects/{name}/schedule"],
|
|
@@ -572,6 +684,7 @@ var canonryMcpTools = [
|
|
|
572
684
|
title: "Delete schedule",
|
|
573
685
|
description: "Delete the scheduled run configuration for a Canonry project.",
|
|
574
686
|
access: "write",
|
|
687
|
+
tier: "setup",
|
|
575
688
|
inputSchema: projectInputSchema,
|
|
576
689
|
annotations: writeAnnotations({ idempotentHint: false, destructiveHint: true }),
|
|
577
690
|
openApiOperations: ["DELETE /api/v1/projects/{name}/schedule"],
|
|
@@ -584,6 +697,7 @@ var canonryMcpTools = [
|
|
|
584
697
|
title: "Dismiss insight",
|
|
585
698
|
description: "Dismiss an intelligence insight for a Canonry project.",
|
|
586
699
|
access: "write",
|
|
700
|
+
tier: "setup",
|
|
587
701
|
inputSchema: insightInputSchema,
|
|
588
702
|
annotations: writeAnnotations({ idempotentHint: true }),
|
|
589
703
|
openApiOperations: ["POST /api/v1/projects/{name}/insights/{id}/dismiss"],
|
|
@@ -594,6 +708,7 @@ var canonryMcpTools = [
|
|
|
594
708
|
title: "Attach agent webhook",
|
|
595
709
|
description: "Attach an external agent webhook to project run and insight events.",
|
|
596
710
|
access: "write",
|
|
711
|
+
tier: "core",
|
|
597
712
|
inputSchema: agentWebhookAttachInputSchema,
|
|
598
713
|
annotations: writeAnnotations({ idempotentHint: true }),
|
|
599
714
|
openApiOperations: ["GET /api/v1/projects/{name}/notifications", "POST /api/v1/projects/{name}/notifications"],
|
|
@@ -618,6 +733,7 @@ var canonryMcpTools = [
|
|
|
618
733
|
title: "Detach agent webhook",
|
|
619
734
|
description: "Detach the external agent webhook for a Canonry project.",
|
|
620
735
|
access: "write",
|
|
736
|
+
tier: "agent",
|
|
621
737
|
inputSchema: projectInputSchema,
|
|
622
738
|
annotations: writeAnnotations({ idempotentHint: true, destructiveHint: true }),
|
|
623
739
|
openApiOperations: ["GET /api/v1/projects/{name}/notifications", "DELETE /api/v1/projects/{name}/notifications/{id}"],
|
|
@@ -634,6 +750,7 @@ var canonryMcpTools = [
|
|
|
634
750
|
];
|
|
635
751
|
var CANONRY_MCP_TOOL_COUNT = canonryMcpTools.length;
|
|
636
752
|
var CANONRY_MCP_READ_TOOL_COUNT = canonryMcpTools.filter((tool) => tool.access === "read").length;
|
|
753
|
+
var CANONRY_MCP_CORE_TOOL_COUNT = canonryMcpTools.filter((tool) => tool.tier === "core").length;
|
|
637
754
|
|
|
638
755
|
// src/mcp/results.ts
|
|
639
756
|
function jsonToolResult(value) {
|
|
@@ -705,8 +822,119 @@ function hasErrorEnvelope(value) {
|
|
|
705
822
|
return Boolean(error && typeof error === "object");
|
|
706
823
|
}
|
|
707
824
|
|
|
825
|
+
// src/mcp/toolkits.ts
|
|
826
|
+
var CANONRY_MCP_TOOLKIT_NAMES = ["monitoring", "setup", "gsc", "ga", "agent"];
|
|
827
|
+
var CANONRY_MCP_TOOLKITS = [
|
|
828
|
+
{
|
|
829
|
+
name: "monitoring",
|
|
830
|
+
title: "Runs, snapshots, insights, health",
|
|
831
|
+
description: "Inspect run history, query snapshots, intelligence insights, and health timelines.",
|
|
832
|
+
whenToLoad: "Load when investigating regressions, comparing runs, or reviewing insights and health history."
|
|
833
|
+
},
|
|
834
|
+
{
|
|
835
|
+
name: "setup",
|
|
836
|
+
title: "Project configuration",
|
|
837
|
+
description: "Manage keywords, competitors, schedules, project upsert, and config-as-code roundtrips.",
|
|
838
|
+
whenToLoad: "Load when onboarding a new project or editing tracked keywords, competitors, or schedules."
|
|
839
|
+
},
|
|
840
|
+
{
|
|
841
|
+
name: "gsc",
|
|
842
|
+
title: "Google Search Console",
|
|
843
|
+
description: "Read GSC performance, inspections, coverage, sitemaps, and deindexed URLs.",
|
|
844
|
+
whenToLoad: "Load when you need indexing, coverage, or sitemap data from Google Search Console."
|
|
845
|
+
},
|
|
846
|
+
{
|
|
847
|
+
name: "ga",
|
|
848
|
+
title: "Google Analytics 4",
|
|
849
|
+
description: "Read GA traffic, AI/social referral history, attribution trend, and session history.",
|
|
850
|
+
whenToLoad: "Load when you need traffic, referral, or attribution data from Google Analytics 4."
|
|
851
|
+
},
|
|
852
|
+
{
|
|
853
|
+
name: "agent",
|
|
854
|
+
title: "Agent webhook lifecycle",
|
|
855
|
+
description: "Detach the configured external-agent webhook from a project.",
|
|
856
|
+
whenToLoad: "Load when removing an agent webhook subscription. (Attach lives in the core tier.)"
|
|
857
|
+
}
|
|
858
|
+
];
|
|
859
|
+
function isCanonryMcpToolkitName(value) {
|
|
860
|
+
return CANONRY_MCP_TOOLKIT_NAMES.includes(value);
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
// src/mcp/dynamic-catalog.ts
|
|
864
|
+
var DynamicToolCatalog = class {
|
|
865
|
+
entries;
|
|
866
|
+
loaded = /* @__PURE__ */ new Set();
|
|
867
|
+
eager;
|
|
868
|
+
scope;
|
|
869
|
+
constructor(entries, scope, options = {}) {
|
|
870
|
+
this.entries = entries;
|
|
871
|
+
this.scope = scope;
|
|
872
|
+
this.eager = Boolean(options.eager);
|
|
873
|
+
if (this.eager) {
|
|
874
|
+
for (const toolkit of CANONRY_MCP_TOOLKITS) {
|
|
875
|
+
if (this.toolsForToolkit(toolkit.name).length > 0) {
|
|
876
|
+
this.loaded.add(toolkit.name);
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
applyInitialEnablement() {
|
|
882
|
+
if (this.eager) return;
|
|
883
|
+
for (const entry of this.entries) {
|
|
884
|
+
if (entry.tool.tier !== "core") entry.registered.disable();
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
loadToolkit(rawName) {
|
|
888
|
+
if (!isCanonryMcpToolkitName(rawName)) {
|
|
889
|
+
const valid = CANONRY_MCP_TOOLKITS.map((t) => t.name).join(", ");
|
|
890
|
+
throw new Error(`Unknown toolkit "${rawName}". Available: ${valid}.`);
|
|
891
|
+
}
|
|
892
|
+
const name = rawName;
|
|
893
|
+
const matches = this.entries.filter((entry) => entry.tool.tier === name);
|
|
894
|
+
if (matches.length === 0) {
|
|
895
|
+
return { status: "empty", name, tools: [] };
|
|
896
|
+
}
|
|
897
|
+
if (this.loaded.has(name)) {
|
|
898
|
+
return { status: "already-loaded", name, tools: matches.map((entry) => entry.tool.name) };
|
|
899
|
+
}
|
|
900
|
+
for (const entry of matches) {
|
|
901
|
+
entry.registered.enable();
|
|
902
|
+
}
|
|
903
|
+
this.loaded.add(name);
|
|
904
|
+
return { status: "loaded", name, tools: matches.map((entry) => entry.tool.name) };
|
|
905
|
+
}
|
|
906
|
+
helpResult() {
|
|
907
|
+
return {
|
|
908
|
+
scope: this.scope,
|
|
909
|
+
eager: this.eager,
|
|
910
|
+
loadedToolkits: [...this.loaded].sort(),
|
|
911
|
+
coreTools: this.entries.filter((entry) => entry.tool.tier === "core").map((entry) => entry.tool.name),
|
|
912
|
+
toolkits: CANONRY_MCP_TOOLKITS.map((toolkit) => this.toolkitEntry(toolkit)).filter((entry) => entry.toolCount > 0),
|
|
913
|
+
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."
|
|
914
|
+
};
|
|
915
|
+
}
|
|
916
|
+
toolkitEntry(toolkit) {
|
|
917
|
+
const tools = this.toolsForToolkit(toolkit.name);
|
|
918
|
+
return {
|
|
919
|
+
name: toolkit.name,
|
|
920
|
+
title: toolkit.title,
|
|
921
|
+
description: toolkit.description,
|
|
922
|
+
whenToLoad: toolkit.whenToLoad,
|
|
923
|
+
toolCount: tools.length,
|
|
924
|
+
tools,
|
|
925
|
+
loaded: this.loaded.has(toolkit.name)
|
|
926
|
+
};
|
|
927
|
+
}
|
|
928
|
+
toolsForToolkit(name) {
|
|
929
|
+
return this.entries.filter((entry) => entry.tool.tier === name).map((entry) => entry.tool.name);
|
|
930
|
+
}
|
|
931
|
+
};
|
|
932
|
+
|
|
708
933
|
// src/mcp/server.ts
|
|
709
934
|
function createCanonryMcpServer(options = {}) {
|
|
935
|
+
return createCanonryMcpServerWithCatalog(options).server;
|
|
936
|
+
}
|
|
937
|
+
function createCanonryMcpServerWithCatalog(options = {}) {
|
|
710
938
|
const clientFactory = options.clientFactory ?? createApiClient;
|
|
711
939
|
const client = clientFactory();
|
|
712
940
|
const scope = options.scope ?? "all";
|
|
@@ -714,10 +942,11 @@ function createCanonryMcpServer(options = {}) {
|
|
|
714
942
|
name: "canonry",
|
|
715
943
|
version: PACKAGE_VERSION
|
|
716
944
|
});
|
|
945
|
+
const entries = [];
|
|
717
946
|
for (const registryTool of getCanonryMcpTools(scope)) {
|
|
718
947
|
const tool = registryTool;
|
|
719
948
|
const handler = tool.handler;
|
|
720
|
-
server.registerTool(
|
|
949
|
+
const registered = server.registerTool(
|
|
721
950
|
tool.name,
|
|
722
951
|
{
|
|
723
952
|
title: tool.title,
|
|
@@ -727,8 +956,36 @@ function createCanonryMcpServer(options = {}) {
|
|
|
727
956
|
},
|
|
728
957
|
async (input) => withToolErrors(() => handler(client, input))
|
|
729
958
|
);
|
|
959
|
+
entries.push({ tool, registered });
|
|
730
960
|
}
|
|
731
|
-
|
|
961
|
+
const catalog = new DynamicToolCatalog(entries, scope, { eager: options.eager });
|
|
962
|
+
catalog.applyInitialEnablement();
|
|
963
|
+
registerMetaTools(server, catalog);
|
|
964
|
+
return { server, catalog };
|
|
965
|
+
}
|
|
966
|
+
function registerMetaTools(server, catalog) {
|
|
967
|
+
server.registerTool(
|
|
968
|
+
"canonry_help",
|
|
969
|
+
{
|
|
970
|
+
title: "List Canonry MCP toolkits",
|
|
971
|
+
description: "List available toolkits and which are loaded. Call before canonry_load_toolkit if unsure which to load.",
|
|
972
|
+
inputSchema: {},
|
|
973
|
+
annotations: { readOnlyHint: true }
|
|
974
|
+
},
|
|
975
|
+
async () => withToolErrors(async () => catalog.helpResult())
|
|
976
|
+
);
|
|
977
|
+
server.registerTool(
|
|
978
|
+
"canonry_load_toolkit",
|
|
979
|
+
{
|
|
980
|
+
title: "Load a Canonry MCP toolkit",
|
|
981
|
+
description: "Register a toolkit's tools for this session and emit notifications/tools/list_changed. Idempotent. Loaded toolkits remain loaded for the rest of the session.",
|
|
982
|
+
inputSchema: {
|
|
983
|
+
name: z3.enum(CANONRY_MCP_TOOLKIT_NAMES).describe("Toolkit name. List options with canonry_help.")
|
|
984
|
+
},
|
|
985
|
+
annotations: { readOnlyHint: false, idempotentHint: true, destructiveHint: false }
|
|
986
|
+
},
|
|
987
|
+
async ({ name }) => withToolErrors(async () => catalog.loadToolkit(name))
|
|
988
|
+
);
|
|
732
989
|
}
|
|
733
990
|
function getCanonryMcpTools(scope = "all") {
|
|
734
991
|
return scope === "read-only" ? canonryMcpTools.filter((tool) => tool.access === "read") : [...canonryMcpTools];
|
|
@@ -736,17 +993,23 @@ function getCanonryMcpTools(scope = "all") {
|
|
|
736
993
|
|
|
737
994
|
// src/mcp/cli.ts
|
|
738
995
|
async function main(argv = process.argv.slice(2)) {
|
|
739
|
-
const
|
|
996
|
+
const options = parseCliOptions(argv);
|
|
997
|
+
const server = createCanonryMcpServer({ scope: options.scope, eager: options.eager });
|
|
740
998
|
await server.connect(new StdioServerTransport());
|
|
741
999
|
}
|
|
742
|
-
function
|
|
743
|
-
let scope = normalizeScope(
|
|
1000
|
+
function parseCliOptions(argv, env = process.env) {
|
|
1001
|
+
let scope = normalizeScope(env.CANONRY_MCP_SCOPE);
|
|
1002
|
+
let eager = parseEagerEnv(env.CANONRY_MCP_EAGER);
|
|
744
1003
|
for (let i = 0; i < argv.length; i += 1) {
|
|
745
1004
|
const arg = argv[i];
|
|
746
1005
|
if (arg === "--read-only") {
|
|
747
1006
|
scope = "read-only";
|
|
748
1007
|
continue;
|
|
749
1008
|
}
|
|
1009
|
+
if (arg === "--eager") {
|
|
1010
|
+
eager = true;
|
|
1011
|
+
continue;
|
|
1012
|
+
}
|
|
750
1013
|
if (arg === "--scope") {
|
|
751
1014
|
const next = argv[i + 1];
|
|
752
1015
|
if (!next) throw new Error("Missing value for --scope");
|
|
@@ -760,13 +1023,18 @@ function parseScope(argv, envScope = process.env.CANONRY_MCP_SCOPE) {
|
|
|
760
1023
|
}
|
|
761
1024
|
throw new Error(`Unknown canonry-mcp argument: ${arg}`);
|
|
762
1025
|
}
|
|
763
|
-
return scope;
|
|
1026
|
+
return { scope, eager };
|
|
764
1027
|
}
|
|
765
1028
|
function normalizeScope(value) {
|
|
766
1029
|
if (!value || value === "all") return "all";
|
|
767
1030
|
if (value === "read-only") return "read-only";
|
|
768
1031
|
throw new Error(`Invalid MCP scope "${value}". Expected "all" or "read-only".`);
|
|
769
1032
|
}
|
|
1033
|
+
function parseEagerEnv(value) {
|
|
1034
|
+
if (!value) return false;
|
|
1035
|
+
const normalized = value.trim().toLowerCase();
|
|
1036
|
+
return normalized === "1" || normalized === "true" || normalized === "yes";
|
|
1037
|
+
}
|
|
770
1038
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
771
1039
|
main().catch((error) => {
|
|
772
1040
|
const message = error instanceof Error ? error.message : "canonry-mcp failed";
|
|
@@ -777,5 +1045,5 @@ if (import.meta.url === `file://${process.argv[1]}`) {
|
|
|
777
1045
|
}
|
|
778
1046
|
export {
|
|
779
1047
|
main,
|
|
780
|
-
|
|
1048
|
+
parseCliOptions
|
|
781
1049
|
};
|