@primer/mcp 0.0.5 → 0.2.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/dist/index.js +1 -1
- package/dist/primer.d.ts.map +1 -1
- package/dist/{server-BzATDQ5A.js → server-CjO5UCV7.js} +82 -34
- package/dist/server.d.ts.map +1 -1
- package/dist/stdio.js +1 -1
- package/package.json +17 -13
- package/src/primer.ts +0 -4
- package/src/server.ts +217 -165
- package/dist/server-Ccnupv1s.js +0 -718
package/src/server.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import {McpServer} from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
2
2
|
// eslint-disable-next-line import/no-namespace
|
|
3
3
|
import * as cheerio from 'cheerio'
|
|
4
|
-
|
|
4
|
+
// eslint-disable-next-line import/no-namespace
|
|
5
|
+
import * as z from 'zod'
|
|
5
6
|
import TurndownService from 'turndown'
|
|
6
7
|
import {listComponents, listPatterns, listIcons} from './primer'
|
|
7
8
|
import {tokens, serialize} from './primitives'
|
|
@@ -17,35 +18,40 @@ const turndownService = new TurndownService()
|
|
|
17
18
|
// -----------------------------------------------------------------------------
|
|
18
19
|
// Project setup
|
|
19
20
|
// -----------------------------------------------------------------------------
|
|
20
|
-
server.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
server.registerTool(
|
|
22
|
+
'init',
|
|
23
|
+
{
|
|
24
|
+
description: 'Setup or create a project that includes Primer React',
|
|
25
|
+
},
|
|
26
|
+
async () => {
|
|
27
|
+
const url = new URL(`/product/getting-started/react`, 'https://primer.style')
|
|
28
|
+
const response = await fetch(url)
|
|
29
|
+
if (!response.ok) {
|
|
30
|
+
throw new Error(`Failed to fetch ${url}: ${response.statusText}`)
|
|
31
|
+
}
|
|
26
32
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
33
|
+
const html = await response.text()
|
|
34
|
+
if (!html) {
|
|
35
|
+
return {
|
|
36
|
+
content: [],
|
|
37
|
+
}
|
|
31
38
|
}
|
|
32
|
-
}
|
|
33
39
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
const $ = cheerio.load(html)
|
|
41
|
+
const source = $('main').html()
|
|
42
|
+
if (!source) {
|
|
43
|
+
return {
|
|
44
|
+
content: [],
|
|
45
|
+
}
|
|
39
46
|
}
|
|
40
|
-
}
|
|
41
47
|
|
|
42
|
-
|
|
48
|
+
const text = turndownService.turndown(source)
|
|
43
49
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
50
|
+
return {
|
|
51
|
+
content: [
|
|
52
|
+
{
|
|
53
|
+
type: 'text',
|
|
54
|
+
text: `The getting started documentation for Primer React is included below. It's important that the project:
|
|
49
55
|
|
|
50
56
|
- 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
57
|
- Installs the latest version of \`@primer/react\` from \`npm\`
|
|
@@ -58,37 +64,45 @@ server.tool('init', 'Setup or create a project that includes Primer React', asyn
|
|
|
58
64
|
|
|
59
65
|
${text}
|
|
60
66
|
`,
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
)
|
|
65
72
|
|
|
66
73
|
// -----------------------------------------------------------------------------
|
|
67
74
|
// Components
|
|
68
75
|
// -----------------------------------------------------------------------------
|
|
69
|
-
server.
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
server.registerTool(
|
|
77
|
+
'list_components',
|
|
78
|
+
{description: 'List all of the components available from Primer React'},
|
|
79
|
+
async () => {
|
|
80
|
+
const components = listComponents().map(component => {
|
|
81
|
+
return `- ${component.name}`
|
|
82
|
+
})
|
|
83
|
+
return {
|
|
84
|
+
content: [
|
|
85
|
+
{
|
|
86
|
+
type: 'text',
|
|
87
|
+
text: `The following components are available in the @primer/react in TypeScript projects:
|
|
78
88
|
|
|
79
89
|
${components.join('\n')}
|
|
80
90
|
|
|
81
91
|
You can use the \`get_component\` tool to get more information about a specific component. You can use these components from the @primer/react package.`,
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
)
|
|
86
97
|
|
|
87
|
-
server.
|
|
98
|
+
server.registerTool(
|
|
88
99
|
'get_component',
|
|
89
|
-
'Retrieve documentation and usage details for a specific React component from the @primer/react package by its name. This tool provides the official Primer documentation for any listed component, making it easy to inspect, reuse, or integrate components in your project.',
|
|
90
100
|
{
|
|
91
|
-
|
|
101
|
+
description:
|
|
102
|
+
'Retrieve documentation and usage details for a specific React component from the @primer/react package by its name. This tool provides the official Primer documentation for any listed component, making it easy to inspect, reuse, or integrate components in your project.',
|
|
103
|
+
inputSchema: {
|
|
104
|
+
name: z.string().describe('The name of the component to retrieve'),
|
|
105
|
+
},
|
|
92
106
|
},
|
|
93
107
|
async ({name}) => {
|
|
94
108
|
const components = listComponents()
|
|
@@ -97,12 +111,27 @@ server.tool(
|
|
|
97
111
|
})
|
|
98
112
|
if (!match) {
|
|
99
113
|
return {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
114
|
+
isError: true,
|
|
115
|
+
errorMessage: `There is no component named \`${name}\` in the @primer/react package. For a full list of components, use the \`list_components\` tool.`,
|
|
116
|
+
content: [],
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const llmsUrl = new URL(`/product/components/${match.slug}/llms.txt`, 'https://primer.style')
|
|
121
|
+
const llmsResponse = await fetch(llmsUrl)
|
|
122
|
+
if (llmsResponse.ok) {
|
|
123
|
+
try {
|
|
124
|
+
const llmsText = await llmsResponse.text()
|
|
125
|
+
return {
|
|
126
|
+
content: [
|
|
127
|
+
{
|
|
128
|
+
type: 'text',
|
|
129
|
+
text: llmsText,
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
}
|
|
133
|
+
} catch (_: unknown) {
|
|
134
|
+
// If there's an error fetching or processing the llms.txt, we fall back to the regular documentation
|
|
106
135
|
}
|
|
107
136
|
}
|
|
108
137
|
|
|
@@ -141,11 +170,13 @@ ${text}`,
|
|
|
141
170
|
},
|
|
142
171
|
)
|
|
143
172
|
|
|
144
|
-
server.
|
|
173
|
+
server.registerTool(
|
|
145
174
|
'get_component_examples',
|
|
146
|
-
'Get examples for how to use a component from Primer React',
|
|
147
175
|
{
|
|
148
|
-
|
|
176
|
+
description: 'Get examples for how to use a component from Primer React',
|
|
177
|
+
inputSchema: {
|
|
178
|
+
name: z.string().describe('The name of the component to retrieve'),
|
|
179
|
+
},
|
|
149
180
|
},
|
|
150
181
|
async ({name}) => {
|
|
151
182
|
const components = listComponents()
|
|
@@ -199,11 +230,13 @@ ${text}`,
|
|
|
199
230
|
},
|
|
200
231
|
)
|
|
201
232
|
|
|
202
|
-
server.
|
|
233
|
+
server.registerTool(
|
|
203
234
|
'get_component_usage_guidelines',
|
|
204
|
-
'Get usage information for how to use a component from Primer',
|
|
205
235
|
{
|
|
206
|
-
|
|
236
|
+
description: 'Get usage information for how to use a component from Primer',
|
|
237
|
+
inputSchema: {
|
|
238
|
+
name: z.string().describe('The name of the component to retrieve'),
|
|
239
|
+
},
|
|
207
240
|
},
|
|
208
241
|
async ({name}) => {
|
|
209
242
|
const components = listComponents()
|
|
@@ -268,11 +301,14 @@ ${text}`,
|
|
|
268
301
|
},
|
|
269
302
|
)
|
|
270
303
|
|
|
271
|
-
server.
|
|
304
|
+
server.registerTool(
|
|
272
305
|
'get_component_accessibility_guidelines',
|
|
273
|
-
'Retrieve accessibility guidelines and best practices for a specific component from the @primer/react package by its name. Use this tool to get official accessibility recommendations, usage tips, and requirements to ensure your UI components are inclusive and meet accessibility standards.',
|
|
274
306
|
{
|
|
275
|
-
|
|
307
|
+
description:
|
|
308
|
+
'Retrieve accessibility guidelines and best practices for a specific component from the @primer/react package by its name. Use this tool to get official accessibility recommendations, usage tips, and requirements to ensure your UI components are inclusive and meet accessibility standards.',
|
|
309
|
+
inputSchema: {
|
|
310
|
+
name: z.string().describe('The name of the component to retrieve'),
|
|
311
|
+
},
|
|
276
312
|
},
|
|
277
313
|
async ({name}) => {
|
|
278
314
|
const components = listComponents()
|
|
@@ -340,27 +376,33 @@ ${text}`,
|
|
|
340
376
|
// -----------------------------------------------------------------------------
|
|
341
377
|
// Patterns
|
|
342
378
|
// -----------------------------------------------------------------------------
|
|
343
|
-
server.
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
379
|
+
server.registerTool(
|
|
380
|
+
'list_patterns',
|
|
381
|
+
{description: 'List all of the patterns available from Primer React'},
|
|
382
|
+
async () => {
|
|
383
|
+
const patterns = listPatterns().map(pattern => {
|
|
384
|
+
return `- ${pattern.name}`
|
|
385
|
+
})
|
|
386
|
+
return {
|
|
387
|
+
content: [
|
|
388
|
+
{
|
|
389
|
+
type: 'text',
|
|
390
|
+
text: `The following patterns are available in the @primer/react in TypeScript projects:
|
|
352
391
|
|
|
353
392
|
${patterns.join('\n')}`,
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
}
|
|
393
|
+
},
|
|
394
|
+
],
|
|
395
|
+
}
|
|
396
|
+
},
|
|
397
|
+
)
|
|
358
398
|
|
|
359
|
-
server.
|
|
399
|
+
server.registerTool(
|
|
360
400
|
'get_pattern',
|
|
361
|
-
'Get a specific pattern by name',
|
|
362
401
|
{
|
|
363
|
-
|
|
402
|
+
description: 'Get a specific pattern by name',
|
|
403
|
+
inputSchema: {
|
|
404
|
+
name: z.string().describe('The name of the pattern to retrieve'),
|
|
405
|
+
},
|
|
364
406
|
},
|
|
365
407
|
async ({name}) => {
|
|
366
408
|
const patterns = listPatterns()
|
|
@@ -417,7 +459,7 @@ ${text}`,
|
|
|
417
459
|
// -----------------------------------------------------------------------------
|
|
418
460
|
// Design Tokens
|
|
419
461
|
// -----------------------------------------------------------------------------
|
|
420
|
-
server.
|
|
462
|
+
server.registerTool('list_tokens', {description: 'List all of the design tokens available from Primer'}, async () => {
|
|
421
463
|
let text =
|
|
422
464
|
'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'
|
|
423
465
|
|
|
@@ -436,108 +478,122 @@ server.tool('list_tokens', 'List all of the design tokens available from Primer'
|
|
|
436
478
|
// -----------------------------------------------------------------------------
|
|
437
479
|
// Foundations
|
|
438
480
|
// -----------------------------------------------------------------------------
|
|
439
|
-
server.
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
481
|
+
server.registerTool(
|
|
482
|
+
'get_color_usage',
|
|
483
|
+
{description: 'Get the guidelines for how to apply color to a user interface'},
|
|
484
|
+
async () => {
|
|
485
|
+
const url = new URL(`/product/getting-started/foundations/color-usage`, 'https://primer.style')
|
|
486
|
+
const response = await fetch(url)
|
|
487
|
+
if (!response.ok) {
|
|
488
|
+
throw new Error(`Failed to fetch ${url} - ${response.statusText}`)
|
|
489
|
+
}
|
|
445
490
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
491
|
+
const html = await response.text()
|
|
492
|
+
if (!html) {
|
|
493
|
+
return {
|
|
494
|
+
content: [],
|
|
495
|
+
}
|
|
450
496
|
}
|
|
451
|
-
}
|
|
452
497
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
498
|
+
const $ = cheerio.load(html)
|
|
499
|
+
const source = $('main').html()
|
|
500
|
+
if (!source) {
|
|
501
|
+
return {
|
|
502
|
+
content: [],
|
|
503
|
+
}
|
|
458
504
|
}
|
|
459
|
-
}
|
|
460
505
|
|
|
461
|
-
|
|
506
|
+
const text = turndownService.turndown(source)
|
|
462
507
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
}
|
|
508
|
+
return {
|
|
509
|
+
content: [
|
|
510
|
+
{
|
|
511
|
+
type: 'text',
|
|
512
|
+
text: `Here is the documentation for color usage in Primer:\n\n${text}`,
|
|
513
|
+
},
|
|
514
|
+
],
|
|
515
|
+
}
|
|
516
|
+
},
|
|
517
|
+
)
|
|
472
518
|
|
|
473
|
-
server.
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
519
|
+
server.registerTool(
|
|
520
|
+
'get_typography_usage',
|
|
521
|
+
{description: 'Get the guidelines for how to apply typography to a user interface'},
|
|
522
|
+
async () => {
|
|
523
|
+
const url = new URL(`/product/getting-started/foundations/typography`, 'https://primer.style')
|
|
524
|
+
const response = await fetch(url)
|
|
525
|
+
if (!response.ok) {
|
|
526
|
+
throw new Error(`Failed to fetch ${url} - ${response.statusText}`)
|
|
527
|
+
}
|
|
479
528
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
529
|
+
const html = await response.text()
|
|
530
|
+
if (!html) {
|
|
531
|
+
return {
|
|
532
|
+
content: [],
|
|
533
|
+
}
|
|
484
534
|
}
|
|
485
|
-
}
|
|
486
535
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
536
|
+
const $ = cheerio.load(html)
|
|
537
|
+
const source = $('main').html()
|
|
538
|
+
if (!source) {
|
|
539
|
+
return {
|
|
540
|
+
content: [],
|
|
541
|
+
}
|
|
492
542
|
}
|
|
493
|
-
}
|
|
494
543
|
|
|
495
|
-
|
|
544
|
+
const text = turndownService.turndown(source)
|
|
496
545
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
}
|
|
546
|
+
return {
|
|
547
|
+
content: [
|
|
548
|
+
{
|
|
549
|
+
type: 'text',
|
|
550
|
+
text: `Here is the documentation for typography usage in Primer:\n\n${text}`,
|
|
551
|
+
},
|
|
552
|
+
],
|
|
553
|
+
}
|
|
554
|
+
},
|
|
555
|
+
)
|
|
506
556
|
|
|
507
557
|
// -----------------------------------------------------------------------------
|
|
508
558
|
// Icons
|
|
509
559
|
// -----------------------------------------------------------------------------
|
|
510
|
-
server.
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
560
|
+
server.registerTool(
|
|
561
|
+
'list_icons',
|
|
562
|
+
{description: 'List all of the icons (octicons) available from Primer Octicons React'},
|
|
563
|
+
async () => {
|
|
564
|
+
const icons = listIcons().map(icon => {
|
|
565
|
+
const keywords = icon.keywords.map(keyword => {
|
|
566
|
+
return `<keyword>${keyword}</keyword>`
|
|
567
|
+
})
|
|
568
|
+
const sizes = icon.heights.map(height => {
|
|
569
|
+
return `<size value="${height}"></size>`
|
|
570
|
+
})
|
|
571
|
+
return [`<icon name="${icon.name}">`, ...keywords, ...sizes, `</icon>`].join('\n')
|
|
517
572
|
})
|
|
518
|
-
return [`<icon name="${icon.name}">`, ...keywords, ...sizes, `</icon>`].join('\n')
|
|
519
|
-
})
|
|
520
573
|
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
574
|
+
return {
|
|
575
|
+
content: [
|
|
576
|
+
{
|
|
577
|
+
type: 'text',
|
|
578
|
+
text: `The following icons are available in the @primer/octicons-react package in TypeScript projects:
|
|
526
579
|
|
|
527
580
|
${icons.join('\n')}
|
|
528
581
|
|
|
529
582
|
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
|
-
}
|
|
583
|
+
},
|
|
584
|
+
],
|
|
585
|
+
}
|
|
586
|
+
},
|
|
587
|
+
)
|
|
534
588
|
|
|
535
|
-
server.
|
|
589
|
+
server.registerTool(
|
|
536
590
|
'get_icon',
|
|
537
|
-
'Get a specific icon (octicon) by name from Primer',
|
|
538
591
|
{
|
|
539
|
-
|
|
540
|
-
|
|
592
|
+
description: 'Get a specific icon (octicon) by name from Primer',
|
|
593
|
+
inputSchema: {
|
|
594
|
+
name: z.string().describe('The name of the icon to retrieve'),
|
|
595
|
+
size: z.string().optional().describe('The size of the icon to retrieve, e.g. "16"').default('16'),
|
|
596
|
+
},
|
|
541
597
|
},
|
|
542
598
|
async ({name, size}) => {
|
|
543
599
|
const icons = listIcons()
|
|
@@ -593,9 +649,9 @@ ${text}`,
|
|
|
593
649
|
// -----------------------------------------------------------------------------
|
|
594
650
|
// Coding guidelines
|
|
595
651
|
// -----------------------------------------------------------------------------
|
|
596
|
-
server.
|
|
652
|
+
server.registerTool(
|
|
597
653
|
'primer_coding_guidelines',
|
|
598
|
-
'Get the guidelines when writing code that uses Primer or for UI code that you are creating',
|
|
654
|
+
{description: 'Get the guidelines when writing code that uses Primer or for UI code that you are creating'},
|
|
599
655
|
async () => {
|
|
600
656
|
return {
|
|
601
657
|
content: [
|
|
@@ -643,19 +699,15 @@ The following list of coding guidelines must be followed:
|
|
|
643
699
|
*
|
|
644
700
|
*
|
|
645
701
|
**/
|
|
646
|
-
server.
|
|
702
|
+
server.registerTool(
|
|
647
703
|
'review_alt_text',
|
|
648
|
-
'Evaluates image alt text against accessibility best practices and context relevance.',
|
|
649
704
|
{
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
.
|
|
654
|
-
|
|
655
|
-
|
|
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'),
|
|
705
|
+
description: 'Evaluates image alt text against accessibility best practices and context relevance.',
|
|
706
|
+
inputSchema: {
|
|
707
|
+
surroundingText: z.string().describe('Text surrounding the image, relevant to the image.'),
|
|
708
|
+
alt: z.string().describe('The alt text of the image being evaluated'),
|
|
709
|
+
image: z.string().describe('The image URL or file path being evaluated'),
|
|
710
|
+
},
|
|
659
711
|
},
|
|
660
712
|
async ({surroundingText, alt, image}) => {
|
|
661
713
|
// Call the LLM through MCP sampling
|