@primer/mcp 0.3.3 → 0.4.0-rc.4d4be073a
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/{server-C2QaEv-c.js → server-CkSoZOVD.js} +120 -30
- package/dist/stdio.js +1 -1
- package/package.json +2 -2
- package/src/primer.ts +33 -0
- package/src/server.ts +51 -16
- package/dist/server-CGPYmiEJ.js +0 -1504
package/dist/index.js
CHANGED
|
@@ -40,36 +40,63 @@ const components = Object.entries(componentsMetadata.components).map(([id, compo
|
|
|
40
40
|
function listComponents() {
|
|
41
41
|
return components;
|
|
42
42
|
}
|
|
43
|
+
// Scenario patterns are listed first so name resolution favours them over UI patterns.
|
|
43
44
|
const patterns = [{
|
|
45
|
+
id: 'copy',
|
|
46
|
+
name: 'Copy',
|
|
47
|
+
category: 'scenario'
|
|
48
|
+
}, {
|
|
49
|
+
id: 'delete',
|
|
50
|
+
name: 'Delete',
|
|
51
|
+
category: 'scenario'
|
|
52
|
+
}, {
|
|
53
|
+
id: 'filter',
|
|
54
|
+
name: 'Filter',
|
|
55
|
+
category: 'scenario'
|
|
56
|
+
}, {
|
|
57
|
+
id: 'search',
|
|
58
|
+
name: 'Search',
|
|
59
|
+
category: 'scenario'
|
|
60
|
+
}, {
|
|
44
61
|
id: 'data-visualization',
|
|
45
|
-
name: 'Data Visualization'
|
|
62
|
+
name: 'Data Visualization',
|
|
63
|
+
category: 'ui'
|
|
46
64
|
}, {
|
|
47
65
|
id: 'degraded-experiences',
|
|
48
|
-
name: 'Degraded Experiences'
|
|
66
|
+
name: 'Degraded Experiences',
|
|
67
|
+
category: 'ui'
|
|
49
68
|
}, {
|
|
50
69
|
id: 'empty-states',
|
|
51
|
-
name: 'Empty States'
|
|
70
|
+
name: 'Empty States',
|
|
71
|
+
category: 'ui'
|
|
52
72
|
}, {
|
|
53
73
|
id: 'feature-onboarding',
|
|
54
|
-
name: 'Feature Onboarding'
|
|
74
|
+
name: 'Feature Onboarding',
|
|
75
|
+
category: 'ui'
|
|
55
76
|
}, {
|
|
56
77
|
id: 'forms',
|
|
57
|
-
name: 'Forms'
|
|
78
|
+
name: 'Forms',
|
|
79
|
+
category: 'ui'
|
|
58
80
|
}, {
|
|
59
81
|
id: 'loading',
|
|
60
|
-
name: 'Loading'
|
|
82
|
+
name: 'Loading',
|
|
83
|
+
category: 'ui'
|
|
61
84
|
}, {
|
|
62
85
|
id: 'navigation',
|
|
63
|
-
name: 'Navigation'
|
|
86
|
+
name: 'Navigation',
|
|
87
|
+
category: 'ui'
|
|
64
88
|
}, {
|
|
65
89
|
id: 'notification-messaging',
|
|
66
|
-
name: 'Notification message'
|
|
90
|
+
name: 'Notification message',
|
|
91
|
+
category: 'ui'
|
|
67
92
|
}, {
|
|
68
93
|
id: 'progressive-disclosure',
|
|
69
|
-
name: 'Progressive disclosure'
|
|
94
|
+
name: 'Progressive disclosure',
|
|
95
|
+
category: 'ui'
|
|
70
96
|
}, {
|
|
71
97
|
id: 'saving',
|
|
72
|
-
name: 'Saving'
|
|
98
|
+
name: 'Saving',
|
|
99
|
+
category: 'ui'
|
|
73
100
|
}];
|
|
74
101
|
function listPatterns() {
|
|
75
102
|
return patterns;
|
|
@@ -736,7 +763,7 @@ function runStylelint(css) {
|
|
|
736
763
|
});
|
|
737
764
|
}
|
|
738
765
|
|
|
739
|
-
var version = "0.
|
|
766
|
+
var version = "0.4.0";
|
|
740
767
|
var packageJson = {
|
|
741
768
|
version: version};
|
|
742
769
|
|
|
@@ -753,7 +780,10 @@ const allTokensWithGuidelines = loadAllTokensWithGuidelines();
|
|
|
753
780
|
// Project setup
|
|
754
781
|
// -----------------------------------------------------------------------------
|
|
755
782
|
server.registerTool('init', {
|
|
756
|
-
description: 'Setup or create a project that includes Primer React'
|
|
783
|
+
description: 'Setup or create a project that includes Primer React',
|
|
784
|
+
annotations: {
|
|
785
|
+
readOnlyHint: true
|
|
786
|
+
}
|
|
757
787
|
}, async () => {
|
|
758
788
|
const url = new URL(`/product/getting-started/react`, 'https://primer.style');
|
|
759
789
|
const response = await fetch(url);
|
|
@@ -798,7 +828,10 @@ ${text}
|
|
|
798
828
|
// Components
|
|
799
829
|
// -----------------------------------------------------------------------------
|
|
800
830
|
server.registerTool('list_components', {
|
|
801
|
-
description: 'List all of the components available from Primer React'
|
|
831
|
+
description: 'List all of the components available from Primer React',
|
|
832
|
+
annotations: {
|
|
833
|
+
readOnlyHint: true
|
|
834
|
+
}
|
|
802
835
|
}, async () => {
|
|
803
836
|
const components = listComponents().map(component => {
|
|
804
837
|
return `- ${component.name}`;
|
|
@@ -818,6 +851,9 @@ server.registerTool('get_component', {
|
|
|
818
851
|
description: '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.',
|
|
819
852
|
inputSchema: {
|
|
820
853
|
name: z.string().describe('The name of the component to retrieve')
|
|
854
|
+
},
|
|
855
|
+
annotations: {
|
|
856
|
+
readOnlyHint: true
|
|
821
857
|
}
|
|
822
858
|
}, async ({
|
|
823
859
|
name
|
|
@@ -858,6 +894,9 @@ server.registerTool('get_component_examples', {
|
|
|
858
894
|
description: 'Get examples for how to use a component from Primer React',
|
|
859
895
|
inputSchema: {
|
|
860
896
|
name: z.string().describe('The name of the component to retrieve')
|
|
897
|
+
},
|
|
898
|
+
annotations: {
|
|
899
|
+
readOnlyHint: true
|
|
861
900
|
}
|
|
862
901
|
}, async ({
|
|
863
902
|
name
|
|
@@ -906,6 +945,9 @@ server.registerTool('get_component_usage_guidelines', {
|
|
|
906
945
|
description: 'Get usage information for how to use a component from Primer',
|
|
907
946
|
inputSchema: {
|
|
908
947
|
name: z.string().describe('The name of the component to retrieve')
|
|
948
|
+
},
|
|
949
|
+
annotations: {
|
|
950
|
+
readOnlyHint: true
|
|
909
951
|
}
|
|
910
952
|
}, async ({
|
|
911
953
|
name
|
|
@@ -962,6 +1004,9 @@ server.registerTool('get_component_accessibility_guidelines', {
|
|
|
962
1004
|
description: '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.',
|
|
963
1005
|
inputSchema: {
|
|
964
1006
|
name: z.string().describe('The name of the component to retrieve')
|
|
1007
|
+
},
|
|
1008
|
+
annotations: {
|
|
1009
|
+
readOnlyHint: true
|
|
965
1010
|
}
|
|
966
1011
|
}, async ({
|
|
967
1012
|
name
|
|
@@ -1019,32 +1064,43 @@ ${text}`
|
|
|
1019
1064
|
// Patterns
|
|
1020
1065
|
// -----------------------------------------------------------------------------
|
|
1021
1066
|
server.registerTool('list_patterns', {
|
|
1022
|
-
description: 'List all of the patterns available from Primer React'
|
|
1067
|
+
description: '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.',
|
|
1068
|
+
annotations: {
|
|
1069
|
+
readOnlyHint: true
|
|
1070
|
+
}
|
|
1023
1071
|
}, async () => {
|
|
1024
|
-
const
|
|
1025
|
-
|
|
1026
|
-
});
|
|
1072
|
+
const all = listPatterns();
|
|
1073
|
+
const scenario = all.filter(pattern => pattern.category === 'scenario').map(pattern => `- ${pattern.name}`);
|
|
1074
|
+
const ui = all.filter(pattern => pattern.category === 'ui').map(pattern => `- ${pattern.name}`);
|
|
1027
1075
|
return {
|
|
1028
1076
|
content: [{
|
|
1029
1077
|
type: 'text',
|
|
1030
|
-
text: `The following patterns are available
|
|
1078
|
+
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.
|
|
1079
|
+
|
|
1080
|
+
## Scenario patterns
|
|
1081
|
+
|
|
1082
|
+
${scenario.join('\n')}
|
|
1031
1083
|
|
|
1032
|
-
|
|
1084
|
+
## UI patterns
|
|
1085
|
+
|
|
1086
|
+
${ui.join('\n')}`
|
|
1033
1087
|
}]
|
|
1034
1088
|
};
|
|
1035
1089
|
});
|
|
1036
1090
|
server.registerTool('get_pattern', {
|
|
1037
|
-
description: 'Get a specific pattern by name',
|
|
1091
|
+
description: '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.',
|
|
1038
1092
|
inputSchema: {
|
|
1039
1093
|
name: z.string().describe('The name of the pattern to retrieve')
|
|
1094
|
+
},
|
|
1095
|
+
annotations: {
|
|
1096
|
+
readOnlyHint: true
|
|
1040
1097
|
}
|
|
1041
1098
|
}, async ({
|
|
1042
1099
|
name
|
|
1043
1100
|
}) => {
|
|
1044
1101
|
const patterns = listPatterns();
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
});
|
|
1102
|
+
// Resolve scenario patterns first so a name clash favours the scenario pattern.
|
|
1103
|
+
const match = patterns.find(pattern => pattern.category === 'scenario' && pattern.name === name) ?? patterns.find(pattern => pattern.name === name);
|
|
1048
1104
|
if (!match) {
|
|
1049
1105
|
return {
|
|
1050
1106
|
content: [{
|
|
@@ -1053,7 +1109,8 @@ server.registerTool('get_pattern', {
|
|
|
1053
1109
|
}]
|
|
1054
1110
|
};
|
|
1055
1111
|
}
|
|
1056
|
-
const
|
|
1112
|
+
const basePath = match.category === 'scenario' ? 'scenario-patterns' : 'ui-patterns';
|
|
1113
|
+
const url = new URL(`/product/${basePath}/${match.id}`, 'https://primer.style');
|
|
1057
1114
|
const response = await fetch(url);
|
|
1058
1115
|
if (!response.ok) {
|
|
1059
1116
|
throw new Error(`Failed to fetch ${url} - ${response.statusText}`);
|
|
@@ -1091,6 +1148,9 @@ server.registerTool('find_tokens', {
|
|
|
1091
1148
|
query: z.string().optional().default('').describe('Search keywords (e.g., "danger border", "success background")'),
|
|
1092
1149
|
group: z.string().optional().describe('Filter by group (e.g., "fgColor", "border")'),
|
|
1093
1150
|
limit: z.number().int().min(1).max(100).optional().default(15).describe('Maximum results to return to stay within context limits')
|
|
1151
|
+
},
|
|
1152
|
+
annotations: {
|
|
1153
|
+
readOnlyHint: true
|
|
1094
1154
|
}
|
|
1095
1155
|
}, async ({
|
|
1096
1156
|
query,
|
|
@@ -1172,6 +1232,9 @@ server.registerTool('get_token_group_bundle', {
|
|
|
1172
1232
|
description: "PREFERRED FOR COMPONENTS. Fetch all tokens for complex UI (e.g., Dialogs, Cards) in one call by providing an array of groups like ['overlay', 'shadow']. Use this instead of multiple find_tokens calls to save context.",
|
|
1173
1233
|
inputSchema: {
|
|
1174
1234
|
groups: z.array(z.string()).describe('Array of group names (e.g., ["overlay", "shadow", "focus"])')
|
|
1235
|
+
},
|
|
1236
|
+
annotations: {
|
|
1237
|
+
readOnlyHint: true
|
|
1175
1238
|
}
|
|
1176
1239
|
}, async ({
|
|
1177
1240
|
groups
|
|
@@ -1206,7 +1269,10 @@ server.registerTool('get_token_group_bundle', {
|
|
|
1206
1269
|
};
|
|
1207
1270
|
});
|
|
1208
1271
|
server.registerTool('get_design_token_specs', {
|
|
1209
|
-
description: 'CRITICAL: CALL THIS FIRST. Provides the logic matrix and the list of valid group names. You cannot search accurately without this map.'
|
|
1272
|
+
description: 'CRITICAL: CALL THIS FIRST. Provides the logic matrix and the list of valid group names. You cannot search accurately without this map.',
|
|
1273
|
+
annotations: {
|
|
1274
|
+
readOnlyHint: true
|
|
1275
|
+
}
|
|
1210
1276
|
}, async () => {
|
|
1211
1277
|
const groups = listTokenGroups();
|
|
1212
1278
|
const customRules = getDesignTokenSpecsText(groups);
|
|
@@ -1225,7 +1291,10 @@ server.registerTool('get_design_token_specs', {
|
|
|
1225
1291
|
};
|
|
1226
1292
|
});
|
|
1227
1293
|
server.registerTool('get_token_usage_patterns', {
|
|
1228
|
-
description: '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.'
|
|
1294
|
+
description: '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.',
|
|
1295
|
+
annotations: {
|
|
1296
|
+
readOnlyHint: true
|
|
1297
|
+
}
|
|
1229
1298
|
}, async () => {
|
|
1230
1299
|
const customPatterns = getTokenUsagePatternsText();
|
|
1231
1300
|
let text;
|
|
@@ -1251,6 +1320,9 @@ server.registerTool('lint_css', {
|
|
|
1251
1320
|
description: 'REQUIRED FINAL STEP. Use this to validate your CSS. You cannot complete a task involving CSS without a successful run of this tool.',
|
|
1252
1321
|
inputSchema: {
|
|
1253
1322
|
css: z.string()
|
|
1323
|
+
},
|
|
1324
|
+
annotations: {
|
|
1325
|
+
readOnlyHint: true
|
|
1254
1326
|
}
|
|
1255
1327
|
}, async ({
|
|
1256
1328
|
css
|
|
@@ -1282,7 +1354,10 @@ server.registerTool('lint_css', {
|
|
|
1282
1354
|
// Foundations
|
|
1283
1355
|
// -----------------------------------------------------------------------------
|
|
1284
1356
|
server.registerTool('get_color_usage', {
|
|
1285
|
-
description: 'Get the guidelines for how to apply color to a user interface'
|
|
1357
|
+
description: 'Get the guidelines for how to apply color to a user interface',
|
|
1358
|
+
annotations: {
|
|
1359
|
+
readOnlyHint: true
|
|
1360
|
+
}
|
|
1286
1361
|
}, async () => {
|
|
1287
1362
|
const url = new URL(`/product/getting-started/foundations/color-usage`, 'https://primer.style');
|
|
1288
1363
|
const response = await fetch(url);
|
|
@@ -1311,7 +1386,10 @@ server.registerTool('get_color_usage', {
|
|
|
1311
1386
|
};
|
|
1312
1387
|
});
|
|
1313
1388
|
server.registerTool('get_typography_usage', {
|
|
1314
|
-
description: 'Get the guidelines for how to apply typography to a user interface'
|
|
1389
|
+
description: 'Get the guidelines for how to apply typography to a user interface',
|
|
1390
|
+
annotations: {
|
|
1391
|
+
readOnlyHint: true
|
|
1392
|
+
}
|
|
1315
1393
|
}, async () => {
|
|
1316
1394
|
const url = new URL(`/product/getting-started/foundations/typography`, 'https://primer.style');
|
|
1317
1395
|
const response = await fetch(url);
|
|
@@ -1344,7 +1422,10 @@ server.registerTool('get_typography_usage', {
|
|
|
1344
1422
|
// Icons
|
|
1345
1423
|
// -----------------------------------------------------------------------------
|
|
1346
1424
|
server.registerTool('list_icons', {
|
|
1347
|
-
description: 'List all of the icons (octicons) available from Primer Octicons React'
|
|
1425
|
+
description: 'List all of the icons (octicons) available from Primer Octicons React',
|
|
1426
|
+
annotations: {
|
|
1427
|
+
readOnlyHint: true
|
|
1428
|
+
}
|
|
1348
1429
|
}, async () => {
|
|
1349
1430
|
const icons = listIcons().map(icon => {
|
|
1350
1431
|
const keywords = icon.keywords.map(keyword => {
|
|
@@ -1371,6 +1452,9 @@ server.registerTool('get_icon', {
|
|
|
1371
1452
|
inputSchema: {
|
|
1372
1453
|
name: z.string().describe('The name of the icon to retrieve'),
|
|
1373
1454
|
size: z.string().optional().describe('The size of the icon to retrieve, e.g. "16"').default('16')
|
|
1455
|
+
},
|
|
1456
|
+
annotations: {
|
|
1457
|
+
readOnlyHint: true
|
|
1374
1458
|
}
|
|
1375
1459
|
}, async ({
|
|
1376
1460
|
name,
|
|
@@ -1420,7 +1504,10 @@ ${text}`
|
|
|
1420
1504
|
// Coding guidelines
|
|
1421
1505
|
// -----------------------------------------------------------------------------
|
|
1422
1506
|
server.registerTool('primer_coding_guidelines', {
|
|
1423
|
-
description: 'Get the guidelines when writing code that uses Primer or for UI code that you are creating'
|
|
1507
|
+
description: 'Get the guidelines when writing code that uses Primer or for UI code that you are creating',
|
|
1508
|
+
annotations: {
|
|
1509
|
+
readOnlyHint: true
|
|
1510
|
+
}
|
|
1424
1511
|
}, async () => {
|
|
1425
1512
|
return {
|
|
1426
1513
|
content: [{
|
|
@@ -1471,6 +1558,9 @@ server.registerTool('review_alt_text', {
|
|
|
1471
1558
|
surroundingText: z.string().describe('Text surrounding the image, relevant to the image.'),
|
|
1472
1559
|
alt: z.string().describe('The alt text of the image being evaluated'),
|
|
1473
1560
|
image: z.string().describe('The image URL or file path being evaluated')
|
|
1561
|
+
},
|
|
1562
|
+
annotations: {
|
|
1563
|
+
readOnlyHint: true
|
|
1474
1564
|
}
|
|
1475
1565
|
}, async ({
|
|
1476
1566
|
surroundingText,
|
package/dist/stdio.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
2
|
-
import { s as server } from './server-
|
|
2
|
+
import { s as server } from './server-CkSoZOVD.js';
|
|
3
3
|
import '@modelcontextprotocol/sdk/server/mcp.js';
|
|
4
4
|
import 'cheerio';
|
|
5
5
|
import 'zod';
|
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.
|
|
4
|
+
"version": "0.4.0-rc.4d4be073a",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"mcp": "./bin/mcp.js"
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"@modelcontextprotocol/sdk": "^1.24.0",
|
|
38
38
|
"@primer/octicons": "^19.15.5",
|
|
39
39
|
"@primer/primitives": "10.x || 11.x",
|
|
40
|
-
"@primer/react": "^38.
|
|
40
|
+
"@primer/react": "^38.30.0",
|
|
41
41
|
"cheerio": "^1.0.0",
|
|
42
42
|
"turndown": "^7.2.0",
|
|
43
43
|
"zod": "^4.3.5"
|
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
|
-
{
|
|
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
|
|
373
|
-
|
|
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
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
399
|
-
|
|
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
|
|
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
|
-
{
|
|
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
|
-
{
|
|
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
|
-
{
|
|
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
|