@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/dist/stdio.js
CHANGED
|
@@ -1,523 +1,20 @@
|
|
|
1
1
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
const patterns = [{
|
|
19
|
-
id: 'data-visualization',
|
|
20
|
-
name: 'Data Visualization'
|
|
21
|
-
}, {
|
|
22
|
-
id: 'degraded-experiences',
|
|
23
|
-
name: 'Degraded Experiences'
|
|
24
|
-
}, {
|
|
25
|
-
id: 'empty-states',
|
|
26
|
-
name: 'Empty States'
|
|
27
|
-
}, {
|
|
28
|
-
id: 'feature-onboarding',
|
|
29
|
-
name: 'Feature Onboarding'
|
|
30
|
-
}, {
|
|
31
|
-
id: 'forms',
|
|
32
|
-
name: 'Forms'
|
|
33
|
-
}, {
|
|
34
|
-
id: 'loading',
|
|
35
|
-
name: 'Loading'
|
|
36
|
-
}, {
|
|
37
|
-
id: 'navigation',
|
|
38
|
-
name: 'Navigation'
|
|
39
|
-
}, {
|
|
40
|
-
id: 'notification-messaging',
|
|
41
|
-
name: 'Notification message'
|
|
42
|
-
}, {
|
|
43
|
-
id: 'progressive-disclosure',
|
|
44
|
-
name: 'Progressive disclosure'
|
|
45
|
-
}, {
|
|
46
|
-
id: 'saving',
|
|
47
|
-
name: 'Saving'
|
|
48
|
-
}];
|
|
49
|
-
function listPatterns() {
|
|
50
|
-
return patterns;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
var version = "0.0.2";
|
|
54
|
-
var packageJson = {
|
|
55
|
-
version: version};
|
|
56
|
-
|
|
57
|
-
const server = new McpServer({
|
|
58
|
-
name: 'Primer',
|
|
59
|
-
version: packageJson.version
|
|
60
|
-
});
|
|
61
|
-
const turndownService = new TurndownService();
|
|
62
|
-
|
|
63
|
-
// -----------------------------------------------------------------------------
|
|
64
|
-
// Components
|
|
65
|
-
// -----------------------------------------------------------------------------
|
|
66
|
-
server.tool('get_components', 'List all of the components available from Primer React', async () => {
|
|
67
|
-
const components = listComponents().map(component => {
|
|
68
|
-
return `- ${component.name}`;
|
|
69
|
-
});
|
|
70
|
-
return {
|
|
71
|
-
content: [{
|
|
72
|
-
type: 'text',
|
|
73
|
-
text: `The following components are available in the @primer/react in TypeScript projects:
|
|
74
|
-
|
|
75
|
-
${components.join('\n')}
|
|
76
|
-
|
|
77
|
-
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.`
|
|
78
|
-
}]
|
|
79
|
-
};
|
|
80
|
-
});
|
|
81
|
-
server.tool('get_component', 'Get a specific component by name', {
|
|
82
|
-
name: z.string().describe('The name of the component to retrieve')
|
|
83
|
-
}, async ({
|
|
84
|
-
name
|
|
85
|
-
}) => {
|
|
86
|
-
const components = listComponents();
|
|
87
|
-
const match = components.find(component => {
|
|
88
|
-
return component.name === name;
|
|
89
|
-
});
|
|
90
|
-
if (!match) {
|
|
91
|
-
return {
|
|
92
|
-
content: [{
|
|
93
|
-
type: 'text',
|
|
94
|
-
text: `There is no component named \`${name}\` in the @primer/react package. For a full list of components, use the \`get_components\` tool.`
|
|
95
|
-
}]
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
const url = new URL(`/product/components/${match.id}`, 'https://primer.style');
|
|
99
|
-
const response = await fetch(url);
|
|
100
|
-
if (!response.ok) {
|
|
101
|
-
throw new Error(`Failed to fetch ${url}: ${response.statusText}`);
|
|
102
|
-
}
|
|
103
|
-
const html = await response.text();
|
|
104
|
-
if (!html) {
|
|
105
|
-
return {
|
|
106
|
-
content: []
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
const $ = cheerio.load(html);
|
|
110
|
-
const source = $('main').html();
|
|
111
|
-
if (!source) {
|
|
112
|
-
return {
|
|
113
|
-
content: []
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
const text = turndownService.turndown(source);
|
|
117
|
-
return {
|
|
118
|
-
content: [{
|
|
119
|
-
type: 'text',
|
|
120
|
-
text: `Here is the documentation for the \`${name}\` component from the @primer/react package:
|
|
121
|
-
${text}`
|
|
122
|
-
}]
|
|
123
|
-
};
|
|
124
|
-
});
|
|
125
|
-
server.tool('get_component_examples', 'Get examples for how to use a component from Primer React', {
|
|
126
|
-
name: z.string().describe('The name of the component to retrieve')
|
|
127
|
-
}, async ({
|
|
128
|
-
name
|
|
129
|
-
}) => {
|
|
130
|
-
const components = listComponents();
|
|
131
|
-
const match = components.find(component => {
|
|
132
|
-
return component.name === name;
|
|
133
|
-
});
|
|
134
|
-
if (!match) {
|
|
135
|
-
return {
|
|
136
|
-
content: [{
|
|
137
|
-
type: 'text',
|
|
138
|
-
text: `There is no component named \`${name}\` in the @primer/react package. For a full list of components, use the \`get_components\` tool.`
|
|
139
|
-
}]
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
const url = new URL(`/product/components/${match.id}`, 'https://primer.style');
|
|
143
|
-
const response = await fetch(url);
|
|
144
|
-
if (!response.ok) {
|
|
145
|
-
throw new Error(`Failed to fetch ${url}: ${response.statusText}`);
|
|
146
|
-
}
|
|
147
|
-
const html = await response.text();
|
|
148
|
-
if (!html) {
|
|
149
|
-
return {
|
|
150
|
-
content: []
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
const $ = cheerio.load(html);
|
|
154
|
-
const source = $('main').html();
|
|
155
|
-
if (!source) {
|
|
156
|
-
return {
|
|
157
|
-
content: []
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
const text = turndownService.turndown(source);
|
|
161
|
-
return {
|
|
162
|
-
content: [{
|
|
163
|
-
type: 'text',
|
|
164
|
-
text: `Here are some examples of how to use the \`${name}\` component from the @primer/react package:
|
|
165
|
-
|
|
166
|
-
${text}`
|
|
167
|
-
}]
|
|
168
|
-
};
|
|
169
|
-
});
|
|
170
|
-
server.tool('get_component_usage_guidelines', 'Get usage information for how to use a component from Primer', {
|
|
171
|
-
name: z.string().describe('The name of the component to retrieve')
|
|
172
|
-
}, async ({
|
|
173
|
-
name
|
|
174
|
-
}) => {
|
|
175
|
-
const components = listComponents();
|
|
176
|
-
const match = components.find(component => {
|
|
177
|
-
return component.name === name;
|
|
178
|
-
});
|
|
179
|
-
if (!match) {
|
|
180
|
-
return {
|
|
181
|
-
content: [{
|
|
182
|
-
type: 'text',
|
|
183
|
-
text: `There is no component named \`${name}\` in the @primer/react package. For a full list of components, use the \`get_components\` tool.`
|
|
184
|
-
}]
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
const url = new URL(`/product/components/${match.id}/guidelines`, 'https://primer.style');
|
|
188
|
-
const response = await fetch(url);
|
|
189
|
-
if (!response.ok) {
|
|
190
|
-
if (response.status >= 400 && response.status < 500 || response.status >= 300 && response.status < 400) {
|
|
191
|
-
return {
|
|
192
|
-
content: [{
|
|
193
|
-
type: 'text',
|
|
194
|
-
text: `There are no accessibility guidelines for the \`${name}\` component in the @primer/react package.`
|
|
195
|
-
}]
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
throw new Error(`Failed to fetch ${url}: ${response.statusText}`);
|
|
199
|
-
}
|
|
200
|
-
const html = await response.text();
|
|
201
|
-
if (!html) {
|
|
202
|
-
return {
|
|
203
|
-
content: []
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
const $ = cheerio.load(html);
|
|
207
|
-
const source = $('main').html();
|
|
208
|
-
if (!source) {
|
|
209
|
-
return {
|
|
210
|
-
content: []
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
const text = turndownService.turndown(source);
|
|
214
|
-
return {
|
|
215
|
-
content: [{
|
|
216
|
-
type: 'text',
|
|
217
|
-
text: `Here are the usage guidelines for the \`${name}\` component from the @primer/react package:
|
|
218
|
-
|
|
219
|
-
${text}`
|
|
220
|
-
}]
|
|
221
|
-
};
|
|
222
|
-
});
|
|
223
|
-
server.tool('get_component_accessibility_guidelines', 'Get accessibility information for how to use a component from Primer React', {
|
|
224
|
-
name: z.string().describe('The name of the component to retrieve')
|
|
225
|
-
}, async ({
|
|
226
|
-
name
|
|
227
|
-
}) => {
|
|
228
|
-
const components = listComponents();
|
|
229
|
-
const match = components.find(component => {
|
|
230
|
-
return component.name === name;
|
|
231
|
-
});
|
|
232
|
-
if (!match) {
|
|
233
|
-
return {
|
|
234
|
-
content: [{
|
|
235
|
-
type: 'text',
|
|
236
|
-
text: `There is no component named \`${name}\` in the @primer/react package. For a full list of components, use the \`get_components\` tool.`
|
|
237
|
-
}]
|
|
238
|
-
};
|
|
239
|
-
}
|
|
240
|
-
const url = new URL(`/product/components/${match.id}/accessibility`, 'https://primer.style');
|
|
241
|
-
const response = await fetch(url);
|
|
242
|
-
if (!response.ok) {
|
|
243
|
-
if (response.status >= 400 && response.status < 500 || response.status >= 300 && response.status < 400) {
|
|
244
|
-
return {
|
|
245
|
-
content: [{
|
|
246
|
-
type: 'text',
|
|
247
|
-
text: `There are no accessibility guidelines for the \`${name}\` component in the @primer/react package.`
|
|
248
|
-
}]
|
|
249
|
-
};
|
|
250
|
-
}
|
|
251
|
-
throw new Error(`Failed to fetch ${url}: ${response.statusText}`);
|
|
252
|
-
}
|
|
253
|
-
const html = await response.text();
|
|
254
|
-
if (!html) {
|
|
255
|
-
return {
|
|
256
|
-
content: []
|
|
257
|
-
};
|
|
258
|
-
}
|
|
259
|
-
const $ = cheerio.load(html);
|
|
260
|
-
const source = $('main').html();
|
|
261
|
-
if (!source) {
|
|
262
|
-
return {
|
|
263
|
-
content: []
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
const text = turndownService.turndown(source);
|
|
267
|
-
return {
|
|
268
|
-
content: [{
|
|
269
|
-
type: 'text',
|
|
270
|
-
text: `Here are the accessibility guidelines for the \`${name}\` component from the @primer/react package:
|
|
271
|
-
|
|
272
|
-
${text}`
|
|
273
|
-
}]
|
|
274
|
-
};
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
// -----------------------------------------------------------------------------
|
|
278
|
-
// Patterns
|
|
279
|
-
// -----------------------------------------------------------------------------
|
|
280
|
-
server.tool('list_patterns', 'List all of the patterns available from Primer React', async () => {
|
|
281
|
-
const patterns = listPatterns().map(pattern => {
|
|
282
|
-
return `- ${pattern.name}`;
|
|
283
|
-
});
|
|
284
|
-
return {
|
|
285
|
-
content: [{
|
|
286
|
-
type: 'text',
|
|
287
|
-
text: `The following patterns are available in the @primer/react in TypeScript projects:
|
|
288
|
-
|
|
289
|
-
${patterns.join('\n')}`
|
|
290
|
-
}]
|
|
291
|
-
};
|
|
292
|
-
});
|
|
293
|
-
server.tool('get_pattern', 'Get a specific pattern by name', {
|
|
294
|
-
name: z.string().describe('The name of the pattern to retrieve')
|
|
295
|
-
}, async ({
|
|
296
|
-
name
|
|
297
|
-
}) => {
|
|
298
|
-
const patterns = listPatterns();
|
|
299
|
-
const match = patterns.find(pattern => {
|
|
300
|
-
return pattern.name === name;
|
|
301
|
-
});
|
|
302
|
-
if (!match) {
|
|
303
|
-
return {
|
|
304
|
-
content: [{
|
|
305
|
-
type: 'text',
|
|
306
|
-
text: `There is no pattern named \`${name}\` in the @primer/react package. For a full list of patterns, use the \`list_patterns\` tool.`
|
|
307
|
-
}]
|
|
308
|
-
};
|
|
309
|
-
}
|
|
310
|
-
const url = new URL(`/product/ui-patterns/${match.id}`, 'https://primer.style');
|
|
311
|
-
const response = await fetch(url);
|
|
312
|
-
if (!response.ok) {
|
|
313
|
-
throw new Error(`Failed to fetch ${url} - ${response.statusText}`);
|
|
314
|
-
}
|
|
315
|
-
const html = await response.text();
|
|
316
|
-
if (!html) {
|
|
317
|
-
return {
|
|
318
|
-
content: []
|
|
319
|
-
};
|
|
320
|
-
}
|
|
321
|
-
const $ = cheerio.load(html);
|
|
322
|
-
const source = $('main').html();
|
|
323
|
-
if (!source) {
|
|
324
|
-
return {
|
|
325
|
-
content: []
|
|
326
|
-
};
|
|
327
|
-
}
|
|
328
|
-
const text = turndownService.turndown(source);
|
|
329
|
-
return {
|
|
330
|
-
content: [{
|
|
331
|
-
type: 'text',
|
|
332
|
-
text: `Here are the guidelines for the \`${name}\` pattern for Primer:
|
|
333
|
-
|
|
334
|
-
${text}`
|
|
335
|
-
}]
|
|
336
|
-
};
|
|
337
|
-
});
|
|
338
|
-
const tokens = [{
|
|
339
|
-
category: 'color',
|
|
340
|
-
tokens: [{
|
|
341
|
-
category: 'foreground',
|
|
342
|
-
tokens: ['--fgColor-accent', '--fgColor-attention', '--fgColor-black', '--fgColor-closed', '--fgColor-danger', '--fgColor-default', '--fgColor-disabled', '--fgColor-done', '--fgColor-link', '--fgColor-muted', '--fgColor-neutral', '--fgColor-onEmphasis', '--fgColor-onInverse', '--fgColor-open', '--fgColor-severe', '--fgColor-sponsors', '--fgColor-success', '--fgColor-upsell', '--fgColor-white']
|
|
343
|
-
}, {
|
|
344
|
-
category: 'background',
|
|
345
|
-
tokens: ['--bgColor-accent-emphasis', '--bgColor-accent-muted', '--bgColor-attention-emphasis', '--bgColor-attention-muted', '--bgColor-black', '--bgColor-closed-emphasis', '--bgColor-closed-muted', '--bgColor-danger-emphasis', '--bgColor-danger-muted', '--bgColor-default', '--bgColor-disabled', '--bgColor-done-emphasis', '--bgColor-done-muted', '--bgColor-emphasis', '--bgColor-inset', '--bgColor-inverse', '--bgColor-muted', '--bgColor-neutral-emphasis', '--bgColor-neutral-muted', '--bgColor-open-emphasis', '--bgColor-open-muted', '--bgColor-severe-emphasis', '--bgColor-severe-muted', '--bgColor-sponsors-emphasis', '--bgColor-sponsors-muted', '--bgColor-success-emphasis', '--bgColor-success-muted', '--bgColor-transparent', '--bgColor-upsell-emphasis', '--bgColor-upsell-muted', '--bgColor-white']
|
|
346
|
-
}, {
|
|
347
|
-
category: 'border',
|
|
348
|
-
tokens: ['--borderColor-accent-emphasis', '--borderColor-accent-muted', '--borderColor-attention-emphasis', '--borderColor-attention-muted', '--borderColor-closed-emphasis', '--borderColor-closed-muted', '--borderColor-danger-emphasis', '--borderColor-danger-muted', '--borderColor-default', '--borderColor-disabled', '--borderColor-done-emphasis', '--borderColor-done-muted', '--borderColor-emphasis', '--borderColor-muted', '--borderColor-neutral-emphasis', '--borderColor-neutral-muted', '--borderColor-open-emphasis', '--borderColor-open-muted', '--borderColor-severe-emphasis', '--borderColor-severe-muted', '--borderColor-sponsors-emphasis', '--borderColor-sponsors-muted', '--borderColor-success-emphasis', '--borderColor-success-muted', '--borderColor-translucent', '--borderColor-transparent', '--borderColor-upsell-emphasis', '--borderColor-upsell-muted']
|
|
349
|
-
}, {
|
|
350
|
-
category: 'shadow',
|
|
351
|
-
tokens: ['--shadow-floating-large', '--shadow-floating-legacy', '--shadow-floating-medium', '--shadow-floating-small', '--shadow-floating-xlarge', '--shadow-inset', '--shadow-resting-medium', '--shadow-resting-small', '--shadow-resting-xsmall']
|
|
352
|
-
}, {
|
|
353
|
-
category: 'control',
|
|
354
|
-
tokens: ['--control-bgColor-active', '--control-bgColor-disabled', '--control-bgColor-hover', '--control-bgColor-rest', '--control-bgColor-selected', '--control-borderColor-danger', '--control-borderColor-disabled', '--control-borderColor-emphasis', '--control-borderColor-rest', '--control-borderColor-selected', '--control-borderColor-success', '--control-borderColor-warning', '--control-checked-bgColor-active', '--control-checked-bgColor-disabled', '--control-checked-bgColor-hover', '--control-checked-bgColor-rest', '--control-checked-borderColor-active', '--control-checked-borderColor-disabled', '--control-checked-borderColor-hover', '--control-checked-borderColor-rest', '--control-checked-fgColor-disabled', '--control-checked-fgColor-rest', '--control-danger-bgColor-active', '--control-danger-bgColor-hover', '--control-danger-fgColor-hover', '--control-danger-fgColor-rest', '--control-fgColor-disabled', '--control-fgColor-placeholder', '--control-fgColor-rest', '--control-iconColor-rest', '--control-transparent-bgColor-active', '--control-transparent-bgColor-disabled', '--control-transparent-bgColor-hover', '--control-transparent-bgColor-rest', '--control-transparent-bgColor-selected', '--control-transparent-borderColor-active', '--control-transparent-borderColor-hover', '--control-transparent-borderColor-rest']
|
|
355
|
-
}, {
|
|
356
|
-
category: 'focus',
|
|
357
|
-
tokens: ['--focus-outlineColor']
|
|
358
|
-
}, {
|
|
359
|
-
category: 'overlay',
|
|
360
|
-
tokens: ['--overlay-background-bgColor', '--overlay-bgColor', '--overlay-borderColor']
|
|
361
|
-
}]
|
|
362
|
-
}, {
|
|
363
|
-
category: 'size',
|
|
364
|
-
tokens: [{
|
|
365
|
-
category: 'base',
|
|
366
|
-
tokens: ['--base-size-2', '--base-size-4', '--base-size-6', '--base-size-8', '--base-size-12', '--base-size-16', '--base-size-20', '--base-size-24', '--base-size-28', '--base-size-32', '--base-size-36', '--base-size-40', '--base-size-44', '--base-size-48', '--base-size-64', '--base-size-80', '--base-size-96', '--base-size-112', '--base-size-128']
|
|
367
|
-
}, {
|
|
368
|
-
category: 'border',
|
|
369
|
-
tokens: [{
|
|
370
|
-
category: 'border-size',
|
|
371
|
-
tokens: ['--boxShadow-thick', '--boxShadow-thicker', '--boxShadow-thin', '--borderWidth-default', '--borderWidth-thick', '--borderWidth-thicker', '--borderWidth-thin']
|
|
372
|
-
}, {
|
|
373
|
-
category: 'border-radius',
|
|
374
|
-
tokens: ['--borderRadius-default', '--borderRadius-full', '--borderRadius-large', '--borderRadius-medium', '--borderRadius-small']
|
|
375
|
-
}, {
|
|
376
|
-
category: 'outline',
|
|
377
|
-
tokens: ['--outline-focus-offset', '--outline-focus-width']
|
|
378
|
-
}]
|
|
379
|
-
}, {
|
|
380
|
-
category: 'layout',
|
|
381
|
-
tokens: [{
|
|
382
|
-
category: 'stack',
|
|
383
|
-
tokens: ['--stack-gap-condensed', '--stack-gap-normal', '--stack-gap-spacious', '--stack-padding-condensed', '--stack-padding-normal', '--stack-padding-spacious']
|
|
384
|
-
}, {
|
|
385
|
-
category: 'controls',
|
|
386
|
-
tokens: ['--controlStack-large-gap-auto', '--controlStack-large-gap-condensed', '--controlStack-large-gap-spacious', '--controlStack-medium-gap-condensed', '--controlStack-medium-gap-spacious', '--controlStack-small-gap-condensed', '--controlStack-small-gap-spacious', '--controlStack-medium-gap-auto', '--controlStack-small-gap-auto', '--control-xsmall-gap', '--control-small-gap', '--control-medium-gap', '--control-large-gap', '--control-xlarge-gap', '--control-xsmall-lineBoxHeight', '--control-small-lineBoxHeight', '--control-medium-lineBoxHeight', '--control-large-lineBoxHeight', '--control-xlarge-lineBoxHeight', '--control-xsmall-paddingBlock', '--control-small-paddingBlock', '--control-medium-paddingBlock', '--control-large-paddingBlock', '--control-xlarge-paddingBlock', '--control-xsmall-paddingInline-condensed', '--control-small-paddingInline-condensed', '--control-medium-paddingInline-condensed', '--control-large-paddingInline-condensed', '--control-xlarge-paddingInline-condensed', '--control-xsmall-paddingInline-normal', '--control-small-paddingInline-normal', '--control-medium-paddingInline-normal', '--control-large-paddingInline-normal', '--control-xlarge-paddingInline-normal', '--control-xsmall-paddingInline-spacious', '--control-small-paddingInline-spacious', '--control-medium-paddingInline-spacious', '--control-large-paddingInline-spacious', '--control-xlarge-paddingInline-spacious', '--control-xsmall-size', '--control-small-size', '--control-medium-size', '--control-large-size', '--control-xlarge-size']
|
|
387
|
-
}, {
|
|
388
|
-
category: 'overlay',
|
|
389
|
-
tokens: ['--overlay-borderRadius', '--overlay-height-large', '--overlay-height-medium', '--overlay-height-small', '--overlay-height-xlarge', '--overlay-offset', '--overlay-padding-condensed', '--overlay-padding-normal', '--overlay-paddingBlock-condensed', '--overlay-paddingBlock-normal', '--overlay-width-large', '--overlay-width-medium', '--overlay-width-small', '--overlay-width-xlarge', '--overlay-width-xsmall']
|
|
390
|
-
}]
|
|
391
|
-
}]
|
|
392
|
-
}, {
|
|
393
|
-
category: 'typography',
|
|
394
|
-
tokens: [{
|
|
395
|
-
category: 'weight',
|
|
396
|
-
tokens: ['--base-text-weight-light', '--base-text-weight-normal', '--base-text-weight-medium', '--base-text-weight-semibold']
|
|
397
|
-
}, {
|
|
398
|
-
category: 'font-family',
|
|
399
|
-
tokens: ['--fontStack-monospace', '--fontStack-sansSerif', '--fontStack-sansSerifDisplay', '--fontStack-system']
|
|
400
|
-
}, {
|
|
401
|
-
category: 'font-shorthand',
|
|
402
|
-
tokens: ['--text-body-shorthand-large', '--text-body-shorthand-medium', '--text-body-shorthand-small', '--text-caption-shorthand', '--text-codeBlock-shorthand', '--text-codeInline-shorthand', '--text-display-shorthand', '--text-subtitle-shorthand', '--text-title-shorthand-large', '--text-title-shorthand-medium', '--text-title-shorthand-small']
|
|
403
|
-
}, {
|
|
404
|
-
category: 'display',
|
|
405
|
-
tokens: ['--text-display-lineBoxHeight', '--text-display-lineHeight', '--text-display-size', '--text-display-weight']
|
|
406
|
-
}, {
|
|
407
|
-
category: 'title-large',
|
|
408
|
-
tokens: ['--text-title-lineHeight-large', '--text-title-size-large', '--text-title-weight-large']
|
|
409
|
-
}, {
|
|
410
|
-
category: 'title-medium',
|
|
411
|
-
tokens: ['--text-title-lineHeight-medium', '--text-title-size-medium', '--text-title-weight-medium']
|
|
412
|
-
}, {
|
|
413
|
-
category: 'title-small',
|
|
414
|
-
tokens: ['--text-title-lineHeight-small', '--text-title-size-small', '--text-title-weight-small']
|
|
415
|
-
}, {
|
|
416
|
-
category: 'subtitle',
|
|
417
|
-
tokens: ['--text-subtitle-lineHeight', '--text-subtitle-size', '--text-subtitle-weight']
|
|
418
|
-
}, {
|
|
419
|
-
category: 'body-large',
|
|
420
|
-
tokens: ['--text-body-lineHeight-large', '--text-body-size-large']
|
|
421
|
-
}, {
|
|
422
|
-
category: 'body-medium',
|
|
423
|
-
tokens: ['--text-body-lineHeight-medium', '--text-body-size-medium']
|
|
424
|
-
}, {
|
|
425
|
-
category: 'body-small',
|
|
426
|
-
tokens: ['--text-body-lineHeight-small', '--text-body-size-small']
|
|
427
|
-
}, {
|
|
428
|
-
category: 'caption',
|
|
429
|
-
tokens: ['--text-caption-lineHeight', '--text-caption-size', '--text-caption-weight']
|
|
430
|
-
}, {
|
|
431
|
-
category: 'code-block',
|
|
432
|
-
tokens: ['--text-codeBlock-lineHeight', '--text-codeBlock-size', '--text-codeBlock-weight']
|
|
433
|
-
}, {
|
|
434
|
-
category: 'inline-code-block',
|
|
435
|
-
tokens: ['--text-codeInline-size', '--text-codeInline-weight']
|
|
436
|
-
}]
|
|
437
|
-
}];
|
|
438
|
-
function serialize(token) {
|
|
439
|
-
if (typeof token === 'string') {
|
|
440
|
-
// eslint-disable-next-line github/unescaped-html-literal
|
|
441
|
-
return `<token name="${token}"></token>`;
|
|
442
|
-
}
|
|
443
|
-
// eslint-disable-next-line github/unescaped-html-literal
|
|
444
|
-
return `<token-category name="${token.category}">\n${token.tokens.map(serialize).join('\n')}\n</token-category>`;
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
// -----------------------------------------------------------------------------
|
|
448
|
-
// Design Tokens
|
|
449
|
-
// -----------------------------------------------------------------------------
|
|
450
|
-
server.tool('list_tokens', 'List all of the design tokens available from Primer', async () => {
|
|
451
|
-
let text = 'Below is a list of all designs tokens available from Primer. They are organized by category. Tokens are used in CSS and CSS Modules. They can also be referred to in JavaScript files using the style attribute or prop in React components. 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';
|
|
452
|
-
for (const token of tokens) {
|
|
453
|
-
text += serialize(token);
|
|
454
|
-
text += '\n';
|
|
455
|
-
}
|
|
456
|
-
return {
|
|
457
|
-
content: [{
|
|
458
|
-
type: 'text',
|
|
459
|
-
text
|
|
460
|
-
}]
|
|
461
|
-
};
|
|
462
|
-
});
|
|
463
|
-
|
|
464
|
-
// -----------------------------------------------------------------------------
|
|
465
|
-
// Foundations
|
|
466
|
-
// -----------------------------------------------------------------------------
|
|
467
|
-
server.tool('get_color_usage', 'Get the guidelines for how to apply color to a user interface', async () => {
|
|
468
|
-
const url = new URL(`/product/getting-started/foundations/color-usage`, 'https://primer.style');
|
|
469
|
-
const response = await fetch(url);
|
|
470
|
-
if (!response.ok) {
|
|
471
|
-
throw new Error(`Failed to fetch ${url} - ${response.statusText}`);
|
|
472
|
-
}
|
|
473
|
-
const html = await response.text();
|
|
474
|
-
if (!html) {
|
|
475
|
-
return {
|
|
476
|
-
content: []
|
|
477
|
-
};
|
|
478
|
-
}
|
|
479
|
-
const $ = cheerio.load(html);
|
|
480
|
-
const source = $('main').html();
|
|
481
|
-
if (!source) {
|
|
482
|
-
return {
|
|
483
|
-
content: []
|
|
484
|
-
};
|
|
485
|
-
}
|
|
486
|
-
const text = turndownService.turndown(source);
|
|
487
|
-
return {
|
|
488
|
-
content: [{
|
|
489
|
-
type: 'text',
|
|
490
|
-
text: `Here is the documentation for color usage in Primer:\n\n${text}`
|
|
491
|
-
}]
|
|
492
|
-
};
|
|
493
|
-
});
|
|
494
|
-
server.tool('get_typography_usage', 'Get the guidelines for how to apply typography to a user interface', async () => {
|
|
495
|
-
const url = new URL(`/product/getting-started/foundations/typography`, 'https://primer.style');
|
|
496
|
-
const response = await fetch(url);
|
|
497
|
-
if (!response.ok) {
|
|
498
|
-
throw new Error(`Failed to fetch ${url} - ${response.statusText}`);
|
|
499
|
-
}
|
|
500
|
-
const html = await response.text();
|
|
501
|
-
if (!html) {
|
|
502
|
-
return {
|
|
503
|
-
content: []
|
|
504
|
-
};
|
|
505
|
-
}
|
|
506
|
-
const $ = cheerio.load(html);
|
|
507
|
-
const source = $('main').html();
|
|
508
|
-
if (!source) {
|
|
509
|
-
return {
|
|
510
|
-
content: []
|
|
511
|
-
};
|
|
512
|
-
}
|
|
513
|
-
const text = turndownService.turndown(source);
|
|
514
|
-
return {
|
|
515
|
-
content: [{
|
|
516
|
-
type: 'text',
|
|
517
|
-
text: `Here is the documentation for typography usage in Primer:\n\n${text}`
|
|
518
|
-
}]
|
|
519
|
-
};
|
|
520
|
-
});
|
|
2
|
+
import { s as server } from './server-DHzOLtG9.js';
|
|
3
|
+
import '@modelcontextprotocol/sdk/server/mcp.js';
|
|
4
|
+
import 'cheerio';
|
|
5
|
+
import 'zod';
|
|
6
|
+
import 'turndown';
|
|
7
|
+
import '@primer/react/generated/components.json' with { type: 'json' };
|
|
8
|
+
import '@primer/octicons/build/data.json' with { type: 'json' };
|
|
9
|
+
import '@primer/primitives/dist/docs/base/motion/motion.json' with { type: 'json' };
|
|
10
|
+
import '@primer/primitives/dist/docs/base/size/size.json' with { type: 'json' };
|
|
11
|
+
import '@primer/primitives/dist/docs/base/typography/typography.json' with { type: 'json' };
|
|
12
|
+
import '@primer/primitives/dist/docs/functional/size/border.json' with { type: 'json' };
|
|
13
|
+
import '@primer/primitives/dist/docs/functional/size/size-coarse.json' with { type: 'json' };
|
|
14
|
+
import '@primer/primitives/dist/docs/functional/size/size-fine.json' with { type: 'json' };
|
|
15
|
+
import '@primer/primitives/dist/docs/functional/size/size.json' with { type: 'json' };
|
|
16
|
+
import '@primer/primitives/dist/docs/functional/themes/light.json' with { type: 'json' };
|
|
17
|
+
import '@primer/primitives/dist/docs/functional/typography/typography.json' with { type: 'json' };
|
|
521
18
|
|
|
522
19
|
const transport = new StdioServerTransport();
|
|
523
20
|
await server.connect(transport);
|
package/package.json
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@primer/mcp",
|
|
3
3
|
"description": "An MCP server that connects AI tools to the Primer Design System",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.4",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"mcp": "./bin/mcp.js"
|
|
8
8
|
},
|
|
9
9
|
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
},
|
|
10
14
|
"./transports/stdio": {
|
|
11
15
|
"types": "./dist/transports/stdio.d.ts",
|
|
12
16
|
"default": "./dist/stdio.js"
|
|
13
17
|
}
|
|
14
18
|
},
|
|
15
19
|
"files": [
|
|
16
|
-
"bin
|
|
20
|
+
"bin",
|
|
17
21
|
"dist",
|
|
18
22
|
"src",
|
|
19
23
|
"README.md"
|
|
@@ -25,28 +29,29 @@
|
|
|
25
29
|
"watch": "rollup -c -w"
|
|
26
30
|
},
|
|
27
31
|
"dependencies": {
|
|
28
|
-
"@babel/runtime": "^7.
|
|
32
|
+
"@babel/runtime": "^7.28.4",
|
|
29
33
|
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
34
|
+
"@primer/octicons": "^19.15.5",
|
|
30
35
|
"@primer/primitives": "10.x || 11.x",
|
|
31
|
-
"@primer/react": "^
|
|
36
|
+
"@primer/react": "^38.0.0-rc.0",
|
|
32
37
|
"cheerio": "^1.0.0",
|
|
33
38
|
"turndown": "^7.2.0",
|
|
34
39
|
"zod": "^3.23.8"
|
|
35
40
|
},
|
|
36
41
|
"devDependencies": {
|
|
37
|
-
"@babel/core": "^7.
|
|
38
|
-
"@babel/plugin-transform-runtime": "^7.
|
|
39
|
-
"@babel/preset-env": "^7.
|
|
42
|
+
"@babel/core": "^7.28.4",
|
|
43
|
+
"@babel/plugin-transform-runtime": "^7.28.3",
|
|
44
|
+
"@babel/preset-env": "^7.28.3",
|
|
40
45
|
"@babel/preset-typescript": "^7.27.1",
|
|
41
|
-
"@modelcontextprotocol/inspector": "^0.
|
|
46
|
+
"@modelcontextprotocol/inspector": "^0.16.6",
|
|
42
47
|
"@rollup/plugin-babel": "^6.0.4",
|
|
43
|
-
"@rollup/plugin-commonjs": "^
|
|
48
|
+
"@rollup/plugin-commonjs": "^28.0.6",
|
|
44
49
|
"@rollup/plugin-json": "^6.1.0",
|
|
45
|
-
"@rollup/plugin-node-resolve": "^
|
|
50
|
+
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
46
51
|
"@types/turndown": "^5.0.5",
|
|
47
52
|
"rimraf": "^6.0.1",
|
|
48
|
-
"rollup": "^4.
|
|
53
|
+
"rollup": "^4.50.1",
|
|
49
54
|
"rollup-plugin-typescript2": "^0.36.0",
|
|
50
|
-
"typescript": "^5.
|
|
55
|
+
"typescript": "^5.9.2"
|
|
51
56
|
}
|
|
52
57
|
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {server} from './server'
|
package/src/primer.ts
CHANGED
|
@@ -1,9 +1,31 @@
|
|
|
1
1
|
import componentsMetadata from '@primer/react/generated/components.json' with {type: 'json'}
|
|
2
|
+
import octicons from '@primer/octicons/build/data.json' with {type: 'json'}
|
|
2
3
|
|
|
3
4
|
type Component = {
|
|
4
5
|
id: string
|
|
5
6
|
name: string
|
|
6
7
|
importPath: string
|
|
8
|
+
slug: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function idToSlug(id: string): string {
|
|
12
|
+
if (id === 'actionbar') {
|
|
13
|
+
return 'action-bar'
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (id === 'tooltip-v2') {
|
|
17
|
+
return 'tooltip'
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (id === 'dialog_v2') {
|
|
21
|
+
return 'dialog'
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (id.startsWith('skeleton')) {
|
|
25
|
+
return 'skeleton-loaders'
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return id.replaceAll('_', '-')
|
|
7
29
|
}
|
|
8
30
|
|
|
9
31
|
const components: Array<Component> = Object.entries(componentsMetadata.components).map(([id, component]) => {
|
|
@@ -11,6 +33,7 @@ const components: Array<Component> = Object.entries(componentsMetadata.component
|
|
|
11
33
|
id,
|
|
12
34
|
name: component.name,
|
|
13
35
|
importPath: component.importPath,
|
|
36
|
+
slug: idToSlug(id),
|
|
14
37
|
}
|
|
15
38
|
})
|
|
16
39
|
|
|
@@ -70,4 +93,22 @@ function listPatterns(): Array<Pattern> {
|
|
|
70
93
|
return patterns
|
|
71
94
|
}
|
|
72
95
|
|
|
73
|
-
|
|
96
|
+
type Icon = {
|
|
97
|
+
name: string
|
|
98
|
+
keywords: Array<string>
|
|
99
|
+
heights: Array<string>
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const icons: Array<Icon> = Object.values(octicons).map(icon => {
|
|
103
|
+
return {
|
|
104
|
+
name: icon.name,
|
|
105
|
+
keywords: icon.keywords,
|
|
106
|
+
heights: Object.keys(icon.heights),
|
|
107
|
+
}
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
function listIcons(): Array<Icon> {
|
|
111
|
+
return icons
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export {listComponents, listPatterns, listIcons}
|