@primer/mcp 0.3.3 → 0.4.0-rc.2d1806208

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/stdio.js CHANGED
@@ -1,23 +1,7 @@
1
- import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
2
- import { s as server } from './server-C2QaEv-c.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 'node:fs';
10
- import 'node:module';
11
- import 'child_process';
12
- import '@primer/primitives/dist/docs/base/motion/motion.json' with { type: 'json' };
13
- import '@primer/primitives/dist/docs/base/size/size.json' with { type: 'json' };
14
- import '@primer/primitives/dist/docs/base/typography/typography.json' with { type: 'json' };
15
- import '@primer/primitives/dist/docs/functional/size/border.json' with { type: 'json' };
16
- import '@primer/primitives/dist/docs/functional/size/size-coarse.json' with { type: 'json' };
17
- import '@primer/primitives/dist/docs/functional/size/size-fine.json' with { type: 'json' };
18
- import '@primer/primitives/dist/docs/functional/size/size.json' with { type: 'json' };
19
- import '@primer/primitives/dist/docs/functional/themes/light.json' with { type: 'json' };
20
- import '@primer/primitives/dist/docs/functional/typography/typography.json' with { type: 'json' };
21
-
1
+ import { t as server } from "./server-BTJ9W5jN.js";
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ //#region src/transports/stdio.ts
22
4
  const transport = new StdioServerTransport();
23
5
  await server.connect(transport);
6
+ //#endregion
7
+ export {};
@@ -0,0 +1 @@
1
+ export { };
package/package.json CHANGED
@@ -1,7 +1,7 @@
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.3.3",
4
+ "version": "0.4.0-rc.2d1806208",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "mcp": "./bin/mcp.js"
@@ -28,34 +28,25 @@
28
28
  },
29
29
  "scripts": {
30
30
  "clean": "rimraf dist",
31
- "build": "rollup -c",
31
+ "build": "rolldown -c",
32
32
  "type-check": "tsc --noEmit",
33
- "watch": "rollup -c -w"
33
+ "watch": "rolldown -c -w"
34
34
  },
35
35
  "dependencies": {
36
- "@babel/runtime": "^7.28.6",
37
36
  "@modelcontextprotocol/sdk": "^1.24.0",
38
37
  "@primer/octicons": "^19.15.5",
39
38
  "@primer/primitives": "10.x || 11.x",
40
- "@primer/react": "^38.20.0",
39
+ "@primer/react": "^38.30.0",
41
40
  "cheerio": "^1.0.0",
42
41
  "turndown": "^7.2.0",
43
42
  "zod": "^4.3.5"
44
43
  },
45
44
  "devDependencies": {
46
- "@babel/core": "^7.29.0",
47
- "@babel/plugin-transform-runtime": "^7.29.0",
48
- "@babel/preset-env": "^7.29.0",
49
- "@babel/preset-typescript": "^7.28.5",
50
45
  "@modelcontextprotocol/inspector": "^0.16.6",
51
- "@rollup/plugin-babel": "^6.1.0",
52
- "@rollup/plugin-commonjs": "^29.0.0",
53
- "@rollup/plugin-json": "^6.1.0",
54
- "@rollup/plugin-node-resolve": "^16.0.3",
55
46
  "@types/turndown": "^5.0.5",
56
47
  "rimraf": "^6.0.1",
57
- "rollup": "^4.59.0",
58
- "rollup-plugin-typescript2": "^0.36.0",
48
+ "rolldown": "^1.1.2",
49
+ "rolldown-plugin-dts": "^0.26.0",
59
50
  "typescript": "^6.0.3"
60
51
  }
61
52
  }
