@primer/mcp 0.0.2 → 0.0.4
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 +3 -3
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/primer.d.ts +8 -1
- package/dist/primer.d.ts.map +1 -1
- package/dist/primitives.d.ts +65 -0
- package/dist/primitives.d.ts.map +1 -0
- package/dist/server-DHzOLtG9.js +718 -0
- package/dist/server-DSob2l4p.js +671 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/stdio.js +16 -519
- package/package.json +17 -12
- package/src/index.ts +1 -0
- package/src/primer.ts +42 -1
- package/src/primitives.ts +103 -0
- package/src/server.ts +238 -424
package/src/server.ts
CHANGED
|
@@ -3,7 +3,8 @@ import {McpServer} from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
|
3
3
|
import * as cheerio from 'cheerio'
|
|
4
4
|
import {z} from 'zod'
|
|
5
5
|
import TurndownService from 'turndown'
|
|
6
|
-
import {listComponents, listPatterns} from './primer'
|
|
6
|
+
import {listComponents, listPatterns, listIcons} from './primer'
|
|
7
|
+
import {tokens, serialize} from './primitives'
|
|
7
8
|
import packageJson from '../package.json' with {type: 'json'}
|
|
8
9
|
|
|
9
10
|
const server = new McpServer({
|
|
@@ -13,10 +14,59 @@ const server = new McpServer({
|
|
|
13
14
|
|
|
14
15
|
const turndownService = new TurndownService()
|
|
15
16
|
|
|
17
|
+
// -----------------------------------------------------------------------------
|
|
18
|
+
// Project setup
|
|
19
|
+
// -----------------------------------------------------------------------------
|
|
20
|
+
server.tool('init', 'Setup or create a project that includes Primer React', async () => {
|
|
21
|
+
const url = new URL(`/product/getting-started/react`, 'https://primer.style')
|
|
22
|
+
const response = await fetch(url)
|
|
23
|
+
if (!response.ok) {
|
|
24
|
+
throw new Error(`Failed to fetch ${url}: ${response.statusText}`)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const html = await response.text()
|
|
28
|
+
if (!html) {
|
|
29
|
+
return {
|
|
30
|
+
content: [],
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const $ = cheerio.load(html)
|
|
35
|
+
const source = $('main').html()
|
|
36
|
+
if (!source) {
|
|
37
|
+
return {
|
|
38
|
+
content: [],
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const text = turndownService.turndown(source)
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
content: [
|
|
46
|
+
{
|
|
47
|
+
type: 'text',
|
|
48
|
+
text: `The getting started documentation for Primer React is included below. It's important that the project:
|
|
49
|
+
|
|
50
|
+
- Is using a tool like Vite, Next.js, etc that supports TypeScript and React. If the project does not have support for that, generate an appropriate project scaffold
|
|
51
|
+
- Installs the latest version of \`@primer/react\` from \`npm\`
|
|
52
|
+
- Correctly adds the \`ThemeProvider\` and \`BaseStyles\` components to the root of the application
|
|
53
|
+
- Includes an import to a theme from \`@primer/primitives\`
|
|
54
|
+
- If the project wants to use icons, also install the \`@primer/octicons-react\` from \`npm\`
|
|
55
|
+
- Add appropriate agent instructions (like for copilot) to the project to prefer using components, tokens, icons, and more from Primer packages
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
${text}
|
|
60
|
+
`,
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
|
|
16
66
|
// -----------------------------------------------------------------------------
|
|
17
67
|
// Components
|
|
18
68
|
// -----------------------------------------------------------------------------
|
|
19
|
-
server.tool('
|
|
69
|
+
server.tool('list_components', 'List all of the components available from Primer React', async () => {
|
|
20
70
|
const components = listComponents().map(component => {
|
|
21
71
|
return `- ${component.name}`
|
|
22
72
|
})
|
|
@@ -43,7 +93,7 @@ server.tool(
|
|
|
43
93
|
async ({name}) => {
|
|
44
94
|
const components = listComponents()
|
|
45
95
|
const match = components.find(component => {
|
|
46
|
-
return component.name === name
|
|
96
|
+
return component.name === name || component.name.toLowerCase() === name.toLowerCase()
|
|
47
97
|
})
|
|
48
98
|
if (!match) {
|
|
49
99
|
return {
|
|
@@ -56,7 +106,7 @@ server.tool(
|
|
|
56
106
|
}
|
|
57
107
|
}
|
|
58
108
|
|
|
59
|
-
const url = new URL(`/product/components/${match.
|
|
109
|
+
const url = new URL(`/product/components/${match.slug}`, 'https://primer.style')
|
|
60
110
|
const response = await fetch(url)
|
|
61
111
|
if (!response.ok) {
|
|
62
112
|
throw new Error(`Failed to fetch ${url}: ${response.statusText}`)
|
|
@@ -364,432 +414,14 @@ ${text}`,
|
|
|
364
414
|
},
|
|
365
415
|
)
|
|
366
416
|
|
|
367
|
-
type Token = TokenCategory | string
|
|
368
|
-
type TokenCategory = {
|
|
369
|
-
category: string
|
|
370
|
-
tokens: Array<Token>
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
const tokens: Array<Token> = [
|
|
374
|
-
{
|
|
375
|
-
category: 'color',
|
|
376
|
-
tokens: [
|
|
377
|
-
{
|
|
378
|
-
category: 'foreground',
|
|
379
|
-
tokens: [
|
|
380
|
-
'--fgColor-accent',
|
|
381
|
-
'--fgColor-attention',
|
|
382
|
-
'--fgColor-black',
|
|
383
|
-
'--fgColor-closed',
|
|
384
|
-
'--fgColor-danger',
|
|
385
|
-
'--fgColor-default',
|
|
386
|
-
'--fgColor-disabled',
|
|
387
|
-
'--fgColor-done',
|
|
388
|
-
'--fgColor-link',
|
|
389
|
-
'--fgColor-muted',
|
|
390
|
-
'--fgColor-neutral',
|
|
391
|
-
'--fgColor-onEmphasis',
|
|
392
|
-
'--fgColor-onInverse',
|
|
393
|
-
'--fgColor-open',
|
|
394
|
-
'--fgColor-severe',
|
|
395
|
-
'--fgColor-sponsors',
|
|
396
|
-
'--fgColor-success',
|
|
397
|
-
'--fgColor-upsell',
|
|
398
|
-
'--fgColor-white',
|
|
399
|
-
],
|
|
400
|
-
},
|
|
401
|
-
{
|
|
402
|
-
category: 'background',
|
|
403
|
-
tokens: [
|
|
404
|
-
'--bgColor-accent-emphasis',
|
|
405
|
-
'--bgColor-accent-muted',
|
|
406
|
-
'--bgColor-attention-emphasis',
|
|
407
|
-
'--bgColor-attention-muted',
|
|
408
|
-
'--bgColor-black',
|
|
409
|
-
'--bgColor-closed-emphasis',
|
|
410
|
-
'--bgColor-closed-muted',
|
|
411
|
-
'--bgColor-danger-emphasis',
|
|
412
|
-
'--bgColor-danger-muted',
|
|
413
|
-
'--bgColor-default',
|
|
414
|
-
'--bgColor-disabled',
|
|
415
|
-
'--bgColor-done-emphasis',
|
|
416
|
-
'--bgColor-done-muted',
|
|
417
|
-
'--bgColor-emphasis',
|
|
418
|
-
'--bgColor-inset',
|
|
419
|
-
'--bgColor-inverse',
|
|
420
|
-
'--bgColor-muted',
|
|
421
|
-
'--bgColor-neutral-emphasis',
|
|
422
|
-
'--bgColor-neutral-muted',
|
|
423
|
-
'--bgColor-open-emphasis',
|
|
424
|
-
'--bgColor-open-muted',
|
|
425
|
-
'--bgColor-severe-emphasis',
|
|
426
|
-
'--bgColor-severe-muted',
|
|
427
|
-
'--bgColor-sponsors-emphasis',
|
|
428
|
-
'--bgColor-sponsors-muted',
|
|
429
|
-
'--bgColor-success-emphasis',
|
|
430
|
-
'--bgColor-success-muted',
|
|
431
|
-
'--bgColor-transparent',
|
|
432
|
-
'--bgColor-upsell-emphasis',
|
|
433
|
-
'--bgColor-upsell-muted',
|
|
434
|
-
'--bgColor-white',
|
|
435
|
-
],
|
|
436
|
-
},
|
|
437
|
-
{
|
|
438
|
-
category: 'border',
|
|
439
|
-
tokens: [
|
|
440
|
-
'--borderColor-accent-emphasis',
|
|
441
|
-
'--borderColor-accent-muted',
|
|
442
|
-
'--borderColor-attention-emphasis',
|
|
443
|
-
'--borderColor-attention-muted',
|
|
444
|
-
'--borderColor-closed-emphasis',
|
|
445
|
-
'--borderColor-closed-muted',
|
|
446
|
-
'--borderColor-danger-emphasis',
|
|
447
|
-
'--borderColor-danger-muted',
|
|
448
|
-
'--borderColor-default',
|
|
449
|
-
'--borderColor-disabled',
|
|
450
|
-
'--borderColor-done-emphasis',
|
|
451
|
-
'--borderColor-done-muted',
|
|
452
|
-
'--borderColor-emphasis',
|
|
453
|
-
'--borderColor-muted',
|
|
454
|
-
'--borderColor-neutral-emphasis',
|
|
455
|
-
'--borderColor-neutral-muted',
|
|
456
|
-
'--borderColor-open-emphasis',
|
|
457
|
-
'--borderColor-open-muted',
|
|
458
|
-
'--borderColor-severe-emphasis',
|
|
459
|
-
'--borderColor-severe-muted',
|
|
460
|
-
'--borderColor-sponsors-emphasis',
|
|
461
|
-
'--borderColor-sponsors-muted',
|
|
462
|
-
'--borderColor-success-emphasis',
|
|
463
|
-
'--borderColor-success-muted',
|
|
464
|
-
'--borderColor-translucent',
|
|
465
|
-
'--borderColor-transparent',
|
|
466
|
-
'--borderColor-upsell-emphasis',
|
|
467
|
-
'--borderColor-upsell-muted',
|
|
468
|
-
],
|
|
469
|
-
},
|
|
470
|
-
{
|
|
471
|
-
category: 'shadow',
|
|
472
|
-
tokens: [
|
|
473
|
-
'--shadow-floating-large',
|
|
474
|
-
'--shadow-floating-legacy',
|
|
475
|
-
'--shadow-floating-medium',
|
|
476
|
-
'--shadow-floating-small',
|
|
477
|
-
'--shadow-floating-xlarge',
|
|
478
|
-
'--shadow-inset',
|
|
479
|
-
'--shadow-resting-medium',
|
|
480
|
-
'--shadow-resting-small',
|
|
481
|
-
'--shadow-resting-xsmall',
|
|
482
|
-
],
|
|
483
|
-
},
|
|
484
|
-
{
|
|
485
|
-
category: 'control',
|
|
486
|
-
tokens: [
|
|
487
|
-
'--control-bgColor-active',
|
|
488
|
-
'--control-bgColor-disabled',
|
|
489
|
-
'--control-bgColor-hover',
|
|
490
|
-
'--control-bgColor-rest',
|
|
491
|
-
'--control-bgColor-selected',
|
|
492
|
-
'--control-borderColor-danger',
|
|
493
|
-
'--control-borderColor-disabled',
|
|
494
|
-
'--control-borderColor-emphasis',
|
|
495
|
-
'--control-borderColor-rest',
|
|
496
|
-
'--control-borderColor-selected',
|
|
497
|
-
'--control-borderColor-success',
|
|
498
|
-
'--control-borderColor-warning',
|
|
499
|
-
'--control-checked-bgColor-active',
|
|
500
|
-
'--control-checked-bgColor-disabled',
|
|
501
|
-
'--control-checked-bgColor-hover',
|
|
502
|
-
'--control-checked-bgColor-rest',
|
|
503
|
-
'--control-checked-borderColor-active',
|
|
504
|
-
'--control-checked-borderColor-disabled',
|
|
505
|
-
'--control-checked-borderColor-hover',
|
|
506
|
-
'--control-checked-borderColor-rest',
|
|
507
|
-
'--control-checked-fgColor-disabled',
|
|
508
|
-
'--control-checked-fgColor-rest',
|
|
509
|
-
'--control-danger-bgColor-active',
|
|
510
|
-
'--control-danger-bgColor-hover',
|
|
511
|
-
'--control-danger-fgColor-hover',
|
|
512
|
-
'--control-danger-fgColor-rest',
|
|
513
|
-
'--control-fgColor-disabled',
|
|
514
|
-
'--control-fgColor-placeholder',
|
|
515
|
-
'--control-fgColor-rest',
|
|
516
|
-
'--control-iconColor-rest',
|
|
517
|
-
'--control-transparent-bgColor-active',
|
|
518
|
-
'--control-transparent-bgColor-disabled',
|
|
519
|
-
'--control-transparent-bgColor-hover',
|
|
520
|
-
'--control-transparent-bgColor-rest',
|
|
521
|
-
'--control-transparent-bgColor-selected',
|
|
522
|
-
'--control-transparent-borderColor-active',
|
|
523
|
-
'--control-transparent-borderColor-hover',
|
|
524
|
-
'--control-transparent-borderColor-rest',
|
|
525
|
-
],
|
|
526
|
-
},
|
|
527
|
-
{
|
|
528
|
-
category: 'focus',
|
|
529
|
-
tokens: ['--focus-outlineColor'],
|
|
530
|
-
},
|
|
531
|
-
{
|
|
532
|
-
category: 'overlay',
|
|
533
|
-
tokens: ['--overlay-background-bgColor', '--overlay-bgColor', '--overlay-borderColor'],
|
|
534
|
-
},
|
|
535
|
-
],
|
|
536
|
-
},
|
|
537
|
-
{
|
|
538
|
-
category: 'size',
|
|
539
|
-
tokens: [
|
|
540
|
-
{
|
|
541
|
-
category: 'base',
|
|
542
|
-
tokens: [
|
|
543
|
-
'--base-size-2',
|
|
544
|
-
'--base-size-4',
|
|
545
|
-
'--base-size-6',
|
|
546
|
-
'--base-size-8',
|
|
547
|
-
'--base-size-12',
|
|
548
|
-
'--base-size-16',
|
|
549
|
-
'--base-size-20',
|
|
550
|
-
'--base-size-24',
|
|
551
|
-
'--base-size-28',
|
|
552
|
-
'--base-size-32',
|
|
553
|
-
'--base-size-36',
|
|
554
|
-
'--base-size-40',
|
|
555
|
-
'--base-size-44',
|
|
556
|
-
'--base-size-48',
|
|
557
|
-
'--base-size-64',
|
|
558
|
-
'--base-size-80',
|
|
559
|
-
'--base-size-96',
|
|
560
|
-
'--base-size-112',
|
|
561
|
-
'--base-size-128',
|
|
562
|
-
],
|
|
563
|
-
},
|
|
564
|
-
{
|
|
565
|
-
category: 'border',
|
|
566
|
-
tokens: [
|
|
567
|
-
{
|
|
568
|
-
category: 'border-size',
|
|
569
|
-
tokens: [
|
|
570
|
-
'--boxShadow-thick',
|
|
571
|
-
'--boxShadow-thicker',
|
|
572
|
-
'--boxShadow-thin',
|
|
573
|
-
'--borderWidth-default',
|
|
574
|
-
'--borderWidth-thick',
|
|
575
|
-
'--borderWidth-thicker',
|
|
576
|
-
'--borderWidth-thin',
|
|
577
|
-
],
|
|
578
|
-
},
|
|
579
|
-
{
|
|
580
|
-
category: 'border-radius',
|
|
581
|
-
tokens: [
|
|
582
|
-
'--borderRadius-default',
|
|
583
|
-
'--borderRadius-full',
|
|
584
|
-
'--borderRadius-large',
|
|
585
|
-
'--borderRadius-medium',
|
|
586
|
-
'--borderRadius-small',
|
|
587
|
-
],
|
|
588
|
-
},
|
|
589
|
-
{
|
|
590
|
-
category: 'outline',
|
|
591
|
-
tokens: ['--outline-focus-offset', '--outline-focus-width'],
|
|
592
|
-
},
|
|
593
|
-
],
|
|
594
|
-
},
|
|
595
|
-
{
|
|
596
|
-
category: 'layout',
|
|
597
|
-
tokens: [
|
|
598
|
-
{
|
|
599
|
-
category: 'stack',
|
|
600
|
-
tokens: [
|
|
601
|
-
'--stack-gap-condensed',
|
|
602
|
-
'--stack-gap-normal',
|
|
603
|
-
'--stack-gap-spacious',
|
|
604
|
-
'--stack-padding-condensed',
|
|
605
|
-
'--stack-padding-normal',
|
|
606
|
-
'--stack-padding-spacious',
|
|
607
|
-
],
|
|
608
|
-
},
|
|
609
|
-
{
|
|
610
|
-
category: 'controls',
|
|
611
|
-
tokens: [
|
|
612
|
-
'--controlStack-large-gap-auto',
|
|
613
|
-
'--controlStack-large-gap-condensed',
|
|
614
|
-
'--controlStack-large-gap-spacious',
|
|
615
|
-
'--controlStack-medium-gap-condensed',
|
|
616
|
-
'--controlStack-medium-gap-spacious',
|
|
617
|
-
'--controlStack-small-gap-condensed',
|
|
618
|
-
'--controlStack-small-gap-spacious',
|
|
619
|
-
'--controlStack-medium-gap-auto',
|
|
620
|
-
'--controlStack-small-gap-auto',
|
|
621
|
-
|
|
622
|
-
'--control-xsmall-gap',
|
|
623
|
-
'--control-small-gap',
|
|
624
|
-
'--control-medium-gap',
|
|
625
|
-
'--control-large-gap',
|
|
626
|
-
'--control-xlarge-gap',
|
|
627
|
-
'--control-xsmall-lineBoxHeight',
|
|
628
|
-
'--control-small-lineBoxHeight',
|
|
629
|
-
'--control-medium-lineBoxHeight',
|
|
630
|
-
'--control-large-lineBoxHeight',
|
|
631
|
-
'--control-xlarge-lineBoxHeight',
|
|
632
|
-
'--control-xsmall-paddingBlock',
|
|
633
|
-
'--control-small-paddingBlock',
|
|
634
|
-
'--control-medium-paddingBlock',
|
|
635
|
-
'--control-large-paddingBlock',
|
|
636
|
-
'--control-xlarge-paddingBlock',
|
|
637
|
-
'--control-xsmall-paddingInline-condensed',
|
|
638
|
-
'--control-small-paddingInline-condensed',
|
|
639
|
-
'--control-medium-paddingInline-condensed',
|
|
640
|
-
'--control-large-paddingInline-condensed',
|
|
641
|
-
'--control-xlarge-paddingInline-condensed',
|
|
642
|
-
'--control-xsmall-paddingInline-normal',
|
|
643
|
-
'--control-small-paddingInline-normal',
|
|
644
|
-
'--control-medium-paddingInline-normal',
|
|
645
|
-
'--control-large-paddingInline-normal',
|
|
646
|
-
'--control-xlarge-paddingInline-normal',
|
|
647
|
-
'--control-xsmall-paddingInline-spacious',
|
|
648
|
-
'--control-small-paddingInline-spacious',
|
|
649
|
-
'--control-medium-paddingInline-spacious',
|
|
650
|
-
'--control-large-paddingInline-spacious',
|
|
651
|
-
'--control-xlarge-paddingInline-spacious',
|
|
652
|
-
'--control-xsmall-size',
|
|
653
|
-
'--control-small-size',
|
|
654
|
-
'--control-medium-size',
|
|
655
|
-
'--control-large-size',
|
|
656
|
-
'--control-xlarge-size',
|
|
657
|
-
],
|
|
658
|
-
},
|
|
659
|
-
{
|
|
660
|
-
category: 'overlay',
|
|
661
|
-
tokens: [
|
|
662
|
-
'--overlay-borderRadius',
|
|
663
|
-
'--overlay-height-large',
|
|
664
|
-
'--overlay-height-medium',
|
|
665
|
-
'--overlay-height-small',
|
|
666
|
-
'--overlay-height-xlarge',
|
|
667
|
-
'--overlay-offset',
|
|
668
|
-
'--overlay-padding-condensed',
|
|
669
|
-
'--overlay-padding-normal',
|
|
670
|
-
'--overlay-paddingBlock-condensed',
|
|
671
|
-
'--overlay-paddingBlock-normal',
|
|
672
|
-
'--overlay-width-large',
|
|
673
|
-
'--overlay-width-medium',
|
|
674
|
-
'--overlay-width-small',
|
|
675
|
-
'--overlay-width-xlarge',
|
|
676
|
-
'--overlay-width-xsmall',
|
|
677
|
-
],
|
|
678
|
-
},
|
|
679
|
-
],
|
|
680
|
-
},
|
|
681
|
-
],
|
|
682
|
-
},
|
|
683
|
-
{
|
|
684
|
-
category: 'typography',
|
|
685
|
-
tokens: [
|
|
686
|
-
{
|
|
687
|
-
category: 'weight',
|
|
688
|
-
tokens: [
|
|
689
|
-
'--base-text-weight-light',
|
|
690
|
-
'--base-text-weight-normal',
|
|
691
|
-
'--base-text-weight-medium',
|
|
692
|
-
'--base-text-weight-semibold',
|
|
693
|
-
],
|
|
694
|
-
},
|
|
695
|
-
{
|
|
696
|
-
category: 'font-family',
|
|
697
|
-
tokens: [
|
|
698
|
-
'--fontStack-monospace',
|
|
699
|
-
'--fontStack-sansSerif',
|
|
700
|
-
'--fontStack-sansSerifDisplay',
|
|
701
|
-
'--fontStack-system',
|
|
702
|
-
],
|
|
703
|
-
},
|
|
704
|
-
{
|
|
705
|
-
category: 'font-shorthand',
|
|
706
|
-
tokens: [
|
|
707
|
-
'--text-body-shorthand-large',
|
|
708
|
-
'--text-body-shorthand-medium',
|
|
709
|
-
'--text-body-shorthand-small',
|
|
710
|
-
'--text-caption-shorthand',
|
|
711
|
-
'--text-codeBlock-shorthand',
|
|
712
|
-
'--text-codeInline-shorthand',
|
|
713
|
-
'--text-display-shorthand',
|
|
714
|
-
'--text-subtitle-shorthand',
|
|
715
|
-
'--text-title-shorthand-large',
|
|
716
|
-
'--text-title-shorthand-medium',
|
|
717
|
-
'--text-title-shorthand-small',
|
|
718
|
-
],
|
|
719
|
-
},
|
|
720
|
-
{
|
|
721
|
-
category: 'display',
|
|
722
|
-
tokens: [
|
|
723
|
-
'--text-display-lineBoxHeight',
|
|
724
|
-
'--text-display-lineHeight',
|
|
725
|
-
'--text-display-size',
|
|
726
|
-
'--text-display-weight',
|
|
727
|
-
],
|
|
728
|
-
},
|
|
729
|
-
{
|
|
730
|
-
category: 'title-large',
|
|
731
|
-
tokens: ['--text-title-lineHeight-large', '--text-title-size-large', '--text-title-weight-large'],
|
|
732
|
-
},
|
|
733
|
-
{
|
|
734
|
-
category: 'title-medium',
|
|
735
|
-
tokens: ['--text-title-lineHeight-medium', '--text-title-size-medium', '--text-title-weight-medium'],
|
|
736
|
-
},
|
|
737
|
-
{
|
|
738
|
-
category: 'title-small',
|
|
739
|
-
tokens: ['--text-title-lineHeight-small', '--text-title-size-small', '--text-title-weight-small'],
|
|
740
|
-
},
|
|
741
|
-
{
|
|
742
|
-
category: 'subtitle',
|
|
743
|
-
tokens: ['--text-subtitle-lineHeight', '--text-subtitle-size', '--text-subtitle-weight'],
|
|
744
|
-
},
|
|
745
|
-
{
|
|
746
|
-
category: 'body-large',
|
|
747
|
-
tokens: ['--text-body-lineHeight-large', '--text-body-size-large'],
|
|
748
|
-
},
|
|
749
|
-
{
|
|
750
|
-
category: 'body-medium',
|
|
751
|
-
tokens: ['--text-body-lineHeight-medium', '--text-body-size-medium'],
|
|
752
|
-
},
|
|
753
|
-
{
|
|
754
|
-
category: 'body-small',
|
|
755
|
-
tokens: ['--text-body-lineHeight-small', '--text-body-size-small'],
|
|
756
|
-
},
|
|
757
|
-
{
|
|
758
|
-
category: 'caption',
|
|
759
|
-
tokens: ['--text-caption-lineHeight', '--text-caption-size', '--text-caption-weight'],
|
|
760
|
-
},
|
|
761
|
-
{
|
|
762
|
-
category: 'code-block',
|
|
763
|
-
tokens: ['--text-codeBlock-lineHeight', '--text-codeBlock-size', '--text-codeBlock-weight'],
|
|
764
|
-
},
|
|
765
|
-
{
|
|
766
|
-
category: 'inline-code-block',
|
|
767
|
-
tokens: ['--text-codeInline-size', '--text-codeInline-weight'],
|
|
768
|
-
},
|
|
769
|
-
],
|
|
770
|
-
},
|
|
771
|
-
] as const
|
|
772
|
-
|
|
773
|
-
function serialize(token: Token): string {
|
|
774
|
-
if (typeof token === 'string') {
|
|
775
|
-
// eslint-disable-next-line github/unescaped-html-literal
|
|
776
|
-
return `<token name="${token}"></token>`
|
|
777
|
-
}
|
|
778
|
-
// eslint-disable-next-line github/unescaped-html-literal
|
|
779
|
-
return `<token-category name="${token.category}">\n${token.tokens.map(serialize).join('\n')}\n</token-category>`
|
|
780
|
-
}
|
|
781
|
-
|
|
782
417
|
// -----------------------------------------------------------------------------
|
|
783
418
|
// Design Tokens
|
|
784
419
|
// -----------------------------------------------------------------------------
|
|
785
420
|
server.tool('list_tokens', 'List all of the design tokens available from Primer', async () => {
|
|
786
421
|
let text =
|
|
787
|
-
'Below is a list of all
|
|
422
|
+
'Below is a list of all design tokens available from Primer. Tokens are used in CSS and CSS Modules. To refer to the CSS Custom Property for a design token, wrap it in var(--{name-of-token}). To learn how to use a specific token, use a corresponding usage tool for the category of the token. For example, if a token is a color token look for the get_color_usage tool. \n\n'
|
|
788
423
|
|
|
789
|
-
|
|
790
|
-
text += serialize(token)
|
|
791
|
-
text += '\n'
|
|
792
|
-
}
|
|
424
|
+
text += serialize(tokens)
|
|
793
425
|
|
|
794
426
|
return {
|
|
795
427
|
content: [
|
|
@@ -872,4 +504,186 @@ server.tool('get_typography_usage', 'Get the guidelines for how to apply typogra
|
|
|
872
504
|
}
|
|
873
505
|
})
|
|
874
506
|
|
|
507
|
+
// -----------------------------------------------------------------------------
|
|
508
|
+
// Icons
|
|
509
|
+
// -----------------------------------------------------------------------------
|
|
510
|
+
server.tool('list_icons', 'List all of the icons (octicons) available from Primer Octicons React', async () => {
|
|
511
|
+
const icons = listIcons().map(icon => {
|
|
512
|
+
const keywords = icon.keywords.map(keyword => {
|
|
513
|
+
return `<keyword>${keyword}</keyword>`
|
|
514
|
+
})
|
|
515
|
+
const sizes = icon.heights.map(height => {
|
|
516
|
+
return `<size value="${height}"></size>`
|
|
517
|
+
})
|
|
518
|
+
return [`<icon name="${icon.name}">`, ...keywords, ...sizes, `</icon>`].join('\n')
|
|
519
|
+
})
|
|
520
|
+
|
|
521
|
+
return {
|
|
522
|
+
content: [
|
|
523
|
+
{
|
|
524
|
+
type: 'text',
|
|
525
|
+
text: `The following icons are available in the @primer/octicons-react package in TypeScript projects:
|
|
526
|
+
|
|
527
|
+
${icons.join('\n')}
|
|
528
|
+
|
|
529
|
+
You can use the \`get_icon\` tool to get more information about a specific icon. You can use these components from the @primer/octicons-react package.`,
|
|
530
|
+
},
|
|
531
|
+
],
|
|
532
|
+
}
|
|
533
|
+
})
|
|
534
|
+
|
|
535
|
+
server.tool(
|
|
536
|
+
'get_icon',
|
|
537
|
+
'Get a specific icon (octicon) by name from Primer',
|
|
538
|
+
{
|
|
539
|
+
name: z.string().describe('The name of the icon to retrieve'),
|
|
540
|
+
size: z.string().optional().describe('The size of the icon to retrieve, e.g. "16"').default('16'),
|
|
541
|
+
},
|
|
542
|
+
async ({name, size}) => {
|
|
543
|
+
const icons = listIcons()
|
|
544
|
+
const match = icons.find(icon => {
|
|
545
|
+
return icon.name === name || icon.name.toLowerCase() === name.toLowerCase()
|
|
546
|
+
})
|
|
547
|
+
if (!match) {
|
|
548
|
+
return {
|
|
549
|
+
content: [
|
|
550
|
+
{
|
|
551
|
+
type: 'text',
|
|
552
|
+
text: `There is no icon named \`${name}\` in the @primer/octicons-react package. For a full list of icons, use the \`get_icon\` tool.`,
|
|
553
|
+
},
|
|
554
|
+
],
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
const url = new URL(`/octicons/icon/${match.name}-${size}`, 'https://primer.style')
|
|
559
|
+
const response = await fetch(url)
|
|
560
|
+
if (!response.ok) {
|
|
561
|
+
throw new Error(`Failed to fetch ${url}: ${response.statusText}`)
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
const html = await response.text()
|
|
565
|
+
if (!html) {
|
|
566
|
+
return {
|
|
567
|
+
content: [],
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
const $ = cheerio.load(html)
|
|
572
|
+
const source = $('main').html()
|
|
573
|
+
if (!source) {
|
|
574
|
+
return {
|
|
575
|
+
content: [],
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
const text = turndownService.turndown(source)
|
|
580
|
+
|
|
581
|
+
return {
|
|
582
|
+
content: [
|
|
583
|
+
{
|
|
584
|
+
type: 'text',
|
|
585
|
+
text: `Here is the documentation for the \`${name}\` icon at size: \`${size}\`:
|
|
586
|
+
${text}`,
|
|
587
|
+
},
|
|
588
|
+
],
|
|
589
|
+
}
|
|
590
|
+
},
|
|
591
|
+
)
|
|
592
|
+
|
|
593
|
+
// -----------------------------------------------------------------------------
|
|
594
|
+
// Coding guidelines
|
|
595
|
+
// -----------------------------------------------------------------------------
|
|
596
|
+
server.tool(
|
|
597
|
+
'primer_coding_guidelines',
|
|
598
|
+
'Get the guidelines when writing code that uses Primer or for UI code that you are creating',
|
|
599
|
+
async () => {
|
|
600
|
+
return {
|
|
601
|
+
content: [
|
|
602
|
+
{
|
|
603
|
+
type: 'text',
|
|
604
|
+
text: `When writing code that uses Primer, follow these guidelines:
|
|
605
|
+
|
|
606
|
+
## Design Tokens
|
|
607
|
+
|
|
608
|
+
- Prefer design tokens over hard-coded values. For example, use \`var(--fgColor-default)\` instead of \`#24292f\`. Use the \`list_tokens\` tool to find the design token you need.
|
|
609
|
+
- Prefer recommending design tokens in the same group for related CSS properties. For example, when styling background and border color, use tokens from the same group/category
|
|
610
|
+
|
|
611
|
+
## Authoring & Using Components
|
|
612
|
+
|
|
613
|
+
- Prefer re-using a component from Primer when possible over writing a new component.
|
|
614
|
+
- Prefer using existing props for a component for styling instead of adding styling to a component
|
|
615
|
+
- Prefer using icons from Primer instead of creating new icons. Use the \`list_icons\` tool to find the icon you need.
|
|
616
|
+
- Follow patterns from Primer when creating new components. Use the \`list_patterns\` tool to find the pattern you need, if one exists
|
|
617
|
+
- When using a component from Primer, make sure to follow the component's usage and accessibility guidelines
|
|
618
|
+
|
|
619
|
+
## Coding guidelines
|
|
620
|
+
|
|
621
|
+
The following list of coding guidelines must be followed:
|
|
622
|
+
|
|
623
|
+
- Do not use the sx prop for styling components. Instead, use CSS Modules.
|
|
624
|
+
- Do not use the Box component for styling components. Instead, use CSS Modules.
|
|
625
|
+
`,
|
|
626
|
+
},
|
|
627
|
+
],
|
|
628
|
+
}
|
|
629
|
+
},
|
|
630
|
+
)
|
|
631
|
+
|
|
632
|
+
// -----------------------------------------------------------------------------
|
|
633
|
+
// Accessibility
|
|
634
|
+
// -----------------------------------------------------------------------------
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* The `review_alt_text` tool is experimental and may be removed in future versions.
|
|
638
|
+
*
|
|
639
|
+
* The intent of this tool is to assist products like Copilot Code Review and Copilot Coding Agent
|
|
640
|
+
* in reviewing both user- and AI-generated alt text for images, ensuring compliance with accessibility guidelines.
|
|
641
|
+
* This tool is not intended to replace human-generated alt text; rather, it supports the review process
|
|
642
|
+
* by providing suggestions for improvement. It should be used alongside human review, not as a substitute.
|
|
643
|
+
*
|
|
644
|
+
*
|
|
645
|
+
**/
|
|
646
|
+
server.tool(
|
|
647
|
+
'review_alt_text',
|
|
648
|
+
'Evaluates image alt text against accessibility best practices and context relevance.',
|
|
649
|
+
{
|
|
650
|
+
surroundingText: z.string().describe('Text surrounding the image, relevant to the image.'),
|
|
651
|
+
alt: z.string().describe('The alt text of the image being evaluated'),
|
|
652
|
+
image: z
|
|
653
|
+
.union([
|
|
654
|
+
z.instanceof(File).describe('The image src file being evaluated'),
|
|
655
|
+
z.string().url().describe('The URL of the image src being evaluated'),
|
|
656
|
+
z.string().describe('The file path of the image src being evaluated'),
|
|
657
|
+
])
|
|
658
|
+
.describe('The image file, file path, or URL being evaluated'),
|
|
659
|
+
},
|
|
660
|
+
async ({surroundingText, alt, image}) => {
|
|
661
|
+
// Call the LLM through MCP sampling
|
|
662
|
+
const response = await server.server.createMessage({
|
|
663
|
+
messages: [
|
|
664
|
+
{
|
|
665
|
+
role: 'user',
|
|
666
|
+
content: {
|
|
667
|
+
type: 'text',
|
|
668
|
+
text: `Does this alt text: '${alt}' meet accessibility guidelines and describe the image: ${image} accurately in context of this surrounding text: '${surroundingText}'?\n\n`,
|
|
669
|
+
},
|
|
670
|
+
},
|
|
671
|
+
],
|
|
672
|
+
sampling: {temperature: 0.4},
|
|
673
|
+
maxTokens: 500,
|
|
674
|
+
})
|
|
675
|
+
|
|
676
|
+
return {
|
|
677
|
+
content: [
|
|
678
|
+
{
|
|
679
|
+
type: 'text',
|
|
680
|
+
text: response.content.type === 'text' ? response.content.text : 'Unable to generate summary',
|
|
681
|
+
},
|
|
682
|
+
],
|
|
683
|
+
altTextEvaluation: response.content.type === 'text' ? response.content.text : 'Unable to generate summary',
|
|
684
|
+
nextSteps: `If the evaluation indicates issues with the alt text, provide more meaningful alt text based on the feedback. DO NOT run this tool repeatedly on the same image - evaluations may vary slightly with each run.`,
|
|
685
|
+
}
|
|
686
|
+
},
|
|
687
|
+
)
|
|
688
|
+
|
|
875
689
|
export {server}
|