@ainyc/canonry 2.8.2 → 2.10.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.
- package/assets/assets/{index-U1lA1GKP.js → index-PhLDQh1e.js} +103 -102
- package/assets/index.html +1 -1
- package/dist/{chunk-FPZUQADO.js → chunk-KWQCQMPY.js} +78 -1
- package/dist/{chunk-MGBXRWLX.js → chunk-SZSWQG3J.js} +29 -10
- package/dist/cli.js +23 -8
- package/dist/index.js +2 -2
- package/dist/mcp.js +274 -10
- package/package.json +5 -5
package/dist/mcp.js
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
projectUpsertRequestSchema,
|
|
11
11
|
runTriggerRequestSchema,
|
|
12
12
|
scheduleUpsertRequestSchema
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-KWQCQMPY.js";
|
|
14
14
|
import "./chunk-MLKGABMK.js";
|
|
15
15
|
|
|
16
16
|
// src/mcp/cli.ts
|
|
@@ -18,6 +18,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
18
18
|
|
|
19
19
|
// src/mcp/server.ts
|
|
20
20
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
21
|
+
import { z as z3 } from "zod";
|
|
21
22
|
|
|
22
23
|
// src/package-version.ts
|
|
23
24
|
import { createRequire } from "module";
|
|
@@ -184,6 +185,7 @@ var canonryMcpTools = [
|
|
|
184
185
|
title: "List Canonry projects",
|
|
185
186
|
description: "List all Canonry projects available through the configured API.",
|
|
186
187
|
access: "read",
|
|
188
|
+
tier: "core",
|
|
187
189
|
inputSchema: emptyInputSchema,
|
|
188
190
|
annotations: readAnnotations(),
|
|
189
191
|
openApiOperations: ["GET /api/v1/projects"],
|
|
@@ -194,6 +196,7 @@ var canonryMcpTools = [
|
|
|
194
196
|
title: "Get project",
|
|
195
197
|
description: "Get a Canonry project by name.",
|
|
196
198
|
access: "read",
|
|
199
|
+
tier: "core",
|
|
197
200
|
inputSchema: projectInputSchema,
|
|
198
201
|
annotations: readAnnotations(),
|
|
199
202
|
openApiOperations: ["GET /api/v1/projects/{name}"],
|
|
@@ -204,6 +207,7 @@ var canonryMcpTools = [
|
|
|
204
207
|
title: "Export project config",
|
|
205
208
|
description: "Export a Canonry project in config-as-code format.",
|
|
206
209
|
access: "read",
|
|
210
|
+
tier: "setup",
|
|
207
211
|
inputSchema: projectInputSchema,
|
|
208
212
|
annotations: readAnnotations(),
|
|
209
213
|
openApiOperations: ["GET /api/v1/projects/{name}/export"],
|
|
@@ -214,6 +218,7 @@ var canonryMcpTools = [
|
|
|
214
218
|
title: "Get project history",
|
|
215
219
|
description: "Get audit history for a Canonry project.",
|
|
216
220
|
access: "read",
|
|
221
|
+
tier: "monitoring",
|
|
217
222
|
inputSchema: projectInputSchema,
|
|
218
223
|
annotations: readAnnotations(),
|
|
219
224
|
openApiOperations: ["GET /api/v1/projects/{name}/history"],
|
|
@@ -224,6 +229,7 @@ var canonryMcpTools = [
|
|
|
224
229
|
title: "List project runs",
|
|
225
230
|
description: "List runs for a Canonry project.",
|
|
226
231
|
access: "read",
|
|
232
|
+
tier: "monitoring",
|
|
227
233
|
inputSchema: runsListInputSchema,
|
|
228
234
|
annotations: readAnnotations(),
|
|
229
235
|
openApiOperations: ["GET /api/v1/projects/{name}/runs"],
|
|
@@ -234,6 +240,7 @@ var canonryMcpTools = [
|
|
|
234
240
|
title: "Get latest project run",
|
|
235
241
|
description: "Get the latest run and total run count for a Canonry project.",
|
|
236
242
|
access: "read",
|
|
243
|
+
tier: "monitoring",
|
|
237
244
|
inputSchema: projectInputSchema,
|
|
238
245
|
annotations: readAnnotations(),
|
|
239
246
|
openApiOperations: ["GET /api/v1/projects/{name}/runs/latest"],
|
|
@@ -244,6 +251,7 @@ var canonryMcpTools = [
|
|
|
244
251
|
title: "Get run",
|
|
245
252
|
description: "Get a Canonry run with its snapshots.",
|
|
246
253
|
access: "read",
|
|
254
|
+
tier: "monitoring",
|
|
247
255
|
inputSchema: runGetInputSchema,
|
|
248
256
|
annotations: readAnnotations(),
|
|
249
257
|
openApiOperations: ["GET /api/v1/runs/{id}"],
|
|
@@ -254,6 +262,7 @@ var canonryMcpTools = [
|
|
|
254
262
|
title: "Get project timeline",
|
|
255
263
|
description: "Get per-keyword citation history for a Canonry project.",
|
|
256
264
|
access: "read",
|
|
265
|
+
tier: "monitoring",
|
|
257
266
|
inputSchema: timelineInputSchema,
|
|
258
267
|
annotations: readAnnotations(),
|
|
259
268
|
openApiOperations: ["GET /api/v1/projects/{name}/timeline"],
|
|
@@ -264,6 +273,7 @@ var canonryMcpTools = [
|
|
|
264
273
|
title: "List query snapshots",
|
|
265
274
|
description: "List paginated query snapshots for a Canonry project.",
|
|
266
275
|
access: "read",
|
|
276
|
+
tier: "monitoring",
|
|
267
277
|
inputSchema: snapshotsListInputSchema,
|
|
268
278
|
annotations: readAnnotations(),
|
|
269
279
|
openApiOperations: ["GET /api/v1/projects/{name}/snapshots"],
|
|
@@ -278,6 +288,7 @@ var canonryMcpTools = [
|
|
|
278
288
|
title: "Diff snapshots",
|
|
279
289
|
description: "Compare query snapshot states between two Canonry runs.",
|
|
280
290
|
access: "read",
|
|
291
|
+
tier: "monitoring",
|
|
281
292
|
inputSchema: snapshotsDiffInputSchema,
|
|
282
293
|
annotations: readAnnotations(),
|
|
283
294
|
openApiOperations: ["GET /api/v1/projects/{name}/snapshots/diff"],
|
|
@@ -288,6 +299,7 @@ var canonryMcpTools = [
|
|
|
288
299
|
title: "List insights",
|
|
289
300
|
description: "List intelligence insights for a Canonry project.",
|
|
290
301
|
access: "read",
|
|
302
|
+
tier: "monitoring",
|
|
291
303
|
inputSchema: insightsListInputSchema,
|
|
292
304
|
annotations: readAnnotations(),
|
|
293
305
|
openApiOperations: ["GET /api/v1/projects/{name}/insights"],
|
|
@@ -298,6 +310,7 @@ var canonryMcpTools = [
|
|
|
298
310
|
title: "Get insight",
|
|
299
311
|
description: "Get one intelligence insight for a Canonry project.",
|
|
300
312
|
access: "read",
|
|
313
|
+
tier: "monitoring",
|
|
301
314
|
inputSchema: insightInputSchema,
|
|
302
315
|
annotations: readAnnotations(),
|
|
303
316
|
openApiOperations: ["GET /api/v1/projects/{name}/insights/{id}"],
|
|
@@ -306,8 +319,9 @@ var canonryMcpTools = [
|
|
|
306
319
|
defineTool({
|
|
307
320
|
name: "canonry_health_latest",
|
|
308
321
|
title: "Get latest health",
|
|
309
|
-
description:
|
|
322
|
+
description: 'Get the latest health snapshot for a Canonry project. Always returns a snapshot once the project exists: real data carries `status: "ready"`; newly-created projects (or projects with only failed runs) carry `status: "no-data"` with `reason: "no-runs-yet"` and zeroed metrics.',
|
|
310
323
|
access: "read",
|
|
324
|
+
tier: "monitoring",
|
|
311
325
|
inputSchema: projectInputSchema,
|
|
312
326
|
annotations: readAnnotations(),
|
|
313
327
|
openApiOperations: ["GET /api/v1/projects/{name}/health/latest"],
|
|
@@ -318,6 +332,7 @@ var canonryMcpTools = [
|
|
|
318
332
|
title: "Get health history",
|
|
319
333
|
description: "Get health snapshot history for a Canonry project.",
|
|
320
334
|
access: "read",
|
|
335
|
+
tier: "monitoring",
|
|
321
336
|
inputSchema: healthHistoryInputSchema,
|
|
322
337
|
annotations: readAnnotations(),
|
|
323
338
|
openApiOperations: ["GET /api/v1/projects/{name}/health/history"],
|
|
@@ -328,6 +343,7 @@ var canonryMcpTools = [
|
|
|
328
343
|
title: "List keywords",
|
|
329
344
|
description: "List tracked keywords for a Canonry project.",
|
|
330
345
|
access: "read",
|
|
346
|
+
tier: "setup",
|
|
331
347
|
inputSchema: projectInputSchema,
|
|
332
348
|
annotations: readAnnotations(),
|
|
333
349
|
openApiOperations: ["GET /api/v1/projects/{name}/keywords"],
|
|
@@ -338,6 +354,7 @@ var canonryMcpTools = [
|
|
|
338
354
|
title: "List competitors",
|
|
339
355
|
description: "List tracked competitors for a Canonry project.",
|
|
340
356
|
access: "read",
|
|
357
|
+
tier: "setup",
|
|
341
358
|
inputSchema: projectInputSchema,
|
|
342
359
|
annotations: readAnnotations(),
|
|
343
360
|
openApiOperations: ["GET /api/v1/projects/{name}/competitors"],
|
|
@@ -348,6 +365,7 @@ var canonryMcpTools = [
|
|
|
348
365
|
title: "Get schedule",
|
|
349
366
|
description: "Get the scheduled run configuration for a Canonry project.",
|
|
350
367
|
access: "read",
|
|
368
|
+
tier: "setup",
|
|
351
369
|
inputSchema: projectInputSchema,
|
|
352
370
|
annotations: readAnnotations(),
|
|
353
371
|
openApiOperations: ["GET /api/v1/projects/{name}/schedule"],
|
|
@@ -358,6 +376,7 @@ var canonryMcpTools = [
|
|
|
358
376
|
title: "Get settings",
|
|
359
377
|
description: "Get Canonry API settings and configured provider status.",
|
|
360
378
|
access: "read",
|
|
379
|
+
tier: "core",
|
|
361
380
|
inputSchema: emptyInputSchema,
|
|
362
381
|
annotations: readAnnotations(),
|
|
363
382
|
openApiOperations: ["GET /api/v1/settings"],
|
|
@@ -368,6 +387,7 @@ var canonryMcpTools = [
|
|
|
368
387
|
title: "List Google connections",
|
|
369
388
|
description: "List configured Google connections for a Canonry project.",
|
|
370
389
|
access: "read",
|
|
390
|
+
tier: "gsc",
|
|
371
391
|
inputSchema: projectInputSchema,
|
|
372
392
|
annotations: readAnnotations(),
|
|
373
393
|
openApiOperations: ["GET /api/v1/projects/{name}/google/connections"],
|
|
@@ -378,6 +398,7 @@ var canonryMcpTools = [
|
|
|
378
398
|
title: "Get GSC performance",
|
|
379
399
|
description: "Get stored Google Search Console performance rows for a Canonry project.",
|
|
380
400
|
access: "read",
|
|
401
|
+
tier: "gsc",
|
|
381
402
|
inputSchema: gscPerformanceInputSchema,
|
|
382
403
|
annotations: readAnnotations(),
|
|
383
404
|
openApiOperations: ["GET /api/v1/projects/{name}/google/gsc/performance"],
|
|
@@ -388,6 +409,7 @@ var canonryMcpTools = [
|
|
|
388
409
|
title: "List GSC inspections",
|
|
389
410
|
description: "List stored URL inspection rows for a Canonry project.",
|
|
390
411
|
access: "read",
|
|
412
|
+
tier: "gsc",
|
|
391
413
|
inputSchema: gscInspectionsInputSchema,
|
|
392
414
|
annotations: readAnnotations(),
|
|
393
415
|
openApiOperations: ["GET /api/v1/projects/{name}/google/gsc/inspections"],
|
|
@@ -398,6 +420,7 @@ var canonryMcpTools = [
|
|
|
398
420
|
title: "List deindexed GSC URLs",
|
|
399
421
|
description: "List URLs that appear to have become deindexed in Google Search Console data.",
|
|
400
422
|
access: "read",
|
|
423
|
+
tier: "gsc",
|
|
401
424
|
inputSchema: projectInputSchema,
|
|
402
425
|
annotations: readAnnotations(),
|
|
403
426
|
openApiOperations: ["GET /api/v1/projects/{name}/google/gsc/deindexed"],
|
|
@@ -408,6 +431,7 @@ var canonryMcpTools = [
|
|
|
408
431
|
title: "Get GSC coverage",
|
|
409
432
|
description: "Get Google Search Console coverage summary for a Canonry project.",
|
|
410
433
|
access: "read",
|
|
434
|
+
tier: "gsc",
|
|
411
435
|
inputSchema: projectInputSchema,
|
|
412
436
|
annotations: readAnnotations(),
|
|
413
437
|
openApiOperations: ["GET /api/v1/projects/{name}/google/gsc/coverage"],
|
|
@@ -418,6 +442,7 @@ var canonryMcpTools = [
|
|
|
418
442
|
title: "Get GSC coverage history",
|
|
419
443
|
description: "Get Google Search Console coverage history snapshots for a Canonry project.",
|
|
420
444
|
access: "read",
|
|
445
|
+
tier: "gsc",
|
|
421
446
|
inputSchema: gscCoverageHistoryInputSchema,
|
|
422
447
|
annotations: readAnnotations(),
|
|
423
448
|
openApiOperations: ["GET /api/v1/projects/{name}/google/gsc/coverage/history"],
|
|
@@ -428,6 +453,7 @@ var canonryMcpTools = [
|
|
|
428
453
|
title: "Get GSC sitemaps",
|
|
429
454
|
description: "Get sitemap data from Google Search Console for a Canonry project.",
|
|
430
455
|
access: "read",
|
|
456
|
+
tier: "gsc",
|
|
431
457
|
inputSchema: projectInputSchema,
|
|
432
458
|
annotations: readAnnotations(true),
|
|
433
459
|
openApiOperations: ["GET /api/v1/projects/{name}/google/gsc/sitemaps"],
|
|
@@ -438,6 +464,7 @@ var canonryMcpTools = [
|
|
|
438
464
|
title: "Get GA status",
|
|
439
465
|
description: "Get Google Analytics connection status for a Canonry project.",
|
|
440
466
|
access: "read",
|
|
467
|
+
tier: "ga",
|
|
441
468
|
inputSchema: projectInputSchema,
|
|
442
469
|
annotations: readAnnotations(),
|
|
443
470
|
openApiOperations: ["GET /api/v1/projects/{name}/ga/status"],
|
|
@@ -448,6 +475,7 @@ var canonryMcpTools = [
|
|
|
448
475
|
title: "Get GA traffic",
|
|
449
476
|
description: "Get Google Analytics traffic summary for a Canonry project.",
|
|
450
477
|
access: "read",
|
|
478
|
+
tier: "ga",
|
|
451
479
|
inputSchema: gaTrafficInputSchema,
|
|
452
480
|
annotations: readAnnotations(),
|
|
453
481
|
openApiOperations: ["GET /api/v1/projects/{name}/ga/traffic"],
|
|
@@ -458,6 +486,7 @@ var canonryMcpTools = [
|
|
|
458
486
|
title: "Get GA coverage",
|
|
459
487
|
description: "Get Google Analytics page coverage for a Canonry project.",
|
|
460
488
|
access: "read",
|
|
489
|
+
tier: "ga",
|
|
461
490
|
inputSchema: projectInputSchema,
|
|
462
491
|
annotations: readAnnotations(),
|
|
463
492
|
openApiOperations: ["GET /api/v1/projects/{name}/ga/coverage"],
|
|
@@ -468,6 +497,7 @@ var canonryMcpTools = [
|
|
|
468
497
|
title: "Get GA AI referral history",
|
|
469
498
|
description: "Get AI referral sessions per day grouped by source.",
|
|
470
499
|
access: "read",
|
|
500
|
+
tier: "ga",
|
|
471
501
|
inputSchema: gaWindowInputSchema,
|
|
472
502
|
annotations: readAnnotations(),
|
|
473
503
|
openApiOperations: ["GET /api/v1/projects/{name}/ga/ai-referral-history"],
|
|
@@ -478,6 +508,7 @@ var canonryMcpTools = [
|
|
|
478
508
|
title: "Get GA social referral history",
|
|
479
509
|
description: "Get social referral sessions per day grouped by source.",
|
|
480
510
|
access: "read",
|
|
511
|
+
tier: "ga",
|
|
481
512
|
inputSchema: gaWindowInputSchema,
|
|
482
513
|
annotations: readAnnotations(),
|
|
483
514
|
openApiOperations: ["GET /api/v1/projects/{name}/ga/social-referral-history"],
|
|
@@ -488,6 +519,7 @@ var canonryMcpTools = [
|
|
|
488
519
|
title: "Get GA social referral trend",
|
|
489
520
|
description: "Get social referral trend with biggest mover for a Canonry project.",
|
|
490
521
|
access: "read",
|
|
522
|
+
tier: "ga",
|
|
491
523
|
inputSchema: projectInputSchema,
|
|
492
524
|
annotations: readAnnotations(),
|
|
493
525
|
openApiOperations: ["GET /api/v1/projects/{name}/ga/social-referral-trend"],
|
|
@@ -498,6 +530,7 @@ var canonryMcpTools = [
|
|
|
498
530
|
title: "Get GA attribution trend",
|
|
499
531
|
description: "Get per-channel attribution trends for organic, AI, social, and total sessions.",
|
|
500
532
|
access: "read",
|
|
533
|
+
tier: "ga",
|
|
501
534
|
inputSchema: projectInputSchema,
|
|
502
535
|
annotations: readAnnotations(),
|
|
503
536
|
openApiOperations: ["GET /api/v1/projects/{name}/ga/attribution-trend"],
|
|
@@ -508,6 +541,7 @@ var canonryMcpTools = [
|
|
|
508
541
|
title: "Get GA session history",
|
|
509
542
|
description: "Get total sessions per day for a Canonry project.",
|
|
510
543
|
access: "read",
|
|
544
|
+
tier: "ga",
|
|
511
545
|
inputSchema: gaWindowInputSchema,
|
|
512
546
|
annotations: readAnnotations(),
|
|
513
547
|
openApiOperations: ["GET /api/v1/projects/{name}/ga/session-history"],
|
|
@@ -518,6 +552,7 @@ var canonryMcpTools = [
|
|
|
518
552
|
title: "Create or replace project",
|
|
519
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.",
|
|
520
554
|
access: "write",
|
|
555
|
+
tier: "setup",
|
|
521
556
|
inputSchema: projectUpsertInputSchema,
|
|
522
557
|
annotations: writeAnnotations({ idempotentHint: true, destructiveHint: true }),
|
|
523
558
|
openApiOperations: ["PUT /api/v1/projects/{name}"],
|
|
@@ -528,6 +563,7 @@ var canonryMcpTools = [
|
|
|
528
563
|
title: "Apply project config",
|
|
529
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.",
|
|
530
565
|
access: "write",
|
|
566
|
+
tier: "core",
|
|
531
567
|
inputSchema: applyConfigInputSchema,
|
|
532
568
|
// Declarative apply is safe to repeat, but it replaces configured child state.
|
|
533
569
|
annotations: writeAnnotations({ idempotentHint: true, destructiveHint: true }),
|
|
@@ -539,6 +575,7 @@ var canonryMcpTools = [
|
|
|
539
575
|
title: "Generate keyword suggestions",
|
|
540
576
|
description: "Generate candidate key phrases using a configured provider. Returns suggestions only; use canonry_keywords_add to persist them.",
|
|
541
577
|
access: "write",
|
|
578
|
+
tier: "setup",
|
|
542
579
|
inputSchema: keywordGenerateInputSchema,
|
|
543
580
|
annotations: writeAnnotations({ idempotentHint: false, openWorldHint: true }),
|
|
544
581
|
openApiOperations: ["POST /api/v1/projects/{name}/keywords/generate"],
|
|
@@ -549,6 +586,7 @@ var canonryMcpTools = [
|
|
|
549
586
|
title: "Replace keywords",
|
|
550
587
|
description: "Replace the tracked keyword set for a Canonry project.",
|
|
551
588
|
access: "write",
|
|
589
|
+
tier: "setup",
|
|
552
590
|
inputSchema: keywordsInputSchema,
|
|
553
591
|
annotations: writeAnnotations({ idempotentHint: true, destructiveHint: true }),
|
|
554
592
|
openApiOperations: ["PUT /api/v1/projects/{name}/keywords"],
|
|
@@ -561,6 +599,7 @@ var canonryMcpTools = [
|
|
|
561
599
|
title: "Trigger run",
|
|
562
600
|
description: "Trigger an answer-visibility run for a Canonry project.",
|
|
563
601
|
access: "write",
|
|
602
|
+
tier: "core",
|
|
564
603
|
inputSchema: runTriggerInputSchema,
|
|
565
604
|
annotations: writeAnnotations({ idempotentHint: false, openWorldHint: true }),
|
|
566
605
|
openApiOperations: ["POST /api/v1/projects/{name}/runs"],
|
|
@@ -571,6 +610,7 @@ var canonryMcpTools = [
|
|
|
571
610
|
title: "Cancel run",
|
|
572
611
|
description: "Cancel a queued or running Canonry run.",
|
|
573
612
|
access: "write",
|
|
613
|
+
tier: "core",
|
|
574
614
|
inputSchema: runGetInputSchema,
|
|
575
615
|
annotations: writeAnnotations({ idempotentHint: false, destructiveHint: true }),
|
|
576
616
|
openApiOperations: ["POST /api/v1/runs/{id}/cancel"],
|
|
@@ -581,6 +621,7 @@ var canonryMcpTools = [
|
|
|
581
621
|
title: "Add keywords",
|
|
582
622
|
description: "Append tracked keywords to a Canonry project; existing keywords are skipped by the API.",
|
|
583
623
|
access: "write",
|
|
624
|
+
tier: "setup",
|
|
584
625
|
inputSchema: keywordsInputSchema,
|
|
585
626
|
annotations: writeAnnotations({ idempotentHint: true }),
|
|
586
627
|
openApiOperations: ["POST /api/v1/projects/{name}/keywords"],
|
|
@@ -593,6 +634,7 @@ var canonryMcpTools = [
|
|
|
593
634
|
title: "Remove keywords",
|
|
594
635
|
description: "Remove tracked keywords from a Canonry project.",
|
|
595
636
|
access: "write",
|
|
637
|
+
tier: "setup",
|
|
596
638
|
inputSchema: keywordsInputSchema,
|
|
597
639
|
annotations: writeAnnotations({ idempotentHint: true, destructiveHint: true }),
|
|
598
640
|
openApiOperations: ["DELETE /api/v1/projects/{name}/keywords"],
|
|
@@ -605,6 +647,7 @@ var canonryMcpTools = [
|
|
|
605
647
|
title: "Add competitors",
|
|
606
648
|
description: "Add tracked competitor domains to a Canonry project.",
|
|
607
649
|
access: "write",
|
|
650
|
+
tier: "setup",
|
|
608
651
|
inputSchema: competitorsInputSchema,
|
|
609
652
|
annotations: writeAnnotations({ idempotentHint: true }),
|
|
610
653
|
openApiOperations: ["POST /api/v1/projects/{name}/competitors"],
|
|
@@ -617,6 +660,7 @@ var canonryMcpTools = [
|
|
|
617
660
|
title: "Remove competitors",
|
|
618
661
|
description: "Remove tracked competitor domains from a Canonry project.",
|
|
619
662
|
access: "write",
|
|
663
|
+
tier: "setup",
|
|
620
664
|
inputSchema: competitorsInputSchema,
|
|
621
665
|
annotations: writeAnnotations({ idempotentHint: true, destructiveHint: true }),
|
|
622
666
|
openApiOperations: ["DELETE /api/v1/projects/{name}/competitors"],
|
|
@@ -629,6 +673,7 @@ var canonryMcpTools = [
|
|
|
629
673
|
title: "Set schedule",
|
|
630
674
|
description: "Create or replace the scheduled run configuration for a Canonry project.",
|
|
631
675
|
access: "write",
|
|
676
|
+
tier: "setup",
|
|
632
677
|
inputSchema: scheduleSetInputSchema,
|
|
633
678
|
annotations: writeAnnotations({ idempotentHint: true }),
|
|
634
679
|
openApiOperations: ["PUT /api/v1/projects/{name}/schedule"],
|
|
@@ -639,6 +684,7 @@ var canonryMcpTools = [
|
|
|
639
684
|
title: "Delete schedule",
|
|
640
685
|
description: "Delete the scheduled run configuration for a Canonry project.",
|
|
641
686
|
access: "write",
|
|
687
|
+
tier: "setup",
|
|
642
688
|
inputSchema: projectInputSchema,
|
|
643
689
|
annotations: writeAnnotations({ idempotentHint: false, destructiveHint: true }),
|
|
644
690
|
openApiOperations: ["DELETE /api/v1/projects/{name}/schedule"],
|
|
@@ -651,6 +697,7 @@ var canonryMcpTools = [
|
|
|
651
697
|
title: "Dismiss insight",
|
|
652
698
|
description: "Dismiss an intelligence insight for a Canonry project.",
|
|
653
699
|
access: "write",
|
|
700
|
+
tier: "setup",
|
|
654
701
|
inputSchema: insightInputSchema,
|
|
655
702
|
annotations: writeAnnotations({ idempotentHint: true }),
|
|
656
703
|
openApiOperations: ["POST /api/v1/projects/{name}/insights/{id}/dismiss"],
|
|
@@ -661,6 +708,7 @@ var canonryMcpTools = [
|
|
|
661
708
|
title: "Attach agent webhook",
|
|
662
709
|
description: "Attach an external agent webhook to project run and insight events.",
|
|
663
710
|
access: "write",
|
|
711
|
+
tier: "core",
|
|
664
712
|
inputSchema: agentWebhookAttachInputSchema,
|
|
665
713
|
annotations: writeAnnotations({ idempotentHint: true }),
|
|
666
714
|
openApiOperations: ["GET /api/v1/projects/{name}/notifications", "POST /api/v1/projects/{name}/notifications"],
|
|
@@ -685,6 +733,7 @@ var canonryMcpTools = [
|
|
|
685
733
|
title: "Detach agent webhook",
|
|
686
734
|
description: "Detach the external agent webhook for a Canonry project.",
|
|
687
735
|
access: "write",
|
|
736
|
+
tier: "agent",
|
|
688
737
|
inputSchema: projectInputSchema,
|
|
689
738
|
annotations: writeAnnotations({ idempotentHint: true, destructiveHint: true }),
|
|
690
739
|
openApiOperations: ["GET /api/v1/projects/{name}/notifications", "DELETE /api/v1/projects/{name}/notifications/{id}"],
|
|
@@ -701,8 +750,10 @@ var canonryMcpTools = [
|
|
|
701
750
|
];
|
|
702
751
|
var CANONRY_MCP_TOOL_COUNT = canonryMcpTools.length;
|
|
703
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;
|
|
704
754
|
|
|
705
755
|
// src/mcp/results.ts
|
|
756
|
+
import { ZodError } from "zod";
|
|
706
757
|
function jsonToolResult(value) {
|
|
707
758
|
const result = value === void 0 ? { ok: true } : value;
|
|
708
759
|
return {
|
|
@@ -733,6 +784,15 @@ async function withToolErrors(handler) {
|
|
|
733
784
|
}
|
|
734
785
|
}
|
|
735
786
|
function toCanonryErrorEnvelope(error) {
|
|
787
|
+
if (error instanceof ZodError) {
|
|
788
|
+
return {
|
|
789
|
+
error: {
|
|
790
|
+
code: "VALIDATION_ERROR",
|
|
791
|
+
message: zodErrorMessage(error),
|
|
792
|
+
details: { issues: error.issues.map(formatZodIssue) }
|
|
793
|
+
}
|
|
794
|
+
};
|
|
795
|
+
}
|
|
736
796
|
if (error instanceof CliError) {
|
|
737
797
|
return {
|
|
738
798
|
error: {
|
|
@@ -771,9 +831,129 @@ function hasErrorEnvelope(value) {
|
|
|
771
831
|
const error = value.error;
|
|
772
832
|
return Boolean(error && typeof error === "object");
|
|
773
833
|
}
|
|
834
|
+
function formatZodIssue(issue) {
|
|
835
|
+
return { path: issue.path.map(String).join("."), message: issue.message };
|
|
836
|
+
}
|
|
837
|
+
function zodErrorMessage(error) {
|
|
838
|
+
const first = error.issues[0];
|
|
839
|
+
if (!first) return "Input validation failed";
|
|
840
|
+
const path = first.path.map(String).join(".");
|
|
841
|
+
return path ? `${path}: ${first.message}` : first.message;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
// src/mcp/toolkits.ts
|
|
845
|
+
var CANONRY_MCP_TOOLKIT_NAMES = ["monitoring", "setup", "gsc", "ga", "agent"];
|
|
846
|
+
var CANONRY_MCP_TOOLKITS = [
|
|
847
|
+
{
|
|
848
|
+
name: "monitoring",
|
|
849
|
+
title: "Runs, snapshots, insights, health",
|
|
850
|
+
description: "Inspect run history, query snapshots, intelligence insights, and health timelines.",
|
|
851
|
+
whenToLoad: "Load when investigating regressions, comparing runs, or reviewing insights and health history."
|
|
852
|
+
},
|
|
853
|
+
{
|
|
854
|
+
name: "setup",
|
|
855
|
+
title: "Project configuration",
|
|
856
|
+
description: "Manage keywords, competitors, schedules, project upsert, and config-as-code roundtrips.",
|
|
857
|
+
whenToLoad: "Load when onboarding a new project or editing tracked keywords, competitors, or schedules."
|
|
858
|
+
},
|
|
859
|
+
{
|
|
860
|
+
name: "gsc",
|
|
861
|
+
title: "Google Search Console",
|
|
862
|
+
description: "Read GSC performance, inspections, coverage, sitemaps, and deindexed URLs.",
|
|
863
|
+
whenToLoad: "Load when you need indexing, coverage, or sitemap data from Google Search Console."
|
|
864
|
+
},
|
|
865
|
+
{
|
|
866
|
+
name: "ga",
|
|
867
|
+
title: "Google Analytics 4",
|
|
868
|
+
description: "Read GA traffic, AI/social referral history, attribution trend, and session history.",
|
|
869
|
+
whenToLoad: "Load when you need traffic, referral, or attribution data from Google Analytics 4."
|
|
870
|
+
},
|
|
871
|
+
{
|
|
872
|
+
name: "agent",
|
|
873
|
+
title: "Agent webhook lifecycle",
|
|
874
|
+
description: "Detach the configured external-agent webhook from a project.",
|
|
875
|
+
whenToLoad: "Load when removing an agent webhook subscription. (Attach lives in the core tier.)"
|
|
876
|
+
}
|
|
877
|
+
];
|
|
878
|
+
function isCanonryMcpToolkitName(value) {
|
|
879
|
+
return CANONRY_MCP_TOOLKIT_NAMES.includes(value);
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
// src/mcp/dynamic-catalog.ts
|
|
883
|
+
var DynamicToolCatalog = class {
|
|
884
|
+
entries;
|
|
885
|
+
loaded = /* @__PURE__ */ new Set();
|
|
886
|
+
eager;
|
|
887
|
+
scope;
|
|
888
|
+
constructor(entries, scope, options = {}) {
|
|
889
|
+
this.entries = entries;
|
|
890
|
+
this.scope = scope;
|
|
891
|
+
this.eager = Boolean(options.eager);
|
|
892
|
+
if (this.eager) {
|
|
893
|
+
for (const toolkit of CANONRY_MCP_TOOLKITS) {
|
|
894
|
+
if (this.toolsForToolkit(toolkit.name).length > 0) {
|
|
895
|
+
this.loaded.add(toolkit.name);
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
applyInitialEnablement() {
|
|
901
|
+
if (this.eager) return;
|
|
902
|
+
for (const entry of this.entries) {
|
|
903
|
+
if (entry.tool.tier !== "core") entry.registered.disable();
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
loadToolkit(rawName) {
|
|
907
|
+
if (!isCanonryMcpToolkitName(rawName)) {
|
|
908
|
+
const valid = CANONRY_MCP_TOOLKITS.map((t) => t.name).join(", ");
|
|
909
|
+
throw new Error(`Unknown toolkit "${rawName}". Available: ${valid}.`);
|
|
910
|
+
}
|
|
911
|
+
const name = rawName;
|
|
912
|
+
const matches = this.entries.filter((entry) => entry.tool.tier === name);
|
|
913
|
+
if (matches.length === 0) {
|
|
914
|
+
return { status: "empty", name, tools: [] };
|
|
915
|
+
}
|
|
916
|
+
if (this.loaded.has(name)) {
|
|
917
|
+
return { status: "already-loaded", name, tools: matches.map((entry) => entry.tool.name) };
|
|
918
|
+
}
|
|
919
|
+
for (const entry of matches) {
|
|
920
|
+
entry.registered.enable();
|
|
921
|
+
}
|
|
922
|
+
this.loaded.add(name);
|
|
923
|
+
return { status: "loaded", name, tools: matches.map((entry) => entry.tool.name) };
|
|
924
|
+
}
|
|
925
|
+
helpResult() {
|
|
926
|
+
return {
|
|
927
|
+
scope: this.scope,
|
|
928
|
+
eager: this.eager,
|
|
929
|
+
loadedToolkits: [...this.loaded].sort(),
|
|
930
|
+
coreTools: this.entries.filter((entry) => entry.tool.tier === "core").map((entry) => entry.tool.name),
|
|
931
|
+
toolkits: CANONRY_MCP_TOOLKITS.map((toolkit) => this.toolkitEntry(toolkit)).filter((entry) => entry.toolCount > 0),
|
|
932
|
+
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."
|
|
933
|
+
};
|
|
934
|
+
}
|
|
935
|
+
toolkitEntry(toolkit) {
|
|
936
|
+
const tools = this.toolsForToolkit(toolkit.name);
|
|
937
|
+
return {
|
|
938
|
+
name: toolkit.name,
|
|
939
|
+
title: toolkit.title,
|
|
940
|
+
description: toolkit.description,
|
|
941
|
+
whenToLoad: toolkit.whenToLoad,
|
|
942
|
+
toolCount: tools.length,
|
|
943
|
+
tools,
|
|
944
|
+
loaded: this.loaded.has(toolkit.name)
|
|
945
|
+
};
|
|
946
|
+
}
|
|
947
|
+
toolsForToolkit(name) {
|
|
948
|
+
return this.entries.filter((entry) => entry.tool.tier === name).map((entry) => entry.tool.name);
|
|
949
|
+
}
|
|
950
|
+
};
|
|
774
951
|
|
|
775
952
|
// src/mcp/server.ts
|
|
776
953
|
function createCanonryMcpServer(options = {}) {
|
|
954
|
+
return createCanonryMcpServerWithCatalog(options).server;
|
|
955
|
+
}
|
|
956
|
+
function createCanonryMcpServerWithCatalog(options = {}) {
|
|
777
957
|
const clientFactory = options.clientFactory ?? createApiClient;
|
|
778
958
|
const client = clientFactory();
|
|
779
959
|
const scope = options.scope ?? "all";
|
|
@@ -781,10 +961,12 @@ function createCanonryMcpServer(options = {}) {
|
|
|
781
961
|
name: "canonry",
|
|
782
962
|
version: PACKAGE_VERSION
|
|
783
963
|
});
|
|
964
|
+
server.validateToolInput = async (_tool, args) => args;
|
|
965
|
+
const entries = [];
|
|
784
966
|
for (const registryTool of getCanonryMcpTools(scope)) {
|
|
785
967
|
const tool = registryTool;
|
|
786
968
|
const handler = tool.handler;
|
|
787
|
-
server.registerTool(
|
|
969
|
+
const registered = server.registerTool(
|
|
788
970
|
tool.name,
|
|
789
971
|
{
|
|
790
972
|
title: tool.title,
|
|
@@ -792,28 +974,103 @@ function createCanonryMcpServer(options = {}) {
|
|
|
792
974
|
inputSchema: tool.inputSchema,
|
|
793
975
|
annotations: tool.annotations
|
|
794
976
|
},
|
|
795
|
-
async (input) => withToolErrors(() =>
|
|
977
|
+
async (input) => withToolErrors(async () => {
|
|
978
|
+
const parsed = tool.inputSchema.parse(input ?? {});
|
|
979
|
+
return handler(client, parsed);
|
|
980
|
+
})
|
|
796
981
|
);
|
|
982
|
+
entries.push({ tool, registered });
|
|
797
983
|
}
|
|
798
|
-
|
|
984
|
+
const catalog = new DynamicToolCatalog(entries, scope, { eager: options.eager });
|
|
985
|
+
catalog.applyInitialEnablement();
|
|
986
|
+
registerMetaTools(server, catalog);
|
|
987
|
+
return { server, catalog };
|
|
988
|
+
}
|
|
989
|
+
var loadToolkitInputSchema = z3.object({
|
|
990
|
+
name: z3.enum(CANONRY_MCP_TOOLKIT_NAMES).describe("Toolkit name. List options with canonry_help.")
|
|
991
|
+
});
|
|
992
|
+
function registerMetaTools(server, catalog) {
|
|
993
|
+
server.registerTool(
|
|
994
|
+
"canonry_help",
|
|
995
|
+
{
|
|
996
|
+
title: "List Canonry MCP toolkits",
|
|
997
|
+
description: "List available toolkits and which are loaded. Call before canonry_load_toolkit if unsure which to load.",
|
|
998
|
+
inputSchema: {},
|
|
999
|
+
annotations: { readOnlyHint: true }
|
|
1000
|
+
},
|
|
1001
|
+
async () => withToolErrors(async () => catalog.helpResult())
|
|
1002
|
+
);
|
|
1003
|
+
server.registerTool(
|
|
1004
|
+
"canonry_load_toolkit",
|
|
1005
|
+
{
|
|
1006
|
+
title: "Load a Canonry MCP toolkit",
|
|
1007
|
+
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.",
|
|
1008
|
+
inputSchema: loadToolkitInputSchema.shape,
|
|
1009
|
+
annotations: { readOnlyHint: false, idempotentHint: true, destructiveHint: false }
|
|
1010
|
+
},
|
|
1011
|
+
async (input) => withToolErrors(async () => {
|
|
1012
|
+
const parsed = loadToolkitInputSchema.parse(input ?? {});
|
|
1013
|
+
return catalog.loadToolkit(parsed.name);
|
|
1014
|
+
})
|
|
1015
|
+
);
|
|
799
1016
|
}
|
|
800
1017
|
function getCanonryMcpTools(scope = "all") {
|
|
801
1018
|
return scope === "read-only" ? canonryMcpTools.filter((tool) => tool.access === "read") : [...canonryMcpTools];
|
|
802
1019
|
}
|
|
803
1020
|
|
|
804
1021
|
// src/mcp/cli.ts
|
|
1022
|
+
var HELP_TEXT = `Usage: canonry-mcp [--read-only | --scope=<all|read-only>] [--eager]
|
|
1023
|
+
|
|
1024
|
+
Stdio MCP adapter over the Canonry public API. Inherits config from
|
|
1025
|
+
~/.canonry/config.yaml (or $CANONRY_CONFIG_DIR/config.yaml).
|
|
1026
|
+
|
|
1027
|
+
Flags:
|
|
1028
|
+
--read-only Expose read tools only
|
|
1029
|
+
--scope=<all|read-only>
|
|
1030
|
+
Same as --read-only when "read-only"
|
|
1031
|
+
--eager Load all toolkits at start (skip progressive discovery)
|
|
1032
|
+
--help, -h Show this message
|
|
1033
|
+
|
|
1034
|
+
Environment variables:
|
|
1035
|
+
CANONRY_MCP_SCOPE "all" (default) or "read-only"
|
|
1036
|
+
CANONRY_MCP_EAGER "1" / "true" / "yes" to enable eager mode
|
|
1037
|
+
`;
|
|
1038
|
+
var HelpRequested = class extends Error {
|
|
1039
|
+
constructor() {
|
|
1040
|
+
super("canonry-mcp --help requested");
|
|
1041
|
+
this.name = "HelpRequested";
|
|
1042
|
+
}
|
|
1043
|
+
};
|
|
805
1044
|
async function main(argv = process.argv.slice(2)) {
|
|
806
|
-
|
|
1045
|
+
let options;
|
|
1046
|
+
try {
|
|
1047
|
+
options = parseCliOptions(argv);
|
|
1048
|
+
} catch (error) {
|
|
1049
|
+
if (error instanceof HelpRequested) {
|
|
1050
|
+
process.stderr.write(HELP_TEXT);
|
|
1051
|
+
return;
|
|
1052
|
+
}
|
|
1053
|
+
throw error;
|
|
1054
|
+
}
|
|
1055
|
+
const server = createCanonryMcpServer({ scope: options.scope, eager: options.eager });
|
|
807
1056
|
await server.connect(new StdioServerTransport());
|
|
808
1057
|
}
|
|
809
|
-
function
|
|
810
|
-
|
|
1058
|
+
function parseCliOptions(argv, env = process.env) {
|
|
1059
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
1060
|
+
throw new HelpRequested();
|
|
1061
|
+
}
|
|
1062
|
+
let scope = normalizeScope(env.CANONRY_MCP_SCOPE);
|
|
1063
|
+
let eager = parseEagerEnv(env.CANONRY_MCP_EAGER);
|
|
811
1064
|
for (let i = 0; i < argv.length; i += 1) {
|
|
812
1065
|
const arg = argv[i];
|
|
813
1066
|
if (arg === "--read-only") {
|
|
814
1067
|
scope = "read-only";
|
|
815
1068
|
continue;
|
|
816
1069
|
}
|
|
1070
|
+
if (arg === "--eager") {
|
|
1071
|
+
eager = true;
|
|
1072
|
+
continue;
|
|
1073
|
+
}
|
|
817
1074
|
if (arg === "--scope") {
|
|
818
1075
|
const next = argv[i + 1];
|
|
819
1076
|
if (!next) throw new Error("Missing value for --scope");
|
|
@@ -827,13 +1084,18 @@ function parseScope(argv, envScope = process.env.CANONRY_MCP_SCOPE) {
|
|
|
827
1084
|
}
|
|
828
1085
|
throw new Error(`Unknown canonry-mcp argument: ${arg}`);
|
|
829
1086
|
}
|
|
830
|
-
return scope;
|
|
1087
|
+
return { scope, eager };
|
|
831
1088
|
}
|
|
832
1089
|
function normalizeScope(value) {
|
|
833
1090
|
if (!value || value === "all") return "all";
|
|
834
1091
|
if (value === "read-only") return "read-only";
|
|
835
1092
|
throw new Error(`Invalid MCP scope "${value}". Expected "all" or "read-only".`);
|
|
836
1093
|
}
|
|
1094
|
+
function parseEagerEnv(value) {
|
|
1095
|
+
if (!value) return false;
|
|
1096
|
+
const normalized = value.trim().toLowerCase();
|
|
1097
|
+
return normalized === "1" || normalized === "true" || normalized === "yes";
|
|
1098
|
+
}
|
|
837
1099
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
838
1100
|
main().catch((error) => {
|
|
839
1101
|
const message = error instanceof Error ? error.message : "canonry-mcp failed";
|
|
@@ -843,6 +1105,8 @@ if (import.meta.url === `file://${process.argv[1]}`) {
|
|
|
843
1105
|
});
|
|
844
1106
|
}
|
|
845
1107
|
export {
|
|
1108
|
+
HELP_TEXT,
|
|
1109
|
+
HelpRequested,
|
|
846
1110
|
main,
|
|
847
|
-
|
|
1111
|
+
parseCliOptions
|
|
848
1112
|
};
|