package/src/primer.ts CHANGED
@@ -40,48 +40,81 @@ function listComponents(): Array<Component> {
40
40
  type Pattern = {
41
41
  id: string
42
42
  name: string
43
+ // 'scenario' maps to the /product/scenario-patterns/ base path, 'ui' to /product/ui-patterns/
44
+ category: 'scenario' | 'ui'
43
45
  }
44
46
 
47
+ // Scenario patterns are listed first so name resolution favours them over UI patterns.
45
48
  const patterns: Array<Pattern> = [
49
+ {
50
+ id: 'copy',
51
+ name: 'Copy',
52
+ category: 'scenario',
53
+ },
54
+ {
55
+ id: 'delete',
56
+ name: 'Delete',
57
+ category: 'scenario',
58
+ },
59
+ {
60
+ id: 'filter',
61
+ name: 'Filter',
62
+ category: 'scenario',
63
+ },
64
+ {
65
+ id: 'search',
66
+ name: 'Search',
67
+ category: 'scenario',
68
+ },
46
69
  {
47
70
  id: 'data-visualization',
48
71
  name: 'Data Visualization',
72
+ category: 'ui',
49
73
  },
50
74
  {
51
75
  id: 'degraded-experiences',
52
76
  name: 'Degraded Experiences',
77
+ category: 'ui',
53
78
  },
54
79
  {
55
80
  id: 'empty-states',
56
81
  name: 'Empty States',
82
+ category: 'ui',
57
83
  },
58
84
  {
59
85
  id: 'feature-onboarding',
60
86
  name: 'Feature Onboarding',
87
+ category: 'ui',
61
88
  },
62
89
  {
63
90
  id: 'forms',
64
91
  name: 'Forms',
92
+ category: 'ui',
65
93
  },
66
94
  {
67
95
  id: 'loading',
68
96
  name: 'Loading',
97
+ category: 'ui',
69
98
  },
70
99
  {
71
100
  id: 'navigation',
72
101
  name: 'Navigation',
102
+ category: 'ui',
73
103
  },
74
104
  {
75
105
  id: 'notification-messaging',
76
106
  name: 'Notification message',
107
+ category: 'ui',
77
108
  },
78
109
  {
79
110
  id: 'progressive-disclosure',
80
111
  name: 'Progressive disclosure',
112
+ category: 'ui',
81
113
  },
82
114
  {
83
115
  id: 'saving',
84
116
  name: 'Saving',
117
+ category: 'ui',
85
118
  },
86
119
  ]
87
120
 
package/src/server.ts CHANGED
@@ -39,6 +39,7 @@ server.registerTool(
39
39
  'init',
40
40
  {
41
41
  description: 'Setup or create a project that includes Primer React',
42
+ annotations: {readOnlyHint: true},
42
43
  },
43
44
  async () => {
44
45
  const url = new URL(`/product/getting-started/react`, 'https://primer.style')
@@ -92,7 +93,7 @@ ${text}
92
93
  // -----------------------------------------------------------------------------
93
94
  server.registerTool(
94
95
  'list_components',
95
- {description: 'List all of the components available from Primer React'},
96
+ {description: 'List all of the components available from Primer React', annotations: {readOnlyHint: true}},
96
97
  async () => {
97
98
  const components = listComponents().map(component => {
98
99
  return `- ${component.name}`
@@ -120,6 +121,7 @@ server.registerTool(
120
121
  inputSchema: {
121
122
  name: z.string().describe('The name of the component to retrieve'),
122
123
  },
124
+ annotations: {readOnlyHint: true},
123
125
  },
124
126
  async ({name}) => {
125
127
  const components = listComponents()
@@ -166,6 +168,7 @@ server.registerTool(
166
168
  inputSchema: {
167
169
  name: z.string().describe('The name of the component to retrieve'),
168
170
  },
171
+ annotations: {readOnlyHint: true},
169
172
  },
170
173
  async ({name}) => {
171
174
  const components = listComponents()
@@ -226,6 +229,7 @@ server.registerTool(
226
229
  inputSchema: {
227
230
  name: z.string().describe('The name of the component to retrieve'),
228
231
  },
232
+ annotations: {readOnlyHint: true},
229
233
  },
230
234
  async ({name}) => {
231
235
  const components = listComponents()
@@ -298,6 +302,7 @@ server.registerTool(
298
302
  inputSchema: {
299
303
  name: z.string().describe('The name of the component to retrieve'),
300
304
  },
305
+ annotations: {readOnlyHint: true},
301
306
  },
302
307
  async ({name}) => {
303
308
  const components = listComponents()
@@ -367,18 +372,28 @@ ${text}`,
367
372
  // -----------------------------------------------------------------------------
368
373
  server.registerTool(
369
374
  'list_patterns',
370
- {description: 'List all of the patterns available from Primer React'},
375
+ {
376
+ description:
377
+ 'List all of the patterns available from Primer React. Scenario patterns describe specific user tasks (copy, delete, filter, search). Prefer a scenario pattern when one fits the task, and fall back to the more generic UI patterns otherwise.',
378
+ annotations: {readOnlyHint: true},
379
+ },
371
380
  async () => {
372
- const patterns = listPatterns().map(pattern => {
373
- return `- ${pattern.name}`
374
- })
381
+ const all = listPatterns()
382
+ const scenario = all.filter(pattern => pattern.category === 'scenario').map(pattern => `- ${pattern.name}`)
383
+ const ui = all.filter(pattern => pattern.category === 'ui').map(pattern => `- ${pattern.name}`)
375
384
  return {
376
385
  content: [
377
386
  {
378
387
  type: 'text',
379
- text: `The following patterns are available in the @primer/react in TypeScript projects:
388
+ text: `The following patterns are available from \`@primer/react\` for use in TypeScript projects. Scenario patterns describe specific user tasks. Prefer a scenario pattern when one fits the task, and fall back to the UI patterns otherwise.
380
389
 
381
- ${patterns.join('\n')}`,
390
+ ## Scenario patterns
391
+
392
+ ${scenario.join('\n')}
393
+
394
+ ## UI patterns
395
+
396
+ ${ui.join('\n')}`,
382
397
  },
383
398
  ],
384
399
  }
@@ -388,16 +403,19 @@ ${patterns.join('\n')}`,
388
403
  server.registerTool(
389
404
  'get_pattern',
390
405
  {
391
- description: 'Get a specific pattern by name',
406
+ description:
407
+ 'Get a specific pattern by name. Scenario patterns describe specific user tasks (copy, delete, filter, search). Prefer a scenario pattern when one fits the task, and fall back to the more generic UI patterns otherwise.',
392
408
  inputSchema: {
393
409
  name: z.string().describe('The name of the pattern to retrieve'),
394
410
  },
411
+ annotations: {readOnlyHint: true},
395
412
  },
396
413
  async ({name}) => {
397
414
  const patterns = listPatterns()
398
- const match = patterns.find(pattern => {
399
- return pattern.name === name
400
- })
415
+ // Resolve scenario patterns first so a name clash favours the scenario pattern.
416
+ const match =
417
+ patterns.find(pattern => pattern.category === 'scenario' && pattern.name === name) ??
418
+ patterns.find(pattern => pattern.name === name)
401
419
  if (!match) {
402
420
  return {
403
421
  content: [
@@ -409,7 +427,8 @@ server.registerTool(
409
427
  }
410
428
  }
411
429
 
412
- const url = new URL(`/product/ui-patterns/${match.id}`, 'https://primer.style')
430
+ const basePath = match.category === 'scenario' ? 'scenario-patterns' : 'ui-patterns'
431
+ const url = new URL(`/product/${basePath}/${match.id}`, 'https://primer.style')
413
432
  const response = await fetch(url)
414
433
  if (!response.ok) {
415
434
  throw new Error(`Failed to fetch ${url} - ${response.statusText}`)
@@ -469,6 +488,7 @@ server.registerTool(
469
488
  .default(15)
470
489
  .describe('Maximum results to return to stay within context limits'),
471
490
  },
491
+ annotations: {readOnlyHint: true},
472
492
  },
473
493
  async ({query, group, limit}) => {
474
494
  // Resolve group via aliases
@@ -566,6 +586,7 @@ server.registerTool(
566
586
  inputSchema: {
567
587
  groups: z.array(z.string()).describe('Array of group names (e.g., ["overlay", "shadow", "focus"])'),
568
588
  },
589
+ annotations: {readOnlyHint: true},
569
590
  },
570
591
  async ({groups}) => {
571
592
  // Normalize and resolve aliases
@@ -608,6 +629,7 @@ server.registerTool(
608
629
  {
609
630
  description:
610
631
  'CRITICAL: CALL THIS FIRST. Provides the logic matrix and the list of valid group names. You cannot search accurately without this map.',
632
+ annotations: {readOnlyHint: true},
611
633
  },
612
634
  async () => {
613
635
  const groups = listTokenGroups()
@@ -631,6 +653,7 @@ server.registerTool(
631
653
  {
632
654
  description:
633
655
  'Provides "Golden Example" CSS for core patterns: Button (Interactions) and Stack (Layout). Use this to understand how to apply the Logic Matrix, Motion, and Spacing scales.',
656
+ annotations: {readOnlyHint: true},
634
657
  },
635
658
  async () => {
636
659
  const customPatterns = getTokenUsagePatternsText()
@@ -659,6 +682,7 @@ server.registerTool(
659
682
  description:
660
683
  'REQUIRED FINAL STEP. Use this to validate your CSS. You cannot complete a task involving CSS without a successful run of this tool.',
661
684
  inputSchema: {css: z.string()},
685
+ annotations: {readOnlyHint: true},
662
686
  },
663
687
  async ({css}) => {
664
688
  try {
@@ -694,7 +718,7 @@ server.registerTool(
694
718
  // -----------------------------------------------------------------------------
695
719
  server.registerTool(
696
720
  'get_color_usage',
697
- {description: 'Get the guidelines for how to apply color to a user interface'},
721
+ {description: 'Get the guidelines for how to apply color to a user interface', annotations: {readOnlyHint: true}},
698
722
  async () => {
699
723
  const url = new URL(`/product/getting-started/foundations/color-usage`, 'https://primer.style')
700
724
  const response = await fetch(url)
@@ -732,7 +756,10 @@ server.registerTool(
732
756
 
733
757
  server.registerTool(
734
758
  'get_typography_usage',
735
- {description: 'Get the guidelines for how to apply typography to a user interface'},
759
+ {
760
+ description: 'Get the guidelines for how to apply typography to a user interface',
761
+ annotations: {readOnlyHint: true},
762
+ },
736
763
  async () => {
737
764
  const url = new URL(`/product/getting-started/foundations/typography`, 'https://primer.style')
738
765
  const response = await fetch(url)
@@ -773,7 +800,10 @@ server.registerTool(
773
800
  // -----------------------------------------------------------------------------
774
801
  server.registerTool(
775
802
  'list_icons',
776
- {description: 'List all of the icons (octicons) available from Primer Octicons React'},
803
+ {
804
+ description: 'List all of the icons (octicons) available from Primer Octicons React',
805
+ annotations: {readOnlyHint: true},
806
+ },
777
807
  async () => {
778
808
  const icons = listIcons().map(icon => {
779
809
  const keywords = icon.keywords.map(keyword => {
@@ -808,6 +838,7 @@ server.registerTool(
808
838
  name: z.string().describe('The name of the icon to retrieve'),
809
839
  size: z.string().optional().describe('The size of the icon to retrieve, e.g. "16"').default('16'),
810
840
  },
841
+ annotations: {readOnlyHint: true},
811
842
  },
812
843
  async ({name, size}) => {
813
844
  const icons = listIcons()
@@ -865,7 +896,10 @@ ${text}`,
865
896
  // -----------------------------------------------------------------------------
866
897
  server.registerTool(
867
898
  'primer_coding_guidelines',
868
- {description: 'Get the guidelines when writing code that uses Primer or for UI code that you are creating'},
899
+ {
900
+ description: 'Get the guidelines when writing code that uses Primer or for UI code that you are creating',
901
+ annotations: {readOnlyHint: true},
902
+ },
869
903
  async () => {
870
904
  return {
871
905
  content: [
@@ -922,6 +956,7 @@ server.registerTool(
922
956
  alt: z.string().describe('The alt text of the image being evaluated'),
923
957
  image: z.string().describe('The image URL or file path being evaluated'),
924
958
  },
959
+ annotations: {readOnlyHint: true},
925
960
  },
926
961
  async ({surroundingText, alt, image}) => {
927
962
  // Call the LLM through MCP sampling